From f2e6f32311378fd0793667f8513ae57420b584ef Mon Sep 17 00:00:00 2001 From: IanM Date: Thu, 15 Feb 2024 12:19:14 +0000 Subject: [PATCH 1/2] feat: optional poll subtitle --- js/src/forum/components/CreatePollModal.js | 13 ++ js/src/forum/components/EditPollModal.js | 2 + js/src/forum/components/PostPoll.js | 41 +++--- js/src/forum/models/Poll.ts | 4 + ...02_15_000000_modify_polls_add_subtitle.php | 27 ++++ resources/less/forum.less | 6 +- resources/locale/en.yml | 1 + src/Api/AddPostAttributes.php | 5 +- src/Api/Serializers/PollSerializer.php | 1 + src/Commands/CreatePollHandler.php | 1 + src/Commands/EditPollHandler.php | 4 + src/Poll.php | 10 +- tests/integration/api/CreatePollTest.php | 124 ++++++++++++++++++ 13 files changed, 215 insertions(+), 24 deletions(-) create mode 100644 migrations/2024_02_15_000000_modify_polls_add_subtitle.php diff --git a/js/src/forum/components/CreatePollModal.js b/js/src/forum/components/CreatePollModal.js index 6eace313..1d1e7c6f 100755 --- a/js/src/forum/components/CreatePollModal.js +++ b/js/src/forum/components/CreatePollModal.js @@ -15,6 +15,7 @@ export default class CreatePollModal extends Modal { this.optionImageUrls = [Stream(''), Stream('')]; this.question = Stream(''); + this.subtitle = Stream(''); this.endDate = Stream(); @@ -38,6 +39,7 @@ export default class CreatePollModal extends Modal { }); this.question(poll.question); + this.subtitle(poll.subtitle); this.publicPoll(poll.publicPoll); this.hideVotes(poll.hideVotes); this.allowChangeVote(poll.allowChangeVote); @@ -82,6 +84,16 @@ export default class CreatePollModal extends Modal { 100 ); + items.add( + 'subtitle', +
+ + + +
, + 95 + ); + items.add( 'answers',
@@ -266,6 +278,7 @@ export default class CreatePollModal extends Modal { data() { const poll = { question: this.question(), + subtitle: this.subtitle(), endDate: this.dateToTimestamp(this.endDate()), publicPoll: this.publicPoll(), hideVotes: this.hideVotes(), diff --git a/js/src/forum/components/EditPollModal.js b/js/src/forum/components/EditPollModal.js index 23203a35..175ec29a 100755 --- a/js/src/forum/components/EditPollModal.js +++ b/js/src/forum/components/EditPollModal.js @@ -15,6 +15,7 @@ export default class EditPollModal extends CreatePollModal { this.optionAnswers = this.options.map((o) => Stream(o.answer())); this.optionImageUrls = this.options.map((o) => Stream(o.imageUrl())); this.question = Stream(this.poll.question()); + this.subtitle = Stream(this.poll.subtitle()); this.endDate = Stream(this.formatDate(this.poll.endDate())); this.publicPoll = Stream(this.poll.publicPoll()); this.allowMultipleVotes = Stream(this.poll.allowMultipleVotes()); @@ -95,6 +96,7 @@ export default class EditPollModal extends CreatePollModal { return { question: this.question(), + subtitle: this.subtitle(), endDate: this.dateToTimestamp(this.endDate()), publicPoll: this.publicPoll(), hideVotes: this.hideVotes(), diff --git a/js/src/forum/components/PostPoll.js b/js/src/forum/components/PostPoll.js index c312f98e..49583ba7 100644 --- a/js/src/forum/components/PostPoll.js +++ b/js/src/forum/components/PostPoll.js @@ -46,24 +46,29 @@ export default class PostPoll extends Component { return (
-

{poll.question()}

- - {poll.canSeeVoters() && ( - -
diff --git a/js/src/forum/models/Poll.ts b/js/src/forum/models/Poll.ts index 583c4d64..16d34c68 100755 --- a/js/src/forum/models/Poll.ts +++ b/js/src/forum/models/Poll.ts @@ -7,6 +7,10 @@ export default class Poll extends Model { return Model.attribute('question').call(this); } + subtitle() { + return Model.attribute('subtitle').call(this); + } + hasEnded() { return Model.attribute('hasEnded').call(this); } diff --git a/migrations/2024_02_15_000000_modify_polls_add_subtitle.php b/migrations/2024_02_15_000000_modify_polls_add_subtitle.php new file mode 100644 index 00000000..d7036bcc --- /dev/null +++ b/migrations/2024_02_15_000000_modify_polls_add_subtitle.php @@ -0,0 +1,27 @@ + function (Builder $schema) { + $schema->table('polls', function (Blueprint $table) { + $table->text('subtitle')->nullable()->after('question'); + }); + }, + 'down' => function (Builder $schema) { + $schema->table('polls', function (Blueprint $table) { + $table->dropColumn('subtitle'); + }); + }, + ]; + \ No newline at end of file diff --git a/resources/less/forum.less b/resources/less/forum.less index 8aef57c9..7cbaab96 100755 --- a/resources/less/forum.less +++ b/resources/less/forum.less @@ -164,7 +164,7 @@ align-items: baseline; gap: 10px; - &-title { + &-title-container { flex-grow: 1; } @@ -172,6 +172,10 @@ .Button--color-auto('button-primary'); } + &-actions { + + } + .Button { flex-shrink: 1; padding: 6px 10px; diff --git a/resources/locale/en.yml b/resources/locale/en.yml index 8d1181ff..1adccb4a 100755 --- a/resources/locale/en.yml +++ b/resources/locale/en.yml @@ -50,6 +50,7 @@ fof-polls: hide_votes_label: Hide votes until poll ends allow_change_vote_label: Allow users to change their vote question_placeholder: Question + subtitle_placeholder: Subtitle/Description (Optional) submit: Submit moderation: diff --git a/src/Api/AddPostAttributes.php b/src/Api/AddPostAttributes.php index bb206dfd..3430b9a8 100644 --- a/src/Api/AddPostAttributes.php +++ b/src/Api/AddPostAttributes.php @@ -11,9 +11,12 @@ namespace FoF\Polls\Api; +use Flarum\Api\Serializer\PostSerializer; +use Flarum\Post\Post; + class AddPostAttributes { - public function __invoke($serializer, $post, $attributes) + public function __invoke(PostSerializer $serializer, Post $post, array $attributes): array { $attributes['canStartPoll'] = $serializer->getActor()->can('startPoll', $post); diff --git a/src/Api/Serializers/PollSerializer.php b/src/Api/Serializers/PollSerializer.php index 52a7bcdd..13424e32 100755 --- a/src/Api/Serializers/PollSerializer.php +++ b/src/Api/Serializers/PollSerializer.php @@ -34,6 +34,7 @@ protected function getDefaultAttributes($poll) $attributes = [ 'question' => $poll->question, + 'subtitle' => $poll->subtitle, 'hasEnded' => $poll->hasEnded(), 'allowMultipleVotes' => $poll->allow_multiple_votes, 'maxVotes' => $poll->max_votes, diff --git a/src/Commands/CreatePollHandler.php b/src/Commands/CreatePollHandler.php index 3d3ecf8e..674fd4de 100644 --- a/src/Commands/CreatePollHandler.php +++ b/src/Commands/CreatePollHandler.php @@ -110,6 +110,7 @@ public function handle(CreatePoll $command) Arr::get($attributes, 'maxVotes'), Arr::get($attributes, 'hideVotes'), Arr::get($attributes, 'allowChangeVote'), + Arr::get($attributes, 'subtitle') ); $this->events->dispatch(new SavingPollAttributes($command->actor, $poll, $attributes, $attributes)); diff --git a/src/Commands/EditPollHandler.php b/src/Commands/EditPollHandler.php index a31da2ce..cb6a424d 100755 --- a/src/Commands/EditPollHandler.php +++ b/src/Commands/EditPollHandler.php @@ -72,6 +72,10 @@ public function handle(EditPoll $command) $poll->question = $attributes['question']; } + if (isset($attributes['subtitle'])) { + $poll->subtitle = empty($attributes['subtitle']) ? null : $attributes['subtitle']; + } + foreach (['publicPoll', 'allowMultipleVotes', 'hideVotes', 'allowChangeVote'] as $key) { if (isset($attributes[$key])) { $poll->settings[Str::snake($key)] = (bool) $attributes[$key]; diff --git a/src/Poll.php b/src/Poll.php index c448ac82..2b1deccb 100755 --- a/src/Poll.php +++ b/src/Poll.php @@ -20,8 +20,9 @@ use Illuminate\Support\Arr; /** - * @property int $id - * @property string $question + * @property int $id + * @property string $question + * @property string|null $subtitle * @property-read bool $public_poll * @property-read bool $allow_multiple_votes * @property-read int $max_votes @@ -30,7 +31,7 @@ * @property int $vote_count * @property Post $post * @property User $user - * @property int $post_id + * @property int|null $post_id * @property int $user_id * @property \Carbon\Carbon|null $end_date * @property \Carbon\Carbon $created_at @@ -66,11 +67,12 @@ class Poll extends AbstractModel * * @return static */ - public static function build($question, $postId, $actorId, $endDate, $publicPoll, $allowMultipleVotes = false, $maxVotes = 0, $hideVotes = false, $allowChangeVote = true) + public static function build($question, $postId, $actorId, $endDate, $publicPoll, $allowMultipleVotes = false, $maxVotes = 0, $hideVotes = false, $allowChangeVote = true, $subtitle = null) { $poll = new static(); $poll->question = $question; + $poll->subtitle = $subtitle; $poll->post_id = $postId; $poll->user_id = $actorId; $poll->end_date = $endDate; diff --git a/tests/integration/api/CreatePollTest.php b/tests/integration/api/CreatePollTest.php index edcd1e6a..0ed697f7 100644 --- a/tests/integration/api/CreatePollTest.php +++ b/tests/integration/api/CreatePollTest.php @@ -128,6 +128,7 @@ public function authorized_user_can_create_poll_in_post(int $userId) $this->assertNotNull($poll); $this->assertEquals('What is your favourite colour?', $poll->question); + $this->assertNull($poll->subtitle); $response = $this->send( $this->request( @@ -258,6 +259,7 @@ public function authorized_user_can_create_post_poll_on_api(int $userId) $attributes = $data['attributes']; $this->assertEquals('Add a poll to an existing post', $attributes['question']); + $this->assertNull($attributes['subtitle']); $pollId = $data['id']; $this->assertNotNull($pollId); @@ -411,6 +413,7 @@ public function authorized_user_can_create_global_poll_on_api(int $userId) $attributes = $data['attributes']; $this->assertEquals('Add a global poll', $attributes['question']); + $this->assertNull($attributes['subtitle']); $pollId = $data['id']; $this->assertNotNull($pollId); @@ -476,4 +479,125 @@ public function unauthorized_user_cannot_create_global_poll_on_api(int $userId) $this->assertEquals(403, $response->getStatusCode()); } + + /** + * @dataProvider authorizedUserProvider + * + * @test + */ + public function authorized_user_can_create_a_poll_with_a_subtitle_via_api(int $userId) + { + $response = $this->send( + $this->request( + 'POST', + '/api/fof/polls', + [ + 'authenticatedAs' => $userId, + 'json' => [ + 'data' => [ + 'attributes' => [ + 'question' => 'Add a poll with a subtitle', + 'subtitle' => 'This is a subtitle', + 'publicPoll' => false, + 'hideVotes' => false, + 'allowChangeVote' => true, + 'allowMultipleVotes' => false, + 'maxVotes' => 0, + 'endDate' => false, + 'options' => [ + [ + 'answer' => 'Yes', + ], + [ + 'answer' => 'No', + ], + ], + ], + ], + ], + ] + ) + ); + + $this->assertEquals(201, $response->getStatusCode()); + + $json = json_decode($response->getBody()->getContents(), true); + + $data = $json['data']; + $attributes = $data['attributes']; + + $this->assertEquals('Add a poll with a subtitle', $attributes['question']); + $this->assertEquals('This is a subtitle', $attributes['subtitle']); + } + + /** + * @dataProvider authorizedUserProvider + * + * @test + */ + public function authorized_user_can_create_a_poll_with_a_subtitle_via_post(int $userId) + { + $response = $this->send( + $this->request( + 'POST', + '/api/posts', + [ + 'authenticatedAs' => $userId, + 'json' => [ + 'data' => [ + 'attributes' => [ + 'content' => 'Here is my poll', + 'poll' => [ + 'question' => 'What is your favourite colour?', + 'subtitle' => 'This is a subtitle', + 'publicPoll' => false, + 'hideVotes' => false, + 'allowChangeVote' => true, + 'allowMultipleVotes' => false, + 'maxVotes' => 0, + 'endDate' => false, + 'options' => [ + [ + 'answer' => 'Red', + ], + [ + 'answer' => 'Blue', + ], + [ + 'answer' => 'Yellow', + ], + ], + ], + ], + 'relationships' => [ + 'discussion' => [ + 'data' => [ + 'type' => 'discussions', + 'id' => 1, + ], + ], + ], + ], + ], + ] + ) + ); + + $this->assertEquals(201, $response->getStatusCode()); + + $json = json_decode($response->getBody()->getContents(), true); + $data = $json['data']; + + $this->assertArrayHasKey('polls', $data['relationships']); + + $pollId = $data['relationships']['polls']['data'][0]['id']; + $this->assertNotNull($pollId); + + $poll = Poll::find($pollId); + + $this->assertNotNull($poll); + + $this->assertEquals('What is your favourite colour?', $poll->question); + $this->assertEquals('This is a subtitle', $poll->subtitle); + } } From ce20ae8b3b335ca88a92962deab85d20cd21a1b3 Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Thu, 15 Feb 2024 12:19:33 +0000 Subject: [PATCH 2/2] Apply fixes from StyleCI --- ...02_15_000000_modify_polls_add_subtitle.php | 31 ++++++++--------- src/Poll.php | 6 ++-- tests/integration/api/CreatePollTest.php | 34 +++++++++---------- 3 files changed, 35 insertions(+), 36 deletions(-) diff --git a/migrations/2024_02_15_000000_modify_polls_add_subtitle.php b/migrations/2024_02_15_000000_modify_polls_add_subtitle.php index d7036bcc..b23399a3 100644 --- a/migrations/2024_02_15_000000_modify_polls_add_subtitle.php +++ b/migrations/2024_02_15_000000_modify_polls_add_subtitle.php @@ -9,19 +9,18 @@ * file that was distributed with this source code. */ - use Illuminate\Database\Schema\Blueprint; - use Illuminate\Database\Schema\Builder; - - return [ - 'up' => function (Builder $schema) { - $schema->table('polls', function (Blueprint $table) { - $table->text('subtitle')->nullable()->after('question'); - }); - }, - 'down' => function (Builder $schema) { - $schema->table('polls', function (Blueprint $table) { - $table->dropColumn('subtitle'); - }); - }, - ]; - \ No newline at end of file +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Database\Schema\Builder; + +return [ + 'up' => function (Builder $schema) { + $schema->table('polls', function (Blueprint $table) { + $table->text('subtitle')->nullable()->after('question'); + }); + }, + 'down' => function (Builder $schema) { + $schema->table('polls', function (Blueprint $table) { + $table->dropColumn('subtitle'); + }); + }, +]; diff --git a/src/Poll.php b/src/Poll.php index 2b1deccb..ad759dab 100755 --- a/src/Poll.php +++ b/src/Poll.php @@ -20,9 +20,9 @@ use Illuminate\Support\Arr; /** - * @property int $id - * @property string $question - * @property string|null $subtitle + * @property int $id + * @property string $question + * @property string|null $subtitle * @property-read bool $public_poll * @property-read bool $allow_multiple_votes * @property-read int $max_votes diff --git a/tests/integration/api/CreatePollTest.php b/tests/integration/api/CreatePollTest.php index 0ed697f7..2975bc5a 100644 --- a/tests/integration/api/CreatePollTest.php +++ b/tests/integration/api/CreatePollTest.php @@ -496,15 +496,15 @@ public function authorized_user_can_create_a_poll_with_a_subtitle_via_api(int $u 'json' => [ 'data' => [ 'attributes' => [ - 'question' => 'Add a poll with a subtitle', - 'subtitle' => 'This is a subtitle', - 'publicPoll' => false, - 'hideVotes' => false, - 'allowChangeVote' => true, + 'question' => 'Add a poll with a subtitle', + 'subtitle' => 'This is a subtitle', + 'publicPoll' => false, + 'hideVotes' => false, + 'allowChangeVote' => true, 'allowMultipleVotes' => false, - 'maxVotes' => 0, - 'endDate' => false, - 'options' => [ + 'maxVotes' => 0, + 'endDate' => false, + 'options' => [ [ 'answer' => 'Yes', ], @@ -548,15 +548,15 @@ public function authorized_user_can_create_a_poll_with_a_subtitle_via_post(int $ 'attributes' => [ 'content' => 'Here is my poll', 'poll' => [ - 'question' => 'What is your favourite colour?', - 'subtitle' => 'This is a subtitle', - 'publicPoll' => false, - 'hideVotes' => false, - 'allowChangeVote' => true, + 'question' => 'What is your favourite colour?', + 'subtitle' => 'This is a subtitle', + 'publicPoll' => false, + 'hideVotes' => false, + 'allowChangeVote' => true, 'allowMultipleVotes' => false, - 'maxVotes' => 0, - 'endDate' => false, - 'options' => [ + 'maxVotes' => 0, + 'endDate' => false, + 'options' => [ [ 'answer' => 'Red', ], @@ -573,7 +573,7 @@ public function authorized_user_can_create_a_poll_with_a_subtitle_via_post(int $ 'discussion' => [ 'data' => [ 'type' => 'discussions', - 'id' => 1, + 'id' => 1, ], ], ],