Merge commit 'c91c0175db1cc8b954a977d29472886234ce9586' into glitch-soc/merge-upstream
Conflicts: - `spec/controllers/api/v1/timelines/tag_controller_spec.rb`: Glitch-soc had a few extra lines in this file to account for a different default setting. This file got replaced by `spec/requests/api/v1/timelines/tag_spec.rb`, into which the glitch-soc additions were moved too. Additional changes: - `spec/requests/api/v1/statuses/sources_spec.rb`: Add glitch-soc-only attribute `content_type`.
This commit is contained in:
commit
b867d4581e
89 changed files with 1738 additions and 2169 deletions
|
@ -180,9 +180,7 @@ RSpec/LetSetup:
|
|||
- 'spec/controllers/admin/reports/actions_controller_spec.rb'
|
||||
- 'spec/controllers/admin/statuses_controller_spec.rb'
|
||||
- 'spec/controllers/api/v1/accounts/statuses_controller_spec.rb'
|
||||
- 'spec/controllers/api/v1/admin/accounts_controller_spec.rb'
|
||||
- 'spec/controllers/api/v1/filters_controller_spec.rb'
|
||||
- 'spec/controllers/api/v1/followed_tags_controller_spec.rb'
|
||||
- 'spec/controllers/api/v2/admin/accounts_controller_spec.rb'
|
||||
- 'spec/controllers/api/v2/filters/keywords_controller_spec.rb'
|
||||
- 'spec/controllers/api/v2/filters/statuses_controller_spec.rb'
|
||||
|
@ -418,7 +416,6 @@ Rails/SkipsModelValidations:
|
|||
- 'lib/mastodon/cli/accounts.rb'
|
||||
- 'lib/mastodon/cli/main.rb'
|
||||
- 'lib/mastodon/cli/maintenance.rb'
|
||||
- 'spec/controllers/api/v1/admin/accounts_controller_spec.rb'
|
||||
- 'spec/lib/activitypub/activity/follow_spec.rb'
|
||||
- 'spec/services/follow_service_spec.rb'
|
||||
- 'spec/services/update_account_service_spec.rb'
|
||||
|
|
|
@ -151,7 +151,7 @@ GEM
|
|||
erubi (>= 1.0.0)
|
||||
rack (>= 0.9.0)
|
||||
rouge (>= 1.0.0)
|
||||
better_html (2.0.1)
|
||||
better_html (2.0.2)
|
||||
actionview (>= 6.0)
|
||||
activesupport (>= 6.0)
|
||||
ast (~> 2.0)
|
||||
|
@ -345,14 +345,14 @@ GEM
|
|||
rainbow (>= 2.0.0)
|
||||
i18n (1.14.1)
|
||||
concurrent-ruby (~> 1.0)
|
||||
i18n-tasks (1.0.12)
|
||||
i18n-tasks (1.0.13)
|
||||
activesupport (>= 4.0.2)
|
||||
ast (>= 2.1.0)
|
||||
better_html (>= 1.0, < 3.0)
|
||||
erubi
|
||||
highline (>= 2.0.0)
|
||||
i18n
|
||||
parser (>= 2.2.3.0)
|
||||
parser (>= 3.2.2.1)
|
||||
rails-i18n
|
||||
rainbow (>= 2.2.2, < 4.0)
|
||||
terminal-table (>= 1.5.1)
|
||||
|
@ -561,7 +561,7 @@ GEM
|
|||
rails-html-sanitizer (1.6.0)
|
||||
loofah (~> 2.21)
|
||||
nokogiri (~> 1.14)
|
||||
rails-i18n (7.0.7)
|
||||
rails-i18n (7.0.8)
|
||||
i18n (>= 0.7, < 2)
|
||||
railties (>= 6.0.0, < 8)
|
||||
railties (7.0.8)
|
||||
|
|
|
@ -613,7 +613,7 @@
|
|||
"sign_in_banner.create_account": "Sortu kontua",
|
||||
"sign_in_banner.sign_in": "Hasi saioa",
|
||||
"sign_in_banner.sso_redirect": "Hasi saioa edo izena eman",
|
||||
"sign_in_banner.text": "Hasi saioa profilak edo traolak jarraitzeko, bidalketak gogokoetara gehitzeko, partekatzeko edo erantzuteko. Zure kontutik ere komunika zaitezke beste zerbitzari ezberdin vatean.",
|
||||
"sign_in_banner.text": "Hasi saioa profilak edo traolak jarraitzeko, bidalketak gogokoetara gehitzeko, partekatzeko edo erantzuteko. Zure kontutik ere komunika zaitezke beste zerbitzari ezberdin batean.",
|
||||
"status.admin_account": "Ireki @{name} erabiltzailearen moderazio interfazea",
|
||||
"status.admin_domain": "{domain}-(r)en moderazio-interfazea ireki",
|
||||
"status.admin_status": "Ireki bidalketa hau moderazio interfazean",
|
||||
|
|
|
@ -71,8 +71,8 @@
|
|||
"account.unmute_notifications_short": "Poista ilmoitusten mykistys",
|
||||
"account.unmute_short": "Poista mykistys",
|
||||
"account_note.placeholder": "Lisää muistiinpano napsauttamalla",
|
||||
"admin.dashboard.daily_retention": "Käyttäjän säilyminen rekisteröitymisen jälkeiseen päivään mennessä",
|
||||
"admin.dashboard.monthly_retention": "Käyttäjän säilyminen rekisteröitymisen jälkeiseen kuukauteen mennessä",
|
||||
"admin.dashboard.daily_retention": "Käyttäjän pysyminen rekisteröitymisen jälkeiseen päivään mennessä",
|
||||
"admin.dashboard.monthly_retention": "Käyttäjän pysyminen rekisteröitymisen jälkeiseen kuukauteen mennessä",
|
||||
"admin.dashboard.retention.average": "Keskimäärin",
|
||||
"admin.dashboard.retention.cohort": "Kirjautumiset",
|
||||
"admin.dashboard.retention.cohort_size": "Uudet käyttäjät",
|
||||
|
@ -101,7 +101,7 @@
|
|||
"bundle_modal_error.close": "Sulje",
|
||||
"bundle_modal_error.message": "Jotain meni pieleen komponenttia ladattaessa.",
|
||||
"bundle_modal_error.retry": "Yritä uudelleen",
|
||||
"closed_registrations.other_server_instructions": "Koska Mastodon on hajautettu, voit luoda tilin toiselle palvelimelle ja silti olla vuorovaikutuksessa tämän kanssa.",
|
||||
"closed_registrations.other_server_instructions": "Koska Mastodon on hajautettu, voit luoda tilin toiselle palvelimelle ja olla silti vuorovaikutuksessa tämän kanssa.",
|
||||
"closed_registrations_modal.description": "Tilin luonti palveluun {domain} ei tällä hetkellä ole mahdollista, mutta huomioi, ettei Mastodonin käyttö edellytä juuri kyseisen palvelun tiliä.",
|
||||
"closed_registrations_modal.find_another_server": "Etsi toinen palvelin",
|
||||
"closed_registrations_modal.preamble": "Mastodon on hajautettu, joten riippumatta siitä, missä luot tilisi, voit seurata ja olla vuorovaikutuksessa kenen tahansa kanssa tällä palvelimella. Voit jopa isännöidä palvelinta!",
|
||||
|
@ -154,9 +154,9 @@
|
|||
"compose_form.publish_form": "Uusi julkaisu",
|
||||
"compose_form.publish_loud": "{publish}!",
|
||||
"compose_form.save_changes": "Tallenna muutokset",
|
||||
"compose_form.sensitive.hide": "{count, plural, one {Merkitse media arkaluontoiseksi} other {Merkitse mediat arkaluontoiseksi}}",
|
||||
"compose_form.sensitive.marked": "{count, plural, one {Media on merkitty arkaluontoiseksi} other {Mediat on merkitty arkaluontoiseksi}}",
|
||||
"compose_form.sensitive.unmarked": "{count, plural, one {Mediaa ei ole merkitty arkaluontoiseksi} other {Medioja ei ole merkitty arkaluontoiseksi}}",
|
||||
"compose_form.sensitive.hide": "{count, plural, one {Merkitse media arkaluonteiseksi} other {Merkitse mediat arkaluonteisiksi}}",
|
||||
"compose_form.sensitive.marked": "{count, plural, one {Media on merkitty arkaluonteiseksi} other {Mediat on merkitty arkaluonteisiksi}}",
|
||||
"compose_form.sensitive.unmarked": "{count, plural, one {Mediaa ei ole merkitty arkaluonteiseksi} other {Medioita ei ole merkitty arkaluonteisiksi}}",
|
||||
"compose_form.spoiler.marked": "Poista sisältövaroitus",
|
||||
"compose_form.spoiler.unmarked": "Lisää sisältövaroitus",
|
||||
"compose_form.spoiler_placeholder": "Kirjoita varoituksesi tähän",
|
||||
|
@ -592,7 +592,7 @@
|
|||
"search.search_or_paste": "Hae tai kirjoita URL-osoite",
|
||||
"search_popout.full_text_search_disabled_message": "Ei saatavilla palvelimella {domain}.",
|
||||
"search_popout.language_code": "ISO-kielikoodi",
|
||||
"search_popout.options": "Haun asetukset",
|
||||
"search_popout.options": "Hakuvalinnat",
|
||||
"search_popout.quick_actions": "Pikatoiminnot",
|
||||
"search_popout.recent": "Viimeaikaiset haut",
|
||||
"search_popout.specific_date": "tietty päivämäärä",
|
||||
|
@ -686,7 +686,7 @@
|
|||
"timeline_hint.resources.followers": "Seuraajat",
|
||||
"timeline_hint.resources.follows": "seurattua",
|
||||
"timeline_hint.resources.statuses": "Vanhemmat julkaisut",
|
||||
"trends.counter_by_accounts": "{count, plural, one {{counter} henkilö} other {{counter} henkilöä}} {days, plural, one {viimeisen päivän} other {viimeisten {days} päivän}} aikana",
|
||||
"trends.counter_by_accounts": "{count, plural, one {{counter} henkilö} other {{counter} henkilöä}} {days, plural, one {viime päivänä} other {viimeisenä {days} päivänä}}",
|
||||
"trends.trending_now": "Suosittua nyt",
|
||||
"ui.beforeunload": "Luonnos häviää, jos poistut Mastodonista.",
|
||||
"units.short.billion": "{count} mrd.",
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
"account.locked_info": "このアカウントは承認制アカウントです。相手が承認するまでフォローは完了しません。",
|
||||
"account.media": "メディア",
|
||||
"account.mention": "@{name}さんにメンション",
|
||||
"account.moved_to": "{name}さんがアカウントを引っ越しました:",
|
||||
"account.moved_to": "{name}さんはこちらのアカウントに引っ越しました:",
|
||||
"account.mute": "@{name}さんをミュート",
|
||||
"account.mute_notifications_short": "通知をオフにする",
|
||||
"account.mute_short": "ミュート",
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
"account.requested_follow": "{name} ti poslal žiadosť na sledovanie",
|
||||
"account.share": "Zdieľaj @{name} profil",
|
||||
"account.show_reblogs": "Ukáž vyzdvihnutia od @{name}",
|
||||
"account.statuses_counter": "{count, plural, one {{counter} Toot} other {{counter} Toots}}",
|
||||
"account.statuses_counter": "{count, plural, one {{counter} príspevok} other {{counter} príspevkov}}",
|
||||
"account.unblock": "Odblokuj @{name}",
|
||||
"account.unblock_domain": "Prestaň skrývať {domain}",
|
||||
"account.unblock_short": "Odblokuj",
|
||||
|
|
|
@ -204,7 +204,7 @@
|
|||
"dismissable_banner.explore_links": "這些新聞故事正在被此伺服器以及去中心化網路上的人們熱烈討論著。越多不同人所嘟出的新聞排名更高。",
|
||||
"dismissable_banner.explore_statuses": "這些於此伺服器以及去中心化網路中其他伺服器發出的嘟文正在被此伺服器上的人們熱烈討論著。越多不同人轉嘟及最愛排名更高。",
|
||||
"dismissable_banner.explore_tags": "這些主題標籤正在被此伺服器以及去中心化網路上的人們熱烈討論著。越多不同人所嘟出的主題標籤排名更高。",
|
||||
"dismissable_banner.public_timeline": "這些是來自 {domain} 上人們於社群網站中跟隨者所發表之最近公開嘟文。",
|
||||
"dismissable_banner.public_timeline": "這些是來自 {domain} 使用者們跟隨中帳號所發表之最新公開嘟文。",
|
||||
"embed.instructions": "要在您的網站嵌入此嘟文,請複製以下程式碼。",
|
||||
"embed.preview": "它將顯示成這樣:",
|
||||
"emoji_button.activity": "活動",
|
||||
|
@ -271,8 +271,8 @@
|
|||
"filter_modal.select_filter.title": "過濾此嘟文",
|
||||
"filter_modal.title.status": "過濾一則嘟文",
|
||||
"firehose.all": "全部",
|
||||
"firehose.local": "此伺服器",
|
||||
"firehose.remote": "其他伺服器",
|
||||
"firehose.local": "本站",
|
||||
"firehose.remote": "聯邦宇宙",
|
||||
"follow_request.authorize": "授權",
|
||||
"follow_request.reject": "拒絕",
|
||||
"follow_requests.unlocked_explanation": "即便您的帳號未被鎖定,{domain} 的管理員認為您可能想要自己審核這些帳號的跟隨請求。",
|
||||
|
|
|
@ -36,7 +36,8 @@ class LinkDetailsExtractor
|
|||
end
|
||||
|
||||
def language
|
||||
json['inLanguage']
|
||||
lang = json['inLanguage']
|
||||
lang.is_a?(Hash) ? (lang['alternateName'] || lang['name']) : lang
|
||||
end
|
||||
|
||||
def type
|
||||
|
|
|
@ -2,25 +2,40 @@
|
|||
|
||||
class ExistingUsernameValidator < ActiveModel::EachValidator
|
||||
def validate_each(record, attribute, value)
|
||||
return if value.blank?
|
||||
@value = value
|
||||
return if @value.blank?
|
||||
|
||||
usernames_and_domains = value.split(',').filter_map do |str|
|
||||
username, domain = str.strip.gsub(/\A@/, '').split('@', 2)
|
||||
if options[:multiple]
|
||||
record.errors.add(attribute, not_found_multiple_message) if usernames_with_no_accounts.any?
|
||||
elsif usernames_with_no_accounts.any? || usernames_and_domains.size > 1
|
||||
record.errors.add(attribute, not_found_message)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def usernames_and_domains
|
||||
@value.split(',').filter_map do |string|
|
||||
username, domain = string.strip.gsub(/\A@/, '').split('@', 2)
|
||||
domain = nil if TagManager.instance.local_domain?(domain)
|
||||
|
||||
next if username.blank?
|
||||
|
||||
[str, username, domain]
|
||||
[string, username, domain]
|
||||
end
|
||||
end
|
||||
|
||||
usernames_with_no_accounts = usernames_and_domains.filter_map do |(str, username, domain)|
|
||||
str unless Account.find_remote(username, domain)
|
||||
def usernames_with_no_accounts
|
||||
usernames_and_domains.filter_map do |(string, username, domain)|
|
||||
string unless Account.find_remote(username, domain)
|
||||
end
|
||||
end
|
||||
|
||||
if options[:multiple]
|
||||
record.errors.add(attribute, I18n.t('existing_username_validator.not_found_multiple', usernames: usernames_with_no_accounts.join(', '))) if usernames_with_no_accounts.any?
|
||||
elsif usernames_with_no_accounts.any? || usernames_and_domains.size > 1
|
||||
record.errors.add(attribute, I18n.t('existing_username_validator.not_found'))
|
||||
end
|
||||
def not_found_multiple_message
|
||||
I18n.t('existing_username_validator.not_found_multiple', usernames: usernames_with_no_accounts.join(', '))
|
||||
end
|
||||
|
||||
def not_found_message
|
||||
I18n.t('existing_username_validator.not_found')
|
||||
end
|
||||
end
|
||||
|
|
38
app/views/disputes/strikes/_card.html.haml
Normal file
38
app/views/disputes/strikes/_card.html.haml
Normal file
|
@ -0,0 +1,38 @@
|
|||
.strike-card
|
||||
- unless strike.none_action?
|
||||
%p= t "user_mailer.warning.explanation.#{strike.action}", instance: Rails.configuration.x.local_domain
|
||||
- if strike.text.present?
|
||||
= linkify(strike.text)
|
||||
- if strike.report && !strike.report.other?
|
||||
%p
|
||||
%strong= t('user_mailer.warning.reason')
|
||||
= t("user_mailer.warning.categories.#{strike.report.category}")
|
||||
- if strike.report.violation? && strike.report.rule_ids.present?
|
||||
%ul.strike-card__rules
|
||||
- strike.report.rules.each do |rule|
|
||||
%li
|
||||
%span.strike-card__rules__text= rule.text
|
||||
- if strike.status_ids.present? && !strike.status_ids.empty?
|
||||
%p
|
||||
%strong= t('user_mailer.warning.statuses')
|
||||
.strike-card__statuses-list
|
||||
- status_map = strike.statuses.includes(:application, :media_attachments).index_by(&:id)
|
||||
- strike.status_ids.each do |status_id|
|
||||
.strike-card__statuses-list__item
|
||||
- if (status = status_map[status_id.to_i])
|
||||
.one-liner
|
||||
.emojify= one_line_preview(status)
|
||||
- status.ordered_media_attachments.each do |media_attachment|
|
||||
%abbr{ title: media_attachment.description }
|
||||
= fa_icon 'link'
|
||||
= media_attachment.file_file_name
|
||||
.strike-card__statuses-list__item__meta
|
||||
= link_to ActivityPub::TagManager.instance.url_for(status), target: '_blank', rel: 'noopener noreferrer' do
|
||||
%time.formatted{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at)
|
||||
- unless status.application.nil?
|
||||
·
|
||||
= status.application.name
|
||||
- else
|
||||
.one-liner= t('disputes.strikes.status', id: status_id)
|
||||
.strike-card__statuses-list__item__meta
|
||||
= t('disputes.strikes.status_removed')
|
|
@ -21,51 +21,7 @@
|
|||
|
||||
.report-header
|
||||
.report-header__card
|
||||
.strike-card
|
||||
- unless @strike.none_action?
|
||||
%p= t "user_mailer.warning.explanation.#{@strike.action}", instance: Rails.configuration.x.local_domain
|
||||
|
||||
- if @strike.text.present?
|
||||
= linkify(@strike.text)
|
||||
|
||||
- if @strike.report && !@strike.report.other?
|
||||
%p
|
||||
%strong= t('user_mailer.warning.reason')
|
||||
= t("user_mailer.warning.categories.#{@strike.report.category}")
|
||||
|
||||
- if @strike.report.violation? && @strike.report.rule_ids.present?
|
||||
%ul.strike-card__rules
|
||||
- @strike.report.rules.each do |rule|
|
||||
%li
|
||||
%span.strike-card__rules__text= rule.text
|
||||
|
||||
- if @strike.status_ids.present? && !@strike.status_ids.empty?
|
||||
%p
|
||||
%strong= t('user_mailer.warning.statuses')
|
||||
|
||||
.strike-card__statuses-list
|
||||
- status_map = @strike.statuses.includes(:application, :media_attachments).index_by(&:id)
|
||||
|
||||
- @strike.status_ids.each do |status_id|
|
||||
.strike-card__statuses-list__item
|
||||
- if (status = status_map[status_id.to_i])
|
||||
.one-liner
|
||||
.emojify= one_line_preview(status)
|
||||
|
||||
- status.ordered_media_attachments.each do |media_attachment|
|
||||
%abbr{ title: media_attachment.description }
|
||||
= fa_icon 'link'
|
||||
= media_attachment.file_file_name
|
||||
.strike-card__statuses-list__item__meta
|
||||
= link_to ActivityPub::TagManager.instance.url_for(status), target: '_blank', rel: 'noopener noreferrer' do
|
||||
%time.formatted{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at)
|
||||
- unless status.application.nil?
|
||||
·
|
||||
= status.application.name
|
||||
- else
|
||||
.one-liner= t('disputes.strikes.status', id: status_id)
|
||||
.strike-card__statuses-list__item__meta
|
||||
= t('disputes.strikes.status_removed')
|
||||
= render 'card', strike: @strike
|
||||
|
||||
.report-header__details
|
||||
.report-header__details__item
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
enabled = ENV['ES_ENABLED'] == 'true'
|
||||
host = ENV.fetch('ES_HOST') { 'localhost' }
|
||||
port = ENV.fetch('ES_PORT') { 9200 }
|
||||
user = ENV.fetch('ES_USER') { nil }
|
||||
password = ENV.fetch('ES_PASS') { nil }
|
||||
fallback_prefix = ENV.fetch('REDIS_NAMESPACE') { nil }
|
||||
user = ENV.fetch('ES_USER', nil).presence
|
||||
password = ENV.fetch('ES_PASS', nil).presence
|
||||
fallback_prefix = ENV.fetch('REDIS_NAMESPACE', nil).presence
|
||||
prefix = ENV.fetch('ES_PREFIX') { fallback_prefix }
|
||||
|
||||
Chewy.settings = {
|
||||
|
|
|
@ -14,6 +14,7 @@ Rails.application.config.middleware.insert_before 0, Rack::Cors do
|
|||
with_options headers: :any, credentials: false do
|
||||
with_options methods: [:get] do
|
||||
resource '/.well-known/*'
|
||||
resource '/nodeinfo/*'
|
||||
resource '/@:username'
|
||||
resource '/users/:username'
|
||||
end
|
||||
|
|
|
@ -394,7 +394,7 @@ Devise.setup do |config|
|
|||
config.check_at_sign = true
|
||||
config.pam_default_suffix = ENV.fetch('PAM_EMAIL_DOMAIN') { ENV['LOCAL_DOMAIN'] }
|
||||
config.pam_default_service = ENV.fetch('PAM_DEFAULT_SERVICE') { 'rpam' }
|
||||
config.pam_controlled_service = ENV.fetch('PAM_CONTROLLED_SERVICE') { nil }
|
||||
config.pam_controlled_service = ENV.fetch('PAM_CONTROLLED_SERVICE', nil).presence
|
||||
end
|
||||
|
||||
if ENV['LDAP_ENABLED'] == 'true'
|
||||
|
|
|
@ -4,7 +4,7 @@ zh-TW:
|
|||
confirmations:
|
||||
confirmed: 您的電子郵件地址已確認成功。
|
||||
send_instructions: 幾分鐘後您將收到確認信件。若未收到此信件,請檢查垃圾郵件資料夾。
|
||||
send_paranoid_instructions: 如果您的電子郵件存在於我們的資料庫,您將會在幾分鐘內收到確認信。若未收到請檢查垃圾郵件資料夾。
|
||||
send_paranoid_instructions: 如果您的電子郵件存在於我們的資料庫,您將於幾分鐘內收到確認信。若未收到請檢查垃圾郵件資料夾。
|
||||
failure:
|
||||
already_authenticated: 您已登入。
|
||||
inactive: 您的帳號尚未啟用。
|
||||
|
@ -43,7 +43,7 @@ zh-TW:
|
|||
reset_password_instructions:
|
||||
action: 變更密碼
|
||||
explanation: 您已請求帳號的新密碼。
|
||||
extra: 若您並未請求,請忽略此信件。您的密碼在存取上方連結並建立新密碼前不會變更。
|
||||
extra: 若您並未請求,請忽略此信件。您的密碼於存取上方連結並建立新密碼前不會變更。
|
||||
subject: Mastodon:重設密碼指引
|
||||
title: 重設密碼
|
||||
two_factor_disabled:
|
||||
|
|
|
@ -12,7 +12,7 @@ fi:
|
|||
one: seuraaja
|
||||
other: seuraajaa
|
||||
following: seurattu(a)
|
||||
instance_actor_flash: Tämä tili on virtuaalinen toimija, jota käytetään edustamaan itse palvelinta eikä yksittäistä käyttäjää. Sitä käytetään federointitarkoituksiin, eikä sitä tule jäädyttää.
|
||||
instance_actor_flash: Tämä tili on virtuaalinen toimija, jota käytetään edustamaan itse palvelinta eikä yksittäistä käyttäjää. Sitä käytetään liittoutumistarkoituksiin, eikä sitä tule jäädyttää.
|
||||
last_active: viimeksi aktiivinen
|
||||
link_verified_on: Tämän linkin omistus on tarkastettu %{date}
|
||||
nothing_here: Täällä ei ole mitään!
|
||||
|
@ -138,7 +138,7 @@ fi:
|
|||
security_measures:
|
||||
only_password: Vain salasana
|
||||
password_and_2fa: Salasana ja kaksivaiheinen tunnistautuminen
|
||||
sensitive: Pakotus arkaluonteiseksi
|
||||
sensitive: Pakota arkaluonteiseksi
|
||||
sensitized: Merkitty arkaluonteiseksi
|
||||
shared_inbox_url: Jaetun saapuvan postilaatikon osoite
|
||||
show:
|
||||
|
@ -157,7 +157,7 @@ fi:
|
|||
unblock_email: Poista sähköpostiosoitteen esto
|
||||
unblocked_email_msg: Käyttäjän %{username} sähköpostiosoitteen esto kumottiin
|
||||
unconfirmed_email: Sähköpostia ei vahvistettu
|
||||
undo_sensitized: Kumoa pakotus arkaluonteiseksi tiliksi
|
||||
undo_sensitized: Kumoa pakotus arkaluonteiseksi
|
||||
undo_silenced: Kumoa rajoitus
|
||||
undo_suspension: Peru jäähy
|
||||
unsilenced_msg: Tilin %{username} rajoituksen kumoaminen onnistui
|
||||
|
@ -167,7 +167,7 @@ fi:
|
|||
view_domain: Näytä verkkotunnuksen yhteenveto
|
||||
warn: Varoita
|
||||
web: Verkko
|
||||
whitelisted: Sallittu federoimaan
|
||||
whitelisted: Sallittu liittoutua
|
||||
action_logs:
|
||||
action_types:
|
||||
approve_appeal: Hyväksy valitus
|
||||
|
@ -214,12 +214,12 @@ fi:
|
|||
resend_user: Lähetä vahvistusviesti uudelleen
|
||||
reset_password_user: Nollaa salasana
|
||||
resolve_report: Selvitä raportti
|
||||
sensitive_account: Pakotus arkaluontoiseksi tiliksi
|
||||
sensitive_account: Pakotus arkaluonteiseksi tiliksi
|
||||
silence_account: Rajoita tiliä
|
||||
suspend_account: Jäädytä tili
|
||||
unassigned_report: Peruuta raportin määritys
|
||||
unblock_email_account: Poista sähköpostiosoitteen esto
|
||||
unsensitive_account: Kumoa pakotus arkaluontoiseksi tiliksi
|
||||
unsensitive_account: Kumoa pakotus arkaluonteiseksi tiliksi
|
||||
unsilence_account: Kumoa tilin rajoitus
|
||||
unsuspend_account: Kumoa tilin jäädytys
|
||||
update_announcement: Päivitä tiedote
|
||||
|
@ -239,7 +239,7 @@ fi:
|
|||
create_announcement_html: "%{name} loi uuden tiedotteen %{target}"
|
||||
create_canonical_email_block_html: "%{name} esti sähköpostin tiivisteellä %{target}"
|
||||
create_custom_emoji_html: "%{name} lähetti uuden emojin %{target}"
|
||||
create_domain_allow_html: "%{name} salli federoinnin verkkotunnuksen %{target} kanssa"
|
||||
create_domain_allow_html: "%{name} salli liittoutumisen verkkotunnuksen %{target} kanssa"
|
||||
create_domain_block_html: "%{name} esti verkkotunnuksen %{target}"
|
||||
create_email_domain_block_html: "%{name} esti sähköpostiverkkotunnuksen %{target}"
|
||||
create_ip_block_html: "%{name} loi IP-säännön %{target}"
|
||||
|
@ -249,7 +249,7 @@ fi:
|
|||
destroy_announcement_html: "%{name} poisti tiedotteen %{target}"
|
||||
destroy_canonical_email_block_html: "%{name} poisti sähköpostin eston tiivisteellä %{target}"
|
||||
destroy_custom_emoji_html: "%{name} poisti emojin %{target}"
|
||||
destroy_domain_allow_html: "%{name} kielsi federoinnin verkkotunnuksen %{target} kanssa"
|
||||
destroy_domain_allow_html: "%{name} kielsi liittoutumisen verkkotunnuksen %{target} kanssa"
|
||||
destroy_domain_block_html: "%{name} poisti verkkotunnuksen %{target} eston"
|
||||
destroy_email_domain_block_html: "%{name} poisti sähköpostiverkkotunnuksen %{target} eston"
|
||||
destroy_instance_html: "%{name} tyhjensi verkkotunnuksen %{target}"
|
||||
|
@ -278,7 +278,7 @@ fi:
|
|||
suspend_account_html: "%{name} jäädytti käyttäjän %{target} tilin"
|
||||
unassigned_report_html: "%{name} peruutti raportin määrityksen %{target}"
|
||||
unblock_email_account_html: "%{name} poisti käyttäjän %{target} sähköpostiosoitteen eston"
|
||||
unsensitive_account_html: "%{name} poisti käyttäjän %{target} median arkaluonteisen merkinnän"
|
||||
unsensitive_account_html: "%{name} kumosi käyttäjän %{target} median arkaluonteisuusmerkinnän"
|
||||
unsilence_account_html: "%{name} kumosi käyttäjän %{target} rajoituksen"
|
||||
unsuspend_account_html: "%{name} kumosi käyttäjän %{target} tilin jäädytyksen"
|
||||
update_announcement_html: "%{name} päivitti tiedotteen %{target}"
|
||||
|
@ -375,12 +375,12 @@ fi:
|
|||
empty: Valituksia ei löytynyt.
|
||||
title: Valitukset
|
||||
domain_allows:
|
||||
add_new: Salli liitto verkkotunnuksella
|
||||
created_msg: Verkkotunnus on onnistuneesti sallittu federoinnille
|
||||
destroyed_msg: Verkkotunnusta on kielletty federoimasta
|
||||
add_new: Salli liittoutuminen tämän verkkotunnuksen kanssa
|
||||
created_msg: Verkkotunnuksen on onnistuneesti sallittu liittoutua
|
||||
destroyed_msg: Verkkotunnusta on kielletty liittoutumasta
|
||||
export: Vie
|
||||
import: Tuo
|
||||
undo: Estä liitto verkkotunnukselle
|
||||
undo: Kiellä liittoutuminen tämän verkkotunnuksen kanssa
|
||||
domain_blocks:
|
||||
add_new: Lisää uusi verkkotunnuksen esto
|
||||
confirm_suspension:
|
||||
|
@ -527,7 +527,7 @@ fi:
|
|||
public_comment: Julkinen kommentti
|
||||
purge: Tyhjennä
|
||||
purge_description_html: Jos uskot, että tämä verkkotunnus on offline-tilassa tarkoituksella, voit poistaa kaikki verkkotunnuksen tilitietueet ja niihin liittyvät tiedot tallennustilastasi. Tämä voi kestää jonkin aikaa.
|
||||
title: Federointi
|
||||
title: Liittoutuminen
|
||||
total_blocked_by_us: Estämämme
|
||||
total_followed_by_them: Heidän seuraama
|
||||
total_followed_by_us: Meidän seuraama
|
||||
|
@ -562,7 +562,7 @@ fi:
|
|||
relays:
|
||||
add_new: Lisää uusi välittäjä
|
||||
delete: Poista
|
||||
description_html: "<strong>Federointivälittäjä</strong> on välityspalvelin, joka siirtää suuria määriä julkisia julkaisuja siihen liittyneiden palvelinten välillä. <strong>Se voi auttaa pieniä ja keskisuuria palvelimia löytämään fediversumin sisältöä</strong>, mikä muutoin vaatisi paikallisia käyttäjiä seuraamaan etäpalvalinten käyttäjiä manuaalisesti."
|
||||
description_html: "<strong>Liittoutumisvälittäjä</strong> on välityspalvelin, joka siirtää suuria määriä julkisia julkaisuja siihen liittyneiden palvelinten välillä. <strong>Se voi auttaa pieniä ja keskisuuria palvelimia löytämään fediversumin sisältöä</strong>, mikä muutoin vaatisi paikallisia käyttäjiä seuraamaan etäpalvalinten käyttäjiä manuaalisesti."
|
||||
disable: Poista käytöstä
|
||||
disabled: Poissa käytöstä
|
||||
enable: Ota käyttöön
|
||||
|
@ -671,56 +671,56 @@ fi:
|
|||
devops: DevOps
|
||||
invites: Kutsut
|
||||
moderation: Valvonta
|
||||
special: Erikois
|
||||
special: Erityistä
|
||||
delete: Poista
|
||||
description_html: "<strong>Käyttäjärooleilla</strong> voit muokata, mihin toimintoihin ja alueisiin käyttäjäsi pääsevät käsiksi."
|
||||
edit: Muokkaa "%{name}" roolia
|
||||
edit: Muokkaa roolia ”%{name}”
|
||||
everyone: Oletuskäyttöoikeudet
|
||||
everyone_full_description_html: Tämä on <strong>perusrooli</strong> joka vaikuttaa <strong>kaikkiin käyttäjiin</strong>, jopa ilman määrättyä roolia. Kaikki muut roolit perivät sen käyttöoikeudet.
|
||||
everyone_full_description_html: Tämä on <strong>perusrooli</strong>, joka vaikuttaa <strong>kaikkiin käyttäjiin</strong>, jopa ilman määrättyä roolia. Kaikki muut roolit perivät sen käyttöoikeudet.
|
||||
permissions_count:
|
||||
one: "%{count} käyttöoikeus"
|
||||
other: "%{count} käyttöoikeutta"
|
||||
privileges:
|
||||
administrator: Ylläpitäjä
|
||||
administrator_description: Käyttäjät, joilla on tämä käyttöoikeus, ohittavat jokaisen käyttöoikeuden
|
||||
delete_user_data: Poista käyttäjän tiedot
|
||||
delete_user_data: Poistaa käyttäjän tiedot
|
||||
delete_user_data_description: Salli käyttäjien poistaa muiden käyttäjien tiedot viipymättä
|
||||
invite_users: Kutsu käyttäjiä
|
||||
invite_users: Kutsua käyttäjiä
|
||||
invite_users_description: Sallii käyttäjien kutsua uusia ihmisiä palvelimelle
|
||||
manage_announcements: Hallitse tiedotteita
|
||||
manage_announcements: Hallita tiedotteita
|
||||
manage_announcements_description: Sallii käyttäjien hallita tiedotteita palvelimella
|
||||
manage_appeals: Hallitse valituksia
|
||||
manage_appeals: Hallita valituksia
|
||||
manage_appeals_description: Sallii käyttäjien tarkistaa valvontatoimia koskevia valituksia
|
||||
manage_blocks: Hallitse estoja
|
||||
manage_blocks: Hallita estoja
|
||||
manage_blocks_description: Sallii käyttäjien estää sähköpostipalveluntarjoajia ja IP-osoitteita
|
||||
manage_custom_emojis: Hallitse mukautettuja emojeita
|
||||
manage_custom_emojis: Hallita mukautettuja emojeita
|
||||
manage_custom_emojis_description: Sallii käyttäjien hallita mukautettuja emojeita palvelimella
|
||||
manage_federation: Hallitse federointia
|
||||
manage_federation_description: Sallii käyttäjien estää tai sallia federointi muiden verkkotunnusten kanssa ja hallita toimitusta
|
||||
manage_invites: Hallitse kutsuja
|
||||
manage_federation: Hallita liittoutumista
|
||||
manage_federation_description: Sallii käyttäjien estää tai sallia liittoutuminen muiden verkkotunnusten kanssa ja hallita toimitusta
|
||||
manage_invites: Hallita kutsuja
|
||||
manage_invites_description: Sallii käyttäjien selata ja poistaa kutsulinkkejä käytöstä
|
||||
manage_reports: Hallitse raportteja
|
||||
manage_reports: Hallita raportteja
|
||||
manage_reports_description: Sallii käyttäjien tarkistaa raportteja ja suorittaa valvontatoimia niitä vastaan
|
||||
manage_roles: Hallitse rooleja
|
||||
manage_roles: Hallita rooleja
|
||||
manage_roles_description: Sallii käyttäjien hallita ja määrittää rooleja heidän alapuolellaan
|
||||
manage_rules: Hallitse sääntöjä
|
||||
manage_rules: Hallita sääntöjä
|
||||
manage_rules_description: Sallii käyttäjien muuttaa palvelimen sääntöjä
|
||||
manage_settings: Hallitse asetuksia
|
||||
manage_settings: Hallita asetuksia
|
||||
manage_settings_description: Sallii käyttäjien muuttaa sivuston asetuksia
|
||||
manage_taxonomies: Hallitse luokittelua
|
||||
manage_taxonomies: Hallita luokittelua
|
||||
manage_taxonomies_description: Sallii käyttäjien tarkistaa suositun sisällön ja päivittää aihetunnisteiden asetuksia
|
||||
manage_user_access: Hallitse käyttäjäoikeuksia
|
||||
manage_user_access: Hallita käyttäjäoikeuksia
|
||||
manage_user_access_description: Sallii käyttäjien poistaa muiden käyttäjien kaksivaiheinen todennus käytöstä, vaihtaa heidän sähköpostiosoitteensa ja nollata heidän salasanansa
|
||||
manage_users: Hallitse käyttäjiä
|
||||
manage_users: Hallita käyttäjiä
|
||||
manage_users_description: Sallii käyttäjien tarkastella muiden käyttäjien tietoja ja suorittaa valvontatoimia heitä kohtaan
|
||||
manage_webhooks: Hallitse webhookeja
|
||||
manage_webhooks: Hallita webhookeja
|
||||
manage_webhooks_description: Sallii käyttäjien luoda webhookeja hallinnollisiin tapahtumiin
|
||||
view_audit_log: Katsoa valvontalokia
|
||||
view_audit_log_description: Sallii käyttäjien nähdä palvelimen hallinnollisten toimien historian
|
||||
view_dashboard: Näytä koontinäyttö
|
||||
view_dashboard: Katsoa koontinäyttöä
|
||||
view_dashboard_description: Sallii käyttäjien käyttää kojelautaa ja erilaisia mittareita
|
||||
view_devops: DevOps
|
||||
view_devops_description: Sallii käyttäjille oikeuden käyttää Sidekiq ja pgHero dashboardeja
|
||||
view_devops_description: Sallii käyttäjille pääsyn Sidekiq- ja pgHero-hallintapaneeleihin
|
||||
title: Roolit
|
||||
rules:
|
||||
add_new: Lisää sääntö
|
||||
|
@ -732,7 +732,7 @@ fi:
|
|||
settings:
|
||||
about:
|
||||
manage_rules: Hallitse palvelimen sääntöjä
|
||||
preamble: Anna perusteellista tietoa siitä, miten palvelinta käytetään, valvotaan, rahoitetaan.
|
||||
preamble: Anna perusteellista tietoa siitä, miten palvelinta käytetään, valvotaan ja rahoitetaan.
|
||||
rules_hint: On olemassa erityinen alue sääntöjä, joita käyttäjien odotetaan noudattavan.
|
||||
title: Tietoja
|
||||
appearance:
|
||||
|
@ -752,7 +752,7 @@ fi:
|
|||
title: Jätä käyttäjät oletusarvoisesti hakukoneindeksoinnin ulkopuolelle
|
||||
discovery:
|
||||
follow_recommendations: Seuraamissuositukset
|
||||
preamble: Mielenkiintoisen sisällön esille tuominen auttaa saamaan uusia käyttäjiä, jotka eivät ehkä tunne ketään Mastodonista. Määrittele, kuinka erilaiset etsintäominaisuudet toimivat palvelimellasi.
|
||||
preamble: Mielenkiintoisen sisällön esille tuominen auttaa saamaan uusia käyttäjiä, jotka eivät ehkä tunne ketään Mastodonista. Määrittele, kuinka erilaiset löytämisominaisuudet toimivat palvelimellasi.
|
||||
profile_directory: Profiilihakemisto
|
||||
public_timelines: Julkiset aikajanat
|
||||
publish_discovered_servers: Julkaise löydetyt palvelimet
|
||||
|
@ -765,17 +765,17 @@ fi:
|
|||
users: Kirjautuneille paikallisille käyttäjille
|
||||
registrations:
|
||||
preamble: Määritä, kuka voi luoda tilin palvelimellesi.
|
||||
title: Rekisteröinnit
|
||||
title: Rekisteröityminen
|
||||
registrations_mode:
|
||||
modes:
|
||||
approved: Rekisteröinti vaatii hyväksynnän
|
||||
none: Kukaan ei voi rekisteröityä
|
||||
open: Kaikki voivat rekisteröityä
|
||||
security:
|
||||
authorized_fetch: Vaadi todennus yhdistetyiltä palvelimilta
|
||||
authorized_fetch_hint: Todennuksen vaatiminen federoiduilta palvelimilta mahdollistaa sekä käyttäjä- että palvelintason estojen tiukemman valvonnan. Tämä tapahtuu kuitenkin suorituskyvyn kustannuksella, vähentää vastauksiesi tavoittavuutta ja voi aiheuttaa yhteensopivuusongelmia joidenkin federoitujen palvelujen kanssa. Tämä ei myöskään estä omistautuneita toimijoita hakemasta julkisia julkaisujasi ja tilejäsi.
|
||||
authorized_fetch: Vaadi todennus liittoutuvilta palvelimilta
|
||||
authorized_fetch_hint: Todennuksen vaatiminen liittoutuvilta palvelimilta mahdollistaa sekä käyttäjä- että palvelintason estojen tiukemman valvonnan. Tämä tapahtuu kuitenkin suorituskyvyn kustannuksella, vähentää vastauksiesi tavoittavuutta ja voi aiheuttaa yhteensopivuusongelmia joidenkin liittoutuvien palvelujen kanssa. Tämä ei myöskään estä omistautuneita toimijoita hakemasta julkisia julkaisujasi ja tilejäsi.
|
||||
authorized_fetch_overridden_hint: Et voi tällä hetkellä muuttaa tätä asetusta, koska se on ohitettu ympäristömuuttujalla.
|
||||
federation_authentication: Yhdistettyjen palvelinten todentamisen täytäntöönpano
|
||||
federation_authentication: Liittoutumisen todentamisen täytäntöönpano
|
||||
title: Palvelimen asetukset
|
||||
site_uploads:
|
||||
delete: Poista ladattu tiedosto
|
||||
|
@ -1239,7 +1239,7 @@ fi:
|
|||
deprecated_api_multiple_keywords: Näitä parametreja ei voi muuttaa tästä sovelluksesta, koska ne koskevat useampaa kuin yhtä suodattimen avainsanaa. Käytä uudempaa sovellusta tai selainkäyttöliittymää.
|
||||
invalid_context: Ei sisältöä tai se on virheellinen
|
||||
index:
|
||||
contexts: Suodattimet %{contexts}
|
||||
contexts: Suodattaa kontektissa %{contexts}
|
||||
delete: Poista
|
||||
empty: Sinulla ei ole suodattimia.
|
||||
expires_in: Vanhenee %{distance}
|
||||
|
@ -1414,8 +1414,8 @@ fi:
|
|||
not_found: ei voitu löytää
|
||||
on_cooldown: Sinä olet jäähyllä
|
||||
followers_count: Seuraajat muuton aikana
|
||||
incoming_migrations: Siirtyminen toiselta tililtä
|
||||
incoming_migrations_html: Siirtyäksesi toisesta tilistä tähän, sinun täytyy ensin <a href="%{path}">luoda tilin alias</a>.
|
||||
incoming_migrations: Muutto toiselta tililtä
|
||||
incoming_migrations_html: Muuttaaksesi toisesta tilistä tähän, sinun täytyy ensin <a href="%{path}">luoda tilin alias</a>.
|
||||
moved_msg: Tilisi ohjaa nyt kohteeseen %{acct} ja seuraajiasi siirretään.
|
||||
not_redirecting: Tilisi ei ohjaa tällä hetkellä mihinkään muuhun tiliin.
|
||||
on_cooldown: Olet siirtänyt tilisi äskettäin. Tämä toiminto tulee saataville uudelleen %{count} päivän kuluttua.
|
||||
|
@ -1707,7 +1707,7 @@ fi:
|
|||
keep_self_bookmark: Säilytä kirjanmerkkeihin lisäämäsi julkaisut
|
||||
keep_self_bookmark_hint: Ei poista julkaisujasi, jos olet lisännyt ne kirjanmerkkeihin
|
||||
keep_self_fav: Säilytä suosikkeihin lisäämäsi julkaisut
|
||||
keep_self_fav_hint: Ei poista julkaisujasi, jos olet lisännyt ne suosikkeihin
|
||||
keep_self_fav_hint: Ei poista julkaisujasi, jos olet lisännyt ne suosikkeihisi
|
||||
min_age:
|
||||
'1209600': 2 viikkoa
|
||||
'15778476': 6 kuukautta
|
||||
|
@ -1786,7 +1786,7 @@ fi:
|
|||
spam: Roskaposti
|
||||
violation: Sisältö rikkoo seuraavia yhteisön sääntöjä
|
||||
explanation:
|
||||
delete_statuses: Joidenkin julkaisuistasi on havaittu rikkovan ainakin yhtä yhteisön sääntöä, ja instanssin %{instance} valvojat ovat poistaneet ne.
|
||||
delete_statuses: Joidenkin julkaisuistasi on havaittu rikkovan ainakin yhtä yhteisön sääntöä, joten instanssin %{instance} valvojat ovat poistaneet ne.
|
||||
disable: Et voi enää käyttää tiliäsi, mutta profiilisi ja muut tiedot pysyvät muuttumattomina. Voit pyytää varmuuskopiota tiedoistasi, vaihtaa tilin asetuksia tai poistaa tilisi.
|
||||
mark_statuses_as_sensitive: Palvelimen %{instance} valvojat ovat merkinneet osan julkaisuistasi arkaluonteisiksi. Tämä tarkoittaa sitä, että ihmisten täytyy napauttaa mediaa ennen kuin sen esikatselu näytetään. Voit merkitä median itse arkaluonteiseksi, kun julkaiset tulevaisuudessa.
|
||||
sensitive: Tästä lähtien kaikki ladatut mediatiedostot merkitään arkaluonteisiksi ja piilotetaan napsautusvaroituksen taakse.
|
||||
|
@ -1807,7 +1807,7 @@ fi:
|
|||
disable: Tili jäädytetty
|
||||
mark_statuses_as_sensitive: Julkaisut merkitty arkaluonteisiksi
|
||||
none: Varoitus
|
||||
sensitive: Tili on merkitty arkaluonteiseksi
|
||||
sensitive: Tili merkitty arkaluonteiseksi
|
||||
silence: Tiliä rajoitettu
|
||||
suspend: Tili jäädytetty
|
||||
welcome:
|
||||
|
|
|
@ -791,9 +791,9 @@ si:
|
|||
guide_link_text: පරිවර්තකයින්ට දායක වීමට හැකිය.
|
||||
sensitive_content: සංවේදී අන්තර්ගත
|
||||
application_mailer:
|
||||
notification_preferences: ඊමේල් මනාප වෙනස් කරන්න
|
||||
notification_preferences: වි-තැපැල් අභිප්රේත වෙනස් කරන්න
|
||||
salutation: "%{name},"
|
||||
settings: 'ඊමේල් මනාප වෙනස් කරන්න: %{link}'
|
||||
settings: 'වි-තැපැල් අභිප්රේත වෙනස් කරන්න: %{link}'
|
||||
view: 'දැක්ම:'
|
||||
view_profile: පැතිකඩ බලන්න
|
||||
view_status: ලිපිය බලන්න
|
||||
|
@ -1405,11 +1405,11 @@ si:
|
|||
title: සංරක්ෂිත රැගෙන යාම
|
||||
suspicious_sign_in:
|
||||
change_password: මුරපදය වෙනස් කරන්න
|
||||
details: 'පුරනය වීමේ විස්තර මෙන්න:'
|
||||
explanation: අපි නව IP ලිපිනයකින් ඔබගේ ගිණුමට පුරනය වීමක් අනාවරණය කරගෙන ඇත.
|
||||
further_actions_html: මෙය ඔබ නොවේ නම්, අපි ඔබට වහාම %{action} ලෙස නිර්දේශ කර ඔබගේ ගිණුම සුරක්ෂිතව තබා ගැනීමට සාධක දෙකක සත්යාපනය සබල කරන්න.
|
||||
subject: ඔබගේ ගිණුම නව IP ලිපිනයකින් ප්රවේශ වී ඇත
|
||||
title: නව පුරනය වීමක්
|
||||
details: 'ප්රවේශයට අදාළ විස්තර:'
|
||||
explanation: ඔබගේ ගිණුමට නව අ.ජා.කෙ. (IP) ලිපිනයකින් ප්රවේශයක් අනාවරණය වී ඇත.
|
||||
further_actions_html: මේ ඔබ නොවේ නම්, වහාම %{action}. ඔබගේ ගිණුම සුරක්ෂිතව තබා ගැනීමට ද්වි-සාධකය සබල කරන්න.
|
||||
subject: ඔබගේ ගිණුමට නව අ.ජා.කෙ. (IP) ලිපිනයකින් ප්රවේශ වී ඇත
|
||||
title: නව ප්රවේශයක්
|
||||
warning:
|
||||
appeal: අභියාචනයක් ඉදිරිපත් කරන්න
|
||||
appeal_description: මෙය දෝෂයක් බව ඔබ විශ්වාස කරන්නේ නම්, ඔබට %{instance}හි කාර්ය මණ්ඩලයට අභියාචනයක් ඉදිරිපත් කළ හැක.
|
||||
|
|
|
@ -25,7 +25,7 @@ fi:
|
|||
types:
|
||||
disable: Estä käyttäjää käyttämästä tiliään, mutta älä poista tai piilota sen sisältöä.
|
||||
none: Käytä tätä lähettääksesi varoituksen käyttäjälle käynnistämättä mitään muita toimintoja.
|
||||
sensitive: Pakota kaikki tämän käyttäjän mediatiedostot arkaluontoisiksi.
|
||||
sensitive: Pakota kaikki tämän käyttäjän mediatiedostot arkaluonteisiksi.
|
||||
silence: Estä käyttäjää lähettämästä viestejä julkisesti, piilota hänen viestinsä ja ilmoituksensa ihmisiltä, jotka eivät seuraa häntä. Sulkee kaikki tämän tilin raportit.
|
||||
suspend: Estä kaikki vuorovaikutus tältä -tai tälle tilille ja poista sen kaikki sisältö. Päätös voidaan peruuttaa 30 päivän aikana. Sulkee kaikki raportit tätä tiliä vasten.
|
||||
warning_preset_id: Valinnainen. Voit silti lisätä mukautetun tekstin esiasetuksen loppuun
|
||||
|
@ -79,14 +79,14 @@ fi:
|
|||
activity_api_enabled: Paikallisesti julkaistujen julkaisujen, aktiivisten käyttäjien ja rekisteröitymisten viikoittainen määrä
|
||||
backups_retention_period: Säilytä luodut arkistot määritetyn määrän päiviä.
|
||||
bootstrap_timeline_accounts: Nämä tilit kiinnitetään uusien käyttäjien seuraamissuositusten yläpuolelle.
|
||||
closed_registrations_message: Näkyy, kun ilmoittautuminen on suljettu
|
||||
content_cache_retention_period: Viestit muilta palvelimilta poistetaan määritetyn määrän päiviä jälkeen, kun arvo on asetettu positiiviseksi. Tämä voi olla peruuttamatonta.
|
||||
closed_registrations_message: Näkyy, kun rekisteröityminen on suljettu
|
||||
content_cache_retention_period: Kaikki julkaisut ja tehostukset muilta palvelimilta poistetaan, kun määritelty määrä päiviä on kulunut. Osaa julkaisuista voi olla mahdoton palauttaa. Kaikki julkaisuihin liittyvät kirjanmerkit, suosikit ja tehostukset menetetään, eikä niitä voi palauttaa.
|
||||
custom_css: Voit käyttää mukautettuja tyylejä Mastodonin verkkoversiossa.
|
||||
mascot: Ohittaa kuvituksen edistyneessä selainkäyttöliittymässä.
|
||||
media_cache_retention_period: Ladatut mediatiedostot poistetaan määritetyn määrän päiviä jälkeen, kun arvo on positiivinen ja ladataan uudelleen pyynnöstä.
|
||||
peers_api_enabled: Luettelo verkkotunnuksista, jotka tämä palvelin on kohdannut fediversumissa. Se ei kerro, oletko liitossa tietyn palvelimen kanssa, vaan että palvelimesi on ylipäätään tietoinen siitä. Tätä tietoa käytetään palveluissa, jotka keräävät tilastoja liittoutumisesta yleisellä tasolla.
|
||||
peers_api_enabled: Luettelo verkkotunnuksista, jotka tämä palvelin on kohdannut fediversumissa. Se ei kerro, oletko liitossa tietyn palvelimen kanssa, vaan että palvelimesi on ylipäätään tietoinen siitä. Tätä tietoa käytetään palveluissa, jotka keräävät tilastoja federoinnista yleisellä tasolla.
|
||||
profile_directory: Profiilihakemisto lueteloi kaikki käyttäjät, jotka ovat ilmoittaneet olevansa löydettävissä.
|
||||
require_invite_text: Kun kirjautuminen vaatii manuaalisen hyväksynnän, tee ”Miksi haluat liittyä?” teksti syötetään pakolliseksi eikä vapaaehtoiseksi
|
||||
require_invite_text: Kun rekisteröityminen vaatii manuaalisen hyväksynnän, tee ”Miksi haluat liittyä?” -tekstikentästä pakollinen vapaaehtoisen sijaan
|
||||
site_contact_email: Kuinka ihmiset voivat tavoittaa sinut oikeudellisissa tai tukikysymyksissä.
|
||||
site_contact_username: Miten ihmiset voivat tavoittaa sinut Mastodonissa.
|
||||
site_extended_description: Kaikki lisätiedot, jotka voivat olla hyödyllisiä kävijöille ja käyttäjille. Voidaan jäsentää Markdown-syntaksilla.
|
||||
|
@ -96,10 +96,10 @@ fi:
|
|||
status_page_url: URL-osoite sivulle, jonka kautta tämän palvelimen tila voidaan ongelmatilanteissa tarkastaa
|
||||
theme: Teema, jonka uloskirjautuneet vierailijat ja uudet käyttäjät näkevät.
|
||||
thumbnail: Noin 2:1 kuva näytetään palvelimen tietojen rinnalla.
|
||||
timeline_preview: Uloskirjautuneet vierailijat voivat selata uusimpia julkisia viestejä, jotka ovat saatavilla palvelimella.
|
||||
timeline_preview: Uloskirjautuneet vierailijat voivat selata uusimpia julkisia julkaisuja, jotka ovat saatavilla palvelimella.
|
||||
trendable_by_default: Ohita suositun sisällön manuaalinen tarkistus. Yksittäisiä kohteita voidaan edelleen poistaa jälkikäteen.
|
||||
trends: Trendit osoittavat, mitkä julkaisut, aihetunnisteet ja uutiset ovat saamassa vetoa palvelimellasi.
|
||||
trends_as_landing_page: Näytä vierailijoille ja uloskirjautuneille käyttäjille suosittu sisältö palvelininstanssin kuvaustekstin sijaan. Edellytyksenä on, että suosittu sisältö -ominaisuus on käytössä.
|
||||
trends_as_landing_page: Näytä vierailijoille ja uloskirjautuneille käyttäjille suosittua sisältöä palvelimen kuvauksen sijaan. Edellyttää, että trendit on otettu käyttöön.
|
||||
form_challenge:
|
||||
current_password: Olet menossa suojatulle alueelle
|
||||
imports:
|
||||
|
@ -129,9 +129,9 @@ fi:
|
|||
chosen_languages: Kun valittu, vain valituilla kielillä kirjoitetut julkaisut näkyvät julkisilla aikajanoilla
|
||||
role: Rooli määrää, mitkä käyttöoikeudet käyttäjällä on
|
||||
user_role:
|
||||
color: Väri, jota käytetään roolin koko käyttöliittymässä, RGB heksamuodossa
|
||||
color: Väri, jota käytetään roolille kaikkialla käyttöliittymässä, RGB-heksadesimaalimuodossa
|
||||
highlighted: Tämä tekee roolista julkisesti näkyvän
|
||||
name: Roolin julkinen nimi, jos rooli on asetettu näytettäväksi mekkinä
|
||||
name: Roolin julkinen nimi, jos rooli on asetettu näytettäväksi merkkinä
|
||||
permissions_as_keys: Käyttäjillä, joilla on tämä rooli, on käyttöoikeus...
|
||||
position: Korkeampi rooli ratkaisee konfliktit tietyissä tilanteissa. Tiettyjä toimintoja voidaan suorittaa vain rooleille, joiden prioriteetti on pienempi
|
||||
webhook:
|
||||
|
@ -238,10 +238,10 @@ fi:
|
|||
hide: Piilota kokonaan
|
||||
warn: Piilota ja näytä varoitus
|
||||
form_admin_settings:
|
||||
activity_api_enabled: Julkaise yhteenlasketut tilastot käyttäjätoiminnasta rajapinnassa
|
||||
activity_api_enabled: Julkaise yhteenlasketut tilastot käyttäjätoiminnasta ohjelmointirajapinnassa
|
||||
backups_retention_period: Käyttäjän arkiston säilytysaika
|
||||
bootstrap_timeline_accounts: Suosittele aina näitä tilejä uusille käyttäjille
|
||||
closed_registrations_message: Mukautettu viesti, kun kirjautumisia ei ole saatavilla
|
||||
closed_registrations_message: Mukautettu viesti, kun rekisteröityminen ei ole saatavilla
|
||||
content_cache_retention_period: Sisällön välimuistin säilytysaika
|
||||
custom_css: Mukautettu CSS
|
||||
mascot: Mukautettu maskotti (legacy)
|
||||
|
@ -251,7 +251,7 @@ fi:
|
|||
registrations_mode: Kuka voi rekisteröityä
|
||||
require_invite_text: Vaadi syy liittyä
|
||||
show_domain_blocks: Näytä verkkotunnusten estot
|
||||
show_domain_blocks_rationale: Näytä miksi verkkotunnukset on estetty
|
||||
show_domain_blocks_rationale: Näytä, miksi verkkotunnukset on estetty
|
||||
site_contact_email: Ota yhteyttä sähköpostilla
|
||||
site_contact_username: Yhteyshenkilön käyttäjänimi
|
||||
site_extended_description: Laajennettu kuvaus
|
||||
|
@ -261,10 +261,10 @@ fi:
|
|||
status_page_url: Tilasivun URL-osoite
|
||||
theme: Oletusteema
|
||||
thumbnail: Palvelimen pikkukuva
|
||||
timeline_preview: Salli todentamaton pääsy julkiselle aikajanalle
|
||||
timeline_preview: Salli todentamaton pääsy julkisille aikajanoille
|
||||
trendable_by_default: Salli trendit ilman ennakkotarkastusta
|
||||
trends: Trendit käyttöön
|
||||
trends_as_landing_page: Käytä suosittua sisältöä aloitussivuna
|
||||
trends: Ota trendit käyttöön
|
||||
trends_as_landing_page: Käytä trendejä aloitussivuna
|
||||
interactions:
|
||||
must_be_follower: Estä ilmoitukset käyttäjiltä, jotka eivät seuraa sinua
|
||||
must_be_following: Estä ilmoitukset käyttäjiltä, joita et seuraa
|
||||
|
@ -313,7 +313,7 @@ fi:
|
|||
time_zone: Aikavyöhyke
|
||||
user_role:
|
||||
color: Merkin väri
|
||||
highlighted: Näyttä rooli merkkinä käyttäjäprofiileissa
|
||||
highlighted: Näytä rooli merkkinä käyttäjäprofiileissa
|
||||
name: Nimi
|
||||
permissions_as_keys: Oikeudet
|
||||
position: Prioriteetti
|
||||
|
|
|
@ -5,7 +5,7 @@ zh-TW:
|
|||
account:
|
||||
discoverable: 公開嘟文及個人檔案可能於各 Mastodon 功能中被推薦,並且您的個人檔案可能被推薦至其他使用者。
|
||||
display_name: 完整名稱或暱稱。
|
||||
fields: 烘培雞,自我認同代稱,年齡,及任何您想分享的。
|
||||
fields: 烘培雞、自我認同代稱、年齡,及任何您想分享的。
|
||||
indexable: 您的公開嘟文可能會顯示於 Mastodon 之搜尋結果中。曾與您嘟文互動過的人可能無論如何都能搜尋它們。
|
||||
note: '您可以 @mention 其他人或者使用 #主題標籤。'
|
||||
show_collections: 人們將能瀏覽您跟隨中及跟隨者帳號。您所跟隨之人能得知您正在跟隨其帳號。
|
||||
|
@ -31,7 +31,7 @@ zh-TW:
|
|||
warning_preset_id: 選用。您仍可在預設的結尾新增自訂文字
|
||||
announcement:
|
||||
all_day: 核取後,只會顯示出時間範圍中的日期部分
|
||||
ends_at: 可選的,公告會在該時間點自動取消發布
|
||||
ends_at: 可選的,公告會於該時間點自動取消發布
|
||||
scheduled_at: 空白則立即發布公告
|
||||
starts_at: 可選的,讓公告在特定時間範圍內顯示
|
||||
text: 您可以使用嘟文語法,但請小心別讓公告太鴨霸而佔據使用者的整個版面。
|
||||
|
@ -59,8 +59,8 @@ zh-TW:
|
|||
setting_display_media_default: 隱藏標為敏感內容的媒體
|
||||
setting_display_media_hide_all: 總是隱藏所有媒體
|
||||
setting_display_media_show_all: 總是顯示標為敏感內容的媒體
|
||||
setting_use_blurhash: 彩色漸層圖樣是基於隱藏媒體內容顏色產生,所有細節會變得模糊
|
||||
setting_use_pending_items: 關閉自動捲動更新,時間軸只會在點擊後更新
|
||||
setting_use_blurhash: 彩色漸層圖樣是基於隱藏媒體內容顏色產生,所有細節將變得模糊
|
||||
setting_use_pending_items: 關閉自動捲動更新,時間軸只會於點擊後更新
|
||||
username: 您可以使用字幕、數字與底線
|
||||
whole_word: 如果關鍵字或詞組僅有字母與數字,則其將只在符合整個單字的時候才會套用
|
||||
domain_allow:
|
||||
|
@ -126,7 +126,7 @@ zh-TW:
|
|||
tag:
|
||||
name: 您只能變更大小寫,例如,以使其更易讀。
|
||||
user:
|
||||
chosen_languages: 當選取時,只有選取語言之嘟文會在公開時間軸中顯示
|
||||
chosen_languages: 當選取時,只有選取語言之嘟文會於公開時間軸中顯示
|
||||
role: 角色控制使用者有哪些權限
|
||||
user_role:
|
||||
color: 在整個使用者介面中用於角色的顏色,十六進位格式的 RGB
|
||||
|
|
|
@ -353,6 +353,7 @@ sk:
|
|||
silence: Obmedz
|
||||
suspend: Vylúč
|
||||
title: Nové blokovanie domény
|
||||
not_permitted: Nemáš povolenie na vykonanie tohto kroku
|
||||
obfuscate: Zatemniť názov domény
|
||||
private_comment: Súkromný komentár
|
||||
private_comment_hint: Odôvodni toto doménové obmedzenie, pre vnútorné vyrozumenie moderátorov.
|
||||
|
|
|
@ -451,9 +451,7 @@ zh-TW:
|
|||
title: 匯入網域黑名單
|
||||
no_file: 尚未選擇檔案
|
||||
follow_recommendations:
|
||||
description_html: |-
|
||||
<strong>跟隨建議幫助新使用者們快速找到有趣的內容</strong>。當使用者沒有與其他帳號有足夠多的互動以建立個人化跟隨建議時,這些帳號將會被推薦。這些帳號將基於某選定語言之高互動和高本地跟隨者數量帳號而
|
||||
每日重新更新。
|
||||
description_html: "<strong>跟隨建議幫助新使用者們快速找到有趣的內容</strong>。當使用者沒有與其他帳號有足夠多的互動以建立個人化跟隨建議時,這些帳號將會被推薦。這些帳號將基於某選定語言之高互動和高本地跟隨者數量帳號而每日重新更新。"
|
||||
language: 對於語言
|
||||
status: 狀態
|
||||
suppress: 取消跟隨建議
|
||||
|
@ -553,7 +551,7 @@ zh-TW:
|
|||
relays:
|
||||
add_new: 新增中繼站
|
||||
delete: 刪除
|
||||
description_html: "<strong>聯邦中繼站</strong> 是種中繼伺服器,會在訂閱並推送至此中繼站的伺服器之間交換大量的公開嘟文。<strong>中繼站也能協助小型或中型伺服器從聯邦宇宙中探索內容</strong>,而無須本地使用者手動跟隨遠端伺服器的其他使用者。"
|
||||
description_html: "<strong>聯邦中繼站</strong> 是種中繼伺服器,會於訂閱並推送至此中繼站的伺服器之間交換大量的公開嘟文。<strong>中繼站也能協助小型或中型伺服器從聯邦宇宙中探索內容</strong>,而無須本地使用者手動跟隨遠端伺服器的其他使用者。"
|
||||
disable: 停用
|
||||
disabled: 停用
|
||||
enable: 啟用
|
||||
|
@ -988,7 +986,7 @@ zh-TW:
|
|||
aliases:
|
||||
add_new: 建立別名
|
||||
created_msg: 成功建立別名。您可以自舊帳號開始轉移。
|
||||
deleted_msg: 成功移除別名。您將無法再由舊帳號轉移到目前的帳號。
|
||||
deleted_msg: 成功移除別名。您將無法再由舊帳號轉移至目前的帳號。
|
||||
empty: 您目前沒有任何別名。
|
||||
hint_html: 如果想由其他帳號轉移至此帳號,您可以在此處新增別名,稍後系統將容許您將跟隨者由舊帳號轉移至此。此項作業是<strong>無害且可復原的</strong>。 <strong>帳號的遷移程序需要在舊帳號啟動</strong>。
|
||||
remove: 取消連結別名
|
||||
|
@ -999,7 +997,7 @@ zh-TW:
|
|||
confirmation_dialogs: 確認對話框
|
||||
discovery: 探索
|
||||
localization:
|
||||
body: Mastodon 是由志願者翻譯的。
|
||||
body: Mastodon 是由志願者所翻譯。
|
||||
guide_link: https://crowdin.com/project/mastodon
|
||||
guide_link_text: 每個人都能貢獻。
|
||||
sensitive_content: 敏感內容
|
||||
|
@ -1042,8 +1040,8 @@ zh-TW:
|
|||
log_in_with: 登入,使用
|
||||
login: 登入
|
||||
logout: 登出
|
||||
migrate_account: 轉移到另一個帳號
|
||||
migrate_account_html: 如果您希望引導他人跟隨另一個帳號,請 <a href="%{path}">到這裡設定</a>。
|
||||
migrate_account: 轉移至另一個帳號
|
||||
migrate_account_html: 如果您希望引導他人跟隨另一個帳號,請<a href="%{path}">至這裡設定</a>。
|
||||
or_log_in_with: 或透過其他方式登入
|
||||
privacy_policy_agreement_html: 我已閱讀且同意 <a href="%{privacy_policy_path}" target="_blank">隱私權政策</a>
|
||||
progress:
|
||||
|
@ -1072,7 +1070,7 @@ zh-TW:
|
|||
email_below_hint_html: 請檢查您的垃圾郵件資料夾,或是請求另一個。如果是錯的,您可以更正您的電子郵件地址。
|
||||
email_settings_hint_html: 請點擊我們寄給您連結以驗證 %{email}。我們將於此稍候。
|
||||
link_not_received: 無法取得連結嗎?
|
||||
new_confirmation_instructions_sent: 您將會在幾分鐘之內收到新的包含確認連結的電子郵件!
|
||||
new_confirmation_instructions_sent: 您將於幾分鐘之內收到新的包含確認連結的電子郵件!
|
||||
title: 請檢查您的收件匣
|
||||
sign_in:
|
||||
preamble_html: 請使用您於 <strong>%{domain}</strong> 的帳號密碼登入。若您的帳號託管於其他伺服器,您將無法在此登入。
|
||||
|
@ -1084,7 +1082,7 @@ zh-TW:
|
|||
status:
|
||||
account_status: 帳號狀態
|
||||
confirming: 等待電子郵件確認完成。
|
||||
functional: 您的帳號可以正常使用了。
|
||||
functional: "您的帳號可以正常使用了。🎉"
|
||||
pending: 管管們正在處理您的申請,這可能需要一點時間處理。我們將於申請通過後以電子郵件方式通知您。
|
||||
redirecting_to: 您的帳號因目前重定向至 %{acct} 而被停用。
|
||||
view_strikes: 檢視針對您帳號過去的警示
|
||||
|
@ -1410,7 +1408,7 @@ zh-TW:
|
|||
followers: 此動作將會將目前帳號的所有跟隨者轉移至新帳號
|
||||
only_redirect_html: 或者,您也可以<a href="%{path}">僅在您的個人檔案中設定重新導向</a>。
|
||||
other_data: 其他資料並不會自動轉移
|
||||
redirect: 您目前的帳號將會在個人檔案頁面新增重新導向公告,並會被排除在搜尋結果之外
|
||||
redirect: 您目前的帳號將於個人檔案頁面新增重新導向公告,並會被排除在搜尋結果之外
|
||||
moderation:
|
||||
title: 站務
|
||||
move_handler:
|
||||
|
@ -1499,9 +1497,7 @@ zh-TW:
|
|||
posting_defaults: 嘟文預設值
|
||||
public_timelines: 公開時間軸
|
||||
privacy:
|
||||
hint_html: |-
|
||||
<strong>自訂您希望如何讓您的個人檔案及嘟文被找到。</strong>
|
||||
藉由啟用一系列 Mastodon 功能以幫助您觸及更廣的受眾。煩請花些時間確認您是否欲啟用這些設定。
|
||||
hint_html: "<strong>自訂您希望如何讓您的個人檔案及嘟文被發現。</strong>藉由啟用一系列 Mastodon 功能以幫助您觸及更廣的受眾。煩請花些時間確認您是否欲啟用這些設定。"
|
||||
privacy: 隱私權
|
||||
privacy_hint_html: 控制您希望向其他人揭露之內容。人們透過瀏覽其他人的跟隨者與其發嘟之應用程式發現有趣的個人檔案和酷炫的 Mastodon 應用程式,但您能選擇將其隱藏。
|
||||
reach: 觸及
|
||||
|
@ -1665,7 +1661,7 @@ zh-TW:
|
|||
enabled: 自動刪除舊嘟文
|
||||
enabled_hint: 一旦達到指定的保存期限,就會自動刪除您的嘟文,除非該嘟文符合下列例外
|
||||
exceptions: 例外
|
||||
explanation: 因為刪除嘟文是耗費資源的操作,當伺服器不那麼忙碌時才會慢慢完成。因此,您的嘟文會在到達保存期限後一段時間才會被刪除。
|
||||
explanation: 因為刪除嘟文是耗費資源的操作,當伺服器不那麼忙碌時才會慢慢完成。因此,您的嘟文將於到達保存期限後一段時間才會被刪除。
|
||||
ignore_favs: 忽略最愛數
|
||||
ignore_reblogs: 忽略轉嘟數
|
||||
interaction_exceptions: 基於互動的例外規則
|
||||
|
|
|
@ -16,37 +16,63 @@ describe Rack::Attack, type: :request do
|
|||
# https://github.com/rack/rack-attack/blob/v6.6.1/lib/rack/attack/cache.rb#L64-L66
|
||||
# So we want to minimize `Time.now.to_i % period`
|
||||
|
||||
travel_to Time.zone.at((Time.now.to_i / period.seconds).to_i * period.seconds)
|
||||
travel_to Time.zone.at(counter_prefix * period.seconds)
|
||||
end
|
||||
|
||||
context 'when the number of requests is lower than the limit' do
|
||||
it 'does not change the request status' do
|
||||
limit.times do
|
||||
request.call
|
||||
expect(response).to_not have_http_status(429)
|
||||
before do
|
||||
below_limit.times { increment_counter }
|
||||
end
|
||||
|
||||
it 'does not change the request status' do
|
||||
expect { request.call }.to change { throttle_count }.by(1)
|
||||
|
||||
expect(response).to_not have_http_status(429)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the number of requests is higher than the limit' do
|
||||
it 'returns http too many requests after limit and returns to normal status after period' do
|
||||
(limit * 2).times do |i|
|
||||
request.call
|
||||
expect(response).to have_http_status(429) if i > limit
|
||||
before do
|
||||
above_limit.times { increment_counter }
|
||||
end
|
||||
|
||||
it 'returns http too many requests after limit and returns to normal status after period' do
|
||||
expect { request.call }.to change { throttle_count }.by(1)
|
||||
expect(response).to have_http_status(429)
|
||||
|
||||
travel period
|
||||
|
||||
request.call
|
||||
expect { request.call }.to change { throttle_count }.by(1)
|
||||
expect(response).to_not have_http_status(429)
|
||||
end
|
||||
end
|
||||
|
||||
def below_limit
|
||||
limit - 1
|
||||
end
|
||||
|
||||
def above_limit
|
||||
limit * 2
|
||||
end
|
||||
|
||||
def throttle_count
|
||||
described_class.cache.read("#{counter_prefix}:#{throttle}:#{remote_ip}") || 0
|
||||
end
|
||||
|
||||
def counter_prefix
|
||||
(Time.now.to_i / period.seconds).to_i
|
||||
end
|
||||
|
||||
def increment_counter
|
||||
described_class.cache.count("#{throttle}:#{remote_ip}", period)
|
||||
end
|
||||
end
|
||||
|
||||
let(:remote_ip) { '1.2.3.5' }
|
||||
|
||||
describe 'throttle excessive sign-up requests by IP address' do
|
||||
context 'when accessed through the website' do
|
||||
let(:throttle) { 'throttle_sign_up_attempts/ip' }
|
||||
let(:limit) { 25 }
|
||||
let(:period) { 5.minutes }
|
||||
let(:request) { -> { post path, headers: { 'REMOTE_ADDR' => remote_ip } } }
|
||||
|
@ -65,6 +91,7 @@ describe Rack::Attack, type: :request do
|
|||
end
|
||||
|
||||
context 'when accessed through the API' do
|
||||
let(:throttle) { 'throttle_api_sign_up' }
|
||||
let(:limit) { 5 }
|
||||
let(:period) { 30.minutes }
|
||||
let(:request) { -> { post path, headers: { 'REMOTE_ADDR' => remote_ip } } }
|
||||
|
@ -87,6 +114,7 @@ describe Rack::Attack, type: :request do
|
|||
end
|
||||
|
||||
describe 'throttle excessive sign-in requests by IP address' do
|
||||
let(:throttle) { 'throttle_login_attempts/ip' }
|
||||
let(:limit) { 25 }
|
||||
let(:period) { 5.minutes }
|
||||
let(:request) { -> { post path, headers: { 'REMOTE_ADDR' => remote_ip } } }
|
||||
|
|
|
@ -14,11 +14,8 @@ RSpec.describe Api::OEmbedController do
|
|||
get :show, params: { url: short_account_status_url(alice, status) }, format: :json
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'returns private cache control headers', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns private cache control headers' do
|
||||
expect(response.headers['Cache-Control']).to include('private, no-store')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -41,11 +41,9 @@ describe Api::V1::Accounts::CredentialsController do
|
|||
}
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'updates account info', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'updates account info' do
|
||||
user.reload
|
||||
user.account.reload
|
||||
|
||||
|
@ -55,9 +53,7 @@ describe Api::V1::Accounts::CredentialsController do
|
|||
expect(user.account.header).to exist
|
||||
expect(user.setting_default_privacy).to eq('unlisted')
|
||||
expect(user.setting_default_sensitive).to be(true)
|
||||
end
|
||||
|
||||
it 'queues up an account update distribution' do
|
||||
expect(ActivityPub::UpdateDistributionWorker).to have_received(:perform_async).with(user.account_id)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -18,23 +18,19 @@ describe Api::V1::Accounts::FollowerAccountsController do
|
|||
end
|
||||
|
||||
describe 'GET #index' do
|
||||
it 'returns http success' do
|
||||
it 'returns accounts following the given account', :aggregate_failures do
|
||||
get :index, params: { account_id: account.id, limit: 2 }
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns accounts following the given account' do
|
||||
get :index, params: { account_id: account.id, limit: 2 }
|
||||
|
||||
expect(body_as_json.size).to eq 2
|
||||
expect([body_as_json[0][:id], body_as_json[1][:id]]).to contain_exactly(alice.id.to_s, bob.id.to_s)
|
||||
end
|
||||
|
||||
it 'does not return blocked users' do
|
||||
it 'does not return blocked users', :aggregate_failures do
|
||||
user.account.block!(bob)
|
||||
get :index, params: { account_id: account.id, limit: 2 }
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(body_as_json.size).to eq 1
|
||||
expect(body_as_json[0][:id]).to eq alice.id.to_s
|
||||
end
|
||||
|
|
|
@ -18,23 +18,19 @@ describe Api::V1::Accounts::FollowingAccountsController do
|
|||
end
|
||||
|
||||
describe 'GET #index' do
|
||||
it 'returns http success' do
|
||||
it 'returns accounts followed by the given account', :aggregate_failures do
|
||||
get :index, params: { account_id: account.id, limit: 2 }
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns accounts followed by the given account' do
|
||||
get :index, params: { account_id: account.id, limit: 2 }
|
||||
|
||||
expect(body_as_json.size).to eq 2
|
||||
expect([body_as_json[0][:id], body_as_json[1][:id]]).to contain_exactly(alice.id.to_s, bob.id.to_s)
|
||||
end
|
||||
|
||||
it 'does not return blocked users' do
|
||||
it 'does not return blocked users', :aggregate_failures do
|
||||
user.account.block!(bob)
|
||||
get :index, params: { account_id: account.id, limit: 2 }
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(body_as_json.size).to eq 1
|
||||
expect(body_as_json[0][:id]).to eq alice.id.to_s
|
||||
end
|
||||
|
|
|
@ -19,30 +19,24 @@ describe Api::V1::Accounts::NotesController do
|
|||
post :create, params: { account_id: account.id, comment: comment }
|
||||
end
|
||||
|
||||
context 'when account note has reasonable length' do
|
||||
context 'when account note has reasonable length', :aggregate_failures do
|
||||
let(:comment) { 'foo' }
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'updates account note' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(AccountNote.find_by(account_id: user.account.id, target_account_id: account.id).comment).to eq comment
|
||||
end
|
||||
end
|
||||
|
||||
context 'when account note exceeds allowed length' do
|
||||
context 'when account note exceeds allowed length', :aggregate_failures do
|
||||
let(:comment) { 'a' * 2_001 }
|
||||
|
||||
it 'returns 422' do
|
||||
subject
|
||||
expect(response).to have_http_status(422)
|
||||
end
|
||||
|
||||
it 'does not create account note' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
expect(AccountNote.where(account_id: user.account.id, target_account_id: account.id)).to_not exist
|
||||
end
|
||||
end
|
||||
|
|
|
@ -15,14 +15,11 @@ RSpec.describe Api::V1::Accounts::PinsController do
|
|||
describe 'POST #create' do
|
||||
subject { post :create, params: { account_id: kevin.account.id } }
|
||||
|
||||
it 'returns 200' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'creates account_pin' do
|
||||
it 'creates account_pin', :aggregate_failures do
|
||||
expect do
|
||||
subject
|
||||
end.to change { AccountPin.where(account: john.account, target_account: kevin.account).count }.by(1)
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -33,14 +30,11 @@ RSpec.describe Api::V1::Accounts::PinsController do
|
|||
Fabricate(:account_pin, account: john.account, target_account: kevin.account)
|
||||
end
|
||||
|
||||
it 'returns 200' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'destroys account_pin' do
|
||||
it 'destroys account_pin', :aggregate_failures do
|
||||
expect do
|
||||
subject
|
||||
end.to change { AccountPin.where(account: john.account, target_account: kevin.account).count }.by(-1)
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -26,13 +26,10 @@ describe Api::V1::Accounts::RelationshipsController do
|
|||
get :index, params: { id: simon.id }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns JSON with correct data' do
|
||||
it 'returns JSON with correct data', :aggregate_failures do
|
||||
json = body_as_json
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(json).to be_a Enumerable
|
||||
expect(json.first[:following]).to be true
|
||||
expect(json.first[:followed_by]).to be false
|
||||
|
@ -51,11 +48,14 @@ describe Api::V1::Accounts::RelationshipsController do
|
|||
context 'when there is returned JSON data' do
|
||||
let(:json) { body_as_json }
|
||||
|
||||
it 'returns an enumerable json' do
|
||||
it 'returns an enumerable json with correct elements', :aggregate_failures do
|
||||
expect(json).to be_a Enumerable
|
||||
|
||||
expect_simon_item_one
|
||||
expect_lewis_item_two
|
||||
end
|
||||
|
||||
it 'returns a correct first element' do
|
||||
def expect_simon_item_one
|
||||
expect(json.first[:id]).to eq simon.id.to_s
|
||||
expect(json.first[:following]).to be true
|
||||
expect(json.first[:showing_reblogs]).to be true
|
||||
|
@ -65,7 +65,7 @@ describe Api::V1::Accounts::RelationshipsController do
|
|||
expect(json.first[:domain_blocking]).to be false
|
||||
end
|
||||
|
||||
it 'returns a correct second element' do
|
||||
def expect_lewis_item_two
|
||||
expect(json.second[:id]).to eq lewis.id.to_s
|
||||
expect(json.second[:following]).to be false
|
||||
expect(json.second[:showing_reblogs]).to be false
|
||||
|
|
|
@ -14,15 +14,10 @@ describe Api::V1::Accounts::StatusesController do
|
|||
end
|
||||
|
||||
describe 'GET #index' do
|
||||
it 'returns http success' do
|
||||
it 'returns expected headers', :aggregate_failures do
|
||||
get :index, params: { account_id: user.account.id, limit: 1 }
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns expected headers' do
|
||||
get :index, params: { account_id: user.account.id, limit: 1 }
|
||||
|
||||
expect(response.headers['Link'].links.size).to eq(2)
|
||||
end
|
||||
|
||||
|
@ -44,14 +39,11 @@ describe Api::V1::Accounts::StatusesController do
|
|||
get :index, params: { account_id: user.account.id, exclude_replies: true }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns posts along with self replies' do
|
||||
it 'returns posts along with self replies', :aggregate_failures do
|
||||
json = body_as_json
|
||||
post_ids = json.map { |item| item[:id].to_i }.sort
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(post_ids).to eq [status.id, status_self_reply.id]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -25,15 +25,10 @@ RSpec.describe Api::V1::AccountsController do
|
|||
context 'when given truthy agreement' do
|
||||
let(:agreement) { 'true' }
|
||||
|
||||
it 'returns http success' do
|
||||
it 'creates a user', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns a new access token as JSON' do
|
||||
expect(body_as_json[:access_token]).to_not be_blank
|
||||
end
|
||||
|
||||
it 'creates a user' do
|
||||
user = User.find_by(email: 'hello@world.tld')
|
||||
expect(user).to_not be_nil
|
||||
expect(user.created_by_application_id).to eq app.id
|
||||
|
@ -59,18 +54,14 @@ RSpec.describe Api::V1::AccountsController do
|
|||
context 'with unlocked account' do
|
||||
let(:locked) { false }
|
||||
|
||||
it 'returns http success' do
|
||||
it 'creates a following relation between user and target user', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns JSON with following=true and requested=false' do
|
||||
json = body_as_json
|
||||
|
||||
expect(json[:following]).to be true
|
||||
expect(json[:requested]).to be false
|
||||
end
|
||||
|
||||
it 'creates a following relation between user and target user' do
|
||||
expect(user.account.following?(other_account)).to be true
|
||||
end
|
||||
|
||||
|
@ -80,18 +71,14 @@ RSpec.describe Api::V1::AccountsController do
|
|||
context 'with locked account' do
|
||||
let(:locked) { true }
|
||||
|
||||
it 'returns http success' do
|
||||
it 'creates a follow request relation between user and target user', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns JSON with following=false and requested=true' do
|
||||
json = body_as_json
|
||||
|
||||
expect(json[:following]).to be false
|
||||
expect(json[:requested]).to be true
|
||||
end
|
||||
|
||||
it 'creates a follow request relation between user and target user' do
|
||||
expect(user.account.requested?(other_account)).to be true
|
||||
end
|
||||
|
||||
|
@ -148,11 +135,8 @@ RSpec.describe Api::V1::AccountsController do
|
|||
post :unfollow, params: { id: other_account.id }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'removes the following relation between user and target user', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'removes the following relation between user and target user' do
|
||||
expect(user.account.following?(other_account)).to be false
|
||||
end
|
||||
|
||||
|
@ -168,11 +152,8 @@ RSpec.describe Api::V1::AccountsController do
|
|||
post :remove_from_followers, params: { id: other_account.id }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'removes the followed relation between user and target user', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'removes the followed relation between user and target user' do
|
||||
expect(user.account.followed_by?(other_account)).to be false
|
||||
end
|
||||
|
||||
|
@ -188,15 +169,9 @@ RSpec.describe Api::V1::AccountsController do
|
|||
post :block, params: { id: other_account.id }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'creates a blocking relation', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'removes the following relation between user and target user' do
|
||||
expect(user.account.following?(other_account)).to be false
|
||||
end
|
||||
|
||||
it 'creates a blocking relation' do
|
||||
expect(user.account.blocking?(other_account)).to be true
|
||||
end
|
||||
|
||||
|
@ -212,11 +187,8 @@ RSpec.describe Api::V1::AccountsController do
|
|||
post :unblock, params: { id: other_account.id }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'removes the blocking relation between user and target user', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'removes the blocking relation between user and target user' do
|
||||
expect(user.account.blocking?(other_account)).to be false
|
||||
end
|
||||
|
||||
|
@ -232,19 +204,10 @@ RSpec.describe Api::V1::AccountsController do
|
|||
post :mute, params: { id: other_account.id }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'mutes notifications', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'does not remove the following relation between user and target user' do
|
||||
expect(user.account.following?(other_account)).to be true
|
||||
end
|
||||
|
||||
it 'creates a muting relation' do
|
||||
expect(user.account.muting?(other_account)).to be true
|
||||
end
|
||||
|
||||
it 'mutes notifications' do
|
||||
expect(user.account.muting_notifications?(other_account)).to be true
|
||||
end
|
||||
|
||||
|
@ -260,19 +223,10 @@ RSpec.describe Api::V1::AccountsController do
|
|||
post :mute, params: { id: other_account.id, notifications: false }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'does not mute notifications', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'does not remove the following relation between user and target user' do
|
||||
expect(user.account.following?(other_account)).to be true
|
||||
end
|
||||
|
||||
it 'creates a muting relation' do
|
||||
expect(user.account.muting?(other_account)).to be true
|
||||
end
|
||||
|
||||
it 'does not mute notifications' do
|
||||
expect(user.account.muting_notifications?(other_account)).to be false
|
||||
end
|
||||
|
||||
|
@ -288,19 +242,10 @@ RSpec.describe Api::V1::AccountsController do
|
|||
post :mute, params: { id: other_account.id, duration: 300 }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'mutes notifications', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'does not remove the following relation between user and target user' do
|
||||
expect(user.account.following?(other_account)).to be true
|
||||
end
|
||||
|
||||
it 'creates a muting relation' do
|
||||
expect(user.account.muting?(other_account)).to be true
|
||||
end
|
||||
|
||||
it 'mutes notifications' do
|
||||
expect(user.account.muting_notifications?(other_account)).to be true
|
||||
end
|
||||
|
||||
|
@ -316,11 +261,8 @@ RSpec.describe Api::V1::AccountsController do
|
|||
post :unmute, params: { id: other_account.id }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'removes the muting relation between user and target user', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'removes the muting relation between user and target user' do
|
||||
expect(user.account.muting?(other_account)).to be false
|
||||
end
|
||||
|
||||
|
|
|
@ -1,198 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Api::V1::Admin::AccountsController do
|
||||
render_views
|
||||
|
||||
let(:role) { UserRole.find_by(name: 'Moderator') }
|
||||
let(:user) { Fabricate(:user, role: role) }
|
||||
let(:scopes) { 'admin:read admin:write' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
||||
before do
|
||||
allow(controller).to receive(:doorkeeper_token) { token }
|
||||
end
|
||||
|
||||
describe 'GET #index' do
|
||||
let!(:remote_account) { Fabricate(:account, domain: 'example.org') }
|
||||
let!(:other_remote_account) { Fabricate(:account, domain: 'foo.bar') }
|
||||
let!(:suspended_account) { Fabricate(:account, suspended: true) }
|
||||
let!(:suspended_remote) { Fabricate(:account, domain: 'foo.bar', suspended: true) }
|
||||
let!(:disabled_account) { Fabricate(:user, disabled: true).account }
|
||||
let!(:pending_account) { Fabricate(:user, approved: false).account }
|
||||
let!(:admin_account) { user.account }
|
||||
|
||||
let(:params) { {} }
|
||||
|
||||
before do
|
||||
pending_account.user.update(approved: false)
|
||||
get :index, params: params
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
[
|
||||
[{ active: 'true', local: 'true', staff: 'true' }, [:admin_account]],
|
||||
[{ by_domain: 'example.org', remote: 'true' }, [:remote_account]],
|
||||
[{ suspended: 'true' }, [:suspended_account]],
|
||||
[{ disabled: 'true' }, [:disabled_account]],
|
||||
[{ pending: 'true' }, [:pending_account]],
|
||||
].each do |params, expected_results|
|
||||
context "when called with #{params.inspect}" do
|
||||
let(:params) { params }
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it "returns the correct accounts (#{expected_results.inspect})" do
|
||||
json = body_as_json
|
||||
|
||||
expect(json.map { |a| a[:id].to_i }).to eq(expected_results.map { |symbol| send(symbol).id })
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET #show' do
|
||||
before do
|
||||
get :show, params: { id: account.id }
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #approve' do
|
||||
before do
|
||||
account.user.update(approved: false)
|
||||
post :approve, params: { id: account.id }
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'approves user' do
|
||||
expect(account.reload.user_approved?).to be true
|
||||
end
|
||||
|
||||
it 'logs action' do
|
||||
log_item = Admin::ActionLog.last
|
||||
|
||||
expect(log_item).to_not be_nil
|
||||
expect(log_item.action).to eq :approve
|
||||
expect(log_item.account_id).to eq user.account_id
|
||||
expect(log_item.target_id).to eq account.user.id
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #reject' do
|
||||
before do
|
||||
account.user.update(approved: false)
|
||||
post :reject, params: { id: account.id }
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'removes user' do
|
||||
expect(User.where(id: account.user.id).count).to eq 0
|
||||
end
|
||||
|
||||
it 'logs action' do
|
||||
log_item = Admin::ActionLog.last
|
||||
|
||||
expect(log_item).to_not be_nil
|
||||
expect(log_item.action).to eq :reject
|
||||
expect(log_item.account_id).to eq user.account_id
|
||||
expect(log_item.target_id).to eq account.user.id
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #enable' do
|
||||
before do
|
||||
account.user.update(disabled: true)
|
||||
post :enable, params: { id: account.id }
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'enables user' do
|
||||
expect(account.reload.user_disabled?).to be false
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #unsuspend' do
|
||||
before do
|
||||
account.suspend!
|
||||
post :unsuspend, params: { id: account.id }
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'unsuspends account' do
|
||||
expect(account.reload.suspended?).to be false
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #unsensitive' do
|
||||
before do
|
||||
account.touch(:sensitized_at)
|
||||
post :unsensitive, params: { id: account.id }
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'unsensitizes account' do
|
||||
expect(account.reload.sensitized?).to be false
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #unsilence' do
|
||||
before do
|
||||
account.touch(:silenced_at)
|
||||
post :unsilence, params: { id: account.id }
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'unsilences account' do
|
||||
expect(account.reload.silenced?).to be false
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,52 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe Api::V1::Admin::Trends::LinksController do
|
||||
render_views
|
||||
|
||||
let(:role) { UserRole.find_by(name: 'Admin') }
|
||||
let(:user) { Fabricate(:user, role: role) }
|
||||
let(:scopes) { 'admin:read admin:write' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:account) { Fabricate(:account) }
|
||||
let(:preview_card) { Fabricate(:preview_card) }
|
||||
|
||||
before do
|
||||
allow(controller).to receive(:doorkeeper_token) { token }
|
||||
end
|
||||
|
||||
describe 'GET #index' do
|
||||
it 'returns http success' do
|
||||
get :index, params: { account_id: account.id, limit: 2 }
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #approve' do
|
||||
before do
|
||||
post :approve, params: { id: preview_card.id }
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #reject' do
|
||||
before do
|
||||
post :reject, params: { id: preview_card.id }
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -25,11 +25,8 @@ RSpec.describe Api::V1::Announcements::ReactionsController do
|
|||
put :update, params: { announcement_id: announcement.id, id: '😂' }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'creates reaction', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'creates reaction' do
|
||||
expect(announcement.announcement_reactions.find_by(name: '😂', account: user.account)).to_not be_nil
|
||||
end
|
||||
end
|
||||
|
@ -53,11 +50,8 @@ RSpec.describe Api::V1::Announcements::ReactionsController do
|
|||
delete :destroy, params: { announcement_id: announcement.id, id: '😂' }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'creates reaction', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'creates reaction' do
|
||||
expect(announcement.announcement_reactions.find_by(name: '😂', account: user.account)).to be_nil
|
||||
end
|
||||
end
|
||||
|
|
|
@ -47,11 +47,8 @@ RSpec.describe Api::V1::AnnouncementsController do
|
|||
post :dismiss, params: { id: announcement.id }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'dismisses announcement', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'dismisses announcement' do
|
||||
expect(announcement.announcement_mutes.find_by(account: user.account)).to_not be_nil
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Api::V1::BlocksController do
|
||||
render_views
|
||||
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:scopes) { 'read:blocks' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
|
||||
before { allow(controller).to receive(:doorkeeper_token) { token } }
|
||||
|
||||
describe 'GET #index' do
|
||||
it 'limits according to limit parameter' do
|
||||
Array.new(2) { Fabricate(:block, account: user.account) }
|
||||
get :index, params: { limit: 1 }
|
||||
expect(body_as_json.size).to eq 1
|
||||
end
|
||||
|
||||
it 'queries blocks in range according to max_id' do
|
||||
blocks = Array.new(2) { Fabricate(:block, account: user.account) }
|
||||
|
||||
get :index, params: { max_id: blocks[1] }
|
||||
|
||||
expect(body_as_json.size).to eq 1
|
||||
expect(body_as_json[0][:id]).to eq blocks[0].target_account_id.to_s
|
||||
end
|
||||
|
||||
it 'queries blocks in range according to since_id' do
|
||||
blocks = Array.new(2) { Fabricate(:block, account: user.account) }
|
||||
|
||||
get :index, params: { since_id: blocks[0] }
|
||||
|
||||
expect(body_as_json.size).to eq 1
|
||||
expect(body_as_json[0][:id]).to eq blocks[1].target_account_id.to_s
|
||||
end
|
||||
|
||||
it 'sets pagination header for next path' do
|
||||
blocks = Array.new(2) { Fabricate(:block, account: user.account) }
|
||||
get :index, params: { limit: 1, since_id: blocks[0] }
|
||||
expect(response.headers['Link'].find_link(%w(rel next)).href).to eq api_v1_blocks_url(limit: 1, max_id: blocks[1])
|
||||
end
|
||||
|
||||
it 'sets pagination header for previous path' do
|
||||
block = Fabricate(:block, account: user.account)
|
||||
get :index
|
||||
expect(response.headers['Link'].find_link(%w(rel prev)).href).to eq api_v1_blocks_url(since_id: block)
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
get :index
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
context 'with wrong scopes' do
|
||||
let(:scopes) { 'write:blocks' }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
get :index
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -21,17 +21,14 @@ RSpec.describe Api::V1::ConversationsController do
|
|||
PostStatusService.new.call(user.account, text: 'Hey, nobody here', visibility: 'direct')
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
get :index
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns pagination headers' do
|
||||
it 'returns pagination headers', :aggregate_failures do
|
||||
get :index, params: { limit: 1 }
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(response.headers['Link'].links.size).to eq(2)
|
||||
end
|
||||
|
||||
it 'returns conversations' do
|
||||
it 'returns conversations', :aggregate_failures do
|
||||
get :index
|
||||
json = body_as_json
|
||||
expect(json.size).to eq 2
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Api::V1::FavouritesController do
|
||||
render_views
|
||||
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') }
|
||||
|
||||
describe 'GET #index' do
|
||||
context 'without token' do
|
||||
it 'returns http unauthorized' do
|
||||
get :index
|
||||
expect(response).to have_http_status 401
|
||||
end
|
||||
end
|
||||
|
||||
context 'with token' do
|
||||
context 'without read scope' do
|
||||
before do
|
||||
allow(controller).to receive(:doorkeeper_token) do
|
||||
Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: '')
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns http forbidden' do
|
||||
get :index
|
||||
expect(response).to have_http_status 403
|
||||
end
|
||||
end
|
||||
|
||||
context 'without valid resource owner' do
|
||||
before do
|
||||
token = Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read')
|
||||
user.destroy!
|
||||
|
||||
allow(controller).to receive(:doorkeeper_token) { token }
|
||||
end
|
||||
|
||||
it 'returns http unprocessable entity' do
|
||||
get :index
|
||||
expect(response).to have_http_status 422
|
||||
end
|
||||
end
|
||||
|
||||
context 'with read scope and valid resource owner' do
|
||||
before do
|
||||
allow(controller).to receive(:doorkeeper_token) do
|
||||
Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:favourites')
|
||||
end
|
||||
end
|
||||
|
||||
it 'shows favourites owned by the user' do
|
||||
favourite_by_user = Fabricate(:favourite, account: user.account)
|
||||
favourite_by_others = Fabricate(:favourite)
|
||||
|
||||
get :index
|
||||
|
||||
expect(assigns(:statuses)).to contain_exactly(favourite_by_user.status)
|
||||
end
|
||||
|
||||
it 'adds pagination headers if necessary' do
|
||||
favourite = Fabricate(:favourite, account: user.account)
|
||||
|
||||
get :index, params: { limit: 1 }
|
||||
|
||||
expect(response.headers['Link'].find_link(%w(rel next)).href).to eq "http://test.host/api/v1/favourites?limit=1&max_id=#{favourite.id}"
|
||||
expect(response.headers['Link'].find_link(%w(rel prev)).href).to eq "http://test.host/api/v1/favourites?limit=1&min_id=#{favourite.id}"
|
||||
end
|
||||
|
||||
it 'does not add pagination headers if not necessary' do
|
||||
get :index
|
||||
|
||||
expect(response.headers['Link']).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -31,12 +31,10 @@ RSpec.describe Api::V1::FiltersController do
|
|||
post :create, params: { phrase: 'magic', context: %w(home), irreversible: irreversible, whole_word: whole_word }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'creates a filter' do
|
||||
it 'creates a filter', :aggregate_failures do
|
||||
filter = user.account.custom_filters.first
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(filter).to_not be_nil
|
||||
expect(filter.keywords.pluck(:keyword, :whole_word)).to eq [['magic', whole_word]]
|
||||
expect(filter.context).to eq %w(home)
|
||||
|
@ -48,12 +46,10 @@ RSpec.describe Api::V1::FiltersController do
|
|||
let(:irreversible) { false }
|
||||
let(:whole_word) { true }
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'creates a filter' do
|
||||
it 'creates a filter', :aggregate_failures do
|
||||
filter = user.account.custom_filters.first
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(filter).to_not be_nil
|
||||
expect(filter.keywords.pluck(:keyword, :whole_word)).to eq [['magic', whole_word]]
|
||||
expect(filter.context).to eq %w(home)
|
||||
|
@ -83,11 +79,8 @@ RSpec.describe Api::V1::FiltersController do
|
|||
put :update, params: { id: keyword.id, phrase: 'updated' }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'updates the filter', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'updates the filter' do
|
||||
expect(keyword.reload.phrase).to eq 'updated'
|
||||
end
|
||||
end
|
||||
|
@ -101,11 +94,8 @@ RSpec.describe Api::V1::FiltersController do
|
|||
delete :destroy, params: { id: keyword.id }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'removes the filter', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'removes the filter' do
|
||||
expect { keyword.reload }.to raise_error ActiveRecord::RecordNotFound
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Api::V1::FollowedTagsController do
|
||||
render_views
|
||||
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:scopes) { 'read:follows' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
|
||||
before { allow(controller).to receive(:doorkeeper_token) { token } }
|
||||
|
||||
describe 'GET #index' do
|
||||
let!(:tag_follows) { Fabricate.times(5, :tag_follow, account: user.account) }
|
||||
|
||||
before do
|
||||
get :index, params: { limit: 1 }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -5,7 +5,7 @@ require 'rails_helper'
|
|||
describe Api::V1::Instances::TranslationLanguagesController do
|
||||
describe 'GET #show' do
|
||||
context 'when no translation service is configured' do
|
||||
it 'returns empty language matrix' do
|
||||
it 'returns empty language matrix', :aggregate_failures do
|
||||
get :show
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
|
@ -19,7 +19,7 @@ describe Api::V1::Instances::TranslationLanguagesController do
|
|||
allow(TranslationService).to receive_messages(configured?: true, configured: service)
|
||||
end
|
||||
|
||||
it 'returns language matrix' do
|
||||
it 'returns language matrix', :aggregate_failures do
|
||||
get :show
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
|
|
|
@ -1,92 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe Api::V1::Lists::AccountsController do
|
||||
render_views
|
||||
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:list) { Fabricate(:list, account: user.account) }
|
||||
|
||||
before do
|
||||
follow = Fabricate(:follow, account: user.account)
|
||||
list.accounts << follow.target_account
|
||||
allow(controller).to receive(:doorkeeper_token) { token }
|
||||
end
|
||||
|
||||
describe 'GET #index' do
|
||||
let(:scopes) { 'read:lists' }
|
||||
|
||||
it 'returns http success' do
|
||||
get :show, params: { list_id: list.id }
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #create' do
|
||||
let(:scopes) { 'write:lists' }
|
||||
let(:bob) { Fabricate(:account, username: 'bob') }
|
||||
|
||||
context 'when the added account is followed' do
|
||||
before do
|
||||
user.account.follow!(bob)
|
||||
post :create, params: { list_id: list.id, account_ids: [bob.id] }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'adds account to the list' do
|
||||
expect(list.accounts.include?(bob)).to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the added account has been sent a follow request' do
|
||||
before do
|
||||
user.account.follow_requests.create!(target_account: bob)
|
||||
post :create, params: { list_id: list.id, account_ids: [bob.id] }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'adds account to the list' do
|
||||
expect(list.accounts.include?(bob)).to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the added account is not followed' do
|
||||
before do
|
||||
post :create, params: { list_id: list.id, account_ids: [bob.id] }
|
||||
end
|
||||
|
||||
it 'returns http not found' do
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
|
||||
it 'does not add the account to the list' do
|
||||
expect(list.accounts.include?(bob)).to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE #destroy' do
|
||||
let(:scopes) { 'write:lists' }
|
||||
|
||||
before do
|
||||
delete :destroy, params: { list_id: list.id, account_ids: [list.accounts.first.id] }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'removes account from the list' do
|
||||
expect(list.accounts.count).to eq 0
|
||||
end
|
||||
end
|
||||
end
|
|
@ -18,13 +18,10 @@ RSpec.describe Api::V1::MarkersController do
|
|||
get :index, params: { timeline: %w(home notifications) }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns markers' do
|
||||
it 'returns markers', :aggregate_failures do
|
||||
json = body_as_json
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(json.key?(:home)).to be true
|
||||
expect(json[:home][:last_read_id]).to eq '123'
|
||||
expect(json.key?(:notifications)).to be true
|
||||
|
@ -38,11 +35,8 @@ RSpec.describe Api::V1::MarkersController do
|
|||
post :create, params: { home: { last_read_id: '69420' } }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'creates a marker', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'creates a marker' do
|
||||
expect(user.markers.first.timeline).to eq 'home'
|
||||
expect(user.markers.first.last_read_id).to eq 69_420
|
||||
end
|
||||
|
@ -54,11 +48,8 @@ RSpec.describe Api::V1::MarkersController do
|
|||
post :create, params: { home: { last_read_id: '70120' } }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'updates a marker', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'updates a marker' do
|
||||
expect(user.markers.first.timeline).to eq 'home'
|
||||
expect(user.markers.first.last_read_id).to eq 70_120
|
||||
end
|
||||
|
|
|
@ -38,19 +38,10 @@ RSpec.describe Api::V1::MediaController do
|
|||
post :create, params: { file: fixture_file_upload('attachment.jpg', 'image/jpeg') }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'creates a media attachment', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'creates a media attachment' do
|
||||
expect(MediaAttachment.first).to_not be_nil
|
||||
end
|
||||
|
||||
it 'uploads a file' do
|
||||
expect(MediaAttachment.first).to have_attached_file(:file)
|
||||
end
|
||||
|
||||
it 'returns media ID in JSON' do
|
||||
expect(body_as_json[:id]).to eq MediaAttachment.first.id.to_s
|
||||
end
|
||||
end
|
||||
|
@ -60,19 +51,10 @@ RSpec.describe Api::V1::MediaController do
|
|||
post :create, params: { file: fixture_file_upload('attachment.gif', 'image/gif') }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'creates a media attachment', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'creates a media attachment' do
|
||||
expect(MediaAttachment.first).to_not be_nil
|
||||
end
|
||||
|
||||
it 'uploads a file' do
|
||||
expect(MediaAttachment.first).to have_attached_file(:file)
|
||||
end
|
||||
|
||||
it 'returns media ID in JSON' do
|
||||
expect(body_as_json[:id]).to eq MediaAttachment.first.id.to_s
|
||||
end
|
||||
end
|
||||
|
@ -82,17 +64,10 @@ RSpec.describe Api::V1::MediaController do
|
|||
post :create, params: { file: fixture_file_upload('attachment.webm', 'video/webm') }
|
||||
end
|
||||
|
||||
it do
|
||||
# returns http success
|
||||
it 'creates a media attachment', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
|
||||
# creates a media attachment
|
||||
expect(MediaAttachment.first).to_not be_nil
|
||||
|
||||
# uploads a file
|
||||
expect(MediaAttachment.first).to have_attached_file(:file)
|
||||
|
||||
# returns media ID in JSON
|
||||
expect(body_as_json[:id]).to eq MediaAttachment.first.id.to_s
|
||||
end
|
||||
end
|
||||
|
|
|
@ -18,18 +18,13 @@ RSpec.describe Api::V1::Polls::VotesController do
|
|||
post :create, params: { poll_id: poll.id, choices: %w(1) }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'creates a vote', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'creates a vote' do
|
||||
vote = poll.votes.where(account: user.account).first
|
||||
|
||||
expect(vote).to_not be_nil
|
||||
expect(vote.choice).to eq 1
|
||||
end
|
||||
|
||||
it 'updates poll tallies' do
|
||||
expect(poll.reload.cached_tallies).to eq [0, 1]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,75 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Api::V1::ReportsController do
|
||||
render_views
|
||||
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
|
||||
before do
|
||||
allow(controller).to receive(:doorkeeper_token) { token }
|
||||
end
|
||||
|
||||
describe 'POST #create' do
|
||||
let!(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
|
||||
|
||||
let(:scopes) { 'write:reports' }
|
||||
let(:status) { Fabricate(:status) }
|
||||
let(:target_account) { status.account }
|
||||
let(:category) { nil }
|
||||
let(:forward) { nil }
|
||||
let(:rule_ids) { nil }
|
||||
|
||||
before do
|
||||
post :create, params: { status_ids: [status.id], account_id: target_account.id, comment: 'reasons', category: category, rule_ids: rule_ids, forward: forward }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'creates a report' do
|
||||
expect(target_account.targeted_reports).to_not be_empty
|
||||
end
|
||||
|
||||
it 'saves comment' do
|
||||
expect(target_account.targeted_reports.first.comment).to eq 'reasons'
|
||||
end
|
||||
|
||||
it 'sends e-mails to admins' do
|
||||
expect(ActionMailer::Base.deliveries.first.to).to eq([admin.email])
|
||||
end
|
||||
|
||||
context 'when a status does not belong to the reported account' do
|
||||
let(:target_account) { Fabricate(:account) }
|
||||
|
||||
it 'returns http not found' do
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a category is chosen' do
|
||||
let(:category) { 'spam' }
|
||||
|
||||
it 'saves category' do
|
||||
expect(target_account.targeted_reports.first.spam?).to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'when violated rules are chosen' do
|
||||
let(:rule) { Fabricate(:rule) }
|
||||
let(:category) { 'violation' }
|
||||
let(:rule_ids) { [rule.id] }
|
||||
|
||||
it 'saves category' do
|
||||
expect(target_account.targeted_reports.first.violation?).to be true
|
||||
end
|
||||
|
||||
it 'saves rule_ids' do
|
||||
expect(target_account.targeted_reports.first.rule_ids).to contain_exactly(rule.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -21,11 +21,8 @@ describe Api::V1::Statuses::MutesController do
|
|||
post :create, params: { status_id: status.id }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'creates a conversation mute', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'creates a conversation mute' do
|
||||
expect(ConversationMute.find_by(account: user.account, conversation_id: status.conversation_id)).to_not be_nil
|
||||
end
|
||||
end
|
||||
|
@ -38,11 +35,8 @@ describe Api::V1::Statuses::MutesController do
|
|||
post :destroy, params: { status_id: status.id }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'destroys the conversation mute', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'destroys the conversation mute' do
|
||||
expect(ConversationMute.find_by(account: user.account, conversation_id: status.conversation_id)).to be_nil
|
||||
end
|
||||
end
|
||||
|
|
|
@ -24,14 +24,12 @@ RSpec.describe Api::V1::Statuses::RebloggedByAccountsController do
|
|||
Fabricate(:status, account: bob, reblog_of_id: status.id)
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'returns accounts who reblogged the status', :aggregate_failures do
|
||||
get :index, params: { status_id: status.id, limit: 2 }
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(response.headers['Link'].links.size).to eq(2)
|
||||
end
|
||||
|
||||
it 'returns accounts who reblogged the status' do
|
||||
get :index, params: { status_id: status.id, limit: 2 }
|
||||
expect(body_as_json.size).to eq 2
|
||||
expect([body_as_json[0][:id], body_as_json[1][:id]]).to contain_exactly(alice.id.to_s, bob.id.to_s)
|
||||
end
|
||||
|
|
|
@ -28,19 +28,13 @@ describe Api::V1::Statuses::ReblogsController do
|
|||
end
|
||||
|
||||
context 'with public status' do
|
||||
it 'returns http success' do
|
||||
it 'reblogs the status', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'updates the reblogs count' do
|
||||
expect(status.reblogs.count).to eq 1
|
||||
end
|
||||
|
||||
it 'updates the reblogged attribute' do
|
||||
expect(user.account.reblogged?(status)).to be true
|
||||
end
|
||||
|
||||
it 'returns json with updated attributes' do
|
||||
hash_body = body_as_json
|
||||
|
||||
expect(hash_body[:reblog][:id]).to eq status.id.to_s
|
||||
|
@ -67,19 +61,13 @@ describe Api::V1::Statuses::ReblogsController do
|
|||
post :destroy, params: { status_id: status.id }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'destroys the reblog', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'updates the reblogs count' do
|
||||
expect(status.reblogs.count).to eq 0
|
||||
end
|
||||
|
||||
it 'updates the reblogged attribute' do
|
||||
expect(user.account.reblogged?(status)).to be false
|
||||
end
|
||||
|
||||
it 'returns json with updated attributes' do
|
||||
hash_body = body_as_json
|
||||
|
||||
expect(hash_body[:id]).to eq status.id.to_s
|
||||
|
@ -97,19 +85,13 @@ describe Api::V1::Statuses::ReblogsController do
|
|||
post :destroy, params: { status_id: status.id }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'destroys the reblog', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'updates the reblogs count' do
|
||||
expect(status.reblogs.count).to eq 0
|
||||
end
|
||||
|
||||
it 'updates the reblogged attribute' do
|
||||
expect(user.account.reblogged?(status)).to be false
|
||||
end
|
||||
|
||||
it 'returns json with updated attributes' do
|
||||
hash_body = body_as_json
|
||||
|
||||
expect(hash_body[:id]).to eq status.id.to_s
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe Api::V1::Statuses::SourcesController do
|
||||
render_views
|
||||
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:app) { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:statuses', application: app) }
|
||||
|
||||
context 'with an oauth token' do
|
||||
before do
|
||||
allow(controller).to receive(:doorkeeper_token) { token }
|
||||
end
|
||||
|
||||
describe 'GET #show' do
|
||||
let(:status) { Fabricate(:status, account: user.account) }
|
||||
|
||||
before do
|
||||
get :show, params: { status_id: status.id }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -30,14 +30,11 @@ RSpec.describe Api::V1::StatusesController do
|
|||
user.account.custom_filters.create!(phrase: 'filter1', context: %w(home), action: :hide, keywords_attributes: [{ keyword: 'banned' }, { keyword: 'irrelevant' }])
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
get :show, params: { id: status.id }
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns filter information' do
|
||||
it 'returns filter information', :aggregate_failures do
|
||||
get :show, params: { id: status.id }
|
||||
json = body_as_json
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(json[:filtered][0]).to include({
|
||||
filter: a_hash_including({
|
||||
id: user.account.custom_filters.first.id.to_s,
|
||||
|
@ -57,14 +54,11 @@ RSpec.describe Api::V1::StatusesController do
|
|||
filter.statuses.create!(status_id: status.id)
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
get :show, params: { id: status.id }
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns filter information' do
|
||||
it 'returns filter information', :aggregate_failures do
|
||||
get :show, params: { id: status.id }
|
||||
json = body_as_json
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(json[:filtered][0]).to include({
|
||||
filter: a_hash_including({
|
||||
id: user.account.custom_filters.first.id.to_s,
|
||||
|
@ -83,14 +77,11 @@ RSpec.describe Api::V1::StatusesController do
|
|||
user.account.custom_filters.create!(phrase: 'filter1', context: %w(home), action: :hide, keywords_attributes: [{ keyword: 'banned' }, { keyword: 'irrelevant' }])
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
get :show, params: { id: status.id }
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns filter information' do
|
||||
it 'returns filter information', :aggregate_failures do
|
||||
get :show, params: { id: status.id }
|
||||
json = body_as_json
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(json[:reblog][:filtered][0]).to include({
|
||||
filter: a_hash_including({
|
||||
id: user.account.custom_filters.first.id.to_s,
|
||||
|
@ -125,11 +116,8 @@ RSpec.describe Api::V1::StatusesController do
|
|||
post :create, params: { status: 'Hello world' }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'returns rate limit headers', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns rate limit headers' do
|
||||
expect(response.headers['X-RateLimit-Limit']).to eq RateLimiter::FAMILIES[:statuses][:limit].to_s
|
||||
expect(response.headers['X-RateLimit-Remaining']).to eq (RateLimiter::FAMILIES[:statuses][:limit] - 1).to_s
|
||||
end
|
||||
|
@ -143,11 +131,8 @@ RSpec.describe Api::V1::StatusesController do
|
|||
post :create, params: { status: '@alice hm, @bob is really annoying lately', allowed_mentions: [alice.id] }
|
||||
end
|
||||
|
||||
it 'returns http unprocessable entity' do
|
||||
it 'returns serialized extra accounts in body', :aggregate_failures do
|
||||
expect(response).to have_http_status(422)
|
||||
end
|
||||
|
||||
it 'returns serialized extra accounts in body' do
|
||||
expect(body_as_json[:unexpected_accounts].map { |a| a.slice(:id, :acct) }).to eq [{ id: bob.id.to_s, acct: bob.acct }]
|
||||
end
|
||||
end
|
||||
|
@ -157,11 +142,8 @@ RSpec.describe Api::V1::StatusesController do
|
|||
post :create, params: {}
|
||||
end
|
||||
|
||||
it 'returns http unprocessable entity' do
|
||||
it 'returns rate limit headers', :aggregate_failures do
|
||||
expect(response).to have_http_status(422)
|
||||
end
|
||||
|
||||
it 'returns rate limit headers' do
|
||||
expect(response.headers['X-RateLimit-Limit']).to eq RateLimiter::FAMILIES[:statuses][:limit].to_s
|
||||
end
|
||||
end
|
||||
|
@ -173,11 +155,8 @@ RSpec.describe Api::V1::StatusesController do
|
|||
post :create, params: { status: 'Hello world' }
|
||||
end
|
||||
|
||||
it 'returns http too many requests' do
|
||||
it 'returns rate limit headers', :aggregate_failures do
|
||||
expect(response).to have_http_status(429)
|
||||
end
|
||||
|
||||
it 'returns rate limit headers' do
|
||||
expect(response.headers['X-RateLimit-Limit']).to eq RateLimiter::FAMILIES[:statuses][:limit].to_s
|
||||
expect(response.headers['X-RateLimit-Remaining']).to eq '0'
|
||||
end
|
||||
|
@ -192,11 +171,8 @@ RSpec.describe Api::V1::StatusesController do
|
|||
post :destroy, params: { id: status.id }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'removes the status', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'removes the status' do
|
||||
expect(Status.find_by(id: status.id)).to be_nil
|
||||
end
|
||||
end
|
||||
|
@ -209,11 +185,8 @@ RSpec.describe Api::V1::StatusesController do
|
|||
put :update, params: { id: status.id, status: 'I am updated' }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'updates the status', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'updates the status' do
|
||||
expect(status.reload.text).to eq 'I am updated'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,75 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe Api::V1::Timelines::TagController do
|
||||
render_views
|
||||
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:statuses') }
|
||||
|
||||
before do
|
||||
allow(controller).to receive(:doorkeeper_token) { token }
|
||||
end
|
||||
|
||||
describe 'GET #show' do
|
||||
subject do
|
||||
get :show, params: { id: 'test' }
|
||||
end
|
||||
|
||||
before do
|
||||
PostStatusService.new.call(user.account, text: 'It is a #test')
|
||||
end
|
||||
|
||||
context 'when the instance allows public preview' do
|
||||
before do
|
||||
Setting.timeline_preview = true
|
||||
end
|
||||
|
||||
context 'when the user is not authenticated' do
|
||||
let(:token) { nil }
|
||||
|
||||
it 'returns http success', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(response.headers['Link'].links.size).to eq(2)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user is authenticated' do
|
||||
it 'returns http success', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(response.headers['Link'].links.size).to eq(2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the instance does not allow public preview' do
|
||||
before do
|
||||
Form::AdminSettings.new(timeline_preview: false).save
|
||||
end
|
||||
|
||||
context 'when the user is not authenticated' do
|
||||
let(:token) { nil }
|
||||
|
||||
it 'returns http unauthorized' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(401)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user is authenticated' do
|
||||
it 'returns http success', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(response.headers['Link'].links.size).to eq(2)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -44,14 +44,14 @@ RSpec.describe Api::V2::Admin::AccountsController do
|
|||
context "when called with #{params.inspect}" do
|
||||
let(:params) { params }
|
||||
|
||||
it 'returns http success' do
|
||||
it "returns the correct accounts (#{expected_results.inspect})" do
|
||||
expect(response).to have_http_status(200)
|
||||
|
||||
expect(body_json_ids).to eq(expected_results.map { |symbol| send(symbol).id })
|
||||
end
|
||||
|
||||
it "returns the correct accounts (#{expected_results.inspect})" do
|
||||
json = body_as_json
|
||||
|
||||
expect(json.map { |a| a[:id].to_i }).to eq(expected_results.map { |symbol| send(symbol).id })
|
||||
def body_json_ids
|
||||
body_as_json.map { |a| a[:id].to_i }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -40,17 +40,13 @@ RSpec.describe Api::V2::Filters::KeywordsController do
|
|||
post :create, params: { filter_id: filter_id, keyword: 'magic', whole_word: false }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'creates a filter', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns a keyword' do
|
||||
json = body_as_json
|
||||
expect(json[:keyword]).to eq 'magic'
|
||||
expect(json[:whole_word]).to be false
|
||||
end
|
||||
|
||||
it 'creates a keyword' do
|
||||
filter = user.account.custom_filters.first
|
||||
expect(filter).to_not be_nil
|
||||
expect(filter.keywords.pluck(:keyword)).to eq ['magic']
|
||||
|
@ -73,11 +69,9 @@ RSpec.describe Api::V2::Filters::KeywordsController do
|
|||
get :show, params: { id: keyword.id }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'responds with the keyword', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns expected data' do
|
||||
json = body_as_json
|
||||
expect(json[:keyword]).to eq 'foo'
|
||||
expect(json[:whole_word]).to be false
|
||||
|
@ -100,11 +94,9 @@ RSpec.describe Api::V2::Filters::KeywordsController do
|
|||
get :update, params: { id: keyword.id, keyword: 'updated' }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'updates the keyword', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'updates the keyword' do
|
||||
expect(keyword.reload.keyword).to eq 'updated'
|
||||
end
|
||||
|
||||
|
@ -125,11 +117,9 @@ RSpec.describe Api::V2::Filters::KeywordsController do
|
|||
delete :destroy, params: { id: keyword.id }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'destroys the keyword', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'removes the filter' do
|
||||
expect { keyword.reload }.to raise_error ActiveRecord::RecordNotFound
|
||||
end
|
||||
|
||||
|
|
|
@ -41,16 +41,12 @@ RSpec.describe Api::V2::Filters::StatusesController do
|
|||
post :create, params: { filter_id: filter_id, status_id: status.id }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'creates a filter', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns a status filter' do
|
||||
json = body_as_json
|
||||
expect(json[:status_id]).to eq status.id.to_s
|
||||
end
|
||||
|
||||
it 'creates a status filter' do
|
||||
filter = user.account.custom_filters.first
|
||||
expect(filter).to_not be_nil
|
||||
expect(filter.statuses.pluck(:status_id)).to eq [status.id]
|
||||
|
@ -73,11 +69,9 @@ RSpec.describe Api::V2::Filters::StatusesController do
|
|||
get :show, params: { id: status_filter.id }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'responds with the filter', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns expected data' do
|
||||
json = body_as_json
|
||||
expect(json[:status_id]).to eq status_filter.status_id.to_s
|
||||
end
|
||||
|
@ -99,11 +93,9 @@ RSpec.describe Api::V2::Filters::StatusesController do
|
|||
delete :destroy, params: { id: status_filter.id }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
it 'destroys the filter', :aggregate_failures do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'removes the filter' do
|
||||
expect { status_filter.reload }.to raise_error ActiveRecord::RecordNotFound
|
||||
end
|
||||
|
||||
|
|
391
spec/fixtures/requests/json-ld.activitystreams.txt
vendored
391
spec/fixtures/requests/json-ld.activitystreams.txt
vendored
|
@ -1,391 +0,0 @@
|
|||
HTTP/1.1 200 OK
|
||||
Date: Tue, 01 May 2018 23:25:57 GMT
|
||||
Content-Location: activitystreams.jsonld
|
||||
Vary: negotiate,accept
|
||||
TCN: choice
|
||||
Last-Modified: Mon, 16 Apr 2018 00:28:23 GMT
|
||||
ETag: "1eb0-569ec4caa97c0;d3-540ee27e0eec0"
|
||||
Accept-Ranges: bytes
|
||||
Content-Length: 7856
|
||||
Cache-Control: max-age=21600
|
||||
Expires: Wed, 02 May 2018 05:25:57 GMT
|
||||
P3P: policyref="http://www.w3.org/2014/08/p3p.xml"
|
||||
Access-Control-Allow-Origin: *
|
||||
Content-Type: application/ld+json
|
||||
Strict-Transport-Security: max-age=15552000; includeSubdomains; preload
|
||||
Content-Security-Policy: upgrade-insecure-requests
|
||||
|
||||
{
|
||||
"@context": {
|
||||
"@vocab": "_:",
|
||||
"xsd": "http://www.w3.org/2001/XMLSchema#",
|
||||
"as": "https://www.w3.org/ns/activitystreams#",
|
||||
"ldp": "http://www.w3.org/ns/ldp#",
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
"Accept": "as:Accept",
|
||||
"Activity": "as:Activity",
|
||||
"IntransitiveActivity": "as:IntransitiveActivity",
|
||||
"Add": "as:Add",
|
||||
"Announce": "as:Announce",
|
||||
"Application": "as:Application",
|
||||
"Arrive": "as:Arrive",
|
||||
"Article": "as:Article",
|
||||
"Audio": "as:Audio",
|
||||
"Block": "as:Block",
|
||||
"Collection": "as:Collection",
|
||||
"CollectionPage": "as:CollectionPage",
|
||||
"Relationship": "as:Relationship",
|
||||
"Create": "as:Create",
|
||||
"Delete": "as:Delete",
|
||||
"Dislike": "as:Dislike",
|
||||
"Document": "as:Document",
|
||||
"Event": "as:Event",
|
||||
"Follow": "as:Follow",
|
||||
"Flag": "as:Flag",
|
||||
"Group": "as:Group",
|
||||
"Ignore": "as:Ignore",
|
||||
"Image": "as:Image",
|
||||
"Invite": "as:Invite",
|
||||
"Join": "as:Join",
|
||||
"Leave": "as:Leave",
|
||||
"Like": "as:Like",
|
||||
"Link": "as:Link",
|
||||
"Mention": "as:Mention",
|
||||
"Note": "as:Note",
|
||||
"Object": "as:Object",
|
||||
"Offer": "as:Offer",
|
||||
"OrderedCollection": "as:OrderedCollection",
|
||||
"OrderedCollectionPage": "as:OrderedCollectionPage",
|
||||
"Organization": "as:Organization",
|
||||
"Page": "as:Page",
|
||||
"Person": "as:Person",
|
||||
"Place": "as:Place",
|
||||
"Profile": "as:Profile",
|
||||
"Question": "as:Question",
|
||||
"Reject": "as:Reject",
|
||||
"Remove": "as:Remove",
|
||||
"Service": "as:Service",
|
||||
"TentativeAccept": "as:TentativeAccept",
|
||||
"TentativeReject": "as:TentativeReject",
|
||||
"Tombstone": "as:Tombstone",
|
||||
"Undo": "as:Undo",
|
||||
"Update": "as:Update",
|
||||
"Video": "as:Video",
|
||||
"View": "as:View",
|
||||
"Listen": "as:Listen",
|
||||
"Read": "as:Read",
|
||||
"Move": "as:Move",
|
||||
"Travel": "as:Travel",
|
||||
"IsFollowing": "as:IsFollowing",
|
||||
"IsFollowedBy": "as:IsFollowedBy",
|
||||
"IsContact": "as:IsContact",
|
||||
"IsMember": "as:IsMember",
|
||||
"subject": {
|
||||
"@id": "as:subject",
|
||||
"@type": "@id"
|
||||
},
|
||||
"relationship": {
|
||||
"@id": "as:relationship",
|
||||
"@type": "@id"
|
||||
},
|
||||
"actor": {
|
||||
"@id": "as:actor",
|
||||
"@type": "@id"
|
||||
},
|
||||
"attributedTo": {
|
||||
"@id": "as:attributedTo",
|
||||
"@type": "@id"
|
||||
},
|
||||
"attachment": {
|
||||
"@id": "as:attachment",
|
||||
"@type": "@id"
|
||||
},
|
||||
"bcc": {
|
||||
"@id": "as:bcc",
|
||||
"@type": "@id"
|
||||
},
|
||||
"bto": {
|
||||
"@id": "as:bto",
|
||||
"@type": "@id"
|
||||
},
|
||||
"cc": {
|
||||
"@id": "as:cc",
|
||||
"@type": "@id"
|
||||
},
|
||||
"context": {
|
||||
"@id": "as:context",
|
||||
"@type": "@id"
|
||||
},
|
||||
"current": {
|
||||
"@id": "as:current",
|
||||
"@type": "@id"
|
||||
},
|
||||
"first": {
|
||||
"@id": "as:first",
|
||||
"@type": "@id"
|
||||
},
|
||||
"generator": {
|
||||
"@id": "as:generator",
|
||||
"@type": "@id"
|
||||
},
|
||||
"icon": {
|
||||
"@id": "as:icon",
|
||||
"@type": "@id"
|
||||
},
|
||||
"image": {
|
||||
"@id": "as:image",
|
||||
"@type": "@id"
|
||||
},
|
||||
"inReplyTo": {
|
||||
"@id": "as:inReplyTo",
|
||||
"@type": "@id"
|
||||
},
|
||||
"items": {
|
||||
"@id": "as:items",
|
||||
"@type": "@id"
|
||||
},
|
||||
"instrument": {
|
||||
"@id": "as:instrument",
|
||||
"@type": "@id"
|
||||
},
|
||||
"orderedItems": {
|
||||
"@id": "as:items",
|
||||
"@type": "@id",
|
||||
"@container": "@list"
|
||||
},
|
||||
"last": {
|
||||
"@id": "as:last",
|
||||
"@type": "@id"
|
||||
},
|
||||
"location": {
|
||||
"@id": "as:location",
|
||||
"@type": "@id"
|
||||
},
|
||||
"next": {
|
||||
"@id": "as:next",
|
||||
"@type": "@id"
|
||||
},
|
||||
"object": {
|
||||
"@id": "as:object",
|
||||
"@type": "@id"
|
||||
},
|
||||
"oneOf": {
|
||||
"@id": "as:oneOf",
|
||||
"@type": "@id"
|
||||
},
|
||||
"anyOf": {
|
||||
"@id": "as:anyOf",
|
||||
"@type": "@id"
|
||||
},
|
||||
"closed": {
|
||||
"@id": "as:closed",
|
||||
"@type": "xsd:dateTime"
|
||||
},
|
||||
"origin": {
|
||||
"@id": "as:origin",
|
||||
"@type": "@id"
|
||||
},
|
||||
"accuracy": {
|
||||
"@id": "as:accuracy",
|
||||
"@type": "xsd:float"
|
||||
},
|
||||
"prev": {
|
||||
"@id": "as:prev",
|
||||
"@type": "@id"
|
||||
},
|
||||
"preview": {
|
||||
"@id": "as:preview",
|
||||
"@type": "@id"
|
||||
},
|
||||
"replies": {
|
||||
"@id": "as:replies",
|
||||
"@type": "@id"
|
||||
},
|
||||
"result": {
|
||||
"@id": "as:result",
|
||||
"@type": "@id"
|
||||
},
|
||||
"audience": {
|
||||
"@id": "as:audience",
|
||||
"@type": "@id"
|
||||
},
|
||||
"partOf": {
|
||||
"@id": "as:partOf",
|
||||
"@type": "@id"
|
||||
},
|
||||
"tag": {
|
||||
"@id": "as:tag",
|
||||
"@type": "@id"
|
||||
},
|
||||
"target": {
|
||||
"@id": "as:target",
|
||||
"@type": "@id"
|
||||
},
|
||||
"to": {
|
||||
"@id": "as:to",
|
||||
"@type": "@id"
|
||||
},
|
||||
"url": {
|
||||
"@id": "as:url",
|
||||
"@type": "@id"
|
||||
},
|
||||
"altitude": {
|
||||
"@id": "as:altitude",
|
||||
"@type": "xsd:float"
|
||||
},
|
||||
"content": "as:content",
|
||||
"contentMap": {
|
||||
"@id": "as:content",
|
||||
"@container": "@language"
|
||||
},
|
||||
"name": "as:name",
|
||||
"nameMap": {
|
||||
"@id": "as:name",
|
||||
"@container": "@language"
|
||||
},
|
||||
"duration": {
|
||||
"@id": "as:duration",
|
||||
"@type": "xsd:duration"
|
||||
},
|
||||
"endTime": {
|
||||
"@id": "as:endTime",
|
||||
"@type": "xsd:dateTime"
|
||||
},
|
||||
"height": {
|
||||
"@id": "as:height",
|
||||
"@type": "xsd:nonNegativeInteger"
|
||||
},
|
||||
"href": {
|
||||
"@id": "as:href",
|
||||
"@type": "@id"
|
||||
},
|
||||
"hreflang": "as:hreflang",
|
||||
"latitude": {
|
||||
"@id": "as:latitude",
|
||||
"@type": "xsd:float"
|
||||
},
|
||||
"longitude": {
|
||||
"@id": "as:longitude",
|
||||
"@type": "xsd:float"
|
||||
},
|
||||
"mediaType": "as:mediaType",
|
||||
"published": {
|
||||
"@id": "as:published",
|
||||
"@type": "xsd:dateTime"
|
||||
},
|
||||
"radius": {
|
||||
"@id": "as:radius",
|
||||
"@type": "xsd:float"
|
||||
},
|
||||
"rel": "as:rel",
|
||||
"startIndex": {
|
||||
"@id": "as:startIndex",
|
||||
"@type": "xsd:nonNegativeInteger"
|
||||
},
|
||||
"startTime": {
|
||||
"@id": "as:startTime",
|
||||
"@type": "xsd:dateTime"
|
||||
},
|
||||
"summary": "as:summary",
|
||||
"summaryMap": {
|
||||
"@id": "as:summary",
|
||||
"@container": "@language"
|
||||
},
|
||||
"totalItems": {
|
||||
"@id": "as:totalItems",
|
||||
"@type": "xsd:nonNegativeInteger"
|
||||
},
|
||||
"units": "as:units",
|
||||
"updated": {
|
||||
"@id": "as:updated",
|
||||
"@type": "xsd:dateTime"
|
||||
},
|
||||
"width": {
|
||||
"@id": "as:width",
|
||||
"@type": "xsd:nonNegativeInteger"
|
||||
},
|
||||
"describes": {
|
||||
"@id": "as:describes",
|
||||
"@type": "@id"
|
||||
},
|
||||
"formerType": {
|
||||
"@id": "as:formerType",
|
||||
"@type": "@id"
|
||||
},
|
||||
"deleted": {
|
||||
"@id": "as:deleted",
|
||||
"@type": "xsd:dateTime"
|
||||
},
|
||||
"inbox": {
|
||||
"@id": "ldp:inbox",
|
||||
"@type": "@id"
|
||||
},
|
||||
"outbox": {
|
||||
"@id": "as:outbox",
|
||||
"@type": "@id"
|
||||
},
|
||||
"following": {
|
||||
"@id": "as:following",
|
||||
"@type": "@id"
|
||||
},
|
||||
"followers": {
|
||||
"@id": "as:followers",
|
||||
"@type": "@id"
|
||||
},
|
||||
"streams": {
|
||||
"@id": "as:streams",
|
||||
"@type": "@id"
|
||||
},
|
||||
"preferredUsername": "as:preferredUsername",
|
||||
"endpoints": {
|
||||
"@id": "as:endpoints",
|
||||
"@type": "@id"
|
||||
},
|
||||
"uploadMedia": {
|
||||
"@id": "as:uploadMedia",
|
||||
"@type": "@id"
|
||||
},
|
||||
"proxyUrl": {
|
||||
"@id": "as:proxyUrl",
|
||||
"@type": "@id"
|
||||
},
|
||||
"liked": {
|
||||
"@id": "as:liked",
|
||||
"@type": "@id"
|
||||
},
|
||||
"oauthAuthorizationEndpoint": {
|
||||
"@id": "as:oauthAuthorizationEndpoint",
|
||||
"@type": "@id"
|
||||
},
|
||||
"oauthTokenEndpoint": {
|
||||
"@id": "as:oauthTokenEndpoint",
|
||||
"@type": "@id"
|
||||
},
|
||||
"provideClientKey": {
|
||||
"@id": "as:provideClientKey",
|
||||
"@type": "@id"
|
||||
},
|
||||
"signClientKey": {
|
||||
"@id": "as:signClientKey",
|
||||
"@type": "@id"
|
||||
},
|
||||
"sharedInbox": {
|
||||
"@id": "as:sharedInbox",
|
||||
"@type": "@id"
|
||||
},
|
||||
"Public": {
|
||||
"@id": "as:Public",
|
||||
"@type": "@id"
|
||||
},
|
||||
"source": "as:source",
|
||||
"likes": {
|
||||
"@id": "as:likes",
|
||||
"@type": "@id"
|
||||
},
|
||||
"shares": {
|
||||
"@id": "as:shares",
|
||||
"@type": "@id"
|
||||
}
|
||||
}
|
||||
}
|
100
spec/fixtures/requests/json-ld.identity.txt
vendored
100
spec/fixtures/requests/json-ld.identity.txt
vendored
|
@ -1,100 +0,0 @@
|
|||
HTTP/1.1 200 OK
|
||||
Accept-Ranges: bytes
|
||||
Access-Control-Allow-Headers: DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Accept-Encoding
|
||||
Access-Control-Allow-Origin: *
|
||||
Content-Type: application/ld+json
|
||||
Date: Tue, 01 May 2018 23:28:21 GMT
|
||||
Etag: "e26-547a6fc75b04a-gzip"
|
||||
Last-Modified: Fri, 03 Feb 2017 21:30:09 GMT
|
||||
Server: Apache/2.4.7 (Ubuntu)
|
||||
Vary: Accept-Encoding
|
||||
Transfer-Encoding: chunked
|
||||
|
||||
{
|
||||
"@context": {
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
|
||||
"cred": "https://w3id.org/credentials#",
|
||||
"dc": "http://purl.org/dc/terms/",
|
||||
"identity": "https://w3id.org/identity#",
|
||||
"perm": "https://w3id.org/permissions#",
|
||||
"ps": "https://w3id.org/payswarm#",
|
||||
"rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
|
||||
"rdfs": "http://www.w3.org/2000/01/rdf-schema#",
|
||||
"sec": "https://w3id.org/security#",
|
||||
"schema": "http://schema.org/",
|
||||
"xsd": "http://www.w3.org/2001/XMLSchema#",
|
||||
|
||||
"Group": "https://www.w3.org/ns/activitystreams#Group",
|
||||
|
||||
"claim": {"@id": "cred:claim", "@type": "@id"},
|
||||
"credential": {"@id": "cred:credential", "@type": "@id"},
|
||||
"issued": {"@id": "cred:issued", "@type": "xsd:dateTime"},
|
||||
"issuer": {"@id": "cred:issuer", "@type": "@id"},
|
||||
"recipient": {"@id": "cred:recipient", "@type": "@id"},
|
||||
"Credential": "cred:Credential",
|
||||
"CryptographicKeyCredential": "cred:CryptographicKeyCredential",
|
||||
|
||||
"about": {"@id": "schema:about", "@type": "@id"},
|
||||
"address": {"@id": "schema:address", "@type": "@id"},
|
||||
"addressCountry": "schema:addressCountry",
|
||||
"addressLocality": "schema:addressLocality",
|
||||
"addressRegion": "schema:addressRegion",
|
||||
"comment": "rdfs:comment",
|
||||
"created": {"@id": "dc:created", "@type": "xsd:dateTime"},
|
||||
"creator": {"@id": "dc:creator", "@type": "@id"},
|
||||
"description": "schema:description",
|
||||
"email": "schema:email",
|
||||
"familyName": "schema:familyName",
|
||||
"givenName": "schema:givenName",
|
||||
"image": {"@id": "schema:image", "@type": "@id"},
|
||||
"label": "rdfs:label",
|
||||
"name": "schema:name",
|
||||
"postalCode": "schema:postalCode",
|
||||
"streetAddress": "schema:streetAddress",
|
||||
"title": "dc:title",
|
||||
"url": {"@id": "schema:url", "@type": "@id"},
|
||||
"Person": "schema:Person",
|
||||
"PostalAddress": "schema:PostalAddress",
|
||||
"Organization": "schema:Organization",
|
||||
|
||||
"identityService": {"@id": "identity:identityService", "@type": "@id"},
|
||||
"idp": {"@id": "identity:idp", "@type": "@id"},
|
||||
"Identity": "identity:Identity",
|
||||
|
||||
"paymentProcessor": "ps:processor",
|
||||
"preferences": {"@id": "ps:preferences", "@type": "@vocab"},
|
||||
|
||||
"cipherAlgorithm": "sec:cipherAlgorithm",
|
||||
"cipherData": "sec:cipherData",
|
||||
"cipherKey": "sec:cipherKey",
|
||||
"digestAlgorithm": "sec:digestAlgorithm",
|
||||
"digestValue": "sec:digestValue",
|
||||
"domain": "sec:domain",
|
||||
"expires": {"@id": "sec:expiration", "@type": "xsd:dateTime"},
|
||||
"initializationVector": "sec:initializationVector",
|
||||
"member": {"@id": "schema:member", "@type": "@id"},
|
||||
"memberOf": {"@id": "schema:memberOf", "@type": "@id"},
|
||||
"nonce": "sec:nonce",
|
||||
"normalizationAlgorithm": "sec:normalizationAlgorithm",
|
||||
"owner": {"@id": "sec:owner", "@type": "@id"},
|
||||
"password": "sec:password",
|
||||
"privateKey": {"@id": "sec:privateKey", "@type": "@id"},
|
||||
"privateKeyPem": "sec:privateKeyPem",
|
||||
"publicKey": {"@id": "sec:publicKey", "@type": "@id"},
|
||||
"publicKeyPem": "sec:publicKeyPem",
|
||||
"publicKeyService": {"@id": "sec:publicKeyService", "@type": "@id"},
|
||||
"revoked": {"@id": "sec:revoked", "@type": "xsd:dateTime"},
|
||||
"signature": "sec:signature",
|
||||
"signatureAlgorithm": "sec:signatureAlgorithm",
|
||||
"signatureValue": "sec:signatureValue",
|
||||
"CryptographicKey": "sec:Key",
|
||||
"EncryptedMessage": "sec:EncryptedMessage",
|
||||
"GraphSignature2012": "sec:GraphSignature2012",
|
||||
"LinkedDataSignature2015": "sec:LinkedDataSignature2015",
|
||||
|
||||
"accessControl": {"@id": "perm:accessControl", "@type": "@id"},
|
||||
"writePermission": {"@id": "perm:writePermission", "@type": "@id"}
|
||||
}
|
||||
}
|
61
spec/fixtures/requests/json-ld.security.txt
vendored
61
spec/fixtures/requests/json-ld.security.txt
vendored
|
@ -1,61 +0,0 @@
|
|||
HTTP/1.1 200 OK
|
||||
Accept-Ranges: bytes
|
||||
Access-Control-Allow-Headers: DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Accept-Encoding
|
||||
Access-Control-Allow-Origin: *
|
||||
Content-Type: application/ld+json
|
||||
Date: Wed, 02 May 2018 16:25:32 GMT
|
||||
Etag: "7e3-5651ec0f7c5ed-gzip"
|
||||
Last-Modified: Tue, 13 Feb 2018 21:34:04 GMT
|
||||
Server: Apache/2.4.7 (Ubuntu)
|
||||
Vary: Accept-Encoding
|
||||
Content-Length: 2019
|
||||
|
||||
{
|
||||
"@context": {
|
||||
"id": "@id",
|
||||
"type": "@type",
|
||||
|
||||
"dc": "http://purl.org/dc/terms/",
|
||||
"sec": "https://w3id.org/security#",
|
||||
"xsd": "http://www.w3.org/2001/XMLSchema#",
|
||||
|
||||
"EcdsaKoblitzSignature2016": "sec:EcdsaKoblitzSignature2016",
|
||||
"Ed25519Signature2018": "sec:Ed25519Signature2018",
|
||||
"EncryptedMessage": "sec:EncryptedMessage",
|
||||
"GraphSignature2012": "sec:GraphSignature2012",
|
||||
"LinkedDataSignature2015": "sec:LinkedDataSignature2015",
|
||||
"LinkedDataSignature2016": "sec:LinkedDataSignature2016",
|
||||
"CryptographicKey": "sec:Key",
|
||||
|
||||
"authenticationTag": "sec:authenticationTag",
|
||||
"canonicalizationAlgorithm": "sec:canonicalizationAlgorithm",
|
||||
"cipherAlgorithm": "sec:cipherAlgorithm",
|
||||
"cipherData": "sec:cipherData",
|
||||
"cipherKey": "sec:cipherKey",
|
||||
"created": {"@id": "dc:created", "@type": "xsd:dateTime"},
|
||||
"creator": {"@id": "dc:creator", "@type": "@id"},
|
||||
"digestAlgorithm": "sec:digestAlgorithm",
|
||||
"digestValue": "sec:digestValue",
|
||||
"domain": "sec:domain",
|
||||
"encryptionKey": "sec:encryptionKey",
|
||||
"expiration": {"@id": "sec:expiration", "@type": "xsd:dateTime"},
|
||||
"expires": {"@id": "sec:expiration", "@type": "xsd:dateTime"},
|
||||
"initializationVector": "sec:initializationVector",
|
||||
"iterationCount": "sec:iterationCount",
|
||||
"nonce": "sec:nonce",
|
||||
"normalizationAlgorithm": "sec:normalizationAlgorithm",
|
||||
"owner": {"@id": "sec:owner", "@type": "@id"},
|
||||
"password": "sec:password",
|
||||
"privateKey": {"@id": "sec:privateKey", "@type": "@id"},
|
||||
"privateKeyPem": "sec:privateKeyPem",
|
||||
"publicKey": {"@id": "sec:publicKey", "@type": "@id"},
|
||||
"publicKeyBase58": "sec:publicKeyBase58",
|
||||
"publicKeyPem": "sec:publicKeyPem",
|
||||
"publicKeyService": {"@id": "sec:publicKeyService", "@type": "@id"},
|
||||
"revoked": {"@id": "sec:revoked", "@type": "xsd:dateTime"},
|
||||
"salt": "sec:salt",
|
||||
"signature": "sec:signature",
|
||||
"signatureAlgorithm": "sec:signingAlgorithm",
|
||||
"signatureValue": "sec:signatureValue"
|
||||
}
|
||||
}
|
|
@ -18,10 +18,6 @@ RSpec.describe ActivityPub::LinkedDataSignature do
|
|||
|
||||
let(:json) { raw_json.merge('signature' => signature) }
|
||||
|
||||
before do
|
||||
stub_jsonld_contexts!
|
||||
end
|
||||
|
||||
describe '#verify_actor!' do
|
||||
context 'when signature matches' do
|
||||
let(:raw_signature) do
|
||||
|
|
|
@ -82,6 +82,10 @@ RSpec.describe LinkDetailsExtractor do
|
|||
'name' => 'Pet News',
|
||||
'url' => 'https://example.com',
|
||||
},
|
||||
'inLanguage' => {
|
||||
name: 'English',
|
||||
alternateName: 'en',
|
||||
},
|
||||
}.to_json
|
||||
end
|
||||
|
||||
|
@ -115,6 +119,12 @@ RSpec.describe LinkDetailsExtractor do
|
|||
expect(subject.provider_name).to eq 'Pet News'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#language' do
|
||||
it 'returns the language from structured data' do
|
||||
expect(subject.language).to eq 'en'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when is wrapped in CDATA tags' do
|
||||
|
|
|
@ -4,9 +4,31 @@ require 'rails_helper'
|
|||
require 'mastodon/cli/statuses'
|
||||
|
||||
describe Mastodon::CLI::Statuses do
|
||||
let(:cli) { described_class.new }
|
||||
|
||||
describe '.exit_on_failure?' do
|
||||
it 'returns true' do
|
||||
expect(described_class.exit_on_failure?).to be true
|
||||
end
|
||||
end
|
||||
|
||||
describe '#remove', use_transactional_tests: false do
|
||||
context 'with small batch size' do
|
||||
let(:options) { { batch_size: 0 } }
|
||||
|
||||
it 'exits with error message' do
|
||||
expect { cli.invoke :remove, [], options }.to output(
|
||||
a_string_including('Cannot run')
|
||||
).to_stdout.and raise_error(SystemExit)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with default batch size' do
|
||||
it 'removes unreferenced statuses' do
|
||||
expect { cli.invoke :remove }.to output(
|
||||
a_string_including('Done after')
|
||||
).to_stdout
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -54,26 +54,6 @@ Devise::Test::ControllerHelpers.module_eval do
|
|||
end
|
||||
end
|
||||
|
||||
module SignedRequestHelpers
|
||||
def get(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'] = ENV.fetch('LOCAL_DOMAIN')
|
||||
signed_headers = headers.merge('(request-target)' => "get #{path}").slice('(request-target)', 'Host', 'Date')
|
||||
|
||||
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
|
||||
|
||||
RSpec.configure do |config|
|
||||
# This is set before running spec:system, see lib/tasks/tests.rake
|
||||
config.filter_run_excluding type: lambda { |type|
|
||||
|
@ -105,6 +85,12 @@ RSpec.configure do |config|
|
|||
config.include Redisable
|
||||
config.include SignedRequestHelpers, type: :request
|
||||
|
||||
config.around(:each, use_transactional_tests: false) do |example|
|
||||
self.use_transactional_tests = false
|
||||
example.run
|
||||
self.use_transactional_tests = true
|
||||
end
|
||||
|
||||
config.before :each, type: :cli do
|
||||
stub_stdout
|
||||
stub_reset_connection_pools
|
||||
|
@ -114,14 +100,6 @@ RSpec.configure do |config|
|
|||
Capybara.current_driver = :rack_test
|
||||
end
|
||||
|
||||
config.before :each, type: :controller do
|
||||
stub_jsonld_contexts!
|
||||
end
|
||||
|
||||
config.before :each, type: :service do
|
||||
stub_jsonld_contexts!
|
||||
end
|
||||
|
||||
config.before :suite do
|
||||
if RUN_SYSTEM_SPECS
|
||||
Webpacker.compile
|
||||
|
@ -212,9 +190,3 @@ def stub_reset_connection_pools
|
|||
allow(ActiveRecord::Base).to receive(:establish_connection)
|
||||
allow(RedisConfiguration).to receive(:establish_pool)
|
||||
end
|
||||
|
||||
def stub_jsonld_contexts!
|
||||
stub_request(:get, 'https://www.w3.org/ns/activitystreams').to_return(request_fixture('json-ld.activitystreams.txt'))
|
||||
stub_request(:get, 'https://w3id.org/identity/v1').to_return(request_fixture('json-ld.identity.txt'))
|
||||
stub_request(:get, 'https://w3id.org/security/v1').to_return(request_fixture('json-ld.security.txt'))
|
||||
end
|
||||
|
|
|
@ -51,14 +51,9 @@ RSpec.describe 'Account actions' do
|
|||
it_behaves_like 'a successful notification delivery'
|
||||
it_behaves_like 'a successful logged action', :disable, :user
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'disables the target account' do
|
||||
expect { subject }.to change { target_account.reload.user_disabled? }.from(false).to(true)
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -70,14 +65,9 @@ RSpec.describe 'Account actions' do
|
|||
it_behaves_like 'a successful notification delivery'
|
||||
it_behaves_like 'a successful logged action', :sensitive, :account
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'marks the target account as sensitive' do
|
||||
expect { subject }.to change { target_account.reload.sensitized? }.from(false).to(true)
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -89,14 +79,9 @@ RSpec.describe 'Account actions' do
|
|||
it_behaves_like 'a successful notification delivery'
|
||||
it_behaves_like 'a successful logged action', :silence, :account
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'marks the target account as silenced' do
|
||||
expect { subject }.to change { target_account.reload.silenced? }.from(false).to(true)
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -108,14 +93,9 @@ RSpec.describe 'Account actions' do
|
|||
it_behaves_like 'a successful notification delivery'
|
||||
it_behaves_like 'a successful logged action', :suspend, :account
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'marks the target account as suspended' do
|
||||
expect { subject }.to change { target_account.reload.suspended? }.from(false).to(true)
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
401
spec/requests/api/v1/admin/accounts_spec.rb
Normal file
401
spec/requests/api/v1/admin/accounts_spec.rb
Normal file
|
@ -0,0 +1,401 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Accounts' do
|
||||
let(:role) { UserRole.find_by(name: 'Admin') }
|
||||
let(:user) { Fabricate(:user, role: role) }
|
||||
let(:scopes) { 'admin:read:accounts admin:write:accounts' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
describe 'GET /api/v1/admin/accounts' do
|
||||
subject do
|
||||
get '/api/v1/admin/accounts', headers: headers, params: params
|
||||
end
|
||||
|
||||
shared_examples 'a successful request' do
|
||||
it 'returns the correct accounts', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(body_as_json.pluck(:id)).to match_array(expected_results.map { |a| a.id.to_s })
|
||||
end
|
||||
end
|
||||
|
||||
let!(:remote_account) { Fabricate(:account, domain: 'example.org') }
|
||||
let!(:suspended_account) { Fabricate(:account, suspended: true) }
|
||||
let!(:disabled_account) { Fabricate(:user, disabled: true).account }
|
||||
let!(:pending_account) { Fabricate(:user, approved: false).account }
|
||||
let!(:admin_account) { user.account }
|
||||
let(:params) { {} }
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read read:accounts admin:write admin:write:accounts'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
context 'when requesting active local staff accounts' do
|
||||
let(:expected_results) { [admin_account] }
|
||||
let(:params) { { active: 'true', local: 'true', staff: 'true' } }
|
||||
|
||||
it_behaves_like 'a successful request'
|
||||
end
|
||||
|
||||
context 'when requesting remote accounts from a specified domain' do
|
||||
let(:expected_results) { [remote_account] }
|
||||
let(:params) { { by_domain: 'example.org', remote: 'true' } }
|
||||
|
||||
before do
|
||||
Fabricate(:account, domain: 'foo.bar')
|
||||
end
|
||||
|
||||
it_behaves_like 'a successful request'
|
||||
end
|
||||
|
||||
context 'when requesting suspended accounts' do
|
||||
let(:expected_results) { [suspended_account] }
|
||||
let(:params) { { suspended: 'true' } }
|
||||
|
||||
before do
|
||||
Fabricate(:account, domain: 'foo.bar', suspended: true)
|
||||
end
|
||||
|
||||
it_behaves_like 'a successful request'
|
||||
end
|
||||
|
||||
context 'when requesting disabled accounts' do
|
||||
let(:expected_results) { [disabled_account] }
|
||||
let(:params) { { disabled: 'true' } }
|
||||
|
||||
it_behaves_like 'a successful request'
|
||||
end
|
||||
|
||||
context 'when requesting pending accounts' do
|
||||
let(:expected_results) { [pending_account] }
|
||||
let(:params) { { pending: 'true' } }
|
||||
|
||||
before do
|
||||
pending_account.user.update(approved: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'a successful request'
|
||||
end
|
||||
|
||||
context 'when no parameter is given' do
|
||||
let(:expected_results) { [disabled_account, pending_account, admin_account] }
|
||||
|
||||
it_behaves_like 'a successful request'
|
||||
end
|
||||
|
||||
context 'with limit param' do
|
||||
let(:params) { { limit: 2 } }
|
||||
|
||||
it 'returns only the requested number of accounts', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(body_as_json.size).to eq(params[:limit])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v1/admin/accounts/:id' do
|
||||
subject do
|
||||
get "/api/v1/admin/accounts/#{account.id}", headers: headers
|
||||
end
|
||||
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read read:accounts admin:write admin:write:accounts'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'returns the requested account successfully', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(body_as_json).to match(
|
||||
a_hash_including(id: account.id.to_s, username: account.username, email: account.user.email)
|
||||
)
|
||||
end
|
||||
|
||||
context 'when the account is not found' do
|
||||
it 'returns http not found' do
|
||||
get '/api/v1/admin/accounts/-1', headers: headers
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v1/admin/accounts/:id/approve' do
|
||||
subject do
|
||||
post "/api/v1/admin/accounts/#{account.id}/approve", headers: headers
|
||||
end
|
||||
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
||||
context 'when the account is pending' do
|
||||
before do
|
||||
account.user.update(approved: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:accounts read admin:read'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'approves the user successfully', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(account.reload.user_approved?).to be(true)
|
||||
end
|
||||
|
||||
it 'logs action', :aggregate_failures do
|
||||
subject
|
||||
|
||||
log_item = Admin::ActionLog.last
|
||||
|
||||
expect(log_item).to be_present
|
||||
expect(log_item.action).to eq :approve
|
||||
expect(log_item.account_id).to eq user.account_id
|
||||
expect(log_item.target_id).to eq account.user.id
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the account is already approved' do
|
||||
it 'returns http forbidden' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the account is not found' do
|
||||
it 'returns http not found' do
|
||||
post '/api/v1/admin/accounts/-1/approve', headers: headers
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v1/admin/accounts/:id/reject' do
|
||||
subject do
|
||||
post "/api/v1/admin/accounts/#{account.id}/reject", headers: headers
|
||||
end
|
||||
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
||||
context 'when the account is pending' do
|
||||
before do
|
||||
account.user.update(approved: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:accounts read admin:read'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'removes the user successfully', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(User.where(id: account.user.id)).to_not exist
|
||||
end
|
||||
|
||||
it 'logs action', :aggregate_failures do
|
||||
subject
|
||||
|
||||
log_item = Admin::ActionLog.last
|
||||
|
||||
expect(log_item).to be_present
|
||||
expect(log_item.action).to eq :reject
|
||||
expect(log_item.account_id).to eq user.account_id
|
||||
expect(log_item.target_id).to eq account.user.id
|
||||
end
|
||||
end
|
||||
|
||||
context 'when account is already approved' do
|
||||
it 'returns http forbidden' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the account is not found' do
|
||||
it 'returns http not found' do
|
||||
post '/api/v1/admin/accounts/-1/reject', headers: headers
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v1/admin/accounts/:id/enable' do
|
||||
subject do
|
||||
post "/api/v1/admin/accounts/#{account.id}/enable", headers: headers
|
||||
end
|
||||
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
||||
before do
|
||||
account.user.update(disabled: true)
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:accounts read admin:read'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'enables the user successfully', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(account.reload.user_disabled?).to be false
|
||||
end
|
||||
|
||||
context 'when the account is not found' do
|
||||
it 'returns http not found' do
|
||||
post '/api/v1/admin/accounts/-1/enable', headers: headers
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v1/admin/accounts/:id/unsuspend' do
|
||||
subject do
|
||||
post "/api/v1/admin/accounts/#{account.id}/unsuspend", headers: headers
|
||||
end
|
||||
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
||||
context 'when the account is suspended' do
|
||||
before do
|
||||
account.suspend!
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:accounts read admin:read'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'unsuspends the account successfully', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(account.reload.suspended?).to be false
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the account is not suspended' do
|
||||
it 'returns http forbidden' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the account is not found' do
|
||||
it 'returns http not found' do
|
||||
post '/api/v1/admin/accounts/-1/unsuspend', headers: headers
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v1/admin/accounts/:id/unsensitive' do
|
||||
subject do
|
||||
post "/api/v1/admin/accounts/#{account.id}/unsensitive", headers: headers
|
||||
end
|
||||
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
||||
before do
|
||||
account.update(sensitized_at: 10.days.ago)
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:accounts read admin:read'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'unsensitizes the account successfully', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(account.reload.sensitized?).to be false
|
||||
end
|
||||
|
||||
context 'when the account is not found' do
|
||||
it 'returns http not found' do
|
||||
post '/api/v1/admin/accounts/-1/unsensitive', headers: headers
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v1/admin/accounts/:id/unsilence' do
|
||||
subject do
|
||||
post "/api/v1/admin/accounts/#{account.id}/unsilence", headers: headers
|
||||
end
|
||||
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
||||
before do
|
||||
account.update(silenced_at: 3.days.ago)
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:accounts read admin:read'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'unsilences the account successfully', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(account.reload.silenced?).to be false
|
||||
end
|
||||
|
||||
context 'when the account is not found' do
|
||||
it 'returns http not found' do
|
||||
post '/api/v1/admin/accounts/-1/unsilence', headers: headers
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE /api/v1/admin/accounts/:id' do
|
||||
subject do
|
||||
delete "/api/v1/admin/accounts/#{account.id}", headers: headers
|
||||
end
|
||||
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
||||
context 'when account is suspended' do
|
||||
before do
|
||||
account.suspend!
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:accounts read admin:read'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'deletes the account successfully', :aggregate_failures do
|
||||
allow(Admin::AccountDeletionWorker).to receive(:perform_async)
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(Admin::AccountDeletionWorker).to have_received(:perform_async).with(account.id).once
|
||||
end
|
||||
end
|
||||
|
||||
context 'when account is not suspended' do
|
||||
it 'returns http forbidden' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the account is not found' do
|
||||
it 'returns http not found' do
|
||||
delete '/api/v1/admin/accounts/-1', headers: headers
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -92,15 +92,10 @@ RSpec.describe 'Canonical Email Blocks' do
|
|||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
|
||||
context 'when the requested canonical email block exists' do
|
||||
it 'returns http success' do
|
||||
it 'returns the requested canonical email block data correctly', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns the requested canonical email block data correctly' do
|
||||
subject
|
||||
|
||||
json = body_as_json
|
||||
|
||||
expect(json[:id]).to eq(canonical_email_block.id.to_s)
|
||||
|
@ -142,29 +137,19 @@ RSpec.describe 'Canonical Email Blocks' do
|
|||
context 'when there is a matching canonical email block' do
|
||||
let!(:canonical_email_block) { CanonicalEmailBlock.create(params) }
|
||||
|
||||
it 'returns http success' do
|
||||
it 'returns the expected canonical email hash', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns the expected canonical email hash' do
|
||||
subject
|
||||
|
||||
expect(body_as_json[0][:canonical_email_hash]).to eq(canonical_email_block.canonical_email_hash)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there is no matching canonical email block' do
|
||||
it 'returns http success' do
|
||||
it 'returns an empty list', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns an empty list' do
|
||||
subject
|
||||
|
||||
expect(body_as_json).to be_empty
|
||||
end
|
||||
end
|
||||
|
@ -183,15 +168,10 @@ RSpec.describe 'Canonical Email Blocks' do
|
|||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
|
||||
it 'returns http success' do
|
||||
it 'returns the canonical_email_hash correctly', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns the canonical_email_hash correctly' do
|
||||
subject
|
||||
|
||||
expect(body_as_json[:canonical_email_hash]).to eq(canonical_email_block.canonical_email_hash)
|
||||
end
|
||||
|
||||
|
@ -208,15 +188,10 @@ RSpec.describe 'Canonical Email Blocks' do
|
|||
context 'when the canonical_email_hash param is provided instead of email' do
|
||||
let(:params) { { canonical_email_hash: 'dd501ce4e6b08698f19df96f2f15737e48a75660b1fa79b6ff58ea25ee4851a4' } }
|
||||
|
||||
it 'returns http success' do
|
||||
it 'returns the correct canonical_email_hash', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns the correct canonical_email_hash' do
|
||||
subject
|
||||
|
||||
expect(body_as_json[:canonical_email_hash]).to eq(params[:canonical_email_hash])
|
||||
end
|
||||
end
|
||||
|
@ -224,15 +199,10 @@ RSpec.describe 'Canonical Email Blocks' do
|
|||
context 'when both email and canonical_email_hash params are provided' do
|
||||
let(:params) { { email: 'example@email.com', canonical_email_hash: 'dd501ce4e6b08698f19df96f2f15737e48a75660b1fa79b6ff58ea25ee4851a4' } }
|
||||
|
||||
it 'returns http success' do
|
||||
it 'ignores the canonical_email_hash param', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'ignores the canonical_email_hash param' do
|
||||
subject
|
||||
|
||||
expect(body_as_json[:canonical_email_hash]).to eq(canonical_email_block.canonical_email_hash)
|
||||
end
|
||||
end
|
||||
|
@ -262,15 +232,10 @@ RSpec.describe 'Canonical Email Blocks' do
|
|||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
|
||||
it 'returns http success' do
|
||||
it 'deletes the canonical email block', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'deletes the canonical email block' do
|
||||
subject
|
||||
|
||||
expect(CanonicalEmailBlock.find_by(id: canonical_email_block.id)).to be_nil
|
||||
end
|
||||
|
||||
|
|
|
@ -75,15 +75,10 @@ RSpec.describe 'Domain Allows' do
|
|||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
|
||||
it 'returns http success' do
|
||||
it 'returns the expected allowed domain name', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns the expected allowed domain name' do
|
||||
subject
|
||||
|
||||
expect(body_as_json[:domain]).to eq domain_allow.domain
|
||||
end
|
||||
|
||||
|
@ -108,21 +103,11 @@ RSpec.describe 'Domain Allows' do
|
|||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
|
||||
context 'with a valid domain name' do
|
||||
it 'returns http success' do
|
||||
it 'returns the expected domain name', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns the expected domain name' do
|
||||
subject
|
||||
|
||||
expect(body_as_json[:domain]).to eq 'foo.bar.com'
|
||||
end
|
||||
|
||||
it 'creates a domain allow' do
|
||||
subject
|
||||
|
||||
expect(DomainAllow.find_by(domain: 'foo.bar.com')).to be_present
|
||||
end
|
||||
end
|
||||
|
@ -171,15 +156,10 @@ RSpec.describe 'Domain Allows' do
|
|||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
|
||||
it 'returns http success' do
|
||||
it 'deletes the allowed domain', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'deletes the allowed domain' do
|
||||
subject
|
||||
|
||||
expect(DomainAllow.find_by(id: domain_allow.id)).to be_nil
|
||||
end
|
||||
|
||||
|
|
|
@ -89,15 +89,10 @@ RSpec.describe 'Domain Blocks' do
|
|||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
|
||||
it 'returns http success' do
|
||||
it 'returns the expected domain block content', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns the expected domain block content' do
|
||||
subject
|
||||
|
||||
expect(body_as_json).to eq(
|
||||
{
|
||||
id: domain_block.id.to_s,
|
||||
|
@ -133,27 +128,18 @@ RSpec.describe 'Domain Blocks' do
|
|||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns expected domain name and severity' do
|
||||
it 'returns expected domain name and severity', :aggregate_failures do
|
||||
subject
|
||||
|
||||
body = body_as_json
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(body).to match a_hash_including(
|
||||
{
|
||||
domain: 'foo.bar.com',
|
||||
severity: 'silence',
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
it 'creates a domain block' do
|
||||
subject
|
||||
|
||||
expect(DomainBlock.find_by(domain: 'foo.bar.com')).to be_present
|
||||
end
|
||||
|
@ -163,15 +149,10 @@ RSpec.describe 'Domain Blocks' do
|
|||
Fabricate(:domain_block, domain: 'bar.com', severity: :suspend)
|
||||
end
|
||||
|
||||
it 'returns http unprocessable entity' do
|
||||
it 'returns existing domain block in error', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
end
|
||||
|
||||
it 'returns existing domain block in error' do
|
||||
subject
|
||||
|
||||
expect(body_as_json[:existing_domain_block][:domain]).to eq('bar.com')
|
||||
end
|
||||
end
|
||||
|
@ -199,15 +180,10 @@ RSpec.describe 'Domain Blocks' do
|
|||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
|
||||
it 'returns http success' do
|
||||
it 'returns the updated domain block', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns the updated domain block' do
|
||||
subject
|
||||
|
||||
expect(body_as_json).to match a_hash_including(
|
||||
{
|
||||
id: domain_block.id.to_s,
|
||||
|
@ -241,15 +217,10 @@ RSpec.describe 'Domain Blocks' do
|
|||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
|
||||
it 'returns http success' do
|
||||
it 'deletes the domain block', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'deletes the domain block' do
|
||||
subject
|
||||
|
||||
expect(DomainBlock.find_by(id: domain_block.id)).to be_nil
|
||||
end
|
||||
|
||||
|
|
|
@ -93,15 +93,10 @@ RSpec.describe 'Email Domain Blocks' do
|
|||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
|
||||
context 'when email domain block exists' do
|
||||
it 'returns http success' do
|
||||
it 'returns the correct blocked domain', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns the correct blocked domain' do
|
||||
subject
|
||||
|
||||
expect(body_as_json[:domain]).to eq(email_domain_block.domain)
|
||||
end
|
||||
end
|
||||
|
@ -126,15 +121,10 @@ RSpec.describe 'Email Domain Blocks' do
|
|||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
|
||||
it 'returns http success' do
|
||||
it 'returns the correct blocked email domain', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns the correct blocked email domain' do
|
||||
subject
|
||||
|
||||
expect(body_as_json[:domain]).to eq(params[:domain])
|
||||
end
|
||||
|
||||
|
@ -182,21 +172,11 @@ RSpec.describe 'Email Domain Blocks' do
|
|||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
|
||||
it 'returns http success' do
|
||||
it 'deletes email domain block', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns an empty body' do
|
||||
subject
|
||||
|
||||
expect(body_as_json).to be_empty
|
||||
end
|
||||
|
||||
it 'deletes email domain block' do
|
||||
subject
|
||||
|
||||
expect(EmailDomainBlock.find_by(id: email_domain_block.id)).to be_nil
|
||||
end
|
||||
|
||||
|
|
|
@ -84,15 +84,10 @@ RSpec.describe 'IP Blocks' do
|
|||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
|
||||
it 'returns http success' do
|
||||
it 'returns the correct ip block', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns the correct ip block' do
|
||||
subject
|
||||
|
||||
json = body_as_json
|
||||
|
||||
expect(json[:ip]).to eq("#{ip_block.ip}/#{ip_block.ip.prefix}")
|
||||
|
@ -119,15 +114,10 @@ RSpec.describe 'IP Blocks' do
|
|||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
|
||||
it 'returns http success' do
|
||||
it 'returns the correct ip block', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns the correct ip block' do
|
||||
subject
|
||||
|
||||
json = body_as_json
|
||||
|
||||
expect(json[:ip]).to eq("#{params[:ip]}/32")
|
||||
|
@ -186,15 +176,10 @@ RSpec.describe 'IP Blocks' do
|
|||
let!(:ip_block) { IpBlock.create(ip: '185.200.13.3', severity: 'no_access', comment: 'Spam', expires_in: 48.hours) }
|
||||
let(:params) { { severity: 'sign_up_requires_approval', comment: 'Decreasing severity' } }
|
||||
|
||||
it 'returns http success' do
|
||||
it 'returns the correct ip block', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns the correct ip block' do
|
||||
subject
|
||||
|
||||
expect(body_as_json).to match(hash_including({
|
||||
ip: "#{ip_block.ip}/#{ip_block.ip.prefix}",
|
||||
severity: 'sign_up_requires_approval',
|
||||
|
@ -226,21 +211,11 @@ RSpec.describe 'IP Blocks' do
|
|||
|
||||
let!(:ip_block) { IpBlock.create(ip: '185.200.13.3', severity: 'no_access') }
|
||||
|
||||
it 'returns http success' do
|
||||
it 'deletes the ip block', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns an empty body' do
|
||||
subject
|
||||
|
||||
expect(body_as_json).to be_empty
|
||||
end
|
||||
|
||||
it 'deletes the ip block' do
|
||||
subject
|
||||
|
||||
expect(IpBlock.find_by(id: ip_block.id)).to be_nil
|
||||
end
|
||||
|
||||
|
|
|
@ -122,15 +122,10 @@ RSpec.describe 'Reports' do
|
|||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'returns http success' do
|
||||
it 'returns the requested report content', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns the requested report content' do
|
||||
subject
|
||||
|
||||
expect(body_as_json).to include(
|
||||
{
|
||||
id: report.id.to_s,
|
||||
|
@ -155,18 +150,10 @@ RSpec.describe 'Reports' do
|
|||
let!(:report) { Fabricate(:report, category: :other) }
|
||||
let(:params) { { category: 'spam' } }
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
it 'updates the report category', :aggregate_failures do
|
||||
expect { subject }.to change { report.reload.category }.from('other').to('spam')
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'updates the report category' do
|
||||
expect { subject }.to change { report.reload.category }.from('other').to('spam')
|
||||
end
|
||||
|
||||
it 'returns the updated report content' do
|
||||
subject
|
||||
|
||||
report.reload
|
||||
|
||||
|
@ -196,14 +183,9 @@ RSpec.describe 'Reports' do
|
|||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'marks report as resolved' do
|
||||
it 'marks report as resolved', :aggregate_failures do
|
||||
expect { subject }.to change { report.reload.unresolved? }.from(true).to(false)
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -217,14 +199,9 @@ RSpec.describe 'Reports' do
|
|||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'marks report as unresolved' do
|
||||
it 'marks report as unresolved', :aggregate_failures do
|
||||
expect { subject }.to change { report.reload.unresolved? }.from(false).to(true)
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -238,14 +215,9 @@ RSpec.describe 'Reports' do
|
|||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'assigns report to the requesting user' do
|
||||
it 'assigns report to the requesting user', :aggregate_failures do
|
||||
expect { subject }.to change { report.reload.assigned_account_id }.from(nil).to(user.account.id)
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -259,14 +231,9 @@ RSpec.describe 'Reports' do
|
|||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
|
||||
it 'unassigns report from assignee', :aggregate_failures do
|
||||
expect { subject }.to change { report.reload.assigned_account_id }.from(user.account.id).to(nil)
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'unassigns report from assignee' do
|
||||
expect { subject }.to change { report.reload.assigned_account_id }.from(user.account.id).to(nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
129
spec/requests/api/v1/admin/trends/links/links_spec.rb
Normal file
129
spec/requests/api/v1/admin/trends/links/links_spec.rb
Normal file
|
@ -0,0 +1,129 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe 'Links' do
|
||||
let(:role) { UserRole.find_by(name: 'Admin') }
|
||||
let(:user) { Fabricate(:user, role: role) }
|
||||
let(:scopes) { 'admin:read admin:write' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
describe 'GET /api/v1/admin/trends/links' do
|
||||
subject do
|
||||
get '/api/v1/admin/trends/links', headers: headers
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v1/admin/trends/links/:id/approve' do
|
||||
subject do
|
||||
post "/api/v1/admin/trends/links/#{preview_card.id}/approve", headers: headers
|
||||
end
|
||||
|
||||
let(:preview_card) { Fabricate(:preview_card, trendable: false) }
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read write'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'sets the link as trendable' do
|
||||
expect { subject }.to change { preview_card.reload.trendable }.from(false).to(true)
|
||||
end
|
||||
|
||||
it 'returns the link data' do
|
||||
subject
|
||||
|
||||
expect(body_as_json).to match(
|
||||
a_hash_including(
|
||||
url: preview_card.url,
|
||||
title: preview_card.title,
|
||||
description: preview_card.description,
|
||||
type: 'link',
|
||||
requires_review: false
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
context 'when the link does not exist' do
|
||||
it 'returns http not found' do
|
||||
post '/api/v1/admin/trends/links/-1/approve', headers: headers
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
context 'without an authorization header' do
|
||||
let(:headers) { {} }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v1/admin/trends/links/:id/reject' do
|
||||
subject do
|
||||
post "/api/v1/admin/trends/links/#{preview_card.id}/reject", headers: headers
|
||||
end
|
||||
|
||||
let(:preview_card) { Fabricate(:preview_card, trendable: false) }
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read write'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'does not set the link as trendable' do
|
||||
expect { subject }.to_not(change { preview_card.reload.trendable })
|
||||
end
|
||||
|
||||
it 'returns the link data' do
|
||||
subject
|
||||
|
||||
expect(body_as_json).to match(
|
||||
a_hash_including(
|
||||
url: preview_card.url,
|
||||
title: preview_card.title,
|
||||
description: preview_card.description,
|
||||
type: 'link',
|
||||
requires_review: false
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
context 'when the link does not exist' do
|
||||
it 'returns http not found' do
|
||||
post '/api/v1/admin/trends/links/-1/reject', headers: headers
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
context 'without an authorization header' do
|
||||
let(:headers) { {} }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -12,14 +12,10 @@ describe 'Credentials' do
|
|||
let(:token) { Fabricate(:accessible_access_token, scopes: 'read', application: Fabricate(:application)) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
it 'returns http success' do
|
||||
it 'returns the app information correctly', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns the app information correctly' do
|
||||
subject
|
||||
|
||||
expect(body_as_json).to match(
|
||||
a_hash_including(
|
||||
|
|
|
@ -23,20 +23,11 @@ RSpec.describe 'Apps' do
|
|||
end
|
||||
|
||||
context 'with valid params' do
|
||||
it 'returns http success' do
|
||||
it 'creates an OAuth app', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'creates an OAuth app' do
|
||||
subject
|
||||
|
||||
expect(Doorkeeper::Application.find_by(name: client_name)).to be_present
|
||||
end
|
||||
|
||||
it 'returns client ID and client secret' do
|
||||
subject
|
||||
|
||||
body = body_as_json
|
||||
|
||||
|
@ -58,15 +49,10 @@ RSpec.describe 'Apps' do
|
|||
context 'with many duplicate scopes' do
|
||||
let(:scopes) { (%w(read) * 40).join(' ') }
|
||||
|
||||
it 'returns http success' do
|
||||
it 'only saves the scope once', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'only saves the scope once' do
|
||||
subject
|
||||
|
||||
expect(Doorkeeper::Application.find_by(name: client_name).scopes.to_s).to eq 'read'
|
||||
end
|
||||
end
|
||||
|
|
80
spec/requests/api/v1/blocks_spec.rb
Normal file
80
spec/requests/api/v1/blocks_spec.rb
Normal file
|
@ -0,0 +1,80 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Blocks' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:scopes) { 'read:blocks' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
describe 'GET /api/v1/blocks' do
|
||||
subject do
|
||||
get '/api/v1/blocks', headers: headers, params: params
|
||||
end
|
||||
|
||||
let!(:blocks) { Fabricate.times(3, :block, account: user.account) }
|
||||
let(:params) { {} }
|
||||
|
||||
let(:expected_response) do
|
||||
blocks.map { |block| a_hash_including(id: block.target_account.id.to_s, username: block.target_account.username) }
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:blocks'
|
||||
|
||||
it 'returns the blocked accounts', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(body_as_json).to match_array(expected_response)
|
||||
end
|
||||
|
||||
context 'with limit param' do
|
||||
let(:params) { { limit: 2 } }
|
||||
|
||||
it 'returns only the requested number of blocked accounts' do
|
||||
subject
|
||||
|
||||
expect(body_as_json.size).to eq(params[:limit])
|
||||
end
|
||||
|
||||
it 'sets the correct pagination header for the prev path' do
|
||||
subject
|
||||
|
||||
expect(response.headers['Link'].find_link(%w(rel prev)).href).to eq(api_v1_blocks_url(limit: params[:limit], since_id: blocks.last.id))
|
||||
end
|
||||
|
||||
it 'sets the correct pagination header for the next path' do
|
||||
subject
|
||||
|
||||
expect(response.headers['Link'].find_link(%w(rel next)).href).to eq(api_v1_blocks_url(limit: params[:limit], max_id: blocks[1].id))
|
||||
end
|
||||
end
|
||||
|
||||
context 'with max_id param' do
|
||||
let(:params) { { max_id: blocks[1].id } }
|
||||
|
||||
it 'queries the blocks in range according to max_id', :aggregate_failures do
|
||||
subject
|
||||
|
||||
response_body = body_as_json
|
||||
|
||||
expect(response_body.size).to be 1
|
||||
expect(response_body[0][:id]).to eq(blocks[0].target_account.id.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with since_id param' do
|
||||
let(:params) { { since_id: blocks[1].id } }
|
||||
|
||||
it 'queries the blocks in range according to since_id', :aggregate_failures do
|
||||
subject
|
||||
|
||||
response_body = body_as_json
|
||||
|
||||
expect(response_body.size).to be 1
|
||||
expect(response_body[0][:id]).to eq(blocks[2].target_account.id.to_s)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -22,15 +22,10 @@ RSpec.describe 'Domain blocks' do
|
|||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:blocks'
|
||||
|
||||
it 'returns http success' do
|
||||
it 'returns the domains blocked by the requesting user', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns the domains blocked by the requesting user' do
|
||||
subject
|
||||
|
||||
expect(body_as_json).to match_array(blocked_domains)
|
||||
end
|
||||
|
||||
|
@ -54,15 +49,10 @@ RSpec.describe 'Domain blocks' do
|
|||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read read:blocks'
|
||||
|
||||
it 'returns http success' do
|
||||
it 'creates a domain block', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'creates a domain block' do
|
||||
subject
|
||||
|
||||
expect(user.account.domain_blocking?(params[:domain])).to be(true)
|
||||
end
|
||||
|
||||
|
@ -100,15 +90,10 @@ RSpec.describe 'Domain blocks' do
|
|||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read read:blocks'
|
||||
|
||||
it 'returns http success' do
|
||||
it 'deletes the specified domain block', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'deletes the specified domain block' do
|
||||
subject
|
||||
|
||||
expect(user.account.domain_blocking?('example.com')).to be(false)
|
||||
end
|
||||
|
||||
|
|
71
spec/requests/api/v1/favourites_spec.rb
Normal file
71
spec/requests/api/v1/favourites_spec.rb
Normal file
|
@ -0,0 +1,71 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Favourites' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'read:favourites' }
|
||||
let(:headers) { { Authorization: "Bearer #{token.token}" } }
|
||||
|
||||
describe 'GET /api/v1/favourites' do
|
||||
subject do
|
||||
get '/api/v1/favourites', headers: headers, params: params
|
||||
end
|
||||
|
||||
let(:params) { {} }
|
||||
let!(:favourites) { Fabricate.times(3, :favourite, account: user.account) }
|
||||
|
||||
let(:expected_response) do
|
||||
favourites.map do |favourite|
|
||||
a_hash_including(id: favourite.status.id.to_s, account: a_hash_including(id: favourite.status.account.id.to_s))
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write'
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns the favourites' do
|
||||
subject
|
||||
|
||||
expect(body_as_json).to match_array(expected_response)
|
||||
end
|
||||
|
||||
context 'with limit param' do
|
||||
let(:params) { { limit: 2 } }
|
||||
|
||||
it 'returns only the requested number of favourites' do
|
||||
subject
|
||||
|
||||
expect(body_as_json.size).to eq(params[:limit])
|
||||
end
|
||||
|
||||
it 'sets the correct pagination header for the prev path' do
|
||||
subject
|
||||
|
||||
expect(response.headers['Link'].find_link(%w(rel prev)).href).to eq(api_v1_favourites_url(limit: params[:limit], min_id: favourites.last.id))
|
||||
end
|
||||
|
||||
it 'sets the correct pagination header for the next path' do
|
||||
subject
|
||||
|
||||
expect(response.headers['Link'].find_link(%w(rel next)).href).to eq(api_v1_favourites_url(limit: params[:limit], max_id: favourites[1].id))
|
||||
end
|
||||
end
|
||||
|
||||
context 'without an authorization header' do
|
||||
let(:headers) { {} }
|
||||
|
||||
it 'returns http unauthorized' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(401)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -32,15 +32,10 @@ RSpec.describe 'Follow requests' do
|
|||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:follows'
|
||||
|
||||
it 'returns http success' do
|
||||
it 'returns the expected content from accounts requesting to follow', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns the expected content from accounts requesting to follow' do
|
||||
subject
|
||||
|
||||
expect(body_as_json).to match_array(expected_response)
|
||||
end
|
||||
|
||||
|
@ -68,19 +63,9 @@ RSpec.describe 'Follow requests' do
|
|||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read read:follows'
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'allows the requesting follower to follow' do
|
||||
it 'allows the requesting follower to follow', :aggregate_failures do
|
||||
expect { subject }.to change { follower.following?(user.account) }.from(false).to(true)
|
||||
end
|
||||
|
||||
it 'returns JSON with followed_by set to true' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(body_as_json[:followed_by]).to be true
|
||||
end
|
||||
end
|
||||
|
@ -98,21 +83,11 @@ RSpec.describe 'Follow requests' do
|
|||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read read:follows'
|
||||
|
||||
it 'returns http success' do
|
||||
it 'removes the follow request', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'removes the follow request' do
|
||||
subject
|
||||
|
||||
expect(FollowRequest.where(target_account: user.account, account: follower)).to_not exist
|
||||
end
|
||||
|
||||
it 'returns JSON with followed_by set to false' do
|
||||
subject
|
||||
|
||||
expect(body_as_json[:followed_by]).to be false
|
||||
end
|
||||
end
|
||||
|
|
65
spec/requests/api/v1/followed_tags_spec.rb
Normal file
65
spec/requests/api/v1/followed_tags_spec.rb
Normal file
|
@ -0,0 +1,65 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Followed tags' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:scopes) { 'read:follows' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
describe 'GET /api/v1/followed_tags' do
|
||||
subject do
|
||||
get '/api/v1/followed_tags', headers: headers, params: params
|
||||
end
|
||||
|
||||
let!(:tag_follows) { Fabricate.times(5, :tag_follow, account: user.account) }
|
||||
let(:params) { {} }
|
||||
|
||||
let(:expected_response) do
|
||||
tag_follows.map do |tag_follow|
|
||||
a_hash_including(name: tag_follow.tag.name, following: true)
|
||||
end
|
||||
end
|
||||
|
||||
before do
|
||||
Fabricate(:tag_follow)
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:follows'
|
||||
|
||||
it 'returns http success' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
|
||||
it 'returns the followed tags correctly' do
|
||||
subject
|
||||
|
||||
expect(body_as_json).to match_array(expected_response)
|
||||
end
|
||||
|
||||
context 'with limit param' do
|
||||
let(:params) { { limit: 3 } }
|
||||
|
||||
it 'returns only the requested number of follow tags' do
|
||||
subject
|
||||
|
||||
expect(body_as_json.size).to eq(params[:limit])
|
||||
end
|
||||
|
||||
it 'sets the correct pagination header for the prev path' do
|
||||
subject
|
||||
|
||||
expect(response.headers['Link'].find_link(%w(rel prev)).href).to eq(api_v1_followed_tags_url(limit: params[:limit], since_id: tag_follows.last.id))
|
||||
end
|
||||
|
||||
it 'sets the correct pagination header for the next path' do
|
||||
subject
|
||||
|
||||
expect(response.headers['Link'].find_link(%w(rel next)).href).to eq(api_v1_followed_tags_url(limit: params[:limit], max_id: tag_follows[2].id))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
178
spec/requests/api/v1/lists/accounts_spec.rb
Normal file
178
spec/requests/api/v1/lists/accounts_spec.rb
Normal file
|
@ -0,0 +1,178 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Accounts' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'read:lists write:lists' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
describe 'GET /api/v1/lists/:id/accounts' do
|
||||
subject do
|
||||
get "/api/v1/lists/#{list.id}/accounts", headers: headers, params: params
|
||||
end
|
||||
|
||||
let(:params) { { limit: 0 } }
|
||||
let(:list) { Fabricate(:list, account: user.account) }
|
||||
let(:accounts) { Fabricate.times(3, :account) }
|
||||
|
||||
let(:expected_response) do
|
||||
accounts.map do |account|
|
||||
a_hash_including(id: account.id.to_s, username: account.username, acct: account.acct)
|
||||
end
|
||||
end
|
||||
|
||||
before do
|
||||
accounts.each { |account| user.account.follow!(account) }
|
||||
list.accounts << accounts
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:lists'
|
||||
|
||||
it 'returns the accounts in the requested list', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(body_as_json).to match_array(expected_response)
|
||||
end
|
||||
|
||||
context 'with limit param' do
|
||||
let(:params) { { limit: 1 } }
|
||||
|
||||
it 'returns only the requested number of accounts' do
|
||||
subject
|
||||
|
||||
expect(body_as_json.size).to eq(params[:limit])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v1/lists/:id/accounts' do
|
||||
subject do
|
||||
post "/api/v1/lists/#{list.id}/accounts", headers: headers, params: params
|
||||
end
|
||||
|
||||
let(:list) { Fabricate(:list, account: user.account) }
|
||||
let(:bob) { Fabricate(:account, username: 'bob') }
|
||||
let(:params) { { account_ids: [bob.id] } }
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read read:lists'
|
||||
|
||||
context 'when the added account is followed' do
|
||||
before do
|
||||
user.account.follow!(bob)
|
||||
end
|
||||
|
||||
it 'adds account to the list', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(list.accounts).to include(bob)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the added account has been sent a follow request' do
|
||||
before do
|
||||
user.account.follow_requests.create!(target_account: bob)
|
||||
end
|
||||
|
||||
it 'adds account to the list', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(list.accounts).to include(bob)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the added account is not followed' do
|
||||
it 'does not add the account to the list', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
expect(list.accounts).to_not include(bob)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the list is not owned by the requesting user' do
|
||||
let(:list) { Fabricate(:list) }
|
||||
|
||||
before do
|
||||
user.account.follow!(bob)
|
||||
end
|
||||
|
||||
it 'returns http not found' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when account is already in the list' do
|
||||
before do
|
||||
user.account.follow!(bob)
|
||||
list.accounts << bob
|
||||
end
|
||||
|
||||
it 'returns http unprocessable entity' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE /api/v1/lists/:id/accounts' do
|
||||
subject do
|
||||
delete "/api/v1/lists/#{list.id}/accounts", headers: headers, params: params
|
||||
end
|
||||
|
||||
context 'when the list is owned by the requesting user' do
|
||||
let(:list) { Fabricate(:list, account: user.account) }
|
||||
let(:bob) { Fabricate(:account, username: 'bob') }
|
||||
let(:peter) { Fabricate(:account, username: 'peter') }
|
||||
let(:params) { { account_ids: [bob.id] } }
|
||||
|
||||
before do
|
||||
user.account.follow!(bob)
|
||||
user.account.follow!(peter)
|
||||
list.accounts << [bob, peter]
|
||||
end
|
||||
|
||||
it 'removes the specified account from the list', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(list.accounts).to_not include(bob)
|
||||
end
|
||||
|
||||
it 'does not remove any other account from the list' do
|
||||
subject
|
||||
|
||||
expect(list.accounts).to include(peter)
|
||||
end
|
||||
|
||||
context 'when the specified account is not in the list' do
|
||||
let(:params) { { account_ids: [0] } }
|
||||
|
||||
it 'does not remove any account from the list', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(list.accounts).to contain_exactly(bob, peter)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the list is not owned by the requesting user' do
|
||||
let(:list) { Fabricate(:list) }
|
||||
let(:params) { {} }
|
||||
|
||||
it 'returns http not found' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -39,15 +39,10 @@ RSpec.describe 'Lists' do
|
|||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:lists'
|
||||
|
||||
it 'returns http success' do
|
||||
it 'returns the expected lists', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns the expected lists' do
|
||||
subject
|
||||
|
||||
expect(body_as_json).to match_array(expected_response)
|
||||
end
|
||||
end
|
||||
|
@ -61,15 +56,10 @@ RSpec.describe 'Lists' do
|
|||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:lists'
|
||||
|
||||
it 'returns http success' do
|
||||
it 'returns the requested list correctly', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns the requested list correctly' do
|
||||
subject
|
||||
|
||||
expect(body_as_json).to eq({
|
||||
id: list.id.to_s,
|
||||
title: list.title,
|
||||
|
@ -106,21 +96,11 @@ RSpec.describe 'Lists' do
|
|||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read read:lists'
|
||||
|
||||
it 'returns http success' do
|
||||
it 'returns the new list', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns the new list' do
|
||||
subject
|
||||
|
||||
expect(body_as_json).to match(a_hash_including(title: 'my list', replies_policy: 'none', exclusive: true))
|
||||
end
|
||||
|
||||
it 'creates a list' do
|
||||
subject
|
||||
|
||||
expect(List.where(account: user.account).count).to eq(1)
|
||||
end
|
||||
|
||||
|
@ -155,15 +135,10 @@ RSpec.describe 'Lists' do
|
|||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read read:lists'
|
||||
|
||||
it 'returns http success' do
|
||||
it 'returns the updated list', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns the updated list' do
|
||||
subject
|
||||
|
||||
list.reload
|
||||
|
||||
expect(body_as_json).to eq({
|
||||
|
@ -214,15 +189,10 @@ RSpec.describe 'Lists' do
|
|||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read read:lists'
|
||||
|
||||
it 'returns http success' do
|
||||
it 'deletes the list', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'deletes the list' do
|
||||
subject
|
||||
|
||||
expect(List.where(id: list.id)).to_not exist
|
||||
end
|
||||
|
||||
|
|
89
spec/requests/api/v1/reports_spec.rb
Normal file
89
spec/requests/api/v1/reports_spec.rb
Normal file
|
@ -0,0 +1,89 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Reports' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:scopes) { 'write:reports' }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
describe 'POST /api/v1/reports' do
|
||||
subject do
|
||||
post '/api/v1/reports', headers: headers, params: params
|
||||
end
|
||||
|
||||
let!(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
|
||||
let(:status) { Fabricate(:status) }
|
||||
let(:target_account) { status.account }
|
||||
let(:category) { 'other' }
|
||||
let(:forward) { nil }
|
||||
let(:rule_ids) { nil }
|
||||
|
||||
let(:params) do
|
||||
{
|
||||
status_ids: [status.id],
|
||||
account_id: target_account.id,
|
||||
comment: 'reasons',
|
||||
category: category,
|
||||
rule_ids: rule_ids,
|
||||
forward: forward,
|
||||
}
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read read:reports'
|
||||
|
||||
it 'creates a report', :aggregate_failures do
|
||||
perform_enqueued_jobs do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(body_as_json).to match(
|
||||
a_hash_including(
|
||||
status_ids: [status.id.to_s],
|
||||
category: category,
|
||||
comment: 'reasons'
|
||||
)
|
||||
)
|
||||
|
||||
expect(target_account.targeted_reports).to_not be_empty
|
||||
expect(target_account.targeted_reports.first.comment).to eq 'reasons'
|
||||
|
||||
expect(ActionMailer::Base.deliveries.first.to).to eq([admin.email])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a status does not belong to the reported account' do
|
||||
let(:target_account) { Fabricate(:account) }
|
||||
|
||||
it 'returns http not found' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a category is chosen' do
|
||||
let(:category) { 'spam' }
|
||||
|
||||
it 'saves category' do
|
||||
subject
|
||||
|
||||
expect(target_account.targeted_reports.first.spam?).to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'when violated rules are chosen' do
|
||||
let(:rule) { Fabricate(:rule) }
|
||||
let(:category) { 'violation' }
|
||||
let(:rule_ids) { [rule.id] }
|
||||
|
||||
it 'saves category and rule_ids' do
|
||||
subject
|
||||
|
||||
expect(target_account.targeted_reports.first.violation?).to be true
|
||||
expect(target_account.targeted_reports.first.rule_ids).to contain_exactly(rule.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
74
spec/requests/api/v1/statuses/sources_spec.rb
Normal file
74
spec/requests/api/v1/statuses/sources_spec.rb
Normal file
|
@ -0,0 +1,74 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Sources' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:scopes) { 'read:statuses' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
describe 'GET /api/v1/statuses/:status_id/source' do
|
||||
subject do
|
||||
get "/api/v1/statuses/#{status.id}/source", headers: headers
|
||||
end
|
||||
|
||||
let(:status) { Fabricate(:status) }
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:statuses'
|
||||
|
||||
context 'with public status' do
|
||||
it 'returns the source properties of the status', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(body_as_json).to eq({
|
||||
id: status.id.to_s,
|
||||
text: status.text,
|
||||
spoiler_text: status.spoiler_text,
|
||||
content_type: nil,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
context 'with private status of non-followed account' do
|
||||
let(:status) { Fabricate(:status, visibility: :private) }
|
||||
|
||||
it 'returns http not found' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with private status of followed account' do
|
||||
let(:status) { Fabricate(:status, visibility: :private) }
|
||||
|
||||
before do
|
||||
user.account.follow!(status.account)
|
||||
end
|
||||
|
||||
it 'returns the source properties of the status', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(body_as_json).to eq({
|
||||
id: status.id.to_s,
|
||||
text: status.text,
|
||||
spoiler_text: status.spoiler_text,
|
||||
content_type: nil,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
context 'without an authorization header' do
|
||||
let(:headers) { {} }
|
||||
|
||||
it 'returns http unauthorized' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(401)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -17,15 +17,10 @@ RSpec.describe 'Tags' do
|
|||
let!(:tag) { Fabricate(:tag) }
|
||||
let(:name) { tag.name }
|
||||
|
||||
it 'returns http success' do
|
||||
it 'returns the tag', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns the tag' do
|
||||
subject
|
||||
|
||||
expect(body_as_json[:name]).to eq(name)
|
||||
end
|
||||
end
|
||||
|
@ -62,15 +57,10 @@ RSpec.describe 'Tags' do
|
|||
it_behaves_like 'forbidden for wrong scope', 'read read:follows'
|
||||
|
||||
context 'when the tag exists' do
|
||||
it 'returns http success' do
|
||||
it 'creates follow', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
|
||||
it 'creates follow' do
|
||||
subject
|
||||
|
||||
expect(TagFollow.where(tag: tag, account: user.account)).to exist
|
||||
end
|
||||
end
|
||||
|
@ -78,21 +68,11 @@ RSpec.describe 'Tags' do
|
|||
context 'when the tag does not exist' do
|
||||
let(:name) { 'hoge' }
|
||||
|
||||
it 'returns http success' do
|
||||
it 'creates a new tag with the specified name', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'creates a new tag with the specified name' do
|
||||
subject
|
||||
|
||||
expect(Tag.where(name: name)).to exist
|
||||
end
|
||||
|
||||
it 'creates follow' do
|
||||
subject
|
||||
|
||||
expect(TagFollow.where(tag: Tag.find_by(name: name), account: user.account)).to exist
|
||||
end
|
||||
end
|
||||
|
@ -133,15 +113,10 @@ RSpec.describe 'Tags' do
|
|||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read read:follows'
|
||||
|
||||
it 'returns http success' do
|
||||
it 'removes the follow', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'removes the follow' do
|
||||
subject
|
||||
|
||||
expect(TagFollow.where(tag: tag, account: user.account)).to_not exist
|
||||
end
|
||||
|
||||
|
|
116
spec/requests/api/v1/timelines/tag_spec.rb
Normal file
116
spec/requests/api/v1/timelines/tag_spec.rb
Normal file
|
@ -0,0 +1,116 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Tag' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
let(:scopes) { 'read:statuses' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||
|
||||
shared_examples 'a successful request to the tag timeline' do
|
||||
it 'returns the expected statuses', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(body_as_json.pluck(:id)).to match_array(expected_statuses.map { |status| status.id.to_s })
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v1/timelines/tag/:hashtag' do
|
||||
subject do
|
||||
get "/api/v1/timelines/tag/#{hashtag}", headers: headers, params: params
|
||||
end
|
||||
|
||||
before do
|
||||
Setting.timeline_preview = true
|
||||
end
|
||||
|
||||
let(:account) { Fabricate(:account) }
|
||||
let!(:private_status) { PostStatusService.new.call(account, visibility: :private, text: '#life could be a dream') } # rubocop:disable RSpec/LetSetup
|
||||
let!(:life_status) { PostStatusService.new.call(account, text: 'tell me what is my #life without your #love') }
|
||||
let!(:war_status) { PostStatusService.new.call(user.account, text: '#war, war never changes') }
|
||||
let!(:love_status) { PostStatusService.new.call(account, text: 'what is #love?') }
|
||||
let(:params) { {} }
|
||||
let(:hashtag) { 'life' }
|
||||
|
||||
context 'when given only one hashtag' do
|
||||
let(:expected_statuses) { [life_status] }
|
||||
|
||||
it_behaves_like 'a successful request to the tag timeline'
|
||||
end
|
||||
|
||||
context 'with any param' do
|
||||
let(:expected_statuses) { [life_status, love_status] }
|
||||
let(:params) { { any: %(love) } }
|
||||
|
||||
it_behaves_like 'a successful request to the tag timeline'
|
||||
end
|
||||
|
||||
context 'with all param' do
|
||||
let(:expected_statuses) { [life_status] }
|
||||
let(:params) { { all: %w(love) } }
|
||||
|
||||
it_behaves_like 'a successful request to the tag timeline'
|
||||
end
|
||||
|
||||
context 'with none param' do
|
||||
let(:expected_statuses) { [war_status] }
|
||||
let(:hashtag) { 'war' }
|
||||
let(:params) { { none: %w(life love) } }
|
||||
|
||||
it_behaves_like 'a successful request to the tag timeline'
|
||||
end
|
||||
|
||||
context 'with limit param' do
|
||||
let(:hashtag) { 'love' }
|
||||
let(:params) { { limit: 1 } }
|
||||
|
||||
it 'returns only the requested number of statuses' do
|
||||
subject
|
||||
|
||||
expect(body_as_json.size).to eq(params[:limit])
|
||||
end
|
||||
|
||||
it 'sets the correct pagination headers', :aggregate_failures do
|
||||
subject
|
||||
|
||||
headers = response.headers['Link']
|
||||
|
||||
expect(headers.find_link(%w(rel prev)).href).to eq(api_v1_timelines_tag_url(limit: 1, min_id: love_status.id.to_s))
|
||||
expect(headers.find_link(%w(rel next)).href).to eq(api_v1_timelines_tag_url(limit: 1, max_id: love_status.id.to_s))
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the instance allows public preview' do
|
||||
context 'when the user is not authenticated' do
|
||||
let(:headers) { {} }
|
||||
let(:expected_statuses) { [life_status] }
|
||||
|
||||
it_behaves_like 'a successful request to the tag timeline'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the instance does not allow public preview' do
|
||||
before do
|
||||
Form::AdminSettings.new(timeline_preview: false).save
|
||||
end
|
||||
|
||||
context 'when the user is not authenticated' do
|
||||
let(:headers) { {} }
|
||||
|
||||
it 'returns http unauthorized' do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(401)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user is authenticated' do
|
||||
let(:expected_statuses) { [life_status] }
|
||||
|
||||
it_behaves_like 'a successful request to the tag timeline'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -9,7 +9,6 @@ RSpec.describe AfterBlockDomainFromAccountService, type: :service do
|
|||
let!(:alice) { Fabricate(:account, username: 'alice') }
|
||||
|
||||
before do
|
||||
stub_jsonld_contexts!
|
||||
allow(ActivityPub::DeliveryWorker).to receive(:perform_async)
|
||||
end
|
||||
|
||||
|
|
21
spec/support/signed_request_helpers.rb
Normal file
21
spec/support/signed_request_helpers.rb
Normal file
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module SignedRequestHelpers
|
||||
def get(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'] = ENV.fetch('LOCAL_DOMAIN')
|
||||
signed_headers = headers.merge('(request-target)' => "get #{path}").slice('(request-target)', 'Host', 'Date')
|
||||
|
||||
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
|
83
spec/validators/existing_username_validator_spec.rb
Normal file
83
spec/validators/existing_username_validator_spec.rb
Normal file
|
@ -0,0 +1,83 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe ExistingUsernameValidator do
|
||||
let(:record_class) do
|
||||
Class.new do
|
||||
include ActiveModel::Validations
|
||||
attr_accessor :contact, :friends
|
||||
|
||||
def self.name
|
||||
'Record'
|
||||
end
|
||||
|
||||
validates :contact, existing_username: true
|
||||
validates :friends, existing_username: { multiple: true }
|
||||
end
|
||||
end
|
||||
let(:record) { record_class.new }
|
||||
|
||||
describe '#validate_each' do
|
||||
context 'with a nil value' do
|
||||
it 'does not add errors' do
|
||||
record.contact = nil
|
||||
|
||||
expect(record).to be_valid
|
||||
expect(record.errors).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there are no accounts' do
|
||||
it 'adds errors to the record' do
|
||||
record.contact = 'user@example.com'
|
||||
|
||||
expect(record).to_not be_valid
|
||||
expect(record.errors.first.attribute).to eq(:contact)
|
||||
expect(record.errors.first.type).to eq I18n.t('existing_username_validator.not_found')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there are accounts' do
|
||||
before { Fabricate(:account, domain: 'example.com', username: 'user') }
|
||||
|
||||
context 'when the value does not match' do
|
||||
it 'adds errors to the record' do
|
||||
record.contact = 'friend@other.host'
|
||||
|
||||
expect(record).to_not be_valid
|
||||
expect(record.errors.first.attribute).to eq(:contact)
|
||||
expect(record.errors.first.type).to eq I18n.t('existing_username_validator.not_found')
|
||||
end
|
||||
|
||||
context 'when multiple is true' do
|
||||
it 'adds errors to the record' do
|
||||
record.friends = 'friend@other.host'
|
||||
|
||||
expect(record).to_not be_valid
|
||||
expect(record.errors.first.attribute).to eq(:friends)
|
||||
expect(record.errors.first.type).to eq I18n.t('existing_username_validator.not_found_multiple', usernames: 'friend@other.host')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the value does match' do
|
||||
it 'does not add errors to the record' do
|
||||
record.contact = 'user@example.com'
|
||||
|
||||
expect(record).to be_valid
|
||||
expect(record.errors).to be_empty
|
||||
end
|
||||
|
||||
context 'when multiple is true' do
|
||||
it 'does not add errors to the record' do
|
||||
record.friends = 'user@example.com'
|
||||
|
||||
expect(record).to be_valid
|
||||
expect(record.errors).to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -67,39 +67,31 @@ describe MoveWorker do
|
|||
end
|
||||
|
||||
shared_examples 'block and mute handling' do
|
||||
it 'makes blocks carry over and add a note' do
|
||||
it 'makes blocks and mutes carry over and adds a note' do
|
||||
subject.perform(source_account.id, target_account.id)
|
||||
|
||||
expect(block_service).to have_received(:call).with(blocking_account, target_account)
|
||||
expect(AccountNote.find_by(account: blocking_account, target_account: target_account).comment).to include(source_account.acct)
|
||||
end
|
||||
|
||||
it 'makes mutes carry over and add a note' do
|
||||
subject.perform(source_account.id, target_account.id)
|
||||
expect(muting_account.muting?(target_account)).to be true
|
||||
expect(AccountNote.find_by(account: muting_account, target_account: target_account).comment).to include(source_account.acct)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'followers count handling' do
|
||||
it 'updates the source account followers count' do
|
||||
it 'updates the source and target account followers counts' do
|
||||
subject.perform(source_account.id, target_account.id)
|
||||
expect(source_account.reload.followers_count).to eq(source_account.passive_relationships.count)
|
||||
end
|
||||
|
||||
it 'updates the target account followers count' do
|
||||
subject.perform(source_account.id, target_account.id)
|
||||
expect(source_account.reload.followers_count).to eq(source_account.passive_relationships.count)
|
||||
expect(target_account.reload.followers_count).to eq(target_account.passive_relationships.count)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'lists handling' do
|
||||
it 'puts the new account on the list' do
|
||||
it 'puts the new account on the list and makes valid lists', sidekiq: :inline do
|
||||
subject.perform(source_account.id, target_account.id)
|
||||
expect(list.accounts.include?(target_account)).to be true
|
||||
end
|
||||
|
||||
it 'does not create invalid list memberships' do
|
||||
subject.perform(source_account.id, target_account.id)
|
||||
expect(list.accounts.include?(target_account)).to be true
|
||||
expect(ListAccount.all).to all be_valid
|
||||
end
|
||||
end
|
||||
|
|
13
yarn.lock
13
yarn.lock
|
@ -3825,9 +3825,9 @@ buffer@^6.0.3:
|
|||
ieee754 "^1.2.1"
|
||||
|
||||
bufferutil@^4.0.7:
|
||||
version "4.0.7"
|
||||
resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.7.tgz#60c0d19ba2c992dd8273d3f73772ffc894c153ad"
|
||||
integrity sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==
|
||||
version "4.0.8"
|
||||
resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.8.tgz#1de6a71092d65d7766c4d8a522b261a6e787e8ea"
|
||||
integrity sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==
|
||||
dependencies:
|
||||
node-gyp-build "^4.3.0"
|
||||
|
||||
|
@ -8781,9 +8781,9 @@ node-forge@^0.10.0:
|
|||
integrity sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==
|
||||
|
||||
node-gyp-build@^4.3.0:
|
||||
version "4.6.0"
|
||||
resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.6.0.tgz#0c52e4cbf54bbd28b709820ef7b6a3c2d6209055"
|
||||
integrity sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==
|
||||
version "4.6.1"
|
||||
resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.6.1.tgz#24b6d075e5e391b8d5539d98c7fc5c210cac8a3e"
|
||||
integrity sha512-24vnklJmyRS8ViBNI8KbtK/r/DmXQMRiOMXTNz2nrTnAYUwjmEEbnnpB/+kt+yWRv73bPsSPRFddrcIbAxSiMQ==
|
||||
|
||||
node-int64@^0.4.0:
|
||||
version "0.4.0"
|
||||
|
@ -11488,6 +11488,7 @@ stringz@^2.1.0:
|
|||
char-regex "^1.0.2"
|
||||
|
||||
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
||||
name strip-ansi-cjs
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||
|
|
Loading…
Reference in a new issue