From 3a92885a860df12b12d8356faf179a3fc63be6f2 Mon Sep 17 00:00:00 2001 From: ThibG Date: Mon, 11 Mar 2019 00:49:31 +0100 Subject: Support pushing and receiving updates to poll tallies (#10209) * Process incoming poll tallies update * Send Update on poll vote * Do not send Updates for a poll more often than once every 3 minutes * Include voters in people to notify of results update * Schedule closing poll worker on poll creation * Add new notification type for ending polls * Add front-end support for ended poll notifications * Fix UpdatePollSerializer * Fix Updates not being triggered by local votes * Fix tests failure * Fix web push notifications for closing polls * Minor cleanup * Notify voters of both remote and local polls when those close * Fix delivery of poll updates to mentioned accounts and voters --- app/services/activitypub/process_poll_service.rb | 64 ++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 app/services/activitypub/process_poll_service.rb (limited to 'app/services/activitypub/process_poll_service.rb') diff --git a/app/services/activitypub/process_poll_service.rb b/app/services/activitypub/process_poll_service.rb new file mode 100644 index 000000000..ee248169d --- /dev/null +++ b/app/services/activitypub/process_poll_service.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +class ActivityPub::ProcessPollService < BaseService + include JsonLdHelper + + def call(poll, json) + @json = json + return unless supported_context? && expected_type? + + previous_expires_at = poll.expires_at + + expires_at = begin + if @json['closed'].is_a?(String) + @json['closed'] + elsif !@json['closed'].nil? && !@json['closed'].is_a?(FalseClass) + Time.now.utc + else + @json['endTime'] + end + end + + items = begin + if @json['anyOf'].is_a?(Array) + @json['anyOf'] + else + @json['oneOf'] + end + end + + latest_options = items.map { |item| item['name'].presence || item['content'] } + + # If for some reasons the options were changed, it invalidates all previous + # votes, so we need to remove them + poll.votes.delete_all if latest_options != poll.options + + begin + poll.update!( + last_fetched_at: Time.now.utc, + expires_at: expires_at, + options: latest_options, + cached_tallies: items.map { |item| item.dig('replies', 'totalItems') || 0 } + ) + rescue ActiveRecord::StaleObjectError + poll.reload + retry + end + + # If the poll had no expiration date set but now has, and people have voted, + # schedule a notification. + if previous_expires_at.nil? && poll.expires_at.present? && poll.votes.exists? + PollExpirationNotifyWorker.perform_at(poll.expires_at + 5.minutes, poll.id) + end + end + + private + + def supported_context? + super(@json) + end + + def expected_type? + equals_or_includes_any?(@json['type'], %w(Question)) + end +end -- cgit