From b24753d17d84115d155b9af90a0b0a9075d28526 Mon Sep 17 00:00:00 2001 From: Aleksander Kowalski Date: Fri, 6 May 2022 14:24:44 +0200 Subject: [PATCH] #14 - crud for news (#39) * feat: add blades * feat: add * fix: refactor routing * feat: add editor and remove tests * feat: cleaning * fix: after review * fix: cleaning * fix: after review and dump error * fix: remove files * Update resources/css/app.css Co-authored-by: Kamil Piech * fix: after review * fix: after review * fix: remove purifier * fix: after review * feat: update routing and fixed bug * fix: after review * fix: after review * fix: change chmod * fix: eslint run Co-authored-by: Kamil Piech Co-authored-by: aleksander.kowalski --- .gitignore | 1 + config/app.php | 1 + .../2022_03_18_195003_create_news_table.php | 26 +++++++++ database/seeders/DummyDataSeeder.php | 3 +- package.json | 2 + resources/js/app.js | 28 ++++++++++ resources/static/.gitignore | 2 +- .../views/components/form-input.blade.php | 0 resources/views/meetups/create.blade.php | 0 resources/views/meetups/edit.blade.php | 0 resources/views/meetups/index.blade.php | 2 +- resources/views/news/create.blade.php | 29 ++++++++++ resources/views/news/edit.blade.php | 31 +++++++++++ resources/views/news/index.blade.php | 30 ++++++++++ resources/views/organizations/edit.blade.php | 0 resources/views/speakers/edit.blade.php | 0 src/Http/Controllers/NewsController.php | 55 +++++++++++++++++++ src/Http/Requests/News/NewsRequest.php | 25 +++++++++ src/Http/Routing/WebRouting.php | 10 ++++ src/Models/News.php | 16 +++++- src/Models/User.php | 5 ++ tests/manual/public/index.php | 0 webpack.mix.js | 2 +- 23 files changed, 261 insertions(+), 7 deletions(-) create mode 100644 database/migrations/2022_03_18_195003_create_news_table.php mode change 100755 => 100644 resources/views/components/form-input.blade.php mode change 100755 => 100644 resources/views/meetups/create.blade.php mode change 100755 => 100644 resources/views/meetups/edit.blade.php create mode 100644 resources/views/news/create.blade.php create mode 100644 resources/views/news/edit.blade.php create mode 100644 resources/views/news/index.blade.php mode change 100755 => 100644 resources/views/organizations/edit.blade.php mode change 100755 => 100644 resources/views/speakers/edit.blade.php create mode 100644 src/Http/Controllers/NewsController.php create mode 100644 src/Http/Requests/News/NewsRequest.php mode change 100644 => 100755 tests/manual/public/index.php diff --git a/.gitignore b/.gitignore index 8b6c26d4..ee9bd190 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,4 @@ storage/redis/dump.rdb /storage/src/* composer.lock package-lock.json +yarn.lock diff --git a/config/app.php b/config/app.php index f125a881..227d1889 100755 --- a/config/app.php +++ b/config/app.php @@ -52,5 +52,6 @@ "Auth" => Illuminate\Support\Facades\Auth::class, "Constants" => Blumilk\Meetup\Core\Models\Utils\Constants::class, "AvailableNewsletter" => Blumilk\Meetup\Core\Enums\AvailableNewsletter::class, + "Str" => Illuminate\Support\Str::class, ], ]; diff --git a/database/migrations/2022_03_18_195003_create_news_table.php b/database/migrations/2022_03_18_195003_create_news_table.php new file mode 100644 index 00000000..26ac37c9 --- /dev/null +++ b/database/migrations/2022_03_18_195003_create_news_table.php @@ -0,0 +1,26 @@ +id(); + $table->foreignId("author_id")->constrained()->onDelete("cascade"); + $table->string("title"); + $table->longText("text"); + $table->string("slug")->unique(); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists("news"); + } +}; diff --git a/database/seeders/DummyDataSeeder.php b/database/seeders/DummyDataSeeder.php index b348f216..48924842 100755 --- a/database/seeders/DummyDataSeeder.php +++ b/database/seeders/DummyDataSeeder.php @@ -11,7 +11,6 @@ use Blumilk\Meetup\Core\Models\User; use Illuminate\Database\Seeder; use Illuminate\Support\Carbon; -use Illuminate\Support\Facades\Hash; class DummyDataSeeder extends Seeder { @@ -20,7 +19,7 @@ public function run(): void $user = User::factory([ "name" => "Admin", "email" => "admin@example.com", - "password" => Hash::make("password"), + "password" => "password", "email_verified_at" => Carbon::createFromDate(2022, 01, 01), ])->create(); diff --git a/package.json b/package.json index d48897b6..bef764f7 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,8 @@ "eslint-plugin-tailwindcss": "^3.5.0" }, "dependencies": { + "@toast-ui/editor": "^3.1.4", + "codemirror": "^5.65.2", "alpinejs": "^3.9.6", "cross-env": "^7.0.3", "tailwindcss": "^3.0.23", diff --git a/resources/js/app.js b/resources/js/app.js index d41a043b..6ef53beb 100644 --- a/resources/js/app.js +++ b/resources/js/app.js @@ -1,4 +1,32 @@ import Alpine from 'alpinejs' +import Editor from '@toast-ui/editor' +import 'codemirror/lib/codemirror.css' +import '@toast-ui/editor/dist/toastui-editor.css' + +const editor = new Editor({ + el: document.querySelector('#editor'), + height: '400px', + initialEditType: 'markdown', + placeholder: 'Write something cool!', +}) + +if (document.querySelector('#createNews')) { + document.querySelector('#createNews').addEventListener('submit', event => { + event.preventDefault() + document.querySelector('#text').value = editor.getMarkdown() + event.target.submit() + }) +} + +if (document.querySelector('#editNews')) { + editor.setMarkdown(document.querySelector('#oldText').value) + + document.querySelector('#editNews').addEventListener('submit', event => { + event.preventDefault() + document.querySelector('#text').value = editor.getMarkdown() + event.target.submit() + }) +} window.Alpine = Alpine diff --git a/resources/static/.gitignore b/resources/static/.gitignore index bdaf036c..26f465c6 100644 --- a/resources/static/.gitignore +++ b/resources/static/.gitignore @@ -1,2 +1,2 @@ -css/* js/* +css/* diff --git a/resources/views/components/form-input.blade.php b/resources/views/components/form-input.blade.php old mode 100755 new mode 100644 diff --git a/resources/views/meetups/create.blade.php b/resources/views/meetups/create.blade.php old mode 100755 new mode 100644 diff --git a/resources/views/meetups/edit.blade.php b/resources/views/meetups/edit.blade.php old mode 100755 new mode 100644 diff --git a/resources/views/meetups/index.blade.php b/resources/views/meetups/index.blade.php index e1463890..81c7fb2b 100644 --- a/resources/views/meetups/index.blade.php +++ b/resources/views/meetups/index.blade.php @@ -17,7 +17,7 @@ {{ $meetup->language }} Edit -
+ @csrf @method('DELETE') diff --git a/resources/views/news/create.blade.php b/resources/views/news/create.blade.php new file mode 100644 index 00000000..7eb02a15 --- /dev/null +++ b/resources/views/news/create.blade.php @@ -0,0 +1,29 @@ +@extends('layouts.app') + +@section('content') +
+
+

Create News

+ @auth + + @csrf +
+ + + +
+ +
+
+
+ + +
+ +
+ + @endauth +
+
+ +@endsection diff --git a/resources/views/news/edit.blade.php b/resources/views/news/edit.blade.php new file mode 100644 index 00000000..d9b0f282 --- /dev/null +++ b/resources/views/news/edit.blade.php @@ -0,0 +1,31 @@ +@extends('layouts.app') + +@section('content') +
+
+

Edit News

+ @auth +
+ @method('PUT') + @csrf +
+ + + +
+ +
+
+
+ + + +
+ +
+ + @endauth +
+
+ +@endsection diff --git a/resources/views/news/index.blade.php b/resources/views/news/index.blade.php new file mode 100644 index 00000000..ce0136a1 --- /dev/null +++ b/resources/views/news/index.blade.php @@ -0,0 +1,30 @@ +@extends('layouts.app') + +@section('content') +
+
+

News

+ @auth + Create new news + @endauth + @if ($news->count()) + @foreach ($news as $singleNews) +
+ {{ $singleNews->title }} + {!! Str::markdown($singleNews->text) !!} + {{ $singleNews->author }} + + Edit +
+ @csrf + @method('DELETE') + +
+
+ @endforeach + @else +

There are no news

+ @endif +
+
+@endsection diff --git a/resources/views/organizations/edit.blade.php b/resources/views/organizations/edit.blade.php old mode 100755 new mode 100644 diff --git a/resources/views/speakers/edit.blade.php b/resources/views/speakers/edit.blade.php old mode 100755 new mode 100644 diff --git a/src/Http/Controllers/NewsController.php b/src/Http/Controllers/NewsController.php new file mode 100644 index 00000000..cddaf94d --- /dev/null +++ b/src/Http/Controllers/NewsController.php @@ -0,0 +1,55 @@ +orderBy("date")->paginate(20); + + return view("news.index") + ->with("news", $news); + } + + public function create(): View + { + return view("news.create"); + } + + public function store(NewsRequest $request): RedirectResponse + { + $input = $request->validated(); + + $request->user()->news()->create($input); + + return redirect()->route("news"); + } + + public function edit(News $news): View + { + return view("news.edit") + ->with("news", $news); + } + + public function update(NewsRequest $request, News $news): RedirectResponse + { + $news->update($request->validated()); + + return redirect()->route("news"); + } + + public function destroy(News $news): RedirectResponse + { + $news->delete(); + + return back(); + } +} diff --git a/src/Http/Requests/News/NewsRequest.php b/src/Http/Requests/News/NewsRequest.php new file mode 100644 index 00000000..d95d9775 --- /dev/null +++ b/src/Http/Requests/News/NewsRequest.php @@ -0,0 +1,25 @@ + "required|string", + "text" => "required|string", + ]; + } + + protected function prepareForValidation(): void + { + $this->merge([ + "text" => strip_tags($this->text), + ]); + } +} diff --git a/src/Http/Routing/WebRouting.php b/src/Http/Routing/WebRouting.php index df7c02b2..7a10c440 100755 --- a/src/Http/Routing/WebRouting.php +++ b/src/Http/Routing/WebRouting.php @@ -12,6 +12,7 @@ use Blumilk\Meetup\Core\Http\Controllers\ContactController; use Blumilk\Meetup\Core\Http\Controllers\InvitationController; use Blumilk\Meetup\Core\Http\Controllers\MeetupController; +use Blumilk\Meetup\Core\Http\Controllers\NewsController; use Blumilk\Meetup\Core\Http\Controllers\NewsletterSubscriberController; use Blumilk\Meetup\Core\Http\Controllers\OrganizationController; use Blumilk\Meetup\Core\Http\Controllers\OrganizationProfileController; @@ -95,6 +96,15 @@ public function wire(): void $this->router->delete("/speakers/{speaker}", "destroy")->name("speakers.destroy"); }); + $this->router->controller(NewsController::class)->group(function (): void { + $this->router->get("/news", "index")->name("news"); + $this->router->get("/news/create", "create")->middleware("auth")->name("news.create"); + $this->router->post("/news", "store")->middleware("auth")->name("news.store"); + $this->router->get("/news/{news}/edit", "edit")->middleware("auth")->name("news.edit"); + $this->router->put("/news/{news}", "update")->middleware("auth")->name("news.update"); + $this->router->delete("/news/{news}", "destroy")->middleware("auth")->name("news.destroy"); + }); + $this->router->controller(NewsletterSubscriberController::class)->group(function (): void { $this->router->get("/newsletter", "create")->name("newsletter"); $this->router->post("/newsletter/subscribe", "store")->name("newsletter.store"); diff --git a/src/Models/News.php b/src/Models/News.php index 9a6e6ad1..b7024e15 100644 --- a/src/Models/News.php +++ b/src/Models/News.php @@ -8,11 +8,12 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Support\Carbon; +use Illuminate\Support\Str; /** * @property int $id * @property string $name - * @property string|null $content + * @property string|null $text * @property Carbon|null $createdAt * @property Carbon|null $updatedAt * @property-read User $user @@ -22,8 +23,11 @@ class News extends Model use HasFactory; protected $fillable = [ + "author_id", + "slug", + "title", "name", - "content", + "text", ]; protected $casts = [ "date:" . Formats::DATETIME, @@ -33,4 +37,12 @@ public function user(): BelongsTo { return $this->belongsTo(User::class); } + + protected static function boot(): void + { + parent::boot(); + static::creating(function (self $news): void { + $news->slug = Str::slug($news->title); + }); + } } diff --git a/src/Models/User.php b/src/Models/User.php index 757c3186..8cc001f2 100644 --- a/src/Models/User.php +++ b/src/Models/User.php @@ -72,6 +72,11 @@ public function socialAccounts(): HasMany return $this->hasMany(SocialAccount::class); } + public function news(): HasMany + { + return $this->hasMany(News::class); + } + protected static function newFactory(): UserFactory { return UserFactory::new(); diff --git a/tests/manual/public/index.php b/tests/manual/public/index.php old mode 100644 new mode 100755 diff --git a/webpack.mix.js b/webpack.mix.js index 16bc61e2..ffb25f6b 100644 --- a/webpack.mix.js +++ b/webpack.mix.js @@ -6,4 +6,4 @@ mix .setPublicPath('resources/static') .postCss('resources/css/app.css', 'resources/static/css', [ require('tailwindcss'), - ]); + ]); \ No newline at end of file