Merge commit 'b7902225d698a107df2cf8b4ca221caad38fa464' into glitch-soc/merge-upstream

Conflicts:
- `spec/validators/status_length_validator_spec.rb`:
  Upstream refactored tests to stub `StatusLengthValidator::MAX_CHARS`
  while glitch-soc had custom code to read from `MAX_TOOT_CHARS`.
  Switched to using upstream's implementation of the tests.
shrike
Claire 2024-05-04 16:28:30 +02:00
commit 3789d9f825
49 changed files with 911 additions and 205 deletions

View File

@ -1,21 +0,0 @@
{
"problemMatcher": [
{
"owner": "stylelint",
"pattern": [
{
"regexp": "^([^\\s].*)$",
"file": 1
},
{
"regexp": "^\\s+((\\d+):(\\d+))?\\s+(✖|×)\\s+(.*)\\s{2,}(.*)$",
"line": 2,
"column": 3,
"message": 5,
"code": 6,
"loop": true
}
]
}
]
}

View File

@ -38,9 +38,5 @@ jobs:
- name: Set up Javascript environment
uses: ./.github/actions/setup-javascript
- uses: xt0rted/stylelint-problem-matcher@v1
- run: echo "::add-matcher::.github/stylelint-matcher.json"
- name: Stylelint
run: yarn lint:css
run: yarn lint:css -f github

View File

@ -42,14 +42,6 @@ RSpec/MultipleMemoizedHelpers:
RSpec/NestedGroups:
Max: 6
# Configuration parameters: Include.
# Include: app/models/**/*.rb
Rails/HasAndBelongsToMany:
Exclude:
- 'app/models/concerns/account/associations.rb'
- 'app/models/status.rb'
- 'app/models/tag.rb'
Rails/OutputSafety:
Exclude:
- 'config/initializers/simple_form.rb'

View File

@ -31,7 +31,7 @@ gem 'browser'
gem 'charlock_holmes', '~> 0.7.7'
gem 'chewy', '~> 7.3'
gem 'devise', '~> 4.9'
gem 'devise-two-factor', '~> 4.1'
gem 'devise-two-factor'
group :pam_authentication, optional: true do
gem 'devise_pam_authenticatable2', '~> 9.2'

View File

@ -97,8 +97,6 @@ GEM
activerecord (>= 3.2, < 8.0)
rake (>= 10.4, < 14.0)
ast (2.4.2)
attr_encrypted (4.0.0)
encryptor (~> 3.0.0)
attr_required (1.0.2)
awrence (1.2.1)
aws-eventstream (1.3.0)
@ -204,9 +202,8 @@ GEM
railties (>= 4.1.0)
responders
warden (~> 1.2.3)
devise-two-factor (4.1.1)
devise-two-factor (5.0.0)
activesupport (~> 7.0)
attr_encrypted (>= 1.3, < 5, != 2)
devise (~> 4.0)
railties (~> 7.0)
rotp (~> 6.0)
@ -236,7 +233,6 @@ GEM
htmlentities (~> 4.3.3)
launchy (~> 2.1)
mail (~> 2.7)
encryptor (3.0.0)
erubi (1.12.0)
et-orbi (1.2.11)
tzinfo
@ -655,8 +651,8 @@ GEM
rubocop-ast (>= 1.31.1, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.31.2)
parser (>= 3.3.0.4)
rubocop-ast (1.31.3)
parser (>= 3.3.1.0)
rubocop-capybara (2.20.0)
rubocop (~> 1.41)
rubocop-factory_bot (2.25.1)
@ -669,7 +665,7 @@ GEM
rack (>= 1.1)
rubocop (>= 1.33.0, < 2.0)
rubocop-ast (>= 1.31.1, < 2.0)
rubocop-rspec (2.29.1)
rubocop-rspec (2.29.2)
rubocop (~> 1.40)
rubocop-capybara (~> 2.17)
rubocop-factory_bot (~> 2.22)
@ -842,7 +838,7 @@ DEPENDENCIES
database_cleaner-active_record
debug (~> 1.8)
devise (~> 4.9)
devise-two-factor (~> 4.1)
devise-two-factor
devise_pam_authenticatable2 (~> 9.2)
discard (~> 1.2)
doorkeeper (~> 5.6)

View File

@ -29,10 +29,11 @@ class Api::V1::Admin::DomainBlocksController < Api::BaseController
def create
authorize :domain_block, :create?
@domain_block = DomainBlock.new(resource_params)
existing_domain_block = resource_params[:domain].present? ? DomainBlock.rule_for(resource_params[:domain]) : nil
return render json: existing_domain_block, serializer: REST::Admin::ExistingDomainBlockErrorSerializer, status: 422 if existing_domain_block.present?
return render json: existing_domain_block, serializer: REST::Admin::ExistingDomainBlockErrorSerializer, status: 422 if conflicts_with_existing_block?(@domain_block, existing_domain_block)
@domain_block = DomainBlock.create!(resource_params)
@domain_block.save!
DomainBlockWorker.perform_async(@domain_block.id)
log_action :create, @domain_block
render json: @domain_block, serializer: REST::Admin::DomainBlockSerializer
@ -55,6 +56,10 @@ class Api::V1::Admin::DomainBlocksController < Api::BaseController
private
def conflicts_with_existing_block?(domain_block, existing_domain_block)
existing_domain_block.present? && (existing_domain_block.domain == TagManager.instance.normalize_domain(domain_block.domain) || !domain_block.stricter_than?(existing_domain_block))
end
def set_domain_blocks
@domain_blocks = filtered_domain_blocks.order(id: :desc).to_a_paginated_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
end

View File

@ -1,119 +0,0 @@
import * as WebAuthnJSON from '@github/webauthn-json';
import axios from 'axios';
import ready from '../mastodon/ready';
import 'regenerator-runtime/runtime';
function getCSRFToken() {
var CSRFSelector = document.querySelector('meta[name="csrf-token"]');
if (CSRFSelector) {
return CSRFSelector.getAttribute('content');
} else {
return null;
}
}
function hideFlashMessages() {
Array.from(document.getElementsByClassName('flash-message')).forEach(function(flashMessage) {
flashMessage.classList.add('hidden');
});
}
function callback(url, body) {
axios.post(url, JSON.stringify(body), {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-CSRF-Token': getCSRFToken(),
},
credentials: 'same-origin',
}).then(function(response) {
window.location.replace(response.data.redirect_path);
}).catch(function(error) {
if (error.response.status === 422) {
const errorMessage = document.getElementById('security-key-error-message');
errorMessage.classList.remove('hidden');
console.error(error.response.data.error);
} else {
console.error(error);
}
});
}
ready(() => {
if (!WebAuthnJSON.supported()) {
const unsupported_browser_message = document.getElementById('unsupported-browser-message');
if (unsupported_browser_message) {
unsupported_browser_message.classList.remove('hidden');
document.querySelector('.btn.js-webauthn').disabled = true;
}
}
const webAuthnCredentialRegistrationForm = document.getElementById('new_webauthn_credential');
if (webAuthnCredentialRegistrationForm) {
webAuthnCredentialRegistrationForm.addEventListener('submit', (event) => {
event.preventDefault();
var nickname = event.target.querySelector('input[name="new_webauthn_credential[nickname]"]');
if (nickname.value) {
axios.get('/settings/security_keys/options')
.then((response) => {
const credentialOptions = response.data;
WebAuthnJSON.create({ 'publicKey': credentialOptions }).then((credential) => {
var params = { 'credential': credential, 'nickname': nickname.value };
callback('/settings/security_keys', params);
}).catch((error) => {
const errorMessage = document.getElementById('security-key-error-message');
errorMessage.classList.remove('hidden');
console.error(error);
});
}).catch((error) => {
console.error(error.response.data.error);
});
} else {
nickname.focus();
}
});
}
const webAuthnCredentialAuthenticationForm = document.getElementById('webauthn-form');
if (webAuthnCredentialAuthenticationForm) {
webAuthnCredentialAuthenticationForm.addEventListener('submit', (event) => {
event.preventDefault();
axios.get('sessions/security_key_options')
.then((response) => {
const credentialOptions = response.data;
WebAuthnJSON.get({ 'publicKey': credentialOptions }).then((credential) => {
var params = { 'user': { 'credential': credential } };
callback('sign_in', params);
}).catch((error) => {
const errorMessage = document.getElementById('security-key-error-message');
errorMessage.classList.remove('hidden');
console.error(error);
});
}).catch((error) => {
console.error(error.response.data.error);
});
});
const otpAuthenticationForm = document.getElementById('otp-authentication-form');
const linkToOtp = document.getElementById('link-to-otp');
linkToOtp.addEventListener('click', () => {
webAuthnCredentialAuthenticationForm.classList.add('hidden');
otpAuthenticationForm.classList.remove('hidden');
hideFlashMessages();
});
const linkToWebAuthn = document.getElementById('link-to-webauthn');
linkToWebAuthn.addEventListener('click', () => {
otpAuthenticationForm.classList.add('hidden');
webAuthnCredentialAuthenticationForm.classList.remove('hidden');
hideFlashMessages();
});
}
});

View File

@ -0,0 +1,197 @@
import * as WebAuthnJSON from '@github/webauthn-json';
import axios, { AxiosError } from 'axios';
import ready from '../mastodon/ready';
import 'regenerator-runtime/runtime';
type PublicKeyCredentialCreationOptionsJSON =
WebAuthnJSON.CredentialCreationOptionsJSON['publicKey'];
function exceptionHasAxiosError(
error: unknown,
): error is AxiosError<{ error: unknown }> {
return (
error instanceof AxiosError &&
typeof error.response?.data === 'object' &&
'error' in error.response.data
);
}
function logAxiosResponseError(error: unknown) {
if (exceptionHasAxiosError(error)) console.error(error);
}
function getCSRFToken() {
return document
.querySelector<HTMLMetaElement>('meta[name="csrf-token"]')
?.getAttribute('content');
}
function hideFlashMessages() {
document.querySelectorAll('.flash-message').forEach((flashMessage) => {
flashMessage.classList.add('hidden');
});
}
async function callback(
url: string,
body:
| {
credential: WebAuthnJSON.PublicKeyCredentialWithAttestationJSON;
nickname: string;
}
| {
user: { credential: WebAuthnJSON.PublicKeyCredentialWithAssertionJSON };
},
) {
try {
const response = await axios.post<{ redirect_path: string }>(
url,
JSON.stringify(body),
{
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
'X-CSRF-Token': getCSRFToken(),
},
},
);
window.location.replace(response.data.redirect_path);
} catch (error) {
if (error instanceof AxiosError && error.response?.status === 422) {
const errorMessage = document.getElementById(
'security-key-error-message',
);
errorMessage?.classList.remove('hidden');
logAxiosResponseError(error);
} else {
console.error(error);
}
}
}
async function handleWebauthnCredentialRegistration(nickname: string) {
try {
const response = await axios.get<PublicKeyCredentialCreationOptionsJSON>(
'/settings/security_keys/options',
);
const credentialOptions = response.data;
try {
const credential = await WebAuthnJSON.create({
publicKey: credentialOptions,
});
const params = {
credential: credential,
nickname: nickname,
};
await callback('/settings/security_keys', params);
} catch (error) {
const errorMessage = document.getElementById(
'security-key-error-message',
);
errorMessage?.classList.remove('hidden');
console.error(error);
}
} catch (error) {
logAxiosResponseError(error);
}
}
async function handleWebauthnCredentialAuthentication() {
try {
const response = await axios.get<PublicKeyCredentialCreationOptionsJSON>(
'sessions/security_key_options',
);
const credentialOptions = response.data;
try {
const credential = await WebAuthnJSON.get({
publicKey: credentialOptions,
});
const params = { user: { credential: credential } };
void callback('sign_in', params);
} catch (error) {
const errorMessage = document.getElementById(
'security-key-error-message',
);
errorMessage?.classList.remove('hidden');
console.error(error);
}
} catch (error) {
logAxiosResponseError(error);
}
}
ready(() => {
if (!WebAuthnJSON.supported()) {
const unsupported_browser_message = document.getElementById(
'unsupported-browser-message',
);
if (unsupported_browser_message) {
unsupported_browser_message.classList.remove('hidden');
const button = document.querySelector<HTMLButtonElement>(
'button.btn.js-webauthn',
);
if (button) button.disabled = true;
}
}
const webAuthnCredentialRegistrationForm =
document.querySelector<HTMLFormElement>('form#new_webauthn_credential');
if (webAuthnCredentialRegistrationForm) {
webAuthnCredentialRegistrationForm.addEventListener('submit', (event) => {
event.preventDefault();
if (!(event.target instanceof HTMLFormElement)) return;
const nickname = event.target.querySelector<HTMLInputElement>(
'input[name="new_webauthn_credential[nickname]"]',
);
if (nickname?.value) {
void handleWebauthnCredentialRegistration(nickname.value);
} else {
nickname?.focus();
}
});
}
const webAuthnCredentialAuthenticationForm =
document.getElementById('webauthn-form');
if (webAuthnCredentialAuthenticationForm) {
webAuthnCredentialAuthenticationForm.addEventListener('submit', (event) => {
event.preventDefault();
void handleWebauthnCredentialAuthentication();
});
const otpAuthenticationForm = document.getElementById(
'otp-authentication-form',
);
const linkToOtp = document.getElementById('link-to-otp');
linkToOtp?.addEventListener('click', () => {
webAuthnCredentialAuthenticationForm.classList.add('hidden');
otpAuthenticationForm?.classList.remove('hidden');
hideFlashMessages();
});
const linkToWebAuthn = document.getElementById('link-to-webauthn');
linkToWebAuthn?.addEventListener('click', () => {
otpAuthenticationForm?.classList.add('hidden');
webAuthnCredentialAuthenticationForm.classList.remove('hidden');
hideFlashMessages();
});
}
}).catch((e: unknown) => {
throw e;
});

View File

@ -308,6 +308,8 @@
"follow_requests.unlocked_explanation": "Benque tu conto non es serrate, le personal de {domain} pensa que es un bon idea que tu revide manualmente le sequente requestas de iste contos.",
"follow_suggestions.curated_suggestion": "Selection del equipa",
"follow_suggestions.dismiss": "Non monstrar novemente",
"follow_suggestions.featured_longer": "Seligite con cura per le equipa de {domain}",
"follow_suggestions.friends_of_friends_longer": "Popular inter le gente que tu seque",
"follow_suggestions.hints.featured": "Iste profilo ha essite seligite manualmente per le equipa de {domain}.",
"follow_suggestions.hints.friends_of_friends": "Iste profilo es popular inter le gente que tu seque.",
"follow_suggestions.hints.most_followed": "Iste profilo es un del plus sequites sur {domain}.",
@ -315,6 +317,8 @@
"follow_suggestions.hints.similar_to_recently_followed": "Iste profilo es similar al profilos que tu ha recentemente sequite.",
"follow_suggestions.personalized_suggestion": "Suggestion personalisate",
"follow_suggestions.popular_suggestion": "Suggestion personalisate",
"follow_suggestions.popular_suggestion_longer": "Popular sur {domain}",
"follow_suggestions.similar_to_recently_followed_longer": "Similar al profilos que tu ha sequite recentemente",
"follow_suggestions.view_all": "Vider toto",
"follow_suggestions.who_to_follow": "Qui sequer",
"followed_tags": "Hashtags sequite",
@ -470,6 +474,14 @@
"notification.follow_request": "{name} ha requestate de sequer te",
"notification.mention": "{name} te ha mentionate",
"notification.moderation-warning.learn_more": "Apprender plus",
"notification.moderation_warning": "Tu ha recipite un advertimento de moderation",
"notification.moderation_warning.action_delete_statuses": "Alcunes de tu messages ha essite removite.",
"notification.moderation_warning.action_disable": "Tu conto ha essite disactivate.",
"notification.moderation_warning.action_mark_statuses_as_sensitive": "Alcunes de tu messages ha essite marcate como sensibile.",
"notification.moderation_warning.action_none": "Tu conto ha recipite un advertimento de moderation.",
"notification.moderation_warning.action_sensitive": "Tu messages essera marcate como sensibile a partir de ora.",
"notification.moderation_warning.action_silence": "Tu conto ha essite limitate.",
"notification.moderation_warning.action_suspend": "Tu conto ha essite suspendite.",
"notification.own_poll": "Tu sondage ha finite",
"notification.poll": "Un sondage in le qual tu ha votate ha finite",
"notification.reblog": "{name} ha impulsate tu message",

View File

@ -308,6 +308,8 @@
"follow_requests.unlocked_explanation": "Apesar de seu perfil não ser trancado, {domain} exige que você revise a solicitação para te seguir destes perfis manualmente.",
"follow_suggestions.curated_suggestion": "Escolha da equipe",
"follow_suggestions.dismiss": "Não mostrar novamente",
"follow_suggestions.featured_longer": "Escolhido à mão pela equipe de {domain}",
"follow_suggestions.friends_of_friends_longer": "Popular entre as pessoas que você segue",
"follow_suggestions.hints.featured": "Este perfil foi escolhido a dedo pela equipe {domain}.",
"follow_suggestions.hints.friends_of_friends": "Este perfil é popular entre as pessoas que você segue.",
"follow_suggestions.hints.most_followed": "Este perfil é um dos mais seguidos em {domain}.",
@ -315,6 +317,8 @@
"follow_suggestions.hints.similar_to_recently_followed": "Este perfil é semelhante aos perfis que você seguiu recentemente.",
"follow_suggestions.personalized_suggestion": "Sugestão personalizada",
"follow_suggestions.popular_suggestion": "Sugestão popular",
"follow_suggestions.popular_suggestion_longer": "Popular em {domain}",
"follow_suggestions.similar_to_recently_followed_longer": "Similar a perfis que você seguiu recentemente",
"follow_suggestions.view_all": "Visualizar tudo",
"follow_suggestions.who_to_follow": "Quem seguir",
"followed_tags": "Hashtags seguidas",
@ -469,6 +473,15 @@
"notification.follow": "{name} te seguiu",
"notification.follow_request": "{name} quer te seguir",
"notification.mention": "{name} te mencionou",
"notification.moderation-warning.learn_more": "Aprender mais",
"notification.moderation_warning": "Você recebeu um aviso de moderação",
"notification.moderation_warning.action_delete_statuses": "Algumas das suas publicações foram removidas.",
"notification.moderation_warning.action_disable": "Sua conta foi desativada.",
"notification.moderation_warning.action_mark_statuses_as_sensitive": "Algumas de suas publicações foram marcadas por ter conteúdo sensível.",
"notification.moderation_warning.action_none": "Sua conta recebeu um aviso de moderação.",
"notification.moderation_warning.action_sensitive": "Suas publicações serão marcadas como sensíveis a partir de agora.",
"notification.moderation_warning.action_silence": "Sua conta foi limitada.",
"notification.moderation_warning.action_suspend": "Sua conta foi suspensa.",
"notification.own_poll": "Sua enquete terminou",
"notification.poll": "Uma enquete que você votou terminou",
"notification.reblog": "{name} deu boost no teu toot",

View File

@ -448,6 +448,7 @@
"notification.own_poll": "Vaša anketa sa skončila",
"notification.poll": "Anketa, v ktorej ste hlasovali, sa skončila",
"notification.reblog": "{name} zdieľa váš príspevok",
"notification.relationships_severance_event": "Stratené prepojenia s {name}",
"notification.relationships_severance_event.learn_more": "Zisti viac",
"notification.status": "{name} uverejňuje niečo nové",
"notification.update": "{name} upravuje príspevok",
@ -490,6 +491,7 @@
"notifications.policy.filter_new_accounts_title": "Nové účty",
"notifications.policy.filter_not_followers_title": "Ľudia, ktorí ťa nenasledujú",
"notifications.policy.filter_not_following_title": "Ľudia, ktorých nenasleduješ",
"notifications.policy.filter_private_mentions_title": "Nevyžiadané priame spomenutia",
"notifications.policy.title": "Filtrovať oznámenia od…",
"notifications_permission_banner.enable": "Povoliť upozornenia na ploche",
"notifications_permission_banner.how_to_control": "Ak chcete dostávať upozornenia, keď Mastodon nie je otvorený, povoľte upozornenia na ploche. Po ich zapnutí môžete presne kontrolovať, ktoré typy interakcií generujú upozornenia na ploche, a to prostredníctvom tlačidla {icon} vyššie.",

View File

@ -308,6 +308,8 @@
"follow_requests.unlocked_explanation": "Iako vaš nalog nije zaključan, osoblje {domain} smatra da biste možda želeli da ručno pregledate zahteve za praćenje sa ovih naloga.",
"follow_suggestions.curated_suggestion": "Izbor osoblja",
"follow_suggestions.dismiss": "Ne prikazuj ponovo",
"follow_suggestions.featured_longer": "Ručno odabrao tim {domain}",
"follow_suggestions.friends_of_friends_longer": "Popularno među ljudima koje pratite",
"follow_suggestions.hints.featured": "Ovaj profil je ručno izabrao tim {domain}.",
"follow_suggestions.hints.friends_of_friends": "Ovaj profil je popularan među ljudima koje pratite.",
"follow_suggestions.hints.most_followed": "Ovaj profil je jedan od najpraćenijih na {domain}.",
@ -315,6 +317,8 @@
"follow_suggestions.hints.similar_to_recently_followed": "Ovaj profil je sličan profilima koje ste nedavno zapratili.",
"follow_suggestions.personalized_suggestion": "Personalizovani predlog",
"follow_suggestions.popular_suggestion": "Popularni predlog",
"follow_suggestions.popular_suggestion_longer": "Popularno na {domain}",
"follow_suggestions.similar_to_recently_followed_longer": "Slično profilima koje ste nedavno zapratili",
"follow_suggestions.view_all": "Prikaži sve",
"follow_suggestions.who_to_follow": "Koga pratiti",
"followed_tags": "Praćene heš oznake",
@ -469,6 +473,15 @@
"notification.follow": "{name} vas je zapratio",
"notification.follow_request": "{name} je zatražio da vas prati",
"notification.mention": "{name} vas je pomenuo",
"notification.moderation-warning.learn_more": "Saznajte više",
"notification.moderation_warning": "Dobili ste moderatorsko upozorenje",
"notification.moderation_warning.action_delete_statuses": "Neke od vaših objava su uklonjene.",
"notification.moderation_warning.action_disable": "Vaš nalog je onemogućen.",
"notification.moderation_warning.action_mark_statuses_as_sensitive": "Neke od vaših objava su obeležene kao osetljive.",
"notification.moderation_warning.action_none": "Vaš nalog je dobio moderatorsko upozorenje.",
"notification.moderation_warning.action_sensitive": "Vaše objave će ubuduće biti označene kao osetljive.",
"notification.moderation_warning.action_silence": "Vaš nalog je ograničen.",
"notification.moderation_warning.action_suspend": "Vaš nalog je suspendovan.",
"notification.own_poll": "Vaša anketa je završena",
"notification.poll": "Završena je anketa u kojoj ste glasali",
"notification.reblog": "{name} je podržao vašu objavu",

View File

@ -308,6 +308,8 @@
"follow_requests.unlocked_explanation": "Иако ваш налог није закључан, особље {domain} сматра да бисте можда желели да ручно прегледате захтеве за праћење са ових налога.",
"follow_suggestions.curated_suggestion": "Избор особља",
"follow_suggestions.dismiss": "Не приказуј поново",
"follow_suggestions.featured_longer": "Ручно одабрао тим {domain}",
"follow_suggestions.friends_of_friends_longer": "Популарно међу људима које пратите",
"follow_suggestions.hints.featured": "Овај профил је ручно изабрао тим {domain}.",
"follow_suggestions.hints.friends_of_friends": "Овај профил је популаран међу људима које пратите.",
"follow_suggestions.hints.most_followed": "Овај профил је један од најпраћенијих на {domain}.",
@ -315,6 +317,8 @@
"follow_suggestions.hints.similar_to_recently_followed": "Овај профил је сличан профилима које сте недавно запратили.",
"follow_suggestions.personalized_suggestion": "Персонализовани предлог",
"follow_suggestions.popular_suggestion": "Популарни предлог",
"follow_suggestions.popular_suggestion_longer": "Популарно на {domain}",
"follow_suggestions.similar_to_recently_followed_longer": "Слично профилима које сте недавно запратили",
"follow_suggestions.view_all": "Прикажи све",
"follow_suggestions.who_to_follow": "Кога пратити",
"followed_tags": "Праћене хеш ознаке",
@ -469,6 +473,15 @@
"notification.follow": "{name} вас је запратио",
"notification.follow_request": "{name} је затражио да вас прати",
"notification.mention": "{name} вас је поменуо",
"notification.moderation-warning.learn_more": "Сазнајте више",
"notification.moderation_warning": "Добили сте модераторско упозорење",
"notification.moderation_warning.action_delete_statuses": "Неке од ваших објава су уклоњене.",
"notification.moderation_warning.action_disable": "Ваш налог је онемогућен.",
"notification.moderation_warning.action_mark_statuses_as_sensitive": "Неке од ваших објава су обележене као осетљиве.",
"notification.moderation_warning.action_none": "Ваш налог је добио модераторско упозорење.",
"notification.moderation_warning.action_sensitive": "Ваше објаве ће убудуће бити означене као осетљиве.",
"notification.moderation_warning.action_silence": "Ваш налог је ограничен.",
"notification.moderation_warning.action_suspend": "Ваш налог је суспендован.",
"notification.own_poll": "Ваша анкета је завршена",
"notification.poll": "Завршена је анкета у којој сте гласали",
"notification.reblog": "{name} је подржао вашу објаву",

View File

@ -10145,6 +10145,7 @@ noscript {
font-weight: 500;
font-size: 11px;
line-height: 16px;
word-break: keep-all;
&__badge {
background: $ui-button-background-color;

View File

@ -62,7 +62,7 @@ module Account::Associations
has_many :aliases, class_name: 'AccountAlias', dependent: :destroy, inverse_of: :account
# Hashtags
has_and_belongs_to_many :tags
has_and_belongs_to_many :tags # rubocop:disable Rails/HasAndBelongsToMany
has_many :featured_tags, -> { includes(:tag) }, dependent: :destroy, inverse_of: :account
# Account deletion requests

View File

@ -0,0 +1,77 @@
# frozen_string_literal: true
# TODO: This file is here for legacy support during devise-two-factor upgrade.
# It should be removed after all records have been migrated.
module LegacyOtpSecret
extend ActiveSupport::Concern
private
# Decrypt and return the `encrypted_otp_secret` attribute which was used in
# prior versions of devise-two-factor
# @return [String] The decrypted OTP secret
def legacy_otp_secret
return nil unless self[:encrypted_otp_secret]
return nil unless self.class.otp_secret_encryption_key
hmac_iterations = 2000 # a default set by the Encryptor gem
key = self.class.otp_secret_encryption_key
salt = Base64.decode64(encrypted_otp_secret_salt)
iv = Base64.decode64(encrypted_otp_secret_iv)
raw_cipher_text = Base64.decode64(encrypted_otp_secret)
# The last 16 bytes of the ciphertext are the authentication tag - we use
# Galois Counter Mode which is an authenticated encryption mode
cipher_text = raw_cipher_text[0..-17]
auth_tag = raw_cipher_text[-16..-1] # rubocop:disable Style/SlicingWithRange
# this alrorithm lifted from
# https://github.com/attr-encrypted/encryptor/blob/master/lib/encryptor.rb#L54
# create an OpenSSL object which will decrypt the AES cipher with 256 bit
# keys in Galois Counter Mode (GCM). See
# https://ruby.github.io/openssl/OpenSSL/Cipher.html
cipher = OpenSSL::Cipher.new('aes-256-gcm')
# tell the cipher we want to decrypt. Symmetric algorithms use a very
# similar process for encryption and decryption, hence the same object can
# do both.
cipher.decrypt
# Use a Password-Based Key Derivation Function to generate the key actually
# used for encryptoin from the key we got as input.
cipher.key = OpenSSL::PKCS5.pbkdf2_hmac_sha1(key, salt, hmac_iterations, cipher.key_len)
# set the Initialization Vector (IV)
cipher.iv = iv
# The tag must be set after calling Cipher#decrypt, Cipher#key= and
# Cipher#iv=, but before calling Cipher#final. After all decryption is
# performed, the tag is verified automatically in the call to Cipher#final.
#
# If the auth_tag does not verify, then #final will raise OpenSSL::Cipher::CipherError
cipher.auth_tag = auth_tag
# auth_data must be set after auth_tag has been set when decrypting See
# http://ruby-doc.org/stdlib-2.0.0/libdoc/openssl/rdoc/OpenSSL/Cipher.html#method-i-auth_data-3D
# we are not adding any authenticated data but OpenSSL docs say this should
# still be called.
cipher.auth_data = ''
# #update is (somewhat confusingly named) the method which actually
# performs the decryption on the given chunk of data. Our OTP secret is
# short so we only need to call it once.
#
# It is very important that we call #final because:
#
# 1. The authentication tag is checked during the call to #final
# 2. Block based cipher modes (e.g. CBC) work on fixed size chunks. We need
# to call #final to get it to process the last chunk properly. The output
# of #final should be appended to the decrypted value. This isn't
# required for streaming cipher modes but including it is a best practice
# so that your code will continue to function correctly even if you later
# change to a block cipher mode.
cipher.update(cipher_text) + cipher.final
end
end

View File

@ -22,7 +22,7 @@ module User::LdapAuthenticable
safe_username = safe_username.gsub(keys, replacement)
end
resource = joins(:account).find_by(accounts: { username: safe_username })
resource = joins(:account).merge(Account.where(Account.arel_table[:username].lower.eq safe_username.downcase)).take
if resource.blank?
resource = new(

View File

@ -84,7 +84,7 @@ class Status < ApplicationRecord
has_many :local_reblogged, -> { merge(Account.local) }, through: :reblogs, source: :account
has_many :local_bookmarked, -> { merge(Account.local) }, through: :bookmarks, source: :account
has_and_belongs_to_many :tags
has_and_belongs_to_many :tags # rubocop:disable Rails/HasAndBelongsToMany
has_one :preview_cards_status, inverse_of: :status, dependent: :delete

View File

@ -21,8 +21,10 @@
class Tag < ApplicationRecord
include Paginable
# rubocop:disable Rails/HasAndBelongsToMany
has_and_belongs_to_many :statuses
has_and_belongs_to_many :accounts
# rubocop:enable Rails/HasAndBelongsToMany
has_many :passive_relationships, class_name: 'TagFollow', inverse_of: :tag, dependent: :destroy
has_many :featured_tags, dependent: :destroy, inverse_of: :tag

View File

@ -39,6 +39,7 @@
# role_id :bigint(8)
# settings :text
# time_zone :string
# otp_secret :string
#
class User < ApplicationRecord
@ -72,6 +73,8 @@ class User < ApplicationRecord
devise :two_factor_authenticatable,
otp_secret_encryption_key: Rails.configuration.x.otp_secret
include LegacyOtpSecret # Must be after the above `devise` line in order to override the legacy method
devise :two_factor_backupable,
otp_number_of_backup_codes: 10
@ -131,11 +134,6 @@ class User < ApplicationRecord
normalizes :time_zone, with: ->(time_zone) { ActiveSupport::TimeZone[time_zone].nil? ? nil : time_zone }
normalizes :chosen_languages, with: ->(chosen_languages) { chosen_languages.compact_blank.presence }
# This avoids a deprecation warning from Rails 5.1
# It seems possible that a future release of devise-two-factor will
# handle this itself, and this can be removed from our User class.
attribute :otp_secret
has_many :session_activations, dependent: :destroy
delegate :can?, to: :role

View File

@ -87,8 +87,7 @@ Rails.application.configure do
# Otherwise, use letter_opener, which launches a browser window to view sent mail.
config.action_mailer.delivery_method = ENV['HEROKU'] || ENV['VAGRANT'] || ENV['REMOTE_DEV'] ? :letter_opener_web : :letter_opener
# We provide a default secret for the development environment here.
# This value should not be used in production environments!
# TODO: Remove once devise-two-factor data migration complete
config.x.otp_secret = ENV.fetch('OTP_SECRET', '1fc2b87989afa6351912abeebe31ffc5c476ead9bf8b3d74cbc4a302c7b69a45b40b1bbef3506ddad73e942e15ed5ca4b402bf9a66423626051104f4b5f05109')
# Raise error when a before_action's only/except options reference missing actions

View File

@ -158,6 +158,7 @@ Rails.application.configure do
'Referrer-Policy' => 'same-origin',
}
# TODO: Remove once devise-two-factor data migration complete
config.x.otp_secret = ENV.fetch('OTP_SECRET')
# Enable DNS rebinding protection and other `Host` header attacks.

View File

@ -44,6 +44,7 @@ Rails.application.configure do
# Print deprecation notices to the stderr.
config.active_support.deprecation = :stderr
# TODO: Remove once devise-two-factor data migration complete
config.x.otp_secret = '100c7faeef00caa29242f6b04156742bf76065771fd4117990c4282b8748ff3d99f8fdae97c982ab5bd2e6756a159121377cce4421f4a8ecd2d67bd7749a3fb4'
# Generate random VAPID keys

View File

@ -6,9 +6,9 @@
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY
).each do |key|
ENV.fetch(key) do
raise <<~MESSAGE
abort <<~MESSAGE
The ActiveRecord encryption feature requires that these variables are set:
Mastodon now requires that these variables are set:
- ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY
- ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT

View File

@ -16,6 +16,7 @@ ia:
pending: Tu conto es ancora sub revision.
timeout: Tu session ha expirate. Per favor reaperi session pro continuar.
unauthenticated: Es necessari aperir session o crear un conto ante de continuar.
unconfirmed: Es necessari confirmar tu adresse de e-mail ante de continuar.
mailer:
confirmation_instructions:
action: Verificar adresse de e-mail

View File

@ -174,6 +174,7 @@ fy:
read:filters: jo filters besjen
read:follows: de accounts dytsto folgest besjen
read:lists: jo listen besjen
read:me: allinnich de basisgegevens fan jo account lêze
read:mutes: jo negearre brûkers besjen
read:notifications: jo meldingen besjen
read:reports: jo rapportearre berjochten besjen

View File

@ -174,6 +174,7 @@ sr-Latn:
read:filters: pogledaj svoje filtere
read:follows: pogledaj koga pratiš
read:lists: pogledaj svoje liste
read:me: čita samo osnovne informacije o vašem nalogu
read:mutes: pogledaj ignorisanja
read:notifications: pogledaj svoja obaveštenja
read:reports: pogledaj svoje prijave

View File

@ -174,6 +174,7 @@ sr:
read:filters: погледај своје филтере
read:follows: погледај кога пратиш
read:lists: погледај своје листе
read:me: чита само основне информације о вашем налогу
read:mutes: погледај игнорисања
read:notifications: погледај своја обавештења
read:reports: погледај своје пријаве

View File

@ -597,6 +597,9 @@ fy:
actions_description_html: Beslis hokker maatregel nommen wurde moat om dizze rapportaazje op te lossen. Wanneart jo in (straf)maatregel tsjin it rapportearre account nimme, kriget de account in e-mailmelding, behalve wanneart de <strong>spam</strong>-kategory keazen is.
actions_description_remote_html: Beslút hokker aksje nommen wurde moat om dizze rapportaazje ôf te hanneljen. Dit hat allinnich ynfloed op hoet <strong>jo</strong> server kommunisearret mei dizze eksterne account en omgiet mei de ynhâld.
add_to_report: Mear oan de rapportaazje tafoegje
already_suspended_badges:
local: Al opskoarte op dizze server
remote: Al opskoarte op harren server
are_you_sure: Binne jo wis?
assign_to_self: Oan my tawize
assigned: Tawizen moderator
@ -748,6 +751,7 @@ fy:
desc_html: Dit is ôfhinklik fan eksterne scripts fan hCaptcha, wat feilichheids- en privacyrisikos meibringe kin. Boppe dat kin <strong>dit it registraasjeproses bot minder tagonklik meitsje foar guon (foaral handicapte) minsken</strong>. Om dizze redenen kinne jo it beste alternative maatregels oerweagje, lykas registraasje op basis fan goedkarring of op útnûging.
title: Nije brûkers moatte in CAPTCHA oplosse om harren account te befêstigjen
content_retention:
danger_zone: Gefaresône
preamble: Tafersjoch hâlde op hoet berjochten en media fan brûkers op Mastodon bewarre wurde.
title: Bewartermyn berjochten
default_noindex:
@ -767,6 +771,7 @@ fy:
disabled: Oan net ien
users: Oan oanmelde lokale brûkers
registrations:
moderation_recommandation: Soargje derfoar dat jo in adekwaat en responsyf moderaasjeteam hawwe eardat jo registraasjes foar elkenien iepenstelle!
preamble: Tafersjoch hâlde op wat in account op dizze server registrearje kin.
title: Registraasjes
registrations_mode:
@ -1647,13 +1652,24 @@ fy:
import: Ymportearje
import_and_export: Ymportearje en eksportearje
migrate: Accountmigraasje
notifications: E-mailmeldingen
preferences: Ynstellingen
profile: Profyl
relationships: Folgers en folgjenden
severed_relationships: Ferbrutsen folchrelaasjes
statuses_cleanup: Automatysk berjochten fuortsmite
strikes: Fêststelde skeiningen
two_factor_authentication: Twa-stapsferifikaasje
webauthn_authentication: Befeiligingskaaien
severed_relationships:
download: Downloade (%{count})
event_type:
account_suspension: Accountopskoarting (%{target_name})
domain_block: Serveropskoarting (%{target_name})
user_domain_block: Jo hawwe %{target_name} blokkearre
lost_followers: Ferlerne folgers
lost_follows: Ferlerne folge accounts
type: Barren
statuses:
attached:
audio:
@ -1747,6 +1763,7 @@ fy:
contrast: Mastodon (heech kontrast)
default: Mastodon (donker)
mastodon-light: Mastodon (ljocht)
system: Automatysk (systeemtema brûke)
time:
formats:
default: "%d %B %Y om %H:%M"
@ -1838,13 +1855,30 @@ fy:
apps_ios_action: Fia de App Store downloade
apps_step: Us offisjele apps downloade
apps_title: Mastodon-apps
checklist_subtitle: 'Litte wy oan dit nije sosjale aventoer begjinne:'
checklist_title: Wolkomstkontrôlelist
edit_profile_action: Personalisearje
edit_profile_step: Wanneart jo mear oer josels fertelle, krije jo mear ynteraksje mei oare minsken.
edit_profile_title: Jo profyl personalisearje
explanation: Hjir binne inkelde tips om jo op wei te helpen
feature_action: Mear ynfo
feature_audience: Mastodon biedt jo in unike mooglikheid om jo publyk te behearen sûnder tuskenpersoanen. Mastodon, ymplemintearre yn jo eigen ynfrastruktuer, stelt jo yn steat om elke oare Mastodon-server online te folgjen en troch harren folge te wurden, en stiet ûnder kontrôle fan net ien, útsein dy fan jo.
feature_audience_title: Bou jo publyk yn fertrouwen op
feature_control: Jo witte sels it bêste wat jo op jo tiidline sjen wolle. Gjin algoritmen of advertinsjes om jo tiid te fergriemen. Folgje elkenien op elke Mastodon-server fan ien account ôf en ûntfang harren berjochten yn gronologyske folchoarder, en meitsje jo hoekje op it ynternet in bytsje mear as josels.
feature_control_title: Hâld kontrôle oer jo eigen tiidline
feature_creativity: Mastodon stipet audio-, fideo- en fotoberjochten, tagonklikheidsbeskriuwingen, enkêten, ynhâldswarskôgingen, animearre avatars, oanpaste emoji, kontrôle oer it bywurkjen fan miniatueren en mear, om jo te helpen josels online te uterjen. Oft jo no jo keunst, muzyk of podcast publisearje, Mastodon stiet foar jo klear.
feature_creativity_title: Bjusterbaarlike kreativiteit
feature_moderation: Mastodon leit de beslútfoarming wer yn jo hannen. Elke server makket harren eigen rigels en foarskriften, dyt lokaal hanthavene wurde en net fan boppe ôf, lykas sosjale media fan bedriuwen, wêrtroch it it meast fleksibel is yn it reagearjen op de behoeften fan ferskate groepen minsken. Wurd lid fan in server mei de rigels wêrmeit jo akkoard geane, of host jo eigen.
feature_moderation_title: Moderaasje sa as it heart
follow_action: Folgje
follow_step: Op Mastodon draait it hielendal om it folgjen fan ynteressante minsken.
follow_title: Personalisearje jo starttiidline
follows_subtitle: Folgje bekende accounts
follows_title: Wa te folgjen
follows_view_more: Mear minsken om te folgjen besjen
hashtags_recent_count:
one: "%{people} persoan yn de ôfrûne 2 dagen"
other: "%{people} persoanen yn de ôfrûne 2 dagen"
hashtags_subtitle: Wat der yn de ôfrûne 2 dagen bard is ferkenne
hashtags_title: Populêre hashtags
hashtags_view_more: Mear populêre hashtags besjen

View File

@ -111,12 +111,23 @@ ia:
public: Public
push_subscription_expires: Subscription PuSH expira le
redownload: Actualisar profilo
redownloaded_msg: Le profilo de %{username} ha essite actualisate desde le origine
reject: Rejectar
rejected_msg: Le demanda de inscription de %{username} ha essite rejectate
remote_suspension_irreversible: Le datos de iste conto ha essite irreversibilemente delite.
remote_suspension_reversible_hint_html: Le conto ha essite suspendite sur su servitor, e le datos essera removite completemente le %{date}. Usque alora, le servitor remote pote restaurar iste conto sin effectos negative. Si tu vole remover immediatemente tote le datos del conto, tu pote facer lo hic infra.
remove_avatar: Remover avatar
remove_header: Remover capite
removed_avatar_msg: Le imagine de avatar de %{username} ha essite removite
removed_header_msg: Le imagine de capite de %{username} ha essite removite
resend_confirmation:
already_confirmed: Iste usator jam es confirmate
send: Reinviar ligamine de confirmation
success: Ligamine de confirmation inviate con successo!
reset: Reinitialisar
reset_password: Reinitialisar contrasigno
resubscribe: Resubscriber
role: Rolo
search: Cercar
search_same_email_domain: Altere usatores con le mesme dominio de e-mail
search_same_ip: Altere usatores con le mesme IP
@ -124,52 +135,118 @@ ia:
security_measures:
only_password: Solmente contrasigno
password_and_2fa: Contrasigno e 2FA
sensitive: Fortiar sensibile
sensitized: Marcate como sensibile
shared_inbox_url: URL del cassa de entrata condividite
show:
created_reports: Reportos facite
targeted_reports: Signalate per alteres
silence: Limitar
silenced: Limitate
statuses: Messages
strikes: Previe admonitiones
subscribe: Subscriber
suspend: Suspender
suspended: Suspendite
suspension_irreversible: Le datos de iste conto ha essite irreversibilemente delite. Tu pote disfacer le suspension de iste conto pro render lo usabile, ma isto non recuperara alcun datos precedente.
suspension_reversible_hint_html: Le conto ha essite suspendite, e le datos essera removite completemente le %{date}. Usque alora, le conto pote esser restaurate sin effectos negative. Si tu vole remover immediatemente tote le datos del conto, tu pote facer lo hic infra.
title: Contos
unblock_email: Disblocar adresse de e-mail
unblocked_email_msg: Adresse de e-mail de %{username} disblocate con successo
unconfirmed_email: E-mail non confirmate
undo_sensitized: Non plus fortiar sensibile
undo_silenced: Disfacer le limite
undo_suspension: Disfacer le suspension
unsilenced_msg: Le limite del conto de %{username} ha essite cancellate
unsubscribe: Desubscriber
unsuspended_msg: Annullate suspension del conto %{username} con successo
username: Nomine de usator
view_domain: Vider summario de dominio
warn: Avisar
web: Web
whitelisted: Permittite pro federation
action_logs:
action_types:
approve_appeal: Approbar appello
approve_user: Approbar usator
assigned_to_self_report: Assignar reporto
change_email_user: Cambiar e-mail pro le usator
change_role_user: Cambiar le rolo del usator
confirm_user: Confirmar le usator
create_account_warning: Crear un advertimento
create_announcement: Crear annuncio
create_canonical_email_block: Crear blocada de email
create_custom_emoji: Crear emoticone personalisate
create_domain_allow: Crear permisso de dominio
create_domain_block: Crear blocada de dominio
create_email_domain_block: Crear blocada de dominio email
create_ip_block: Crear un regula IP
create_unavailable_domain: Crear dominio indisponibile
create_user_role: Crear un rolo
demote_user: Degradar usator
destroy_announcement: Deler annuncio
destroy_canonical_email_block: Deler blocada de email
destroy_custom_emoji: Deler emoticone personalisate
destroy_domain_allow: Deler permisso de dominio
destroy_domain_block: Deler blocada de dominio
destroy_email_domain_block: Crear blocada de dominio email
destroy_instance: Purgar dominio
destroy_ip_block: Deler le regula IP
destroy_status: Deler le message
destroy_unavailable_domain: Deler le dominio non disponibile
destroy_user_role: Destruer rolo
disable_2fa_user: Disactivar 2FA
disable_custom_emoji: Disactivar emoji personalisate
disable_sign_in_token_auth_user: Disactivar le authentication per testimonio via email pro usator
disable_user: Disactivar le usator
enable_custom_emoji: Activar emoji personalisate
enable_sign_in_token_auth_user: Activar le authentication per testimonio via email pro usator
enable_user: Activar le usator
memorialize_account: Commemorar conto
promote_user: Promover usator
reject_appeal: Rejectar appello
reject_user: Rejectar usator
remove_avatar_user: Remover avatar
reopen_report: Reaperir reporto
resend_user: Reinviar message de confirmation
reset_password_user: Reinitialisar contrasigno
resolve_report: Resolver reporto
sensitive_account: Marcar como sensibile le medios del conto
silence_account: Limitar conto
suspend_account: Suspender conto
unassigned_report: Disassignar reporto
unblock_email_account: Disblocar adresse de e-mail
unsensitive_account: Dismarcar como sensibile le medios del conto
unsilence_account: Disfacer le limite de conto
unsuspend_account: Annullar suspension de conto
update_announcement: Actualisar annuncio
update_custom_emoji: Actualisar emoji personalisate
update_domain_block: Actualisar blocada de dominio
update_ip_block: Actualisar le regula IP
update_status: Actualisar le message
update_user_role: Actualisar rolo
actions:
approve_appeal_html: "%{name} approbava appello del decision de moderation de %{target}"
approve_user_html: "%{name} approbava inscription de %{target}"
assigned_to_self_report_html: "%{name} assignava reporto %{target} a se mesme"
change_email_user_html: "%{name} cambiava le adresse de e-mail address del usator %{target}"
change_role_user_html: "%{name} cambiava rolo de %{target}"
confirm_user_html: "%{name} confirmava le adresse email del usator %{target}"
create_account_warning_html: "%{name} inviava un advertimento a %{target}"
create_announcement_html: "%{name} creava un nove annuncio %{target}"
create_canonical_email_block_html: "%{name} blocava email con le hash %{target}"
create_custom_emoji_html: "%{name} cargava nove emoticone %{target}"
create_domain_allow_html: "%{name} permitteva federation con dominio %{target}"
create_domain_block_html: "%{name} blocava dominio %{target}"
create_email_domain_block_html: "%{name} blocava dominio email %{target}"
create_ip_block_html: "%{name} creava regula pro IP %{target}"
create_unavailable_domain_html: "%{name} stoppava consignation a dominio %{target}"
create_user_role_html: "%{name} creava rolo de %{target}"
demote_user_html: "%{name} degradava usator %{target}"
destroy_announcement_html: "%{name} deleva annuncio %{target}"
destroy_custom_emoji_html: "%{name} deleva emoji %{target}"
destroy_domain_block_html: "%{name} disblocava dominio %{target}"
destroy_user_role_html: "%{name} deleva le rolo de %{target}"
deleted_account: conto delite
announcements:
destroyed_msg: Annuncio delite con successo!
@ -205,6 +282,7 @@ ia:
media_storage: Immagazinage de medios
new_users: nove usatores
opened_reports: reportos aperte
software: Software
top_languages: Linguas le plus active
top_servers: Servitores le plus active
website: Sito web
@ -220,6 +298,10 @@ ia:
edit: Modificar un bloco de dominio
export: Exportar
import: Importar
new:
severity:
silence: Limitar
suspend: Suspender
private_comment: Commento private
public_comment: Commento public
email_domain_blocks:
@ -239,9 +321,16 @@ ia:
status: Stato
title: Sequer le recommendationes
instances:
back_to_all: Toto
back_to_limited: Limitate
back_to_warning: Advertimento
by_domain: Dominio
content_policies:
comment: Nota interne
policies:
silence: Limitar
suspend: Suspender
policy: Politica
reason: Ration public
dashboard:
instance_accounts_dimension: Contos le plus sequite
@ -249,14 +338,23 @@ ia:
delivery:
unavailable: Non disponibile
empty: Necun dominios trovate.
moderation:
all: Toto
limited: Limitate
title: Moderation
private_comment: Commento private
public_comment: Commento public
title: Federation
total_blocked_by_us: Blocate per nos
total_followed_by_us: Sequite per nos
invites:
deactivate_all: Disactivar toto
filter:
all: Toto
available: Disponibile
expired: Expirate
title: Filtro
title: Invitationes
ip_blocks:
add_new: Crear regula
delete: Deler
@ -264,15 +362,19 @@ ia:
'1209600': 2 septimanas
'15778476': 6 menses
'2629746': 1 mense
'31556952': 1 anno
'86400': 1 die
'94670856': 3 annos
new:
title: Crear un nove regula IP
title: Regulas IP
relays:
delete: Deler
description_html: Un <strong>repetitor de federation</strong> es un servitor intermediari que excambia grande volumines de messages public inter le servitores que se inscribe e publica a illo. <strong>Illo pote adjutar le servitores micre e medie a discoperir le contento del fediverso</strong>, sin requirer que le usatores local seque manualmente altere personas sur servitores distante.
disable: Disactivar
disabled: Disactivate
enable: Activar
enable_hint: Un vice activate, tu servitor se inscribera a tote le messages public de iste repetitor, e comenciara a inviar le messages public de iste servitor a illo.
enabled: Activate
save_and_enable: Salveguardar e activar
status: Stato
@ -283,9 +385,11 @@ ia:
category: Categoria
confirm: Confirmar
delete_and_resolve: Deler le messages
no_one_assigned: Nemo
notes:
create: Adder un nota
delete: Deler
title: Notas
skip_to_actions: Saltar al actiones
status: Stato
updated_at: Actualisate
@ -294,6 +398,11 @@ ia:
assigned_users:
one: "%{count} usator"
other: "%{count} usatores"
categories:
invites: Invitationes
moderation: Moderation
special: Special
delete: Deler
everyone: Permissiones predefinite
privileges:
delete_user_data: Deler le datos de usator
@ -302,6 +411,7 @@ ia:
manage_rules: Gerer le regulas
manage_settings: Gerer le parametros
manage_users: Gerer usatores
title: Rolos
rules:
delete: Deler
settings:
@ -317,8 +427,25 @@ ia:
title: Parametros de servitor
site_uploads:
delete: Deler file incargate
software_updates:
documentation_link: Pro saper plus
title: Actualisationes disponibile
type: Typo
types:
major: Version major
minor: Version minor
version: Version
statuses:
account: Autor
application: Application
batch:
report: Reporto
deleted: Delite
favourites: Favoritos
history: Chronologia del versiones
language: Lingua
media:
title: Medios
metadata: Metadatos
open: Aperir message
original_status: Message original
@ -337,6 +464,8 @@ ia:
action: Vider le actualisationes disponibile
upload_check_privacy_error:
action: Verifica hic pro plus de information
application_mailer:
unsubscribe: Desubscriber
edit_profile:
other: Alteres
existing_username_validator:
@ -397,6 +526,21 @@ ia:
login_activities:
authentication_methods:
password: contrasigno
mail_subscriptions:
unsubscribe:
action: Si, desubscriber
complete: Desubscribite
confirmation_html: Es tu secur de voler cancellar le subscription al %{type} de Mastodon sur %{domain} pro tu adresse de e-mail %{email}? Tu pote sempre resubscriber te a partir del <a href="%{settings_path}">parametros de notification in e-mail</a>.
emails:
notification_emails:
favourite: notificationes de favorites in e-mail
follow: notificationes de sequimento in e-mail
follow_request: requestas de sequimento in e-mail
mention: notificationes de mentiones in e-mail
reblog: notificationes de impulsos in e-mail
resubscribe_html: Si tu ha cancellate le subscription in error, tu pote resubscriber te a partir del <a href="%{settings_path}">parametros de notification in e-mail</a>.
success_html: Tu non recipera plus %{type} pro Mastodon sur %{domain} a tu adresse de e-mail %{email}.
title: Desubcriber
migrations:
errors:
not_found: non poterea esser trovate

View File

@ -77,10 +77,13 @@ fy:
warn: Ferstopje de filtere ynhâld efter in warskôging, mei de titel fan it filter as warskôgingstekst
form_admin_settings:
activity_api_enabled: Tal lokaal publisearre artikelen, aktive brûkers en nije registraasjes yn wyklikse werjefte
backups_retention_period: Brûkers hawwe de mooglikheid om argiven fan harren berjochten te generearjen om letter te downloaden. Wannear ynsteld op in positive wearde, wurde dizze argiven automatysk fuortsmiten út jo ûnthâld nei it opjûne oantal dagen.
bootstrap_timeline_accounts: Dizze accounts wurde boppe oan de oanrekommandaasjes oan nije brûkers toand. Meardere brûkersnammen troch kommas skiede.
closed_registrations_message: Werjûn wanneart registraasje fan nije accounts útskeakele is
content_cache_retention_period: Alle berjochten fan oare servers (ynklusyf boosts en reaksjes) wurde fuortsmiten nei it opjûne oantal dagen, nettsjinsteande iennige lokale brûkersynteraksje mei dy berjochten. Dit oanbelanget ek berjochten dyt in lokale brûker oan harren blêdwizers tafoege hat of as favoryt markearre hat. Priveeberjochten tusken brûkers fan ferskate servers gean ek ferlern en binne ûnmooglik te werstellen. It gebrûk fan dizze ynstelling is bedoeld foar servers dyt in spesjaal doel tsjinje en oertrêdet in protte brûkersferwachtingen wanneart dizze foar algemien gebrûk ymplemintearre wurdt.
custom_css: Jo kinne oanpaste CSS tapasse op de webferzje fan dizze Mastodon-server.
mascot: Oerskriuwt de yllustraasje yn de avansearre webomjouwing.
media_cache_retention_period: Mediabestannen fan berjochten fan eksterne brûkers wurde op jo server yn de buffer bewarre. Wannear ynsteld op in positive wearde, wurde media fuortsmiten nei it opjûne oantal dagen. As de mediagegevens opfrege wurde neidat se fuortsmiten binne, wurde se opnij download wannear de orizjinele ynhâld noch hieltyd beskikber is. Fanwegen beheiningen op hoe faak keppelingsfoarbylden websites fan tredden rieplachtsje, wurdt oanrekommandearre om dizze wearde yn te stellen op op syn minste 14 dagen. Oars wurde keppelingsfoarbylden net op oanfraach bywurke.
peers_api_enabled: In list mei domeinnammen, dêrt dizze server yn fediverse kontakt hân mei hat. Hjir wurdt gjin data dield, oft jo mei in bepaalde server federearrest, mar alinnich, dat jo server dat wit. Dit wurdt foar tsjinsten brûkt, dyt statistiken oer federaasje yn algemiene sin sammelet.
profile_directory: De brûkersgids befettet in list fan alle brûkers dy¥t derfoar keazen hawwe om ûntdekt wurde te kinnen.
require_invite_text: Meitsje it ynfoljen fan Wêrom wolle jo jo hjir registrearje? ferplicht yn stee fan opsjoneel, wanneart registraasjes hânmjittich goedkard wurde moatte
@ -240,6 +243,7 @@ fy:
backups_retention_period: Bewartermyn brûkersargyf
bootstrap_timeline_accounts: Accounts dyt altyd oan nije brûkers oanrekommandearre wurde
closed_registrations_message: Oanpast berjocht wannear registraasje útskeakele is
content_cache_retention_period: Bewartermyn foar eksterne ynhâld
custom_css: Oanpaste CSS
mascot: Oanpaste maskotte (legacy)
media_cache_retention_period: Bewartermyn mediabuffer

View File

@ -3,12 +3,96 @@ ia:
simple_form:
hints:
account:
discoverable: Tu messages public e tu profilo pote esser consiliate o recommendate in varie areas de Mastodon e tu profilo pote esser suggerite a altere usatores.
display_name: Tu prenomine e nomine de familia o tu pseudonymo.
fields: Tu pagina principal, pronomines, etate, toto lo que tu vole.
indexable: Tu messages public pote apparer in resultatos del recerca sur Mastodon. Illes qui ha interagite con tu messages totevia pote cercar les.
note: 'Tu pote @mentionar altere personas o #hashtags.'
show_collections: Le personas potera navigar per tu sequites e sequaces. Le personas potera navigar per tu sequites e sequaces.
unlocked: Le personas potera sequer te sin requestar approbation. Dismarca si tu desira revider le requestas de sequer e selige si acceptar o rejectar nove sequaces.
account_alias:
acct: Specifica le nomine_de_usator@dominio del conto ab que tu vole mover
account_migration:
acct: Specifica le nomine_de_usator@dominio del conto a que tu vole mover
account_warning_preset:
text: Tu pote usar le syntaxe de message, tal como URLs, hashtags e mentiones
title: Optional. Non visibile al destinatario
admin_account_action:
include_statuses: Le usator videra que messages ha causate le action o aviso de moderation
send_email_notification: Le usator recipera un explication de cosa eveniva con lor conto
text_html: Optional. Tu pote usar le syntaxe de message. Tu pote <a href="%{path}">adder avisos preconfigurate</a> pro sparniar tempore
type_html: Selige lo que tu vole facer con <strong>%{acct}</strong>
types:
disable: Impedir al usator de usar lor conto, sin deler o celar lor contentos.
none: Usar lo pro inviar un aviso al usator, sin discatenar ulle altere action.
sensitive: Fortiar tote le annexos multimedial de iste usator a esser signalate como sensibile.
silence: Impedir al usator de poter publicar messages con public visibilitate, celar lor messages e notificationes ab gente non sequente illes. Clauder tote le reportos contra iste conto.
suspend: Impedir ulle interaction de o a iste conto e deler su contentos. Reversibile intra 30 dies. Clauder tote le reportos contra iste conto.
warning_preset_id: Optional. Tu pote ancora adder personal texto a fin del preconfigurate
announcement:
all_day: Si marcate, solo le datas del campo tempore sera monstrate
ends_at: Le annuncio sera automaticamente obscurate a iste tempore
scheduled_at: Lassar blanc pro publicar le annuncio immediatemente
starts_at: Optional. In caso tu annuncio es ligate con un specific campo tempore
text: Tu pote usar le syntaxe de message. Presta attention al spatio que le annuncio occupara sur le schermo de usator
appeal:
text: Tu pote solo appellar te un vice
defaults:
autofollow: Illes qui se inscribe per le invitation automaticamente devenira tu sequaces
avatar: WEBP, PNG, GIF or JPG. Al maximo %{size}. Sera diminuite a %{dimensions}px
bot: Signala a alteres que le conto principalmente exeque actiones automatisate e poterea non esser surveliate
context: Un o plure contextos ubi le filtro deberea applicar se
current_password: Pro propositos de securitate insere le contrasigno del conto actual
current_username: Pro confirmar, insere le nomine de usator del conto actual
digest: Solo inviate post un longe periodo de inactivitate e solo si tu ha recipite alcun messages personal in tu absentia
email: Te sera inviate un email de confirmation
header: WEBP, PNG, GIF or JPG. Al maximo %{size}. Sera diminuite a %{dimensions}px
inbox_url: Copia le URL ab le pagina principal del repetitor que tu vole usar
irreversible: Le messages filtrate disparera irreversibilemente, mesmo si le filtro es plus tarde removite
locale: Le lingua del interfacie de usator, del emails e del notificationes pulsate
password: Usa al minus 8 characteres
phrase: Sera concordate ignorante majuscule/minuscule in le texto o avisos de contento de un message
scopes: A que APIs sera permittite acceder al application. Si tu selige un ambito de maxime nivello, tu non besonia de seliger los singulemente.
setting_aggregate_reblogs: Non monstra nove stimulos pro messages que ha essite recentemente stimulate (stimulos solo affice los novemente recipite)
setting_always_send_emails: Normalmente le avisos de email non sera inviate quando tu activemente usa Mastodon
setting_default_sensitive: Le medios sensibile es celate de ordinario e pote esser revelate con un clic
setting_display_media_default: Celar le medios marcate como sensibile
setting_display_media_hide_all: Sempre celar le medios
setting_display_media_show_all: Sempre monstrar le medios
setting_use_blurhash: Le imagines degradate es basate sur le colores del medios visual celate, ma illos offusca qualcunque detalios
setting_use_pending_items: Celar le classification temporal detra un clic in vice que automaticamente rolante le fluxo
username: Tu pote usar litteras, numeros e tractos de sublineamento
whole_word: Quando le parola o expression clave es solo alphanumeric, illo sera solo applicate si illo concorda con tote le parola
domain_allow:
domain: Iste dominio potera reportar datos ab iste servitor e le datos in ingresso ab illo sera processate e immagazinate
email_domain_block:
domain: Isto pote esser le nomine de dominio que apparera in le adresse email o le registration MX que illo usa. Illos sera verificate durante le inscription.
with_dns_records: Un tentativa sera facite pro resolver le registrationes de DNS del dominio date e le resultatos sera alsi blocate
featured_tag:
name: 'Ecce alcun del hashtags que tu usava le plus recentemente:'
filters:
action: Selige que action exequer quando un message concorda con le filtro
actions:
hide: Completemente celar le contento filtrate, comportar se como si illo non existerea
warn: Celar le contento filtrate detra un aviso citante le titulo del filtro
form_admin_settings:
activity_api_enabled: Numeros de messages localmente publicate, usatores active, e nove registrationes in gruppos septimanal
backups_retention_period: Le usatores pote generar archivos de lor messages pro discargar los plus tarde. Quando predefinite a un valor positive, iste archivos sera automaticamente delite de tu immagazinage post le specificate numero de dies.
bootstrap_timeline_accounts: Iste contos sera appunctate al summitate del recommendationes a sequer del nove usatores.
closed_registrations_message: Monstrate quando le inscriptiones es claudite
content_cache_retention_period: Tote messages de altere servitores (includite stimulos e responsas) sera delite post le specificate numero de dies, sin considerar alcun interaction de usator local con ille messages. Isto include messages ubi un usator local los ha marcate como marcapaginas o favoritos. Mentiones private inter usatores de differente instantias sera alsi perdite e impossibile a restaurar. Le uso de iste parametros es intendite pro specific instantias e infringe multe expectationes de usator quando implementate pro uso general.
custom_css: Tu pote applicar stilos personalisate sur le version de web de Mastodon.
mascot: Illo substitue le illustration in le interfacie web avantiate.
media_cache_retention_period: Le files multimedial de messages producite per usatores remote es in cache sur tu servitor. Quando predefinite a un valor positive, le medios sera delite post le numero de dies specificate. Le datos multimedial requirite post que illo es delite, sera re-discargate, si le contento original sera ancora disponibile. Per limitationes sur le frequentia con que le schedas de pre-visualisation de ligamine scruta le sitos de tertie partes, il es recommendate de predefinir iste valor a al minus 14 dies, o le schedas de pre-visualisation de ligamine non sera actualisate sur demanda ante ille tempore.
peers_api_enabled: Un lista de nomines de dominio que iste servitor ha incontrate in le fediverso. Nulle datos es includite ci re tu federation con un date servitor, justo que tu servitor lo cognosce. Isto es usate per servicios que collige statistica re le federation in senso general.
profile_directory: Le directorio de profilo lista tote le usatores qui ha optate pro esser detectabile.
require_invite_text: Quando le inscriptiones require approbation manual, rende obligatori, plus tosto que optional, le entrata de texto “Perque vole tu junger te?”
site_contact_email: Como pote contactar te le personas pro questiones legal o de supporto.
site_contact_username: Como pote contactar te le personas re Mastodon.
site_extended_description: Qualcunque information additional que pote esser utile al visitatores e a tu usatores. Pote esser structurate con syntaxe de markdown.
ip_block:
severities:
no_access: Blocar accesso a tote le ressources
webhook:
events: Selige le eventos a inviar
url: Ubi le eventos essera inviate
@ -22,15 +106,20 @@ ia:
show_collections: Monstrar sequites e sequitores in le profilo
unlocked: Acceptar automaticamente nove sequitores
account_warning_preset:
text: Texto predefinite
title: Titulo
admin_account_action:
send_email_notification: Notificar le usator per e-mail
text: Advertimento personalisate
type: Action
types:
disable: Gelar
none: Inviar un advertimento
sensitive: Sensibile
silence: Limitar
suspend: Suspender
announcement:
starts_at: Initio del evento
text: Annuncio
defaults:
autofollow: Invitar a sequer tu conto
@ -38,25 +127,41 @@ ia:
chosen_languages: Filtrar linguas
confirm_new_password: Confirmar nove contrasigno
confirm_password: Confirmar contrasigno
context: Contextos del filtro
current_password: Contrasigno actual
data: Datos
display_name: Nomine a monstrar
email: Adresse de e-mail
expires_in: Expira post
fields: Campos extra
header: Imagine titulo
honeypot: "%{label} (non compilar)"
inbox_url: URL del cassa de ingresso de repetitor
locale: Lingua de interfacie
max_uses: Numero max de usos
new_password: Nove contrasigno
note: Bio
otp_attempt: Codice a duo factores
password: Contrasigno
phrase: Parola o phrase clave
setting_advanced_layout: Activar le interfacie web avantiate
setting_always_send_emails: Sempre inviar notificationes per e-mail
setting_default_language: Lingua de publication
setting_display_media: Visualisation de medios
setting_display_media_default: Predefinite
setting_display_media_hide_all: Celar toto
setting_display_media_show_all: Monstrar toto
setting_system_font_ui: Usar typo de litteras predefinite del systema
setting_theme: Thema de sito
setting_trends: Monstrar le tendentias de hodie
setting_use_pending_items: Modo lente
severity: Severitate
sign_in_token_attempt: Codice de securitate
title: Titulo
type: Importar le typo
username: Nomine de usator
username_or_email: Nomine de usator o e-mail
whole_word: Parola integre
featured_tag:
name: Hashtag
filters:
@ -74,11 +179,18 @@ ia:
site_title: Nomine de servitor
status_page_url: URL del pagina de stato
theme: Thema predefinite
thumbnail: Miniatura de servitor
trends: Activar tendentias
invite:
comment: Commento
ip_block:
comment: Commento
ip: IP
severities:
no_access: Blocar le accesso
severity: Regula
notification_emails:
digest: Inviar emails compendio
software_updates:
all: Notificar sur tote le actualisationes
critical: Notificar solmente sur actualisationes critic
@ -94,13 +206,18 @@ ia:
name: Hashtag
usable: Permitter al messages usar iste hashtag
user:
role: Rolo
time_zone: Fuso horari
user_role:
name: Nomine
permissions_as_keys: Permissiones
position: Prioritate
webhook:
events: Eventos activate
'no': 'No'
not_recommended: Non recommendate
recommended: Recommendate
required:
mark: "*"
text: requirite
'yes': Si

View File

@ -240,6 +240,7 @@ pt-BR:
backups_retention_period: Período de retenção do arquivo de usuário
bootstrap_timeline_accounts: Sempre recomendar essas contas para novos usuários
closed_registrations_message: Mensagem personalizada quando inscrições não estão disponíveis
content_cache_retention_period: Período de retenção de conteúdo remoto
custom_css: CSS personalizável
mascot: Mascote personalizado (legado)
media_cache_retention_period: Período de retenção do cachê de mídia

View File

@ -77,10 +77,13 @@ sr-Latn:
warn: Sakrij filtrirani sadržaj iza upozorenja u kome se navodi naziv filtera
form_admin_settings:
activity_api_enabled: Brojevi lokalno postavljenih objava, aktivnih korisnika i novih registracija na nedeljnoj bazi
backups_retention_period: Korisnici imaju mogućnost da generišu arhive svojih objava za kasnije preuzimanje. Kada se podese na pozitivnu vrednost, ove arhive će se automatski izbrisati iz vašeg skladišta nakon navedenog broja dana.
bootstrap_timeline_accounts: Ovi nalozi će biti zakačeni na vrh preporuka za praćenje novih korisnika.
closed_registrations_message: Prikazuje se kada su registracije zatvorene
content_cache_retention_period: Sve objave sa drugih servera (uključujući podržavanja i odgovore) će biti izbrisane nakon navedenog broja dana, bez obzira na bilo kakvu interakciju lokalnog korisnika sa tim objavama. Ovo uključuje objave u kojima ih je lokalni korisnik označio kao obeleživače ili omiljene. Privatna pominjanja između korisnika sa različitih instanci će takođe biti izgubljena i nemoguće ih je vratiti. Korišćenje ove postavke je namenjeno za slučajeve posebne namene i krši mnoga očekivanja korisnika kada se primeni za upotrebu opšte namene.
custom_css: Možete da primenite prilagođene stilove na veb verziji Mastodon-a.
mascot: Zamenjuje ilustraciju u naprednom veb okruženju.
media_cache_retention_period: Medijske datoteke iz objava udaljenih korisnika se keširaju na vašem serveru. Kada se podesi na pozitivnu vrednost, mediji će biti izbrisani nakon navedenog broja dana. Ako se medijski podaci zahtevaju nakon brisanja, biće ponovo preuzeti, ako je izvorni sadržaj i dalje dostupan. Zbog ograničenja koliko često kartice za pregled veza anketiraju sajtove trećih strana, preporučuje se da ovu vrednost postavite na najmanje 14 dana, inače kartice za pregled veza neće biti ažurirane na zahtev pre tog vremena.
peers_api_enabled: Lista domena sa kojima se ovaj server susreo u fediverzumu. Ovde nisu sadržani podaci o tome da li se Vaš server federiše sa drugim serverima, već samo da Vaš server zna za njih. Ove informacije koriste servisi koji prikupljaju podatke i vode statistiku o federaciji u širem smislu.
profile_directory: Direktorijum profila navodi sve korisnike koji su se opredelili da budu vidljivi.
require_invite_text: Kada registracije zahtevaju ručno odobrenje, postavite da odgovor na „Zašto želite da se pridružite?“ bude obavezan, a ne opcionalan
@ -240,6 +243,7 @@ sr-Latn:
backups_retention_period: Period čuvanja korisničke arhive
bootstrap_timeline_accounts: Uvek preporuči ove naloge novim korisnicima
closed_registrations_message: Prilagođena poruka kada prijave nisu moguće
content_cache_retention_period: Period zadržavanja udaljenog sadržaja
custom_css: Prilagođeni CSS
mascot: Prilagođena maskota (nasleđe)
media_cache_retention_period: Period čuvanja keša medija

View File

@ -77,10 +77,13 @@ sr:
warn: Сакриј филтрирани садржај иза упозорења у коме се наводи назив филтера
form_admin_settings:
activity_api_enabled: Бројеви локално постављених објава, активних корисника и нових регистрација на недељној бази
backups_retention_period: Корисници имају могућност да генеришу архиве својих објава за касније преузимање. Када се подесе на позитивну вредност, ове архиве ће се аутоматски избрисати из вашег складишта након наведеног броја дана.
bootstrap_timeline_accounts: Ови налози ће бити закачени на врх препорука за праћење нових корисника.
closed_registrations_message: Приказује се када су регистрације затворене
content_cache_retention_period: Све објаве са других сервера (укључујући подржавања и одговоре) ће бити избрисане након наведеног броја дана, без обзира на било какву интеракцију локалног корисника са тим објавама. Ово укључује објаве у којима их је локални корисник означио као обележиваче или омиљене. Приватна помињања између корисника са различитих инстанци ће такође бити изгубљена и немогуће их је вратити. Коришћење ове поставке је намењено за случајеве посебне намене и крши многа очекивања корисника када се примени за употребу опште намене.
custom_css: Можете да примените прилагођене стилове на веб верзији Mastodon-а.
mascot: Замењује илустрацију у напредном веб окружењу.
media_cache_retention_period: Медијске датотеке из објава удаљених корисника се кеширају на вашем серверу. Када се подеси на позитивну вредност, медији ће бити избрисани након наведеног броја дана. Ако се медијски подаци захтевају након брисања, биће поново преузети, ако је изворни садржај и даље доступан. Због ограничења колико често картице за преглед веза анкетирају сајтове трећих страна, препоручује се да ову вредност поставите на најмање 14 дана, иначе картице за преглед веза неће бити ажуриране на захтев пре тог времена.
peers_api_enabled: Листа домена са којима се овај сервер сусрео у федиверзуму. Овде нису садржани подаци о томе да ли се Ваш сервер федерише са другим серверима, већ само да Ваш сервер зна за њих. Ове информације користе сервиси који прикупљају податке и воде статистику о федерацији у ширем смислу.
profile_directory: Директоријум профила наводи све кориснике који су се определили да буду видљиви.
require_invite_text: Када регистрације захтевају ручно одобрење, поставите да одговор на „Зашто желите да се придружите?“ буде обавезан, а не опционалан
@ -240,6 +243,7 @@ sr:
backups_retention_period: Период чувања корисничке архиве
bootstrap_timeline_accounts: Увек препоручи ове налоге новим корисницима
closed_registrations_message: Прилагођена порука када пријаве нису могуће
content_cache_retention_period: Период задржавања удаљеног садржаја
custom_css: Прилагођени CSS
mascot: Прилагођена маскота (наслеђе)
media_cache_retention_period: Период чувања кеша медија

View File

@ -77,10 +77,13 @@ sv:
warn: Dölj det filtrerade innehållet bakom en varning som visar filtrets rubrik
form_admin_settings:
activity_api_enabled: Antalet lokalt publicerade inlägg, aktiva användare och nya registrerade konton per vecka
backups_retention_period: Användare har möjlighet att generera arkiv av sina inlägg för att ladda ned senare. När det sätts till ett positivt värde raderas dessa arkiv automatiskt från din lagring efter det angivna antalet dagar.
bootstrap_timeline_accounts: Dessa konton kommer fästas högst upp i nya användares följrekommendationer.
closed_registrations_message: Visas när nyregistreringar är avstängda
content_cache_retention_period: Alla inlägg från andra servrar (inklusive booster och svar) kommer att raderas efter det angivna antalet dagar, utan hänsyn till någon lokal användarinteraktion med dessa inlägg. Detta inkluderar inlägg där en lokal användare har markerat det som bokmärke eller favoriter. Privata omnämnanden mellan användare från olika instanser kommer också att gå förlorade och blir omöjliga att återställa. Användningen av denna inställning är avsedd för specialfall och bryter många användarförväntningar när de implementeras för allmänt bruk.
custom_css: Du kan använda anpassade stilar på webbversionen av Mastodon.
mascot: Åsidosätter illustrationen i det avancerade webbgränssnittet.
media_cache_retention_period: Mediafiler från inlägg som gjorts av fjärranvändare cachas på din server. När inställd på ett positivt värde kommer media att raderas efter det angivna antalet dagar. Om mediadatat begärs efter att det har raderats, kommer det att laddas ned igen om källinnehållet fortfarande är tillgängligt. På grund av begränsningar för hur ofta förhandsgranskningskort för länkar hämtas från tredjepartswebbplatser, rekommenderas det att ange detta värde till minst 14 dagar, annars kommer förhandsgranskningskorten inte att uppdateras på begäran före den tiden.
peers_api_enabled: En lista över domänen den här servern har stött på i fediversum. Ingen data inkluderas om du har federerat med servern, bara att din server känner till den. Detta används av tjänster som samlar statistik om federering i allmänhet.
profile_directory: Profilkatalogen visar alla användare som har samtyckt till att bli upptäckbara.
require_invite_text: Gör fältet "Varför vill du gå med?" obligatoriskt när nyregistreringar kräver manuellt godkännande
@ -240,6 +243,7 @@ sv:
backups_retention_period: Lagringsperiod för användararkivet
bootstrap_timeline_accounts: Rekommendera alltid dessa konton till nya användare
closed_registrations_message: Anpassat meddelande när nyregistreringar inte är tillgängliga
content_cache_retention_period: Förvaringsperiod för fjärrinnehåll
custom_css: Anpassad CSS
mascot: Anpassad maskot (tekniskt arv)
media_cache_retention_period: Tid för bibehållande av mediecache

View File

@ -236,10 +236,12 @@ sk:
confirm_user_html: "%{name} potvrdil/a emailovú adresu používateľa %{target}"
create_account_warning_html: "%{name} poslal/a upozornenie užívateľovi %{target}"
create_announcement_html: "%{name} vytvoril/a nové oboznámenie %{target}"
create_canonical_email_block_html: "%{name} zablokoval/a email s hašom %{target}"
create_custom_emoji_html: "%{name} nahral/a novú emotikonu %{target}"
create_domain_allow_html: "%{name} povolil/a federáciu s doménou %{target}"
create_domain_block_html: "%{name} zablokoval/a doménu %{target}"
create_email_domain_block_html: "%{name} zablokoval/a e-mailovú doménu %{target}"
create_ip_block_html: "%{name} vytvoril/a pravidlo pre IP %{target}"
create_user_role_html: "%{name} vytvoril/a rolu pre %{target}"
demote_user_html: "%{name} degradoval/a užívateľa %{target}"
destroy_announcement_html: "%{name} vymazal/a oboznámenie %{target}"
@ -621,6 +623,7 @@ sk:
branding:
title: Značka
content_retention:
danger_zone: Riziková zóna
title: Ponechanie obsahu
discovery:
follow_recommendations: Odporúčania pre nasledovanie
@ -726,10 +729,16 @@ sk:
tags:
dashboard:
tag_accounts_measure: unikátnych použití
tag_languages_dimension: Najpoužívanejšie jazyky
tag_servers_dimension: Najpoužívanejšie servery
tag_servers_measure: iné servery
tag_uses_measure: užívateľov celkovo
listable: Môže byť navrhnutý
not_listable: Nebude navrhnutý
not_trendable: Neobjaví sa medzi trendmi
not_usable: Nemôže byť použitý
title: Populárne štítky
trendable: Môže sa objaviť medzi trendmi
trending_rank: 'Populárne #%{rank}'
usable: Môže byť použitý
title: Trendy
@ -752,6 +761,7 @@ sk:
new_appeal:
actions:
delete_statuses: vymazať ich príspevky
disable: zmraziť ich účet
none: varovanie
silence: obmedziť ich účet
new_pending_account:
@ -888,14 +898,21 @@ sk:
strikes:
action_taken: Vykonaný zákrok
appeal: Namietni
appeal_submitted_at: Námietka odoslaná
appeals:
submit: Pošli námietku
approve_appeal: Schváľ námietku
created_at: Dátumom
recipient: Adresované pre
reject_appeal: Zamietni námietku
title_actions:
disable: Zmrazenie účtu
mark_statuses_as_sensitive: Označenie príspevkov za chúlostivé
none: Varovanie
sensitive: Označenie účtu ako chúlostivý
silence: Obmedzenie účtu
your_appeal_approved: Tvoja námietka bola schválená
your_appeal_pending: Odoslal si námietku
domain_validator:
invalid_domain: nieje správny tvar domény
edit_profile:
@ -956,7 +973,11 @@ sk:
expires_on: Expiruje dňa %{date}
title: Triedenia
new:
save: Uložiť nový filter
title: Pridaj nové triedenie
statuses:
batch:
remove: Odstrániť z filtrovania
generic:
all: Všetko
cancel: Zruš
@ -975,15 +996,28 @@ sk:
imports:
errors:
over_rows_processing_limit: obsahuje viac než %{count} riadkov
too_large: Súbor je príliš veľký
failures: Zlyhaní(a)
imported: Nahrané
modes:
merge: Spoj dohromady
merge_long: Ponechaj existujúce záznamy a pridaj k nim nové
overwrite: Prepíš
overwrite_long: Nahraď súčasné záznamy novými
preface: Môžeš nahrať dáta ktoré si exportoval/a z iného Mastodon serveru, ako sú napríklad zoznamy ľudí ktorých sleduješ, alebo blokuješ.
recent_imports: Nedávne nahrania
states:
finished: Dokončené
unconfirmed: Nepotvrdených
status: Stav
success: Tvoje dáta boli nahraté úspešne, a teraz budú spracované v danom čase
titles:
bookmarks: Nahrávanie záložiek
domain_blocking: Nahrávanie blokovaných domén
lists: Nahrávanie zoznamov
type_groups:
constructive: Sledovania a záložky
destructive: Blokovania a utíšenia
types:
blocking: Zoznam blokovaných
bookmarks: Záložky
@ -1026,6 +1060,9 @@ sk:
sign_in_token: emailovým bezpečtnostným kódom
webauthn: bezpečnostnými kľúčmi
title: História overení
mail_subscriptions:
unsubscribe:
title: Ukonči odber
media_attachments:
validations:
images_and_video: K príspevku ktorý už obsahuje obrázky nemôžeš priložiť video
@ -1121,7 +1158,11 @@ sk:
posting_defaults: Východiskové nastavenia príspevkov
public_timelines: Verejné časové osi
privacy:
privacy: Súkromie
search: Vyhľadávanie
title: Súkromie a dosah
privacy_policy:
title: Pravidlá ochrany súkromia
reactions:
errors:
limit_reached: Maximálny počet rôznorodých reakcií bol dosiahnutý
@ -1152,6 +1193,11 @@ sk:
status: Stav účtu
remote_follow:
missing_resource: Nemožno nájsť potrebnú presmerovaciu adresu k tvojmu účtu
rss:
content_warning: 'Varovanie o obsahu:'
descriptions:
account: Verejné príspevky od @%{acct}
tag: 'Verejné príspevky otagované #%{hashtag}'
scheduled_statuses:
over_daily_limit: Prekročil/a si denný limit %{limit} predplánovaných príspevkov
over_total_limit: Prekročil/a si limit %{limit} predplánovaných príspevkov
@ -1203,6 +1249,7 @@ sk:
profile: Profil
relationships: Sledovania a následovatelia
two_factor_authentication: Dvojfázové overenie
webauthn_authentication: Bezpečnostné kľúče
severed_relationships:
lost_followers: Stratení nasledovatelia
lost_follows: Stratené sledovania
@ -1216,11 +1263,13 @@ sk:
other: "%{count} obrázky"
boosted_from_html: Vyzdvihnuté od %{acct_link}
content_warning: 'Varovanie o obsahu: %{warning}'
default_language: Rovnaký ako jazyk rozhrania
disallowed_hashtags:
few: 'obsah nepovolených haštagov: %{tags}'
many: 'obsah nepovolených haštagov: %{tags}'
one: 'obsahoval nepovolený haštag: %{tags}'
other: 'obsahoval nepovolené haštagy: %{tags}'
edited_at_html: Upravené %{date}
errors:
in_reply_not_found: Príspevok, na ktorý sa snažíš odpovedať, pravdepodobne neexistuje.
open_in_web: Otvor v okne na webe
@ -1245,6 +1294,7 @@ sk:
show_thread: Ukáž diskusné vlákno
title: '%{name}: „%{quote}"'
visibilities:
direct: Súkromne
private: Iba pre sledovateľov
private_long: Ukáž iba následovateľom
public: Verejné
@ -1252,10 +1302,24 @@ sk:
unlisted: Nezaradené
unlisted_long: Všetci môžu vidieť, ale nieje zaradené do verejnej osi
statuses_cleanup:
exceptions: Výnimky
ignore_favs: Ignoruj obľúbené
ignore_reblogs: Ignoruj vyzdvihnutia
keep_direct: Ponechaj súkromné správy
keep_pinned: Ponechaj pripnuté príspevky
keep_pinned_hint: Nevymaže žiadne s tvojich pripnutých príspevkov
keep_polls: Ponechaj ankety
keep_self_bookmark: Ponechaj príspevky, ktoré sú záložkami
keep_self_fav: Ponechať príspevky, ktoré si si obľúbil/a
min_age:
'1209600': 2 týždne
'15778476': 6 mesačné
'2629746': 1 mesačné
'31556952': 1 ročné
'5259492': 2 mesačné
'604800': 1 týždeň
'63113904': 2 ročné
'7889238': 3 mesačné
stream_entries:
sensitive_content: Senzitívny obsah
tags:
@ -1282,8 +1346,10 @@ sk:
user_mailer:
appeal_approved:
action: Nastavenia účtu
title: Námietka schválená
appeal_rejected:
subtitle: Tvoje odvolanie bolo zamietnuté.
title: Námietka zamietnutá
backup_ready:
explanation: Vyžiadal/a si si úplnú zálohu svojho Mastodon účtu.
extra: Teraz je pripravená na stiahnutie!
@ -1291,23 +1357,36 @@ sk:
title: Odber archívu
failed_2fa:
details: 'Tu sú podrobnosti o pokuse o prihlásenie:'
suspicious_sign_in:
change_password: zmeň svoje heslo
title: Nové prihlásenie
warning:
appeal: Pošli námietku
reason: 'Dôvod:'
subject:
disable: Tvoj účet %{acct} bol zamrazený
none: Varovanie pre %{acct}
silence: Tvoj účet %{acct} bol obmedzený
suspend: Tvoj účet %{acct} bol vylúčený
title:
delete_statuses: Príspevky vymazané
disable: Účet bol zamrazený
mark_statuses_as_sensitive: Príspevky označené za chúlostivé
none: Varovanie
sensitive: Účet označený za chúlostivý
silence: Účet bol obmedzený
suspend: Tvoj účet bol vylúčený
welcome:
apps_android_action: Získaj ju na Google Play
apps_ios_action: Stiahni z App Store
apps_step: Stiahni naše oficiálne aplikácie.
apps_title: Mastodon aplikácie
edit_profile_action: Prispôsob
edit_profile_title: Prispôsob si svoj profil
explanation: Tu nájdeš nejaké tipy do začiatku
feature_action: Zisti viac
follow_action: Nasleduj
follows_title: Koho nasledovať
post_title: Vytvor svoj prvý príspevok
share_action: Zdieľaj
sign_in_action: Prihlás sa

View File

@ -765,6 +765,7 @@ sr-Latn:
desc_html: Ovo se oslanja na eksterne skripte iz hCaptcha, što može predstavljati zabrinutost za bezbednost i privatnost. Pored toga, <strong>ovo može učiniti proces registracije znatno manje dostupnim nekim (posebno osobama sa invaliditetom)</strong>. Iz ovih razloga, razmotrite alternativne mere kao što je registracija zasnovana na odobrenju ili na pozivu.
title: Zahtevaj od novih korisnika da reše CAPTCHA da bi potvrdili svoj nalog
content_retention:
danger_zone: Opasna zona
preamble: Kontrolišite kako se sadržaj generisan od strane korisnika skladišti na Mastodon-u.
title: Zadržavanje sadržaja
default_noindex:

View File

@ -765,6 +765,7 @@ sr:
desc_html: Ово се ослања на екстерне скрипте из hCaptcha, што може представљати забринутост за безбедност и приватност. Поред тога, <strong>ово може учинити процес регистрације знатно мање доступним неким (посебно особама са инвалидитетом)</strong>. Из ових разлога, размотрите алтернативне мере као што је регистрација заснована на одобрењу или на позиву.
title: Захтевај од нових корисника да реше CAPTCHA да би потврдили свој налог
content_retention:
danger_zone: Опасна зона
preamble: Контролишите како се садржај генерисан од стране корисника складишти на Mastodon-у.
title: Задржавање садржаја
default_noindex:

View File

@ -0,0 +1,7 @@
# frozen_string_literal: true
class AddOtpSecretToUser < ActiveRecord::Migration[7.1]
def change
add_column :users, :otp_secret, :string
end
end

View File

@ -0,0 +1,39 @@
# frozen_string_literal: true
class MigrateDeviseTwoFactorSecrets < ActiveRecord::Migration[7.1]
disable_ddl_transaction!
class MigrationUser < ApplicationRecord
self.table_name = :users
devise :two_factor_authenticatable,
otp_secret_encryption_key: Rails.configuration.x.otp_secret
include LegacyOtpSecret # Must be after the above `devise` line in order to override the legacy method
end
def up
MigrationUser.reset_column_information
users_with_otp_enabled.find_each do |user|
# Gets the new value on already-updated users
# Falls back to legacy value on not-yet-migrated users
otp_secret = user.otp_secret
Rails.logger.debug { "Processing #{user.email}" }
# This is a no-op for migrated users and updates format for not migrated
user.update!(otp_secret: otp_secret)
end
end
def down
raise ActiveRecord::IrreversibleMigration
end
private
def users_with_otp_enabled
MigrationUser.where(otp_required_for_login: true, otp_secret: nil)
end
end

View File

@ -1202,6 +1202,7 @@ ActiveRecord::Schema[7.1].define(version: 2024_03_22_161611) do
t.bigint "role_id"
t.text "settings"
t.string "time_zone"
t.string "otp_secret"
t.index ["account_id"], name: "index_users_on_account_id"
t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
t.index ["created_by_application_id"], name: "index_users_on_created_by_application_id", where: "(created_by_application_id IS NOT NULL)"

View File

@ -1,6 +1,22 @@
# frozen_string_literal: true
# We are providing our own task with our own format
Rake::Task['db:encryption:init'].clear
namespace :db do
namespace :encryption do
desc 'Generate a set of keys for configuring Active Record encryption in a given environment'
task init: :environment do
puts <<~MSG
Add these environment variables to your Mastodon environment:#{' '}
ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=#{SecureRandom.alphanumeric(32)}
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=#{SecureRandom.alphanumeric(32)}
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=#{SecureRandom.alphanumeric(32)}
MSG
end
end
namespace :migrate do
desc 'Setup the db or migrate depending on state of db'
task setup: :environment do

View File

@ -127,6 +127,14 @@ namespace :tests do
exit(1)
end
# This is checking the attribute rather than the method, to avoid the legacy fallback
# and ensure the data has been migrated
unless Account.find_local('qcuser').user[:otp_secret] == 'anotpsecretthatshouldbeencrypted'
puts "DEBUG: #{Account.find_local('qcuser').user.inspect}"
puts 'OTP secret for user not preserved as expected'
exit(1)
end
puts 'No errors found. Database state is consistent with a successful migration process.'
end
@ -213,9 +221,15 @@ namespace :tests do
(4, 10, 'kmruser@localhost', now(), now(), false, 'ku', '{en,kmr,ku,ckb}');
INSERT INTO "users"
(id, account_id, email, created_at, updated_at, locale)
(id, account_id, email, created_at, updated_at, locale,
encrypted_otp_secret, encrypted_otp_secret_iv, encrypted_otp_secret_salt,
otp_required_for_login)
VALUES
(5, 11, 'qcuser@localhost', now(), now(), 'fr-QC');
(5, 11, 'qcuser@localhost', now(), now(), 'fr-QC',
E'Fttsy7QAa0edaDfdfSz094rRLAxc8cJweDQ4BsWH/zozcdVA8o9GLqcKhn2b\nGi/V\n',
'rys3THICkr60BoWC',
'_LMkAGvdg7a+sDIKjI3mR2Q==',
true);
INSERT INTO "settings"
(id, thing_type, thing_id, var, value, created_at, updated_at)

View File

@ -1,7 +1,7 @@
{
"name": "@mastodon/mastodon",
"license": "AGPL-3.0-or-later",
"packageManager": "yarn@4.1.1",
"packageManager": "yarn@4.2.1",
"engines": {
"node": ">=18"
},

View File

@ -9,14 +9,25 @@ RSpec.describe User do
it_behaves_like 'two_factor_backupable'
describe 'otp_secret' do
describe 'legacy_otp_secret' do
it 'is encrypted with OTP_SECRET environment variable' do
user = Fabricate(:user,
encrypted_otp_secret: "Fttsy7QAa0edaDfdfSz094rRLAxc8cJweDQ4BsWH/zozcdVA8o9GLqcKhn2b\nGi/V\n",
encrypted_otp_secret_iv: 'rys3THICkr60BoWC',
encrypted_otp_secret_salt: '_LMkAGvdg7a+sDIKjI3mR2Q==')
expect(user.otp_secret).to eq 'anotpsecretthatshouldbeencrypted'
expect(user.send(:legacy_otp_secret)).to eq 'anotpsecretthatshouldbeencrypted'
end
end
describe 'otp_secret' do
it 'encrypts the saved value' do
user = Fabricate(:user, otp_secret: '123123123')
user.reload
expect(user.otp_secret).to eq '123123123'
expect(user.attributes_before_type_cast[:otp_secret]).to_not eq '123123123'
end
end

View File

@ -130,7 +130,7 @@ RSpec.describe 'Domain Blocks' do
it_behaves_like 'forbidden for wrong role', ''
it_behaves_like 'forbidden for wrong role', 'Moderator'
it 'returns expected domain name and severity', :aggregate_failures do
it 'creates a domain block with the expected domain name and severity', :aggregate_failures do
subject
body = body_as_json
@ -146,7 +146,44 @@ RSpec.describe 'Domain Blocks' do
expect(DomainBlock.find_by(domain: 'foo.bar.com')).to be_present
end
context 'when a stricter domain block already exists' do
context 'when a looser domain block already exists on a higher level domain' do
let(:params) { { domain: 'foo.bar.com', severity: :suspend } }
before do
Fabricate(:domain_block, domain: 'bar.com', severity: :silence)
end
it 'creates a domain block with the expected domain name and severity', :aggregate_failures do
subject
body = body_as_json
expect(response).to have_http_status(200)
expect(body).to match a_hash_including(
{
domain: 'foo.bar.com',
severity: 'suspend',
}
)
expect(DomainBlock.find_by(domain: 'foo.bar.com')).to be_present
end
end
context 'when a domain block already exists on the same domain' do
before do
Fabricate(:domain_block, domain: 'foo.bar.com', severity: :silence)
end
it 'returns existing domain block in error', :aggregate_failures do
subject
expect(response).to have_http_status(422)
expect(body_as_json[:existing_domain_block][:domain]).to eq('foo.bar.com')
end
end
context 'when a stricter domain block already exists on a higher level domain' do
before do
Fabricate(:domain_block, domain: 'bar.com', severity: :suspend)
end

View File

@ -4,6 +4,8 @@ require 'rails_helper'
describe StatusLengthValidator do
describe '#validate' do
before { stub_const("#{described_class}::MAX_CHARS", 500) } # Example values below are relative to this baseline
it 'does not add errors onto remote statuses' do
status = instance_double(Status, local?: false)
allow(status).to receive(:errors)
@ -22,32 +24,27 @@ describe StatusLengthValidator do
expect(status).to_not have_received(:errors)
end
it 'adds an error when content warning is over MAX_CHARS characters' do
chars = StatusLengthValidator::MAX_CHARS + 1
status = instance_double(Status, spoiler_text: 'a' * chars, text: '', errors: activemodel_errors, local?: true, reblog?: false)
it 'adds an error when content warning is over character limit' do
status = status_double(spoiler_text: 'a' * 520)
subject.validate(status)
expect(status.errors).to have_received(:add)
end
it 'adds an error when text is over MAX_CHARS characters' do
chars = StatusLengthValidator::MAX_CHARS + 1
status = instance_double(Status, spoiler_text: '', text: 'a' * chars, errors: activemodel_errors, local?: true, reblog?: false)
it 'adds an error when text is over character limit' do
status = status_double(text: 'a' * 520)
subject.validate(status)
expect(status.errors).to have_received(:add)
end
it 'adds an error when text and content warning are over MAX_CHARS characters total' do
chars1 = 20
chars2 = StatusLengthValidator::MAX_CHARS + 1 - chars1
status = instance_double(Status, spoiler_text: 'a' * chars1, text: 'b' * chars2, errors: activemodel_errors, local?: true, reblog?: false)
it 'adds an error when text and content warning are over character limit total' do
status = status_double(spoiler_text: 'a' * 250, text: 'b' * 251)
subject.validate(status)
expect(status.errors).to have_received(:add)
end
it 'counts URLs as 23 characters flat' do
chars = StatusLengthValidator::MAX_CHARS - 1 - 23
text = ('a' * chars) + " http://#{'b' * 30}.com/example"
status = instance_double(Status, spoiler_text: '', text: text, errors: activemodel_errors, local?: true, reblog?: false)
text = ('a' * 476) + " http://#{'b' * 30}.com/example"
status = status_double(text: text)
subject.validate(status)
expect(status.errors).to_not have_received(:add)
@ -55,7 +52,7 @@ describe StatusLengthValidator do
it 'does not count non-autolinkable URLs as 23 characters flat' do
text = ('a' * 476) + "http://#{'b' * 30}.com/example"
status = instance_double(Status, spoiler_text: '', text: text, errors: activemodel_errors, local?: true, reblog?: false)
status = status_double(text: text)
subject.validate(status)
expect(status.errors).to have_received(:add)
@ -63,16 +60,14 @@ describe StatusLengthValidator do
it 'does not count overly long URLs as 23 characters flat' do
text = "http://example.com/valid?#{'#foo?' * 1000}"
status = instance_double(Status, spoiler_text: '', text: text, errors: activemodel_errors, local?: true, reblog?: false)
status = status_double(text: text)
subject.validate(status)
expect(status.errors).to have_received(:add)
end
it 'counts only the front part of remote usernames' do
username = '@alice'
chars = StatusLengthValidator::MAX_CHARS - 1 - username.length
text = ('a' * chars) + " #{username}@#{'b' * 30}.com"
status = instance_double(Status, spoiler_text: '', text: text, errors: activemodel_errors, local?: true, reblog?: false)
text = ('a' * 475) + " @alice@#{'b' * 30}.com"
status = status_double(text: text)
subject.validate(status)
expect(status.errors).to_not have_received(:add)
@ -80,7 +75,7 @@ describe StatusLengthValidator do
it 'does count both parts of remote usernames for overly long domains' do
text = "@alice@#{'b' * 500}.com"
status = instance_double(Status, spoiler_text: '', text: text, errors: activemodel_errors, local?: true, reblog?: false)
status = status_double(text: text)
subject.validate(status)
expect(status.errors).to have_received(:add)
@ -89,6 +84,17 @@ describe StatusLengthValidator do
private
def status_double(spoiler_text: '', text: '')
instance_double(
Status,
spoiler_text: spoiler_text,
text: text,
errors: activemodel_errors,
local?: true,
reblog?: false
)
end
def activemodel_errors
instance_double(ActiveModel::Errors, add: nil)
end

View File

@ -1,7 +1,7 @@
{
"name": "@mastodon/streaming",
"license": "AGPL-3.0-or-later",
"packageManager": "yarn@4.1.1",
"packageManager": "yarn@4.2.1",
"engines": {
"node": ">=18"
},