Merge branch 'master' into glitch-soc/merge-upstream
Conflicts: - Gemfile - Gemfile.lock - app/controllers/about_controller.rb - app/controllers/auth/sessions_controller.rb
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class ActivityTracker
|
||||
EXPIRE_AFTER = 90.days.seconds
|
||||
EXPIRE_AFTER = 6.months.seconds
|
||||
|
||||
class << self
|
||||
include Redisable
|
||||
|
||||
@@ -232,25 +232,40 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
|
||||
items = @object['oneOf']
|
||||
end
|
||||
|
||||
voters_count = @object['votersCount']
|
||||
|
||||
@account.polls.new(
|
||||
multiple: multiple,
|
||||
expires_at: expires_at,
|
||||
options: items.map { |item| item['name'].presence || item['content'] }.compact,
|
||||
cached_tallies: items.map { |item| item.dig('replies', 'totalItems') || 0 }
|
||||
cached_tallies: items.map { |item| item.dig('replies', 'totalItems') || 0 },
|
||||
voters_count: voters_count
|
||||
)
|
||||
end
|
||||
|
||||
def poll_vote?
|
||||
return false if replied_to_status.nil? || replied_to_status.preloadable_poll.nil? || !replied_to_status.local? || !replied_to_status.preloadable_poll.options.include?(@object['name'])
|
||||
|
||||
unless replied_to_status.preloadable_poll.expired?
|
||||
replied_to_status.preloadable_poll.votes.create!(account: @account, choice: replied_to_status.preloadable_poll.options.index(@object['name']), uri: @object['id'])
|
||||
ActivityPub::DistributePollUpdateWorker.perform_in(3.minutes, replied_to_status.id) unless replied_to_status.preloadable_poll.hide_totals?
|
||||
end
|
||||
poll_vote! unless replied_to_status.preloadable_poll.expired?
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
def poll_vote!
|
||||
poll = replied_to_status.preloadable_poll
|
||||
already_voted = true
|
||||
RedisLock.acquire(poll_lock_options) do |lock|
|
||||
if lock.acquired?
|
||||
already_voted = poll.votes.where(account: @account).exists?
|
||||
poll.votes.create!(account: @account, choice: poll.options.index(@object['name']), uri: @object['id'])
|
||||
else
|
||||
raise Mastodon::RaceConditionError
|
||||
end
|
||||
end
|
||||
increment_voters_count! unless already_voted
|
||||
ActivityPub::DistributePollUpdateWorker.perform_in(3.minutes, replied_to_status.id) unless replied_to_status.preloadable_poll.hide_totals?
|
||||
end
|
||||
|
||||
def resolve_thread(status)
|
||||
return unless status.reply? && status.thread.nil? && Request.valid_url?(in_reply_to_uri)
|
||||
ThreadResolveWorker.perform_async(status.id, in_reply_to_uri)
|
||||
@@ -416,7 +431,22 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
|
||||
ActivityPub::RawDistributionWorker.perform_async(Oj.dump(@json), replied_to_status.account_id, [@account.preferred_inbox_url])
|
||||
end
|
||||
|
||||
def increment_voters_count!
|
||||
poll = replied_to_status.preloadable_poll
|
||||
unless poll.voters_count.nil?
|
||||
poll.voters_count = poll.voters_count + 1
|
||||
poll.save
|
||||
end
|
||||
rescue ActiveRecord::StaleObjectError
|
||||
poll.reload
|
||||
retry
|
||||
end
|
||||
|
||||
def lock_options
|
||||
{ redis: Redis.current, key: "create:#{@object['id']}" }
|
||||
end
|
||||
|
||||
def poll_lock_options
|
||||
{ redis: Redis.current, key: "vote:#{replied_to_status.poll_id}:#{@account.id}" }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -21,7 +21,7 @@ class ActivityPub::Activity::Follow < ActivityPub::Activity
|
||||
|
||||
follow_request = FollowRequest.create!(account: @account, target_account: target_account, uri: @json['id'])
|
||||
|
||||
if target_account.locked?
|
||||
if target_account.locked? || @account.silenced?
|
||||
NotifyService.new.call(target_account, follow_request)
|
||||
else
|
||||
AuthorizeFollowService.new.call(@account, target_account)
|
||||
|
||||
@@ -19,11 +19,7 @@ class ActivityPub::Activity::Move < ActivityPub::Activity
|
||||
origin_account.update(moved_to_account: target_account)
|
||||
|
||||
# Initiate a re-follow for each follower
|
||||
origin_account.followers.local.select(:id).find_in_batches do |follower_accounts|
|
||||
UnfollowFollowWorker.push_bulk(follower_accounts.map(&:id)) do |follower_account_id|
|
||||
[follower_account_id, origin_account.id, target_account.id]
|
||||
end
|
||||
end
|
||||
MoveWorker.perform_async(origin_account.id, target_account.id)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -21,6 +21,7 @@ class ActivityPub::Adapter < ActiveModelSerializers::Adapter::Base
|
||||
identity_proof: { 'toot' => 'http://joinmastodon.org/ns#', 'IdentityProof' => 'toot:IdentityProof' },
|
||||
blurhash: { 'toot' => 'http://joinmastodon.org/ns#', 'blurhash' => 'toot:blurhash' },
|
||||
discoverable: { 'toot' => 'http://joinmastodon.org/ns#', 'discoverable' => 'toot:discoverable' },
|
||||
voters_count: { 'toot' => 'http://joinmastodon.org/ns#', 'votersCount' => 'toot:votersCount' },
|
||||
}.freeze
|
||||
|
||||
def self.default_key_transform
|
||||
|
||||
7
app/lib/nodeinfo/adapter.rb
Normal file
7
app/lib/nodeinfo/adapter.rb
Normal file
@@ -0,0 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class NodeInfo::Adapter < ActiveModelSerializers::Adapter::Attributes
|
||||
def self.default_key_transform
|
||||
:camel_lower
|
||||
end
|
||||
end
|
||||
69
app/lib/toc_generator.rb
Normal file
69
app/lib/toc_generator.rb
Normal file
@@ -0,0 +1,69 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class TOCGenerator
|
||||
TARGET_ELEMENTS = %w(h1 h2 h3 h4 h5 h6).freeze
|
||||
LISTED_ELEMENTS = %w(h2 h3).freeze
|
||||
|
||||
class Section
|
||||
attr_accessor :depth, :title, :children, :anchor
|
||||
|
||||
def initialize(depth, title, anchor)
|
||||
@depth = depth
|
||||
@title = title
|
||||
@children = []
|
||||
@anchor = anchor
|
||||
end
|
||||
|
||||
delegate :<<, to: :children
|
||||
end
|
||||
|
||||
def initialize(source_html)
|
||||
@source_html = source_html
|
||||
@processed = false
|
||||
@target_html = ''
|
||||
@headers = []
|
||||
@slugs = Hash.new { |h, k| h[k] = 0 }
|
||||
end
|
||||
|
||||
def html
|
||||
parse_and_transform unless @processed
|
||||
@target_html
|
||||
end
|
||||
|
||||
def toc
|
||||
parse_and_transform unless @processed
|
||||
@headers
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def parse_and_transform
|
||||
return if @source_html.blank?
|
||||
|
||||
parsed_html = Nokogiri::HTML.fragment(@source_html)
|
||||
|
||||
parsed_html.traverse do |node|
|
||||
next unless TARGET_ELEMENTS.include?(node.name)
|
||||
|
||||
anchor = node['id'] || node.text.parameterize.presence || 'sec'
|
||||
@slugs[anchor] += 1
|
||||
anchor = "#{anchor}-#{@slugs[anchor]}" if @slugs[anchor] > 1
|
||||
|
||||
node['id'] = anchor
|
||||
|
||||
next unless LISTED_ELEMENTS.include?(node.name)
|
||||
|
||||
depth = node.name[1..-1]
|
||||
latest_section = @headers.last
|
||||
|
||||
if latest_section.nil? || latest_section.depth >= depth
|
||||
@headers << Section.new(depth, node.text, anchor)
|
||||
else
|
||||
latest_section << Section.new(depth, node.text, anchor)
|
||||
end
|
||||
end
|
||||
|
||||
@target_html = parsed_html.to_s
|
||||
@processed = true
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user