Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add polls #10111

Merged
merged 9 commits into from
Mar 3, 2019
Merged

Add polls #10111

merged 9 commits into from
Mar 3, 2019

Conversation

Gargron
Copy link
Member

@Gargron Gargron commented Feb 25, 2019

Fix #1629


TODO:

  • Database schema
  • Attach to statuses model
  • Serialize to REST API
  • REST API for creating
  • REST API for voting
  • Prevent double-voting
  • REST API for retrieving results
  • Serialize poll to ActivityPub
  • Serialize voting to ActivityPub
  • Parse remote polls from ActivityPub
  • Handle incoming votes
  • Fetch latest results of remote polls from ActivityPub on demand
  • Web UI component for displaying polls
  • Tests

TODO in separate PRs:

  • Web UI component for creating polls

@Gargron Gargron added work in progress Not to be merged, currently being worked on api REST API, Streaming API, Web Push API activitypub Protocol-related changes, federation labels Feb 25, 2019
@tateisu
Copy link
Contributor

tateisu commented Feb 25, 2019

How do we see this from the ActivityPub?

There is a version of friends.nico as an existing implementation.
In the case of friends.nico, voting has time limit. The result was output as another post.

@Gargron
Copy link
Member Author

Gargron commented Feb 25, 2019

How do we see this from the ActivityPub?

In my understanding, when a poll is attached to a status, the status should have type Question instead of Note, and contain oneOf/anyOf/closed properties. I do not know yet how exactly the vote counts would be represented. Perhaps the items inside oneOf/anyOf would have a replies property containing a Collection with totalItems...

In the case of friends.nico, voting has time limit.

Represented here by expires_at property (optional). Although perhaps it should not be optional, who ever needs infinite polls?

@Gargron Gargron force-pushed the feature-polls branch 6 times, most recently from 8e99cfb to b0d0db6 Compare February 26, 2019 03:00
@Gargron Gargron force-pushed the feature-polls branch 13 times, most recently from a7d0e9f to 63a1a44 Compare March 2, 2019 23:13
@Gargron Gargron force-pushed the feature-polls branch 5 times, most recently from 16ac9ae to 4ffe700 Compare March 3, 2019 02:35
@Gargron Gargron removed the work in progress Not to be merged, currently being worked on label Mar 3, 2019
@Gargron Gargron marked this pull request as ready for review March 3, 2019 02:35
Copy link
Contributor

@ClearlyClaire ClearlyClaire left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, I like this PR, but I have some concerns. Mainly, we make a few arbitrary choices that may not work well with other implementations:

  • as far as I can see, we don't allow for changing votes, that is, neither deleting existing votes, nor overwriting existing ones. If other implementations allow this, we don't have a correct error path to notify them that their vote is invalid. This may lead to inconsistent user experience.
  • polls and media being mutually exclusive kind of makes sense with the current UI, but other software might have different interfaces and not have that limit
  • the number of replies etc. are quite arbitrary and might also be an issue

An interesting thing is that polls being tied to a Note, they are only visible to the audience of that Note. However, the voting code does not seem to enforce that only the audience can vote. It might be worth tightening those restrictions.

Finally, we could send and support Update of the poll/its collections to update the tallies without the need for fetching changes.

app/controllers/api/v1/statuses_controller.rb Show resolved Hide resolved
app/lib/activitypub/activity/create.rb Show resolved Hide resolved
app/lib/activitypub/activity/create.rb Show resolved Hide resolved
app/lib/activitypub/activity/create.rb Show resolved Hide resolved
app/models/poll.rb Outdated Show resolved Hide resolved
app/serializers/activitypub/note_serializer.rb Outdated Show resolved Hide resolved
poll.update!(
expires_at: expires_at,
cached_tallies: items.map { |item| item.dig('replies', 'totalItems') || 0 }
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same remark as earlier, what about fetching collections that aren't inlined?
Furthermore, if the poll has changed since it was initially fetched, this code will produce inconsistent tallies.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Furthermore, if the poll has changed since it was initially fetched, this code will produce inconsistent tallies.

I don't understand what you mean. This is fetched from the origin, for remote polls. The origin has the most correct count of votes.

Copy link
Contributor

@ClearlyClaire ClearlyClaire Mar 3, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I meant that if the list of options changed (which nothing in the specs forbids), the updated tallies are going to be garbage.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think updating the options of published polls should be allowed. That invalidates the results.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could reorder them or add requested options, I don't know. I think we should at least update tallies based on name, not on the option's position in the serialization.

app/validators/poll_validator.rb Show resolved Hide resolved
app/validators/poll_validator.rb Show resolved Hide resolved
@ClearlyClaire
Copy link
Contributor

I'm also thinking that, in the case we can't manage getting tallies from the remote server (because there is nothing standardized for that and the suggested solution is the Question's replies thing, which we do not want), we should offer to go to the remote public page to see the results.

Also, aren't we missing code to display the poll on public pages?

@@ -250,6 +255,8 @@ def decrement_count!(key)
before_validation :set_conversation
before_validation :set_local

before_save :set_poll_id
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can use a normal association instead of this, now, can't we?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have this throwaway inverse reference to polls so that during eager-loading we can skip queries on the polls table when no statuses have polls, which I believe would be the most common case.

@@ -0,0 +1,5 @@
class AddPollIdToStatuses < ActiveRecord::Migration[5.2]
def change
add_column :statuses, :poll_id, :bigint
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same goes here, we can use a foreign key.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think foreign keys are an increasingly bad idea. It requires having an index on that column, otherwise DELETE or NULLIFY cascades take an incredible amount of time. Any index on statuses would also be massive.

Copy link
Contributor

@ClearlyClaire ClearlyClaire left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think poll_vote? is still very confusing, fallback for remote implementations not using our replies scheme should be considered, limits could be tweaked, and we could investigate sending Updates and fetching the size of replies collections identified by an URI instead of being inlined, but that's all stuff that can be done later.

@Gargron Gargron merged commit 230a012 into master Mar 3, 2019
@Gargron Gargron deleted the feature-polls branch March 3, 2019 21:18
@mattcoxonline
Copy link

Do you have a design for the creation of polls in the web UI, @Gargron ? Want me to create some mocks?

@Gargron
Copy link
Member Author

Gargron commented Mar 5, 2019

@mattcoxonline I do not have a design. You can give it a go...

hiyuki2578 pushed a commit to ProjectMyosotis/mastodon that referenced this pull request Oct 2, 2019
* Add polls

Fix mastodon#1629

* Add tests

* Fixes

* Change API for creating polls

* Use name instead of content for votes

* Remove poll validation for remote polls

* Add polls to public pages

* When updating the poll, update options just in case they were changed

* Fix public pages showing both poll and other media
messenjahofchrist pushed a commit to Origin-Creative/mastodon that referenced this pull request Jul 30, 2021
* Add polls

Fix mastodon#1629

* Add tests

* Fixes

* Change API for creating polls

* Use name instead of content for votes

* Remove poll validation for remote polls

* Add polls to public pages

* When updating the poll, update options just in case they were changed

* Fix public pages showing both poll and other media
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
activitypub Protocol-related changes, federation api REST API, Streaming API, Web Push API
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants