diff --git a/app/Album.php b/app/Album.php index 0fe9cf1..fde9739 100644 --- a/app/Album.php +++ b/app/Album.php @@ -16,7 +16,7 @@ class Album extends Model * @var array */ protected $fillable = [ - 'name', 'description' + 'name', 'description', 'url_alias' ]; /** @@ -31,7 +31,19 @@ class Album extends Model { $this->name = $request->get('name'); $this->description = $request->get('description'); + $this->generateAlias(); return $this; } + + public function generateAlias() + { + $this->url_alias = ucfirst(preg_replace('/[^a-z0-9\-]/', '-', strtolower($this->name))); + } + + public function getUploadDisk() + { + // TODO allow albums to specify a storage location + return 'local'; + } } \ No newline at end of file diff --git a/app/Console/Commands/ProcessUploadCommand.php b/app/Console/Commands/ProcessUploadCommand.php new file mode 100644 index 0000000..8bfbd84 --- /dev/null +++ b/app/Console/Commands/ProcessUploadCommand.php @@ -0,0 +1,80 @@ +orderBy('created_at', 'desc') + ->get(); + + foreach ($uploadsToProcess as $upload) + { + $this->output->writeln(sprintf('Processing upload #%d', $upload->id)); + $this->handleUpload($upload); + } + } + + private function handleUpload(Upload $upload) + { + $photos = $upload->uploadPhotos; + foreach ($photos as $photo) + { + $this->handlePhoto($photo); + } + } + + private function handlePhoto(UploadPhoto $uploadPhoto) + { + $photo = $uploadPhoto->photo; + $this->output->writeln(sprintf('Analysing photo #%d: %s', $photo->id, $photo->name)); + + $album = $photo->album; + + $photoFile = Storage::path(sprintf('albums/%s/%s', $album->url_alias, $photo->file_name), $album->getUploadDisk()); + dump($photoFile); + + dump(@exif_read_data($photoFile)); + } +} diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 622e774..4190201 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -2,6 +2,8 @@ namespace App\Console; +use App\Console\Commands\ProcessUploadCommand; +use App\Upload; use Illuminate\Console\Scheduling\Schedule; use Illuminate\Foundation\Console\Kernel as ConsoleKernel; @@ -13,7 +15,7 @@ class Kernel extends ConsoleKernel * @var array */ protected $commands = [ - // + ProcessUploadCommand::class ]; /** @@ -24,8 +26,11 @@ class Kernel extends ConsoleKernel */ protected function schedule(Schedule $schedule) { - // $schedule->command('inspire') - // ->hourly(); + $schedule->command('twilight:process-uploads') + ->everyMinute() + ->when(function () { + return (Upload::where('is_completed', 0)->count() > 0); + }); } /** diff --git a/app/Helpers/ThemeHelper.php b/app/Helpers/ThemeHelper.php index 094bb6e..7165df1 100644 --- a/app/Helpers/ThemeHelper.php +++ b/app/Helpers/ThemeHelper.php @@ -73,7 +73,7 @@ class ThemeHelper { $themeName = ThemeHelper::DEFAULT_THEME; - $currentTheme = Configuration::all()->where('key', 'theme')->first(); + $currentTheme = Configuration::where('key', 'theme')->first(); if (!is_null($currentTheme)) { $themeName = $currentTheme->value; diff --git a/app/Http/Controllers/Admin/AlbumController.php b/app/Http/Controllers/Admin/AlbumController.php index cb54278..f9d513e 100644 --- a/app/Http/Controllers/Admin/AlbumController.php +++ b/app/Http/Controllers/Admin/AlbumController.php @@ -43,7 +43,7 @@ class AlbumController extends Controller { $this->authorize('admin-access'); - $album = $this->loadAlbum($id); + $album = AlbumController::loadAlbum($id); return Theme::render('admin.delete_album', ['album' => $album]); } @@ -74,7 +74,7 @@ class AlbumController extends Controller { $this->authorize('admin-access'); - $album = $this->loadAlbum($id); + $album = AlbumController::loadAlbum($id); return Theme::render('admin.show_album', ['album' => $album]); } @@ -89,7 +89,7 @@ class AlbumController extends Controller { $this->authorize('admin-access'); - $album = $this->loadAlbum($id); + $album = AlbumController::loadAlbum($id); return Theme::render('admin.edit_album', ['album' => $album]); } @@ -105,7 +105,7 @@ class AlbumController extends Controller { $this->authorize('admin-access'); - $album = $this->loadAlbum($id); + $album = AlbumController::loadAlbum($id); $album->fromRequest($request)->save(); return Theme::render('admin.show_album', ['album' => $album]); @@ -127,9 +127,13 @@ class AlbumController extends Controller return redirect(route('albums.index')); } - private function loadAlbum($id) + /** + * @param $id + * @return Album + */ + public static function loadAlbum($id) { - $album = Album::all()->where('id', intval($id))->first(); + $album = Album::where('id', intval($id))->first(); if (is_null($album)) { App::abort(404); diff --git a/app/Http/Controllers/Admin/PhotoController.php b/app/Http/Controllers/Admin/PhotoController.php new file mode 100644 index 0000000..cc52d67 --- /dev/null +++ b/app/Http/Controllers/Admin/PhotoController.php @@ -0,0 +1,126 @@ +authorize('admin-access'); + + /** @var UploadedFile $photoFile */ + $photoFile = UploadedFile::createFromBase($request->files->get('photo')); + + // Load the linked album + $album = AlbumController::loadAlbum($request->get('album_id')); + + $storageLocation = sprintf('albums/%s', $album->url_alias); + + /** @var \SplFileInfo $savedFile */ + $savedFilePath = $photoFile->store($storageLocation, $album->getUploadDisk()); + + $photo = new Photo(); + $photo->album_id = $album->id; + $photo->name = $photoFile->getClientOriginalName(); + $photo->file_name = basename($savedFilePath); + $photo->mime_type = $photoFile->getClientMimeType(); + $photo->file_size = $photoFile->getSize(); + $photo->save(); + + $upload = new Upload(); + $upload->is_completed = false; + $upload->is_processing = false; + $upload->number_photos = 1; + $upload->save(); + + $uploadPhoto = new UploadPhoto(); + $uploadPhoto->upload_id = $upload->id; + $uploadPhoto->photo_id = $photo->id; + $uploadPhoto->save(); + + exit(); + } + + /** + * Display the specified resource. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function show($id) + { + // + } + + /** + * Show the form for editing the specified resource. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function edit($id) + { + // + } + + /** + * Update the specified resource in storage. + * + * @param \Illuminate\Http\Request $request + * @param int $id + * @return \Illuminate\Http\Response + */ + public function update(Request $request, $id) + { + // + } + + /** + * Remove the specified resource from storage. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function destroy($id) + { + // + } +} diff --git a/app/Photo.php b/app/Photo.php new file mode 100644 index 0000000..038d209 --- /dev/null +++ b/app/Photo.php @@ -0,0 +1,33 @@ +belongsTo(Album::class); + } +} diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index f74bdd1..ad6906d 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -4,6 +4,7 @@ namespace App\Providers; use App\Facade\Theme; use App\Helpers\ThemeHelper; +use Illuminate\Database\QueryException; use Illuminate\Support\Facades\View; use Illuminate\Support\ServiceProvider; @@ -21,7 +22,14 @@ class AppServiceProvider extends ServiceProvider return new ThemeHelper(); }); - $this->addThemeInfoToView(); + try + { + $this->addThemeInfoToView(); + } + catch (QueryException $ex) + { + // When running migrations, the configuration table may not exist - so ignore and continue + } } /** diff --git a/app/Upload.php b/app/Upload.php new file mode 100644 index 0000000..cafe392 --- /dev/null +++ b/app/Upload.php @@ -0,0 +1,33 @@ +hasMany(UploadPhoto::class); + } +} diff --git a/app/UploadPhoto.php b/app/UploadPhoto.php new file mode 100644 index 0000000..fd56101 --- /dev/null +++ b/app/UploadPhoto.php @@ -0,0 +1,33 @@ +belongsTo(Photo::class); + } +} diff --git a/config/database.php b/config/database.php index fd22e8e..3449771 100644 --- a/config/database.php +++ b/config/database.php @@ -56,8 +56,8 @@ return [ 'driver' => 'mysql', 'host' => env('DB_HOST', 'localhost'), 'port' => env('DB_PORT', '3306'), - 'database' => env('DB_DATABASE', 'forge'), - 'username' => env('DB_USERNAME', 'forge'), + 'database' => env('DB_DATABASE', 'blue_twilight'), + 'username' => env('DB_USERNAME', 'blue_twilight'), 'password' => env('DB_PASSWORD', ''), 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', @@ -70,8 +70,8 @@ return [ 'driver' => 'pgsql', 'host' => env('DB_HOST', 'localhost'), 'port' => env('DB_PORT', '5432'), - 'database' => env('DB_DATABASE', 'forge'), - 'username' => env('DB_USERNAME', 'forge'), + 'database' => env('DB_DATABASE', 'blue_twilight'), + 'username' => env('DB_USERNAME', 'blue_twilight'), 'password' => env('DB_PASSWORD', ''), 'charset' => 'utf8', 'prefix' => '', diff --git a/database/migrations/2014_10_12_000000_create_users_table.php b/database/migrations/2014_10_12_000000_create_users_table.php index 55574ee..689cbee 100644 --- a/database/migrations/2014_10_12_000000_create_users_table.php +++ b/database/migrations/2014_10_12_000000_create_users_table.php @@ -30,6 +30,6 @@ class CreateUsersTable extends Migration */ public function down() { - Schema::drop('users'); + Schema::dropIfExists('users'); } } diff --git a/database/migrations/2014_10_12_100000_create_password_resets_table.php b/database/migrations/2014_10_12_100000_create_password_resets_table.php index bda733d..1eefa40 100644 --- a/database/migrations/2014_10_12_100000_create_password_resets_table.php +++ b/database/migrations/2014_10_12_100000_create_password_resets_table.php @@ -27,6 +27,6 @@ class CreatePasswordResetsTable extends Migration */ public function down() { - Schema::drop('password_resets'); + Schema::dropIfExists('password_resets'); } } diff --git a/database/migrations/2016_09_01_144313_create_albums_table.php b/database/migrations/2016_09_01_144313_create_albums_table.php index f685949..467757f 100644 --- a/database/migrations/2016_09_01_144313_create_albums_table.php +++ b/database/migrations/2016_09_01_144313_create_albums_table.php @@ -17,6 +17,7 @@ class CreateAlbumsTable extends Migration $table->increments('id'); $table->string('name'); $table->text('description'); + $table->string('url_alias'); $table->timestamps(); }); } @@ -28,6 +29,6 @@ class CreateAlbumsTable extends Migration */ public function down() { - Schema::drop('albums'); + Schema::dropIfExists('albums'); } } diff --git a/database/migrations/2016_09_02_091706_create_config_table.php b/database/migrations/2016_09_02_091706_create_config_table.php index d6f1f0a..ccc3dd3 100644 --- a/database/migrations/2016_09_02_091706_create_config_table.php +++ b/database/migrations/2016_09_02_091706_create_config_table.php @@ -28,6 +28,6 @@ class CreateConfigTable extends Migration */ public function down() { - Schema::drop('configuration'); + Schema::dropIfExists('configuration'); } } diff --git a/database/migrations/2016_09_02_125912_create_photos_table.php b/database/migrations/2016_09_02_125912_create_photos_table.php new file mode 100644 index 0000000..73afd0d --- /dev/null +++ b/database/migrations/2016_09_02_125912_create_photos_table.php @@ -0,0 +1,41 @@ +bigIncrements('id'); + $table->unsignedInteger('album_id'); + $table->string('name'); + $table->string('description')->default(''); + $table->string('file_name'); + $table->string('mime_type'); + $table->unsignedBigInteger('file_size'); + $table->timestamps(); + + $table->foreign('album_id') + ->references('id')->on('albums') + ->onDelete('no action'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('photos'); + } +} diff --git a/database/migrations/2016_09_02_144354_create_uploads_table.php b/database/migrations/2016_09_02_144354_create_uploads_table.php new file mode 100644 index 0000000..928ce1d --- /dev/null +++ b/database/migrations/2016_09_02_144354_create_uploads_table.php @@ -0,0 +1,36 @@ +increments('id'); + $table->boolean('is_completed'); + $table->boolean('is_processing'); + $table->integer('number_photos')->default(0); + $table->integer('number_successful')->default(0); + $table->integer('number_failed')->default(0); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('uploads'); + } +} diff --git a/database/migrations/2016_09_02_144359_create_upload_photos_table.php b/database/migrations/2016_09_02_144359_create_upload_photos_table.php new file mode 100644 index 0000000..f9aaf31 --- /dev/null +++ b/database/migrations/2016_09_02_144359_create_upload_photos_table.php @@ -0,0 +1,40 @@ +bigIncrements('id'); + $table->unsignedInteger('upload_id'); + $table->unsignedBigInteger('photo_id'); + $table->timestamps(); + + $table->foreign('upload_id') + ->references('id')->on('uploads') + ->onDelete('cascade'); + $table->foreign('photo_id') + ->references('id')->on('photos') + ->onDelete('cascade'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('upload_photos'); + } +} diff --git a/public/themes/base/css/app.css b/public/themes/base/css/app.css index 1e5d40c..cbf908f 100644 --- a/public/themes/base/css/app.css +++ b/public/themes/base/css/app.css @@ -6,4 +6,10 @@ .form-actions { text-align: right; +} + +.tab-content { + border: solid 1px #ddd; + border-top: 0; + padding: 10px; } \ No newline at end of file diff --git a/resources/lang/en/forms.php b/resources/lang/en/forms.php index 98eaf01..c0c1154 100644 --- a/resources/lang/en/forms.php +++ b/resources/lang/en/forms.php @@ -6,5 +6,6 @@ return [ 'description_label' => 'Description:', 'edit_action' => 'Edit', 'name_label' => 'Name:', + 'upload_action' => 'Upload', 'save_action' => 'Save Changes' ]; \ No newline at end of file diff --git a/resources/views/themes/base/admin/create_album.blade.php b/resources/views/themes/base/admin/create_album.blade.php index 8297ec5..280ede5 100644 --- a/resources/views/themes/base/admin/create_album.blade.php +++ b/resources/views/themes/base/admin/create_album.blade.php @@ -32,8 +32,8 @@
- {!! Form::submit(trans('forms.create_action'), ['class' => 'btn btn-success']) !!} @lang('forms.cancel_action') + {!! Form::submit(trans('forms.create_action'), ['class' => 'btn btn-success']) !!}
{!! Form::close() !!} diff --git a/resources/views/themes/base/admin/edit_album.blade.php b/resources/views/themes/base/admin/edit_album.blade.php index 5b9728f..d4cdd87 100644 --- a/resources/views/themes/base/admin/edit_album.blade.php +++ b/resources/views/themes/base/admin/edit_album.blade.php @@ -32,8 +32,8 @@
- {!! Form::submit(trans('forms.save_action'), ['class' => 'btn btn-success']) !!} @lang('forms.cancel_action') + {!! Form::submit(trans('forms.save_action'), ['class' => 'btn btn-success']) !!}
{!! Form::close() !!} diff --git a/resources/views/themes/base/admin/show_album.blade.php b/resources/views/themes/base/admin/show_album.blade.php index acb3fa3..549cc5b 100644 --- a/resources/views/themes/base/admin/show_album.blade.php +++ b/resources/views/themes/base/admin/show_album.blade.php @@ -8,6 +8,42 @@

{{ $album->name }}

{{ $album->description }}


+ +
+ {{-- Nav tabs --}} + + + {{-- Tab panes --}} +
+
+

Upload a single image

+ + {!! Form::open(['route' => 'photos.store', 'method' => 'POST', 'files' => true]) !!} + {!! Form::hidden('album_id', $album->id) !!} + +
+ {!! Form::file('photo', ['class' => 'control-label']) !!} +
+ +
+ {!! Form::submit(trans('forms.upload_action'), ['class' => 'btn btn-success']) !!} +
+ {!! Form::close() !!} +
+ +
+

Settings

+
+
+
+ +
+ @lang('forms.edit_action') + @lang('forms.delete_action') +
diff --git a/resources/views/themes/bootstrap3/.gitkeep b/resources/views/themes/bootstrap3/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/routes/web.php b/routes/web.php index 7636da9..b181b17 100644 --- a/routes/web.php +++ b/routes/web.php @@ -22,4 +22,5 @@ Route::group(['prefix' => 'admin'], function () { Route::get('albums/{id}/delete', 'Admin\AlbumController@delete')->name('albums.delete'); Route::resource('albums', 'Admin\AlbumController'); + Route::resource('photos', 'Admin\PhotoController'); }); \ No newline at end of file