diff --git a/README.md b/README.md new file mode 100644 index 000000000..250c45ca5 --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +## How long did you spend to complete this test? + +I took about 7 hours + +## What was easy? + +All steps, exept steps 5 and bonus + +## What was hard? + +Nothing too hard, but took most time on view, validation and upload file. \ No newline at end of file diff --git a/app/Http/Controllers/PostController.php b/app/Http/Controllers/PostController.php new file mode 100644 index 000000000..9d26a4a92 --- /dev/null +++ b/app/Http/Controllers/PostController.php @@ -0,0 +1,63 @@ +hasFile('image')) { + // Create directory images if doesn't exist + File::makeDirectory(public_path().'/images', 0755, true, true); + // Avoid file names duplicated + $fileNameWithExt = $request->file('image')->getClientOriginalName(); + // Just file name + $fileName = pathinfo($fileNameWithExt, PATHINFO_FILENAME); + // Just file extension + $extension = $request->file('image')->extension(); + // Name to Store + $fileNameToStore = $fileName.'_'.time().'.'.$extension; + //Full Path + $imgPath = public_path().'/images/'.$fileNameToStore; + //resize and store + Image::make($request->file('image'))->resize(400, 300)->save($imgPath); + } + + $post = Post::create([ + 'user_id' => Auth::user()->id, + 'name' => trim($request->name), + 'description' => trim($request->description), + 'image' => $imgPath + ]); + + session()->flash('success', "The post '{$post->name}' has been created!"); + + } catch(QueryException $exception) { + session()->flash('exception', "A database error occurred when creating a new post. + Please refresh the page and try again. + If the problem persists, contact the support."); + } catch(\Exception $exception) { + session()->flash('exception', "Please refresh the page and try again. If the problem persists, contact the support."); + } finally { + return redirect(route('post.create')); + } + } +} diff --git a/app/Http/Requests/PostCreateRequest.php b/app/Http/Requests/PostCreateRequest.php new file mode 100644 index 000000000..d627ffd9e --- /dev/null +++ b/app/Http/Requests/PostCreateRequest.php @@ -0,0 +1,32 @@ + + */ + public function rules() + { + return [ + 'name' => 'required|max:255|unique:posts,name', + 'description' => 'required', + 'image' => 'required|image|mimes:jpg,png,jpeg,gif,svg|max:2048' + ]; + } +} diff --git a/app/Models/Post.php b/app/Models/Post.php new file mode 100644 index 000000000..a40242728 --- /dev/null +++ b/app/Models/Post.php @@ -0,0 +1,28 @@ + + */ + protected $fillable = [ + 'user_id', + 'name', + 'description', + 'image' + ]; + + public function user() + { + return $this->belongsTo(User::class); + } +} diff --git a/app/Models/User.php b/app/Models/User.php index 23b406346..d8d695731 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -41,4 +41,9 @@ class User extends Authenticatable protected $casts = [ 'email_verified_at' => 'datetime', ]; + + public function posts() + { + return $this->hasMany(Post::class); + } } diff --git a/composer.json b/composer.json index f45b5b916..d1c6e2672 100644 --- a/composer.json +++ b/composer.json @@ -7,6 +7,7 @@ "require": { "php": "^8.0.2", "guzzlehttp/guzzle": "^7.2", + "intervention/image": "^2.7", "laravel/framework": "^9.19", "laravel/sanctum": "^3.0", "laravel/tinker": "^2.7" diff --git a/composer.lock b/composer.lock index b5c88b445..8832c8ab8 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "5d5b387077098f2f11ded0abfe855eae", + "content-hash": "3a7ecfc4c7a9a6c2db4e374466501ec2", "packages": [ { "name": "brick/math", @@ -889,6 +889,90 @@ ], "time": "2022-06-20T21:43:11+00:00" }, + { + "name": "intervention/image", + "version": "2.7.2", + "source": { + "type": "git", + "url": "https://github.com/Intervention/image.git", + "reference": "04be355f8d6734c826045d02a1079ad658322dad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Intervention/image/zipball/04be355f8d6734c826045d02a1079ad658322dad", + "reference": "04be355f8d6734c826045d02a1079ad658322dad", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "guzzlehttp/psr7": "~1.1 || ^2.0", + "php": ">=5.4.0" + }, + "require-dev": { + "mockery/mockery": "~0.9.2", + "phpunit/phpunit": "^4.8 || ^5.7 || ^7.5.15" + }, + "suggest": { + "ext-gd": "to use GD library based image processing.", + "ext-imagick": "to use Imagick based image processing.", + "intervention/imagecache": "Caching extension for the Intervention Image library" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.4-dev" + }, + "laravel": { + "providers": [ + "Intervention\\Image\\ImageServiceProvider" + ], + "aliases": { + "Image": "Intervention\\Image\\Facades\\Image" + } + } + }, + "autoload": { + "psr-4": { + "Intervention\\Image\\": "src/Intervention/Image" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Oliver Vogel", + "email": "oliver@intervention.io", + "homepage": "https://intervention.io/" + } + ], + "description": "Image handling and manipulation library with support for Laravel integration", + "homepage": "http://image.intervention.io/", + "keywords": [ + "gd", + "image", + "imagick", + "laravel", + "thumbnail", + "watermark" + ], + "support": { + "issues": "https://github.com/Intervention/image/issues", + "source": "https://github.com/Intervention/image/tree/2.7.2" + }, + "funding": [ + { + "url": "https://paypal.me/interventionio", + "type": "custom" + }, + { + "url": "https://github.com/Intervention", + "type": "github" + } + ], + "time": "2022-05-21T17:30:32+00:00" + }, { "name": "laravel/framework", "version": "v9.23.0", diff --git a/database/migrations/2022_09_02_104041_create_posts_table.php b/database/migrations/2022_09_02_104041_create_posts_table.php new file mode 100644 index 000000000..916bc2d32 --- /dev/null +++ b/database/migrations/2022_09_02_104041_create_posts_table.php @@ -0,0 +1,35 @@ +id(); + $table->foreignId('user_id')->constrained()->cascadeOnDelete(); + $table->string('name')->unique(); + $table->text('description'); + $table->text('image'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('posts'); + } +}; diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index a9aafbf99..e1cd6bc8a 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -14,11 +14,9 @@ class DatabaseSeeder extends Seeder */ public function run() { - // \App\Models\User::factory(10)->create(); - -// \App\Models\User::factory()->create([ -// 'name' => 'Test User', -// 'email' => 'user@codinglabs.test', -// ]); + \App\Models\User::factory()->create([ + 'email' => 'test@test.com', + 'password' => bcrypt('secret') + ]); } } diff --git a/package-lock.json b/package-lock.json index b5016d620..74765ec46 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "laravel-skills-test", + "name": "laravel.skills.exercise", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/public/images/.gitignore b/public/images/.gitignore new file mode 100644 index 000000000..b722e9e13 --- /dev/null +++ b/public/images/.gitignore @@ -0,0 +1 @@ +!.gitignore \ No newline at end of file diff --git a/public/images/default_job_image_1662296372.jpg b/public/images/default_job_image_1662296372.jpg new file mode 100644 index 000000000..03a6f0426 Binary files /dev/null and b/public/images/default_job_image_1662296372.jpg differ diff --git a/public/images/facebook-profile_1662296317.jpg b/public/images/facebook-profile_1662296317.jpg new file mode 100644 index 000000000..01f7f28ca Binary files /dev/null and b/public/images/facebook-profile_1662296317.jpg differ diff --git a/resources/views/components/input-file.blade.php b/resources/views/components/input-file.blade.php new file mode 100644 index 000000000..3237e435d --- /dev/null +++ b/resources/views/components/input-file.blade.php @@ -0,0 +1,14 @@ +merge(['class' => 'block + w-full + px-3 + py-1.5 + text-base + font-normal + text-gray-700 + bg-gray-100 bg-clip-padding + border border-solid border-gray-300 + rounded + transition + ease-in-out + m-0 + focus:text-gray-700 focus:bg-white focus:border-blue-600 focus:outline-none']) !!}> diff --git a/resources/views/components/textarea.blade.php b/resources/views/components/textarea.blade.php new file mode 100644 index 000000000..becbb9703 --- /dev/null +++ b/resources/views/components/textarea.blade.php @@ -0,0 +1,12 @@ + \ No newline at end of file diff --git a/resources/views/home.blade.php b/resources/views/home.blade.php new file mode 100644 index 000000000..70a1fc914 --- /dev/null +++ b/resources/views/home.blade.php @@ -0,0 +1,51 @@ + + +

+ {{ __('Create a New Post') }} +

+
+
+
+
+
+
+ @csrf +
+
+ +
+ + + +
+ +
+ + + +
+ +
+ + + + +
+ +
+ + + + {{ __('Create Post') }} + + + +
+
+
+
+
+
+
+
+
diff --git a/resources/views/inc/messages.blade.php b/resources/views/inc/messages.blade.php new file mode 100644 index 000000000..60b6a5204 --- /dev/null +++ b/resources/views/inc/messages.blade.php @@ -0,0 +1,36 @@ + + +@if(count($errors) > 0) + @foreach($errors->all() as $error) + + @endforeach +@endif + + +@if(session()->has('success')) + +@endif + +@if(session()->has('exception')) + +@endif \ No newline at end of file diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php index 6ae3c8cbb..ab2e40aa4 100644 --- a/resources/views/layouts/app.blade.php +++ b/resources/views/layouts/app.blade.php @@ -12,6 +12,7 @@ @vite(['resources/css/app.css', 'resources/js/app.js']) +
@@ -26,6 +27,7 @@
+ @include('inc.messages') {{ $slot }}
diff --git a/resources/views/layouts/navigation.blade.php b/resources/views/layouts/navigation.blade.php index 3355c7dde..0e9b128a2 100644 --- a/resources/views/layouts/navigation.blade.php +++ b/resources/views/layouts/navigation.blade.php @@ -15,6 +15,9 @@ {{ __('Dashboard') }} + + {{ __('Blog') }} + diff --git a/routes/web.php b/routes/web.php index 852b11f82..e134eb9dc 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,6 +1,7 @@ middleware(['auth'])->name('dashboard'); +Route::resource('post', PostController::class)->only(['create','store'])->middleware(['auth']); + require __DIR__.'/auth.php'; diff --git a/storage/app/public/.gitignore b/storage/app/public/.gitignore deleted file mode 100644 index d6b7ef32c..000000000 --- a/storage/app/public/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore