Initial poll implementation - #2113
BentiGorlich wants to merge 8 commits into
Conversation
|
Open things:
|
ca5a66c to
21b69c7
Compare
- add the ability to add a poll to Entry, EntryComment, Post and PostComment - Polls: - can be multiple choice - can contain an unlimited number of choices - can expire - Add a hidden form for the poll to all create forms, the form appears when a checkbox is checked - The ActivityPub implementation is the same as on Mastodon: https://docs.joinmastodon.org/spec/activitypub/#Question - Add tests for the ActivityPub implementation and the Api controller - The api had to be shifted a bit -> the `serialize...` functions in the base api take only the entity classes now instead of their dto variant -> touched a lot of api classes because of this
- fix the end date being ignored upon poll creation - make the poll end date DATETIMETZ_IMMUTABLE -> with time zone - implement refreshing the vote counts of remote polls - fix handling of `Update` activities -> only edit the poll (and discarding all votes) when the content actually changed, pass through the correct object to refresh the poll counts - send an `Update` activity when a vote is created on a local poll - fix missing query from `EntryCommentRepository` and `PostCommentRepository` in the `PollVoteFactory` - add a way to invalidate the cache of an activity object - add support for the `closed` property on polls (it is the same as `endTime`) - add a way to just show the results of a poll in the UI
- if an object contains a poll, it needs to be of type 'Question' in the AP representation - update the testing snapshots - scrub the URL from `Question` object snapshots as well
94fdbef to
d227f4e
Compare
|
As I implemented all the remaining things a while back and now tested it on my server in combination with mastodon, I think this is ready |
- fix duplicate choices not being noticed - fix endDate not being assigned in the EntryFactory - fix choices not being part of the poll after being created - add tests for that
# Conflicts: # translations/messages.en.yaml
|
Just some small minor remarks;
|
- append the choice array of the poll, rather than refreshing the entity - move the test to the functional directory
| @@ -0,0 +1,24 @@ | |||
| .poll { | |||
| margin: auto; | |||
There was a problem hiding this comment.
Why centered instead of left-aligned?
| @@ -0,0 +1,33 @@ | |||
| <?php | |||
There was a problem hiding this comment.
This looks like dev code which should not be in prod.
| // Rate limiting already taken care of | ||
| $comment = $manager->create($dto, $this->getUserOrThrow(), rateLimit: false); | ||
| $dto = $factory->createDto($comment); | ||
| $dto->parent = $parent; |
There was a problem hiding this comment.
Whats up with this line? You removed the creation of the dto variable, but still use it here.
| // Rate limiting already taken care of | ||
| $comment = $manager->create($dto, $this->getUserOrThrow(), rateLimit: false); | ||
| $dto = $factory->createDto($comment); | ||
| $dto->parent = $parent; |
| )] | ||
| #[OA\Response( | ||
| response: 400, | ||
| description: 'Poll was not valid. Possibly: poll already ended, choices do not exist, user already voted', |
There was a problem hiding this comment.
user already voted
maybe return an HTTP "conflict" status instead of "bad request"
|
|
||
| $voteEntities = []; | ||
| foreach (array_unique($choices) as $choice) { | ||
| $choiceEntity = $poll->findChoice($choice); |
There was a problem hiding this comment.
This does not check if the choice is a valid one. As this function can be called with AP originating user content, it must be checked.
I suggest the check should throw an exception on invalid input. Then the check in the Controllers can be replaced with a try-catch which rethrow as a fitting Http-Exception.
|
|
||
| public function getContentOfPoll(Poll $poll): Entry|EntryComment|Post|PostComment|null | ||
| { | ||
| return $this->entryRepository->findOneBy(['poll' => $poll]) |
There was a problem hiding this comment.
why not poll->getSubject()?
| } | ||
|
|
||
| /** | ||
| * Call PollManager::canCreateFromApObject() first, this that $object contains all the necessary information. |
| } | ||
|
|
||
| /** | ||
| * Call PollManager::canCreateFromApObject() first, this that $payload contains all the necessary information. |
There was a problem hiding this comment.
this <-> that
Call PollManager::canCreateFromApObject() first, to ensure that $payload contains all the necessary information.
| self::assertNotNull($entry->poll->findChoice('C')); | ||
| self::assertEquals(1, $entry->poll->findChoice('C')->voteCount); | ||
| } | ||
|
|
There was a problem hiding this comment.
Some negative tests would be nice. Like activities with invalid choices, multiple votes for the same choice by the same user.
|
Is it planned that incoming votes to local polls will be federated out via Announces? |
| poll_vote: | ||
| controller: App\Controller\PollVoteController::vote | ||
| path: /poll/{id}/vote | ||
| methods: [GET] |
There was a problem hiding this comment.
Because voting is a one-time state change, exposing it as GET lets another site make a logged-in user vote by sending them to a crafted link. Please switch this route and the poll form to POST and validate a CSRF token.
serialize...functions in the base api take only the entity classes now instead of their dto variant -> touched a lot of api classes because of thisImages:
Each create form (Thread, Microblog, Comments) now have this checkbox to add a poll:

When checked it looks like this:

Once created it looks like this:

If you have voted it looks like this:

Closes #647