Merge pull request #2446 from ClearlyClaire/glitch-soc/merge-upstream

Merge upstream changes up to 9f218c9924
This commit is contained in:
Claire 2023-10-19 20:47:22 +02:00 committed by GitHub
commit 1c53aec00e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
45 changed files with 480 additions and 173 deletions

View file

@ -113,6 +113,7 @@ jobs:
CAS_ENABLED: true CAS_ENABLED: true
BUNDLE_WITH: 'pam_authentication test' BUNDLE_WITH: 'pam_authentication test'
CI_JOBS: ${{ matrix.ci_job }}/4 CI_JOBS: ${{ matrix.ci_job }}/4
GITHUB_RSPEC: ${{ matrix.ruby-version == '.ruby-version' && github.event.pull_request && 'true' }}
strategy: strategy:
fail-fast: false fail-fast: false

View file

@ -48,27 +48,6 @@ Lint/UnusedBlockArgument:
- 'config/initializers/paperclip.rb' - 'config/initializers/paperclip.rb'
- 'config/initializers/simple_form.rb' - 'config/initializers/simple_form.rb'
# This cop supports unsafe autocorrection (--autocorrect-all).
Lint/UselessAssignment:
Exclude:
- 'app/services/activitypub/process_status_update_service.rb'
- 'config/initializers/3_omniauth.rb'
- 'db/migrate/20190511134027_add_silenced_at_suspended_at_to_accounts.rb'
- 'db/post_migrate/20190511152737_remove_suspended_silenced_account_fields.rb'
- 'spec/controllers/api/v1/favourites_controller_spec.rb'
- 'spec/controllers/concerns/account_controller_concern_spec.rb'
- 'spec/helpers/jsonld_helper_spec.rb'
- 'spec/models/account_spec.rb'
- 'spec/models/domain_block_spec.rb'
- 'spec/models/status_spec.rb'
- 'spec/models/user_spec.rb'
- 'spec/models/webauthn_credentials_spec.rb'
- 'spec/services/account_search_service_spec.rb'
- 'spec/services/post_status_service_spec.rb'
- 'spec/services/precompute_feed_service_spec.rb'
- 'spec/services/resolve_url_service_spec.rb'
- 'spec/views/statuses/show.html.haml_spec.rb'
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes. # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
Metrics/AbcSize: Metrics/AbcSize:
Max: 144 Max: 144
@ -88,26 +67,6 @@ Metrics/CyclomaticComplexity:
Metrics/PerceivedComplexity: Metrics/PerceivedComplexity:
Max: 27 Max: 27
# Configuration parameters: EnforcedStyle, CheckMethodNames, CheckSymbols, AllowedIdentifiers, AllowedPatterns.
# SupportedStyles: snake_case, normalcase, non_integer
# AllowedIdentifiers: capture3, iso8601, rfc1123_date, rfc822, rfc2822, rfc3339, x86_64
Naming/VariableNumber:
Exclude:
- 'db/migrate/20180106000232_add_index_on_statuses_for_api_v1_accounts_account_id_statuses.rb'
- 'db/migrate/20180514140000_revert_index_change_on_statuses_for_api_v1_accounts_account_id_statuses.rb'
- 'db/migrate/20190820003045_update_statuses_index.rb'
- 'db/migrate/20190823221802_add_local_index_to_statuses.rb'
- 'db/migrate/20200119112504_add_public_index_to_statuses.rb'
- 'spec/models/account_spec.rb'
- 'spec/models/domain_block_spec.rb'
- 'spec/models/user_spec.rb'
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: SafeMultiline.
Performance/DeletePrefix:
Exclude:
- 'app/models/featured_tag.rb'
Performance/MapMethodChain: Performance/MapMethodChain:
Exclude: Exclude:
- 'app/models/feed.rb' - 'app/models/feed.rb'

View file

@ -1,9 +1,9 @@
# frozen_string_literal: true # frozen_string_literal: true
class Api::V1::Apps::CredentialsController < Api::BaseController class Api::V1::Apps::CredentialsController < Api::BaseController
before_action -> { doorkeeper_authorize! :read }
def show def show
render json: doorkeeper_token.application, serializer: REST::ApplicationSerializer, fields: %i(name website vapid_key) return doorkeeper_render_error unless valid_doorkeeper_token?
render json: doorkeeper_token.application, serializer: REST::ApplicationSerializer, fields: %i(name website vapid_key client_id scopes)
end end
end end

View file

@ -0,0 +1,19 @@
# frozen_string_literal: true
module Admin
module DisputesHelper
def strike_action_label(appeal)
t(key_for_action(appeal),
scope: 'admin.strikes.actions',
name: content_tag(:span, appeal.strike.account.username, class: 'username'),
target: content_tag(:span, appeal.account.username, class: 'target'))
.html_safe
end
private
def key_for_action(appeal)
AccountWarning.actions.slice(appeal.strike.action).keys.first
end
end
end

View file

@ -37,7 +37,7 @@ const getHomeFeedSpeed = createSelector([
state => state.getIn(['timelines', 'home', 'pendingItems'], ImmutableList()), state => state.getIn(['timelines', 'home', 'pendingItems'], ImmutableList()),
state => state.get('statuses'), state => state.get('statuses'),
], (statusIds, pendingStatusIds, statusMap) => { ], (statusIds, pendingStatusIds, statusMap) => {
const recentStatusIds = pendingStatusIds.size > 0 ? pendingStatusIds : statusIds; const recentStatusIds = pendingStatusIds.concat(statusIds);
const statuses = recentStatusIds.filter(id => id !== null).map(id => statusMap.get(id)).filter(status => status?.get('account') !== me).take(20); const statuses = recentStatusIds.filter(id => id !== null).map(id => statusMap.get(id)).filter(status => status?.get('account') !== me).take(20);
if (statuses.isEmpty()) { if (statuses.isEmpty()) {

View file

@ -100,7 +100,7 @@ class LinkFooter extends PureComponent {
{DividingCircle} {DividingCircle}
<a href={source_url} rel='noopener noreferrer' target='_blank'><FormattedMessage id='footer.source_code' defaultMessage='View source code' /></a> <a href={source_url} rel='noopener noreferrer' target='_blank'><FormattedMessage id='footer.source_code' defaultMessage='View source code' /></a>
{DividingCircle} {DividingCircle}
<span class='version'>v{version}</span> <span className='version'>v{version}</span>
</p> </p>
</div> </div>
); );

View file

@ -57,10 +57,10 @@ class NavigationPanel extends Component {
<div className='navigation-panel'> <div className='navigation-panel'>
{transientSingleColumn && ( {transientSingleColumn && (
<div className='navigation-panel__logo'> <div className='navigation-panel__logo'>
<div class='switch-to-advanced'> <div className='switch-to-advanced'>
{intl.formatMessage(messages.openedInClassicInterface)} {intl.formatMessage(messages.openedInClassicInterface)}
{" "} {" "}
<a href={`/deck${location.pathname}`} class='switch-to-advanced__toggle'> <a href={`/deck${location.pathname}`} className='switch-to-advanced__toggle'>
{intl.formatMessage(messages.advancedInterface)} {intl.formatMessage(messages.advancedInterface)}
</a> </a>
</div> </div>

View file

@ -37,7 +37,7 @@ const getHomeFeedSpeed = createSelector([
state => state.getIn(['timelines', 'home', 'pendingItems'], ImmutableList()), state => state.getIn(['timelines', 'home', 'pendingItems'], ImmutableList()),
state => state.get('statuses'), state => state.get('statuses'),
], (statusIds, pendingStatusIds, statusMap) => { ], (statusIds, pendingStatusIds, statusMap) => {
const recentStatusIds = pendingStatusIds.size > 0 ? pendingStatusIds : statusIds; const recentStatusIds = pendingStatusIds.concat(statusIds);
const statuses = recentStatusIds.filter(id => id !== null).map(id => statusMap.get(id)).filter(status => status?.get('account') !== me).take(20); const statuses = recentStatusIds.filter(id => id !== null).map(id => statusMap.get(id)).filter(status => status?.get('account') !== me).take(20);
if (statuses.isEmpty()) { if (statuses.isEmpty()) {

View file

@ -100,7 +100,7 @@ class LinkFooter extends PureComponent {
{DividingCircle} {DividingCircle}
<a href={source_url} rel='noopener noreferrer' target='_blank'><FormattedMessage id='footer.source_code' defaultMessage='View source code' /></a> <a href={source_url} rel='noopener noreferrer' target='_blank'><FormattedMessage id='footer.source_code' defaultMessage='View source code' /></a>
{DividingCircle} {DividingCircle}
<span class='version'>v{version}</span> <span className='version'>v{version}</span>
</p> </p>
</div> </div>
); );

View file

@ -59,10 +59,10 @@ class NavigationPanel extends Component {
<Link to='/' className='column-link column-link--logo'><WordmarkLogo /></Link> <Link to='/' className='column-link column-link--logo'><WordmarkLogo /></Link>
{transientSingleColumn ? ( {transientSingleColumn ? (
<div class='switch-to-advanced'> <div className='switch-to-advanced'>
{intl.formatMessage(messages.openedInClassicInterface)} {intl.formatMessage(messages.openedInClassicInterface)}
{" "} {" "}
<a href={`/deck${location.pathname}`} class='switch-to-advanced__toggle'> <a href={`/deck${location.pathname}`} className='switch-to-advanced__toggle'>
{intl.formatMessage(messages.advancedInterface)} {intl.formatMessage(messages.advancedInterface)}
</a> </a>
</div> </div>

View file

@ -71,11 +71,11 @@
"account.unmute_notifications_short": "Poista ilmoitusten mykistys", "account.unmute_notifications_short": "Poista ilmoitusten mykistys",
"account.unmute_short": "Poista mykistys", "account.unmute_short": "Poista mykistys",
"account_note.placeholder": "Lisää muistiinpano napsauttamalla", "account_note.placeholder": "Lisää muistiinpano napsauttamalla",
"admin.dashboard.daily_retention": "Käyttäjän pysyminen rekisteröitymisen jälkeiseen päivään mennessä", "admin.dashboard.daily_retention": "Käyttäjien pysyvyys rekisteröitymisen jälkeen päivittäin",
"admin.dashboard.monthly_retention": "Käyttäjän pysyminen rekisteröitymisen jälkeiseen kuukauteen mennessä", "admin.dashboard.monthly_retention": "Käyttäjien pysyvyys rekisteröitymisen jälkeen kuukausittain",
"admin.dashboard.retention.average": "Keskimäärin", "admin.dashboard.retention.average": "Keskimäärin",
"admin.dashboard.retention.cohort": "Kirjautumiset", "admin.dashboard.retention.cohort": "Rekisteröitymis-kk.",
"admin.dashboard.retention.cohort_size": "Uudet käyttäjät", "admin.dashboard.retention.cohort_size": "Uusia käyttäjiä",
"admin.impact_report.instance_accounts": "Tilien profiilit, jotka tämä poistaisi", "admin.impact_report.instance_accounts": "Tilien profiilit, jotka tämä poistaisi",
"admin.impact_report.instance_followers": "Seuraajat, jotka käyttäjämme menettäisivät", "admin.impact_report.instance_followers": "Seuraajat, jotka käyttäjämme menettäisivät",
"admin.impact_report.instance_follows": "Seuraajat, jotka heidän käyttäjänsä menettäisivät", "admin.impact_report.instance_follows": "Seuraajat, jotka heidän käyttäjänsä menettäisivät",
@ -114,7 +114,7 @@
"column.directory": "Selaa profiileja", "column.directory": "Selaa profiileja",
"column.domain_blocks": "Estetyt verkkotunnukset", "column.domain_blocks": "Estetyt verkkotunnukset",
"column.favourites": "Suosikit", "column.favourites": "Suosikit",
"column.firehose": "Live-syötteet", "column.firehose": "Livesyötteet",
"column.follow_requests": "Seuraamispyynnöt", "column.follow_requests": "Seuraamispyynnöt",
"column.home": "Koti", "column.home": "Koti",
"column.lists": "Listat", "column.lists": "Listat",
@ -135,7 +135,7 @@
"community.column_settings.remote_only": "Vain etätilit", "community.column_settings.remote_only": "Vain etätilit",
"compose.language.change": "Vaihda kieli", "compose.language.change": "Vaihda kieli",
"compose.language.search": "Hae kieliä...", "compose.language.search": "Hae kieliä...",
"compose.published.body": "Julkaisusi julkaistiin.", "compose.published.body": "Julkaisu lähetetty.",
"compose.published.open": "Avaa", "compose.published.open": "Avaa",
"compose.saved.body": "Julkaisu tallennettu.", "compose.saved.body": "Julkaisu tallennettu.",
"compose_form.direct_message_warning_learn_more": "Lisätietoja", "compose_form.direct_message_warning_learn_more": "Lisätietoja",
@ -436,10 +436,10 @@
"notifications.clear": "Tyhjennä ilmoitukset", "notifications.clear": "Tyhjennä ilmoitukset",
"notifications.clear_confirmation": "Haluatko varmasti poistaa kaikki ilmoitukset pysyvästi?", "notifications.clear_confirmation": "Haluatko varmasti poistaa kaikki ilmoitukset pysyvästi?",
"notifications.column_settings.admin.report": "Uudet ilmoitukset:", "notifications.column_settings.admin.report": "Uudet ilmoitukset:",
"notifications.column_settings.admin.sign_up": "Uudet kirjautumiset:", "notifications.column_settings.admin.sign_up": "Uudet rekisteröitymiset:",
"notifications.column_settings.alert": "Työpöytäilmoitukset", "notifications.column_settings.alert": "Työpöytäilmoitukset",
"notifications.column_settings.favourite": "Suosikit:", "notifications.column_settings.favourite": "Suosikit:",
"notifications.column_settings.filter_bar.advanced": "Näytä kaikki kategoriat", "notifications.column_settings.filter_bar.advanced": "Näytä kaikki luokat",
"notifications.column_settings.filter_bar.category": "Pikasuodatuspalkki", "notifications.column_settings.filter_bar.category": "Pikasuodatuspalkki",
"notifications.column_settings.filter_bar.show_bar": "Näytä suodatinpalkki", "notifications.column_settings.filter_bar.show_bar": "Näytä suodatinpalkki",
"notifications.column_settings.follow": "Uudet seuraajat:", "notifications.column_settings.follow": "Uudet seuraajat:",
@ -517,7 +517,7 @@
"privacy.private.short": "Vain seuraajat", "privacy.private.short": "Vain seuraajat",
"privacy.public.long": "Näkyy kaikille", "privacy.public.long": "Näkyy kaikille",
"privacy.public.short": "Julkinen", "privacy.public.short": "Julkinen",
"privacy.unlisted.long": "Näkyy kaikille, mutta jää pois löytämisominaisuuksista", "privacy.unlisted.long": "Näkyy kaikille mutta jää pois löytämisominaisuuksista",
"privacy.unlisted.short": "Listaamaton", "privacy.unlisted.short": "Listaamaton",
"privacy_policy.last_updated": "Viimeksi päivitetty {date}", "privacy_policy.last_updated": "Viimeksi päivitetty {date}",
"privacy_policy.title": "Tietosuojakäytäntö", "privacy_policy.title": "Tietosuojakäytäntö",
@ -589,13 +589,13 @@
"search.quick_action.go_to_hashtag": "Siirry aihetunnisteeseen {x}", "search.quick_action.go_to_hashtag": "Siirry aihetunnisteeseen {x}",
"search.quick_action.open_url": "Avaa URL-osoite Mastodonissa", "search.quick_action.open_url": "Avaa URL-osoite Mastodonissa",
"search.quick_action.status_search": "Julkaisut haulla {x}", "search.quick_action.status_search": "Julkaisut haulla {x}",
"search.search_or_paste": "Hae tai kirjoita URL-osoite", "search.search_or_paste": "Hae tai liitä URL-osoite",
"search_popout.full_text_search_disabled_message": "Ei saatavilla palvelimella {domain}.", "search_popout.full_text_search_disabled_message": "Ei saatavilla palvelimella {domain}.",
"search_popout.language_code": "ISO-kielikoodi", "search_popout.language_code": "ISO-kielikoodi",
"search_popout.options": "Hakuvalinnat", "search_popout.options": "Hakuvalinnat",
"search_popout.quick_actions": "Pikatoiminnot", "search_popout.quick_actions": "Pikatoiminnot",
"search_popout.recent": "Viimeaikaiset haut", "search_popout.recent": "Viimeaikaiset haut",
"search_popout.specific_date": "tietty päivämäärä", "search_popout.specific_date": "tarkka päiväys",
"search_popout.user": "käyttäjä", "search_popout.user": "käyttäjä",
"search_results.accounts": "Profiilit", "search_results.accounts": "Profiilit",
"search_results.all": "Kaikki", "search_results.all": "Kaikki",

View file

@ -137,7 +137,7 @@
"compose.language.search": "言語を検索...", "compose.language.search": "言語を検索...",
"compose.published.body": "投稿されました!", "compose.published.body": "投稿されました!",
"compose.published.open": "開く", "compose.published.open": "開く",
"compose.saved.body": "投稿が保存されました", "compose.saved.body": "変更を保存しました。",
"compose_form.direct_message_warning_learn_more": "もっと詳しく", "compose_form.direct_message_warning_learn_more": "もっと詳しく",
"compose_form.encryption_warning": "Mastodonの投稿はエンドツーエンド暗号化に対応していません。安全に送受信されるべき情報をMastodonで共有しないでください。", "compose_form.encryption_warning": "Mastodonの投稿はエンドツーエンド暗号化に対応していません。安全に送受信されるべき情報をMastodonで共有しないでください。",
"compose_form.hashtag_warning": "この投稿は公開設定ではないのでハッシュタグの一覧に表示されません。公開投稿だけがハッシュタグで検索できます。", "compose_form.hashtag_warning": "この投稿は公開設定ではないのでハッシュタグの一覧に表示されません。公開投稿だけがハッシュタグで検索できます。",

View file

@ -114,7 +114,7 @@
"column.directory": "瀏覽個人檔案", "column.directory": "瀏覽個人檔案",
"column.domain_blocks": "已封鎖網域", "column.domain_blocks": "已封鎖網域",
"column.favourites": "最愛", "column.favourites": "最愛",
"column.firehose": "即時內容", "column.firehose": "即時河道",
"column.follow_requests": "跟隨請求", "column.follow_requests": "跟隨請求",
"column.home": "首頁", "column.home": "首頁",
"column.lists": "列表", "column.lists": "列表",

View file

@ -51,7 +51,7 @@ class FeaturedTag < ApplicationRecord
private private
def strip_name def strip_name
self.name = name&.strip&.gsub(/\A#/, '') self.name = name&.strip&.delete_prefix('#')
end end
def set_tag def set_tag

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
class REST::ApplicationSerializer < ActiveModel::Serializer class REST::ApplicationSerializer < ActiveModel::Serializer
attributes :id, :name, :website, :redirect_uri, attributes :id, :name, :website, :scopes, :redirect_uri,
:client_id, :client_secret, :vapid_key :client_id, :client_secret, :vapid_key
def id def id

View file

@ -97,8 +97,6 @@ class ActivityPub::ProcessStatusUpdateService < BaseService
end end
end end
added_media_attachments = @next_media_attachments - previous_media_attachments
@status.ordered_media_attachment_ids = @next_media_attachments.map(&:id) @status.ordered_media_attachment_ids = @next_media_attachments.map(&:id)
@media_attachments_changed = true if @status.ordered_media_attachment_ids != previous_media_attachments_ids @media_attachments_changed = true if @status.ordered_media_attachment_ids != previous_media_attachments_ids

View file

@ -4,7 +4,7 @@
= image_tag appeal.account.avatar.url(:original), alt: '', width: 40, height: 40, class: 'avatar' = image_tag appeal.account.avatar.url(:original), alt: '', width: 40, height: 40, class: 'avatar'
.log-entry__content .log-entry__content
.log-entry__title .log-entry__title
= t(appeal.strike.action, scope: 'admin.strikes.actions', name: content_tag(:span, appeal.strike.account.username, class: 'username'), target: content_tag(:span, appeal.account.username, class: 'target')).html_safe = strike_action_label(appeal)
.log-entry__timestamp .log-entry__timestamp
%time.formatted{ datetime: appeal.strike.created_at.iso8601 } %time.formatted{ datetime: appeal.strike.created_at.iso8601 }
= l(appeal.strike.created_at) = l(appeal.strike.created_at)

View file

@ -1,38 +1,5 @@
{ {
"ignored_warnings": [ "ignored_warnings": [
{
"warning_type": "Cross-Site Scripting",
"warning_code": 2,
"fingerprint": "71cf98c8235b5cfa9946b5db8fdc1a2f3a862566abb34e4542be6f3acae78233",
"check_name": "CrossSiteScripting",
"message": "Unescaped model attribute",
"file": "app/views/admin/disputes/appeals/_appeal.html.haml",
"line": 7,
"link": "https://brakemanscanner.org/docs/warning_types/cross_site_scripting",
"code": "t((Unresolved Model).new.strike.action, :scope => \"admin.strikes.actions\", :name => content_tag(:span, (Unresolved Model).new.strike.account.username, :class => \"username\"), :target => content_tag(:span, (Unresolved Model).new.account.username, :class => \"target\"))",
"render_path": [
{
"type": "template",
"name": "admin/disputes/appeals/index",
"line": 20,
"file": "app/views/admin/disputes/appeals/index.html.haml",
"rendered": {
"name": "admin/disputes/appeals/_appeal",
"file": "app/views/admin/disputes/appeals/_appeal.html.haml"
}
}
],
"location": {
"type": "template",
"template": "admin/disputes/appeals/_appeal"
},
"user_input": "(Unresolved Model).new.strike",
"confidence": "Weak",
"cwe_id": [
79
],
"note": ""
},
{ {
"warning_type": "Cross-Site Scripting", "warning_type": "Cross-Site Scripting",
"warning_code": 4, "warning_code": 4,

View file

@ -9,9 +9,6 @@ Rails.application.config.middleware.use OmniAuth::Builder do
end end
Devise.setup do |config| Devise.setup do |config|
# Devise omniauth strategies
options = {}
# CAS strategy # CAS strategy
if ENV['CAS_ENABLED'] == 'true' if ENV['CAS_ENABLED'] == 'true'
cas_options = {} cas_options = {}

View file

@ -53,3 +53,7 @@ sk:
position: position:
elevated: nemôže byť vyššia ako vaša súčasná rola elevated: nemôže byť vyššia ako vaša súčasná rola
own_role: nie je možné zmeniť s vašou aktuálnou rolou own_role: nie je možné zmeniť s vašou aktuálnou rolou
webhook:
attributes:
events:
invalid_permissions: nemožno zahrnúť udalosti, ku ktorým nemáte práva

View file

@ -129,6 +129,7 @@ sk:
crypto: Šifrovanie End-to-end crypto: Šifrovanie End-to-end
favourites: Obľúbené favourites: Obľúbené
filters: Filtre filters: Filtre
follow: Sledovanie, stlmenie a blokovanie
follows: Sledovania follows: Sledovania
lists: Zoznamy lists: Zoznamy
media: Mediálne prílohy media: Mediálne prílohy
@ -148,9 +149,19 @@ sk:
scopes: scopes:
admin:read: prezeraj všetky dáta na serveri admin:read: prezeraj všetky dáta na serveri
admin:read:accounts: prezeraj chúlostivé informácie na všetkých účtoch admin:read:accounts: prezeraj chúlostivé informácie na všetkých účtoch
admin:read:canonical_email_blocks: čítať citlivé informácie všetkých kanonických e-mailových blokov
admin:read:domain_allows: čítať citlivé informácie zo všetkých povolených domén
admin:read:domain_blocks: čítať citlivé informácie zo všetkých blokov domén
admin:read:email_domain_blocks: čítať citlivé informácie zo všetkých blokov emailových domén
admin:read:ip_blocks: čítať citlivé informácie zo všetkých blokov IP
admin:read:reports: čítaj chulostivé informácie o všetkých hláseniach a nahlásených účtoch admin:read:reports: čítaj chulostivé informácie o všetkých hláseniach a nahlásených účtoch
admin:write: uprav všetky dáta na serveri admin:write: uprav všetky dáta na serveri
admin:write:accounts: urob moderovacie úkony na účtoch admin:write:accounts: urob moderovacie úkony na účtoch
admin:write:canonical_email_blocks: vykonať akcie moderácie na kanonických emailových blokoch
admin:write:domain_allows: vykonať akcie moderácie na povolených doménach
admin:write:domain_blocks: vykonať akcie moderácie na doménových blokoch
admin:write:email_domain_blocks: vykonať akcie moderácie na blokoch emailových domén
admin:write:ip_blocks: vykonať akcie moderácie na blokoch IP
admin:write:reports: urob moderovacie úkony voči hláseniam admin:write:reports: urob moderovacie úkony voči hláseniam
crypto: používať end-to-end šifrovanie crypto: používať end-to-end šifrovanie
follow: uprav vzťahy svojho účtu follow: uprav vzťahy svojho účtu
@ -159,6 +170,7 @@ sk:
read:accounts: prezri si informácie o účte read:accounts: prezri si informácie o účte
read:blocks: prezri svoje bloky read:blocks: prezri svoje bloky
read:bookmarks: pozri svoje záložky read:bookmarks: pozri svoje záložky
read:favourites: zobraziť vaše obľúbené
read:filters: prezri svoje filtrovanie read:filters: prezri svoje filtrovanie
read:follows: prezri si svoje sledovania read:follows: prezri si svoje sledovania
read:lists: prezri si svoje zoznamy read:lists: prezri si svoje zoznamy

View file

@ -33,7 +33,7 @@ fi:
accounts: accounts:
add_email_domain_block: Estä sähköpostiverkkotunnus add_email_domain_block: Estä sähköpostiverkkotunnus
approve: Hyväksy approve: Hyväksy
approved_msg: Käyttäjän %{username} liittymishakemus hyväksyttiin approved_msg: Käyttäjän %{username} rekisteröitymishakemus hyväksyttiin
are_you_sure: Oletko varma? are_you_sure: Oletko varma?
avatar: Profiilikuva avatar: Profiilikuva
by_domain: Verkkotunnus by_domain: Verkkotunnus
@ -364,7 +364,7 @@ fi:
other: "<strong>%{count}</strong> odottavaa käyttäjää" other: "<strong>%{count}</strong> odottavaa käyttäjää"
resolved_reports: ratkaistut raportit resolved_reports: ratkaistut raportit
software: Ohjelmisto software: Ohjelmisto
sources: Rekisteröitymisen lähteet sources: Rekisteröitymislähteet
space: Tilankäyttö space: Tilankäyttö
title: Hallintapaneeli title: Hallintapaneeli
top_languages: Aktiivisimmat kielet top_languages: Aktiivisimmat kielet
@ -440,7 +440,7 @@ fi:
title: Estä uusi sähköpostiverkkotunnus title: Estä uusi sähköpostiverkkotunnus
no_email_domain_block_selected: Sähköpostin verkkotunnuksia ei muutettu, koska yhtään ei ollut valittuna no_email_domain_block_selected: Sähköpostin verkkotunnuksia ei muutettu, koska yhtään ei ollut valittuna
not_permitted: Ei sallittu not_permitted: Ei sallittu
resolved_dns_records_hint_html: Verkkotunnuksen nimi määräytyy seuraaviin MX-verkkotunnuksiin, jotka ovat viime kädessä vastuussa sähköpostin vastaanottamisesta. MX-verkkotunnuksen estäminen estää kirjautumisen mistä tahansa sähköpostiosoitteesta, joka käyttää samaa MX-verkkotunnusta, vaikka näkyvä verkkotunnuksen nimi olisikin erilainen. <strong>Varo estämästä suuria sähköpostin palveluntarjoajia.</strong> resolved_dns_records_hint_html: Verkkotunnuksen nimi määräytyy seuraaviin MX-verkkotunnuksiin, jotka ovat viime kädessä vastuussa sähköpostin vastaanottamisesta. MX-verkkotunnuksen estäminen estää rekisteröitymisen mistä tahansa sähköpostiosoitteesta, joka käyttää samaa MX-verkkotunnusta, vaikka näkyvä verkkotunnuksen nimi olisikin erilainen. <strong>Varo estämästä suuria sähköpostin palveluntarjoajia.</strong>
resolved_through_html: Ratkaistu %{domain} kautta resolved_through_html: Ratkaistu %{domain} kautta
title: Estetyt sähköpostiverkkotunnukset title: Estetyt sähköpostiverkkotunnukset
export_domain_allows: export_domain_allows:
@ -1405,7 +1405,7 @@ fi:
migrations: migrations:
acct: Muuttanut tunnukselle acct: Muuttanut tunnukselle
cancel: Peruuta uudelleenohjaus cancel: Peruuta uudelleenohjaus
cancel_explanation: Uudelleenohjauksen peruuttaminen aktivoi uudelleen nykyisen tilisi, mutta ei palauta seuraajia, jotka on siirretty kyseiselle tilille. cancel_explanation: Uudelleenohjauksen peruuttaminen aktivoi nykyisen tilisi uudelleen mutta ei palauta seuraajia, jotka on siirretty kyseiselle tilille.
cancelled_msg: Uudelleenohjaus peruttu onnistuneesti. cancelled_msg: Uudelleenohjaus peruttu onnistuneesti.
errors: errors:
already_moved: on sama tili, jonka olet jo siirtänyt already_moved: on sama tili, jonka olet jo siirtänyt

View file

@ -59,14 +59,14 @@ fi:
setting_display_media_default: Piilota arkaluonteiseksi merkitty media setting_display_media_default: Piilota arkaluonteiseksi merkitty media
setting_display_media_hide_all: Piilota media aina setting_display_media_hide_all: Piilota media aina
setting_display_media_show_all: Näytä media aina setting_display_media_show_all: Näytä media aina
setting_use_blurhash: Liukuvärit perustuvat piilotettujen kuvien väreihin, mutta sumentavat yksityiskohdat setting_use_blurhash: Liukuvärit perustuvat piilotettujen kuvien väreihin mutta sumentavat yksityiskohdat
setting_use_pending_items: Piilota aikajanan päivitykset napsautuksen taakse syötteen automaattisen vierityksen sijaan setting_use_pending_items: Piilota aikajanan päivitykset napsautuksen taakse syötteen automaattisen vierityksen sijaan
username: Voit käyttää kirjaimia, numeroita ja alaviivoja username: Voit käyttää kirjaimia, numeroita ja alaviivoja
whole_word: Kun avainsana tai -fraasi on kokonaan aakkosnumeerinen, se on voimassa vain, jos se vastaa koko sanaa whole_word: Kun avainsana tai -fraasi on kokonaan aakkosnumeerinen, se on voimassa vain, jos se vastaa koko sanaa
domain_allow: domain_allow:
domain: Tämä verkkotunnus voi noutaa tietoja tältä palvelimelta ja sieltä saapuvat tiedot käsitellään ja tallennetaan domain: Tämä verkkotunnus voi noutaa tietoja tältä palvelimelta ja sieltä saapuvat tiedot käsitellään ja tallennetaan
email_domain_block: email_domain_block:
domain: Tämä voi olla se verkkotunnus, joka näkyy sähköpostiosoitteessa tai MX tietueessa jota se käyttää. Ne tarkistetaan rekisteröitymisen yhteydessä. domain: Tämä voi olla verkkotunnus, joka näkyy sähköpostiosoitteessa tai sen käyttämässä MX-tietueessa. Ne tarkistetaan rekisteröitymisen yhteydessä.
with_dns_records: Annetun verkkotunnuksen DNS-tietueet yritetään ratkaista ja tulokset myös estetään with_dns_records: Annetun verkkotunnuksen DNS-tietueet yritetään ratkaista ja tulokset myös estetään
featured_tag: featured_tag:
name: 'Tässä muutamia hiljattain käyttämiäsi aihetunnisteita:' name: 'Tässä muutamia hiljattain käyttämiäsi aihetunnisteita:'
@ -112,7 +112,7 @@ fi:
ip: Kirjoita IPv4- tai IPv6-osoite. Voit estää kokonaisia alueita käyttämällä CIDR-syntaksia. Varo, että et lukitse itseäsi ulos! ip: Kirjoita IPv4- tai IPv6-osoite. Voit estää kokonaisia alueita käyttämällä CIDR-syntaksia. Varo, että et lukitse itseäsi ulos!
severities: severities:
no_access: Estä pääsy kaikkiin resursseihin no_access: Estä pääsy kaikkiin resursseihin
sign_up_block: Uudet kirjautumiset eivät ole mahdollisia sign_up_block: Uudet rekisteröitymiset eivät ole mahdollisia
sign_up_requires_approval: Uudet rekisteröitymiset edellyttävät hyväksyntääsi sign_up_requires_approval: Uudet rekisteröitymiset edellyttävät hyväksyntääsi
severity: Valitse, mitä tapahtuu tämän IP-osoitteen pyynnöille severity: Valitse, mitä tapahtuu tämän IP-osoitteen pyynnöille
rule: rule:

View file

@ -30,7 +30,7 @@ zh-TW:
suspend: 禁止所有對該帳號任何互動,並且刪除其內容。三十天內可以撤銷此動作。關閉所有對此帳號之檢舉報告。 suspend: 禁止所有對該帳號任何互動,並且刪除其內容。三十天內可以撤銷此動作。關閉所有對此帳號之檢舉報告。
warning_preset_id: 選用。您仍可在預設的結尾新增自訂文字 warning_preset_id: 選用。您仍可在預設的結尾新增自訂文字
announcement: announcement:
all_day: 核取後,只會顯示出時間範圍中的日期部分 all_day: 當選取時,僅顯示出時間範圍中的日期部分
ends_at: 可選的,公告會於該時間點自動取消發布 ends_at: 可選的,公告會於該時間點自動取消發布
scheduled_at: 空白則立即發布公告 scheduled_at: 空白則立即發布公告
starts_at: 可選的,讓公告在特定時間範圍內顯示 starts_at: 可選的,讓公告在特定時間範圍內顯示
@ -60,7 +60,7 @@ zh-TW:
setting_display_media_hide_all: 總是隱藏所有媒體 setting_display_media_hide_all: 總是隱藏所有媒體
setting_display_media_show_all: 總是顯示標為敏感內容的媒體 setting_display_media_show_all: 總是顯示標為敏感內容的媒體
setting_use_blurhash: 彩色漸層圖樣是基於隱藏媒體內容顏色產生,所有細節將變得模糊 setting_use_blurhash: 彩色漸層圖樣是基於隱藏媒體內容顏色產生,所有細節將變得模糊
setting_use_pending_items: 關閉自動捲動更新,時間軸只會於點擊後更新 setting_use_pending_items: 關閉自動捲動更新,時間軸於點擊後更新
username: 您可以使用字幕、數字與底線 username: 您可以使用字幕、數字與底線
whole_word: 如果關鍵字或詞組僅有字母與數字,則其將只在符合整個單字的時候才會套用 whole_word: 如果關鍵字或詞組僅有字母與數字,則其將只在符合整個單字的時候才會套用
domain_allow: domain_allow:

View file

@ -578,7 +578,7 @@ zh-TW:
mark_as_sensitive_description_html: 被檢舉的嘟文中的媒體將會被標記為敏感內容,並將會記錄一次警告,以協助您升級同一帳號未來的違規行為。 mark_as_sensitive_description_html: 被檢舉的嘟文中的媒體將會被標記為敏感內容,並將會記錄一次警告,以協助您升級同一帳號未來的違規行為。
other_description_html: 檢視更多控制帳號行為以及自訂檢舉帳號通知之選項。 other_description_html: 檢視更多控制帳號行為以及自訂檢舉帳號通知之選項。
resolve_description_html: 被檢舉的帳號將不被採取任何行動,不會加以刪除線標記,並且此份報告將被關閉。 resolve_description_html: 被檢舉的帳號將不被採取任何行動,不會加以刪除線標記,並且此份報告將被關閉。
silence_description_html: 此帳號僅對已跟隨帳號之使用者或手動查詢可見,將大幅度限制觸及範圍。此設定可隨時被還原。關閉所有對此帳號之檢舉報告。 silence_description_html: 此帳號僅對已跟隨帳號之使用者或手動查詢可見,將大幅度限制觸及範圍。此設定可隨時被還原。關閉所有對此帳號之檢舉報告。
suspend_description_html: 此帳號及其所有內容將不可被存取並且最終被移除,並且無法與之進行互動。三十天內可以撤銷此動作。關閉所有對此帳號之檢舉報告。 suspend_description_html: 此帳號及其所有內容將不可被存取並且最終被移除,並且無法與之進行互動。三十天內可以撤銷此動作。關閉所有對此帳號之檢舉報告。
actions_description_html: 決定應對此報告採取何種行動。若您對檢舉之帳號採取懲罰措施,則將對他們發送 e-mail 通知,如非選擇了 <strong>垃圾郵件</strong> 類別。 actions_description_html: 決定應對此報告採取何種行動。若您對檢舉之帳號採取懲罰措施,則將對他們發送 e-mail 通知,如非選擇了 <strong>垃圾郵件</strong> 類別。
actions_description_remote_html: 決定將對此檢舉報告採取何種動作。這將僅作用於<strong>您的伺服器</strong>與此遠端帳號及其內容之通訊行為。 actions_description_remote_html: 決定將對此檢舉報告採取何種動作。這將僅作用於<strong>您的伺服器</strong>與此遠端帳號及其內容之通訊行為。

4
db/migrate/.rubocop.yml Normal file
View file

@ -0,0 +1,4 @@
inherit_from: ../../.rubocop.yml
Naming/VariableNumber:
CheckSymbols: false

View file

@ -19,7 +19,6 @@ class AddSilencedAtSuspendedAtToAccounts < ActiveRecord::Migration[5.2]
# Record suspend date of blocks and silences for users whose limitations match # Record suspend date of blocks and silences for users whose limitations match
# a domain block # a domain block
DomainBlock.where(severity: [:silence, :suspend]).find_each do |block| DomainBlock.where(severity: [:silence, :suspend]).find_each do |block|
scope = block.accounts
if block.suspend? if block.suspend?
block.accounts.where(suspended: true).in_batches.update_all(suspended_at: block.created_at) block.accounts.where(suspended: true).in_batches.update_all(suspended_at: block.created_at)
else else

View file

@ -18,7 +18,6 @@ class RemoveSuspendedSilencedAccountFields < ActiveRecord::Migration[5.2]
# Record suspend date of blocks and silences for users whose limitations match # Record suspend date of blocks and silences for users whose limitations match
# a domain block # a domain block
DomainBlock.where(severity: [:silence, :suspend]).find_each do |block| DomainBlock.where(severity: [:silence, :suspend]).find_each do |block|
scope = block.accounts
if block.suspend? if block.suspend?
block.accounts.where(suspended: true).in_batches.update_all(suspended_at: block.created_at) block.accounts.where(suspended: true).in_batches.update_all(suspended_at: block.created_at)
else else

View file

@ -18,10 +18,14 @@ RSpec.describe Admin::Disputes::AppealsController do
describe 'GET #index' do describe 'GET #index' do
let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) } let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
it 'lists appeals' do before { appeal }
it 'returns a page that lists details of appeals' do
get :index get :index
expect(response).to have_http_status(200) expect(response).to have_http_status(:success)
expect(response.body).to include("<span class=\"username\">#{strike.account.username}</span>")
expect(response.body).to include("<span class=\"target\">#{appeal.account.username}</span>")
end end
end end

View file

@ -62,7 +62,7 @@ describe AccountControllerConcern do
end end
it 'sets link headers' do it 'sets link headers' do
account = Fabricate(:account, username: 'username') Fabricate(:account, username: 'username')
get 'success', params: { account_username: 'username' } get 'success', params: { account_username: 'username' }
expect(response.headers['Link'].to_s).to eq '<http://test.host/.well-known/webfinger?resource=acct%3Ausername%40cb6e6126.ngrok.io>; rel="lrdd"; type="application/jrd+json", <https://cb6e6126.ngrok.io/users/username>; rel="alternate"; type="application/activity+json"' expect(response.headers['Link'].to_s).to eq '<http://test.host/.well-known/webfinger?resource=acct%3Ausername%40cb6e6126.ngrok.io>; rel="lrdd"; type="application/jrd+json", <https://cb6e6126.ngrok.io/users/username>; rel="alternate"; type="application/activity+json"'
end end

View file

@ -0,0 +1,21 @@
# frozen_string_literal: true
require 'rails_helper'
describe Admin::DisputesHelper do
describe 'strike_action_label' do
it 'returns html describing the appeal' do
adam = Account.new(username: 'Adam')
becky = Account.new(username: 'Becky')
strike = AccountWarning.new(account: adam, action: :suspend)
appeal = Appeal.new(strike: strike, account: becky)
expected = <<~OUTPUT.strip
<span class="username">Adam</span> suspended <span class="target">Becky</span>'s account
OUTPUT
result = helper.strike_action_label(appeal)
expect(result).to eq(expected)
end
end
end

View file

@ -158,14 +158,14 @@ describe JsonLdHelper do
it 'deems a safe compacting as such' do it 'deems a safe compacting as such' do
json['object'].delete('convo') json['object'].delete('convo')
compacted = compact(json) compacted = compact(json)
deemed_compatible = patch_for_forwarding!(json, compacted) patch_for_forwarding!(json, compacted)
expect(compacted['to']).to eq ['https://www.w3.org/ns/activitystreams#Public'] expect(compacted['to']).to eq ['https://www.w3.org/ns/activitystreams#Public']
expect(safe_for_forwarding?(json, compacted)).to be true expect(safe_for_forwarding?(json, compacted)).to be true
end end
it 'deems an unsafe compacting as such' do it 'deems an unsafe compacting as such' do
compacted = compact(json) compacted = compact(json)
deemed_compatible = patch_for_forwarding!(json, compacted) patch_for_forwarding!(json, compacted)
expect(compacted['to']).to eq ['https://www.w3.org/ns/activitystreams#Public'] expect(compacted['to']).to eq ['https://www.w3.org/ns/activitystreams#Public']
expect(safe_for_forwarding?(json, compacted)).to be false expect(safe_for_forwarding?(json, compacted)).to be false
end end

View file

@ -1356,4 +1356,254 @@ describe Mastodon::CLI::Accounts do
end end
end end
end end
describe '#prune' do
let!(:local_account) { Fabricate(:account) }
let!(:bot_account) { Fabricate(:account, bot: true, domain: 'example.com') }
let!(:group_account) { Fabricate(:account, actor_type: 'Group', domain: 'example.com') }
let!(:mentioned_account) { Fabricate(:account, domain: 'example.com') }
let!(:prunable_accounts) do
Fabricate.times(3, :account, domain: 'example.com', bot: false, suspended_at: nil, silenced_at: nil)
end
before do
Fabricate(:mention, account: mentioned_account, status: Fabricate(:status, account: Fabricate(:account)))
stub_parallelize_with_progress!
end
it 'prunes all remote accounts with no interactions with local users' do
cli.prune
prunable_account_ids = prunable_accounts.pluck(:id)
expect(Account.where(id: prunable_account_ids).count).to eq(0)
end
it 'displays a successful message' do
expect { cli.prune }.to output(
a_string_including("OK, pruned #{prunable_accounts.size} accounts")
).to_stdout
end
it 'does not prune local accounts' do
cli.prune
expect(Account.exists?(id: local_account.id)).to be(true)
end
it 'does not prune bot accounts' do
cli.prune
expect(Account.exists?(id: bot_account.id)).to be(true)
end
it 'does not prune group accounts' do
cli.prune
expect(Account.exists?(id: group_account.id)).to be(true)
end
it 'does not prune accounts that have been mentioned' do
cli.prune
expect(Account.exists?(id: mentioned_account.id)).to be true
end
context 'with --dry-run option' do
before do
cli.options = { dry_run: true }
end
it 'does not prune any account' do
cli.prune
prunable_account_ids = prunable_accounts.pluck(:id)
expect(Account.where(id: prunable_account_ids).count).to eq(prunable_accounts.size)
end
it 'displays a successful message with (DRY RUN)' do
expect { cli.prune }.to output(
a_string_including("OK, pruned #{prunable_accounts.size} accounts (DRY RUN)")
).to_stdout
end
end
end
describe '#migrate' do
let!(:source_account) { Fabricate(:account) }
let!(:target_account) { Fabricate(:account, domain: 'example.com') }
let(:arguments) { [source_account.username] }
let(:resolve_account_service) { instance_double(ResolveAccountService, call: nil) }
let(:move_service) { instance_double(MoveService, call: nil) }
before do
allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service)
allow(MoveService).to receive(:new).and_return(move_service)
end
shared_examples 'a successful migration' do
it 'calls the MoveService for the last migration' do
cli.invoke(:migrate, arguments, options)
last_migration = source_account.migrations.last
expect(move_service).to have_received(:call).with(last_migration).once
end
it 'displays a successful message' do
expect { cli.invoke(:migrate, arguments, options) }.to output(
a_string_including("OK, migrated #{source_account.acct} to #{target_account.acct}")
).to_stdout
end
end
context 'when both --replay and --target options are given' do
let(:options) { { replay: true, target: "#{target_account.username}@example.com" } }
it 'exits with an error message indicating that using both options is not possible' do
expect { cli.invoke(:migrate, arguments, options) }.to output(
a_string_including('Use --replay or --target, not both')
).to_stdout
.and raise_error(SystemExit)
end
end
context 'when no option is given' do
it 'exits with an error message indicating that at least one option must be used' do
expect { cli.invoke(:migrate, arguments, {}) }.to output(
a_string_including('Use either --replay or --target')
).to_stdout
.and raise_error(SystemExit)
end
end
context 'when the given username is not found' do
let(:arguments) { ['non_existent_username'] }
it 'exits with an error message indicating that there is no such account' do
expect { cli.invoke(:migrate, arguments, replay: true) }.to output(
a_string_including("No such account: #{arguments.first}")
).to_stdout
.and raise_error(SystemExit)
end
end
context 'with --replay option' do
let(:options) { { replay: true } }
context 'when the specified account has no previous migrations' do
it 'exits with an error message indicating that the given account has no previous migrations' do
expect { cli.invoke(:migrate, arguments, options) }.to output(
a_string_including('The specified account has not performed any migration')
).to_stdout
.and raise_error(SystemExit)
end
end
context 'when the specified account has a previous migration' do
before do
allow(resolve_account_service).to receive(:call).with(source_account.acct, any_args).and_return(source_account)
allow(resolve_account_service).to receive(:call).with(target_account.acct, any_args).and_return(target_account)
target_account.aliases.create!(acct: source_account.acct)
source_account.migrations.create!(acct: target_account.acct)
source_account.update!(moved_to_account: target_account)
end
it_behaves_like 'a successful migration'
context 'when the specified account is redirecting to a different target account' do
before do
source_account.update!(moved_to_account: nil)
end
it 'exits with an error message' do
expect { cli.invoke(:migrate, arguments, options) }.to output(
a_string_including('The specified account is not redirecting to its last migration target. Use --force if you want to replay the migration anyway')
).to_stdout
.and raise_error(SystemExit)
end
end
context 'with --force option' do
let(:options) { { replay: true, force: true } }
it_behaves_like 'a successful migration'
end
end
end
context 'with --target option' do
let(:options) { { target: target_account.acct } }
before do
allow(resolve_account_service).to receive(:call).with(source_account.acct, any_args).and_return(source_account)
allow(resolve_account_service).to receive(:call).with(target_account.acct, any_args).and_return(target_account)
end
context 'when the specified target account is not found' do
before do
allow(resolve_account_service).to receive(:call).with(target_account.acct).and_return(nil)
end
it 'exits with an error message indicating that there is no such account' do
expect { cli.invoke(:migrate, arguments, options) }.to output(
a_string_including("The specified target account could not be found: #{options[:target]}")
).to_stdout
.and raise_error(SystemExit)
end
end
context 'when the specified target account exists' do
before do
target_account.aliases.create!(acct: source_account.acct)
end
it 'creates a migration for the specified account with the target account' do
cli.invoke(:migrate, arguments, options)
last_migration = source_account.migrations.last
expect(last_migration.acct).to eq(target_account.acct)
end
it_behaves_like 'a successful migration'
end
context 'when the migration record is invalid' do
it 'exits with an error indicating that the validation failed' do
expect { cli.invoke(:migrate, arguments, options) }.to output(
a_string_including('Error: Validation failed')
).to_stdout
.and raise_error(SystemExit)
end
end
context 'when the specified account is redirecting to a different target account' do
before do
allow(Account).to receive(:find_local).with(source_account.username).and_return(source_account)
allow(source_account).to receive(:moved_to_account_id).and_return(-1)
end
it 'exits with an error message' do
expect { cli.invoke(:migrate, arguments, options) }.to output(
a_string_including('The specified account is redirecting to a different target account. Use --force if you want to change the migration target')
).to_stdout
.and raise_error(SystemExit)
end
end
context 'with --target and --force options' do
let(:options) { { target: target_account.acct, force: true } }
before do
target_account.aliases.create!(acct: source_account.acct)
allow(Account).to receive(:find_local).with(source_account.username).and_return(source_account)
allow(source_account).to receive(:moved_to_account_id).and_return(-1)
end
it_behaves_like 'a successful migration'
end
end
end
end end

View file

@ -356,7 +356,7 @@ RSpec.describe Account do
end end
it 'does not return suspended users' do it 'does not return suspended users' do
match = Fabricate( Fabricate(
:account, :account,
display_name: 'Display Name', display_name: 'Display Name',
username: 'username', username: 'username',
@ -483,7 +483,7 @@ RSpec.describe Account do
end end
it 'does not return non-followed accounts' do it 'does not return non-followed accounts' do
match = Fabricate( Fabricate(
:account, :account,
display_name: 'A & l & i & c & e', display_name: 'A & l & i & c & e',
username: 'username', username: 'username',
@ -495,7 +495,7 @@ RSpec.describe Account do
end end
it 'does not return suspended users' do it 'does not return suspended users' do
match = Fabricate( Fabricate(
:account, :account,
display_name: 'Display Name', display_name: 'Display Name',
username: 'username', username: 'username',
@ -535,7 +535,7 @@ RSpec.describe Account do
end end
it 'does not return suspended users' do it 'does not return suspended users' do
match = Fabricate( Fabricate(
:account, :account,
display_name: 'Display Name', display_name: 'Display Name',
username: 'username', username: 'username',
@ -719,10 +719,10 @@ RSpec.describe Account do
context 'when is local' do context 'when is local' do
it 'is invalid if the username is not unique in case-insensitive comparison among local accounts' do it 'is invalid if the username is not unique in case-insensitive comparison among local accounts' do
account_1 = Fabricate(:account, username: 'the_doctor') _account = Fabricate(:account, username: 'the_doctor')
account_2 = Fabricate.build(:account, username: 'the_Doctor') non_unique_account = Fabricate.build(:account, username: 'the_Doctor')
account_2.valid? non_unique_account.valid?
expect(account_2).to model_have_error_on_field(:username) expect(non_unique_account).to model_have_error_on_field(:username)
end end
it 'is invalid if the username is reserved' do it 'is invalid if the username is reserved' do
@ -743,9 +743,9 @@ RSpec.describe Account do
end end
it 'is valid if we are creating a possibly-conflicting instance actor account' do it 'is valid if we are creating a possibly-conflicting instance actor account' do
account_1 = Fabricate(:account, username: 'examplecom') _account = Fabricate(:account, username: 'examplecom')
account_2 = Fabricate.build(:account, id: -99, actor_type: 'Application', locked: true, username: 'example.com') instance_account = Fabricate.build(:account, id: -99, actor_type: 'Application', locked: true, username: 'example.com')
expect(account_2.valid?).to be true expect(instance_account.valid?).to be true
end end
it 'is invalid if the username doesn\'t only contains letters, numbers and underscores' do it 'is invalid if the username doesn\'t only contains letters, numbers and underscores' do
@ -877,17 +877,17 @@ RSpec.describe Account do
describe 'remote' do describe 'remote' do
it 'returns an array of accounts who have a domain' do it 'returns an array of accounts who have a domain' do
account_1 = Fabricate(:account, domain: nil) _account = Fabricate(:account, domain: nil)
account_2 = Fabricate(:account, domain: 'example.com') account_with_domain = Fabricate(:account, domain: 'example.com')
expect(described_class.remote).to contain_exactly(account_2) expect(described_class.remote).to contain_exactly(account_with_domain)
end end
end end
describe 'local' do describe 'local' do
it 'returns an array of accounts who do not have a domain' do it 'returns an array of accounts who do not have a domain' do
account_1 = Fabricate(:account, domain: nil) local_account = Fabricate(:account, domain: nil)
account_2 = Fabricate(:account, domain: 'example.com') _account_with_domain = Fabricate(:account, domain: 'example.com')
expect(described_class.where('id > 0').local).to contain_exactly(account_1) expect(described_class.where('id > 0').local).to contain_exactly(local_account)
end end
end end
@ -911,17 +911,17 @@ RSpec.describe Account do
describe 'silenced' do describe 'silenced' do
it 'returns an array of accounts who are silenced' do it 'returns an array of accounts who are silenced' do
account_1 = Fabricate(:account, silenced: true) silenced_account = Fabricate(:account, silenced: true)
account_2 = Fabricate(:account, silenced: false) _account = Fabricate(:account, silenced: false)
expect(described_class.silenced).to contain_exactly(account_1) expect(described_class.silenced).to contain_exactly(silenced_account)
end end
end end
describe 'suspended' do describe 'suspended' do
it 'returns an array of accounts who are suspended' do it 'returns an array of accounts who are suspended' do
account_1 = Fabricate(:account, suspended: true) suspended_account = Fabricate(:account, suspended: true)
account_2 = Fabricate(:account, suspended: false) _account = Fabricate(:account, suspended: false)
expect(described_class.suspended).to contain_exactly(account_1) expect(described_class.suspended).to contain_exactly(suspended_account)
end end
end end

View file

@ -11,10 +11,10 @@ RSpec.describe DomainBlock do
end end
it 'is invalid if the same normalized domain already exists' do it 'is invalid if the same normalized domain already exists' do
domain_block_1 = Fabricate(:domain_block, domain: 'にゃん') _domain_block = Fabricate(:domain_block, domain: 'にゃん')
domain_block_2 = Fabricate.build(:domain_block, domain: 'xn--r9j5b5b') domain_block_with_normalized_value = Fabricate.build(:domain_block, domain: 'xn--r9j5b5b')
domain_block_2.valid? domain_block_with_normalized_value.valid?
expect(domain_block_2).to model_have_error_on_field(:domain) expect(domain_block_with_normalized_value).to model_have_error_on_field(:domain)
end end
end end

View file

@ -166,7 +166,7 @@ RSpec.describe Status do
describe '#replies_count' do describe '#replies_count' do
it 'is the number of replies' do it 'is the number of replies' do
reply = Fabricate(:status, account: bob, thread: subject) Fabricate(:status, account: bob, thread: subject)
expect(subject.replies_count).to eq 1 expect(subject.replies_count).to eq 1
end end

View file

@ -55,17 +55,17 @@ RSpec.describe User do
describe 'scopes' do describe 'scopes' do
describe 'recent' do describe 'recent' do
it 'returns an array of recent users ordered by id' do it 'returns an array of recent users ordered by id' do
user_1 = Fabricate(:user) first_user = Fabricate(:user)
user_2 = Fabricate(:user) second_user = Fabricate(:user)
expect(described_class.recent).to eq [user_2, user_1] expect(described_class.recent).to eq [second_user, first_user]
end end
end end
describe 'confirmed' do describe 'confirmed' do
it 'returns an array of users who are confirmed' do it 'returns an array of users who are confirmed' do
user_1 = Fabricate(:user, confirmed_at: nil) Fabricate(:user, confirmed_at: nil)
user_2 = Fabricate(:user, confirmed_at: Time.zone.now) confirmed_user = Fabricate(:user, confirmed_at: Time.zone.now)
expect(described_class.confirmed).to contain_exactly(user_2) expect(described_class.confirmed).to contain_exactly(confirmed_user)
end end
end end

View file

@ -37,7 +37,7 @@ RSpec.describe WebauthnCredential do
end end
it 'is invalid if already exist a webauthn credential with the same external id' do it 'is invalid if already exist a webauthn credential with the same external id' do
existing_webauthn_credential = Fabricate(:webauthn_credential, external_id: '_Typ0ygudDnk9YUVWLQayw') Fabricate(:webauthn_credential, external_id: '_Typ0ygudDnk9YUVWLQayw')
new_webauthn_credential = Fabricate.build(:webauthn_credential, external_id: '_Typ0ygudDnk9YUVWLQayw') new_webauthn_credential = Fabricate.build(:webauthn_credential, external_id: '_Typ0ygudDnk9YUVWLQayw')
new_webauthn_credential.valid? new_webauthn_credential.valid?
@ -47,7 +47,7 @@ RSpec.describe WebauthnCredential do
it 'is invalid if user already registered a webauthn credential with the same nickname' do it 'is invalid if user already registered a webauthn credential with the same nickname' do
user = Fabricate(:user) user = Fabricate(:user)
existing_webauthn_credential = Fabricate(:webauthn_credential, user_id: user.id, nickname: 'USB Key') Fabricate(:webauthn_credential, user_id: user.id, nickname: 'USB Key')
new_webauthn_credential = Fabricate.build(:webauthn_credential, user_id: user.id, nickname: 'USB Key') new_webauthn_credential = Fabricate.build(:webauthn_credential, user_id: user.id, nickname: 'USB Key')
new_webauthn_credential.valid? new_webauthn_credential.valid?

View file

@ -9,7 +9,8 @@ describe 'Credentials' do
end end
context 'with an oauth token' do context 'with an oauth token' do
let(:token) { Fabricate(:accessible_access_token, scopes: 'read', application: Fabricate(:application)) } let(:application) { Fabricate(:application, scopes: 'read') }
let(:token) { Fabricate(:accessible_access_token, application: application) }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
it 'returns the app information correctly', :aggregate_failures do it 'returns the app information correctly', :aggregate_failures do
@ -21,7 +22,35 @@ describe 'Credentials' do
a_hash_including( a_hash_including(
name: token.application.name, name: token.application.name,
website: token.application.website, website: token.application.website,
vapid_key: Rails.configuration.x.vapid_public_key vapid_key: Rails.configuration.x.vapid_public_key,
scopes: token.application.scopes.map(&:to_s),
client_id: token.application.uid
)
)
end
end
context 'with a non-read scoped oauth token' do
let(:application) { Fabricate(:application, scopes: 'admin:write') }
let(:token) { Fabricate(:accessible_access_token, application: application) }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
it 'returns http success' 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(
name: token.application.name,
website: token.application.website,
vapid_key: Rails.configuration.x.vapid_public_key,
scopes: token.application.scopes.map(&:to_s),
client_id: token.application.uid
) )
) )
end end
@ -36,5 +65,49 @@ describe 'Credentials' do
expect(response).to have_http_status(401) expect(response).to have_http_status(401)
end end
end end
context 'with a revoked oauth token' do
let(:application) { Fabricate(:application, scopes: 'read') }
let(:token) { Fabricate(:accessible_access_token, application: application, revoked_at: DateTime.now.utc) }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
it 'returns http authorization error' do
subject
expect(response).to have_http_status(401)
end
it 'returns the error in the json response' do
subject
expect(body_as_json).to match(
a_hash_including(
error: 'The access token was revoked'
)
)
end
end
context 'with an invalid oauth token' do
let(:application) { Fabricate(:application, scopes: 'read') }
let(:token) { Fabricate(:accessible_access_token, application: application) }
let(:headers) { { 'Authorization' => "Bearer #{token.token}-invalid" } }
it 'returns http authorization error' do
subject
expect(response).to have_http_status(401)
end
it 'returns the error in the json response' do
subject
expect(body_as_json).to match(
a_hash_including(
error: 'The access token is invalid'
)
)
end
end
end end
end end

View file

@ -56,7 +56,7 @@ describe AccountSearchService, type: :service do
service = instance_double(ResolveAccountService, call: nil) service = instance_double(ResolveAccountService, call: nil)
allow(ResolveAccountService).to receive(:new).and_return(service) allow(ResolveAccountService).to receive(:new).and_return(service)
results = subject.call('newuser@remote.com', nil, limit: 10, resolve: true) subject.call('newuser@remote.com', nil, limit: 10, resolve: true)
expect(service).to have_received(:call).with('newuser@remote.com') expect(service).to have_received(:call).with('newuser@remote.com')
end end
@ -64,14 +64,14 @@ describe AccountSearchService, type: :service do
service = instance_double(ResolveAccountService, call: nil) service = instance_double(ResolveAccountService, call: nil)
allow(ResolveAccountService).to receive(:new).and_return(service) allow(ResolveAccountService).to receive(:new).and_return(service)
results = subject.call('newuser@remote.com', nil, limit: 10, resolve: false) subject.call('newuser@remote.com', nil, limit: 10, resolve: false)
expect(service).to_not have_received(:call) expect(service).to_not have_received(:call)
end end
end end
it 'returns the fuzzy match first, and does not return suspended exacts' do it 'returns the fuzzy match first, and does not return suspended exacts' do
partial = Fabricate(:account, username: 'exactness') partial = Fabricate(:account, username: 'exactness')
exact = Fabricate(:account, username: 'exact', suspended: true) Fabricate(:account, username: 'exact', suspended: true)
results = subject.call('exact', nil, limit: 10) results = subject.call('exact', nil, limit: 10)
expect(results.size).to eq 1 expect(results.size).to eq 1
@ -79,7 +79,7 @@ describe AccountSearchService, type: :service do
end end
it 'does not return suspended remote accounts' do it 'does not return suspended remote accounts' do
remote = Fabricate(:account, username: 'a', domain: 'remote', display_name: 'e', suspended: true) Fabricate(:account, username: 'a', domain: 'remote', display_name: 'e', suspended: true)
results = subject.call('a@example.com', nil, limit: 2) results = subject.call('a@example.com', nil, limit: 2)
expect(results.size).to eq 0 expect(results.size).to eq 0

View file

@ -155,7 +155,7 @@ RSpec.describe PostStatusService, type: :service do
it 'processes duplicate mentions correctly' do it 'processes duplicate mentions correctly' do
account = Fabricate(:account) account = Fabricate(:account)
mentioned_account = Fabricate(:account, username: 'alice') Fabricate(:account, username: 'alice')
expect do expect do
subject.call(account, text: '@alice @alice @alice hey @alice') subject.call(account, text: '@alice @alice @alice hey @alice')
@ -212,7 +212,7 @@ RSpec.describe PostStatusService, type: :service do
account = Fabricate(:account) account = Fabricate(:account)
media = Fabricate(:media_attachment, account: Fabricate(:account)) media = Fabricate(:media_attachment, account: Fabricate(:account))
status = subject.call( subject.call(
account, account,
text: 'test status update', text: 'test status update',
media_ids: [media.id] media_ids: [media.id]

View file

@ -27,7 +27,7 @@ RSpec.describe PrecomputeFeedService, type: :service do
muted_account = Fabricate(:account) muted_account = Fabricate(:account)
Fabricate(:mute, account: account, target_account: muted_account) Fabricate(:mute, account: account, target_account: muted_account)
reblog = Fabricate(:status, account: muted_account) reblog = Fabricate(:status, account: muted_account)
status = Fabricate(:status, account: account, reblog: reblog) Fabricate(:status, account: account, reblog: reblog)
subject.call(account) subject.call(account)

View file

@ -8,7 +8,7 @@ describe ResolveURLService, type: :service do
describe '#call' do describe '#call' do
it 'returns nil when there is no resource url' do it 'returns nil when there is no resource url' do
url = 'http://example.com/missing-resource' url = 'http://example.com/missing-resource'
known_account = Fabricate(:account, uri: url, domain: 'example.com') Fabricate(:account, uri: url, domain: 'example.com')
service = instance_double(FetchResourceService) service = instance_double(FetchResourceService)
allow(FetchResourceService).to receive(:new).and_return service allow(FetchResourceService).to receive(:new).and_return service

View file

@ -38,7 +38,7 @@ RSpec.configure do |config|
end end
# Use the GitHub Annotations formatter for CI # Use the GitHub Annotations formatter for CI
if ENV['GITHUB_ACTIONS'] == 'true' if ENV['GITHUB_ACTIONS'] == 'true' && ENV['GITHUB_RSPEC'] == 'true'
require 'rspec/github' require 'rspec/github'
config.add_formatter RSpec::Github::Formatter config.add_formatter RSpec::Github::Formatter
end end

View file

@ -13,7 +13,7 @@ describe 'statuses/show.html.haml', without_verify_partial_doubles: true do
it 'has valid opengraph tags' do it 'has valid opengraph tags' do
alice = Fabricate(:account, username: 'alice', display_name: 'Alice') alice = Fabricate(:account, username: 'alice', display_name: 'Alice')
status = Fabricate(:status, account: alice, text: 'Hello World') status = Fabricate(:status, account: alice, text: 'Hello World')
media = Fabricate(:media_attachment, account: alice, status: status, type: :video) Fabricate(:media_attachment, account: alice, status: status, type: :video)
assign(:status, status) assign(:status, status)
assign(:account, alice) assign(:account, alice)
@ -32,7 +32,7 @@ describe 'statuses/show.html.haml', without_verify_partial_doubles: true do
it 'has twitter player tag' do it 'has twitter player tag' do
alice = Fabricate(:account, username: 'alice', display_name: 'Alice') alice = Fabricate(:account, username: 'alice', display_name: 'Alice')
status = Fabricate(:status, account: alice, text: 'Hello World') status = Fabricate(:status, account: alice, text: 'Hello World')
media = Fabricate(:media_attachment, account: alice, status: status, type: :video) Fabricate(:media_attachment, account: alice, status: status, type: :video)
assign(:status, status) assign(:status, status)
assign(:account, alice) assign(:account, alice)