1
0
This commit is contained in:
Noa Himesaka 2023-10-20 13:28:13 +09:00
commit 3697bb6811
216 changed files with 4252 additions and 3633 deletions

3
.github/FUNDING.yml vendored
View File

@ -1,3 +0,0 @@
patreon: mastodon
open_collective: mastodon
custom: https://sponsor.joinmastodon.org

View File

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

View File

@ -1,13 +1,13 @@
# This configuration was generated by
# `haml-lint --auto-gen-config`
# on 2023-10-03 08:32:28 -0400 using Haml-Lint version 0.51.0.
# on 2023-10-11 11:31:24 -0400 using Haml-Lint version 0.51.0.
# The point is for the user to remove these configuration records
# one by one as the lints are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of Haml-Lint, may require this file to be generated again.
linters:
# Offense count: 944
# Offense count: 946
LineLength:
enabled: false
@ -26,14 +26,6 @@ linters:
- 'app/views/admin/reports/show.html.haml'
- 'app/views/disputes/strikes/show.html.haml'
# Offense count: 15
InstanceVariables:
exclude:
- 'app/views/admin/reports/_actions.html.haml'
- 'app/views/auth/registrations/_status.html.haml'
- 'app/views/auth/sessions/two_factor/_otp_authentication_form.html.haml'
- 'app/views/relationships/_account.html.haml'
# Offense count: 2
IdNames:
exclude:

View File

@ -48,27 +48,6 @@ Lint/UnusedBlockArgument:
- 'config/initializers/paperclip.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.
Metrics/AbcSize:
Max: 144
@ -88,26 +67,6 @@ Metrics/CyclomaticComplexity:
Metrics/PerceivedComplexity:
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:
Exclude:
- 'app/models/feed.rb'
@ -180,9 +139,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 +375,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'
@ -523,12 +479,6 @@ Style/ClassVars:
Exclude:
- 'config/initializers/devise.rb'
# This cop supports unsafe autocorrection (--autocorrect-all).
Style/CombinableLoops:
Exclude:
- 'app/models/form/custom_emoji_batch.rb'
- 'app/models/form/ip_block_batch.rb'
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: AllowedVars.
Style/FetchEnvVar:

View File

@ -2,6 +2,46 @@
All notable changes to this project will be documented in this file.
## [4.2.1] - 2023-10-10
### Added
- Add redirection on `/deck` URLs for logged-out users ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27128))
- Add support for v4.2.0 migrations to `tootctl maintenance fix-duplicates` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27147))
### Changed
- Change some worker lock TTLs to be shorter-lived ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27246))
- Change user archive export allowed period from 7 days to 6 days ([suddjian](https://github.com/mastodon/mastodon/pull/27200))
### Fixed
- Fix duplicate reports being sent when reporting some remote posts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27355))
- Fix clicking on already-opened thread post scrolling to the top of the thread ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27331), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/27338), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/27350))
- Fix some remote posts getting truncated ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27307))
- Fix some cases of infinite scroll code trying to fetch inaccessible posts in a loop ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27286))
- Fix `Vary` headers not being set on some redirects ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27272))
- Fix mentions being matched in some URL query strings ([mjankowski](https://github.com/mastodon/mastodon/pull/25656))
- Fix unexpected linebreak in version string in the Web UI ([vmstan](https://github.com/mastodon/mastodon/pull/26986))
- Fix double scroll bars in some columns in advanced interface ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27187))
- Fix boosts of local users being filtered in account timelines ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27204))
- Fix multiple instances of the trend refresh scheduler sometimes running at once ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27253))
- Fix importer returning negative row estimates ([jgillich](https://github.com/mastodon/mastodon/pull/27258))
- Fix incorrectly keeping outdated update notices absent from the API endpoint ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27021))
- Fix import progress not updating on certain failures ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27247))
- Fix websocket connections being incorrectly decremented twice on errors ([ThisIsMissEm](https://github.com/mastodon/mastodon/pull/27238))
- Fix explore prompt appearing because of posts being received out of order ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27211))
- Fix explore prompt sometimes showing up when the home TL is loading ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27062))
- Fix link handling of mentions in user profiles when logged out ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27185))
- Fix filtering audit log for entries about disabling 2FA ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27186))
- Fix notification toasts not respecting reduce-motion ([c960657](https://github.com/mastodon/mastodon/pull/27178))
- Fix retention dashboard not displaying correct month ([vmstan](https://github.com/mastodon/mastodon/pull/27180))
- Fix tIME chunk not being properly removed from PNG uploads ([TheEssem](https://github.com/mastodon/mastodon/pull/27111))
- Fix division by zero in video in bitrate computation code ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27129))
- Fix inefficient queries in “Follows and followers” as well as several admin pages ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27116), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/27306))
- Fix ActiveRecord using two connection pools when no replica is defined ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27061))
- Fix the search documentation URL in system checks ([renchap](https://github.com/mastodon/mastodon/pull/27036))
## [4.2.0] - 2023-09-21
The following changelog entries focus on changes visible to users, administrators, client developers or federated software developers, but there has also been a lot of code modernization, refactoring, and tooling work, in particular by [@danielmbrasil](https://github.com/danielmbrasil), [@mjankowski](https://github.com/mjankowski), [@nschonni](https://github.com/nschonni), [@renchap](https://github.com/renchap), and [@takayamaki](https://github.com/takayamaki).

View File

@ -106,6 +106,9 @@ group :test do
# Used to split testing into chunks in CI
gem 'rspec_chunked', '~> 0.6'
# Adds RSpec Error/Warning annotations to GitHub PRs on the Files tab
gem 'rspec-github', '~> 2.4', require: false
# RSpec progress bar formatter
gem 'fuubar', '~> 2.5'

View File

@ -146,12 +146,12 @@ GEM
net-http-persistent (~> 4.0)
nokogiri (~> 1, >= 1.10.8)
base64 (0.1.1)
bcrypt (3.1.18)
bcrypt (3.1.19)
better_errors (2.10.1)
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)
@ -210,17 +210,17 @@ GEM
database_cleaner-core (2.0.1)
date (3.3.3)
debug_inspector (1.1.0)
devise (4.9.2)
devise (4.9.3)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0)
responders
warden (~> 1.2.3)
devise-two-factor (4.1.0)
activesupport (< 7.1)
devise-two-factor (4.1.1)
activesupport (~> 7.0)
attr_encrypted (>= 1.3, < 5, != 2)
devise (~> 4.0)
railties (< 7.1)
railties (~> 7.0)
rotp (~> 6.0)
devise_pam_authenticatable2 (9.2.0)
devise (>= 4.0.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)
@ -412,12 +412,12 @@ GEM
llhttp-ffi (0.4.0)
ffi-compiler (~> 1.0)
rake (~> 13.0)
lograge (0.13.0)
lograge (0.14.0)
actionpack (>= 4)
activesupport (>= 4)
railties (>= 4)
request_store (~> 1.0)
loofah (2.21.3)
loofah (2.21.4)
crass (~> 1.0.2)
nokogiri (>= 1.12.0)
mail (2.8.1)
@ -440,7 +440,7 @@ GEM
mime-types-data (3.2023.0808)
mini_mime (1.1.5)
mini_portile2 (2.8.4)
minitest (5.19.0)
minitest (5.20.0)
msgpack (1.7.1)
multi_json (1.15.0)
multipart-post (2.3.0)
@ -493,7 +493,7 @@ GEM
orm_adapter (0.5.0)
ox (2.14.17)
parallel (1.23.0)
parser (3.2.2.3)
parser (3.2.2.4)
ast (~> 2.4.1)
racc
parslet (2.0.0)
@ -513,7 +513,7 @@ GEM
premailer (~> 1.7, >= 1.7.9)
private_address_check (0.5.0)
public_suffix (5.0.3)
puma (6.3.1)
puma (6.4.0)
nio4r (~> 2.0)
pundit (2.3.0)
activesupport (>= 3.0.0)
@ -554,14 +554,14 @@ GEM
actionpack (>= 5.0.1.rc1)
actionview (>= 5.0.1.rc1)
activesupport (>= 5.0.1.rc1)
rails-dom-testing (2.1.1)
rails-dom-testing (2.2.0)
activesupport (>= 5.0.0)
minitest
nokogiri (>= 1.6)
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)
@ -583,10 +583,10 @@ GEM
redis (>= 4)
redlock (1.3.2)
redis (>= 3.0.0, < 6.0)
regexp_parser (2.8.1)
regexp_parser (2.8.2)
request_store (1.5.1)
rack (>= 1.4)
responders (3.1.0)
responders (3.1.1)
actionpack (>= 5.2)
railties (>= 5.2)
rexml (3.2.6)
@ -602,6 +602,8 @@ GEM
rspec-expectations (3.12.3)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.12.0)
rspec-github (2.4.0)
rspec-core (~> 3.0)
rspec-mocks (3.12.5)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.12.0)
@ -620,12 +622,12 @@ GEM
sidekiq (>= 5, < 8)
rspec-support (3.12.1)
rspec_chunked (0.6)
rubocop (1.56.4)
rubocop (1.57.1)
base64 (~> 0.1.1)
json (~> 2.3)
language_server-protocol (>= 3.17.0)
parallel (~> 1.10)
parser (>= 3.2.2.3)
parser (>= 3.2.2.4)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml (>= 3.2.5, < 4.0)
@ -634,11 +636,11 @@ GEM
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.29.0)
parser (>= 3.2.1.0)
rubocop-capybara (2.18.0)
rubocop-capybara (2.19.0)
rubocop (~> 1.41)
rubocop-factory_bot (2.23.1)
rubocop (~> 1.33)
rubocop-performance (1.19.0)
rubocop-performance (1.19.1)
rubocop (>= 1.7.0, < 2.0)
rubocop-ast (>= 0.4.0)
rubocop-rails (2.20.2)
@ -671,7 +673,7 @@ GEM
rubyzip (>= 1.2.2, < 3.0)
websocket (~> 1.0)
semantic_range (3.0.0)
sidekiq (6.5.10)
sidekiq (6.5.12)
connection_pool (>= 2.2.5, < 3)
rack (~> 2.0)
redis (>= 4.5.0, < 5)
@ -789,7 +791,7 @@ GEM
xorcist (1.1.3)
xpath (3.2.0)
nokogiri (~> 1.8)
zeitwerk (2.6.11)
zeitwerk (2.6.12)
PLATFORMS
ruby
@ -885,6 +887,7 @@ DEPENDENCIES
redis (~> 4.5)
redis-namespace (~> 1.10)
rqrcode (~> 2.2)
rspec-github (~> 2.4)
rspec-rails (~> 6.0)
rspec-sidekiq (~> 4.0)
rspec_chunked (~> 0.6)

View File

@ -1,9 +1,9 @@
# frozen_string_literal: true
class Api::V1::Apps::CredentialsController < Api::BaseController
before_action -> { doorkeeper_authorize! :read }
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

View File

@ -5,6 +5,7 @@ module TwoFactorAuthenticationConcern
included do
prepend_before_action :authenticate_with_two_factor, if: :two_factor_enabled?, only: [:create]
helper_method :webauthn_enabled?
end
def two_factor_enabled?
@ -89,4 +90,10 @@ module TwoFactorAuthenticationConcern
set_locale { render :two_factor }
end
protected
def webauthn_enabled?
@webauthn_enabled
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

@ -66,7 +66,7 @@ class Search extends PureComponent {
{ label: <><mark>before:</mark> <FormattedMessage id='search_popout.specific_date' defaultMessage='specific date' /></>, action: e => { e.preventDefault(); this._insertText('before:'); } },
{ label: <><mark>during:</mark> <FormattedMessage id='search_popout.specific_date' defaultMessage='specific date' /></>, action: e => { e.preventDefault(); this._insertText('during:'); } },
{ label: <><mark>after:</mark> <FormattedMessage id='search_popout.specific_date' defaultMessage='specific date' /></>, action: e => { e.preventDefault(); this._insertText('after:'); } },
{ label: <><mark>in:</mark> <FormattedList type='disjunction' value={['all', 'library']} /></>, action: e => { e.preventDefault(); this._insertText('in:'); } }
{ label: <><mark>in:</mark> <FormattedList type='disjunction' value={['all', 'library', 'public']} /></>, action: e => { e.preventDefault(); this._insertText('in:'); } }
];
setRef = c => {

View File

@ -37,7 +37,7 @@ const getHomeFeedSpeed = createSelector([
state => state.getIn(['timelines', 'home', 'pendingItems'], ImmutableList()),
state => state.get('statuses'),
], (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);
if (statuses.isEmpty()) {

View File

@ -668,7 +668,7 @@ class Status extends ImmutablePureComponent {
shouldUpdateScroll = (prevRouterProps, { location }) => {
// Do not change scroll when opening a modal
if (location.state?.mastodonModalKey && location.state?.mastodonModalKey !== prevRouterProps?.location?.state?.mastodonModalKey) {
if (location.state?.mastodonModalKey !== prevRouterProps?.location?.state?.mastodonModalKey) {
return false;
}

View File

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

View File

@ -57,10 +57,10 @@ class NavigationPanel extends Component {
<div className='navigation-panel'>
{transientSingleColumn && (
<div className='navigation-panel__logo'>
<div class='switch-to-advanced'>
<div className='switch-to-advanced'>
{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)}
</a>
</div>

View File

@ -191,7 +191,9 @@ class SwitchingColumnsArea extends PureComponent {
{singleColumn ? <Redirect from='/deck' to='/home' exact /> : null}
{singleColumn && pathName.startsWith('/deck/') ? <Redirect from={pathName} to={pathName.slice(5)} /> : null}
{/* Redirect old bookmarks (without /deck) with home-like routes to the advanced interface */}
{!singleColumn && pathName === '/getting-started' ? <Redirect from='/getting-started' to='/deck/getting-started' exact /> : null}
{!singleColumn && pathName === '/home' ? <Redirect from='/home' to='/deck/getting-started' exact /> : null}
<WrappedRoute path='/getting-started' component={GettingStarted} content={children} />
<WrappedRoute path='/keyboard-shortcuts' component={KeyboardShortcuts} content={children} />

View File

@ -95,6 +95,7 @@ const initialPath = document.querySelector("head meta[name=initialPath]")?.getAt
/** @type {boolean} */
export const hasMultiColumnPath = initialPath === '/'
|| initialPath === '/getting-started'
|| initialPath === '/home'
|| initialPath.startsWith('/deck');
/**

View File

@ -64,7 +64,7 @@ class Search extends PureComponent {
{ label: <><mark>before:</mark> <FormattedMessage id='search_popout.specific_date' defaultMessage='specific date' /></>, action: e => { e.preventDefault(); this._insertText('before:'); } },
{ label: <><mark>during:</mark> <FormattedMessage id='search_popout.specific_date' defaultMessage='specific date' /></>, action: e => { e.preventDefault(); this._insertText('during:'); } },
{ label: <><mark>after:</mark> <FormattedMessage id='search_popout.specific_date' defaultMessage='specific date' /></>, action: e => { e.preventDefault(); this._insertText('after:'); } },
{ label: <><mark>in:</mark> <FormattedList type='disjunction' value={['all', 'library']} /></>, action: e => { e.preventDefault(); this._insertText('in:'); } }
{ label: <><mark>in:</mark> <FormattedList type='disjunction' value={['all', 'library', 'public']} /></>, action: e => { e.preventDefault(); this._insertText('in:'); } }
];
setRef = c => {

View File

@ -37,7 +37,7 @@ const getHomeFeedSpeed = createSelector([
state => state.getIn(['timelines', 'home', 'pendingItems'], ImmutableList()),
state => state.get('statuses'),
], (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);
if (statuses.isEmpty()) {

View File

@ -634,7 +634,7 @@ class Status extends ImmutablePureComponent {
shouldUpdateScroll = (prevRouterProps, { location }) => {
// Do not change scroll when opening a modal
if (location.state?.mastodonModalKey && location.state?.mastodonModalKey !== prevRouterProps?.location?.state?.mastodonModalKey) {
if (location.state?.mastodonModalKey !== prevRouterProps?.location?.state?.mastodonModalKey) {
return false;
}

View File

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

View File

@ -59,10 +59,10 @@ class NavigationPanel extends Component {
<Link to='/' className='column-link column-link--logo'><WordmarkLogo /></Link>
{transientSingleColumn ? (
<div class='switch-to-advanced'>
<div className='switch-to-advanced'>
{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)}
</a>
</div>

View File

@ -184,7 +184,9 @@ class SwitchingColumnsArea extends PureComponent {
{singleColumn ? <Redirect from='/deck' to='/home' exact /> : null}
{singleColumn && pathName.startsWith('/deck/') ? <Redirect from={pathName} to={pathName.slice(5)} /> : null}
{/* Redirect old bookmarks (without /deck) with home-like routes to the advanced interface */}
{!singleColumn && pathName === '/getting-started' ? <Redirect from='/getting-started' to='/deck/getting-started' exact /> : null}
{!singleColumn && pathName === '/home' ? <Redirect from='/home' to='/deck/getting-started' exact /> : null}
<WrappedRoute path='/getting-started' component={GettingStarted} content={children} />
<WrappedRoute path='/keyboard-shortcuts' component={KeyboardShortcuts} content={children} />

View File

@ -104,6 +104,7 @@ const initialPath = document.querySelector("head meta[name=initialPath]")?.getAt
/** @type {boolean} */
export const hasMultiColumnPath = initialPath === '/'
|| initialPath === '/getting-started'
|| initialPath === '/home'
|| initialPath.startsWith('/deck');
/**

View File

@ -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",

View File

@ -1,6 +1,6 @@
{
"about.blocks": "Valvotut palvelimet",
"about.contact": "Yhteydenotto:",
"about.contact": "Ota yhteyttä:",
"about.disclaimer": "Mastodon on vapaa avoimen lähdekoodin ohjelmisto ja Mastodon gGmbH:n tavaramerkki.",
"about.domain_blocks.no_reason_available": "Syytä ei ole ilmoitettu",
"about.domain_blocks.preamble": "Mastodonin avulla voidaan yleensä tarkastella minkä tahansa fediversumiin kuuluvan palvelimen sisältöä ja vuorovaikuttaa eri palvelinten käyttäjien kanssa. Nämä ovat tälle palvelimelle määritetyt poikkeukset.",
@ -26,15 +26,15 @@
"account.domain_blocked": "Verkkotunnus estetty",
"account.edit_profile": "Muokkaa profiilia",
"account.enable_notifications": "Ilmoita minulle, kun @{name} julkaisee",
"account.endorse": "Suosittele profiilissasi",
"account.endorse": "Pidä esillä profiilissa",
"account.featured_tags.last_status_at": "Viimeisin julkaisu {date}",
"account.featured_tags.last_status_never": "Ei julkaisuja",
"account.featured_tags.title": "Käyttäjän {name} esille nostetut aihetunnisteet",
"account.featured_tags.title": "Käyttäjän {name} esillä pidettävät aihetunnisteet",
"account.follow": "Seuraa",
"account.followers": "seuraaja(t)",
"account.followers": "Seuraajat",
"account.followers.empty": "Kukaan ei seuraa tätä käyttäjää vielä.",
"account.followers_counter": "{count, plural, one {{counter} seuraaja} other {{counter} seuraajaa}}",
"account.following": "Seurataan",
"account.following": "Seuratut",
"account.following_counter": "{count, plural, one {{counter} seurattu} other {{counter} seurattua}}",
"account.follows.empty": "Tämä käyttäjä ei vielä seuraa ketään.",
"account.follows_you": "Seuraa sinua",
@ -62,20 +62,20 @@
"account.share": "Jaa käyttäjän @{name} profiili",
"account.show_reblogs": "Näytä käyttäjän @{name} tehostukset",
"account.statuses_counter": "{count, plural, one {{counter} julkaisu} other {{counter} julkaisua}}",
"account.unblock": "Poista esto: @{name}",
"account.unblock_domain": "Salli palvelu {domain}",
"account.unblock": "Poista käyttäjän @{name} esto",
"account.unblock_domain": "Poista verkkotunnuksen {domain} esto",
"account.unblock_short": "Poista esto",
"account.unendorse": "Poista suosittelu profiilistasi",
"account.unendorse": "Älä pidä esillä profiilissa",
"account.unfollow": "Lopeta seuraaminen",
"account.unmute": "Poista käyttäjän @{name} mykistys",
"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äjien pysyvyys rekisteröitymisen jälkeen päivittäin",
"admin.dashboard.monthly_retention": "Käyttäjien pysyvyys rekisteröitymisen jälkeen kuukausittain",
"admin.dashboard.retention.average": "Keskimäärin",
"admin.dashboard.retention.cohort": "Kirjautumiset",
"admin.dashboard.retention.cohort_size": "Uudet käyttäjät",
"admin.dashboard.retention.cohort": "Rekisteröitymis-kk.",
"admin.dashboard.retention.cohort_size": "Uusia käyttäjiä",
"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_follows": "Seuraajat, jotka heidän käyttäjänsä menettäisivä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!",
@ -114,7 +114,7 @@
"column.directory": "Selaa profiileja",
"column.domain_blocks": "Estetyt verkkotunnukset",
"column.favourites": "Suosikit",
"column.firehose": "Live-syötteet",
"column.firehose": "Livesyötteet",
"column.follow_requests": "Seuraamispyynnöt",
"column.home": "Koti",
"column.lists": "Listat",
@ -135,7 +135,7 @@
"community.column_settings.remote_only": "Vain etätilit",
"compose.language.change": "Vaihda kieli",
"compose.language.search": "Hae kieliä...",
"compose.published.body": "Julkaisusi julkaistiin.",
"compose.published.body": "Julkaisu lähetetty.",
"compose.published.open": "Avaa",
"compose.saved.body": "Julkaisu tallennettu.",
"compose_form.direct_message_warning_learn_more": "Lisätietoja",
@ -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",
@ -194,7 +194,7 @@
"copypaste.copied": "Kopioitu",
"copypaste.copy_to_clipboard": "Kopioi leikepöydälle",
"directory.federated": "Koko tunnettu fediversumi",
"directory.local": "Vain palvelusta {domain}",
"directory.local": "Vain palvelimelta {domain}",
"directory.new_arrivals": "Äskettäin saapuneet",
"directory.recently_active": "Hiljattain aktiiviset",
"disabled_account_banner.account_settings": "Tilin asetukset",
@ -225,12 +225,12 @@
"empty_column.account_suspended": "Tili jäädytetty",
"empty_column.account_timeline": "Ei viestejä täällä.",
"empty_column.account_unavailable": "Profiilia ei löydy",
"empty_column.blocks": "Et ole estänyt käyttäjiä.",
"empty_column.blocks": "Et ole vielä estänyt käyttäjiä.",
"empty_column.bookmarked_statuses": "Et ole vielä lisännyt julkaisuja kirjanmerkkeihisi. Kun lisäät yhden, se näkyy tässä.",
"empty_column.community": "Paikallinen aikajana on tyhjä. Kirjoita jotain julkista, niin homma lähtee käyntiin!",
"empty_column.direct": "Yksityisiä mainintoja ei vielä ole. Jos lähetät tai sinulle lähetetään sellaisia, näet ne täällä.",
"empty_column.domain_blocks": "Palveluita ei ole vielä estetty.",
"empty_column.explore_statuses": "Mikään ei trendaa nyt. Tarkista myöhemmin uudelleen!",
"empty_column.domain_blocks": "Verkkotunnuksia ei ole vielä estetty.",
"empty_column.explore_statuses": "Mikään ei ole nyt suosittua. Tarkista myöhemmin uudelleen!",
"empty_column.favourited_statuses": "Sinulla ei ole vielä yhtään suosikkijulkaisua. Kun lisäät sellaisen, näkyy se tässä.",
"empty_column.favourites": "Kukaan ei ole vielä lisännyt tätä julkaisua suosikkeihinsa. Kun joku tekee niin, tulee hän tähän näkyviin.",
"empty_column.follow_requests": "Et ole vielä vastaanottanut seuraamispyyntöjä. Saamasi pyynnöt näkyvät täällä.",
@ -266,7 +266,7 @@
"filter_modal.select_filter.context_mismatch": "ei sovellu tähän kontekstiin",
"filter_modal.select_filter.expired": "vanhentunut",
"filter_modal.select_filter.prompt_new": "Uusi luokka: {name}",
"filter_modal.select_filter.search": "Etsi tai luo",
"filter_modal.select_filter.search": "Hae tai luo",
"filter_modal.select_filter.subtitle": "Käytä olemassa olevaa luokkaa tai luo uusi",
"filter_modal.select_filter.title": "Suodata tämä julkaisu",
"filter_modal.title.status": "Suodata julkaisu",
@ -336,9 +336,9 @@
"keyboard_shortcuts.blocked": "Avaa estettyjen käyttäjien luettelo",
"keyboard_shortcuts.boost": "Tehosta julkaisua",
"keyboard_shortcuts.column": "Kohdista sarakkeeseen",
"keyboard_shortcuts.compose": "siirry tekstinsyöttöön",
"keyboard_shortcuts.compose": "Kohdista kirjoituskenttään",
"keyboard_shortcuts.description": "Kuvaus",
"keyboard_shortcuts.direct": "avataksesi yksityisten mainintojen sarakkeen",
"keyboard_shortcuts.direct": "Avaa yksityisten mainintojen sarake",
"keyboard_shortcuts.down": "Siirry listassa alaspäin",
"keyboard_shortcuts.enter": "Avaa julkaisu",
"keyboard_shortcuts.favourite": "Lisää julkaisu suosikkeihin",
@ -347,22 +347,22 @@
"keyboard_shortcuts.heading": "Pikanäppäimet",
"keyboard_shortcuts.home": "Avaa kotiaikajana",
"keyboard_shortcuts.hotkey": "Pikanäppäin",
"keyboard_shortcuts.legend": "Näytä tämä selite",
"keyboard_shortcuts.legend": "Näytä tämä ohje",
"keyboard_shortcuts.local": "Avaa paikallinen aikajana",
"keyboard_shortcuts.mention": "Mainitse julkaisija",
"keyboard_shortcuts.muted": "Avaa lista mykistetyistä käyttäjistä",
"keyboard_shortcuts.mention": "Mainitse kirjoittaja",
"keyboard_shortcuts.muted": "Avaa mykistettyjen käyttäjien luettelo",
"keyboard_shortcuts.my_profile": "Avaa profiilisi",
"keyboard_shortcuts.notifications": "Avaa ilmoitukset-valikko",
"keyboard_shortcuts.notifications": "Avaa ilmoitussarake",
"keyboard_shortcuts.open_media": "Avaa media",
"keyboard_shortcuts.pinned": "Avaa kiinnitettyjen julkaisujen luettelo",
"keyboard_shortcuts.profile": "Avaa kirjoittajan profiili",
"keyboard_shortcuts.reply": "Vastaa julkaisuun",
"keyboard_shortcuts.requests": "Avaa seuraamispyyntöjen luettelo",
"keyboard_shortcuts.search": "siirry hakukenttään",
"keyboard_shortcuts.search": "Kohdista hakukenttään",
"keyboard_shortcuts.spoilers": "Näytä/piilota sisältövaroituskenttä",
"keyboard_shortcuts.start": "avaa \"Aloitus\"",
"keyboard_shortcuts.toggle_hidden": "näytä/piilota sisältövaroituksella merkitty teksti",
"keyboard_shortcuts.toggle_sensitivity": "näytä/piilota media",
"keyboard_shortcuts.start": "Avaa Näin pääset alkuun -sarake",
"keyboard_shortcuts.toggle_hidden": "Näytä/piilota sisältövaroituksella merkitty teksti",
"keyboard_shortcuts.toggle_sensitivity": "Näytä/piilota media",
"keyboard_shortcuts.toot": "Luo uusi julkaisu",
"keyboard_shortcuts.unfocus": "Poistu teksti-/hakukentästä",
"keyboard_shortcuts.up": "Siirry listassa ylöspäin",
@ -414,12 +414,12 @@
"navigation_bar.lists": "Listat",
"navigation_bar.logout": "Kirjaudu ulos",
"navigation_bar.mutes": "Mykistetyt käyttäjät",
"navigation_bar.opened_in_classic_interface": "Julkaisut, profiilit ja tietyt muut sivut avautuvat oletuksena perinteiseen web-käyttöliittymään.",
"navigation_bar.opened_in_classic_interface": "Julkaisut, profiilit ja tietyt muut sivut avautuvat oletuksena perinteiseen selainkäyttöliittymään.",
"navigation_bar.personal": "Henkilökohtainen",
"navigation_bar.pins": "Kiinnitetyt julkaisut",
"navigation_bar.preferences": "Asetukset",
"navigation_bar.public_timeline": "Yleinen aikajana",
"navigation_bar.search": "Haku",
"navigation_bar.search": "Hae",
"navigation_bar.security": "Turvallisuus",
"not_signed_in_indicator.not_signed_in": "Sinun on kirjauduttava sisään käyttääksesi resurssia.",
"notification.admin.report": "{name} teki ilmoituksen käytäjästä {target}",
@ -436,10 +436,10 @@
"notifications.clear": "Tyhjennä ilmoitukset",
"notifications.clear_confirmation": "Haluatko varmasti poistaa kaikki ilmoitukset pysyvästi?",
"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.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.show_bar": "Näytä suodatinpalkki",
"notifications.column_settings.follow": "Uudet seuraajat:",
@ -472,14 +472,14 @@
"notifications_permission_banner.title": "Älä anna minkään mennä ohi",
"onboarding.action.back": "Palaa takaisin",
"onboarding.actions.back": "Palaa takaisin",
"onboarding.actions.go_to_explore": "Siirry suosituimpien aiheiden syötteeseen",
"onboarding.actions.go_to_explore": "Siirry suosittujen aiheiden syötteeseen",
"onboarding.actions.go_to_home": "Siirry kotisyötteeseeni",
"onboarding.compose.template": "Tervehdys #Mastodon!",
"onboarding.follows.empty": "Valitettavasti tuloksia ei voida näyttää juuri nyt. Voit kokeilla hakua tai selata tutustumissivua löytääksesi seurattavaa, tai yrittää myöhemmin uudelleen.",
"onboarding.follows.empty": "Valitettavasti tuloksia ei voida näyttää juuri nyt. Voit kokeilla hakua tai selata tutustumissivua löytääksesi seurattavaa tai yrittää myöhemmin uudelleen.",
"onboarding.follows.lead": "Kokoat oman kotisyötteesi itse. Mitä enemmän ihmisiä seuraat, sitä aktiivisempi ja kiinnostavampi syöte on. Nämä profiilit voivat olla alkuun hyvä lähtökohta — voit aina lopettaa niiden seuraamisen myöhemmin!",
"onboarding.follows.title": "Mukauta kotisyötettäsi",
"onboarding.share.lead": "Kerro ihmisille, kuinka he voivat löytää sinut Mastodonista!",
"onboarding.share.message": "Olen {username} #Mastodon'issa! Seuraa minua osoitteessa {url}",
"onboarding.share.message": "Olen {username} #Mastodonissa! Seuraa minua osoitteessa {url}",
"onboarding.share.next_steps": "Mahdolliset seuraavat vaiheet:",
"onboarding.share.title": "Jaa profiilisi",
"onboarding.start.lead": "Uusi Mastodon-tilisi on nyt valmiina käyttöön. Kyseessä on ainutlaatuinen, hajautettu sosiaalisen median alusta, jolla sinä itse algoritmin sijaan määrität käyttökokemuksesi. Näin hyödyt Mastodonista eniten:",
@ -517,7 +517,7 @@
"privacy.private.short": "Vain seuraajat",
"privacy.public.long": "Näkyy kaikille",
"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_policy.last_updated": "Viimeksi päivitetty {date}",
"privacy_policy.title": "Tietosuojakäytäntö",
@ -537,7 +537,7 @@
"relative_time.today": "tänään",
"reply_indicator.cancel": "Peruuta",
"report.block": "Estä",
"report.block_explanation": "Et näe hänen viestejään, eikä hän voi nähdä viestejäsi tai seurata sinua. Hän näkevät, että olet estänyt hänet.",
"report.block_explanation": "Et näe hänen viestejään, eikä hän voi nähdä viestejäsi tai seurata sinua. Hän näkee, että olet estänyt hänet.",
"report.categories.legal": "Lakiasiat",
"report.categories.other": "Muu",
"report.categories.spam": "Roskaposti",
@ -584,18 +584,18 @@
"report_notification.open": "Avaa raportti",
"search.no_recent_searches": "Ei viimeaikaisia hakuja",
"search.placeholder": "Hae",
"search.quick_action.account_search": "Profiilit, jotka vastaavat hakua {x}",
"search.quick_action.go_to_account": "Avaa profiili {x}",
"search.quick_action.account_search": "Profiilit haulla {x}",
"search.quick_action.go_to_account": "Siirry profiiliin {x}",
"search.quick_action.go_to_hashtag": "Siirry aihetunnisteeseen {x}",
"search.quick_action.open_url": "Avaa URL-osoite Mastodonissa",
"search.quick_action.status_search": "Julkaisut haulla {x}",
"search.search_or_paste": "Etsi 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.language_code": "ISO-kielikoodi",
"search_popout.options": "Haun asetukset",
"search_popout.options": "Hakuvalinnat",
"search_popout.quick_actions": "Pikatoiminnot",
"search_popout.recent": "Viime haut",
"search_popout.specific_date": "tietty päivämäärä",
"search_popout.recent": "Viimeaikaiset haut",
"search_popout.specific_date": "tarkka päiväys",
"search_popout.user": "käyttäjä",
"search_results.accounts": "Profiilit",
"search_results.all": "Kaikki",
@ -637,7 +637,7 @@
"status.history.created": "{name} luotu {date}",
"status.history.edited": "{name} muokkasi {date}",
"status.load_more": "Lataa lisää",
"status.media.open": "Napsauta avataksesi",
"status.media.open": "Avaa napsauttamalla",
"status.media.show": "Napsauta näyttääksesi",
"status.media_hidden": "Media piilotettu",
"status.mention": "Mainitse @{name}",
@ -654,7 +654,7 @@
"status.reblogs.empty": "Kukaan ei ole vielä tehostanut tätä julkaisua. Kun joku tekee niin, tulee hän tähän näkyviin.",
"status.redraft": "Poista ja palauta muokattavaksi",
"status.remove_bookmark": "Poista kirjanmerkki",
"status.replied_to": "Vastattu {name}",
"status.replied_to": "Vastaus käyttäjälle {name}",
"status.reply": "Vastaa",
"status.replyAll": "Vastaa ketjuun",
"status.report": "Raportoi @{name}",
@ -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.",
@ -694,7 +694,7 @@
"units.short.thousand": "{count} t.",
"upload_area.title": "Lataa raahaamalla ja pudottamalla tähän",
"upload_button.label": "Lisää kuvia, video tai äänitiedosto",
"upload_error.limit": "Tiedostolatauksien raja ylitetty.",
"upload_error.limit": "Tiedostolatauksien rajoitus ylitetty.",
"upload_error.poll": "Tiedoston lataaminen ei ole sallittua äänestyksissä.",
"upload_form.audio_description": "Kuvaile sisältöä kuuroille ja kuulorajoitteisille",
"upload_form.description": "Kuvaile sisältöä sokeille ja näkörajoitteisille",
@ -715,7 +715,7 @@
"upload_modal.preview_label": "Esikatselu ({ratio})",
"upload_progress.label": "Ladataan...",
"upload_progress.processing": "Käsitellään…",
"username.taken": "Käyttäjätunnus on jo varattu. Kokeile toista",
"username.taken": "Käyttäjänimi on jo varattu. Kokeile toista",
"video.close": "Sulje video",
"video.download": "Lataa tiedosto",
"video.exit_fullscreen": "Poistu koko näytön tilasta",

View File

@ -7,7 +7,7 @@
"about.domain_blocks.silenced.explanation": "San fharsaingeachd, chan fhaic thu pròifilean agus susbaint an fhrithealaiche seo ach ma nì thu lorg no ma tha thu ga leantainn.",
"about.domain_blocks.silenced.title": "Cuingichte",
"about.domain_blocks.suspended.explanation": "Cha dèid dàta sam bith on fhrithealaiche seo a phròiseasadh, a stòradh no iomlaid agus chan urrainn do na cleachdaichean on fhrithealaiche sin conaltradh no eadar-ghnìomh a ghabhail an-seo.",
"about.domain_blocks.suspended.title": "Na dhàil",
"about.domain_blocks.suspended.title": "À rèim",
"about.not_available": "Cha deach am fiosrachadh seo a sholar air an fhrithealaiche seo.",
"about.powered_by": "Lìonra sòisealta sgaoilte le cumhachd {mastodon}",
"about.rules": "Riaghailtean an fhrithealaiche",

View File

@ -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": "ミュート",
@ -137,7 +137,7 @@
"compose.language.search": "言語を検索...",
"compose.published.body": "投稿されました!",
"compose.published.open": "開く",
"compose.saved.body": "投稿が保存されました",
"compose.saved.body": "変更を保存しました。",
"compose_form.direct_message_warning_learn_more": "もっと詳しく",
"compose_form.encryption_warning": "Mastodonの投稿はエンドツーエンド暗号化に対応していません。安全に送受信されるべき情報をMastodonで共有しないでください。",
"compose_form.hashtag_warning": "この投稿は公開設定ではないのでハッシュタグの一覧に表示されません。公開投稿だけがハッシュタグで検索できます。",
@ -250,7 +250,7 @@
"errors.unexpected_crash.report_issue": "問題を報告",
"explore.search_results": "検索結果",
"explore.suggested_follows": "ユーザー",
"explore.title": "エクスプローラー",
"explore.title": "探索する",
"explore.trending_links": "ニュース",
"explore.trending_statuses": "投稿",
"explore.trending_tags": "ハッシュタグ",

View File

@ -102,7 +102,7 @@
"bundle_modal_error.message": "컴포넌트를 불러오는 중 문제가 발생했습니다.",
"bundle_modal_error.retry": "다시 시도",
"closed_registrations.other_server_instructions": "마스토돈은 분산화 되어 있기 때문에, 다른 서버에서 계정을 만들더라도 이 서버와 상호작용 할 수 있습니다.",
"closed_registrations_modal.description": "{domain}은 현재 가입이 막혀있는 상태입니다, 만약 마스토돈을 이용하기 위해 꼭 {domain}을 사용할 필요는 없다는 사실을 인지해 두세요.",
"closed_registrations_modal.description": "{domain}은 현재 가입이 막혀있는 상태입니다, 마스토돈을 이용하기 위해 꼭 {domain}을 사용할 필요는 없다는 사실을 인지해 두세요.",
"closed_registrations_modal.find_another_server": "다른 서버 찾기",
"closed_registrations_modal.preamble": "마스토돈은 분산화 되어 있습니다, 그렇기 때문에 어디에서 계정을 생성하든, 이 서버에 있는 누구와도 팔로우와 상호작용을 할 수 있습니다. 심지어는 스스로 서버를 만드는 것도 가능합니다!",
"closed_registrations_modal.title": "마스토돈에서 가입",

View File

@ -65,6 +65,7 @@
"account.unendorse": "Mostrar pas pel perfil",
"account.unfollow": "Quitar de sègre",
"account.unmute": "Quitar de rescondre @{name}",
"account.unmute_notifications_short": "Restablir las notificacions",
"account.unmute_short": "Tornar afichar",
"account_note.placeholder": "Clicar per ajustar una nòta",
"admin.dashboard.retention.average": "Mejana",
@ -97,6 +98,8 @@
"column.direct": "Mencions privadas",
"column.directory": "Percórrer los perfils",
"column.domain_blocks": "Domenis resconduts",
"column.favourites": "Favorits",
"column.firehose": "Tuts en dirèct",
"column.follow_requests": "Demandas dabonament",
"column.home": "Acuèlh",
"column.lists": "Listas",
@ -117,6 +120,7 @@
"community.column_settings.remote_only": "Sonque alonhat",
"compose.language.change": "Cambiar de lenga",
"compose.language.search": "Recercar de lengas...",
"compose.published.body": "Tut publicat.",
"compose.published.open": "Dobrir",
"compose.saved.body": "Publicacion enregistrada.",
"compose_form.direct_message_warning_learn_more": "Ne saber mai",
@ -170,6 +174,7 @@
"conversation.open": "Veire la conversacion",
"conversation.with": "Amb {names}",
"copypaste.copied": "Copiat",
"copypaste.copy_to_clipboard": "Copiar al quichapapièr",
"directory.federated": "Del fediverse conegut",
"directory.local": "Solament de {domain}",
"directory.new_arrivals": "Nòus-venguts",
@ -220,6 +225,7 @@
"errors.unexpected_crash.copy_stacktrace": "Copiar las traças al quichapapièrs",
"errors.unexpected_crash.report_issue": "Senhalar un problèma",
"explore.search_results": "Resultats de recèrca",
"explore.suggested_follows": "Personas",
"explore.title": "Explorar",
"explore.trending_links": "Novèlas",
"explore.trending_statuses": "Publicacions",
@ -234,6 +240,7 @@
"filter_modal.select_filter.search": "Cercar o crear",
"filter_modal.select_filter.title": "Filtrar aquesta publicacion",
"filter_modal.title.status": "Filtrar una publicacion",
"firehose.local": "Aqueste servidor",
"follow_request.authorize": "Acceptar",
"follow_request.reject": "Regetar",
"follow_requests.unlocked_explanation": "Encara que vòstre compte siasque pas verrolhat, la còla de {domain} pensèt que volriatz benlèu repassar las demandas dabonament daquestes comptes.",
@ -257,12 +264,19 @@
"hashtag.column_settings.tag_mode.any": "Un daquestes",
"hashtag.column_settings.tag_mode.none": "Cap daquestes",
"hashtag.column_settings.tag_toggle": "Inclure las etiquetas suplementàrias dins aquesta colomna",
"hashtag.counter_by_accounts": "{count, plural, one {{counter} participant} other {{counter} participants}}",
"hashtag.counter_by_uses": "{count, plural, one {{counter} tut} other {{counter} tuts}}",
"hashtag.counter_by_uses_today": "{count, plural, one {{counter} tut} other {{counter} tuts}} uèi",
"hashtag.follow": "Sègre letiqueta",
"hashtag.unfollow": "Quitar de sègre letiqueta",
"hashtags.and_other": "…e {count, plural, one {}other {# de mai}}",
"home.actions.go_to_explore": "Agachatz las tendéncias",
"home.actions.go_to_suggestions": "Trobatz de monde de sègre",
"home.column_settings.basic": "Basic",
"home.column_settings.show_reblogs": "Mostrar los partatges",
"home.column_settings.show_replies": "Mostrar las responsas",
"home.hide_announcements": "Rescondre las anóncias",
"home.pending_critical_update.link": "Veire las mesas a jorn",
"home.show_announcements": "Mostrar las anóncias",
"interaction_modal.on_another_server": "Sus un autre servidor",
"interaction_modal.on_this_server": "Sus aqueste servidor",
@ -332,14 +346,17 @@
"mute_modal.hide_notifications": "Rescondre las notificacions daquesta persona?",
"mute_modal.indefinite": "Cap de data de fin",
"navigation_bar.about": "A prepaus",
"navigation_bar.advanced_interface": "Dobrir linterfàcia web avançada",
"navigation_bar.blocks": "Personas blocadas",
"navigation_bar.bookmarks": "Marcadors",
"navigation_bar.community_timeline": "Flux public local",
"navigation_bar.compose": "Escriure un nòu tut",
"navigation_bar.direct": "Mencions privadas",
"navigation_bar.discover": "Trobar",
"navigation_bar.domain_blocks": "Domenis resconduts",
"navigation_bar.edit_profile": "Modificar lo perfil",
"navigation_bar.explore": "Explorar",
"navigation_bar.favourites": "Favorits",
"navigation_bar.filters": "Mots ignorats",
"navigation_bar.follow_requests": "Demandas dabonament",
"navigation_bar.followed_tags": "Etiquetas seguidas",
@ -369,6 +386,7 @@
"notifications.column_settings.admin.report": "Senhalaments novèls:",
"notifications.column_settings.admin.sign_up": "Nòus inscrits:",
"notifications.column_settings.alert": "Notificacions localas",
"notifications.column_settings.favourite": "Favorits :",
"notifications.column_settings.filter_bar.advanced": "Mostrar totas las categorias",
"notifications.column_settings.filter_bar.category": "Barra de recèrca rapida",
"notifications.column_settings.filter_bar.show_bar": "Afichar la barra de filtres",
@ -386,6 +404,7 @@
"notifications.column_settings.update": "Modificacions:",
"notifications.filter.all": "Totas",
"notifications.filter.boosts": "Partages",
"notifications.filter.favourites": "Favorits",
"notifications.filter.follows": "Seguiments",
"notifications.filter.mentions": "Mencions",
"notifications.filter.polls": "Resultats del sondatge",
@ -399,15 +418,21 @@
"notifications_permission_banner.enable": "Activar las notificacions burèu",
"notifications_permission_banner.how_to_control": "Per recebre las notificacions de Mastodon quand es pas dobèrt, activatz las notificacions de burèu. Podètz precisar quin tipe de notificacion generarà una notificacion de burèu via lo boton {icon} dessús un còp activadas.",
"notifications_permission_banner.title": "Manquetz pas jamai res",
"onboarding.action.back": "Tornar en rèire",
"onboarding.actions.back": "Tornar en rèire",
"onboarding.actions.go_to_explore": "See what's trending",
"onboarding.actions.go_to_home": "Go to your home feed",
"onboarding.compose.template": "Adiu #Mastodon !",
"onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!",
"onboarding.follows.title": "Popular on Mastodon",
"onboarding.share.title": "Partejar vòstre perfil",
"onboarding.start.lead": "Your new Mastodon account is ready to go. Here's how you can make the most of it:",
"onboarding.start.skip": "Want to skip right ahead?",
"onboarding.start.title": "Tot es prèst !",
"onboarding.steps.follow_people.body": "You curate your own feed. Lets fill it with interesting people.",
"onboarding.steps.follow_people.title": "Follow {count, plural, one {one person} other {# people}}",
"onboarding.steps.publish_status.body": "Say hello to the world.",
"onboarding.steps.publish_status.title": "Escrivètz vòstre primièr tut",
"onboarding.steps.setup_profile.body": "Others are more likely to interact with you with a filled out profile.",
"onboarding.steps.setup_profile.title": "Customize your profile",
"onboarding.steps.share_profile.body": "Let your friends know how to find you on Mastodon!",
@ -415,6 +440,7 @@
"picture_in_picture.restore": "Lo tornar",
"poll.closed": "Tampat",
"poll.refresh": "Actualizar",
"poll.reveal": "Veire los resultats",
"poll.total_people": "{count, plural, one {# persona} other {# personas}}",
"poll.total_votes": "{count, plural, one {# vòte} other {# vòtes}}",
"poll.vote": "Votar",
@ -482,11 +508,17 @@
"report_notification.open": "Dobrir lo senhalament",
"search.placeholder": "Recercar",
"search.search_or_paste": "Recercar o picar una URL",
"search_popout.language_code": "Còdi ISO de lenga",
"search_popout.options": "Opcions de recèrca",
"search_popout.quick_actions": "Accions rapidas",
"search_popout.recent": "Recèrcas recentas",
"search_popout.specific_date": "data especifica",
"search_popout.user": "utilizaire",
"search_results.accounts": "Perfils",
"search_results.all": "Tot",
"search_results.hashtags": "Etiquetas",
"search_results.nothing_found": "Cap de resultat per aquestes tèrmes de recèrca",
"search_results.see_all": "O veire tot",
"search_results.statuses": "Tuts",
"search_results.title": "Recèrca: {q}",
"server_banner.active_users": "utilizaires actius",
@ -506,16 +538,20 @@
"status.copy": "Copiar lo ligam de lestatut",
"status.delete": "Escafar",
"status.detailed_status": "Vista detalhada de la convèrsa",
"status.direct_indicator": "Mencion privada",
"status.edit": "Modificar",
"status.edited": "Modificat {date}",
"status.edited_x_times": "Modificat {count, plural, un {{count} còp} other {{count} còps}}",
"status.embed": "Embarcar",
"status.favourite": "Apondre als favorits",
"status.filter": "Filtrar aquesta publicacion",
"status.filtered": "Filtrat",
"status.hide": "Amagar la publicacion",
"status.history.created": "{name} o creèt lo {date}",
"status.history.edited": "{name} o modifiquèt lo {date}",
"status.load_more": "Cargar mai",
"status.media.open": "Clicar per dobrir",
"status.media.show": "Clicar per mostar",
"status.media_hidden": "Mèdia rescondut",
"status.mention": "Mencionar",
"status.more": "Mai",
@ -546,6 +582,7 @@
"status.title.with_attachments": "{user} posted {attachmentCount, plural, one {an attachment} other {# attachments}}",
"status.translate": "Traduire",
"status.translated_from_with": "Traduch del {lang} amb {provider}",
"status.uncached_media_warning": "Apercebut indisponible",
"status.unmute_conversation": "Tornar mostrar la conversacion",
"status.unpin": "Tirar del perfil",
"subscribed_languages.lead": "Sonque las publicacions dins las lengas seleccionadas apreissaràn dins vòstre acuèlh e linha cronologica aprèp aqueste cambiament. Seleccionatz pas res per recebre las publicacions en quina lenga que siá.",

View File

@ -218,7 +218,10 @@
"home.hide_announcements": "නිවේදන සඟවන්න",
"home.pending_critical_update.link": "යාවත්කාල බලන්න",
"home.show_announcements": "නිවේදන පෙන්වන්න",
"interaction_modal.login.action": "මුලට ගෙනයන්න",
"interaction_modal.on_this_server": "මෙම සේවාදායකයෙහි",
"interaction_modal.title.favourite": "{name}ගේ ලිපිය ප්‍රිය කරන්න",
"interaction_modal.title.follow": "{name} අනුගමනය",
"intervals.full.days": "{number, plural, one {දවස් #} other {දවස් #}}",
"intervals.full.hours": "{number, plural, one {පැය #} other {පැය #}}",
"intervals.full.minutes": "{number, plural, one {විනාඩි #} other {විනාඩි #}}",
@ -319,6 +322,7 @@
"notifications.mark_as_read": "සියළු දැනුම්දීම් කියවූ බව යොදන්න",
"notifications_permission_banner.enable": "වැඩතල දැනුම්දීම් සබල කරන්න",
"notifications_permission_banner.title": "කිසිවක් අතපසු නොකරන්න",
"onboarding.actions.go_to_explore": "නැගී එන දෑ වෙත ගෙනයන්න",
"onboarding.compose.template": "ආයුබෝ #මාස්ටඩන්!",
"onboarding.share.title": "ඔබගේ පැතිකඩ බෙදාගන්න",
"onboarding.steps.publish_status.title": "පළමු ලිපිය පළ කරන්න",
@ -358,6 +362,7 @@
"report.categories.other": "වෙනත්",
"report.categories.spam": "ආයාචිත",
"report.categories.violation": "අන්තර්ගතය නිසා සේවාදායකයේ නීතියක් හෝ කිහිපයක් කඩ වේ",
"report.category.subtitle": "හොඳම ගැලපීම තෝරන්න",
"report.category.title": "මෙම {type}සමඟ සිදුවන්නේ කුමක්දැයි අපට කියන්න",
"report.category.title_account": "පැතිකඩ",
"report.category.title_status": "ලිපිය",
@ -394,14 +399,25 @@
"report_notification.categories.spam": "ආයාචිත",
"report_notification.categories.violation": "නීතිය කඩ කිරීම",
"report_notification.open": "විවෘත වාර්තාව",
"search.no_recent_searches": "මෑත සෙවීම් නැත",
"search.placeholder": "සොයන්න",
"search.quick_action.account_search": "ගැළපෙන පැතිකඩ {x}",
"search.quick_action.go_to_account": "{x} පැතිකඩ වෙත යන්න",
"search.quick_action.open_url": "ලිපිනය මාස්ටඩන්හි අරින්න",
"search.quick_action.status_search": "ගැළපෙන ලිපි {x}",
"search.search_or_paste": "සොයන්න හෝ ඒ.ස.නි. අලවන්න",
"search_popout.options": "සෙවුම් විකල්ප",
"search_popout.quick_actions": "ඉක්මන් ක්‍රියාමාර්ග",
"search_popout.recent": "මෑත සෙවීම්",
"search_popout.specific_date": "නිශ්චිත දිනයකට",
"search_popout.user": "පරිශ්‍රීලකයා",
"search_results.accounts": "පැතිකඩ",
"search_results.all": "සියල්ල",
"search_results.nothing_found": "මෙම සෙවුම් පද සඳහා කිසිවක් සොයාගත නොහැකි විය",
"search_results.see_all": "සියල්ල බලන්න",
"search_results.statuses": "ලිපි",
"search_results.title": "{q} සොයන්න",
"server_banner.active_users": "සක්‍රිය පරිශ්‍රීලකයින්",
"server_banner.learn_more": "තව දැනගන්න",
"sign_in_banner.create_account": "ගිණුමක් සාදන්න",
"sign_in_banner.sign_in": "පිවිසෙන්න",

View File

@ -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",

View File

@ -79,16 +79,16 @@
"admin.impact_report.instance_accounts": "Профілі облікових записів буде видалено",
"admin.impact_report.instance_followers": "Підписники, яких можуть втратити наші користувачі",
"admin.impact_report.instance_follows": "Підписники, яких можуть втратити їхні користувачі",
"admin.impact_report.title": "Наслідки",
"alert.rate_limited.message": "Спробуйте ще раз через {retry_time, time, medium}.",
"admin.impact_report.title": "Підсумки впливу",
"alert.rate_limited.message": "Спробуйте ще раз за {retry_time, time, medium}.",
"alert.rate_limited.title": "Швидкість обмежена",
"alert.unexpected.message": "Сталася неочікувана помилка.",
"alert.unexpected.title": "Ой!",
"announcement.announcement": "Оголошення",
"attachments_list.unprocessed": "(не оброблено)",
"audio.hide": "Сховати аудіо",
"autosuggest_hashtag.per_week": "{count} в тиждень",
"boost_modal.combo": "Ви можете натиснути {combo}, щоб пропустити це наступного разу",
"autosuggest_hashtag.per_week": "{count} на тиждень",
"boost_modal.combo": "Ви можете натиснути {combo}, щоби пропустити це наступного разу",
"bundle_column_error.copy_stacktrace": "Копіювати звіт про помилку",
"bundle_column_error.error.body": "Неможливо показати запитану сторінку. Це може бути спричинено помилкою у нашому коді, або через проблему сумісності з браузером.",
"bundle_column_error.error.title": "О, ні!",
@ -140,7 +140,7 @@
"compose.saved.body": "Допис збережено.",
"compose_form.direct_message_warning_learn_more": "Дізнатися більше",
"compose_form.encryption_warning": "Дописи на Mastodon не захищені шифруванням. Не поширюйте жодну делікатну інформацію.",
"compose_form.hashtag_warning": ей допис не буде зображений у жодній стрічці гештеґу, оскільки він прихований. Тільки публічні дописи можуть бути знайдені за гештеґом.",
"compose_form.hashtag_warning": ього допису не буде під жодним гештеґом, оскільки він не є загальнодоступним. За гештеґом можна шукати лише публічні дописи.",
"compose_form.lock_disclaimer": "Ваш обліковий запис не {locked}. Будь-який користувач може підписатися на вас та переглядати ваші дописи для підписників.",
"compose_form.lock_disclaimer.lock": "приватний",
"compose_form.placeholder": "Що у вас на думці?",
@ -151,7 +151,7 @@
"compose_form.poll.switch_to_multiple": "Дозволити вибір декількох відповідей",
"compose_form.poll.switch_to_single": "Перемкнути у режим вибору однієї відповіді",
"compose_form.publish": "Опублікувати",
"compose_form.publish_form": "Опублікувати",
"compose_form.publish_form": "Новий допис",
"compose_form.publish_loud": "{publish}!",
"compose_form.save_changes": "Зберегти зміни",
"compose_form.sensitive.hide": "{count, plural, one {Позначити медіа делікатним} other {Позначити медіа делікатними}}",
@ -206,7 +206,7 @@
"dismissable_banner.explore_tags": "Ці хештеги зараз набирають популярності серед людей на цьому та інших серверах децентралізованої мережі. Хештеги, які використовуються більшою кількістю людей, мають вищий рейтинг.",
"dismissable_banner.public_timeline": "Це найновіші загальнодоступні дописи від людей в соціальній мережі, на які підписані люди в {domain}.",
"embed.instructions": "Вбудуйте цей допис до вашого вебсайту, скопіювавши код нижче.",
"embed.preview": "Ось як він виглядатиме:",
"embed.preview": "Ось який вигляд це матиме:",
"emoji_button.activity": "Діяльність",
"emoji_button.clear": "Очистити",
"emoji_button.custom": "Власні",
@ -227,7 +227,7 @@
"empty_column.account_unavailable": "Профіль недоступний",
"empty_column.blocks": "Ви ще не заблокували жодного користувача.",
"empty_column.bookmarked_statuses": "У вас ще немає дописів у закладках. Коли ви щось додасте до закладок, воно з'явиться тут.",
"empty_column.community": "Локальна стрічка пуста. Напишіть щось, щоб розігріти народ!",
"empty_column.community": "Локальна стрічка порожня. Напишіть щось, щоб розігріти народ!",
"empty_column.direct": "У вас ще немає жодних особистих згадок. Коли ви надсилаєте чи отримуєте повідомлення, воно з'явиться тут.",
"empty_column.domain_blocks": "Тут поки немає прихованих доменів.",
"empty_column.explore_statuses": "Нема нічого популярного. Подивіться пізніше!",
@ -240,10 +240,10 @@
"empty_column.list": "Цей список порожній. Коли його учасники додадуть нові дописи, вони з'являться тут.",
"empty_column.lists": "У вас ще немає списків. Коли ви їх створите, вони з'являться тут.",
"empty_column.mutes": "Ви ще не приховали жодного користувача.",
"empty_column.notifications": "У вас ще немає сповіщень. Переписуйтесь з іншими користувачами, щоб почати розмову.",
"empty_column.notifications": "У вас ще немає сповіщень. Коли інші люди почнуть взаємодіяти з вами, ви побачите їх тут.",
"empty_column.public": "Тут поки нічого немає! Опублікуйте щось, або вручну підпишіться на користувачів інших серверів, щоб заповнити стрічку",
"error.unexpected_crash.explanation": "Через помилку у нашому коді або несумісність браузера, ця сторінка не може бути зображена коректно.",
"error.unexpected_crash.explanation_addons": "Неможливо правильно показати цю сторінку. Ймовірно, цю помилку викликано додатком браузера або автоматичним засобом перекладу.",
"error.unexpected_crash.explanation_addons": "Неможливо правильно показати цю сторінку. Ймовірно, цю помилку спричинило розширення браузера або автоматичний засіб перекладу.",
"error.unexpected_crash.next_steps": "Спробуйте перезавантажити сторінку. Якщо це не допоможе, ви все ще зможете використовувати Mastodon через інший браузер або рідний застосунок.",
"error.unexpected_crash.next_steps_addons": "Спробуйте їх вимкнути та оновити сторінку. Якщо це не допомагає, ви можете використовувати Mastodon через інший браузер або окремий застосунок.",
"errors.unexpected_crash.copy_stacktrace": "Скопіювати трасування стека у буфер обміну",
@ -394,7 +394,7 @@
"moved_to_account_banner.text": "Ваш обліковий запис {disabledAccount} наразі вимкнений, оскільки вас перенесено до {movedToAccount}.",
"mute_modal.duration": "Тривалість",
"mute_modal.hide_notifications": "Сховати сповіщення цього користувача?",
"mute_modal.indefinite": "Назавжди",
"mute_modal.indefinite": "Невизначений строк",
"navigation_bar.about": "Про застосунок",
"navigation_bar.advanced_interface": "Відкрити в розширеному вебінтерфейсі",
"navigation_bar.blocks": "Заблоковані користувачі",
@ -428,7 +428,7 @@
"notification.follow": "{name} підписалися на вас",
"notification.follow_request": "{name} відправили запит на підписку",
"notification.mention": "{name} згадали вас",
"notification.own_poll": "Ваше опитування завершено",
"notification.own_poll": "Ваше опитування завершилося",
"notification.poll": "Опитування, у якому ви голосували, скінчилося",
"notification.reblog": "{name} поширює ваш допис",
"notification.status": "{name} щойно дописує",
@ -480,7 +480,7 @@
"onboarding.follows.title": "Персоналізуйте домашню стрічку",
"onboarding.share.lead": "Розкажіть людям про те, як вони можуть знайти вас на Mastodon!",
"onboarding.share.message": "Я {username} на #Mastodon! Стежте за мною на {url}",
"onboarding.share.next_steps": "Можливі наступні кроки:",
"onboarding.share.next_steps": "Можливі такі кроки:",
"onboarding.share.title": "Поділитися своїм профілем",
"onboarding.start.lead": "Тепер ви — частина Mastodon, унікальної децентралізованої платформи соціальних медіа, де ви, а не алгоритми керують вашими вподобаннями. Розпочнімо роботу:",
"onboarding.start.skip": "Хочете пропустити?",
@ -694,7 +694,7 @@
"units.short.thousand": "{count} тис",
"upload_area.title": "Перетягніть сюди, щоб завантажити",
"upload_button.label": "Додати зображення, відео або аудіо",
"upload_error.limit": "Ліміт завантаження файлів перевищено.",
"upload_error.limit": "Ви перевищили ліміт завантаження файлів.",
"upload_error.poll": "Не можна завантажувати файли до опитувань.",
"upload_form.audio_description": "Опишіть для людей із вадами слуху",
"upload_form.description": "Опишіть для людей з вадами зору",
@ -713,7 +713,7 @@
"upload_modal.hint": "Клацніть або перетягніть коло на превʼю, щоб обрати точку, яку буде завжди видно на мініатюрах.",
"upload_modal.preparing_ocr": "Підготовка OCR…",
"upload_modal.preview_label": "Переглянути ({ratio})",
"upload_progress.label": "Завантаження...",
"upload_progress.label": "Вивантаження...",
"upload_progress.processing": "Обробка…",
"username.taken": "Це ім'я користувача вже зайнято. Спробуйте інше",
"video.close": "Закрити відео",

View File

@ -114,7 +114,7 @@
"column.directory": "瀏覽個人檔案",
"column.domain_blocks": "已封鎖網域",
"column.favourites": "最愛",
"column.firehose": "即時內容",
"column.firehose": "即時河道",
"column.follow_requests": "跟隨請求",
"column.home": "首頁",
"column.lists": "列表",
@ -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} 的管理員認為您可能想要自己審核這些帳號的跟隨請求。",
@ -409,7 +409,7 @@
"navigation_bar.favourites": "最愛",
"navigation_bar.filters": "已靜音的關鍵字",
"navigation_bar.follow_requests": "跟隨請求",
"navigation_bar.followed_tags": "已跟隨主題標籤",
"navigation_bar.followed_tags": "已跟隨主題標籤",
"navigation_bar.follows_and_followers": "跟隨中與跟隨者",
"navigation_bar.lists": "列表",
"navigation_bar.logout": "登出",

View File

@ -217,6 +217,7 @@ class FeedManager
# also tagged with another followed hashtag or from a followed user
scope = from_tag.statuses
.where(id: timeline_status_ids)
.where.not(account: into_account)
.where.not(account: into_account.following)
.tagged_with_none(TagFollow.where(account: into_account).pluck(:tag_id))

View File

@ -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

View File

@ -58,6 +58,8 @@ class SearchQueryTransformer < Parslet::Transform
case @flags['in']
when 'library'
[StatusesIndex]
when 'public'
[PublicStatusesIndex]
else
[PublicStatusesIndex, StatusesIndex]
end

View File

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

View File

@ -34,7 +34,7 @@ class Form::CustomEmojiBatch
end
def update!
custom_emojis.each { |custom_emoji| authorize(custom_emoji, :update?) }
verify_authorization(:update?)
category = if category_id.present?
CustomEmojiCategory.find(category_id)
@ -49,7 +49,7 @@ class Form::CustomEmojiBatch
end
def list!
custom_emojis.each { |custom_emoji| authorize(custom_emoji, :update?) }
verify_authorization(:update?)
custom_emojis.each do |custom_emoji|
custom_emoji.update(visible_in_picker: true)
@ -58,7 +58,7 @@ class Form::CustomEmojiBatch
end
def unlist!
custom_emojis.each { |custom_emoji| authorize(custom_emoji, :update?) }
verify_authorization(:update?)
custom_emojis.each do |custom_emoji|
custom_emoji.update(visible_in_picker: false)
@ -67,7 +67,7 @@ class Form::CustomEmojiBatch
end
def enable!
custom_emojis.each { |custom_emoji| authorize(custom_emoji, :enable?) }
verify_authorization(:enable?)
custom_emojis.each do |custom_emoji|
custom_emoji.update(disabled: false)
@ -76,7 +76,7 @@ class Form::CustomEmojiBatch
end
def disable!
custom_emojis.each { |custom_emoji| authorize(custom_emoji, :disable?) }
verify_authorization(:disable?)
custom_emojis.each do |custom_emoji|
custom_emoji.update(disabled: true)
@ -85,7 +85,7 @@ class Form::CustomEmojiBatch
end
def copy!
custom_emojis.each { |custom_emoji| authorize(custom_emoji, :copy?) }
verify_authorization(:copy?)
custom_emojis.each do |custom_emoji|
copied_custom_emoji = custom_emoji.copy!
@ -94,11 +94,15 @@ class Form::CustomEmojiBatch
end
def delete!
custom_emojis.each { |custom_emoji| authorize(custom_emoji, :destroy?) }
verify_authorization(:destroy?)
custom_emojis.each do |custom_emoji|
custom_emoji.destroy
log_action :destroy, custom_emoji
end
end
def verify_authorization(permission)
custom_emojis.each { |custom_emoji| authorize(custom_emoji, permission) }
end
end

View File

@ -21,11 +21,15 @@ class Form::IpBlockBatch
end
def delete!
ip_blocks.each { |ip_block| authorize(ip_block, :destroy?) }
verify_authorization(:destroy?)
ip_blocks.each do |ip_block|
ip_block.destroy
log_action :destroy, ip_block
end
end
def verify_authorization(permission)
ip_blocks.each { |ip_block| authorize(ip_block, permission) }
end
end

View File

@ -16,11 +16,18 @@ class ManifestSerializer < ActiveModel::Serializer
512
).freeze
attributes :name, :short_name,
attributes :id, :name, :short_name,
:icons, :theme_color, :background_color,
:display, :start_url, :scope,
:share_target, :shortcuts
def id
# This is set to `/home` because that was the old value of `start_url` and
# thus the fallback ID computed by Chrome:
# https://developer.chrome.com/blog/pwa-manifest-id/
'/home'
end
def name
object.title
end
@ -53,7 +60,7 @@ class ManifestSerializer < ActiveModel::Serializer
end
def start_url
'/home'
'/'
end
def scope

View File

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

View File

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

View File

@ -57,7 +57,7 @@ class ReportService < BaseService
def forward_to_replied_to!
# Send report to servers to which the account was replying to, so they also have a chance to act
inbox_urls = Account.remote.where(domain: forward_to_domains).where(id: Status.where(id: reported_status_ids).where.not(in_reply_to_account_id: nil).select(:in_reply_to_account_id)).inboxes - [@target_account.inbox_url]
inbox_urls = Account.remote.where(domain: forward_to_domains).where(id: Status.where(id: reported_status_ids).where.not(in_reply_to_account_id: nil).select(:in_reply_to_account_id)).inboxes - [@target_account.inbox_url, @target_account.shared_inbox_url]
inbox_urls.each do |inbox_url|
ActivityPub::DeliveryWorker.perform_async(payload, some_local_account.id, inbox_url)

View File

@ -28,7 +28,13 @@ class UpdateAccountService < BaseService
end
def check_links(account)
VerifyAccountLinksWorker.perform_async(account.id) if account.fields.any?(&:requires_verification?)
return unless account.fields.any?(&:requires_verification?)
if account.local?
VerifyAccountLinksWorker.perform_async(account.id)
else
VerifyAccountLinksWorker.perform_in(rand(10.minutes.to_i), account.id)
end
end
def process_hashtags(account)

View File

@ -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]
end
usernames_with_no_accounts = usernames_and_domains.filter_map do |(str, username, domain)|
str unless Account.find_remote(username, domain)
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'))
[string, username, domain]
end
end
def usernames_with_no_accounts
usernames_and_domains.filter_map do |(string, username, domain)|
string unless Account.find_remote(username, domain)
end
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

View File

@ -11,16 +11,31 @@ class UnreservedUsernameValidator < ActiveModel::Validator
private
def pam_controlled?
return false unless Devise.pam_authentication && Devise.pam_controlled_service
Rpam2.account(Devise.pam_controlled_service, @username).present?
def reserved_username?
pam_username_reserved? || settings_username_reserved?
end
def reserved_username?
return true if pam_controlled?
return false unless Setting.reserved_usernames
def pam_username_reserved?
pam_controlled? && pam_reserves_username?
end
def pam_controlled?
Devise.pam_authentication && Devise.pam_controlled_service
end
def pam_reserves_username?
Rpam2.account(Devise.pam_controlled_service, @username)
end
def settings_username_reserved?
settings_has_reserved_usernames? && settings_reserves_username?
end
def settings_has_reserved_usernames?
Setting.reserved_usernames.present?
end
def settings_reserves_username?
Setting.reserved_usernames.include?(@username.downcase)
end
end

View File

@ -0,0 +1,41 @@
- if account.suspended?
%hr.spacer/
- if account.suspension_origin_remote?
%p.muted-hint= deletion_request.present? ? t('admin.accounts.remote_suspension_reversible_hint_html', date: content_tag(:strong, l(deletion_request.due_at.to_date))) : t('admin.accounts.remote_suspension_irreversible')
- else
%p.muted-hint= deletion_request.present? ? t('admin.accounts.suspension_reversible_hint_html', date: content_tag(:strong, l(deletion_request.due_at.to_date))) : t('admin.accounts.suspension_irreversible')
= link_to t('admin.accounts.undo_suspension'), unsuspend_admin_account_path(account.id), method: :post, class: 'button' if can?(:unsuspend, account)
= link_to t('admin.accounts.redownload'), redownload_admin_account_path(account.id), method: :post, class: 'button' if can?(:redownload, account) && account.suspension_origin_remote?
- if deletion_request.present?
= link_to t('admin.accounts.delete'), admin_account_path(account.id), method: :delete, class: 'button button--destructive', data: { confirm: t('admin.accounts.are_you_sure') } if can?(:destroy, account)
- else
.action-buttons
%div
- if account.local? && account.user_approved?
= link_to t('admin.accounts.warn'), new_admin_account_action_path(account.id, type: 'none'), class: 'button' if can?(:warn, account)
- if account.user_disabled?
= link_to t('admin.accounts.enable'), enable_admin_account_path(account.id), method: :post, class: 'button' if can?(:enable, account.user)
- else
= link_to t('admin.accounts.disable'), new_admin_account_action_path(account.id, type: 'disable'), class: 'button' if can?(:disable, account.user)
- if account.sensitized?
= link_to t('admin.accounts.undo_sensitized'), unsensitive_admin_account_path(account.id), method: :post, class: 'button' if can?(:unsensitive, account)
- elsif !account.local? || account.user_approved?
= link_to t('admin.accounts.sensitive'), new_admin_account_action_path(account.id, type: 'sensitive'), class: 'button' if can?(:sensitive, account)
- if account.silenced?
= link_to t('admin.accounts.undo_silenced'), unsilence_admin_account_path(account.id), method: :post, class: 'button' if can?(:unsilence, account)
- elsif !account.local? || account.user_approved?
= link_to t('admin.accounts.silence'), new_admin_account_action_path(account.id, type: 'silence'), class: 'button' if can?(:silence, account)
- if account.local?
- if account.user_pending?
= link_to t('admin.accounts.approve'), approve_admin_account_path(account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button' if can?(:approve, account.user)
= link_to t('admin.accounts.reject'), reject_admin_account_path(account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button button--destructive' if can?(:reject, account.user)
- unless account.user_confirmed?
= link_to t('admin.accounts.confirm'), admin_account_confirmation_path(account.id), method: :post, class: 'button' if can?(:confirm, account.user)
- if !account.local? || account.user_approved?
= link_to t('admin.accounts.perform_full_suspension'), new_admin_account_action_path(account.id, type: 'suspend'), class: 'button' if can?(:suspend, account)
%div
- if account.local?
- if !account.memorial? && account.user_approved?
= link_to t('admin.accounts.memorialize'), memorialize_admin_account_path(account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button button--destructive' if can?(:memorialize, account)
- else
= link_to t('admin.accounts.redownload'), redownload_admin_account_path(account.id), method: :post, class: 'button' if can?(:redownload, account)

View File

@ -0,0 +1,43 @@
.dashboard__counters.admin-account-counters
%div
= link_to admin_account_statuses_path(account.id) do
.dashboard__counters__num= number_with_delimiter account.statuses_count
.dashboard__counters__label= t 'admin.accounts.statuses'
%div
= link_to admin_account_statuses_path(account.id, { media: true }) do
.dashboard__counters__num= number_to_human_size account.media_attachments.sum('file_file_size')
.dashboard__counters__label= t 'admin.accounts.media_attachments'
%div
= link_to admin_account_relationships_path(account.id, location: account.local? ? nil : 'local', relationship: 'followed_by') do
.dashboard__counters__num= number_with_delimiter account.local_followers_count
.dashboard__counters__label= t 'admin.accounts.followers'
%div
= link_to admin_reports_path(account_id: account.id) do
.dashboard__counters__num= number_with_delimiter account.reports.count
.dashboard__counters__label= t 'admin.accounts.show.created_reports'
%div
= link_to admin_reports_path(target_account_id: account.id) do
.dashboard__counters__num= number_with_delimiter account.targeted_reports.count
.dashboard__counters__label= t 'admin.accounts.show.targeted_reports'
%div
= link_to admin_action_logs_path(target_account_id: account.id) do
.dashboard__counters__text
- if account.local? && account.user.nil?
= t('admin.accounts.deleted')
- elsif account.memorial?
= t('admin.accounts.memorialized')
- elsif account.suspended?
= t('admin.accounts.suspended')
- elsif account.silenced?
= t('admin.accounts.silenced')
- elsif account.local? && account.user&.disabled?
= t('admin.accounts.disabled')
- elsif account.local? && !account.user&.confirmed?
= t('admin.accounts.confirming')
- elsif account.local? && !account.user_approved?
= t('admin.accounts.pending')
- elsif account.sensitized?
= t('admin.accounts.sensitive')
- else
= t('admin.accounts.no_limits_imposed')
.dashboard__counters__label= t 'admin.accounts.login_status'

View File

@ -0,0 +1,82 @@
- if account.avatar?
%tr
%th= t('admin.accounts.avatar')
%td= table_link_to 'trash', t('admin.accounts.remove_avatar'), remove_avatar_admin_account_path(account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if can?(:remove_avatar, account)
%td
- if account.header?
%tr
%th= t('admin.accounts.header')
%td= table_link_to 'trash', t('admin.accounts.remove_header'), remove_header_admin_account_path(account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if can?(:remove_header, account)
%td
%tr
%th= t('admin.accounts.role')
%td
- if account.user_role&.everyone?
= t('admin.accounts.no_role_assigned')
- else
= account.user_role&.name
%td
= table_link_to 'vcard', t('admin.accounts.change_role.label'), admin_user_role_path(account.user) if can?(:change_role, account.user)
%tr
%th{ rowspan: can?(:create, :email_domain_block) ? 3 : 2 }= t('admin.accounts.email')
%td{ rowspan: can?(:create, :email_domain_block) ? 3 : 2 }= account.user_email
%td= table_link_to 'edit', t('admin.accounts.change_email.label'), admin_account_change_email_path(account.id) if can?(:change_email, account.user)
%tr
%td= table_link_to 'search', t('admin.accounts.search_same_email_domain'), admin_accounts_path(email: "%@#{account.user_email.split('@').last}")
- if can?(:create, :email_domain_block)
%tr
%td= table_link_to 'ban', t('admin.accounts.add_email_domain_block'), new_admin_email_domain_block_path(_domain: account.user_email.split('@').last)
- if account.user_unconfirmed_email.present?
%tr
%th= t('admin.accounts.unconfirmed_email')
%td= account.user_unconfirmed_email
%td
%tr
%th= t('admin.accounts.email_status')
%td
- if account.user&.confirmed?
= t('admin.accounts.confirmed')
- else
= t('admin.accounts.confirming')
%td= table_link_to 'refresh', t('admin.accounts.resend_confirmation.send'), resend_admin_account_confirmation_path(account.id), method: :post if can?(:confirm, account.user)
%tr
%th{ rowspan: can?(:reset_password, account.user) ? 2 : 1 }= t('admin.accounts.security')
%td{ rowspan: can?(:reset_password, account.user) ? 2 : 1 }
- if account.user&.two_factor_enabled?
= t 'admin.accounts.security_measures.password_and_2fa'
- else
= t 'admin.accounts.security_measures.only_password'
%td
- if account.user&.two_factor_enabled?
= table_link_to 'unlock', t('admin.accounts.disable_two_factor_authentication'), admin_user_two_factor_authentication_path(account.user.id), method: :delete if can?(:disable_2fa, account.user)
- if can?(:reset_password, account.user)
%tr
%td
= table_link_to 'key', t('admin.accounts.reset_password'), admin_account_reset_path(account.id), method: :create, data: { confirm: t('admin.accounts.are_you_sure') }
%tr
%th= t('simple_form.labels.defaults.locale')
%td= standard_locale_name(account.user_locale)
%td
%tr
%th= t('admin.accounts.joined')
%td
%time.formatted{ datetime: account.created_at.iso8601, title: l(account.created_at) }= l account.created_at
%td
- recent_ips = account.user.ips.order(used_at: :desc).to_a
- recent_ips.each_with_index do |recent_ip, i|
%tr
- if i.zero?
%th{ rowspan: recent_ips.size }= t('admin.accounts.most_recent_ip')
%td= recent_ip.ip
%td= table_link_to 'search', t('admin.accounts.search_same_ip'), admin_accounts_path(ip: recent_ip.ip)
%tr
%th= t('admin.accounts.most_recent_activity')
%td
- if account.user_current_sign_in_at
%time.formatted{ datetime: account.user_current_sign_in_at.iso8601, title: l(account.user_current_sign_in_at) }= l account.user_current_sign_in_at
%td
- if account.user&.invited?
%tr
%th= t('admin.accounts.invited_by')
%td= admin_account_link_to account.user.invite.user.account
%td

View File

@ -0,0 +1,15 @@
%tr
%th= t('admin.accounts.inbox_url')
%td
= account.inbox_url
= fa_icon DeliveryFailureTracker.available?(account.inbox_url) ? 'check' : 'times'
%td
= table_link_to 'search', domain_block.present? ? t('admin.domain_blocks.view') : t('admin.accounts.view_domain'), admin_instance_path(account.domain)
%tr
%th= t('admin.accounts.shared_inbox_url')
%td
= account.shared_inbox_url
= fa_icon DeliveryFailureTracker.available?(account.shared_inbox_url) ? 'check' : 'times'
%td
- if domain_block.nil?
= table_link_to 'ban', t('admin.domain_blocks.add_new'), new_admin_domain_block_path(_domain: account.domain)

View File

@ -27,49 +27,7 @@
%div
.account__header__content.emojify= prerender_custom_emojis(account_bio_format(account), account.emojis)
.dashboard__counters.admin-account-counters
%div
= link_to admin_account_statuses_path(@account.id) do
.dashboard__counters__num= number_with_delimiter @account.statuses_count
.dashboard__counters__label= t 'admin.accounts.statuses'
%div
= link_to admin_account_statuses_path(@account.id, { media: true }) do
.dashboard__counters__num= number_to_human_size @account.media_attachments.sum('file_file_size')
.dashboard__counters__label= t 'admin.accounts.media_attachments'
%div
= link_to admin_account_relationships_path(@account.id, location: @account.local? ? nil : 'local', relationship: 'followed_by') do
.dashboard__counters__num= number_with_delimiter @account.local_followers_count
.dashboard__counters__label= t 'admin.accounts.followers'
%div
= link_to admin_reports_path(account_id: @account.id) do
.dashboard__counters__num= number_with_delimiter @account.reports.count
.dashboard__counters__label= t '.created_reports'
%div
= link_to admin_reports_path(target_account_id: @account.id) do
.dashboard__counters__num= number_with_delimiter @account.targeted_reports.count
.dashboard__counters__label= t '.targeted_reports'
%div
= link_to admin_action_logs_path(target_account_id: @account.id) do
.dashboard__counters__text
- if @account.local? && @account.user.nil?
= t('admin.accounts.deleted')
- elsif @account.memorial?
= t('admin.accounts.memorialized')
- elsif @account.suspended?
= t('admin.accounts.suspended')
- elsif @account.silenced?
= t('admin.accounts.silenced')
- elsif @account.local? && @account.user&.disabled?
= t('admin.accounts.disabled')
- elsif @account.local? && !@account.user&.confirmed?
= t('admin.accounts.confirming')
- elsif @account.local? && !@account.user_approved?
= t('admin.accounts.pending')
- elsif @account.sensitized?
= t('admin.accounts.sensitive')
- else
= t('admin.accounts.no_limits_imposed')
.dashboard__counters__label= t 'admin.accounts.login_status'
= render 'admin/accounts/counters', account: @account
- if @account.local? && @account.user.nil?
= link_to t('admin.accounts.unblock_email'), unblock_email_admin_account_path(@account.id), method: :post, class: 'button' if can?(:unblock_email, @account) && CanonicalEmailBlock.exists?(reference_account_id: @account.id)
@ -78,171 +36,11 @@
%table.table.inline-table
%tbody
- if @account.local?
- if @account.avatar?
%tr
%th= t('admin.accounts.avatar')
%td= table_link_to 'trash', t('admin.accounts.remove_avatar'), remove_avatar_admin_account_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if can?(:remove_avatar, @account)
%td
- if @account.header?
%tr
%th= t('admin.accounts.header')
%td= table_link_to 'trash', t('admin.accounts.remove_header'), remove_header_admin_account_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if can?(:remove_header, @account)
%td
%tr
%th= t('admin.accounts.role')
%td
- if @account.user_role&.everyone?
= t('admin.accounts.no_role_assigned')
- else
= @account.user_role&.name
%td
= table_link_to 'vcard', t('admin.accounts.change_role.label'), admin_user_role_path(@account.user) if can?(:change_role, @account.user)
%tr
%th{ rowspan: can?(:create, :email_domain_block) ? 3 : 2 }= t('admin.accounts.email')
%td{ rowspan: can?(:create, :email_domain_block) ? 3 : 2 }= @account.user_email
%td= table_link_to 'edit', t('admin.accounts.change_email.label'), admin_account_change_email_path(@account.id) if can?(:change_email, @account.user)
%tr
%td= table_link_to 'search', t('admin.accounts.search_same_email_domain'), admin_accounts_path(email: "%@#{@account.user_email.split('@').last}")
- if can?(:create, :email_domain_block)
%tr
%td= table_link_to 'ban', t('admin.accounts.add_email_domain_block'), new_admin_email_domain_block_path(_domain: @account.user_email.split('@').last)
- if @account.user_unconfirmed_email.present?
%tr
%th= t('admin.accounts.unconfirmed_email')
%td= @account.user_unconfirmed_email
%td
%tr
%th= t('admin.accounts.email_status')
%td
- if @account.user&.confirmed?
= t('admin.accounts.confirmed')
- else
= t('admin.accounts.confirming')
%td= table_link_to 'refresh', t('admin.accounts.resend_confirmation.send'), resend_admin_account_confirmation_path(@account.id), method: :post if can?(:confirm, @account.user)
%tr
%th{ rowspan: can?(:reset_password, @account.user) ? 2 : 1 }= t('admin.accounts.security')
%td{ rowspan: can?(:reset_password, @account.user) ? 2 : 1 }
- if @account.user&.two_factor_enabled?
= t 'admin.accounts.security_measures.password_and_2fa'
- else
= t 'admin.accounts.security_measures.only_password'
%td
- if @account.user&.two_factor_enabled?
= table_link_to 'unlock', t('admin.accounts.disable_two_factor_authentication'), admin_user_two_factor_authentication_path(@account.user.id), method: :delete if can?(:disable_2fa, @account.user)
- if can?(:reset_password, @account.user)
%tr
%td
= table_link_to 'key', t('admin.accounts.reset_password'), admin_account_reset_path(@account.id), method: :create, data: { confirm: t('admin.accounts.are_you_sure') }
%tr
%th= t('simple_form.labels.defaults.locale')
%td= standard_locale_name(@account.user_locale)
%td
%tr
%th= t('admin.accounts.joined')
%td
%time.formatted{ datetime: @account.created_at.iso8601, title: l(@account.created_at) }= l @account.created_at
%td
- recent_ips = @account.user.ips.order(used_at: :desc).to_a
- recent_ips.each_with_index do |recent_ip, i|
%tr
- if i.zero?
%th{ rowspan: recent_ips.size }= t('admin.accounts.most_recent_ip')
%td= recent_ip.ip
%td= table_link_to 'search', t('admin.accounts.search_same_ip'), admin_accounts_path(ip: recent_ip.ip)
%tr
%th= t('admin.accounts.most_recent_activity')
%td
- if @account.user_current_sign_in_at
%time.formatted{ datetime: @account.user_current_sign_in_at.iso8601, title: l(@account.user_current_sign_in_at) }= l @account.user_current_sign_in_at
%td
- if @account.user&.invited?
%tr
%th= t('admin.accounts.invited_by')
%td= admin_account_link_to @account.user.invite.user.account
%td
= render 'admin/accounts/local_account', account: @account
- else
%tr
%th= t('admin.accounts.inbox_url')
%td
= @account.inbox_url
= fa_icon DeliveryFailureTracker.available?(@account.inbox_url) ? 'check' : 'times'
%td
= table_link_to 'search', @domain_block.present? ? t('admin.domain_blocks.view') : t('admin.accounts.view_domain'), admin_instance_path(@account.domain)
%tr
%th= t('admin.accounts.shared_inbox_url')
%td
= @account.shared_inbox_url
= fa_icon DeliveryFailureTracker.available?(@account.shared_inbox_url) ? 'check' : 'times'
%td
- if @domain_block.nil?
= table_link_to 'ban', t('admin.domain_blocks.add_new'), new_admin_domain_block_path(_domain: @account.domain)
= render 'admin/accounts/remote_account', account: @account, domain_block: @domain_block
- if @account.suspended?
%hr.spacer/
- if @account.suspension_origin_remote?
%p.muted-hint= @deletion_request.present? ? t('admin.accounts.remote_suspension_reversible_hint_html', date: content_tag(:strong, l(@deletion_request.due_at.to_date))) : t('admin.accounts.remote_suspension_irreversible')
- else
%p.muted-hint= @deletion_request.present? ? t('admin.accounts.suspension_reversible_hint_html', date: content_tag(:strong, l(@deletion_request.due_at.to_date))) : t('admin.accounts.suspension_irreversible')
= link_to t('admin.accounts.undo_suspension'), unsuspend_admin_account_path(@account.id), method: :post, class: 'button' if can?(:unsuspend, @account)
= link_to t('admin.accounts.redownload'), redownload_admin_account_path(@account.id), method: :post, class: 'button' if can?(:redownload, @account) && @account.suspension_origin_remote?
- if @deletion_request.present?
= link_to t('admin.accounts.delete'), admin_account_path(@account.id), method: :delete, class: 'button button--destructive', data: { confirm: t('admin.accounts.are_you_sure') } if can?(:destroy, @account)
- else
.action-buttons
%div
- if @account.local? && @account.user_approved?
= link_to t('admin.accounts.warn'), new_admin_account_action_path(@account.id, type: 'none'), class: 'button' if can?(:warn, @account)
- if @account.user_disabled?
= link_to t('admin.accounts.enable'), enable_admin_account_path(@account.id), method: :post, class: 'button' if can?(:enable, @account.user)
- else
= link_to t('admin.accounts.disable'), new_admin_account_action_path(@account.id, type: 'disable'), class: 'button' if can?(:disable, @account.user)
- if @account.sensitized?
= link_to t('admin.accounts.undo_sensitized'), unsensitive_admin_account_path(@account.id), method: :post, class: 'button' if can?(:unsensitive, @account)
- elsif !@account.local? || @account.user_approved?
= link_to t('admin.accounts.sensitive'), new_admin_account_action_path(@account.id, type: 'sensitive'), class: 'button' if can?(:sensitive, @account)
- if @account.silenced?
= link_to t('admin.accounts.undo_silenced'), unsilence_admin_account_path(@account.id), method: :post, class: 'button' if can?(:unsilence, @account)
- elsif !@account.local? || @account.user_approved?
= link_to t('admin.accounts.silence'), new_admin_account_action_path(@account.id, type: 'silence'), class: 'button' if can?(:silence, @account)
- if @account.local?
- if @account.user_pending?
= link_to t('admin.accounts.approve'), approve_admin_account_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button' if can?(:approve, @account.user)
= link_to t('admin.accounts.reject'), reject_admin_account_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button button--destructive' if can?(:reject, @account.user)
- unless @account.user_confirmed?
= link_to t('admin.accounts.confirm'), admin_account_confirmation_path(@account.id), method: :post, class: 'button' if can?(:confirm, @account.user)
- if !@account.local? || @account.user_approved?
= link_to t('admin.accounts.perform_full_suspension'), new_admin_account_action_path(@account.id, type: 'suspend'), class: 'button' if can?(:suspend, @account)
%div
- if @account.local?
- if !@account.memorial? && @account.user_approved?
= link_to t('admin.accounts.memorialize'), memorialize_admin_account_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button button--destructive' if can?(:memorialize, @account)
- else
= link_to t('admin.accounts.redownload'), redownload_admin_account_path(@account.id), method: :post, class: 'button' if can?(:redownload, @account)
= render 'admin/accounts/buttons', account: @account, deletion_request: @deletion_request
%hr.spacer/

View File

@ -4,7 +4,7 @@
= image_tag appeal.account.avatar.url(:original), alt: '', width: 40, height: 40, class: 'avatar'
.log-entry__content
.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
%time.formatted{ datetime: appeal.strike.created_at.iso8601 }
= l(appeal.strike.created_at)

View File

@ -1,11 +1,11 @@
= form_tag preview_admin_report_actions_path(@report), method: :post do
= form_tag preview_admin_report_actions_path(report), method: :post do
.report-actions
.report-actions__item
.report-actions__item__button
= link_to t('admin.reports.mark_as_resolved'), resolve_admin_report_path(@report), method: :post, class: 'button'
= link_to t('admin.reports.mark_as_resolved'), resolve_admin_report_path(report), method: :post, class: 'button'
.report-actions__item__description
= t('admin.reports.actions.resolve_description_html')
- if @statuses.any? { |status| (status.with_media? || status.with_preview_card?) && !status.discarded? }
- if statuses.any? { |status| (status.with_media? || status.with_preview_card?) && !status.discarded? }
.report-actions__item
.report-actions__item__button
= button_tag t('admin.reports.mark_as_sensitive'), name: :mark_as_sensitive, class: 'button'
@ -28,6 +28,6 @@
= t('admin.reports.actions.suspend_description_html')
.report-actions__item
.report-actions__item__button
= link_to t('admin.accounts.custom'), new_admin_account_action_path(@report.target_account_id, report_id: @report.id), class: 'button'
= link_to t('admin.accounts.custom'), new_admin_account_action_path(report.target_account_id, report_id: report.id), class: 'button'
.report-actions__item__description
= t('admin.reports.actions.other_description_html')

View File

@ -0,0 +1,24 @@
- if report.account.instance_actor?
%p= t('admin.reports.comment_description_html', name: content_tag(:strong, site_hostname, class: 'username'))
- elsif report.account.local?
%p= t('admin.reports.comment_description_html', name: content_tag(:strong, report.account.username, class: 'username'))
- else
%p= t('admin.reports.comment_description_html', name: t('admin.reports.remote_user_placeholder', instance: report.account.domain))
.report-notes
.report-notes__item
- if report.account.local? && !report.account.instance_actor?
= image_tag report.account.avatar.url, class: 'report-notes__item__avatar'
- else
= image_tag(full_asset_url('avatars/original/missing.png', skip_pipeline: true), class: 'report-notes__item__avatar')
.report-notes__item__header
%span.username
- if report.account.instance_actor?
= site_hostname
- elsif report.account.local?
= link_to report.account.username, admin_account_path(report.account_id)
- else
= link_to report.account.domain, admin_instance_path(report.account.domain)
%time.relative-formatted{ datetime: report.created_at.iso8601 }
= l report.created_at.to_date
.report-notes__item__content
= simple_format(h(report.comment))

View File

@ -0,0 +1,46 @@
.report-header__card
.account-card
.account-card__header
= image_tag report.target_account.header.url, alt: ''
.account-card__title
.account-card__title__avatar
= image_tag report.target_account.avatar.url, alt: ''
.display-name
%bdi
%strong.emojify.p-name= display_name(report.target_account, custom_emojify: true)
%span
= acct(report.target_account)
= fa_icon('lock') if report.target_account.locked?
- if report.target_account.note.present?
.account-card__bio.emojify
= prerender_custom_emojis(account_bio_format(report.target_account), report.target_account.emojis)
.account-card__actions
.account-card__counters
.account-card__counters__item
= friendly_number_to_human report.target_account.statuses_count
%small= t('accounts.posts', count: report.target_account.statuses_count).downcase
.account-card__counters__item
= friendly_number_to_human report.target_account.followers_count
%small= t('accounts.followers', count: report.target_account.followers_count).downcase
.account-card__counters__item
= friendly_number_to_human report.target_account.following_count
%small= t('accounts.following', count: report.target_account.following_count).downcase
.account-card__actions__button
= link_to t('admin.reports.view_profile'), admin_account_path(report.target_account_id), class: 'button'
.report-header__details.report-header__details--horizontal
.report-header__details__item
.report-header__details__item__header
%strong= t('admin.accounts.joined')
.report-header__details__item__content
%time.time-ago{ datetime: report.target_account.created_at.iso8601, title: l(report.target_account.created_at) }= l report.target_account.created_at
.report-header__details__item
.report-header__details__item__header
%strong= t('accounts.last_active')
.report-header__details__item__content
- if report.target_account.last_status_at.present?
%time.time-ago{ datetime: report.target_account.last_status_at.to_date.iso8601, title: l(report.target_account.last_status_at.to_date) }= l report.target_account.last_status_at
.report-header__details__item
.report-header__details__item__header
%strong= t('admin.accounts.strikes')
.report-header__details__item__content
= report.target_account.previous_strikes_count

View File

@ -0,0 +1,53 @@
.report-header__details
.report-header__details__item
.report-header__details__item__header
%strong= t('admin.reports.created_at')
.report-header__details__item__content
%time.formatted{ datetime: report.created_at.iso8601 }
.report-header__details__item
.report-header__details__item__header
%strong= t('admin.reports.reported_by')
.report-header__details__item__content
- if report.account.instance_actor?
= site_hostname
- elsif report.account.local?
= admin_account_link_to report.account
- else
= report.account.domain
.report-header__details__item
.report-header__details__item__header
%strong= t('admin.reports.status')
.report-header__details__item__content
- if report.action_taken?
= t('admin.reports.resolved')
- else
= t('admin.reports.unresolved')
- unless report.target_account.local?
.report-header__details__item
.report-header__details__item__header
%strong= t('admin.reports.forwarded')
.report-header__details__item__content
- if report.forwarded?
= t('simple_form.yes')
- else
= t('simple_form.no')
- if report.action_taken_by_account.present?
.report-header__details__item
.report-header__details__item__header
%strong= t('admin.reports.action_taken_by')
.report-header__details__item__content
= admin_account_link_to report.action_taken_by_account
- else
.report-header__details__item
.report-header__details__item__header
%strong= t('admin.reports.assigned')
.report-header__details__item__content
- if report.assigned_account.nil?
= t 'admin.reports.no_one_assigned'
- else
= admin_account_link_to report.assigned_account
- if report.assigned_account != current_user.account
= table_link_to 'user', t('admin.reports.assign_to_self'), assign_to_self_admin_report_path(report), method: :post
- elsif !report.assigned_account.nil?
= table_link_to 'trash', t('admin.reports.unassign'), unassign_admin_report_path(report), method: :post

View File

@ -8,106 +8,8 @@
= link_to t('admin.reports.mark_as_unresolved'), reopen_admin_report_path(@report), method: :post, class: 'button'
.report-header
.report-header__card
.account-card
.account-card__header
= image_tag @report.target_account.header.url, alt: ''
.account-card__title
.account-card__title__avatar
= image_tag @report.target_account.avatar.url, alt: ''
.display-name
%bdi
%strong.emojify.p-name= display_name(@report.target_account, custom_emojify: true)
%span
= acct(@report.target_account)
= fa_icon('lock') if @report.target_account.locked?
- if @report.target_account.note.present?
.account-card__bio.emojify
= prerender_custom_emojis(account_bio_format(@report.target_account), @report.target_account.emojis)
.account-card__actions
.account-card__counters
.account-card__counters__item
= friendly_number_to_human @report.target_account.statuses_count
%small= t('accounts.posts', count: @report.target_account.statuses_count).downcase
.account-card__counters__item
= friendly_number_to_human @report.target_account.followers_count
%small= t('accounts.followers', count: @report.target_account.followers_count).downcase
.account-card__counters__item
= friendly_number_to_human @report.target_account.following_count
%small= t('accounts.following', count: @report.target_account.following_count).downcase
.account-card__actions__button
= link_to t('admin.reports.view_profile'), admin_account_path(@report.target_account_id), class: 'button'
.report-header__details.report-header__details--horizontal
.report-header__details__item
.report-header__details__item__header
%strong= t('admin.accounts.joined')
.report-header__details__item__content
%time.time-ago{ datetime: @report.target_account.created_at.iso8601, title: l(@report.target_account.created_at) }= l @report.target_account.created_at
.report-header__details__item
.report-header__details__item__header
%strong= t('accounts.last_active')
.report-header__details__item__content
- if @report.target_account.last_status_at.present?
%time.time-ago{ datetime: @report.target_account.last_status_at.to_date.iso8601, title: l(@report.target_account.last_status_at.to_date) }= l @report.target_account.last_status_at
.report-header__details__item
.report-header__details__item__header
%strong= t('admin.accounts.strikes')
.report-header__details__item__content
= @report.target_account.previous_strikes_count
.report-header__details
.report-header__details__item
.report-header__details__item__header
%strong= t('admin.reports.created_at')
.report-header__details__item__content
%time.formatted{ datetime: @report.created_at.iso8601 }
.report-header__details__item
.report-header__details__item__header
%strong= t('admin.reports.reported_by')
.report-header__details__item__content
- if @report.account.instance_actor?
= site_hostname
- elsif @report.account.local?
= admin_account_link_to @report.account
- else
= @report.account.domain
.report-header__details__item
.report-header__details__item__header
%strong= t('admin.reports.status')
.report-header__details__item__content
- if @report.action_taken?
= t('admin.reports.resolved')
- else
= t('admin.reports.unresolved')
- unless @report.target_account.local?
.report-header__details__item
.report-header__details__item__header
%strong= t('admin.reports.forwarded')
.report-header__details__item__content
- if @report.forwarded?
= t('simple_form.yes')
- else
= t('simple_form.no')
- if @report.action_taken_by_account.present?
.report-header__details__item
.report-header__details__item__header
%strong= t('admin.reports.action_taken_by')
.report-header__details__item__content
= admin_account_link_to @report.action_taken_by_account
- else
.report-header__details__item
.report-header__details__item__header
%strong= t('admin.reports.assigned')
.report-header__details__item__content
- if @report.assigned_account.nil?
= t 'admin.reports.no_one_assigned'
- else
= admin_account_link_to @report.assigned_account
- if @report.assigned_account != current_user.account
= table_link_to 'user', t('admin.reports.assign_to_self'), assign_to_self_admin_report_path(@report), method: :post
- elsif !@report.assigned_account.nil?
= table_link_to 'trash', t('admin.reports.unassign'), unassign_admin_report_path(@report), method: :post
= render 'admin/reports/header_card', report: @report
= render 'admin/reports/header_details', report: @report
%hr.spacer
@ -118,33 +20,7 @@
= react_admin_component :report_reason_selector, id: @report.id, category: @report.category, rule_ids: @report.rule_ids&.map(&:to_s), disabled: @report.action_taken?
- if @report.comment.present?
- if @report.account.instance_actor?
%p= t('admin.reports.comment_description_html', name: content_tag(:strong, site_hostname, class: 'username'))
- elsif @report.account.local?
%p= t('admin.reports.comment_description_html', name: content_tag(:strong, @report.account.username, class: 'username'))
- else
%p= t('admin.reports.comment_description_html', name: t('admin.reports.remote_user_placeholder', instance: @report.account.domain))
.report-notes
.report-notes__item
- if @report.account.local? && !@report.account.instance_actor?
= image_tag @report.account.avatar.url, class: 'report-notes__item__avatar'
- else
= image_tag(full_asset_url('avatars/original/missing.png', skip_pipeline: true), class: 'report-notes__item__avatar')
.report-notes__item__header
%span.username
- if @report.account.instance_actor?
= site_hostname
- elsif @report.account.local?
= link_to @report.account.username, admin_account_path(@report.account_id)
- else
= link_to @report.account.domain, admin_instance_path(@report.account.domain)
%time.relative-formatted{ datetime: @report.created_at.iso8601 }
= l @report.created_at.to_date
.report-notes__item__content
= simple_format(h(@report.comment))
= render 'admin/reports/comment', report: @report
%hr.spacer/
@ -179,7 +55,7 @@
%p#actions= t(@report.target_account.local? ? 'admin.reports.actions_description_html' : 'admin.reports.actions_description_remote_html')
= render partial: 'admin/reports/actions'
= render partial: 'admin/reports/actions', locals: { report: @report, statuses: @statuses }
- unless @action_logs.empty?
%hr.spacer/

View File

@ -1,30 +1,30 @@
- if !@user.confirmed?
- if !user.confirmed?
.flash-message.warning
= t('auth.status.confirming')
= link_to t('auth.didnt_get_confirmation'), new_user_confirmation_path
- elsif !@user.approved?
- elsif !user.approved?
.flash-message.warning
= t('auth.status.pending')
- elsif @user.account.moved_to_account_id.present?
- elsif user.account.moved_to_account_id.present?
.flash-message.warning
= t('auth.status.redirecting_to', acct: @user.account.moved_to_account.pretty_acct)
= t('auth.status.redirecting_to', acct: user.account.moved_to_account.pretty_acct)
= link_to t('migrations.cancel'), settings_migration_path
%h3= t('auth.status.account_status')
%p.hint
- if @user.account.suspended?
- if user.account.suspended?
%span.negative-hint= t('user_mailer.warning.explanation.suspend')
- elsif @user.disabled?
- elsif user.disabled?
%span.negative-hint= t('user_mailer.warning.explanation.disable')
- elsif @user.account.silenced?
- elsif user.account.silenced?
%span.warning-hint= t('user_mailer.warning.explanation.silence')
- else
%span.positive-hint= t('auth.status.functional')
= render partial: 'account_warning', collection: @strikes
= render partial: 'account_warning', collection: strikes
- if @user.account.strikes.exists?
- if user.account.strikes.exists?
%hr.spacer/
%p.muted-hint

View File

@ -1,7 +1,7 @@
- content_for :page_title do
= t('settings.account_settings')
= render 'status'
= render partial: 'status', locals: { user: @user, strikes: @strikes }
%h3= t('auth.security')

View File

@ -1,7 +1,7 @@
- content_for :page_title do
= t('auth.login')
- if @webauthn_enabled
- if webauthn_enabled?
= render partial: 'auth/sessions/two_factor/webauthn_form', locals: { hidden: @scheme_type != 'webauthn' }
= render partial: 'auth/sessions/two_factor/otp_authentication_form', locals: { hidden: @scheme_type != 'totp' }

View File

@ -13,6 +13,6 @@
- if Setting.site_contact_email.present?
%p.hint.subtle-hint= t('users.otp_lost_help_html', email: mail_to(Setting.site_contact_email, nil))
- if @webauthn_enabled
- if webauthn_enabled?
.form-footer
= link_to(t('auth.link_to_webauth'), '#', id: 'link-to-webauthn')

View 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')

View File

@ -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

View File

@ -6,7 +6,7 @@
%tbody
%tr
%td.accounts-table__interrelationships
= interrelationships_icon(@relationships, account.id)
= interrelationships_icon(relationships, account.id)
%td= account_link_to account
%td.accounts-table__count.optional
= friendly_number_to_human account.statuses_count

View File

@ -50,6 +50,6 @@
- if @accounts.empty?
= nothing_here 'nothing-here--under-tabs'
- else
= render partial: 'account', collection: @accounts, locals: { f: f }
= render partial: 'account', collection: @accounts, locals: { f: f, relationships: @relationships }
= paginate @accounts

View File

@ -1,62 +1,5 @@
{
"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": "Denial of Service",
"warning_code": 76,
"fingerprint": "7b6abba5699755348e7ee82a4694bfbf574b41c7cce2d0db0f7c11ae3f983c72",
"check_name": "RegexDoS",
"message": "Model attribute used in regular expression",
"file": "lib/mastodon/cli/domains.rb",
"line": 128,
"link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/",
"code": "/\\.?(#{DomainBlock.where(:severity => 1).pluck(:domain).map do\n Regexp.escape(domain)\n end.join(\"|\")})$/",
"render_path": null,
"location": {
"type": "method",
"class": "Mastodon::CLI::Domains",
"method": "crawl"
},
"user_input": "DomainBlock.where(:severity => 1).pluck(:domain)",
"confidence": "Weak",
"cwe_id": [
20,
185
],
"note": ""
},
{
"warning_type": "Cross-Site Scripting",
"warning_code": 4,

View File

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

View File

@ -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 = {

View File

@ -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

View File

@ -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'

View File

@ -11,7 +11,7 @@ fi:
locale: Alue
password: Salasana
user/account:
username: Käyttäjätunnus
username: Käyttäjänimi
user/invite_request:
text: Syy
errors:

View File

@ -53,3 +53,7 @@ sk:
position:
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
webhook:
attributes:
events:
invalid_permissions: nemožno zahrnúť udalosti, ku ktorým nemáte práva

View File

@ -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:

View File

@ -119,11 +119,11 @@ fi:
write: Vain kirjoitusoikeus
title:
accounts: Tilit
admin/accounts: Tilien hallinta
admin/accounts: Tilien hallinnointi
admin/all: Kaikki hallinnolliset toiminnot
admin/reports: Raporttien hallinta
admin/reports: Raporttien hallinnointi
all: Täysi pääsy Mastodon-tiliisi
blocks: Torjutut
blocks: Estot
bookmarks: Kirjanmerkit
conversations: Keskustelut
crypto: Päästä päähän -salaus

View File

@ -129,6 +129,7 @@ sk:
crypto: Šifrovanie End-to-end
favourites: Obľúbené
filters: Filtre
follow: Sledovanie, stlmenie a blokovanie
follows: Sledovania
lists: Zoznamy
media: Mediálne prílohy
@ -148,9 +149,19 @@ sk:
scopes:
admin:read: prezeraj všetky dáta na serveri
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:write: uprav všetky dáta na serveri
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
crypto: používať end-to-end šifrovanie
follow: uprav vzťahy svojho účtu
@ -159,6 +170,7 @@ sk:
read:accounts: prezri si informácie o účte
read:blocks: prezri svoje bloky
read:bookmarks: pozri svoje záložky
read:favourites: zobraziť vaše obľúbené
read:filters: prezri svoje filtrovanie
read:follows: prezri si svoje sledovania
read:lists: prezri si svoje zoznamy

View File

@ -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!
@ -28,12 +28,12 @@ fi:
title: Suorita valvontatoimi käyttäjälle %{acct}
account_moderation_notes:
create: Jätä muistiinpano
created_msg: Valvontamerkinnän luonti onnistui!
destroyed_msg: Valvontamerkinnän poisto onnistui!
created_msg: Valvontamuistiinpanon luonti onnistui!
destroyed_msg: Valvontamuistiinpanon poisto onnistui!
accounts:
add_email_domain_block: Estä sähköpostidomain
add_email_domain_block: Estä sähköpostiverkkotunnus
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?
avatar: Profiilikuva
by_domain: Verkkotunnus
@ -96,10 +96,10 @@ fi:
silenced: Rajoitettu
suspended: Jäädytetty
title: Valvonta
moderation_notes: Valvontamerkinnät
moderation_notes: Valvontamuistiinpanot
most_recent_activity: Viimeisin toiminta
most_recent_ip: Viimeisin IP
no_account_selected: Yhtään tiliä ei muutettu, koska mitään ei valittu
no_account_selected: Tilejä ei muutettu, koska yhtään ei ollut valittuna
no_limits_imposed: Rajoituksia ei ole asetettu
no_role_assigned: Roolia ei ole määritetty
not_subscribed: Ei tilaaja
@ -118,7 +118,7 @@ fi:
reject: Hylkää
rejected_msg: Käyttäjän %{username} rekisteröitymishakemus hylättiin
remote_suspension_irreversible: Tämän tilin tiedot on poistettu peruuttamattomasti.
remote_suspension_reversible_hint_html: Tili on jäädytetty heidän palvelimellaan, ja kaikki tiedot poistetaan %{date}. Sitä ennen etäpalvelin voi palauttaa tilin ongelmitta. Jos haluat poistaa kaikki tilin tiedot heti, onnistuu se alta.
remote_suspension_reversible_hint_html: Tili on jäädytetty omalla palvelimellaan, ja kaikki tiedot poistetaan %{date}. Sitä ennen etäpalvelin voi palauttaa tilin ongelmitta. Jos haluat poistaa kaikki tilin tiedot heti, onnistuu se alta.
remove_avatar: Poista profiilikuva
remove_header: Poista otsakekuva
removed_avatar_msg: Käyttäjän %{username} avatar-kuva poistettu onnistuneesti
@ -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,17 +157,17 @@ 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
unsubscribe: Lopeta tilaus
unsuspended_msg: Tilin %{username} jäädytyksen kumoaminen onnistui
username: Käyttäjätunnus
username: Käyttäjänimi
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
@ -182,7 +182,7 @@ fi:
create_custom_emoji: Luo mukautettu emoji
create_domain_allow: Luo verkkotunnuksen salliminen
create_domain_block: Luo verkkotunnuksen esto
create_email_domain_block: Luo sähköpostin verkkotunnuksen esto
create_email_domain_block: Luo sähköpostiverkkotunnuksen esto
create_ip_block: Luo IP-sääntö
create_unavailable_domain: Luo ei-saatavilla oleva verkkotunnus
create_user_role: Luo rooli
@ -192,7 +192,7 @@ fi:
destroy_custom_emoji: Poista mukautettu emoji
destroy_domain_allow: Poista verkkotunnuksen salliminen
destroy_domain_block: Poista verkkotunnuksen esto
destroy_email_domain_block: Poista sähköpostin verkkotunnuksen esto
destroy_email_domain_block: Poista sähköpostiverkkotunnuksen esto
destroy_instance: Tyhjennä verkkotunnus
destroy_ip_block: Poista IP-sääntö
destroy_status: Poista julkaisu
@ -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
@ -237,21 +237,21 @@ fi:
confirm_user_html: "%{name} vahvisti käyttäjän %{target} sähköpostiosoitteen"
create_account_warning_html: "%{name} lähetti varoituksen käyttäjälle %{target}"
create_announcement_html: "%{name} loi uuden tiedotteen %{target}"
create_canonical_email_block_html: "%{name} esti sähköpostin hashilla %{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öpostin %{target}"
create_email_domain_block_html: "%{name} esti sähköpostiverkkotunnuksen %{target}"
create_ip_block_html: "%{name} loi IP-säännön %{target}"
create_unavailable_domain_html: "%{name} pysäytti toimituksen verkkotunnukseen %{target}"
create_user_role_html: "%{name} loi roolin %{target}"
demote_user_html: "%{name} alensi käyttäjän %{target}"
destroy_announcement_html: "%{name} poisti tiedotteen %{target}"
destroy_canonical_email_block_html: "%{name} poisti sähköpostieston hashilla %{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öpostin verkkotunnuksen %{target} eston"
destroy_email_domain_block_html: "%{name} poisti sähköpostiverkkotunnuksen %{target} eston"
destroy_instance_html: "%{name} tyhjensi verkkotunnuksen %{target}"
destroy_ip_block_html: "%{name} poisti IP-säännön %{target}"
destroy_status_html: "%{name} poisti käyttäjän %{target} julkaisun"
@ -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}"
@ -332,7 +332,7 @@ fi:
listed: Listalla
new:
title: Lisää uusi mukautettu emoji
no_emoji_selected: Emojeita ei muutettu, koska yhtään ei valittu
no_emoji_selected: Emojeita ei muutettu, koska yhtään ei ollut valittuna
not_permitted: Sinulla ei ole oikeutta suorittaa tätä toimintoa
overwrite: Korvaa
shortcode: Lyhennekoodi
@ -364,7 +364,7 @@ fi:
other: "<strong>%{count}</strong> odottavaa käyttäjää"
resolved_reports: ratkaistut raportit
software: Ohjelmisto
sources: Rekisteröitymisen lähteet
sources: Rekisteröitymislähteet
space: Tilankäyttö
title: Hallintapaneeli
top_languages: Aktiivisimmat kielet
@ -375,14 +375,14 @@ 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
add_new: Lisää uusi verkkotunnuksen esto
confirm_suspension:
cancel: Peruuta
confirm: Jäädytä
@ -409,7 +409,7 @@ fi:
silence: Rajoita
suspend: Jäädytä
title: Uusi verkkotunnuksen esto
no_domain_block_selected: Verkkoalue-estoihin ei tehty muutoksia, koska valintoja ei tehty
no_domain_block_selected: Verkkotunnusten estoja ei muutettu, koska yhtään ei ollut valittuna
not_permitted: Nykyiset käyttöoikeutesi eivät kata tätä toimintoa
obfuscate: Peitä verkkotunnuksen nimi
obfuscate_hint: Peitä verkkotunnus osittain luettelossa, jos julkinen verkkotunnusten rajoitusluettelo on käytössä
@ -421,14 +421,14 @@ fi:
reject_media_hint: Poistaa paikallisesti tallennetut mediatiedostot eikä lataa niitä enää jatkossa. Ei merkitystä jäähyn kohdalla
reject_reports: Hylkää raportit
reject_reports_hint: Ohita kaikki tästä verkkotunnuksesta tulevat raportit. Erottamisen kannalta ei merkitystä
undo: Peru
undo: Peru verkkotunnuksen esto
view: Näytä verkkotunnuksen esto
email_domain_blocks:
add_new: Lisää uusi
attempts_over_week:
one: "%{count} yritystä viimeisen viikon aikana"
other: "%{count} rekisteröitymisyritystä viimeisen viikon aikana"
created_msg: Sähköpostiverkkotunnuksen lisäys estolistalle onnistui
created_msg: Sähköpostiverkkotunnus estetty onnistuneesti
delete: Poista
dns:
types:
@ -437,26 +437,26 @@ fi:
new:
create: Lisää verkkotunnus
resolve: Ratkaise verkkotunnus
title: Uusi sähköpostiestolistan merkintä
no_email_domain_block_selected: Sähköpostin verkkotunnuksia ei muutettu, koska yhtään ei valittu
title: Estä uusi sähköpostiverkkotunnus
no_email_domain_block_selected: Sähköpostin verkkotunnuksia ei muutettu, koska yhtään ei ollut valittuna
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
title: Sähköpostiestolista
title: Estetyt sähköpostiverkkotunnukset
export_domain_allows:
new:
title: Tuo sallitut verkkoalueet
title: Tuo sallittuja verkkotunnuksia
no_file: Yhtäkään tiedostoa ei ole valittu
export_domain_blocks:
import:
description_html: Olet tuomassa verkkotunnusten estoluetteloa. Tarkista luettelo huolella etenkin, jos et ole laatinut sitä itse.
existing_relationships_warning: Olemassa olevat seuraussuhteet
private_comment_description_html: 'Tuodun estolistan alkuperän selvillä pitämiseksi, lisätään tietojen yhteyteen seuraava yksityinen kommentti: <q>%{comment}</q>'
private_comment_template: Tuotu lähteestä %{source}, pvm %{date}
title: Tuo luettelo verkkoalue-estoista
invalid_domain_block: 'Yksi tai useampi verkkotunnuksen lohko ohitettiin seuraavien virheiden vuoksi: %{error}'
private_comment_description_html: 'Seurataksesi tuotujen estojen alkuperää lisätään estojen yhteyteen seuraava yksityinen kommentti: <q>%{comment}</q>'
private_comment_template: Tuotu lähteestä %{source} %{date}
title: Tuo verkkotunnusten estoja
invalid_domain_block: 'Yksi tai useampi verkkotunnuksen esto ohitettiin seuraavien virheiden vuoksi: %{error}'
new:
title: Tuo luettelo verkkoalue-estoista
title: Tuo verkkotunnusten estoja
no_file: Yhtäkään tiedostoa ei ole valittu
follow_recommendations:
description_html: "<strong>Seuraamissuositukset auttavat uusia käyttäjiä löytämään nopeasti kiinnostavaa sisältöä</strong>. Kun käyttäjä ei ole ollut tarpeeksi vuorovaikutuksessa muiden kanssa, jotta hänelle olisi muodostunut henkilökohtaisia seuraamissuosituksia, suositellaan niiden sijaan näitä tilejä. Ne lasketaan päivittäin uudelleen yhdistelmästä tilejä, jotka ovat viime aikoina olleet aktiivisimmin sitoutuneita ja joilla on suurimmat paikalliset seuraajamäärät tietyllä kielellä."
@ -482,9 +482,9 @@ fi:
back_to_limited: Rajoitettu
back_to_warning: Varoitus
by_domain: Verkkotunnus
confirm_purge: Oletko varma, että haluat pysyvästi poistaa tiedot tältä verkkotunnukselta?
confirm_purge: Haluatko varmasti poistaa pysyvästi tämän verkkotunnuksen tiedot?
content_policies:
comment: Sisäinen huomautus
comment: Sisäinen muistiinpano
description_html: Voit määrittää sisältökäytännöt, joita sovelletaan kaikkiin tämän verkkotunnuksen ja sen aliverkkotunnuksien tileihin.
limited_federation_mode_description_html: Voit valita sallitaanko federointi tällä verkkotunnuksella.
policies:
@ -527,8 +527,8 @@ 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
total_blocked_by_us: Estetty meidän toimesta
title: Liittoutuminen
total_blocked_by_us: Estämämme
total_followed_by_them: Heidän seuraama
total_followed_by_us: Meidän seuraama
total_reported: Niitä koskevat raportit
@ -555,14 +555,14 @@ fi:
'94670856': 3 vuotta
new:
title: Luo uusi IP-sääntö
no_ip_block_selected: IP-sääntöjä ei muutettu, koska yhtään ei ole valittuna
no_ip_block_selected: IP-sääntöjä ei muutettu, koska yhtään ei ollut valittuna
title: IP-säännöt
relationships:
title: "%{acct}n suhteet"
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
@ -576,13 +576,13 @@ fi:
status: Tila
title: Välittäjät
report_notes:
created_msg: Muistiinpano onnistuneesti lisätty raporttiin!
destroyed_msg: Muistiinpano onnistuneesti poistettu raportista!
created_msg: Muistiinpano lisätty raporttiin onnistuneesti!
destroyed_msg: Muistiinpano poistettu raportista onnistuneesti!
reports:
account:
notes:
one: "%{count} ilmoitus"
other: "%{count} ilmoitusta"
one: "%{count} muistiinpano"
other: "%{count} muistiinpanoa"
action_log: Tarkastusloki
action_taken_by: Toimen tehnyt
actions:
@ -621,8 +621,8 @@ fi:
create_and_unresolve: Avaa uudelleen ja lisää muistiinpano
delete: Poista
placeholder: Kuvaile mitä toimia on tehty tai muita päivityksiä tähän raporttiin…
title: Merkinnät
notes_description_html: Tarkastele ja jätä merkintöjä muille valvojille ja itsellesi tulevaisuuteen
title: Muistiinpanot
notes_description_html: Tarkastele ja jätä muistiinpanoja muille valvojille ja itsellesi tulevaisuuteen
processed_msg: 'Raportti #%{id} käsitelty'
quick_actions_description_html: 'Suorita nopea toiminto tai vieritä alas nähdäksesi raportoitu sisältö:'
remote_user_placeholder: etäkäyttäjä instanssista %{instance}
@ -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
everyone: Oletus 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.
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.
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_description: Sallii käyttäjien tarkistaa nousussa olevan sisällön ja päivittää aihetunnisteiden asetuksia
manage_user_access: Hallitse käyttäjäoikeuksia
manage_taxonomies: Hallita luokittelua
manage_taxonomies_description: Sallii käyttäjien tarkistaa suositun sisällön ja päivittää aihetunnisteiden asetuksia
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,14 +732,14 @@ 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:
preamble: Mukauta Mastodonin verkkokäyttöliittymää.
preamble: Mukauta Mastodonin selainkäyttöliittymää.
title: Ulkoasu
branding:
preamble: Palvelimesi brändäys erottaa sen muista verkon palvelimista. Nämä tiedot voivat näkyä monissa eri ympäristöissä, kuten Mastodonin verkkokäyttöliittymässä, natiivisovelluksissa, linkkien esikatseluissa muilla sivustoilla, viestintäsovelluksissa ja niin edelleen. Siksi nämä tiedot kannattaa pitää selkeinä, lyhyinä ja ytimekkäinä.
preamble: Palvelimesi brändäys erottaa sen muista verkon palvelimista. Nämä tiedot voivat näkyä monissa eri ympäristöissä, kuten Mastodonin selainkäyttöliittymässä, natiivisovelluksissa, linkkien esikatseluissa muilla sivustoilla, viestintäsovelluksissa ja niin edelleen. Siksi nämä tiedot kannattaa pitää selkeinä, lyhyinä ja ytimekkäinä.
title: Brändäys
captcha_enabled:
desc_html: Tämä perustuu ulkoisiin skripteihin hCaptchasta, mikä voi olla turvallisuus- ja yksityisyysongelma. Lisäksi <strong>tämä voi tehdä rekisteröinnin ihmisille huomattavasti (erityisesti vammaisten) helpommaksi</strong>. Harkitse vaihtoehtoisia toimenpiteitä, kuten hyväksymisperusteista tai kutsupohjaista rekisteröintiä.
@ -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
@ -808,13 +808,13 @@ fi:
media:
title: Media
metadata: Metadata
no_status_selected: Julkaisuja ei muutettu, koska yhtään ei ole valittuna
no_status_selected: Julkaisuja ei muutettu, koska yhtään ei ollut valittuna
open: Avaa julkaisu
original_status: Alkuperäinen julkaisu
reblogs: Edelleen jako
status_changed: Julkaisua muutettu
title: Tilin tilat
trending: Nousussa
trending: Suosituttua
visibility: Näkyvyys
with_media: Sisältää mediaa
strikes:
@ -833,7 +833,7 @@ fi:
database_schema_check:
message_html: Tietokannan siirto on vireillä. Suorita ne varmistaaksesi, että sovellus toimii odotetulla tavalla
elasticsearch_health_red:
message_html: Elasticsearch-klusteri on vikatilassa (punainen tila); hakuominaisuudet eivät ole käytettävissä
message_html: Elasticsearch-klusteri on vikatilassa (punainen tila), joten hakuominaisuudet eivät ole käytettävissä
elasticsearch_health_yellow:
message_html: Elasticsearch-klusteri on häiriötilassa (keltainen tila), joten suosittelemme tutkimaan syyn
elasticsearch_index_mismatch:
@ -843,13 +843,13 @@ fi:
message_html: Elasticsearch-klusterissa on useampi kuin yksi solmu, mutta Mastodonia ei ole määritetty käyttämään niitä.
elasticsearch_preset_single_node:
action: Katso käyttöohjeet
message_html: Elasticsearch-klusterissa on vain yksi solmu, <code>ES_PRESET</code> tulisi asettaa arvoon <code>single_node_cluster</code>.
message_html: Elasticsearch-klusterissa on vain yksi solmu. <code>ES_PRESET</code> tulisi asettaa arvoon <code>single_node_cluster</code>.
elasticsearch_reset_chewy:
message_html: Elasticsearch-järjestelmäindeksi on vanhentunut asetusmuutoksen vuoksi. Suorita <code>tootctl search deploy --reset-chewy</code> päivittääksesi sen.
elasticsearch_running_check:
message_html: Ei saatu yhteyttä Elasticsearch. Tarkista, että se on käynnissä tai poista kokotekstihaku käytöstä
message_html: Ei saatu yhteyttä Elasticsearchiin. Tarkista, että se on käynnissä tai poista kokotekstihaku käytöstä
elasticsearch_version_check:
message_html: 'Yhteensopimaton Elasticsearch versio: %{value}'
message_html: 'Yhteensopimaton Elasticsearch-versio: %{value}'
version_comparison: Elasticsearch %{running_version} on käynnissä, kun %{required_version} vaaditaan
rules_check:
action: Hallitse palvelimen sääntöjä
@ -882,9 +882,9 @@ fi:
description_html: Nämä ovat linkkejä, joita jaetaan tällä hetkellä paljon tileillä, joilta palvelimesi näkee viestejä. Se voi auttaa käyttäjiäsi saamaan selville, mitä maailmassa tapahtuu. Linkkejä ei näytetä julkisesti, ennen kuin hyväksyt julkaisijan. Voit myös sallia tai hylätä yksittäiset linkit.
disallow: Hylkää linkki
disallow_provider: Estä julkaisija
no_link_selected: Yhtään linkkiä ei muutettu, koska yhtään ei valittu
no_link_selected: Linkkejä ei muutettu, koska yhtään ei ollut valittuna
publishers:
no_publisher_selected: Julkaisijoita ei muutettu, koska yhtään ei valittu
no_publisher_selected: Julkaisijoita ei muutettu, koska yhtään ei ollut valittuna
shared_by_over_week:
one: Yksi henkilö jakanut viimeisen viikon aikana
other: Jakanut %{count} henkilöä viimeisen viikon aikana
@ -905,7 +905,7 @@ fi:
description_html: Nämä ovat julkaisuja, joita palvelimesi tietää jaettavan ja lisättävän suosikkeihin paljon tällä hetkellä. Listaus voi auttaa uusia ja palaavia käyttäjiäsi löytämään lisää seurattavia. Julkaisut eivät näy julkisesti ennen kuin hyväksyt niiden julkaisijan ja julkaisija sallii tilinsä ehdottamisen. Voit myös sallia tai hylätä yksittäisiä julkaisuja.
disallow: Kiellä julkaisu
disallow_account: Estä tekijä
no_status_selected: Suosittuja julkaisuja ei muutettu, koska yhtään ei ole valittuna
no_status_selected: Suosittuja julkaisuja ei muutettu, koska yhtään ei ollut valittuna
not_discoverable: Tekijä ei ole ilmoittanut olevansa löydettävissä
shared_by:
one: Jaettu tai lisätty suosikkeihin kerran
@ -921,21 +921,21 @@ fi:
tag_uses_measure: käyttökerrat
description_html: Nämä ovat aihetunnisteita, jotka näkyvät tällä hetkellä monissa julkaisuissa, jotka palvelimesi näkee. Tämä voi auttaa käyttäjiäsi selvittämään, mistä ihmiset puhuvat eniten tällä hetkellä. Mitään aihetunnisteita ei näytetä julkisesti, ennen kuin hyväksyt ne.
listable: Voidaan ehdottaa
no_tag_selected: Yhtään tagia ei muutettu, koska yhtään ei valittu
no_tag_selected: Tunnisteita ei muutettu, koska yhtään ei ollut valittuna
not_listable: Ei tulla ehdottamaan
not_trendable: Ei näy trendien alla
not_usable: Ei voida käyttää
peaked_on_and_decaying: Saavutti huipun %{date}, nyt hiipuu
title: Suositut aihetunnisteet
trendable: Voi näkyä trendien alla
trending_rank: 'Nousussa #%{rank}'
trending_rank: 'Suosittua #%{rank}'
usable: Voidaan käyttää
usage_comparison: Käytetty %{today} kertaa tänään, verrattuna %{yesterday} eiliseen
used_by_over_week:
one: Yhden henkilön käyttämä viime viikon aikana
other: Käyttänyt %{count} henkilöä viimeisen viikon aikana
title: Trendit
trending: Nousussa
trending: Suosittua
warning_presets:
add_new: Lisää uusi
delete: Poista
@ -995,8 +995,8 @@ fi:
new_trending_statuses:
title: Suositut julkaisut
new_trending_tags:
no_approved_tags: Tällä hetkellä ei ole hyväksyttyjä trendikkäitä aihetunnisteita.
requirements: 'Mikä tahansa näistä ehdokkaista voisi ylittää #%{rank} hyväksytyn trendikkään aihetunnisteen, joka on tällä hetkellä #%{lowest_tag_name} arvosanalla %{lowest_tag_score}.'
no_approved_tags: Tällä hetkellä ei ole hyväksyttyjä suosittuja aihetunnisteita.
requirements: 'Mikä tahansa näistä ehdokkaista voisi ylittää #%{rank} hyväksytyn suositun aihetunnisteen, joka on tällä hetkellä #%{lowest_tag_name} %{lowest_tag_score} pisteellä.'
title: Suositut aihetunnisteet
subject: Uusia trendejä tarkistettavaksi instanssissa %{instance}
aliases:
@ -1008,7 +1008,7 @@ fi:
remove: Poista aliaksen linkitys
appearance:
advanced_web_interface: Edistynyt selainkäyttöliittymä
advanced_web_interface_hint: 'Jos haluat hyödyntää näytön koko leveyttä, edistyneen webkäyttöliittymän avulla voit määrittää useita erilaisia sarakkeita, niin näet kerralla niin paljon tietoa kuin haluat: kotisyöte, ilmoitukset, yleinen aikajana, mikä tahansa määrä listoja ja aihetunnisteita.'
advanced_web_interface_hint: 'Jos haluat hyödyntää näytön koko leveyttä, edistyneen selainkäyttöliittymän avulla voit määrittää useita erilaisia sarakkeita, niin näet kerralla niin paljon tietoa kuin haluat: kotisyöte, ilmoitukset, yleinen aikajana, mikä tahansa määrä listoja ja aihetunnisteita.'
animations_and_accessibility: Animaatiot ja saavutettavuus
confirmation_dialogs: Vahvistusvalinnat
discovery: Löytäminen
@ -1089,7 +1089,7 @@ fi:
new_confirmation_instructions_sent: Saat uuden vahvistuslinkin sisältävän sähköpostiviestin muutamassa minuutissa!
title: Tarkista sähköpostilaatikkosi
sign_in:
preamble_html: Kirjaudu <strong>%{domain}</strong>-tunnuksellasi. Jos tilisi sijaitsee eri palvelimella, et voi kirjautua täällä.
preamble_html: Kirjaudu <strong>%{domain}</strong>-tunnuksellasi. Jos tilisi sijaitsee eri palvelimella, et voi kirjautua tässä.
title: Kirjaudu palvelimelle %{domain}
sign_up:
manual_review: Palvelimen %{domain} valvojat tarkistavat rekisteröitymiset käsin. Helpottaaksesi rekisteröitymisesi käsittelyä kerro hieman itsestäsi ja miksi haluat luoda käyttäjätilin palvelimelle %{domain}.
@ -1220,8 +1220,8 @@ fi:
featured_tags:
add_new: Lisää uusi
errors:
limit: Olet jo nostanut esille enimmäismäärän aihetunnisteita
hint_html: "<strong>Mitä ovat näkyvillä olevat hashtagit eli aihetunnisteet?</strong> Ne ovat näkyvissä julkisessa profiilissasi ja niiden avulla ihmiset voivat selata julkisia viestejäsi nimenomaan näiden aihetunnisteiden alla. Ne auttavat esimerkiksi luovan työn tai pitkäaikaisten projektien seurannassa."
limit: Pidät jo esillä aihetunnisteiden enimmäismäärää
hint_html: "<strong>Pidä tärkeimpiä aihetunnisteitasi esillä profiilissasi.</strong> Erinomainen työkalu, jolla pidät kirjaa luovista teoksistasi ja pitkäaikaisista projekteistasi. Esillä pitämäsi aihetunnisteet ovat näyttävällä paikalla profiilissasi ja mahdollistavat nopean pääsyn omiin julkaisuihisi."
filters:
contexts:
account: Profiilit
@ -1236,10 +1236,10 @@ fi:
statuses_hint_html: Tämä suodatin koskee yksittäisten julkaisujen valintaa riippumatta siitä, vastaavatko ne alla olevia avainsanoja. <a href="%{path}">Tarkista tai poista julkaisut suodattimesta</a>.
title: Muokkaa suodatinta
errors:
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 verkkokäyttöliittymää.
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}
@ -1262,7 +1262,7 @@ fi:
batch:
remove: Poista suodattimista
index:
hint: Tämä suodatin koskee yksittäisten julkaisujen valintaa muista kriteereistä riippumatta. Voit lisätä lisää julkaisuja tähän suodattimeen verkkokäyttöliittymästä.
hint: Tämä suodatin koskee yksittäisten julkaisujen valintaa muista kriteereistä riippumatta. Voit lisätä lisää julkaisuja tähän suodattimeen selainkäyttöliittymästä.
title: Suodatetut julkaisut
generic:
all: Kaikki
@ -1271,7 +1271,7 @@ fi:
other: Kaikki <strong>%{count}</strong> kohdetta tällä sivulla on valittu.
all_matching_items_selected_html:
one: "<strong>%{count}</strong> kohde, joka vastaa hakuasi."
other: Kaikki <strong>%{count}</strong> kohdetta, jotka vastaavat hakuasi.
other: Kaikki <strong>%{count}</strong> hakuasi vastaavaa kohdetta.
cancel: Peruuta
changes_saved_msg: Muutosten tallennus onnistui!
confirm: Vahvista
@ -1283,7 +1283,7 @@ fi:
save_changes: Tallenna muutokset
select_all_matching_items:
one: Valitse %{count} kohde, joka vastaa hakuasi.
other: Valitse kaikki %{count} kohdetta, jotka vastaavat hakuasi.
other: Valitse kaikki %{count} hakuasi vastaavaa kohdetta.
today: tänään
validation_errors:
one: Kaikki ei ole aivan oikein! Tarkasta alla oleva virhe
@ -1291,7 +1291,7 @@ fi:
imports:
errors:
empty: Tyhjä CSV-tiedosto
incompatible_type: Yhteensopimaton valitun tuontilajin kanssa
incompatible_type: Yhteensopimaton valitun tuontityypin kanssa
invalid_csv_file: 'Epäkelpo CSV-tiedosto. Virhe: %{error}'
over_rows_processing_limit: sisältää yli %{count} riviä
too_large: Tiedosto on liian suuri
@ -1332,8 +1332,8 @@ fi:
bookmarks: Tuodaan kirjanmerkkejä
domain_blocking: Tuodaan estettyjä verkkotunnuksia
following: Tuodaan seurattuja tilejä
lists: Listojen tuonti
muting: Tuodaan hiljennettyjä tilejä
lists: Tuodaan listoja
muting: Tuodaan mykistettyjä tilejä
type: Tuonnin tyyppi
type_groups:
constructive: Seuratut ja kirjanmerkit
@ -1341,7 +1341,7 @@ fi:
types:
blocking: Estoluettelo
bookmarks: Kirjanmerkit
domain_blocking: Verkkotunnuksen estoluettelo
domain_blocking: Verkkotunnusten estoluettelo
following: Seurattujen luettelo
lists: Listat
muting: Mykistettyjen luettelo
@ -1403,9 +1403,9 @@ fi:
not_ready: Ei voi liittää tiedostoja, joiden käsittely on kesken. Yritä hetken kuluttua uudelleen!
too_many: Tiedostoja voi liittää enintään 4
migrations:
acct: uuden tilin käyttäjätunnus@verkkotunnus
acct: Muuttanut tunnukselle
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.
errors:
already_moved: on sama tili, jonka olet jo siirtänyt
@ -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.
@ -1437,7 +1437,7 @@ fi:
title: Valvonta
move_handler:
carry_blocks_over_text: Tämä käyttäjä siirtyi paikasta %{acct}, jonka olit estänyt.
carry_mutes_over_text: Tämä käyttäjä siirtyi paikasta %{acct}, jonka mykistit.
carry_mutes_over_text: Tämä käyttäjä siirtyi tililtä %{acct}, jonka olet mykistänyt.
copy_account_note_text: 'Tämä käyttäjä siirtyi paikasta %{acct}, tässä olivat aiemmat muistiinpanosi niistä:'
navigation:
toggle_menu: Avaa/sulje valikko
@ -1526,7 +1526,7 @@ fi:
privacy_hint_html: Määritä, kuinka paljon muita avustavia tietoja haluat paljastaa. Käyttäjät löytävät kiinnostavia profiileja ja hienoja sovelluksia, kun he selaavat toisten seuraamia käyttäjiä ja kun he näkevät, millä sovelluksilla nämä julkaisevat. Saatat kuitenkin haluta piilottaa nämä tiedot.
reach: Tavoittavuus
reach_hint_html: Määritä, haluatko tulla uusien käyttäjien löytämäksi ja seuraamaksi. Haluatko julkaisujesi näkyvän Selaa-sivulla? Haluatko muiden käyttäjien näkevän sinut seuraamissuosituksissaan? Haluatko hyväksyä kaikki uudet seuraajat automaattisesti vai päättää jokaisesta erikseen?
search: Haku
search: Hae
search_hint_html: Määritä, kuinka haluat tulla löydetyksi. Haluatko, että ihmiset löytävät sinut julkisten julkaisujesi perusteella? Haluatko, että ihmiset Mastodonin ulkopuolella löytävät profiilisi tehdessään hakuja verkossa? Otathan huomioon, ettei julkisten tietojen täyttä kaikista hakukoneista poisjäämistä voi taata.
title: Yksityisyys ja tavoittavuus
privacy_policy:
@ -1626,7 +1626,7 @@ fi:
development: Kehitys
edit_profile: Muokkaa profiilia
export: Vie tietoja
featured_tags: Esiteltävät aihetunnisteet
featured_tags: Esillä pidettävät aihetunnisteet
import: Tuo
import_and_export: Tuonti ja vienti
migrate: Tilin muutto muualle
@ -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:

View File

@ -1653,7 +1653,7 @@ ja:
private_long: フォロワーにのみ表示されます
public: 公開
public_long: 誰でも見ることができ、かつ公開タイムラインに表示されます
unlisted: 収載
unlisted: 収載
unlisted_long: 誰でも見ることができますが、公開タイムラインには表示されません
statuses_cleanup:
enabled: 古い投稿を自動的に削除する

View File

@ -881,9 +881,9 @@ ko:
only_allowed: 허용된 것만
pending_review: 심사 대기
preview_card_providers:
allowed: 이 발행처의 링크는 유행록에 실릴 수 있음
allowed: 이 발행처의 링크는 유행록에 실릴 수 있음
description_html: 당신의 서버에서 많은 링크가 공유되고 있는 도메인들입니다. 링크의 도메인이 승인되기 전까지는 링크들은 공개적으로 트렌드에 게시되지 않습니다. 당신의 승인(또는 거절)은 서브도메인까지 확장됩니다.
rejected: 이 발행처의 링크는 유행록에 실리지 않음
rejected: 이 발행처의 링크는 유행록에 실리지 않음
title: 발행처
rejected: 거부됨
statuses:
@ -906,14 +906,14 @@ ko:
tag_servers_measure: 다른 서버들
tag_uses_measure: 총 사용
description_html: 현재 서버에서 볼 수 있는 게시물에서 많이 공유되고 있는 해시태그들입니다. 현재 사람들이 무슨 이야기를 하고 있는지 사용자들이 파악할 수 있도록 도움이 됩니다. 승인하지 않는 한 해시태그는 공개적으로 게시되지 않습니다.
listable: 추천될 수 있습니다
listable: 추천될 수 있
no_tag_selected: 아무 것도 선택 되지 않아 어떤 태그도 바뀌지 않았습니다
not_listable: 추천될 수 없습니다
not_trendable: 유행 목록에 나타나지 않습니다
not_usable: 사용불가
not_listable: 추천하지 않음
not_trendable: 유행 목록에 나타내지 않음
not_usable: 이용할 수 없음
peaked_on_and_decaying: "%{date}에 고점을 찍고, 떨어지고 있습니다"
title: 유행하는 해시태그
trendable: 유행 목록에 나타날 수 있습니다
trendable: 유행 목록에 나타날 수 있
trending_rank: "#%{rank}위로 유행 중"
usable: 사용 가능
usage_comparison: 오늘은 %{today}회 쓰였고, 어제는 %{yesterday}회 쓰임

View File

@ -299,7 +299,7 @@ si:
updated_msg: ඉමොජි සාර්ථකව යාවත්කාලීන කරන ලදී!
upload: උඩුගත කරන්න
dashboard:
active_users: ක්රියාකාරී පරිශීලකයන්
active_users: ක්රිය පරිශ්‍රීලකයන්
interactions: අන්තර්ක්රියා
media_storage: මාධ්‍ය ආචයනය
new_users: නව පරිශ්‍රීලකයින්
@ -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}හි කාර්ය මණ්ඩලයට අභියාචනයක් ඉදිරිපත් කළ හැක.

View File

@ -323,7 +323,7 @@ es-MX:
url: URL de Endpoint
'no': 'No'
not_recommended: No recomendado
overridden: Sobrescrito
overridden: Reemplazado
recommended: Recomendado
required:
mark: "*"

View File

@ -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
@ -43,7 +43,7 @@ fi:
bot: Tämä tili suorittaa enimmäkseen automaattisia toimintoja eikä sitä ehkä valvota
context: Ainakin yksi konteksti, jossa suodattimen pitäisi olla voimassa
current_password: Turvallisuussyistä kirjoita nykyisen tilin salasana
current_username: Vahvista kirjoittamalla nykyisen tilin käyttäjätunnus
current_username: Vahvista kirjoittamalla nykyisen tilin käyttäjänimi
digest: Lähetetään vain pitkän poissaolon jälkeen ja vain, jos olet saanut suoria viestejä poissaolosi aikana
email: Sinulle lähetetään vahvistussähköposti
header: PNG, GIF tai JPG. Enintään %{size}. Skaalataan kokoon %{dimensions} px
@ -59,14 +59,14 @@ fi:
setting_display_media_default: Piilota arkaluonteiseksi merkitty media
setting_display_media_hide_all: Piilota 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
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
domain_allow:
domain: Tämä verkkotunnus voi noutaa tietoja tältä palvelimelta ja sieltä saapuvat tiedot käsitellään ja tallennetaan
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
featured_tag:
name: 'Tässä muutamia hiljattain käyttämiäsi aihetunnisteita:'
@ -78,15 +78,15 @@ fi:
form_admin_settings:
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 suositusten 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.
bootstrap_timeline_accounts: Nämä tilit kiinnitetään uusien käyttäjien seuraamissuositusten yläpuolelle.
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ä käyttöliittymässä.
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:
@ -109,10 +109,10 @@ fi:
ip_block:
comment: Valinnainen. Muista miksi lisäsit tämän säännön.
expires_in: IP-osoitteet ovat rajallinen resurssi, joskus niitä jaetaan ja vaihtavat usein omistajaa. Tästä syystä epämääräisiä IP-lohkoja ei suositella.
ip: Kirjoita IPv4- tai IPv6-osoite. Voit estää kokonaisia alueita käyttämällä CIDR-syntaksia. Varo, että et lukitse itseäsi!
ip: Kirjoita IPv4- tai IPv6-osoite. Voit estää kokonaisia alueita käyttämällä CIDR-syntaksia. Varo, että et lukitse itseäsi ulos!
severities:
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
severity: Valitse, mitä tapahtuu tämän IP-osoitteen pyynnöille
rule:
@ -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:
@ -140,7 +140,7 @@ fi:
url: Mihin tapahtumat lähetetään
labels:
account:
discoverable: Nosta profiili ja julkaisut esille löytämisalgoritmeissa
discoverable: Pidä profiiliasi ja julkaisujasi esillä löytämisalgoritmeissa
fields:
name: Nimike
value: Sisältö
@ -148,9 +148,9 @@ fi:
show_collections: Näytä seuratut ja seuraajat profiilissa
unlocked: Hyväksy uudet seuraajat automaattisesti
account_alias:
acct: Vanhan tilin käyttäjätunnus
acct: Vanhan tilin käyttäjänimi
account_migration:
acct: Uuden tilin käyttäjätunnus
acct: Uuden tilin käyttäjänimi
account_warning_preset:
text: Esiasetettu teksti
title: Nimi
@ -163,8 +163,8 @@ fi:
disable: Poista kirjautuminen käytöstä
none: Älä tee mitään
sensitive: Arkaluonteinen
silence: Hiljennä
suspend: Poista käytöstä ja tuhoa käyttäjätunnuksen tiedot peruuttamattomasti
silence: Rajoita
suspend: Jäädytä
warning_preset_id: Käytä varoitusmallia
announcement:
all_day: Koko päivän kestävä tapahtuma
@ -225,9 +225,9 @@ fi:
severity: Vakavuus
sign_in_token_attempt: Turvakoodi
title: Nimi
type: Tuontilaji
type: Tuontityyppi
username: Käyttäjänimi
username_or_email: Käyttäjänimi tai sähköposti
username_or_email: Käyttäjänimi tai sähköpostiosoite
whole_word: Koko sana
email_domain_block:
with_dns_records: Sisällytä toimialueen MX tietueet ja IP-osoite
@ -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)
@ -250,10 +250,10 @@ fi:
profile_directory: Ota profiilihakemisto käyttöön
registrations_mode: Kuka voi rekisteröityä
require_invite_text: Vaadi syy liittyä
show_domain_blocks: Näytä domainestot
show_domain_blocks_rationale: Näytä miksi verkkotunnukset on estetty
show_domain_blocks: Näytä verkkotunnusten estot
show_domain_blocks_rationale: Näytä, miksi verkkotunnukset on estetty
site_contact_email: Ota yhteyttä sähköpostilla
site_contact_username: Kontaktin käyttäjänimi
site_contact_username: Yhteyshenkilön käyttäjänimi
site_extended_description: Laajennettu kuvaus
site_short_description: Palvelimen kuvaus
site_terms: Tietosuojakäytäntö
@ -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
@ -278,7 +278,7 @@ fi:
ip: IP-osoite
severities:
no_access: Estä pääsy
sign_up_block: Estä kirjautumiset
sign_up_block: Estä rekisteröitymiset
sign_up_requires_approval: Rajoita rekisteröitymisiä
severity: Sääntö
notification_emails:
@ -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

View File

@ -5,7 +5,7 @@ zh-TW:
account:
discoverable: 公開嘟文及個人檔案可能於各 Mastodon 功能中被推薦,並且您的個人檔案可能被推薦至其他使用者。
display_name: 完整名稱或暱稱。
fields: 烘培雞,自我認同代稱,年齡,及任何您想分享的。
fields: 烘培雞、自我認同代稱、年齡,及任何您想分享的。
indexable: 您的公開嘟文可能會顯示於 Mastodon 之搜尋結果中。曾與您嘟文互動過的人可能無論如何都能搜尋它們。
note: '您可以 @mention 其他人或者使用 #主題標籤。'
show_collections: 人們將能瀏覽您跟隨中及跟隨者帳號。您所跟隨之人能得知您正在跟隨其帳號。
@ -30,8 +30,8 @@ zh-TW:
suspend: 禁止所有對該帳號任何互動,並且刪除其內容。三十天內可以撤銷此動作。關閉所有對此帳號之檢舉報告。
warning_preset_id: 選用。您仍可在預設的結尾新增自訂文字
announcement:
all_day: 核取後,只會顯示出時間範圍中的日期部分
ends_at: 可選的,公告會該時間點自動取消發布
all_day: 當選取時,僅顯示出時間範圍中的日期部分
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

View File

@ -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.

View File

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

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
# a domain block
DomainBlock.where(severity: [:silence, :suspend]).find_each do |block|
scope = block.accounts
if block.suspend?
block.accounts.where(suspended: true).in_batches.update_all(suspended_at: block.created_at)
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
# a domain block
DomainBlock.where(severity: [:silence, :suspend]).find_each do |block|
scope = block.accounts
if block.suspend?
block.accounts.where(suspended: true).in_batches.update_all(suspended_at: block.created_at)
else

View File

@ -111,7 +111,7 @@ services:
test: ['CMD-SHELL', "ps aux | grep '[s]idekiq\ 6' || false"]
## Uncomment to enable federation with tor instances along with adding the following ENV variables
## http_proxy=http://privoxy:8118
## http_hidden_proxy=http://privoxy:8118
## ALLOW_ACCESS_TO_HIDDEN_SERVICE=true
# tor:
# image: sirboops/tor

View File

@ -125,7 +125,7 @@ module Mastodon::CLI
failed = Concurrent::AtomicFixnum.new(0)
start_at = Time.now.to_f
seed = start ? [start] : Instance.pluck(:domain)
blocked_domains = /\.?(#{DomainBlock.where(severity: 1).pluck(:domain).map { |domain| Regexp.escape(domain) }.join('|')})$/
blocked_domains = /\.?(#{Regexp.union(domain_block_suspended_domains).source})$/
progress = create_progress_bar
pool = Concurrent::ThreadPoolExecutor.new(min_threads: 0, max_threads: options[:concurrency], idletime: 10, auto_terminate: true, max_queue: 0)
@ -189,6 +189,10 @@ module Mastodon::CLI
private
def domain_block_suspended_domains
DomainBlock.suspend.pluck(:domain)
end
def stats_to_summary(stats, processed, failed, start_at)
stats.compact!

View File

@ -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
before do
below_limit.times { increment_counter }
end
it 'does not change the request status' do
limit.times do
request.call
expect(response).to_not have_http_status(429)
end
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
before do
above_limit.times { increment_counter }
end
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
end
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 } } }

View File

@ -7,468 +7,319 @@ RSpec.describe AccountsController do
let(:account) { Fabricate(:account) }
shared_examples 'cacheable response' do
it 'does not set cookies' do
expect(response.cookies).to be_empty
expect(response.headers['Set-Cookies']).to be_nil
shared_examples 'unapproved account check' do
before { account.user.update(approved: false) }
it 'returns http not found' do
get :show, params: { username: account.username, format: format }
expect(response).to have_http_status(404)
end
end
shared_examples 'permanently suspended account check' do
before do
account.suspend!
account.deletion_request.destroy
end
it 'does not set sessions' do
expect(session).to be_empty
end
it 'returns http gone' do
get :show, params: { username: account.username, format: format }
it 'returns Vary header' do
expect(response.headers['Vary']).to include 'Accept'
expect(response).to have_http_status(410)
end
end
it 'returns public Cache-Control header' do
expect(response.headers['Cache-Control']).to include 'public'
shared_examples 'temporarily suspended account check' do |code: 403|
before { account.suspend! }
it 'returns appropriate http response code' do
get :show, params: { username: account.username, format: format }
expect(response).to have_http_status(code)
end
end
describe 'GET #show' do
let(:format) { 'html' }
context 'with basic account status checks' do
context 'with HTML' do
let(:format) { 'html' }
let!(:status) { Fabricate(:status, account: account) }
let!(:status_reply) { Fabricate(:status, account: account, thread: Fabricate(:status)) }
let!(:status_self_reply) { Fabricate(:status, account: account, thread: status) }
let!(:status_media) { Fabricate(:status, account: account) }
let!(:status_pinned) { Fabricate(:status, account: account) }
let!(:status_private) { Fabricate(:status, account: account, visibility: :private) }
let!(:status_direct) { Fabricate(:status, account: account, visibility: :direct) }
let!(:status_reblog) { Fabricate(:status, account: account, reblog: Fabricate(:status)) }
it_behaves_like 'unapproved account check'
it_behaves_like 'permanently suspended account check'
it_behaves_like 'temporarily suspended account check'
end
before do
status_media.media_attachments << Fabricate(:media_attachment, account: account, type: :image)
account.pinned_statuses << status_pinned
account.pinned_statuses << status_private
end
context 'with JSON' do
let(:format) { 'json' }
shared_examples 'preliminary checks' do
context 'when account is not approved' do
before do
account.user.update(approved: false)
end
it_behaves_like 'unapproved account check'
it_behaves_like 'permanently suspended account check'
it_behaves_like 'temporarily suspended account check', code: 200
end
it 'returns http not found' do
get :show, params: { username: account.username, format: format }
expect(response).to have_http_status(404)
end
context 'with RSS' do
let(:format) { 'rss' }
it_behaves_like 'unapproved account check'
it_behaves_like 'permanently suspended account check'
it_behaves_like 'temporarily suspended account check'
end
end
context 'with HTML' do
let(:format) { 'html' }
it_behaves_like 'preliminary checks'
context 'when account is permanently suspended' do
before do
account.suspend!
account.deletion_request.destroy
end
it 'returns http gone' do
get :show, params: { username: account.username, format: format }
expect(response).to have_http_status(410)
end
end
context 'when account is temporarily suspended' do
before do
account.suspend!
end
it 'returns http forbidden' do
get :show, params: { username: account.username, format: format }
expect(response).to have_http_status(403)
end
end
shared_examples 'common response characteristics' do
it 'returns http success' do
expect(response).to have_http_status(200)
end
it 'returns Link header' do
expect(response.headers['Link'].to_s).to include ActivityPub::TagManager.instance.uri_for(account)
end
it 'renders show template' do
expect(response).to render_template(:show)
end
end
context 'with a normal account in an HTML request' do
before do
get :show, params: { username: account.username, format: format }
end
it_behaves_like 'common response characteristics'
end
context 'with replies' do
before do
allow(controller).to receive(:replies_requested?).and_return(true)
get :show, params: { username: account.username, format: format }
end
it_behaves_like 'common response characteristics'
end
context 'with media' do
before do
allow(controller).to receive(:media_requested?).and_return(true)
get :show, params: { username: account.username, format: format }
end
it_behaves_like 'common response characteristics'
end
context 'with tag' do
let(:tag) { Fabricate(:tag) }
let!(:status_tag) { Fabricate(:status, account: account) }
before do
allow(controller).to receive(:tag_requested?).and_return(true)
status_tag.tags << tag
get :show, params: { username: account.username, format: format, tag: tag.to_param }
end
it_behaves_like 'common response characteristics'
end
end
context 'with JSON' do
let(:authorized_fetch_mode) { false }
let(:format) { 'json' }
context 'with existing statuses' do
let!(:status) { Fabricate(:status, account: account) }
let!(:status_reply) { Fabricate(:status, account: account, thread: Fabricate(:status)) }
let!(:status_self_reply) { Fabricate(:status, account: account, thread: status) }
let!(:status_media) { Fabricate(:status, account: account) }
let!(:status_pinned) { Fabricate(:status, account: account) }
let!(:status_private) { Fabricate(:status, account: account, visibility: :private) }
let!(:status_direct) { Fabricate(:status, account: account, visibility: :direct) }
let!(:status_reblog) { Fabricate(:status, account: account, reblog: Fabricate(:status)) }
before do
allow(controller).to receive(:authorized_fetch_mode?).and_return(authorized_fetch_mode)
status_media.media_attachments << Fabricate(:media_attachment, account: account, type: :image)
account.pinned_statuses << status_pinned
account.pinned_statuses << status_private
end
it_behaves_like 'preliminary checks'
context 'with HTML' do
let(:format) { 'html' }
context 'when account is suspended permanently' do
before do
account.suspend!
account.deletion_request.destroy
shared_examples 'common HTML response' do
it 'returns a standard HTML response', :aggregate_failures do
expect(response).to have_http_status(200)
expect(response.headers['Link'].to_s).to include ActivityPub::TagManager.instance.uri_for(account)
expect(response).to render_template(:show)
end
end
it 'returns http gone' do
get :show, params: { username: account.username, format: format }
expect(response).to have_http_status(410)
context 'with a normal account in an HTML request' do
before do
get :show, params: { username: account.username, format: format }
end
it_behaves_like 'common HTML response'
end
context 'with replies' do
before do
allow(controller).to receive(:replies_requested?).and_return(true)
get :show, params: { username: account.username, format: format }
end
it_behaves_like 'common HTML response'
end
context 'with media' do
before do
allow(controller).to receive(:media_requested?).and_return(true)
get :show, params: { username: account.username, format: format }
end
it_behaves_like 'common HTML response'
end
context 'with tag' do
let(:tag) { Fabricate(:tag) }
let!(:status_tag) { Fabricate(:status, account: account) }
before do
allow(controller).to receive(:tag_requested?).and_return(true)
status_tag.tags << tag
get :show, params: { username: account.username, format: format, tag: tag.to_param }
end
it_behaves_like 'common HTML response'
end
end
context 'when account is suspended temporarily' do
context 'with JSON' do
let(:authorized_fetch_mode) { false }
let(:format) { 'json' }
before do
account.suspend!
allow(controller).to receive(:authorized_fetch_mode?).and_return(authorized_fetch_mode)
end
it 'returns http success' do
get :show, params: { username: account.username, format: format }
expect(response).to have_http_status(200)
end
end
context 'with a normal account in a JSON request' do
before do
get :show, params: { username: account.username, format: format }
end
context 'with a normal account in a JSON request' do
before do
get :show, params: { username: account.username, format: format }
it 'returns a JSON version of the account', :aggregate_failures do
expect(response).to have_http_status(200)
expect(response.media_type).to eq 'application/activity+json'
expect(body_as_json).to include(:id, :type, :preferredUsername, :inbox, :publicKey, :name, :summary)
end
it_behaves_like 'cacheable response', expects_vary: 'Accept, Accept-Language, Cookie'
context 'with authorized fetch mode' do
let(:authorized_fetch_mode) { true }
it 'returns http unauthorized' do
expect(response).to have_http_status(401)
end
end
end
it 'returns http success' do
expect(response).to have_http_status(200)
context 'when signed in' do
let(:user) { Fabricate(:user) }
before do
sign_in(user)
get :show, params: { username: account.username, format: format }
end
it 'returns a private JSON version of the account', :aggregate_failures do
expect(response).to have_http_status(200)
expect(response.media_type).to eq 'application/activity+json'
expect(response.headers['Cache-Control']).to include 'private'
expect(body_as_json).to include(:id, :type, :preferredUsername, :inbox, :publicKey, :name, :summary)
end
end
it 'returns application/activity+json' do
expect(response.media_type).to eq 'application/activity+json'
end
context 'with signature' do
let(:remote_account) { Fabricate(:account, domain: 'example.com') }
it_behaves_like 'cacheable response'
before do
allow(controller).to receive(:signed_request_actor).and_return(remote_account)
get :show, params: { username: account.username, format: format }
end
it 'renders account' do
json = body_as_json
expect(json).to include(:id, :type, :preferredUsername, :inbox, :publicKey, :name, :summary)
end
it 'returns a JSON version of the account', :aggregate_failures do
expect(response).to have_http_status(200)
context 'with authorized fetch mode' do
let(:authorized_fetch_mode) { true }
expect(response.media_type).to eq 'application/activity+json'
it 'returns http unauthorized' do
expect(response).to have_http_status(401)
expect(body_as_json).to include(:id, :type, :preferredUsername, :inbox, :publicKey, :name, :summary)
end
it_behaves_like 'cacheable response', expects_vary: 'Accept, Accept-Language, Cookie'
context 'with authorized fetch mode' do
let(:authorized_fetch_mode) { true }
it 'returns a private signature JSON version of the account', :aggregate_failures do
expect(response).to have_http_status(200)
expect(response.media_type).to eq 'application/activity+json'
expect(response.headers['Cache-Control']).to include 'private'
expect(response.headers['Vary']).to include 'Signature'
expect(body_as_json).to include(:id, :type, :preferredUsername, :inbox, :publicKey, :name, :summary)
end
end
end
end
context 'when signed in' do
let(:user) { Fabricate(:user) }
before do
sign_in(user)
get :show, params: { username: account.username, format: format }
end
it 'returns http success' do
expect(response).to have_http_status(200)
end
it 'returns application/activity+json' do
expect(response.media_type).to eq 'application/activity+json'
end
it 'returns private Cache-Control header' do
expect(response.headers['Cache-Control']).to include 'private'
end
it 'renders account' do
json = body_as_json
expect(json).to include(:id, :type, :preferredUsername, :inbox, :publicKey, :name, :summary)
end
end
context 'with signature' do
let(:remote_account) { Fabricate(:account, domain: 'example.com') }
before do
allow(controller).to receive(:signed_request_actor).and_return(remote_account)
get :show, params: { username: account.username, format: format }
end
it 'returns http success' do
expect(response).to have_http_status(200)
end
it 'returns application/activity+json' do
expect(response.media_type).to eq 'application/activity+json'
end
it_behaves_like 'cacheable response'
it 'renders account' do
json = body_as_json
expect(json).to include(:id, :type, :preferredUsername, :inbox, :publicKey, :name, :summary)
end
context 'with authorized fetch mode' do
let(:authorized_fetch_mode) { true }
context 'with RSS' do
let(:format) { 'rss' }
shared_examples 'common RSS response' do
it 'returns http success' do
expect(response).to have_http_status(200)
end
it 'returns application/activity+json' do
expect(response.media_type).to eq 'application/activity+json'
it_behaves_like 'cacheable response', expects_vary: 'Accept, Accept-Language, Cookie'
end
context 'with a normal account in an RSS request' do
before do
get :show, params: { username: account.username, format: format }
end
it 'returns private Cache-Control header' do
expect(response.headers['Cache-Control']).to include 'private'
end
it_behaves_like 'common RSS response'
it 'returns Vary header with Signature' do
expect(response.headers['Vary']).to include 'Signature'
end
it 'renders account' do
json = body_as_json
expect(json).to include(:id, :type, :preferredUsername, :inbox, :publicKey, :name, :summary)
it 'responds with correct statuses', :aggregate_failures do
expect(response.body).to include_status_tag(status_media)
expect(response.body).to include_status_tag(status_self_reply)
expect(response.body).to include_status_tag(status)
expect(response.body).to_not include_status_tag(status_direct)
expect(response.body).to_not include_status_tag(status_private)
expect(response.body).to_not include_status_tag(status_reblog.reblog)
expect(response.body).to_not include_status_tag(status_reply)
end
end
end
end
context 'with RSS' do
let(:format) { 'rss' }
context 'with replies' do
before do
allow(controller).to receive(:replies_requested?).and_return(true)
get :show, params: { username: account.username, format: format }
end
it_behaves_like 'preliminary checks'
it_behaves_like 'common RSS response'
context 'when account is permanently suspended' do
before do
account.suspend!
account.deletion_request.destroy
it 'responds with correct statuses with replies', :aggregate_failures do
expect(response.body).to include_status_tag(status_media)
expect(response.body).to include_status_tag(status_reply)
expect(response.body).to include_status_tag(status_self_reply)
expect(response.body).to include_status_tag(status)
expect(response.body).to_not include_status_tag(status_direct)
expect(response.body).to_not include_status_tag(status_private)
expect(response.body).to_not include_status_tag(status_reblog.reblog)
end
end
it 'returns http gone' do
get :show, params: { username: account.username, format: format }
expect(response).to have_http_status(410)
end
end
context 'with media' do
before do
allow(controller).to receive(:media_requested?).and_return(true)
get :show, params: { username: account.username, format: format }
end
context 'when account is temporarily suspended' do
before do
account.suspend!
it_behaves_like 'common RSS response'
it 'responds with correct statuses with media', :aggregate_failures do
expect(response.body).to include_status_tag(status_media)
expect(response.body).to_not include_status_tag(status_direct)
expect(response.body).to_not include_status_tag(status_private)
expect(response.body).to_not include_status_tag(status_reblog.reblog)
expect(response.body).to_not include_status_tag(status_reply)
expect(response.body).to_not include_status_tag(status_self_reply)
expect(response.body).to_not include_status_tag(status)
end
end
it 'returns http forbidden' do
get :show, params: { username: account.username, format: format }
expect(response).to have_http_status(403)
end
end
context 'with tag' do
let(:tag) { Fabricate(:tag) }
shared_examples 'common response characteristics' do
it 'returns http success' do
expect(response).to have_http_status(200)
end
let!(:status_tag) { Fabricate(:status, account: account) }
it_behaves_like 'cacheable response'
end
before do
allow(controller).to receive(:tag_requested?).and_return(true)
status_tag.tags << tag
get :show, params: { username: account.username, format: format, tag: tag.to_param }
end
context 'with a normal account in an RSS request' do
before do
get :show, params: { username: account.username, format: format }
end
it_behaves_like 'common RSS response'
it_behaves_like 'common response characteristics'
it 'renders public status' do
expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status))
end
it 'renders self-reply' do
expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status_self_reply))
end
it 'renders status with media' do
expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status_media))
end
it 'does not render reblog' do
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_reblog.reblog))
end
it 'does not render private status' do
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_private))
end
it 'does not render direct status' do
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_direct))
end
it 'does not render reply to someone else' do
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_reply))
end
end
context 'with replies' do
before do
allow(controller).to receive(:replies_requested?).and_return(true)
get :show, params: { username: account.username, format: format }
end
it_behaves_like 'common response characteristics'
it 'renders public status' do
expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status))
end
it 'renders self-reply' do
expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status_self_reply))
end
it 'renders status with media' do
expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status_media))
end
it 'does not render reblog' do
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_reblog.reblog))
end
it 'does not render private status' do
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_private))
end
it 'does not render direct status' do
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_direct))
end
it 'renders reply to someone else' do
expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status_reply))
end
end
context 'with media' do
before do
allow(controller).to receive(:media_requested?).and_return(true)
get :show, params: { username: account.username, format: format }
end
it_behaves_like 'common response characteristics'
it 'does not render public status' do
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status))
end
it 'does not render self-reply' do
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_self_reply))
end
it 'renders status with media' do
expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status_media))
end
it 'does not render reblog' do
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_reblog.reblog))
end
it 'does not render private status' do
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_private))
end
it 'does not render direct status' do
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_direct))
end
it 'does not render reply to someone else' do
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_reply))
end
end
context 'with tag' do
let(:tag) { Fabricate(:tag) }
let!(:status_tag) { Fabricate(:status, account: account) }
before do
allow(controller).to receive(:tag_requested?).and_return(true)
status_tag.tags << tag
get :show, params: { username: account.username, format: format, tag: tag.to_param }
end
it_behaves_like 'common response characteristics'
it 'does not render public status' do
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status))
end
it 'does not render self-reply' do
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_self_reply))
end
it 'does not render status with media' do
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_media))
end
it 'does not render reblog' do
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_reblog.reblog))
end
it 'does not render private status' do
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_private))
end
it 'does not render direct status' do
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_direct))
end
it 'does not render reply to someone else' do
expect(response.body).to_not include(ActivityPub::TagManager.instance.url_for(status_reply))
end
it 'renders status with tag' do
expect(response.body).to include(ActivityPub::TagManager.instance.url_for(status_tag))
it 'responds with correct statuses with a tag', :aggregate_failures do
expect(response.body).to include_status_tag(status_tag)
expect(response.body).to_not include_status_tag(status_direct)
expect(response.body).to_not include_status_tag(status_media)
expect(response.body).to_not include_status_tag(status_private)
expect(response.body).to_not include_status_tag(status_reblog.reblog)
expect(response.body).to_not include_status_tag(status_reply)
expect(response.body).to_not include_status_tag(status_self_reply)
expect(response.body).to_not include_status_tag(status)
end
end
end
end
end
def include_status_tag(status)
include ActivityPub::TagManager.instance.url_for(status)
end
end

View File

@ -7,22 +7,6 @@ RSpec.describe ActivityPub::CollectionsController do
let!(:private_pinned) { Fabricate(:status, account: account, text: 'secret private stuff', visibility: :private) }
let(:remote_account) { nil }
shared_examples 'cacheable response' do
it 'does not set cookies' do
expect(response.cookies).to be_empty
expect(response.headers['Set-Cookies']).to be_nil
end
it 'does not set sessions' do
response
expect(session).to be_empty
end
it 'returns public Cache-Control header' do
expect(response.headers['Cache-Control']).to include 'public'
end
end
before do
allow(controller).to receive(:signed_request_actor).and_return(remote_account)

View File

@ -5,22 +5,6 @@ require 'rails_helper'
RSpec.describe ActivityPub::OutboxesController do
let!(:account) { Fabricate(:account) }
shared_examples 'cacheable response' do
it 'does not set cookies' do
expect(response.cookies).to be_empty
expect(response.headers['Set-Cookies']).to be_nil
end
it 'does not set sessions' do
response
expect(session).to be_empty
end
it 'returns public Cache-Control header' do
expect(response.headers['Cache-Control']).to include 'public'
end
end
before do
Fabricate(:status, account: account, visibility: :public)
Fabricate(:status, account: account, visibility: :unlisted)

View File

@ -8,22 +8,6 @@ RSpec.describe ActivityPub::RepliesController do
let(:remote_reply_id) { 'https://foobar.com/statuses/1234' }
let(:remote_querier) { nil }
shared_examples 'cacheable response' do
it 'does not set cookies' do
expect(response.cookies).to be_empty
expect(response.headers['Set-Cookies']).to be_nil
end
it 'does not set sessions' do
response
expect(session).to be_empty
end
it 'returns public Cache-Control header' do
expect(response.headers['Cache-Control']).to include 'public'
end
end
shared_examples 'common behavior' do
context 'when status is private' do
let(:parent_visibility) { :private }

View File

@ -15,6 +15,20 @@ RSpec.describe Admin::Disputes::AppealsController do
let(:strike) { Fabricate(:account_warning, target_account: target_account, action: :suspend) }
let(:appeal) { Fabricate(:appeal, strike: strike, account: target_account) }
describe 'GET #index' do
let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
before { appeal }
it 'returns a page that lists details of appeals' do
get :index
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
describe 'POST #approve' do
let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }

View File

@ -165,6 +165,17 @@ RSpec.describe Admin::DomainBlocksController do
end
end
describe 'GET #edit' do
let(:domain_block) { Fabricate(:domain_block) }
it 'returns http success' do
get :edit, params: { id: domain_block.id }
expect(assigns(:domain_block)).to be_instance_of(DomainBlock)
expect(response).to have_http_status(200)
end
end
describe 'PUT #update' do
subject do
post :update, params: { :id => domain_block.id, :domain_block => { domain: 'example.com', severity: new_severity }, 'confirm' => '' }

View File

@ -9,6 +9,14 @@ RSpec.describe Admin::ExportDomainAllowsController do
sign_in Fabricate(:user, role: UserRole.find_by(name: 'Admin')), scope: :user
end
describe 'GET #new' do
it 'returns http success' do
get :new
expect(response).to have_http_status(200)
end
end
describe 'GET #export' do
it 'renders instances' do
Fabricate(:domain_allow, domain: 'good.domain')

View File

@ -9,6 +9,14 @@ RSpec.describe Admin::ExportDomainBlocksController do
sign_in Fabricate(:user, role: UserRole.find_by(name: 'Admin')), scope: :user
end
describe 'GET #new' do
it 'returns http success' do
get :new
expect(response).to have_http_status(200)
end
end
describe 'GET #export' do
it 'renders instances' do
Fabricate(:domain_block, domain: 'bad.domain', severity: 'silence', public_comment: 'bad server')

View File

@ -34,6 +34,63 @@ RSpec.describe Admin::InstancesController do
end
end
describe 'GET #show' do
it 'shows an instance page' do
get :show, params: { id: account_popular_main.domain }
expect(response).to have_http_status(200)
end
end
describe 'POST #clear_delivery_errors' do
let(:tracker) { instance_double(DeliveryFailureTracker, clear_failures!: true) }
before { allow(DeliveryFailureTracker).to receive(:new).and_return(tracker) }
it 'clears instance delivery errors' do
post :clear_delivery_errors, params: { id: account_popular_main.domain }
expect(response).to redirect_to(admin_instance_path(account_popular_main.domain))
expect(tracker).to have_received(:clear_failures!)
end
end
describe 'POST #restart_delivery' do
let(:tracker) { instance_double(DeliveryFailureTracker, track_success!: true) }
before { allow(DeliveryFailureTracker).to receive(:new).and_return(tracker) }
context 'with an unavailable instance' do
before { Fabricate(:unavailable_domain, domain: account_popular_main.domain) }
it 'tracks success on the instance' do
post :restart_delivery, params: { id: account_popular_main.domain }
expect(response).to redirect_to(admin_instance_path(account_popular_main.domain))
expect(tracker).to have_received(:track_success!)
end
end
context 'with an available instance' do
it 'does not track success on the instance' do
post :restart_delivery, params: { id: account_popular_main.domain }
expect(response).to redirect_to(admin_instance_path(account_popular_main.domain))
expect(tracker).to_not have_received(:track_success!)
end
end
end
describe 'POST #stop_delivery' do
it 'clears instance delivery errors' do
expect do
post :stop_delivery, params: { id: account_popular_main.domain }
end.to change(UnavailableDomain, :count).by(1)
expect(response).to redirect_to(admin_instance_path(account_popular_main.domain))
end
end
describe 'DELETE #destroy' do
subject { delete :destroy, params: { id: Instance.first.id } }

Some files were not shown because too many files have changed in this diff Show More