diff --git a/src/Api/Controllers/CreatePollController.php b/src/Api/Controllers/CreatePollController.php index d313b435..c06e9826 100644 --- a/src/Api/Controllers/CreatePollController.php +++ b/src/Api/Controllers/CreatePollController.php @@ -46,11 +46,12 @@ public function __construct(PostRepository $posts, Dispatcher $bus) protected function data(ServerRequestInterface $request, Document $document) { $postId = Arr::get($request->getParsedBody(), 'data.relationships.post.data.id'); + $actor = RequestUtil::getActor($request); return $this->bus->dispatch( new CreatePoll( - RequestUtil::getActor($request), - $this->posts->findOrFail($postId), + $actor, + $this->posts->findOrFail($postId, $actor), Arr::get($request->getParsedBody(), 'data.attributes') ) ); diff --git a/src/Api/Controllers/ListPollsController.php b/src/Api/Controllers/ListPollsController.php index e669f035..d8dfef4a 100644 --- a/src/Api/Controllers/ListPollsController.php +++ b/src/Api/Controllers/ListPollsController.php @@ -62,6 +62,7 @@ public function data(ServerRequestInterface $request, Document $document): Colle $results = $this->polls->queryVisibleTo($actor) ->select('polls.*') + //->whereNull('post_id') ->orderBy($sortIsDefault ? 'id' : $sort, 'desc') ->skip($offset) ->take($limit); diff --git a/src/Api/Serializers/PollSerializer.php b/src/Api/Serializers/PollSerializer.php index 9e99b72e..82d04354 100755 --- a/src/Api/Serializers/PollSerializer.php +++ b/src/Api/Serializers/PollSerializer.php @@ -12,6 +12,7 @@ namespace FoF\Polls\Api\Serializers; use Flarum\Api\Serializer\AbstractSerializer; +use Flarum\Api\Serializer\PostSerializer; use FoF\Polls\Poll; class PollSerializer extends AbstractSerializer @@ -45,6 +46,7 @@ protected function getDefaultAttributes($poll) 'canDelete' => $this->actor->can('delete', $poll), 'canSeeVoters' => $this->actor->can('seeVoters', $poll), 'canChangeVote' => $this->actor->can('changeVote', $poll), + 'isGlobal' => $poll->isGlobal(), ]; if ($this->actor->can('seeVoteCount', $poll)) { diff --git a/src/Poll.php b/src/Poll.php index abd9ef39..c448ac82 100755 --- a/src/Poll.php +++ b/src/Poll.php @@ -85,6 +85,11 @@ public static function build($question, $postId, $actorId, $endDate, $publicPoll return $poll; } + public function isGlobal(): bool + { + return $this->post_id === null; + } + /** * @return bool */ diff --git a/src/PollRepository.php b/src/PollRepository.php index 2118e506..cc585d80 100644 --- a/src/PollRepository.php +++ b/src/PollRepository.php @@ -47,4 +47,9 @@ public function findOrFail($id, User $actor = null): Poll { return $this->queryVisibleTo($actor)->findOrFail($id); } + + public function find($id, User $actor = null): ?Poll + { + return $this->queryVisibleTo($actor)->find($id); + } } diff --git a/tests/integration/api/CreatePollTest.php b/tests/integration/api/CreatePollTest.php new file mode 100644 index 00000000..21a76778 --- /dev/null +++ b/tests/integration/api/CreatePollTest.php @@ -0,0 +1,195 @@ +extension('fof-polls'); + + $this->prepareDatabase([ + 'users' => [ + $this->normalUser(), + ['id' => 3, 'username' => 'polluser', 'email' => 'polluser@machine.local', 'password' => 'too-obscure', 'is_email_confirmed' => true] + ], + 'discussions' => [ + ['id' => 1, 'title' => 'Discussion 1', 'comment_count' => 1, 'participant_count' => 1, 'created_at' => '2021-01-01 00:00:00'], + ], + 'posts' => [ + ['id' => 1, 'user_id' => 1, 'discussion_id' => 1, 'number' => 1, 'created_at' => '2021-01-01 00:00:00', 'content' => 'Post 1'], + ], + 'group_user' => [ + ['user_id' => 3, 'group_id' => 4], + ], + 'group_permission' => [ + ['permission' => 'discussion.polls.start', 'group_id' => 4], + ], + ]); + } + + private function authorizedUserProvider(): array + { + return [ + [1], + [3] + ]; + } + + private function unauthorizedUserProvider(): array + { + return [ + [2], + ]; + } + + /** + * @dataProvider authorizedUserProvider + * @test + */ + public function authorized_user_can_create_poll_in_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?', + '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); + + $response = $this->send( + $this->request( + 'GET', + '/api/fof/polls/' . $pollId, + [ + 'authenticatedAs' => $userId, + ] + ) + ); + + $this->assertEquals(200, $response->getStatusCode()); + + $json = json_decode($response->getBody()->getContents(), true); + + $this->assertFalse($json['data']['attributes']['isGlobal']); + } + + /** + * @dataProvider unauthorizedUserProvider + * @test + */ + public function unauthorized_user_cannot_create_poll_in_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?', + '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(422, $response->getStatusCode()); + $errors = json_decode($response->getBody()->getContents(), true)['errors']; + + $this->assertEquals('validation_error', $errors[0]['code']); + $this->assertEquals('/data/attributes/poll', $errors[0]['source']['pointer']); + } +}