mirror of
https://github.com/glitch-soc/mastodon
synced 2025-04-25 00:44:51 +00:00
Merge pull request #3017 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to e28b64ac2d
This commit is contained in:
commit
51a8c6c3f7
18 changed files with 439 additions and 259 deletions
|
@ -504,6 +504,7 @@
|
||||||
"navigation_bar.follows_and_followers": "Падпіскі і падпісчыкі",
|
"navigation_bar.follows_and_followers": "Падпіскі і падпісчыкі",
|
||||||
"navigation_bar.lists": "Спісы",
|
"navigation_bar.lists": "Спісы",
|
||||||
"navigation_bar.logout": "Выйсці",
|
"navigation_bar.logout": "Выйсці",
|
||||||
|
"navigation_bar.moderation": "Мадэрацыя",
|
||||||
"navigation_bar.mutes": "Ігнараваныя карыстальнікі",
|
"navigation_bar.mutes": "Ігнараваныя карыстальнікі",
|
||||||
"navigation_bar.opened_in_classic_interface": "Допісы, уліковыя запісы і іншыя спецыфічныя старонкі па змоўчанні адчыняюцца ў класічным вэб-інтэрфейсе.",
|
"navigation_bar.opened_in_classic_interface": "Допісы, уліковыя запісы і іншыя спецыфічныя старонкі па змоўчанні адчыняюцца ў класічным вэб-інтэрфейсе.",
|
||||||
"navigation_bar.personal": "Асабістае",
|
"navigation_bar.personal": "Асабістае",
|
||||||
|
|
|
@ -669,7 +669,7 @@
|
||||||
"notifications_permission_banner.title": "Nenechte si nic uniknout",
|
"notifications_permission_banner.title": "Nenechte si nic uniknout",
|
||||||
"onboarding.follows.back": "Zpět",
|
"onboarding.follows.back": "Zpět",
|
||||||
"onboarding.follows.done": "Hotovo",
|
"onboarding.follows.done": "Hotovo",
|
||||||
"onboarding.follows.empty": "Bohužel, žádné výsledky nelze momentálně zobrazit. Můžete zkusit vyhledat nebo procházet stránku s průzkumem a najít lidi, kteří budou sledovat, nebo to zkuste znovu později.",
|
"onboarding.follows.empty": "Bohužel, žádné výsledky nelze momentálně zobrazit. Můžete zkusit najít uživatele ke sledování za pomocí vyhledávání nebo na stránce „Objevit“, nebo to zkuste znovu později.",
|
||||||
"onboarding.follows.search": "Hledat",
|
"onboarding.follows.search": "Hledat",
|
||||||
"onboarding.follows.title": "Sledujte lidi a začněte",
|
"onboarding.follows.title": "Sledujte lidi a začněte",
|
||||||
"onboarding.profile.discoverable": "Udělat svůj profil vyhledatelným",
|
"onboarding.profile.discoverable": "Udělat svůj profil vyhledatelným",
|
||||||
|
|
|
@ -10,7 +10,7 @@ class AccountReachFinder
|
||||||
end
|
end
|
||||||
|
|
||||||
def inboxes
|
def inboxes
|
||||||
(followers_inboxes + reporters_inboxes + recently_mentioned_inboxes + relay_inboxes).uniq
|
(followers_inboxes + reporters_inboxes + recently_mentioned_inboxes + recently_followed_inboxes + recently_requested_inboxes + relay_inboxes).uniq
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -31,13 +31,32 @@ class AccountReachFinder
|
||||||
.take(RECENT_LIMIT)
|
.take(RECENT_LIMIT)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def recently_followed_inboxes
|
||||||
|
@account
|
||||||
|
.following
|
||||||
|
.where(follows: { created_at: recent_date_cutoff... })
|
||||||
|
.inboxes
|
||||||
|
.take(RECENT_LIMIT)
|
||||||
|
end
|
||||||
|
|
||||||
|
def recently_requested_inboxes
|
||||||
|
Account
|
||||||
|
.where(id: @account.follow_requests.where({ created_at: recent_date_cutoff... }).select(:target_account_id))
|
||||||
|
.inboxes
|
||||||
|
.take(RECENT_LIMIT)
|
||||||
|
end
|
||||||
|
|
||||||
def relay_inboxes
|
def relay_inboxes
|
||||||
Relay.enabled.pluck(:inbox_url)
|
Relay.enabled.pluck(:inbox_url)
|
||||||
end
|
end
|
||||||
|
|
||||||
def oldest_status_id
|
def oldest_status_id
|
||||||
Mastodon::Snowflake
|
Mastodon::Snowflake
|
||||||
.id_at(STATUS_SINCE.ago, with_random: false)
|
.id_at(recent_date_cutoff, with_random: false)
|
||||||
|
end
|
||||||
|
|
||||||
|
def recent_date_cutoff
|
||||||
|
@account.suspended? && @account.suspension_origin_local? ? @account.suspended_at - STATUS_SINCE : STATUS_SINCE.ago
|
||||||
end
|
end
|
||||||
|
|
||||||
def recent_statuses
|
def recent_statuses
|
||||||
|
|
|
@ -429,7 +429,7 @@ lv:
|
||||||
obfuscate: Apslēpt domēna vārdu
|
obfuscate: Apslēpt domēna vārdu
|
||||||
obfuscate_hint: Daļēji apslēpt domēna nosaukumu sarakstā, ja ir iespējota domēna ierobežojumu saraksta reklamēšana
|
obfuscate_hint: Daļēji apslēpt domēna nosaukumu sarakstā, ja ir iespējota domēna ierobežojumu saraksta reklamēšana
|
||||||
private_comment: Privāts komentārs
|
private_comment: Privāts komentārs
|
||||||
private_comment_hint: Atstāj komentāru par šo domēna ierobežojumu moderatoru iekšējai lietošanai.
|
private_comment_hint: Atstāt piebildi par šo domēna ierobežojumu satura pārraudzītāju iekšējai lietošanai.
|
||||||
public_comment: Publisks komentārs
|
public_comment: Publisks komentārs
|
||||||
public_comment_hint: Piebilde par šo domēna ierobežojumu vispārējai sabiedrībai, ja ir iespējota domēnu ierobežojumu saraksta reklamēšana.
|
public_comment_hint: Piebilde par šo domēna ierobežojumu vispārējai sabiedrībai, ja ir iespējota domēnu ierobežojumu saraksta reklamēšana.
|
||||||
reject_media: Noraidīt multivides failus
|
reject_media: Noraidīt multivides failus
|
||||||
|
@ -647,7 +647,7 @@ lv:
|
||||||
delete: Dzēst
|
delete: Dzēst
|
||||||
placeholder: Jāapraksta veiktās darbības vai jebkuri citi saistītie atjauninājumi...
|
placeholder: Jāapraksta veiktās darbības vai jebkuri citi saistītie atjauninājumi...
|
||||||
title: Piezīmes
|
title: Piezīmes
|
||||||
notes_description_html: Skati un atstāj piezīmes citiem moderatoriem un sev nākotnei
|
notes_description_html: Apskatīt un atstāt piezīmes citiem satura pārraudzītājiem un sev nākotnei
|
||||||
processed_msg: 'Pārskats #%{id} veiksmīgi apstrādāts'
|
processed_msg: 'Pārskats #%{id} veiksmīgi apstrādāts'
|
||||||
quick_actions_description_html: 'Veic ātro darbību vai ritini uz leju, lai skatītu saturu, par kuru ziņots:'
|
quick_actions_description_html: 'Veic ātro darbību vai ritini uz leju, lai skatītu saturu, par kuru ziņots:'
|
||||||
remote_user_placeholder: attālais lietotājs no %{instance}
|
remote_user_placeholder: attālais lietotājs no %{instance}
|
||||||
|
@ -1048,6 +1048,8 @@ lv:
|
||||||
title: Tīmekļa āķi
|
title: Tīmekļa āķi
|
||||||
webhook: Tīmekļa āķis
|
webhook: Tīmekļa āķis
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
auto_close_registrations:
|
||||||
|
body: Nesenu satura pārraudzības darbību trūkuma dēļ reģistrācija %{instance} ir automātiski pārslēgta nepieciešamība pēc pašrocīgas izskatīšanas, lai novērstu %{instance} izmantošana kā platformu iespējami sliktiem dalībniekiem. Jebkurā brīdī var ieslēgt atpakaļ atvērtu reģistrēšanos.
|
||||||
new_appeal:
|
new_appeal:
|
||||||
actions:
|
actions:
|
||||||
delete_statuses: lai izdzēstu viņu ierakstus
|
delete_statuses: lai izdzēstu viņu ierakstus
|
||||||
|
@ -1166,8 +1168,8 @@ lv:
|
||||||
accept: Pieņemt
|
accept: Pieņemt
|
||||||
back: Atpakaļ
|
back: Atpakaļ
|
||||||
invited_by: 'Tu vari pievienoties %{domain}, pateicoties uzaicinājumam, ko saņēmi no:'
|
invited_by: 'Tu vari pievienoties %{domain}, pateicoties uzaicinājumam, ko saņēmi no:'
|
||||||
preamble: Tos iestata un ievieš %{domain} moderatori.
|
preamble: Tos iestata un ievieš %{domain} satura pārraudzītāji.
|
||||||
preamble_invited: Pirms turpināt, lūdzu, apsver galvenos noteikumus, ko noteikuši %{domain} moderatori.
|
preamble_invited: Pirms turpināt, lūgums apsvērt pamatnoteikumus, kurus norādījuši %{domain} satura pārraudzītāji.
|
||||||
title: Daži pamatnoteikumi.
|
title: Daži pamatnoteikumi.
|
||||||
title_invited: Tu esi uzaicināts.
|
title_invited: Tu esi uzaicināts.
|
||||||
security: Drošība
|
security: Drošība
|
||||||
|
@ -1181,7 +1183,7 @@ lv:
|
||||||
preamble_html: Jāpiesakās ar saviem <strong>%{domain}</strong> piekļuves datiem. Ja konts tiek mitināts citā serverī, šeit nevarēs pieteikties.
|
preamble_html: Jāpiesakās ar saviem <strong>%{domain}</strong> piekļuves datiem. Ja konts tiek mitināts citā serverī, šeit nevarēs pieteikties.
|
||||||
title: Pieteikties %{domain}
|
title: Pieteikties %{domain}
|
||||||
sign_up:
|
sign_up:
|
||||||
manual_review: Reģistrācijas domēnā %{domain} manuāli pārbauda mūsu moderatori. Lai palīdzētu mums apstrādāt tavu reģistrāciju, uzraksti mazliet par sevi un to, kāpēc vēlies kontu %{domain}.
|
manual_review: Reģistrāciju %{domain} pašrocīgi izskata mūsu satura pārraudzītāji. Lai palīdzētu mums apstrādāt Tavu reģistrāciju, uzraksti mazliet par sevi un to, kāpēc vēlies kontu %{domain}!
|
||||||
title: Atļauj tevi iestatīt %{domain}.
|
title: Atļauj tevi iestatīt %{domain}.
|
||||||
status:
|
status:
|
||||||
account_status: Konta statuss
|
account_status: Konta statuss
|
||||||
|
@ -1730,6 +1732,7 @@ lv:
|
||||||
user_domain_block: Jūs bloķējāt %{target_name}
|
user_domain_block: Jūs bloķējāt %{target_name}
|
||||||
lost_followers: Zaudētie sekotāji
|
lost_followers: Zaudētie sekotāji
|
||||||
lost_follows: Zaudētie sekojumi
|
lost_follows: Zaudētie sekojumi
|
||||||
|
preamble: Tu vari zaudēt sekojamos un sekotājus, kad liedz domēnu vai kad satura pārraudzītāji izlemj apturēt attālu serveri. Kad t as notiek, būs iespējams lejupielādēt sarakstus ar pārtrauktajām saiknēm, kurus tad var izpētīt un, iespējams, ievietot citā serverī.
|
||||||
type: Notikums
|
type: Notikums
|
||||||
statuses:
|
statuses:
|
||||||
attached:
|
attached:
|
||||||
|
@ -1878,9 +1881,9 @@ lv:
|
||||||
spam: Spams
|
spam: Spams
|
||||||
violation: Saturs pārkāpj šādas kopienas pamatnostādnes
|
violation: Saturs pārkāpj šādas kopienas pamatnostādnes
|
||||||
explanation:
|
explanation:
|
||||||
delete_statuses: Tika konstatēts, ka dažas no tavām ziņām pārkāpj vienu vai vairākas kopienas vadlīnijas, un rezultātā %{instance} moderatori tās noņēma.
|
delete_statuses: Tika noteikts, ka daži no Taviem ierakstiem pārkāpj vienu vai vairākas kopienas vadlīnijas, tādējādi tos noņēma %{instance} satura pārraudzītāji.
|
||||||
disable: Tu vairs nevari izmantot savu kontu, taču tavs profils un citi dati paliek neskarti. Tu vari pieprasīt savu datu dublējumu, mainīt konta iestatījumus vai dzēst kontu.
|
disable: Tu vairs nevari izmantot savu kontu, taču tavs profils un citi dati paliek neskarti. Tu vari pieprasīt savu datu dublējumu, mainīt konta iestatījumus vai dzēst kontu.
|
||||||
mark_statuses_as_sensitive: "%{instance} satura pārraudzītāji dažus no Taviem ierakstiem ir atzīmējuši kā jūtīgus. Tas nozīmē, ka cilvēkiem būs jāpiesit ierakstos esošajiem informāijas nesējiem, pirms tiek attēlots priekšskatījums. Tu pats vari atzīmēt informācijas nesēju kā jūtīgu, kad nākotnē tādu ievietosi."
|
mark_statuses_as_sensitive: "%{instance} satura pārraudzītāji dažus no Taviem ierakstiem ir atzīmējuši kā jūtīgus. Tas nozīmē, ka cilvēkiem būs jāpiesit ierakstos esošajiem informāijas nesējiem, pirms tiek attēlots to priekšskatījums. Tu pats vari atzīmēt informācijas nesēju kā jūtīgu, kad nākotnē tādu ievietosi."
|
||||||
sensitive: Turpmāk visi augšupielādētās informācijas nesēju datnes tiks atzīmētas kā jūtīgas un paslēptas aiz klikšķināma brīdinājuma.
|
sensitive: Turpmāk visi augšupielādētās informācijas nesēju datnes tiks atzīmētas kā jūtīgas un paslēptas aiz klikšķināma brīdinājuma.
|
||||||
silence: Tu joprojām vari izmantot savu kontu, taču tikai tie cilvēki, kuri jau tev seko, redzēs tavas ziņas šajā serverī, un tev var tikt liegtas dažādas atklāšanas funkcijas. Tomēr citi joprojām var tev manuāli sekot.
|
silence: Tu joprojām vari izmantot savu kontu, taču tikai tie cilvēki, kuri jau tev seko, redzēs tavas ziņas šajā serverī, un tev var tikt liegtas dažādas atklāšanas funkcijas. Tomēr citi joprojām var tev manuāli sekot.
|
||||||
suspend: Tu vairs nevari izmantot savu kontu, un tavs profils un citi dati vairs nav pieejami. Tu joprojām vari pieteikties, lai pieprasītu savu datu dublēšanu, līdz dati tiks pilnībā noņemti aptuveni 30 dienu laikā, taču mēs saglabāsim dažus pamata datus, lai neļautu tev izvairīties no apturēšanas.
|
suspend: Tu vairs nevari izmantot savu kontu, un tavs profils un citi dati vairs nav pieejami. Tu joprojām vari pieteikties, lai pieprasītu savu datu dublēšanu, līdz dati tiks pilnībā noņemti aptuveni 30 dienu laikā, taču mēs saglabāsim dažus pamata datus, lai neļautu tev izvairīties no apturēšanas.
|
||||||
|
|
|
@ -75,6 +75,7 @@ fr-CA:
|
||||||
filters:
|
filters:
|
||||||
action: Choisir l'action à effectuer quand un message correspond au filtre
|
action: Choisir l'action à effectuer quand un message correspond au filtre
|
||||||
actions:
|
actions:
|
||||||
|
blur: Cacher les médias derrière un avertissement, sans cacher le texte
|
||||||
hide: Cacher complètement le contenu filtré, faire comme s'il n'existait pas
|
hide: Cacher complètement le contenu filtré, faire comme s'il n'existait pas
|
||||||
warn: Cacher le contenu filtré derrière un avertissement mentionnant le nom du filtre
|
warn: Cacher le contenu filtré derrière un avertissement mentionnant le nom du filtre
|
||||||
form_admin_settings:
|
form_admin_settings:
|
||||||
|
@ -260,6 +261,7 @@ fr-CA:
|
||||||
name: Mot-clic
|
name: Mot-clic
|
||||||
filters:
|
filters:
|
||||||
actions:
|
actions:
|
||||||
|
blur: Masquer les médias derrière un avertissement
|
||||||
hide: Cacher complètement
|
hide: Cacher complètement
|
||||||
warn: Cacher derrière un avertissement
|
warn: Cacher derrière un avertissement
|
||||||
form_admin_settings:
|
form_admin_settings:
|
||||||
|
|
|
@ -75,6 +75,7 @@ fr:
|
||||||
filters:
|
filters:
|
||||||
action: Choisir l'action à effectuer quand un message correspond au filtre
|
action: Choisir l'action à effectuer quand un message correspond au filtre
|
||||||
actions:
|
actions:
|
||||||
|
blur: Cacher les médias derrière un avertissement, sans cacher le texte
|
||||||
hide: Cacher complètement le contenu filtré, faire comme s'il n'existait pas
|
hide: Cacher complètement le contenu filtré, faire comme s'il n'existait pas
|
||||||
warn: Cacher le contenu filtré derrière un avertissement mentionnant le nom du filtre
|
warn: Cacher le contenu filtré derrière un avertissement mentionnant le nom du filtre
|
||||||
form_admin_settings:
|
form_admin_settings:
|
||||||
|
@ -260,6 +261,7 @@ fr:
|
||||||
name: Hashtag
|
name: Hashtag
|
||||||
filters:
|
filters:
|
||||||
actions:
|
actions:
|
||||||
|
blur: Masquer les médias derrière un avertissement
|
||||||
hide: Cacher complètement
|
hide: Cacher complètement
|
||||||
warn: Cacher derrière un avertissement
|
warn: Cacher derrière un avertissement
|
||||||
form_admin_settings:
|
form_admin_settings:
|
||||||
|
|
|
@ -75,6 +75,7 @@ gl:
|
||||||
filters:
|
filters:
|
||||||
action: Elixe a acción a realizar cando algunha publicación coincida co filtro
|
action: Elixe a acción a realizar cando algunha publicación coincida co filtro
|
||||||
actions:
|
actions:
|
||||||
|
blur: Ocultar multimedia detrás dun aviso, sen ocultar o texto que se inclúa
|
||||||
hide: Agochar todo o contido filtrado, facer coma se non existise
|
hide: Agochar todo o contido filtrado, facer coma se non existise
|
||||||
warn: Agochar o contido filtrado tras un aviso que conteña o nome do filtro
|
warn: Agochar o contido filtrado tras un aviso que conteña o nome do filtro
|
||||||
form_admin_settings:
|
form_admin_settings:
|
||||||
|
@ -260,6 +261,7 @@ gl:
|
||||||
name: Cancelo
|
name: Cancelo
|
||||||
filters:
|
filters:
|
||||||
actions:
|
actions:
|
||||||
|
blur: Ocultar multimedia cun aviso
|
||||||
hide: Agochar completamente
|
hide: Agochar completamente
|
||||||
warn: Agochar tras un aviso
|
warn: Agochar tras un aviso
|
||||||
form_admin_settings:
|
form_admin_settings:
|
||||||
|
|
|
@ -26,7 +26,7 @@ lv:
|
||||||
types:
|
types:
|
||||||
disable: Neļauj lietotājam izmantot savu kontu, bet neizdzēs vai neslēp tā saturu.
|
disable: Neļauj lietotājam izmantot savu kontu, bet neizdzēs vai neslēp tā saturu.
|
||||||
none: Izmanto šo, lai nosūtītu lietotājam brīdinājumu, neradot nekādas citas darbības.
|
none: Izmanto šo, lai nosūtītu lietotājam brīdinājumu, neradot nekādas citas darbības.
|
||||||
sensitive: Piespiest visus šī lietotāja multivides pielikumus atzīmēt kā sensitīvus.
|
sensitive: Visus šī lietotāja informācijas nesēju pielikumus uzspiesti atzīmēt kā jūtīgus.
|
||||||
silence: Neļaut lietotājam veikt ierakstus ar publisku redzamību, paslēpt viņa ierakstus un paziņojumus no cilvēkiem, kas tam neseko. Tiek aizvērti visi ziņojumi par šo kontu.
|
silence: Neļaut lietotājam veikt ierakstus ar publisku redzamību, paslēpt viņa ierakstus un paziņojumus no cilvēkiem, kas tam neseko. Tiek aizvērti visi ziņojumi par šo kontu.
|
||||||
suspend: Novērs jebkādu mijiedarbību no šī konta vai uz to un dzēs tā saturu. Atgriežams 30 dienu laikā. Tiek aizvērti visi šī konta pārskati.
|
suspend: Novērs jebkādu mijiedarbību no šī konta vai uz to un dzēs tā saturu. Atgriežams 30 dienu laikā. Tiek aizvērti visi šī konta pārskati.
|
||||||
warning_preset_id: Neobligāts. Tu joprojām vari pievienot pielāgotu tekstu sākotnējās iestatīšanas beigās
|
warning_preset_id: Neobligāts. Tu joprojām vari pievienot pielāgotu tekstu sākotnējās iestatīšanas beigās
|
||||||
|
@ -56,8 +56,8 @@ lv:
|
||||||
scopes: Kuriem API lietotnei būs ļauts piekļūt. Ja atlasa augstākā līmeņa tvērumu, nav nepieciešamas atlasīt atsevišķus.
|
scopes: Kuriem API lietotnei būs ļauts piekļūt. Ja atlasa augstākā līmeņa tvērumu, nav nepieciešamas atlasīt atsevišķus.
|
||||||
setting_aggregate_reblogs: Nerādīt jaunus izcēlumus ziņām, kas nesen tika palielinātas (ietekmē tikai nesen saņemtos palielinājumus)
|
setting_aggregate_reblogs: Nerādīt jaunus izcēlumus ziņām, kas nesen tika palielinātas (ietekmē tikai nesen saņemtos palielinājumus)
|
||||||
setting_always_send_emails: Parasti e-pasta paziņojumi netiek sūtīti, kad aktīvi izmantojat Mastodon
|
setting_always_send_emails: Parasti e-pasta paziņojumi netiek sūtīti, kad aktīvi izmantojat Mastodon
|
||||||
setting_default_sensitive: Sensitīva multivide pēc noklusējuma ir paslēpti, un tos var atklāt, noklikšķinot
|
setting_default_sensitive: Pēc noklusējuma jūtīgi informācijas nesēji ir paslēpti, un tos var atklāt ar klikšķi
|
||||||
setting_display_media_default: Paslēpt multividi, kas atzīmēta kā sensitīva
|
setting_display_media_default: Paslēpt informācijas nesējus, kas atzīmēti kā jūtīgi
|
||||||
setting_display_media_hide_all: Vienmēr slēpt multividi
|
setting_display_media_hide_all: Vienmēr slēpt multividi
|
||||||
setting_display_media_show_all: Vienmēr rādīt multividi
|
setting_display_media_show_all: Vienmēr rādīt multividi
|
||||||
setting_system_scrollbars_ui: Attiecas tikai uz darbvirsmas pārlūkiem, kuru pamatā ir Safari vai Chrome
|
setting_system_scrollbars_ui: Attiecas tikai uz darbvirsmas pārlūkiem, kuru pamatā ir Safari vai Chrome
|
||||||
|
@ -179,7 +179,7 @@ lv:
|
||||||
types:
|
types:
|
||||||
disable: Iesaldēt
|
disable: Iesaldēt
|
||||||
none: Nosūtīt brīdinājumu
|
none: Nosūtīt brīdinājumu
|
||||||
sensitive: Sensitīvs
|
sensitive: Jūtīgs
|
||||||
silence: Ierobežot
|
silence: Ierobežot
|
||||||
suspend: Apturēt
|
suspend: Apturēt
|
||||||
warning_preset_id: Lietot iepriekš iestatītus brīdinājumus
|
warning_preset_id: Lietot iepriekš iestatītus brīdinājumus
|
||||||
|
@ -223,7 +223,7 @@ lv:
|
||||||
setting_boost_modal: Rādīt apstiprinājuma dialogu pirms izcelšanas
|
setting_boost_modal: Rādīt apstiprinājuma dialogu pirms izcelšanas
|
||||||
setting_default_language: Publicēšanas valoda
|
setting_default_language: Publicēšanas valoda
|
||||||
setting_default_privacy: Publicēšanas privātums
|
setting_default_privacy: Publicēšanas privātums
|
||||||
setting_default_sensitive: Atļaut atzīmēt multividi kā sensitīvu
|
setting_default_sensitive: Vienmēr atzīmēt informācijas nesējus kā jūtīgus
|
||||||
setting_delete_modal: Parādīt apstiprinājuma dialogu pirms ziņas dzēšanas
|
setting_delete_modal: Parādīt apstiprinājuma dialogu pirms ziņas dzēšanas
|
||||||
setting_disable_hover_cards: Atspējot profila priekšskatījumu pēc kursora novietošanas
|
setting_disable_hover_cards: Atspējot profila priekšskatījumu pēc kursora novietošanas
|
||||||
setting_disable_swiping: Atspējot vilkšanas kustības
|
setting_disable_swiping: Atspējot vilkšanas kustības
|
||||||
|
|
|
@ -75,6 +75,7 @@ pt-PT:
|
||||||
filters:
|
filters:
|
||||||
action: Escolha qual a ação a executar quando uma publicação corresponde ao filtro
|
action: Escolha qual a ação a executar quando uma publicação corresponde ao filtro
|
||||||
actions:
|
actions:
|
||||||
|
blur: Esconder multimédia com um aviso à frente, sem esconder o texto
|
||||||
hide: Ocultar completamente o conteúdo filtrado, comportando-se como se não existisse
|
hide: Ocultar completamente o conteúdo filtrado, comportando-se como se não existisse
|
||||||
warn: Ocultar o conteúdo filtrado por trás de um aviso mencionando o título do filtro
|
warn: Ocultar o conteúdo filtrado por trás de um aviso mencionando o título do filtro
|
||||||
form_admin_settings:
|
form_admin_settings:
|
||||||
|
@ -260,6 +261,7 @@ pt-PT:
|
||||||
name: Etiqueta
|
name: Etiqueta
|
||||||
filters:
|
filters:
|
||||||
actions:
|
actions:
|
||||||
|
blur: Esconder multimédia com um aviso
|
||||||
hide: Ocultar por completo
|
hide: Ocultar por completo
|
||||||
warn: Ocultar com um aviso
|
warn: Ocultar com um aviso
|
||||||
form_admin_settings:
|
form_admin_settings:
|
||||||
|
|
|
@ -1,112 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'rails_helper'
|
|
||||||
|
|
||||||
RSpec.describe ActivityPub::InboxesController do
|
|
||||||
let(:remote_account) { nil }
|
|
||||||
|
|
||||||
before do
|
|
||||||
allow(controller).to receive(:signed_request_actor).and_return(remote_account)
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'POST #create' do
|
|
||||||
context 'with signature' do
|
|
||||||
let(:remote_account) { Fabricate(:account, domain: 'example.com', protocol: :activitypub) }
|
|
||||||
|
|
||||||
before do
|
|
||||||
post :create, body: '{}'
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns http accepted' do
|
|
||||||
expect(response).to have_http_status(202)
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with a specific account' do
|
|
||||||
subject(:response) { post :create, params: { account_username: account.username }, body: '{}' }
|
|
||||||
|
|
||||||
let(:account) { Fabricate(:account) }
|
|
||||||
|
|
||||||
context 'when account is permanently suspended' do
|
|
||||||
before do
|
|
||||||
account.suspend!
|
|
||||||
account.deletion_request.destroy
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns http gone' do
|
|
||||||
expect(response).to have_http_status(410)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when account is temporarily suspended' do
|
|
||||||
before do
|
|
||||||
account.suspend!
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns http accepted' do
|
|
||||||
expect(response).to have_http_status(202)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with Collection-Synchronization header' do
|
|
||||||
let(:remote_account) { Fabricate(:account, followers_url: 'https://example.com/followers', domain: 'example.com', uri: 'https://example.com/actor', protocol: :activitypub) }
|
|
||||||
let(:synchronization_collection) { remote_account.followers_url }
|
|
||||||
let(:synchronization_url) { 'https://example.com/followers-for-domain' }
|
|
||||||
let(:synchronization_hash) { 'somehash' }
|
|
||||||
let(:synchronization_header) { "collectionId=\"#{synchronization_collection}\", digest=\"#{synchronization_hash}\", url=\"#{synchronization_url}\"" }
|
|
||||||
|
|
||||||
before do
|
|
||||||
allow(ActivityPub::FollowersSynchronizationWorker).to receive(:perform_async).and_return(nil)
|
|
||||||
allow(remote_account).to receive(:local_followers_hash).and_return('somehash')
|
|
||||||
|
|
||||||
request.headers['Collection-Synchronization'] = synchronization_header
|
|
||||||
post :create, body: '{}'
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with mismatching target collection' do
|
|
||||||
let(:synchronization_collection) { 'https://example.com/followers2' }
|
|
||||||
|
|
||||||
it 'does not start a synchronization job' do
|
|
||||||
expect(ActivityPub::FollowersSynchronizationWorker).to_not have_received(:perform_async)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with mismatching domain in partial collection attribute' do
|
|
||||||
let(:synchronization_url) { 'https://example.org/followers' }
|
|
||||||
|
|
||||||
it 'does not start a synchronization job' do
|
|
||||||
expect(ActivityPub::FollowersSynchronizationWorker).to_not have_received(:perform_async)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with matching digest' do
|
|
||||||
it 'does not start a synchronization job' do
|
|
||||||
expect(ActivityPub::FollowersSynchronizationWorker).to_not have_received(:perform_async)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with mismatching digest' do
|
|
||||||
let(:synchronization_hash) { 'wronghash' }
|
|
||||||
|
|
||||||
it 'starts a synchronization job' do
|
|
||||||
expect(ActivityPub::FollowersSynchronizationWorker).to have_received(:perform_async)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns http accepted' do
|
|
||||||
expect(response).to have_http_status(202)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'without signature' do
|
|
||||||
before do
|
|
||||||
post :create, body: '{}'
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns http not authorized' do
|
|
||||||
expect(response).to have_http_status(401)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -13,13 +13,28 @@ RSpec.describe AccountReachFinder do
|
||||||
let(:ap_mentioned_example_com) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://example.com/inbox-3', domain: 'example.com') }
|
let(:ap_mentioned_example_com) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://example.com/inbox-3', domain: 'example.com') }
|
||||||
let(:ap_mentioned_example_org) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://example.org/inbox-4', domain: 'example.org') }
|
let(:ap_mentioned_example_org) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://example.org/inbox-4', domain: 'example.org') }
|
||||||
|
|
||||||
|
let(:ap_followed_example_com) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://example.com/inbox-5', domain: 'example.com') }
|
||||||
|
let(:ap_followed_example_org) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://example.com/inbox-6', domain: 'example.org') }
|
||||||
|
|
||||||
|
let(:ap_requested_example_com) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://example.com/inbox-7', domain: 'example.com') }
|
||||||
|
let(:ap_requested_example_org) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://example.com/inbox-8', domain: 'example.org') }
|
||||||
|
|
||||||
let(:unrelated_account) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://example.com/unrelated-inbox', domain: 'example.com') }
|
let(:unrelated_account) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://example.com/unrelated-inbox', domain: 'example.com') }
|
||||||
|
let(:old_followed_account) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://example.com/old-followed-inbox', domain: 'example.com') }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
travel_to(2.months.ago) { account.follow!(old_followed_account) }
|
||||||
|
|
||||||
ap_follower_example_com.follow!(account)
|
ap_follower_example_com.follow!(account)
|
||||||
ap_follower_example_org.follow!(account)
|
ap_follower_example_org.follow!(account)
|
||||||
ap_follower_with_shared.follow!(account)
|
ap_follower_with_shared.follow!(account)
|
||||||
|
|
||||||
|
account.follow!(ap_followed_example_com)
|
||||||
|
account.follow!(ap_followed_example_org)
|
||||||
|
|
||||||
|
account.request_follow!(ap_requested_example_com)
|
||||||
|
account.request_follow!(ap_requested_example_org)
|
||||||
|
|
||||||
Fabricate(:status, account: account).tap do |status|
|
Fabricate(:status, account: account).tap do |status|
|
||||||
status.mentions << Mention.new(account: ap_follower_example_com)
|
status.mentions << Mention.new(account: ap_follower_example_com)
|
||||||
status.mentions << Mention.new(account: ap_mentioned_with_shared)
|
status.mentions << Mention.new(account: ap_mentioned_with_shared)
|
||||||
|
@ -44,7 +59,10 @@ RSpec.describe AccountReachFinder do
|
||||||
expect(subject)
|
expect(subject)
|
||||||
.to include(*follower_inbox_urls)
|
.to include(*follower_inbox_urls)
|
||||||
.and include(*mentioned_account_inbox_urls)
|
.and include(*mentioned_account_inbox_urls)
|
||||||
|
.and include(*recently_followed_inbox_urls)
|
||||||
|
.and include(*recently_requested_inbox_urls)
|
||||||
.and not_include(unrelated_account.preferred_inbox_url)
|
.and not_include(unrelated_account.preferred_inbox_url)
|
||||||
|
.and not_include(old_followed_account.preferred_inbox_url)
|
||||||
end
|
end
|
||||||
|
|
||||||
def follower_inbox_urls
|
def follower_inbox_urls
|
||||||
|
@ -56,5 +74,15 @@ RSpec.describe AccountReachFinder do
|
||||||
[ap_mentioned_with_shared, ap_mentioned_example_com, ap_mentioned_example_org]
|
[ap_mentioned_with_shared, ap_mentioned_example_com, ap_mentioned_example_org]
|
||||||
.map(&:preferred_inbox_url)
|
.map(&:preferred_inbox_url)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def recently_followed_inbox_urls
|
||||||
|
[ap_followed_example_com, ap_followed_example_org]
|
||||||
|
.map(&:preferred_inbox_url)
|
||||||
|
end
|
||||||
|
|
||||||
|
def recently_requested_inbox_urls
|
||||||
|
[ap_requested_example_com, ap_requested_example_org]
|
||||||
|
.map(&:preferred_inbox_url)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,22 +2,19 @@
|
||||||
|
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe ActivityPub::CollectionsController do
|
RSpec.describe 'ActivityPub Collections' do
|
||||||
let!(:account) { Fabricate(:account) }
|
let!(:account) { Fabricate(:account) }
|
||||||
let!(:private_pinned) { Fabricate(:status, account: account, text: 'secret private stuff', visibility: :private) }
|
let!(:private_pinned) { Fabricate(:status, account: account, text: 'secret private stuff', visibility: :private) }
|
||||||
let(:remote_account) { nil }
|
let(:remote_account) { nil }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
allow(controller).to receive(:signed_request_actor).and_return(remote_account)
|
Fabricate.times(2, :status_pin, account: account)
|
||||||
|
|
||||||
Fabricate(:status_pin, account: account)
|
|
||||||
Fabricate(:status_pin, account: account)
|
|
||||||
Fabricate(:status_pin, account: account, status: private_pinned)
|
Fabricate(:status_pin, account: account, status: private_pinned)
|
||||||
Fabricate(:status, account: account, visibility: :private)
|
Fabricate(:status, account: account, visibility: :private)
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'GET #show' do
|
describe 'GET #show' do
|
||||||
subject(:response) { get :show, params: { id: id, account_username: account.username } }
|
subject { get account_collection_path(id: id, account_username: account.username), headers: nil, sign_with: remote_account }
|
||||||
|
|
||||||
context 'when id is "featured"' do
|
context 'when id is "featured"' do
|
||||||
let(:id) { 'featured' }
|
let(:id) { 'featured' }
|
||||||
|
@ -26,10 +23,13 @@ RSpec.describe ActivityPub::CollectionsController do
|
||||||
let(:remote_account) { nil }
|
let(:remote_account) { nil }
|
||||||
|
|
||||||
it 'returns http success and correct media type and correct items' do
|
it 'returns http success and correct media type and correct items' do
|
||||||
|
subject
|
||||||
|
|
||||||
expect(response)
|
expect(response)
|
||||||
.to have_http_status(200)
|
.to have_http_status(200)
|
||||||
.and have_cacheable_headers
|
.and have_cacheable_headers
|
||||||
expect(response.media_type).to eq 'application/activity+json'
|
expect(response.media_type)
|
||||||
|
.to eq 'application/activity+json'
|
||||||
|
|
||||||
expect(response.parsed_body[:orderedItems])
|
expect(response.parsed_body[:orderedItems])
|
||||||
.to be_an(Array)
|
.to be_an(Array)
|
||||||
|
@ -45,17 +45,21 @@ RSpec.describe ActivityPub::CollectionsController do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns http gone' do
|
it 'returns http gone' do
|
||||||
expect(response).to have_http_status(410)
|
subject
|
||||||
|
|
||||||
|
expect(response)
|
||||||
|
.to have_http_status(410)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when account is temporarily suspended' do
|
context 'when account is temporarily suspended' do
|
||||||
before do
|
before { account.suspend! }
|
||||||
account.suspend!
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns http forbidden' do
|
it 'returns http forbidden' do
|
||||||
expect(response).to have_http_status(403)
|
subject
|
||||||
|
|
||||||
|
expect(response)
|
||||||
|
.to have_http_status(403)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -65,11 +69,14 @@ RSpec.describe ActivityPub::CollectionsController do
|
||||||
|
|
||||||
context 'when getting a featured resource' do
|
context 'when getting a featured resource' do
|
||||||
it 'returns http success and correct media type and expected items' do
|
it 'returns http success and correct media type and expected items' do
|
||||||
|
subject
|
||||||
|
|
||||||
expect(response)
|
expect(response)
|
||||||
.to have_http_status(200)
|
.to have_http_status(200)
|
||||||
.and have_cacheable_headers
|
.and have_cacheable_headers
|
||||||
|
|
||||||
expect(response.media_type).to eq 'application/activity+json'
|
expect(response.media_type)
|
||||||
|
.to eq 'application/activity+json'
|
||||||
|
|
||||||
expect(response.parsed_body[:orderedItems])
|
expect(response.parsed_body[:orderedItems])
|
||||||
.to be_an(Array)
|
.to be_an(Array)
|
||||||
|
@ -80,39 +87,45 @@ RSpec.describe ActivityPub::CollectionsController do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with authorized fetch mode' do
|
context 'with authorized fetch mode' do
|
||||||
before do
|
before { Setting.authorized_fetch = true }
|
||||||
allow(controller).to receive(:authorized_fetch_mode?).and_return(true)
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when signed request account is blocked' do
|
context 'when signed request account is blocked' do
|
||||||
before do
|
before { account.block!(remote_account) }
|
||||||
account.block!(remote_account)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns http success and correct media type and cache headers and empty items' do
|
it 'returns http success and correct media type and cache headers and empty items' do
|
||||||
expect(response).to have_http_status(200)
|
subject
|
||||||
expect(response.media_type).to eq 'application/activity+json'
|
|
||||||
expect(response.headers['Cache-Control']).to include 'private'
|
|
||||||
|
|
||||||
expect(response.parsed_body[:orderedItems])
|
expect(response)
|
||||||
.to be_an(Array)
|
.to have_http_status(200)
|
||||||
.and be_empty
|
expect(response.media_type)
|
||||||
|
.to eq('application/activity+json')
|
||||||
|
expect(response.headers['Cache-Control'])
|
||||||
|
.to include('private')
|
||||||
|
|
||||||
|
expect(response.parsed_body)
|
||||||
|
.to include(
|
||||||
|
orderedItems: be_an(Array).and(be_empty)
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when signed request account is domain blocked' do
|
context 'when signed request account is domain blocked' do
|
||||||
before do
|
before { account.block_domain!(remote_account.domain) }
|
||||||
account.block_domain!(remote_account.domain)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns http success and correct media type and cache headers and empty items' do
|
it 'returns http success and correct media type and cache headers and empty items' do
|
||||||
expect(response).to have_http_status(200)
|
subject
|
||||||
expect(response.media_type).to eq 'application/activity+json'
|
|
||||||
expect(response.headers['Cache-Control']).to include 'private'
|
|
||||||
|
|
||||||
expect(response.parsed_body[:orderedItems])
|
expect(response)
|
||||||
.to be_an(Array)
|
.to have_http_status(200)
|
||||||
.and be_empty
|
expect(response.media_type)
|
||||||
|
.to eq('application/activity+json')
|
||||||
|
expect(response.headers['Cache-Control'])
|
||||||
|
.to include('private')
|
||||||
|
|
||||||
|
expect(response.parsed_body)
|
||||||
|
.to include(
|
||||||
|
orderedItems: be_an(Array).and(be_empty)
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -123,7 +136,10 @@ RSpec.describe ActivityPub::CollectionsController do
|
||||||
let(:id) { 'hoge' }
|
let(:id) { 'hoge' }
|
||||||
|
|
||||||
it 'returns http not found' do
|
it 'returns http not found' do
|
||||||
expect(response).to have_http_status(404)
|
subject
|
||||||
|
|
||||||
|
expect(response)
|
||||||
|
.to have_http_status(404)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe ActivityPub::FollowersSynchronizationsController do
|
RSpec.describe 'ActivityPub Follower Synchronizations' do
|
||||||
let!(:account) { Fabricate(:account) }
|
let!(:account) { Fabricate(:account) }
|
||||||
let!(:follower_example_com_user_a) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/users/a') }
|
let!(:follower_example_com_user_a) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/users/a') }
|
||||||
let!(:follower_example_com_user_b) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/users/b') }
|
let!(:follower_example_com_user_b) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/users/b') }
|
||||||
|
@ -14,32 +14,34 @@ RSpec.describe ActivityPub::FollowersSynchronizationsController do
|
||||||
follower_example_com_user_b.follow!(account)
|
follower_example_com_user_b.follow!(account)
|
||||||
follower_foo_com_user_a.follow!(account)
|
follower_foo_com_user_a.follow!(account)
|
||||||
follower_example_com_instance_actor.follow!(account)
|
follower_example_com_instance_actor.follow!(account)
|
||||||
|
|
||||||
allow(controller).to receive(:signed_request_actor).and_return(remote_account)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'GET #show' do
|
describe 'GET #show' do
|
||||||
context 'without signature' do
|
context 'without signature' do
|
||||||
let(:remote_account) { nil }
|
subject { get account_followers_synchronization_path(account_username: account.username) }
|
||||||
|
|
||||||
before do
|
|
||||||
get :show, params: { account_username: account.username }
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns http not authorized' do
|
it 'returns http not authorized' do
|
||||||
expect(response).to have_http_status(401)
|
subject
|
||||||
|
|
||||||
|
expect(response)
|
||||||
|
.to have_http_status(401)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with signature from example.com' do
|
context 'with signature from example.com' do
|
||||||
subject(:response) { get :show, params: { account_username: account.username } }
|
subject { get account_followers_synchronization_path(account_username: account.username), headers: nil, sign_with: remote_account }
|
||||||
|
|
||||||
let(:remote_account) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/instance') }
|
let(:remote_account) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/instance') }
|
||||||
|
|
||||||
it 'returns http success and cache control and activity json types and correct items' do
|
it 'returns http success and cache control and activity json types and correct items' do
|
||||||
expect(response).to have_http_status(200)
|
subject
|
||||||
expect(response.headers['Cache-Control']).to eq 'max-age=0, private'
|
|
||||||
expect(response.media_type).to eq 'application/activity+json'
|
expect(response)
|
||||||
|
.to have_http_status(200)
|
||||||
|
expect(response.headers['Cache-Control'])
|
||||||
|
.to eq 'max-age=0, private'
|
||||||
|
expect(response.media_type)
|
||||||
|
.to eq 'application/activity+json'
|
||||||
|
|
||||||
expect(response.parsed_body[:orderedItems])
|
expect(response.parsed_body[:orderedItems])
|
||||||
.to be_an(Array)
|
.to be_an(Array)
|
||||||
|
@ -57,17 +59,21 @@ RSpec.describe ActivityPub::FollowersSynchronizationsController do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns http gone' do
|
it 'returns http gone' do
|
||||||
expect(response).to have_http_status(410)
|
subject
|
||||||
|
|
||||||
|
expect(response)
|
||||||
|
.to have_http_status(410)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when account is temporarily suspended' do
|
context 'when account is temporarily suspended' do
|
||||||
before do
|
before { account.suspend! }
|
||||||
account.suspend!
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns http forbidden' do
|
it 'returns http forbidden' do
|
||||||
expect(response).to have_http_status(403)
|
subject
|
||||||
|
|
||||||
|
expect(response)
|
||||||
|
.to have_http_status(403)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
148
spec/requests/activitypub/inboxes_spec.rb
Normal file
148
spec/requests/activitypub/inboxes_spec.rb
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe 'ActivityPub Inboxes' do
|
||||||
|
let(:remote_account) { nil }
|
||||||
|
|
||||||
|
describe 'POST #create' do
|
||||||
|
context 'with signature' do
|
||||||
|
let(:remote_account) { Fabricate(:account, domain: 'example.com', protocol: :activitypub) }
|
||||||
|
|
||||||
|
context 'without a named account' do
|
||||||
|
subject { post inbox_path, params: {}.to_json, sign_with: remote_account }
|
||||||
|
|
||||||
|
it 'returns http accepted' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response)
|
||||||
|
.to have_http_status(202)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with a specific account' do
|
||||||
|
subject { post account_inbox_path(account_username: account.username), params: {}.to_json, sign_with: remote_account }
|
||||||
|
|
||||||
|
let(:account) { Fabricate(:account) }
|
||||||
|
|
||||||
|
context 'when account is permanently suspended' do
|
||||||
|
before do
|
||||||
|
account.suspend!
|
||||||
|
account.deletion_request.destroy
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns http gone' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response)
|
||||||
|
.to have_http_status(410)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when account is temporarily suspended' do
|
||||||
|
before { account.suspend! }
|
||||||
|
|
||||||
|
it 'returns http accepted' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response)
|
||||||
|
.to have_http_status(202)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with Collection-Synchronization header' do
|
||||||
|
subject { post inbox_path, params: {}.to_json, headers: { 'Collection-Synchronization' => synchronization_header }, sign_with: remote_account }
|
||||||
|
|
||||||
|
let(:remote_account) { Fabricate(:account, followers_url: 'https://example.com/followers', domain: 'example.com', uri: 'https://example.com/actor', protocol: :activitypub) }
|
||||||
|
let(:synchronization_collection) { remote_account.followers_url }
|
||||||
|
let(:synchronization_url) { 'https://example.com/followers-for-domain' }
|
||||||
|
let(:synchronization_hash) { 'somehash' }
|
||||||
|
let(:synchronization_header) { "collectionId=\"#{synchronization_collection}\", digest=\"#{synchronization_hash}\", url=\"#{synchronization_url}\"" }
|
||||||
|
|
||||||
|
before do
|
||||||
|
stub_follow_sync_worker
|
||||||
|
stub_followers_hash
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with mismatching target collection' do
|
||||||
|
let(:synchronization_collection) { 'https://example.com/followers2' }
|
||||||
|
|
||||||
|
it 'does not start a synchronization job' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response)
|
||||||
|
.to have_http_status(202)
|
||||||
|
expect(ActivityPub::FollowersSynchronizationWorker)
|
||||||
|
.to_not have_received(:perform_async)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with mismatching domain in partial collection attribute' do
|
||||||
|
let(:synchronization_url) { 'https://example.org/followers' }
|
||||||
|
|
||||||
|
it 'does not start a synchronization job' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response)
|
||||||
|
.to have_http_status(202)
|
||||||
|
expect(ActivityPub::FollowersSynchronizationWorker)
|
||||||
|
.to_not have_received(:perform_async)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with matching digest' do
|
||||||
|
it 'does not start a synchronization job' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response)
|
||||||
|
.to have_http_status(202)
|
||||||
|
expect(ActivityPub::FollowersSynchronizationWorker)
|
||||||
|
.to_not have_received(:perform_async)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with mismatching digest' do
|
||||||
|
let(:synchronization_hash) { 'wronghash' }
|
||||||
|
|
||||||
|
it 'starts a synchronization job' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response)
|
||||||
|
.to have_http_status(202)
|
||||||
|
expect(ActivityPub::FollowersSynchronizationWorker)
|
||||||
|
.to have_received(:perform_async)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns http accepted' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response)
|
||||||
|
.to have_http_status(202)
|
||||||
|
end
|
||||||
|
|
||||||
|
def stub_follow_sync_worker
|
||||||
|
allow(ActivityPub::FollowersSynchronizationWorker)
|
||||||
|
.to receive(:perform_async)
|
||||||
|
.and_return(nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
def stub_followers_hash
|
||||||
|
Rails.cache.write("followers_hash:#{remote_account.id}:local", 'somehash') # Populate value to match request
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'without signature' do
|
||||||
|
subject { post inbox_path, params: {}.to_json }
|
||||||
|
|
||||||
|
it 'returns http not authorized' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response)
|
||||||
|
.to have_http_status(401)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe ActivityPub::OutboxesController do
|
RSpec.describe 'ActivityPub Outboxes' do
|
||||||
let!(:account) { Fabricate(:account) }
|
let!(:account) { Fabricate(:account) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
@ -11,13 +11,11 @@ RSpec.describe ActivityPub::OutboxesController do
|
||||||
Fabricate(:status, account: account, visibility: :private)
|
Fabricate(:status, account: account, visibility: :private)
|
||||||
Fabricate(:status, account: account, visibility: :direct)
|
Fabricate(:status, account: account, visibility: :direct)
|
||||||
Fabricate(:status, account: account, visibility: :limited)
|
Fabricate(:status, account: account, visibility: :limited)
|
||||||
|
|
||||||
allow(controller).to receive(:signed_request_actor).and_return(remote_account)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'GET #show' do
|
describe 'GET #show' do
|
||||||
context 'without signature' do
|
context 'without signature' do
|
||||||
subject(:response) { get :show, params: { account_username: account.username, page: page } }
|
subject { get account_outbox_path(account_username: account.username, page: page) }
|
||||||
|
|
||||||
let(:remote_account) { nil }
|
let(:remote_account) { nil }
|
||||||
|
|
||||||
|
@ -25,13 +23,18 @@ RSpec.describe ActivityPub::OutboxesController do
|
||||||
let(:page) { nil }
|
let(:page) { nil }
|
||||||
|
|
||||||
it 'returns http success and correct media type and headers and items count' do
|
it 'returns http success and correct media type and headers and items count' do
|
||||||
|
subject
|
||||||
|
|
||||||
expect(response)
|
expect(response)
|
||||||
.to have_http_status(200)
|
.to have_http_status(200)
|
||||||
.and have_cacheable_headers
|
.and have_cacheable_headers
|
||||||
|
|
||||||
expect(response.media_type).to eq 'application/activity+json'
|
expect(response.media_type)
|
||||||
expect(response.headers['Vary']).to be_nil
|
.to eq 'application/activity+json'
|
||||||
expect(response.parsed_body[:totalItems]).to eq 4
|
expect(response.headers['Vary'])
|
||||||
|
.to be_nil
|
||||||
|
expect(response.parsed_body[:totalItems])
|
||||||
|
.to eq 4
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when account is permanently suspended' do
|
context 'when account is permanently suspended' do
|
||||||
|
@ -41,17 +44,21 @@ RSpec.describe ActivityPub::OutboxesController do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns http gone' do
|
it 'returns http gone' do
|
||||||
expect(response).to have_http_status(410)
|
subject
|
||||||
|
|
||||||
|
expect(response)
|
||||||
|
.to have_http_status(410)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when account is temporarily suspended' do
|
context 'when account is temporarily suspended' do
|
||||||
before do
|
before { account.suspend! }
|
||||||
account.suspend!
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns http forbidden' do
|
it 'returns http forbidden' do
|
||||||
expect(response).to have_http_status(403)
|
subject
|
||||||
|
|
||||||
|
expect(response)
|
||||||
|
.to have_http_status(403)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -60,12 +67,16 @@ RSpec.describe ActivityPub::OutboxesController do
|
||||||
let(:page) { 'true' }
|
let(:page) { 'true' }
|
||||||
|
|
||||||
it 'returns http success and correct media type and vary header and items' do
|
it 'returns http success and correct media type and vary header and items' do
|
||||||
|
subject
|
||||||
|
|
||||||
expect(response)
|
expect(response)
|
||||||
.to have_http_status(200)
|
.to have_http_status(200)
|
||||||
.and have_cacheable_headers
|
.and have_cacheable_headers
|
||||||
|
|
||||||
expect(response.media_type).to eq 'application/activity+json'
|
expect(response.media_type)
|
||||||
expect(response.headers['Vary']).to include 'Signature'
|
.to eq 'application/activity+json'
|
||||||
|
expect(response.headers['Vary'])
|
||||||
|
.to include 'Signature'
|
||||||
|
|
||||||
expect(response.parsed_body)
|
expect(response.parsed_body)
|
||||||
.to include(
|
.to include(
|
||||||
|
@ -82,35 +93,42 @@ RSpec.describe ActivityPub::OutboxesController do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns http gone' do
|
it 'returns http gone' do
|
||||||
expect(response).to have_http_status(410)
|
subject
|
||||||
|
|
||||||
|
expect(response)
|
||||||
|
.to have_http_status(410)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when account is temporarily suspended' do
|
context 'when account is temporarily suspended' do
|
||||||
before do
|
before { account.suspend! }
|
||||||
account.suspend!
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns http forbidden' do
|
it 'returns http forbidden' do
|
||||||
expect(response).to have_http_status(403)
|
subject
|
||||||
|
|
||||||
|
expect(response)
|
||||||
|
.to have_http_status(403)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with signature' do
|
context 'with signature' do
|
||||||
|
subject { get account_outbox_path(account_username: account.username, page: page), headers: nil, sign_with: remote_account }
|
||||||
|
|
||||||
let(:remote_account) { Fabricate(:account, domain: 'example.com') }
|
let(:remote_account) { Fabricate(:account, domain: 'example.com') }
|
||||||
let(:page) { 'true' }
|
let(:page) { 'true' }
|
||||||
|
|
||||||
context 'when signed request account does not follow account' do
|
context 'when signed request account does not follow account' do
|
||||||
before do
|
|
||||||
get :show, params: { account_username: account.username, page: page }
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns http success and correct media type and headers and items' do
|
it 'returns http success and correct media type and headers and items' do
|
||||||
expect(response).to have_http_status(200)
|
subject
|
||||||
expect(response.media_type).to eq 'application/activity+json'
|
|
||||||
expect(response.headers['Cache-Control']).to eq 'max-age=60, private'
|
expect(response)
|
||||||
|
.to have_http_status(200)
|
||||||
|
expect(response.media_type)
|
||||||
|
.to eq 'application/activity+json'
|
||||||
|
expect(response.headers['Cache-Control'])
|
||||||
|
.to eq 'private, no-store'
|
||||||
|
|
||||||
expect(response.parsed_body)
|
expect(response.parsed_body)
|
||||||
.to include(
|
.to include(
|
||||||
|
@ -122,15 +140,17 @@ RSpec.describe ActivityPub::OutboxesController do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when signed request account follows account' do
|
context 'when signed request account follows account' do
|
||||||
before do
|
before { remote_account.follow!(account) }
|
||||||
remote_account.follow!(account)
|
|
||||||
get :show, params: { account_username: account.username, page: page }
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns http success and correct media type and headers and items' do
|
it 'returns http success and correct media type and headers and items' do
|
||||||
expect(response).to have_http_status(200)
|
subject
|
||||||
expect(response.media_type).to eq 'application/activity+json'
|
|
||||||
expect(response.headers['Cache-Control']).to eq 'max-age=60, private'
|
expect(response)
|
||||||
|
.to have_http_status(200)
|
||||||
|
expect(response.media_type)
|
||||||
|
.to eq 'application/activity+json'
|
||||||
|
expect(response.headers['Cache-Control'])
|
||||||
|
.to eq 'private, no-store'
|
||||||
|
|
||||||
expect(response.parsed_body)
|
expect(response.parsed_body)
|
||||||
.to include(
|
.to include(
|
||||||
|
@ -142,15 +162,17 @@ RSpec.describe ActivityPub::OutboxesController do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when signed request account is blocked' do
|
context 'when signed request account is blocked' do
|
||||||
before do
|
before { account.block!(remote_account) }
|
||||||
account.block!(remote_account)
|
|
||||||
get :show, params: { account_username: account.username, page: page }
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns http success and correct media type and headers and items' do
|
it 'returns http success and correct media type and headers and items' do
|
||||||
expect(response).to have_http_status(200)
|
subject
|
||||||
expect(response.media_type).to eq 'application/activity+json'
|
|
||||||
expect(response.headers['Cache-Control']).to eq 'max-age=60, private'
|
expect(response)
|
||||||
|
.to have_http_status(200)
|
||||||
|
expect(response.media_type)
|
||||||
|
.to eq 'application/activity+json'
|
||||||
|
expect(response.headers['Cache-Control'])
|
||||||
|
.to eq 'private, no-store'
|
||||||
|
|
||||||
expect(response.parsed_body)
|
expect(response.parsed_body)
|
||||||
.to include(
|
.to include(
|
||||||
|
@ -160,15 +182,17 @@ RSpec.describe ActivityPub::OutboxesController do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when signed request account is domain blocked' do
|
context 'when signed request account is domain blocked' do
|
||||||
before do
|
before { account.block_domain!(remote_account.domain) }
|
||||||
account.block_domain!(remote_account.domain)
|
|
||||||
get :show, params: { account_username: account.username, page: page }
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns http success and correct media type and headers and items' do
|
it 'returns http success and correct media type and headers and items' do
|
||||||
expect(response).to have_http_status(200)
|
subject
|
||||||
expect(response.media_type).to eq 'application/activity+json'
|
|
||||||
expect(response.headers['Cache-Control']).to eq 'max-age=60, private'
|
expect(response)
|
||||||
|
.to have_http_status(200)
|
||||||
|
expect(response.media_type)
|
||||||
|
.to eq 'application/activity+json'
|
||||||
|
expect(response.headers['Cache-Control'])
|
||||||
|
.to eq 'private, no-store'
|
||||||
|
|
||||||
expect(response.parsed_body)
|
expect(response.parsed_body)
|
||||||
.to include(
|
.to include(
|
|
@ -2,9 +2,9 @@
|
||||||
|
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe ActivityPub::RepliesController do
|
RSpec.describe 'ActivityPub Replies' do
|
||||||
let(:status) { Fabricate(:status, visibility: parent_visibility) }
|
let(:status) { Fabricate(:status, visibility: parent_visibility) }
|
||||||
let(:remote_account) { Fabricate(:account, domain: 'foobar.com') }
|
let(:remote_account) { Fabricate(:account, domain: 'foobar.com') }
|
||||||
let(:remote_reply_id) { 'https://foobar.com/statuses/1234' }
|
let(:remote_reply_id) { 'https://foobar.com/statuses/1234' }
|
||||||
let(:remote_querier) { nil }
|
let(:remote_querier) { nil }
|
||||||
|
|
||||||
|
@ -13,7 +13,10 @@ RSpec.describe ActivityPub::RepliesController do
|
||||||
let(:parent_visibility) { :private }
|
let(:parent_visibility) { :private }
|
||||||
|
|
||||||
it 'returns http not found' do
|
it 'returns http not found' do
|
||||||
expect(response).to have_http_status(404)
|
subject
|
||||||
|
|
||||||
|
expect(response)
|
||||||
|
.to have_http_status(404)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -21,7 +24,10 @@ RSpec.describe ActivityPub::RepliesController do
|
||||||
let(:parent_visibility) { :direct }
|
let(:parent_visibility) { :direct }
|
||||||
|
|
||||||
it 'returns http not found' do
|
it 'returns http not found' do
|
||||||
expect(response).to have_http_status(404)
|
subject
|
||||||
|
|
||||||
|
expect(response)
|
||||||
|
.to have_http_status(404)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -31,7 +37,10 @@ RSpec.describe ActivityPub::RepliesController do
|
||||||
let(:parent_visibility) { :public }
|
let(:parent_visibility) { :public }
|
||||||
|
|
||||||
it 'returns http not found' do
|
it 'returns http not found' do
|
||||||
expect(response).to have_http_status(404)
|
subject
|
||||||
|
|
||||||
|
expect(response)
|
||||||
|
.to have_http_status(404)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -48,19 +57,23 @@ RSpec.describe ActivityPub::RepliesController do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns http gone' do
|
it 'returns http gone' do
|
||||||
expect(response).to have_http_status(410)
|
subject
|
||||||
|
|
||||||
|
expect(response)
|
||||||
|
.to have_http_status(410)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when account is temporarily suspended' do
|
context 'when account is temporarily suspended' do
|
||||||
let(:parent_visibility) { :public }
|
let(:parent_visibility) { :public }
|
||||||
|
|
||||||
before do
|
before { status.account.suspend! }
|
||||||
status.account.suspend!
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns http forbidden' do
|
it 'returns http forbidden' do
|
||||||
expect(response).to have_http_status(403)
|
subject
|
||||||
|
|
||||||
|
expect(response)
|
||||||
|
.to have_http_status(403)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -68,15 +81,20 @@ RSpec.describe ActivityPub::RepliesController do
|
||||||
let(:parent_visibility) { :public }
|
let(:parent_visibility) { :public }
|
||||||
|
|
||||||
it 'returns http success and correct media type' do
|
it 'returns http success and correct media type' do
|
||||||
|
subject
|
||||||
|
|
||||||
expect(response)
|
expect(response)
|
||||||
.to have_http_status(200)
|
.to have_http_status(200)
|
||||||
.and have_cacheable_headers
|
.and have_cacheable_headers
|
||||||
|
|
||||||
expect(response.media_type).to eq 'application/activity+json'
|
expect(response.media_type)
|
||||||
|
.to eq 'application/activity+json'
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'without only_other_accounts' do
|
context 'without `only_other_accounts` param' do
|
||||||
it "returns items with thread author's replies" do
|
it "returns items with thread author's replies" do
|
||||||
|
subject
|
||||||
|
|
||||||
expect(response.parsed_body)
|
expect(response.parsed_body)
|
||||||
.to include(
|
.to include(
|
||||||
first: be_a(Hash).and(
|
first: be_a(Hash).and(
|
||||||
|
@ -91,6 +109,8 @@ RSpec.describe ActivityPub::RepliesController do
|
||||||
|
|
||||||
context 'when there are few self-replies' do
|
context 'when there are few self-replies' do
|
||||||
it 'points next to replies from other people' do
|
it 'points next to replies from other people' do
|
||||||
|
subject
|
||||||
|
|
||||||
expect(response.parsed_body)
|
expect(response.parsed_body)
|
||||||
.to include(
|
.to include(
|
||||||
first: be_a(Hash).and(
|
first: be_a(Hash).and(
|
||||||
|
@ -108,6 +128,8 @@ RSpec.describe ActivityPub::RepliesController do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'points next to other self-replies' do
|
it 'points next to other self-replies' do
|
||||||
|
subject
|
||||||
|
|
||||||
expect(response.parsed_body)
|
expect(response.parsed_body)
|
||||||
.to include(
|
.to include(
|
||||||
first: be_a(Hash).and(
|
first: be_a(Hash).and(
|
||||||
|
@ -120,31 +142,33 @@ RSpec.describe ActivityPub::RepliesController do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with only_other_accounts' do
|
context 'with `only_other_accounts` param' do
|
||||||
let(:only_other_accounts) { 'true' }
|
let(:only_other_accounts) { 'true' }
|
||||||
|
|
||||||
it 'returns items with other public or unlisted replies' do
|
it 'returns items with other public or unlisted replies and correctly inlines replies and uses IDs' do
|
||||||
|
subject
|
||||||
|
|
||||||
expect(response.parsed_body)
|
expect(response.parsed_body)
|
||||||
.to include(
|
.to include(
|
||||||
first: be_a(Hash).and(
|
first: be_a(Hash).and(
|
||||||
include(items: be_an(Array).and(have_attributes(size: 3)))
|
include(items: be_an(Array).and(have_attributes(size: 3)))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
end
|
|
||||||
|
|
||||||
it 'only inlines items that are local and public or unlisted replies' do
|
# Only inline replies that are local and public, or unlisted
|
||||||
expect(inlined_replies)
|
expect(inlined_replies)
|
||||||
.to all(satisfy { |item| targets_public_collection?(item) })
|
.to all(satisfy { |item| targets_public_collection?(item) })
|
||||||
.and all(satisfy { |item| ActivityPub::TagManager.instance.local_uri?(item[:id]) })
|
.and all(satisfy { |item| ActivityPub::TagManager.instance.local_uri?(item[:id]) })
|
||||||
end
|
|
||||||
|
|
||||||
it 'uses ids for remote toots' do
|
# Use ids for remote replies
|
||||||
expect(remote_replies)
|
expect(remote_replies)
|
||||||
.to all(satisfy { |item| item.is_a?(String) && !ActivityPub::TagManager.instance.local_uri?(item) })
|
.to all(satisfy { |item| item.is_a?(String) && !ActivityPub::TagManager.instance.local_uri?(item) })
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when there are few replies' do
|
context 'when there are few replies' do
|
||||||
it 'does not have a next page' do
|
it 'does not have a next page' do
|
||||||
|
subject
|
||||||
|
|
||||||
expect(response.parsed_body)
|
expect(response.parsed_body)
|
||||||
.to include(
|
.to include(
|
||||||
first: be_a(Hash).and(not_include(next: be_present))
|
first: be_a(Hash).and(not_include(next: be_present))
|
||||||
|
@ -158,6 +182,8 @@ RSpec.describe ActivityPub::RepliesController do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'points next to other replies' do
|
it 'points next to other replies' do
|
||||||
|
subject
|
||||||
|
|
||||||
expect(response.parsed_body)
|
expect(response.parsed_body)
|
||||||
.to include(
|
.to include(
|
||||||
first: be_a(Hash).and(
|
first: be_a(Hash).and(
|
||||||
|
@ -176,10 +202,8 @@ RSpec.describe ActivityPub::RepliesController do
|
||||||
|
|
||||||
before do
|
before do
|
||||||
stub_const 'ActivityPub::RepliesController::DESCENDANTS_LIMIT', 5
|
stub_const 'ActivityPub::RepliesController::DESCENDANTS_LIMIT', 5
|
||||||
allow(controller).to receive(:signed_request_actor).and_return(remote_querier)
|
|
||||||
|
|
||||||
Fabricate(:status, thread: status, visibility: :public)
|
Fabricate.times(2, :status, thread: status, visibility: :public)
|
||||||
Fabricate(:status, thread: status, visibility: :public)
|
|
||||||
Fabricate(:status, thread: status, visibility: :private)
|
Fabricate(:status, thread: status, visibility: :private)
|
||||||
Fabricate(:status, account: status.account, thread: status, visibility: :public)
|
Fabricate(:status, account: status.account, thread: status, visibility: :public)
|
||||||
Fabricate(:status, account: status.account, thread: status, visibility: :private)
|
Fabricate(:status, account: status.account, thread: status, visibility: :private)
|
||||||
|
@ -188,31 +212,29 @@ RSpec.describe ActivityPub::RepliesController do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'GET #index' do
|
describe 'GET #index' do
|
||||||
subject(:response) { get :index, params: { account_username: status.account.username, status_id: status.id, only_other_accounts: only_other_accounts } }
|
|
||||||
|
|
||||||
let(:only_other_accounts) { nil }
|
let(:only_other_accounts) { nil }
|
||||||
|
|
||||||
context 'with no signature' do
|
context 'with no signature' do
|
||||||
|
subject { get account_status_replies_path(account_username: status.account.username, status_id: status.id, only_other_accounts: only_other_accounts) }
|
||||||
|
|
||||||
it_behaves_like 'allowed access'
|
it_behaves_like 'allowed access'
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with signature' do
|
context 'with signature' do
|
||||||
|
subject { get account_status_replies_path(account_username: status.account.username, status_id: status.id, only_other_accounts: only_other_accounts), headers: nil, sign_with: remote_querier }
|
||||||
|
|
||||||
let(:remote_querier) { Fabricate(:account, domain: 'example.com') }
|
let(:remote_querier) { Fabricate(:account, domain: 'example.com') }
|
||||||
|
|
||||||
it_behaves_like 'allowed access'
|
it_behaves_like 'allowed access'
|
||||||
|
|
||||||
context 'when signed request account is blocked' do
|
context 'when signed request account is blocked' do
|
||||||
before do
|
before { status.account.block!(remote_querier) }
|
||||||
status.account.block!(remote_querier)
|
|
||||||
end
|
|
||||||
|
|
||||||
it_behaves_like 'disallowed access'
|
it_behaves_like 'disallowed access'
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when signed request account is domain blocked' do
|
context 'when signed request account is domain blocked' do
|
||||||
before do
|
before { status.account.block_domain!(remote_querier.domain) }
|
||||||
status.account.block_domain!(remote_querier.domain)
|
|
||||||
end
|
|
||||||
|
|
||||||
it_behaves_like 'disallowed access'
|
it_behaves_like 'disallowed access'
|
||||||
end
|
end
|
|
@ -18,4 +18,24 @@ module SignedRequestHelpers
|
||||||
|
|
||||||
super(path, headers: headers, **args)
|
super(path, headers: headers, **args)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def post(path, headers: nil, sign_with: nil, **args)
|
||||||
|
return super(path, headers: headers, **args) if sign_with.nil?
|
||||||
|
|
||||||
|
headers ||= {}
|
||||||
|
headers['Date'] = Time.now.utc.httpdate
|
||||||
|
headers['Host'] = Rails.configuration.x.local_domain
|
||||||
|
headers['Digest'] = "SHA-256=#{Digest::SHA256.base64digest(args[:params].to_s)}"
|
||||||
|
|
||||||
|
signed_headers = headers.merge('(request-target)' => "post #{path}").slice('(request-target)', 'Host', 'Date', 'Digest')
|
||||||
|
|
||||||
|
key_id = ActivityPub::TagManager.instance.key_uri_for(sign_with)
|
||||||
|
keypair = sign_with.keypair
|
||||||
|
signed_string = signed_headers.map { |key, value| "#{key.downcase}: #{value}" }.join("\n")
|
||||||
|
signature = Base64.strict_encode64(keypair.sign(OpenSSL::Digest.new('SHA256'), signed_string))
|
||||||
|
|
||||||
|
headers['Signature'] = "keyId=\"#{key_id}\",algorithm=\"rsa-sha256\",headers=\"#{signed_headers.keys.join(' ').downcase}\",signature=\"#{signature}\""
|
||||||
|
|
||||||
|
super(path, headers: headers, **args)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -24,9 +24,6 @@ RSpec.describe 'Account notes', :inline_jobs, :js, :streaming do
|
||||||
# The easiest way is to send ctrl+enter ourselves
|
# The easiest way is to send ctrl+enter ourselves
|
||||||
find_field(class: 'account__header__account-note__content').send_keys [:control, :enter]
|
find_field(class: 'account__header__account-note__content').send_keys [:control, :enter]
|
||||||
|
|
||||||
expect(page)
|
|
||||||
.to have_css('.account__header__account-note .inline-alert', text: 'SAVED')
|
|
||||||
|
|
||||||
expect(page)
|
expect(page)
|
||||||
.to have_css('.account__header__account-note__content', text: note_text)
|
.to have_css('.account__header__account-note__content', text: note_text)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue