diff --git a/app/Concerns/HasEditLog.php b/app/Concerns/HasEditLog.php new file mode 100644 index 000000000..8848b4ec1 --- /dev/null +++ b/app/Concerns/HasEditLog.php @@ -0,0 +1,42 @@ + $model->author_id, + 'editable_id' => $model->id, + 'editable_type' => constant($model::class.'::TABLE') ?? $model::class, + 'edited_at' => now(), + ]); + + $cacheKey = sprintf('%s-%s', Str::slug($model::class), $model->id); + if (Cache::has($cacheKey)) { + Cache::forget($cacheKey); + } + }); + } + + public function edits(): MorphMany + { + return $this->morphMany(Edit::class, 'editable'); + } + + public function getLatestEditAttribute(): ?Edit + { + $cacheKey = sprintf('%s-%s', Str::slug($this::class), $this->id); + + return Cache::rememberForever($cacheKey, function () { + return $this->edits()->latest('edited_at')->first(); + }); + } +} diff --git a/app/Models/Article.php b/app/Models/Article.php index ef0f41851..3a21e7644 100644 --- a/app/Models/Article.php +++ b/app/Models/Article.php @@ -3,6 +3,7 @@ namespace App\Models; use App\Concerns\HasAuthor; +use App\Concerns\HasEditLog; use App\Concerns\HasLikes; use App\Concerns\HasSlug; use App\Concerns\HasTags; @@ -19,6 +20,7 @@ final class Article extends Model { use HasFactory; use HasAuthor; + use HasEditLog; use HasSlug; use HasLikes; use HasTimestamps; diff --git a/app/Models/Edit.php b/app/Models/Edit.php new file mode 100644 index 000000000..4227edbfa --- /dev/null +++ b/app/Models/Edit.php @@ -0,0 +1,35 @@ +morphTo(); + } +} diff --git a/app/Models/Reply.php b/app/Models/Reply.php index 4dacf3f9c..ee7c3022d 100644 --- a/app/Models/Reply.php +++ b/app/Models/Reply.php @@ -3,6 +3,7 @@ namespace App\Models; use App\Concerns\HasAuthor; +use App\Concerns\HasEditLog; use App\Concerns\HasLikes; use App\Concerns\HasTimestamps; use Illuminate\Database\Eloquent\Builder; @@ -16,6 +17,7 @@ final class Reply extends Model { use HasFactory; use HasAuthor; + use HasEditLog; use HasLikes; use HasTimestamps; diff --git a/app/Models/Thread.php b/app/Models/Thread.php index 44fa510bb..2babc5f77 100644 --- a/app/Models/Thread.php +++ b/app/Models/Thread.php @@ -3,6 +3,7 @@ namespace App\Models; use App\Concerns\HasAuthor; +use App\Concerns\HasEditLog; use App\Concerns\HasLikes; use App\Concerns\HasSlug; use App\Concerns\HasTags; @@ -30,6 +31,7 @@ final class Thread extends Model implements ReplyAble, SubscriptionAble, Feedabl { use HasFactory; use HasAuthor; + use HasEditLog; use HasLikes; use HasSlug; use HasTags; diff --git a/database/factories/EditFactory.php b/database/factories/EditFactory.php new file mode 100644 index 000000000..b925ab0ba --- /dev/null +++ b/database/factories/EditFactory.php @@ -0,0 +1,44 @@ +faker->randomElement([Article::class, Reply::class, Thread::class]); + $editableFactory = call_user_func([$editableClass, 'factory']); + + return [ + 'author_id' => function () { + return User::factory()->create()->id; + }, + 'editable_id' => function () use ($editableFactory) { + return $editableFactory->create()->id; + }, + 'editable_type' => function () use ($editableClass) { + return constant($editableClass.'::TABLE') ?? $editableClass; + }, + 'edited_at' => $this->faker->dateTimeThisMonth(), + ]; + } +} diff --git a/database/migrations/2021_11_05_194336_create_edits_table.php b/database/migrations/2021_11_05_194336_create_edits_table.php new file mode 100644 index 000000000..8ae7ceb79 --- /dev/null +++ b/database/migrations/2021_11_05_194336_create_edits_table.php @@ -0,0 +1,28 @@ +id(); + + $table->foreignIdFor(User::class, 'author_id'); + + $table->unsignedBigInteger('editable_id'); + $table->string('editable_type'); + + $table->timestamp('edited_at'); + }); + } +} diff --git a/resources/views/articles/show.blade.php b/resources/views/articles/show.blade.php index b1ae87cbd..aeae071e9 100644 --- a/resources/views/articles/show.blade.php +++ b/resources/views/articles/show.blade.php @@ -84,6 +84,14 @@ class="prose prose-lg text-gray-800 prose-lio" {!! $article->body() !!} + @if($article->latestEdit) +
+ Last edit by + {{ $article->latestEdit->author()->name() }} + on {{ $article->latestEdit->edited_at->format('j M, Y') }}. +
+ @endif +
diff --git a/resources/views/components/threads/reply.blade.php b/resources/views/components/threads/reply.blade.php index ca65a30d7..b5c81d9b5 100644 --- a/resources/views/components/threads/reply.blade.php +++ b/resources/views/components/threads/reply.blade.php @@ -31,6 +31,14 @@ class="prose prose-lio max-w-none p-6 break-words" >
+ @if($reply->latestEdit) +
+ Last edit by + {{ $reply->latestEdit->author()->name() }} + on {{ $reply->latestEdit->edited_at->format('j M, Y') }}. +
+ @endif +
diff --git a/resources/views/components/threads/thread.blade.php b/resources/views/components/threads/thread.blade.php index d6bce4c27..f6daeac0b 100644 --- a/resources/views/components/threads/thread.blade.php +++ b/resources/views/components/threads/thread.blade.php @@ -57,6 +57,14 @@ class="prose prose-lio max-w-none p-6 break-words" >
+ @if($thread->latestEdit) +
+ Last edit by + {{ $thread->latestEdit->author()->name() }} + on {{ $thread->latestEdit->edited_at->format('j M, Y') }}. +
+ @endif +