From 3223f65ce3edfa60d0f77c8307963f6d14937cdc Mon Sep 17 00:00:00 2001 From: Toby Zerner Date: Tue, 23 Jun 2015 10:34:33 +0930 Subject: [PATCH] Allow author to delete discussion if there are no replies Also disallow the first post in a discussion to be deleted or hidden (thus preventing discussions with zero posts) closes flarum/core#90 closes flarum/core#92 --- .../forum/src/initializers/post-controls.js | 7 +++- ..._02_24_000000_create_discussions_table.php | 5 ++- .../Api/Serializers/DiscussionSerializer.php | 19 +++++---- .../Commands/EditPostCommandHandler.php | 19 +++++---- .../Events/DiscussionMetadataUpdater.php | 3 ++ .../core/src/Core/Models/CommentPost.php | 9 ++++ framework/core/src/Core/Models/Discussion.php | 41 +++++++++++++++---- framework/core/src/Core/Models/Post.php | 7 ++++ 8 files changed, 80 insertions(+), 30 deletions(-) diff --git a/framework/core/js/forum/src/initializers/post-controls.js b/framework/core/js/forum/src/initializers/post-controls.js index dfa378235..57ad1b53f 100644 --- a/framework/core/js/forum/src/initializers/post-controls.js +++ b/framework/core/js/forum/src/initializers/post-controls.js @@ -37,11 +37,14 @@ export default function(app) { items.add('restore', ActionButton.component({ icon: 'reply', label: 'Restore', onclick: restoreAction.bind(this) })); } else { items.add('edit', ActionButton.component({ icon: 'pencil', label: 'Edit', onclick: editAction.bind(this) })); - items.add('hide', ActionButton.component({ icon: 'times', label: 'Delete', onclick: hideAction.bind(this) })); + + if (this.number() != 1) { + items.add('hide', ActionButton.component({ icon: 'times', label: 'Delete', onclick: hideAction.bind(this) })); + } } } - if ((this.contentType() !== 'comment' || this.isHidden()) && this.canDelete()) { + if ((this.contentType() !== 'comment' || this.isHidden()) && this.canDelete() && this.number() != 1) { items.add('delete', ActionButton.component({ icon: 'times', label: 'Delete', onclick: deleteAction.bind(this) })); } diff --git a/framework/core/migrations/2015_02_24_000000_create_discussions_table.php b/framework/core/migrations/2015_02_24_000000_create_discussions_table.php index c64b53776..2f8a84bb8 100644 --- a/framework/core/migrations/2015_02_24_000000_create_discussions_table.php +++ b/framework/core/migrations/2015_02_24_000000_create_discussions_table.php @@ -15,16 +15,17 @@ class CreateDiscussionsTable extends Migration public function up() { Schema::create('discussions', function (Blueprint $table) { - + $table->increments('id'); $table->string('title', 200); $table->integer('comments_count')->unsigned()->default(0); + $table->integer('participants_count')->unsigned()->default(0); $table->integer('number_index')->unsigned()->default(0); $table->dateTime('start_time'); $table->integer('start_user_id')->unsigned()->nullable(); $table->integer('start_post_id')->unsigned()->nullable(); - + $table->dateTime('last_time')->nullable(); $table->integer('last_user_id')->unsigned()->nullable(); $table->integer('last_post_id')->unsigned()->nullable(); diff --git a/framework/core/src/Api/Serializers/DiscussionSerializer.php b/framework/core/src/Api/Serializers/DiscussionSerializer.php index e5f56edaf..f013d9805 100644 --- a/framework/core/src/Api/Serializers/DiscussionSerializer.php +++ b/framework/core/src/Api/Serializers/DiscussionSerializer.php @@ -16,16 +16,17 @@ class DiscussionSerializer extends DiscussionBasicSerializer $state = $discussion->stateFor($user); $attributes += [ - 'commentsCount' => (int) $discussion->comments_count, - 'startTime' => $discussion->start_time->toRFC3339String(), - 'lastTime' => $discussion->last_time ? $discussion->last_time->toRFC3339String() : null, - 'lastPostNumber' => $discussion->last_post_number, - 'canReply' => $discussion->can($user, 'reply'), - 'canRename' => $discussion->can($user, 'rename'), - 'canDelete' => $discussion->can($user, 'delete'), + 'commentsCount' => (int) $discussion->comments_count, + 'participantsCount' => (int) $discussion->participants_count, + 'startTime' => $discussion->start_time->toRFC3339String(), + 'lastTime' => $discussion->last_time ? $discussion->last_time->toRFC3339String() : null, + 'lastPostNumber' => $discussion->last_post_number, + 'canReply' => $discussion->can($user, 'reply'), + 'canRename' => $discussion->can($user, 'rename'), + 'canDelete' => $discussion->can($user, 'delete'), - 'readTime' => $state && $state->read_time ? $state->read_time->toRFC3339String() : null, - 'readNumber' => $state ? (int) $state->read_number : 0 + 'readTime' => $state && $state->read_time ? $state->read_time->toRFC3339String() : null, + 'readNumber' => $state ? (int) $state->read_number : 0 ]; return $this->extendAttributes($discussion, $attributes); diff --git a/framework/core/src/Core/Handlers/Commands/EditPostCommandHandler.php b/framework/core/src/Core/Handlers/Commands/EditPostCommandHandler.php index 50ed8fdea..8ad795cab 100644 --- a/framework/core/src/Core/Handlers/Commands/EditPostCommandHandler.php +++ b/framework/core/src/Core/Handlers/Commands/EditPostCommandHandler.php @@ -3,6 +3,7 @@ use Flarum\Core\Repositories\PostRepositoryInterface as PostRepository; use Flarum\Core\Events\PostWillBeSaved; use Flarum\Core\Support\DispatchesEvents; +use Flarum\Core\Models\CommentPost; class EditPostCommandHandler { @@ -22,15 +23,17 @@ class EditPostCommandHandler $post->assertCan($user, 'edit'); - if (isset($command->data['content'])) { - $post->revise($command->data['content'], $user); - } + if ($post instanceof CommentPost) { + if (isset($command->data['content'])) { + $post->revise($command->data['content'], $user); + } - if (isset($command->data['isHidden'])) { - if ($command->data['isHidden']) { - $post->hide($user); - } else { - $post->restore($user); + if (isset($command->data['isHidden'])) { + if ($command->data['isHidden']) { + $post->hide($user); + } else { + $post->restore($user); + } } } diff --git a/framework/core/src/Core/Handlers/Events/DiscussionMetadataUpdater.php b/framework/core/src/Core/Handlers/Events/DiscussionMetadataUpdater.php index b7b0c7312..2fdd27a27 100755 --- a/framework/core/src/Core/Handlers/Events/DiscussionMetadataUpdater.php +++ b/framework/core/src/Core/Handlers/Events/DiscussionMetadataUpdater.php @@ -28,6 +28,7 @@ class DiscussionMetadataUpdater $discussion->comments_count++; $discussion->setLastPost($event->post); + $discussion->refreshParticipantsCount(); $discussion->save(); } @@ -46,6 +47,7 @@ class DiscussionMetadataUpdater $discussion = $event->post->discussion; $discussion->refreshCommentsCount(); + $discussion->refreshParticipantsCount(); $discussion->refreshLastPost(); $discussion->save(); } @@ -56,6 +58,7 @@ class DiscussionMetadataUpdater if ($discussion->exists) { $discussion->refreshCommentsCount(); + $discussion->refreshParticipantsCount(); if ($discussion->last_post_id == $post->id) { $discussion->refreshLastPost(); diff --git a/framework/core/src/Core/Models/CommentPost.php b/framework/core/src/Core/Models/CommentPost.php index 2c63f695e..bf7ba92f4 100755 --- a/framework/core/src/Core/Models/CommentPost.php +++ b/framework/core/src/Core/Models/CommentPost.php @@ -5,6 +5,7 @@ use Flarum\Core\Events\PostWasPosted; use Flarum\Core\Events\PostWasRevised; use Flarum\Core\Events\PostWasHidden; use Flarum\Core\Events\PostWasRestored; +use Flarum\Core\Exceptions\ValidationFailureException; class CommentPost extends Post { @@ -75,6 +76,10 @@ class CommentPost extends Post */ public function hide($user) { + if ($this->number == 1) { + throw new ValidationFailureException; + } + if (! $this->hide_time) { $this->hide_time = time(); $this->hide_user_id = $user->id; @@ -93,6 +98,10 @@ class CommentPost extends Post */ public function restore($user) { + if ($this->number == 1) { + throw new ValidationFailureException; + } + if ($this->hide_time !== null) { $this->hide_time = null; $this->hide_user_id = null; diff --git a/framework/core/src/Core/Models/Discussion.php b/framework/core/src/Core/Models/Discussion.php index 3728d0d6b..fc338ef98 100755 --- a/framework/core/src/Core/Models/Discussion.php +++ b/framework/core/src/Core/Models/Discussion.php @@ -20,15 +20,16 @@ class Discussion extends Model * @var array */ public static $rules = [ - 'title' => 'required', - 'start_time' => 'required|date', - 'comments_count' => 'integer', - 'start_user_id' => 'integer', - 'start_post_id' => 'integer', - 'last_time' => 'date', - 'last_user_id' => 'integer', - 'last_post_id' => 'integer', - 'last_post_number' => 'integer' + 'title' => 'required', + 'start_time' => 'required|date', + 'comments_count' => 'integer', + 'participants_count' => 'integer', + 'start_user_id' => 'integer', + 'start_post_id' => 'integer', + 'last_time' => 'date', + 'last_user_id' => 'integer', + 'last_post_id' => 'integer', + 'last_post_number' => 'integer' ]; protected static $relationships = []; @@ -175,6 +176,18 @@ class Discussion extends Model return $this; } + /** + * Refresh the discussion's participants count. + * + * @return $this + */ + public function refreshParticipantsCount() + { + $this->participants_count = $this->participants()->count('users.id'); + + return $this; + } + /** * Specify that a post was added to this discussion during this request * for later retrieval. @@ -255,6 +268,16 @@ class Discussion extends Model return $this->posts()->where('type', 'comment')->whereNull('hide_time'); } + /** + * Define the relationship with the discussion's participants. + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function participants() + { + return User::join('posts', 'posts.user_id', '=', 'users.id')->where('posts.discussion_id', $this->id)->select('users.*')->distinct(); + } + /** * Define the relationship with the discussion's first post. * diff --git a/framework/core/src/Core/Models/Post.php b/framework/core/src/Core/Models/Post.php index baaef5045..0596a99a6 100755 --- a/framework/core/src/Core/Models/Post.php +++ b/framework/core/src/Core/Models/Post.php @@ -2,6 +2,7 @@ use Flarum\Core\Events\PostWasDeleted; use Flarum\Core\Support\Locked; +use Flarum\Core\Exceptions\ValidationFailureException; class Post extends Model { @@ -74,6 +75,12 @@ class Post extends Model $post->discussion->save(); }); + static::deleting(function ($post) { + if ($post->number == 1) { + throw new ValidationFailureException; + } + }); + static::deleted(function ($post) { $post->raise(new PostWasDeleted($post)); });