mirror of
https://github.com/glitch-soc/mastodon
synced 2025-04-24 15:24:51 +00:00
Merge commit 'c43508b3e0b05c5e739d726bad53f1eef89e9376' into glitch-soc/merge-upstream
Conflicts: - `app/lib/content_security_policy.rb`: Upstream added support for `EXTRA_MEDIA_HOSTS` which is very similar to glitch-soc's `EXTRA_DATA_HOST`. Deprecate `EXTRA_DATA_HOST` FOR `EXTRA_MEDIA_HOST`.
This commit is contained in:
commit
449dc30739
13 changed files with 196 additions and 40 deletions
|
@ -309,6 +309,9 @@ MAX_POLL_OPTION_CHARS=100
|
|||
# HCAPTCHA_SECRET_KEY=
|
||||
# HCAPTCHA_SITE_KEY=
|
||||
|
||||
# Optional list of hosts that are allowed to serve media for your instance
|
||||
# EXTRA_MEDIA_HOSTS=https://data.example1.com,https://data.example2.com
|
||||
|
||||
# IP and session retention
|
||||
# -----------------------
|
||||
# Make sure to modify the scheduling of ip_cleanup_scheduler in config/sidekiq.yml
|
||||
|
|
|
@ -81,9 +81,14 @@
|
|||
"alert.rate_limited.title": "Feur bevennet",
|
||||
"alert.unexpected.message": "Ur fazi dic'hortozet zo degouezhet.",
|
||||
"alert.unexpected.title": "Hopala !",
|
||||
"alt_text_modal.cancel": "Nullañ",
|
||||
"alt_text_modal.change_thumbnail": "Kemmañ ar velvenn",
|
||||
"alt_text_modal.done": "Graet",
|
||||
"announcement.announcement": "Kemennad",
|
||||
"annual_report.summary.followers.followers": "heulier",
|
||||
"annual_report.summary.highlighted_post.possessive": "{name}",
|
||||
"annual_report.summary.most_used_hashtag.none": "Hini ebet",
|
||||
"annual_report.summary.new_posts.new_posts": "toudoù nevez",
|
||||
"attachments_list.unprocessed": "(ket meret)",
|
||||
"audio.hide": "Kuzhat ar c'hleved",
|
||||
"block_modal.show_less": "Diskouez nebeutoc'h",
|
||||
|
@ -109,9 +114,11 @@
|
|||
"column.blocks": "Implijer·ezed·ien berzet",
|
||||
"column.bookmarks": "Sinedoù",
|
||||
"column.community": "Red-amzer lec'hel",
|
||||
"column.create_list": "Krouiñ ul listenn",
|
||||
"column.direct": "Menegoù prevez",
|
||||
"column.directory": "Mont a-dreuz ar profiloù",
|
||||
"column.domain_blocks": "Domani berzet",
|
||||
"column.edit_list": "Kemmañ al listenn",
|
||||
"column.favourites": "Muiañ-karet",
|
||||
"column.firehose": "Redoù war-eeun",
|
||||
"column.follow_requests": "Rekedoù heuliañ",
|
||||
|
@ -162,9 +169,12 @@
|
|||
"confirmations.delete.message": "Ha sur oc'h e fell deoc'h dilemel an toud-mañ ?",
|
||||
"confirmations.delete_list.confirm": "Dilemel",
|
||||
"confirmations.delete_list.message": "Ha sur eo hoc'h eus c'hoant da zilemel ar roll-mañ da vat ?",
|
||||
"confirmations.delete_list.title": "Dilemel al listenn?",
|
||||
"confirmations.discard_edit_media.confirm": "Nac'hañ",
|
||||
"confirmations.discard_edit_media.message": "Bez ez eus kemmoù n'int ket enrollet e deskrivadur ar media pe ar rakwel, nullañ anezho evelato?",
|
||||
"confirmations.edit.confirm": "Kemmañ",
|
||||
"confirmations.edit.message": "Kemmañ bremañ a zilamo ar gemennadenn emaoc'h o skrivañ. Sur e oc'h e fell deoc'h kenderc'hel ganti?",
|
||||
"confirmations.follow_to_list.title": "Heuliañ an implijer·ez?",
|
||||
"confirmations.logout.confirm": "Digevreañ",
|
||||
"confirmations.logout.message": "Ha sur oc'h e fell deoc'h digevreañ ?",
|
||||
"confirmations.mute.confirm": "Kuzhat",
|
||||
|
@ -266,8 +276,10 @@
|
|||
"footer.privacy_policy": "Reolennoù prevezded",
|
||||
"footer.source_code": "Gwelet ar c'hod mammenn",
|
||||
"footer.status": "Statud",
|
||||
"footer.terms_of_service": "Divizoù implijout hollek",
|
||||
"generic.saved": "Enrollet",
|
||||
"getting_started.heading": "Loc'hañ",
|
||||
"hashtag.admin_moderation": "Digeriñ an etrefas evezhiañ evit #{name}",
|
||||
"hashtag.column_header.tag_mode.all": "ha(g) {additional}",
|
||||
"hashtag.column_header.tag_mode.any": "pe {additional}",
|
||||
"hashtag.column_header.tag_mode.none": "hep {additional}",
|
||||
|
@ -337,8 +349,14 @@
|
|||
"limited_account_hint.action": "Diskouez an aelad memes tra",
|
||||
"limited_account_hint.title": "Kuzhet eo bet ar profil-mañ gant an evezhierien eus {domain}.",
|
||||
"link_preview.author": "Gant {name}",
|
||||
"lists.add_member": "Ouzhpennañ",
|
||||
"lists.add_to_list": "Ouzhpennañ d'al listenn",
|
||||
"lists.create": "Krouiñ",
|
||||
"lists.create_list": "Krouiñ ul listenn",
|
||||
"lists.delete": "Dilemel al listenn",
|
||||
"lists.done": "Graet",
|
||||
"lists.edit": "Kemmañ al listenn",
|
||||
"lists.list_name": "Anv al listenn",
|
||||
"lists.replies_policy.followed": "Pep implijer.ez heuliet",
|
||||
"lists.replies_policy.list": "Izili ar roll",
|
||||
"lists.replies_policy.none": "Den ebet",
|
||||
|
@ -373,11 +391,17 @@
|
|||
"notification.follow": "heuliañ a ra {name} ac'hanoc'h",
|
||||
"notification.follow.name_and_others": "{name} <a>{count, plural, one {hag # den all} two {ha # zen all} few {ha # den all} many {ha # den all} other {ha # den all}}</a> zo o heuliañ ac'hanoc'h",
|
||||
"notification.follow_request": "Gant {name} eo bet goulennet ho heuliañ",
|
||||
"notification.label.reply": "Respont",
|
||||
"notification.moderation-warning.learn_more": "Gouzout hiroc'h",
|
||||
"notification.own_poll": "Echu eo ho sontadeg",
|
||||
"notification.reblog": "Gant {name} eo bet skignet ho toud",
|
||||
"notification.relationships_severance_event.learn_more": "Gouzout hiroc'h",
|
||||
"notification.status": "Emañ {name} o paouez toudañ",
|
||||
"notification.update": "Gant {name} ez eus bet kemmet un toud",
|
||||
"notification_requests.accept": "Asantiñ",
|
||||
"notification_requests.dismiss": "Diverkañ",
|
||||
"notification_requests.edit_selection": "Kemmañ",
|
||||
"notification_requests.exit_selection": "Graet",
|
||||
"notifications.clear": "Skarzhañ ar c'hemennoù",
|
||||
"notifications.clear_confirmation": "Ha sur oc'h e fell deoc'h skarzhañ ho holl kemennoù ?",
|
||||
"notifications.column_settings.admin.report": "Disklêriadurioù nevez :",
|
||||
|
@ -410,6 +434,10 @@
|
|||
"notifications.permission_denied": "Kemennoù war ar burev n'int ket hegerz rak pedadenn aotren ar merdeer a zo bet nullet araok",
|
||||
"notifications.permission_denied_alert": "Kemennoù wa ar burev na c'hellont ket bezañ lezelet, rak aotre ar merdeer a zo bet nac'het a-raok",
|
||||
"notifications.permission_required": "Kemennoù war ar burev n'int ket hegerz abalamour d'an aotre rekis n'eo ket bet roet.",
|
||||
"notifications.policy.accept": "Asantiñ",
|
||||
"notifications.policy.accept_hint": "Diskouez er c’hemennoù",
|
||||
"notifications.policy.drop": "Tremen e-bioù",
|
||||
"notifications.policy.filter": "Silañ",
|
||||
"notifications.policy.filter_new_accounts_title": "Kontoù nevez",
|
||||
"notifications_permission_banner.enable": "Lezel kemennoù war ar burev",
|
||||
"notifications_permission_banner.how_to_control": "Evit reseviñ kemennoù pa ne vez ket digoret Mastodon, lezelit kemennoù war ar burev. Gallout a rit kontrollañ peseurt eskemmoù a c'henel kemennoù war ar burev gant ar {icon} nozelenn a-us kentre ma'z int lezelet.",
|
||||
|
@ -515,6 +543,7 @@
|
|||
"search_results.accounts": "Profiloù",
|
||||
"search_results.all": "Pep tra",
|
||||
"search_results.hashtags": "Hashtagoù",
|
||||
"search_results.no_results": "Disoc'h ebet.",
|
||||
"search_results.see_all": "Gwelet pep tra",
|
||||
"search_results.statuses": "Toudoù",
|
||||
"server_banner.active_users": "implijerien·ezed oberiant",
|
||||
|
@ -579,6 +608,7 @@
|
|||
"subscribed_languages.target": "Cheñch ar yezhoù koumanantet evit {target}",
|
||||
"tabs_bar.home": "Degemer",
|
||||
"tabs_bar.notifications": "Kemennoù",
|
||||
"terms_of_service.title": "Divizoù implijout",
|
||||
"time_remaining.days": "{number, plural,one {# devezh} other {# a zevezh}} a chom",
|
||||
"time_remaining.hours": "{number, plural, one {# eurvezh} other{# eurvezh}} a chom",
|
||||
"time_remaining.minutes": "{number, plural, one {# munut} other{# a vunut}} a chom",
|
||||
|
|
|
@ -562,6 +562,7 @@
|
|||
"notification.favourite": "{name} märkis su postituse lemmikuks",
|
||||
"notification.favourite.name_and_others_with_link": "{name} ja <a>{count, plural, one {# veel} other {# teist}}</a> märkis su postituse lemmikuks",
|
||||
"notification.favourite_pm": "{name} märkis sinu privaatse mainimise lemmikuks",
|
||||
"notification.favourite_pm.name_and_others_with_link": "{name} ja <a>{count, plural, one {# veel} other {# veel}}</a> märkisid su privaatse mainimise lemmikuks",
|
||||
"notification.follow": "{name} alustas su jälgimist",
|
||||
"notification.follow.name_and_others": "{name} ja veel {count, plural, one {# kasutaja} other {# kasutajat}} hakkas sind jälgima",
|
||||
"notification.follow_request": "{name} soovib sind jälgida",
|
||||
|
@ -696,6 +697,7 @@
|
|||
"poll_button.remove_poll": "Eemalda küsitlus",
|
||||
"privacy.change": "Muuda postituse nähtavust",
|
||||
"privacy.direct.long": "Kõik postituses mainitud",
|
||||
"privacy.direct.short": "Privaatne mainimine",
|
||||
"privacy.private.long": "Ainult jälgijad",
|
||||
"privacy.private.short": "Jälgijad",
|
||||
"privacy.public.long": "Nii kasutajad kui mittekasutajad",
|
||||
|
|
|
@ -10,7 +10,7 @@ class ContentSecurityPolicy
|
|||
end
|
||||
|
||||
def media_hosts
|
||||
[assets_host, cdn_host_value, paperclip_root_url].concat(extra_data_hosts).compact
|
||||
[assets_host, cdn_host_value, paperclip_root_url].concat(extra_media_hosts).compact
|
||||
end
|
||||
|
||||
def sso_host
|
||||
|
@ -31,8 +31,17 @@ class ContentSecurityPolicy
|
|||
|
||||
private
|
||||
|
||||
# TODO: remove after 4.4.0
|
||||
def extra_data_hosts
|
||||
ENV.fetch('EXTRA_DATA_HOSTS', '').split('|')
|
||||
return [] unless ENV['EXTRA_DATA_HOSTS']
|
||||
|
||||
ENV.fetch('EXTRA_DATA_HOSTS', '').split('|').tap do |hosts|
|
||||
Rails.logger.warn "EXTRA_DATA_HOSTS is deprecated, use EXTRA_MEDIA_HOSTS=#{hosts.join(',')}"
|
||||
end
|
||||
end
|
||||
|
||||
def extra_media_hosts
|
||||
ENV.fetch('EXTRA_MEDIA_HOSTS', '').split(/(?:\s*,\s*|\s+)/).presence || extra_data_hosts
|
||||
end
|
||||
|
||||
def url_from_configured_asset_host
|
||||
|
|
|
@ -153,7 +153,7 @@ class Account < ApplicationRecord
|
|||
scope :not_excluded_by_account, ->(account) { where.not(id: account.excluded_from_timeline_account_ids) }
|
||||
scope :not_domain_blocked_by_account, ->(account) { where(arel_table[:domain].eq(nil).or(arel_table[:domain].not_in(account.excluded_from_timeline_domains))) }
|
||||
scope :dormant, -> { joins(:account_stat).merge(AccountStat.without_recent_activity) }
|
||||
scope :with_username, ->(value) { where arel_table[:username].lower.eq(value.to_s.downcase) }
|
||||
scope :with_username, ->(value) { value.is_a?(Array) ? where(arel_table[:username].lower.in(value.map { |x| x.to_s.downcase })) : where(arel_table[:username].lower.eq(value.to_s.downcase)) }
|
||||
scope :with_domain, ->(value) { where arel_table[:domain].lower.eq(value&.to_s&.downcase) }
|
||||
scope :without_memorial, -> { where(memorial: false) }
|
||||
scope :duplicate_uris, -> { select(:uri, Arel.star.count).group(:uri).having(Arel.star.count.gt(1)) }
|
||||
|
|
|
@ -107,6 +107,7 @@ class REST::InstanceSerializer < ActiveModel::Serializer
|
|||
{
|
||||
enabled: registrations_enabled?,
|
||||
approval_required: Setting.registrations_mode == 'approved',
|
||||
reason_required: Setting.registrations_mode == 'approved' && Setting.require_invite_text,
|
||||
message: registrations_enabled? ? nil : registrations_message,
|
||||
min_age: Setting.min_age.presence,
|
||||
url: ENV.fetch('SSO_ACCOUNT_SIGN_UP', nil),
|
||||
|
|
|
@ -4,32 +4,46 @@ class ActivityPub::SynchronizeFollowersService < BaseService
|
|||
include JsonLdHelper
|
||||
include Payloadable
|
||||
|
||||
MAX_COLLECTION_PAGES = 10
|
||||
|
||||
def call(account, partial_collection_url)
|
||||
@account = account
|
||||
@expected_followers_ids = []
|
||||
|
||||
items = collection_items(partial_collection_url)
|
||||
return if items.nil?
|
||||
|
||||
# There could be unresolved accounts (hence the call to .compact) but this
|
||||
# should never happen in practice, since in almost all cases we keep an
|
||||
# Account record, and should we not do that, we should have sent a Delete.
|
||||
# In any case there is not much we can do if that occurs.
|
||||
@expected_followers = items.filter_map { |uri| ActivityPub::TagManager.instance.uri_to_resource(uri, Account) }
|
||||
return unless process_collection!(partial_collection_url)
|
||||
|
||||
remove_unexpected_local_followers!
|
||||
handle_unexpected_outgoing_follows!
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def process_page!(items)
|
||||
page_expected_followers = extract_local_followers(items)
|
||||
@expected_followers_ids.concat(page_expected_followers.pluck(:id))
|
||||
|
||||
handle_unexpected_outgoing_follows!(page_expected_followers)
|
||||
end
|
||||
|
||||
def extract_local_followers(items)
|
||||
# There could be unresolved accounts (hence the call to .filter_map) but this
|
||||
# should never happen in practice, since in almost all cases we keep an
|
||||
# Account record, and should we not do that, we should have sent a Delete.
|
||||
# In any case there is not much we can do if that occurs.
|
||||
|
||||
# TODO: this will need changes when switching to numeric IDs
|
||||
|
||||
usernames = items.filter_map { |uri| ActivityPub::TagManager.instance.uri_to_local_id(uri, :username)&.downcase }
|
||||
Account.local.with_username(usernames)
|
||||
end
|
||||
|
||||
def remove_unexpected_local_followers!
|
||||
@account.followers.local.where.not(id: @expected_followers.map(&:id)).reorder(nil).find_each do |unexpected_follower|
|
||||
@account.followers.local.where.not(id: @expected_followers_ids).reorder(nil).find_each do |unexpected_follower|
|
||||
UnfollowService.new.call(unexpected_follower, @account)
|
||||
end
|
||||
end
|
||||
|
||||
def handle_unexpected_outgoing_follows!
|
||||
@expected_followers.each do |expected_follower|
|
||||
def handle_unexpected_outgoing_follows!(expected_followers)
|
||||
expected_followers.each do |expected_follower|
|
||||
next if expected_follower.following?(@account)
|
||||
|
||||
if expected_follower.requested?(@account)
|
||||
|
@ -50,21 +64,33 @@ class ActivityPub::SynchronizeFollowersService < BaseService
|
|||
Oj.dump(serialize_payload(follow, ActivityPub::UndoFollowSerializer))
|
||||
end
|
||||
|
||||
def collection_items(collection_or_uri)
|
||||
collection = fetch_collection(collection_or_uri)
|
||||
return unless collection.is_a?(Hash)
|
||||
# Only returns true if the whole collection has been processed
|
||||
def process_collection!(collection_uri, max_pages: MAX_COLLECTION_PAGES)
|
||||
collection = fetch_collection(collection_uri)
|
||||
return false unless collection.is_a?(Hash)
|
||||
|
||||
collection = fetch_collection(collection['first']) if collection['first'].present?
|
||||
return unless collection.is_a?(Hash)
|
||||
|
||||
# Abort if we'd have to paginate through more than one page of followers
|
||||
return if collection['next'].present?
|
||||
while collection.is_a?(Hash)
|
||||
process_page!(as_array(collection_page_items(collection)))
|
||||
|
||||
max_pages -= 1
|
||||
|
||||
return true if collection['next'].blank? # We reached the end of the collection
|
||||
return false if max_pages <= 0 # We reached our pages limit
|
||||
|
||||
collection = fetch_collection(collection['next'])
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
def collection_page_items(collection)
|
||||
case collection['type']
|
||||
when 'Collection', 'CollectionPage'
|
||||
as_array(collection['items'])
|
||||
collection['items']
|
||||
when 'OrderedCollection', 'OrderedCollectionPage'
|
||||
as_array(collection['orderedItems'])
|
||||
collection['orderedItems']
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -55,6 +55,8 @@ ko:
|
|||
too_soon: 너무 이릅니다. %{date} 이후로 지정해야 합니다
|
||||
user:
|
||||
attributes:
|
||||
date_of_birth:
|
||||
below_limit: 나이 제한보다 아래입니다
|
||||
email:
|
||||
blocked: 허용되지 않은 이메일 제공자입니다
|
||||
unreachable: 존재하지 않는 것 같습니다
|
||||
|
|
|
@ -47,6 +47,7 @@ br:
|
|||
demote: Argilañ
|
||||
disable: Skornañ
|
||||
disabled: Skornet
|
||||
display_name: Anv diskouezet
|
||||
domain: Domani
|
||||
edit: Kemmañ
|
||||
email: Postel
|
||||
|
@ -66,6 +67,7 @@ br:
|
|||
moderation:
|
||||
active: Oberiant
|
||||
all: Pep tra
|
||||
disabled: Diweredekaet
|
||||
pending: War ober
|
||||
silenced: Bevennet
|
||||
suspended: Astalet
|
||||
|
@ -98,6 +100,7 @@ br:
|
|||
action_logs:
|
||||
action_types:
|
||||
destroy_status: Dilemel ar c'hannad
|
||||
reset_password_user: Adderaouekaat ar ger-tremen
|
||||
update_status: Hizivaat ar c'hannad
|
||||
actions:
|
||||
destroy_status_html: Dilamet eo bet toud %{target} gant %{name}
|
||||
|
|
|
@ -85,25 +85,25 @@ lv:
|
|||
title: Drošības atslēgas iespējotas
|
||||
omniauth_callbacks:
|
||||
failure: Nevarēja autentificēt tevi no %{kind}, jo "%{reason}".
|
||||
success: Veiksmīgi autentificēts no %{kind} konta.
|
||||
success: Sekmīgi autentificēts no %{kind} konta.
|
||||
passwords:
|
||||
no_token: Tu nevari piekļūt šai lapai, ja neesi saņēmis paroles atiestatīšanas e-pasta ziņojumu. Ja ienāci no paroles atiestatīšanas e-pasta, lūdzu, pārliecinies, vai izmanto visu norādīto URL.
|
||||
send_instructions: Ja Tava e-pasta adrese ir mūsu datubāzē, pēc dažām minūtēm savā e-pasta adresē saņemsi paroles atkopes saiti. Lūgums pārbaudīt mēstuļu mapi, ja nesaņēmi šo e-pasta ziņojumu.
|
||||
send_paranoid_instructions: Ja Tava e-pasta adrese ir mūsu datubāzē, pēc dažām minūtēm savā e-pasta adresē saņemsi paroles atkopes saiti. Lūgums pārbaudīt mēstuļu mapi, ja nesaņēmi šo e-pasta ziņojumu.
|
||||
updated: Tava parole tika veiksmīgi nomainīta. Tagad esi pieteicies.
|
||||
updated_not_active: Tava parole ir veiksmīgi nomainīta.
|
||||
updated: Tava parole tika sekmīgi nomainīta. Tagad esi pieteicies.
|
||||
updated_not_active: Tava parole tika sekmīgi nomainīta.
|
||||
registrations:
|
||||
destroyed: Visu labu! Tavs konts ir veiksmīgi atcelts. Mēs ceram tevi drīz atkal redzēt.
|
||||
update_needs_confirmation: Tu veiksmīgi atjaunināji savu kontu, taču mums ir jāapliecina Tava jaunā e-pasta adrese. Lūgums pārbaudīt savu e-pastu un sekot apstiprinājuma saitei, lai apstiprinātu savu jauno e-pasta adresi. Lūgums pārbaudīt mēstuļu mapi, ja nesaņēmi šo e-pasta ziņojumu.
|
||||
updated: Tavs konts ir veiksmīgi atjaunināts.
|
||||
destroyed: Visu labu! Tavs konts ir sekmīgi atcelts. Mēs ceram Tevi drīz atkal redzēt.
|
||||
update_needs_confirmation: Tu sekmīgi atjaunināji savu kontu, taču mums ir jāapliecina Tava jaunā e-pasta adrese. Lūgums pārbaudīt savu e-pastu un sekot apstiprinājuma saitei, lai apstiprinātu savu jauno e-pasta adresi. Lūgums pārbaudīt mēstuļu mapi, ja nesaņēmi šo e-pasta ziņojumu.
|
||||
updated: Tavs konts tika sekmīgi atjaunināts.
|
||||
sessions:
|
||||
already_signed_out: Veiksmīgi izrakstījies.
|
||||
signed_in: Veiksmīgi pieteicies.
|
||||
signed_out: Veiksmīgi izrakstījies.
|
||||
already_signed_out: Sekmīgi izrakstījies.
|
||||
signed_in: Sekmīgi pierakstījies.
|
||||
signed_out: Sekmīgi izrakstījies.
|
||||
unlocks:
|
||||
send_instructions: Pēc dažām minūtēm Tu saņemsi e-pasta ziņojumu ar norādēm, kā atslēgt savu kontu. Lūgums pārbaudīt mēstuļu mapi, ja nesaņēmi šo e-pasta ziņojumu.
|
||||
send_paranoid_instructions: Ja Tavs konts pastāv, dažu minūšu laikā saņemsi e-pasta ziņojumu ar norādēm, kā to atslēgt. Lūgums pārbaudīt mēstuļu mapi, ja nesaņēmi šo e-pasta ziņojumu.
|
||||
unlocked: Konts tika veiksmīgi atbloķēts. Lūgums pieteikties, lai turpinātu.
|
||||
unlocked: Konts tika sekmīgi atslēgts. Lūgums pieteikties, lai turpinātu.
|
||||
errors:
|
||||
messages:
|
||||
already_confirmed: jau tika apstiprināts, lūgums mēģināt pieteikties
|
||||
|
|
|
@ -153,7 +153,7 @@ ko:
|
|||
position: 특정 상황에서 충돌이 발생할 경우 더 높은 역할이 충돌을 해결합니다. 특정 작업은 우선순위가 낮은 역할에 대해서만 수행될 수 있습니다
|
||||
webhook:
|
||||
events: 전송할 이벤트를 선택하세요
|
||||
template: 원하는 JSON 페이로드를 변수와 함께 작성하거나, 그냥 냅둬서 기본 JSON을 사용할 수 있습니다.
|
||||
template: 원하는 JSON 페이로드를 변수와 함께 작성하거나, 그대로 두어 기본 JSON을 사용할 수 있습니다.
|
||||
url: 이벤트가 어디로 전송될 지
|
||||
labels:
|
||||
account:
|
||||
|
@ -269,6 +269,7 @@ ko:
|
|||
favicon: 파비콘
|
||||
mascot: 사용자 정의 마스코트 (legacy)
|
||||
media_cache_retention_period: 미디어 캐시 유지 기한
|
||||
min_age: 최소 연령 제한
|
||||
peers_api_enabled: API에 발견 된 서버들의 목록 발행
|
||||
profile_directory: 프로필 책자 활성화
|
||||
registrations_mode: 누가 가입할 수 있는지
|
||||
|
@ -347,6 +348,9 @@ ko:
|
|||
jurisdiction: 법적 관할권
|
||||
min_age: 최소 연령
|
||||
user:
|
||||
date_of_birth_1i: 일
|
||||
date_of_birth_2i: 월
|
||||
date_of_birth_3i: 년
|
||||
role: 역할
|
||||
time_zone: 시간대
|
||||
user_role:
|
||||
|
|
|
@ -169,7 +169,7 @@ RSpec.describe 'Notifications' do
|
|||
end
|
||||
|
||||
context 'with min_id param' do
|
||||
let(:params) { { min_id: user.account.notifications.reload.first.id - 1 } }
|
||||
let(:params) { { min_id: user.account.notifications.order(id: :asc).first.id - 1 } }
|
||||
|
||||
it 'returns a notification group covering all notifications' do
|
||||
subject
|
||||
|
|
|
@ -10,7 +10,7 @@ RSpec.describe ActivityPub::SynchronizeFollowersService do
|
|||
let(:bob) { Fabricate(:account, username: 'bob') }
|
||||
let(:eve) { Fabricate(:account, username: 'eve') }
|
||||
let(:mallory) { Fabricate(:account, username: 'mallory') }
|
||||
let(:collection_uri) { 'http://example.com/partial-followers' }
|
||||
let(:collection_uri) { 'https://example.com/partial-followers' }
|
||||
|
||||
let(:items) do
|
||||
[alice, eve, mallory].map do |account|
|
||||
|
@ -97,7 +97,76 @@ RSpec.describe ActivityPub::SynchronizeFollowersService do
|
|||
it_behaves_like 'synchronizes followers'
|
||||
end
|
||||
|
||||
context 'when the endpoint is a paginated Collection of actor URIs with a next page' do
|
||||
context 'when the endpoint is a paginated Collection of actor URIs split across multiple pages' do
|
||||
before do
|
||||
stub_request(:get, 'https://example.com/partial-followers')
|
||||
.to_return(status: 200, headers: { 'Content-Type': 'application/activity+json' }, body: Oj.dump({
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
type: 'Collection',
|
||||
id: 'https://example.com/partial-followers',
|
||||
first: 'https://example.com/partial-followers/1',
|
||||
}))
|
||||
|
||||
stub_request(:get, 'https://example.com/partial-followers/1')
|
||||
.to_return(status: 200, headers: { 'Content-Type': 'application/activity+json' }, body: Oj.dump({
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
type: 'CollectionPage',
|
||||
id: 'https://example.com/partial-followers/1',
|
||||
partOf: 'https://example.com/partial-followers',
|
||||
next: 'https://example.com/partial-followers/2',
|
||||
items: [alice, eve].map { |account| ActivityPub::TagManager.instance.uri_for(account) },
|
||||
}))
|
||||
|
||||
stub_request(:get, 'https://example.com/partial-followers/2')
|
||||
.to_return(status: 200, headers: { 'Content-Type': 'application/activity+json' }, body: Oj.dump({
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
type: 'CollectionPage',
|
||||
id: 'https://example.com/partial-followers/2',
|
||||
partOf: 'https://example.com/partial-followers',
|
||||
items: ActivityPub::TagManager.instance.uri_for(mallory),
|
||||
}))
|
||||
end
|
||||
|
||||
it_behaves_like 'synchronizes followers'
|
||||
end
|
||||
|
||||
context 'when the endpoint is a paginated Collection of actor URIs split across, but one page errors out' do
|
||||
before do
|
||||
stub_request(:get, 'https://example.com/partial-followers')
|
||||
.to_return(status: 200, headers: { 'Content-Type': 'application/activity+json' }, body: Oj.dump({
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
type: 'Collection',
|
||||
id: 'https://example.com/partial-followers',
|
||||
first: 'https://example.com/partial-followers/1',
|
||||
}))
|
||||
|
||||
stub_request(:get, 'https://example.com/partial-followers/1')
|
||||
.to_return(status: 200, headers: { 'Content-Type': 'application/activity+json' }, body: Oj.dump({
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
type: 'CollectionPage',
|
||||
id: 'https://example.com/partial-followers/1',
|
||||
partOf: 'https://example.com/partial-followers',
|
||||
next: 'https://example.com/partial-followers/2',
|
||||
items: [mallory].map { |account| ActivityPub::TagManager.instance.uri_for(account) },
|
||||
}))
|
||||
|
||||
stub_request(:get, 'https://example.com/partial-followers/2')
|
||||
.to_return(status: 404)
|
||||
end
|
||||
|
||||
it 'confirms pending follow request but does not remove extra followers' do
|
||||
previous_follower_ids = actor.followers.pluck(:id)
|
||||
|
||||
subject.call(actor, collection_uri)
|
||||
|
||||
expect(previous_follower_ids - actor.followers.reload.pluck(:id))
|
||||
.to be_empty
|
||||
expect(mallory)
|
||||
.to be_following(actor)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the endpoint is a paginated Collection of actor URIs with more pages than we allow' do
|
||||
let(:payload) do
|
||||
{
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
|
@ -113,12 +182,19 @@ RSpec.describe ActivityPub::SynchronizeFollowersService do
|
|||
end
|
||||
|
||||
before do
|
||||
stub_const('ActivityPub::SynchronizeFollowersService::MAX_COLLECTION_PAGES', 1)
|
||||
stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' })
|
||||
end
|
||||
|
||||
it 'does not change followers' do
|
||||
expect { subject.call(actor, collection_uri) }
|
||||
.to_not(change { actor.followers.reload.reorder(id: :asc).pluck(:id) })
|
||||
it 'confirms pending follow request but does not remove extra followers' do
|
||||
previous_follower_ids = actor.followers.pluck(:id)
|
||||
|
||||
subject.call(actor, collection_uri)
|
||||
|
||||
expect(previous_follower_ids - actor.followers.reload.pluck(:id))
|
||||
.to be_empty
|
||||
expect(mallory)
|
||||
.to be_following(actor)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Add table
Reference in a new issue