Merge pull request #578 from ThibG/glitch-soc/merge-upstream

Merge upstream changes
th-downstream
ThibG 6 years ago committed by GitHub
commit 6eee447159

@ -1 +1 @@
6 8

@ -5,6 +5,8 @@ libidn11
libidn11-dev libidn11-dev
libpq-dev libpq-dev
libprotobuf-dev libprotobuf-dev
libssl-dev
libxdamage1 libxdamage1
libxfixes3 libxfixes3
protobuf-compiler protobuf-compiler
zlib1g-dev

@ -1,3 +1,4 @@
FROM node:8.11.3-alpine as node
FROM ruby:2.4.4-alpine3.6 FROM ruby:2.4.4-alpine3.6
LABEL maintainer="https://github.com/tootsuite/mastodon" \ LABEL maintainer="https://github.com/tootsuite/mastodon" \
@ -11,8 +12,6 @@ ENV PATH=/mastodon/bin:$PATH \
RAILS_ENV=production \ RAILS_ENV=production \
NODE_ENV=production NODE_ENV=production
ARG YARN_VERSION=1.3.2
ARG YARN_DOWNLOAD_SHA256=6cfe82e530ef0837212f13e45c1565ba53f5199eec2527b85ecbcd88bf26821d
ARG LIBICONV_VERSION=1.15 ARG LIBICONV_VERSION=1.15
ARG LIBICONV_DOWNLOAD_SHA256=ccf536620a45458d26ba83887a983b96827001e92a13847b45e4925cc8913178 ARG LIBICONV_DOWNLOAD_SHA256=ccf536620a45458d26ba83887a983b96827001e92a13847b45e4925cc8913178
@ -20,6 +19,11 @@ EXPOSE 3000 4000
WORKDIR /mastodon WORKDIR /mastodon
COPY --from=node /usr/local/bin/node /usr/local/bin/node
COPY --from=node /usr/local/lib/node_modules /usr/local/lib/node_modules
COPY --from=node /usr/local/bin/npm /usr/local/bin/npm
COPY --from=node /opt/yarn-* /opt/yarn
RUN apk -U upgrade \ RUN apk -U upgrade \
&& apk add -t build-dependencies \ && apk add -t build-dependencies \
build-base \ build-base \
@ -39,20 +43,13 @@ RUN apk -U upgrade \
imagemagick \ imagemagick \
libidn \ libidn \
libpq \ libpq \
nodejs \
nodejs-npm \
protobuf \ protobuf \
tini \ tini \
tzdata \ tzdata \
&& update-ca-certificates \ && update-ca-certificates \
&& mkdir -p /tmp/src /opt \
&& wget -O yarn.tar.gz "https://github.com/yarnpkg/yarn/releases/download/v$YARN_VERSION/yarn-v$YARN_VERSION.tar.gz" \
&& echo "$YARN_DOWNLOAD_SHA256 *yarn.tar.gz" | sha256sum -c - \
&& tar -xzf yarn.tar.gz -C /tmp/src \
&& rm yarn.tar.gz \
&& mv /tmp/src/yarn-v$YARN_VERSION /opt/yarn \
&& ln -s /opt/yarn/bin/yarn /usr/local/bin/yarn \ && ln -s /opt/yarn/bin/yarn /usr/local/bin/yarn \
&& ln -s /opt/yarn/bin/yarnpkg /usr/local/bin/yarnpkg \ && ln -s /opt/yarn/bin/yarnpkg /usr/local/bin/yarnpkg \
&& mkdir -p /tmp/src /opt \
&& wget -O libiconv.tar.gz "https://ftp.gnu.org/pub/gnu/libiconv/libiconv-$LIBICONV_VERSION.tar.gz" \ && wget -O libiconv.tar.gz "https://ftp.gnu.org/pub/gnu/libiconv/libiconv-$LIBICONV_VERSION.tar.gz" \
&& echo "$LIBICONV_DOWNLOAD_SHA256 *libiconv.tar.gz" | sha256sum -c - \ && echo "$LIBICONV_DOWNLOAD_SHA256 *libiconv.tar.gz" | sha256sum -c - \
&& tar -xzf libiconv.tar.gz -C /tmp/src \ && tar -xzf libiconv.tar.gz -C /tmp/src \
@ -72,7 +69,7 @@ RUN rm /lib/stack-fix.c
RUN bundle config build.nokogiri --with-iconv-lib=/usr/local/lib --with-iconv-include=/usr/local/include \ RUN bundle config build.nokogiri --with-iconv-lib=/usr/local/lib --with-iconv-include=/usr/local/include \
&& bundle install -j$(getconf _NPROCESSORS_ONLN) --deployment --without test development \ && bundle install -j$(getconf _NPROCESSORS_ONLN) --deployment --without test development \
&& yarn --pure-lockfile \ && yarn install --pure-lockfile --ignore-engines \
&& yarn cache clean && yarn cache clean
RUN addgroup -g ${GID} mastodon && adduser -h /mastodon -s /bin/sh -D -G mastodon -u ${UID} mastodon \ RUN addgroup -g ${GID} mastodon && adduser -h /mastodon -s /bin/sh -D -G mastodon -u ${UID} mastodon \
@ -83,9 +80,11 @@ COPY . /mastodon
RUN chown -R mastodon:mastodon /mastodon RUN chown -R mastodon:mastodon /mastodon
VOLUME /mastodon/public/system /mastodon/public/assets /mastodon/public/packs VOLUME /mastodon/public/system
USER mastodon USER mastodon
ENV LD_PRELOAD=/lib/stack-fix.so ENV LD_PRELOAD=/lib/stack-fix.so
RUN OTP_SECRET=precompile_placeholder SECRET_KEY_BASE=precompile_placeholder bundle exec rails assets:precompile
ENTRYPOINT ["/sbin/tini", "--"] ENTRYPOINT ["/sbin/tini", "--"]

@ -0,0 +1,58 @@
# frozen_string_literal: true
module Admin
class RelaysController < BaseController
before_action :set_relay, except: [:index, :new, :create]
def index
authorize :relay, :update?
@relays = Relay.all
end
def new
authorize :relay, :update?
@relay = Relay.new(inbox_url: Relay::PRESET_RELAY)
end
def create
authorize :relay, :update?
@relay = Relay.new(resource_params)
if @relay.save
@relay.enable!
redirect_to admin_relays_path
else
render action: :new
end
end
def destroy
authorize :relay, :update?
@relay.destroy
redirect_to admin_relays_path
end
def enable
authorize :relay, :update?
@relay.enable!
redirect_to admin_relays_path
end
def disable
authorize :relay, :update?
@relay.disable!
redirect_to admin_relays_path
end
private
def set_relay
@relay = Relay.find(params[:id])
end
def resource_params
params.require(:relay).permit(:inbox_url)
end
end
end

@ -67,7 +67,7 @@ module StreamEntriesHelper
end end
def acct(account) def acct(account)
if embedded_view? && account.local? if account.local?
"@#{account.acct}@#{Rails.configuration.x.local_domain}" "@#{account.acct}@#{Rails.configuration.x.local_domain}"
else else
"@#{account.acct}" "@#{account.acct}"

@ -1,6 +1,9 @@
// This file will be loaded on admin pages, regardless of theme. // This file will be loaded on admin pages, regardless of theme.
import { delegate } from 'rails-ujs'; import { delegate } from 'rails-ujs';
import { start } from '../mastodon/common';
start();
function handleDeleteStatus(event) { function handleDeleteStatus(event) {
const [data] = event.detail; const [data] = event.detail;

@ -1,8 +1,5 @@
// This file will be loaded on all pages, regardless of theme. // This file will be loaded on all pages, regardless of theme.
import { start } from 'rails-ujs';
import 'font-awesome/css/font-awesome.css'; import 'font-awesome/css/font-awesome.css';
require.context('../images/', true); require.context('../images/', true);
start();

@ -1,3 +1,7 @@
import { start } from 'rails-ujs';
start();
import 'flavours/glitch/styles/index.scss'; import 'flavours/glitch/styles/index.scss';
// This ensures that webpack compiles our images. // This ensures that webpack compiles our images.

@ -128,7 +128,7 @@ export function expandDomainBlocks() {
return (dispatch, getState) => { return (dispatch, getState) => {
const url = getState().getIn(['domain_lists', 'blocks', 'next']); const url = getState().getIn(['domain_lists', 'blocks', 'next']);
if (url === null) { if (!url) {
return; return;
} }

@ -0,0 +1,8 @@
import Rails from 'rails-ujs';
export function start() {
require('font-awesome/css/font-awesome.css');
require.context('../images/', true);
Rails.start();
};

@ -7,7 +7,7 @@ import { connect } from 'react-redux';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component'; import ImmutablePureComponent from 'react-immutable-pure-component';
import { me, invitesEnabled } from '../../initial_state'; import { me, invitesEnabled, version } from '../../initial_state';
import { fetchFollowRequests } from '../../actions/accounts'; import { fetchFollowRequests } from '../../actions/accounts';
import { List as ImmutableList } from 'immutable'; import { List as ImmutableList } from 'immutable';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
@ -149,7 +149,7 @@ export default class GettingStarted extends ImmutablePureComponent {
<FormattedMessage <FormattedMessage
id='getting_started.open_source_notice' id='getting_started.open_source_notice'
defaultMessage='Mastodon is open source software. You can contribute or report issues on GitHub at {github}.' defaultMessage='Mastodon is open source software. You can contribute or report issues on GitHub at {github}.'
values={{ github: <a href='https://github.com/tootsuite/mastodon' rel='noopener' target='_blank'>tootsuite/mastodon</a> }} values={{ github: <span><a href='https://github.com/tootsuite/mastodon' rel='noopener' target='_blank'>tootsuite/mastodon</a> (v{version})</span> }}
/> />
</p> </p>
</div> </div>

@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classNames from 'classnames'; import classNames from 'classnames';
import { LoadingBar } from 'react-redux-loading-bar';
import ZoomableImage from './zoomable_image'; import ZoomableImage from './zoomable_image';
export default class ImageLoader extends React.PureComponent { export default class ImageLoader extends React.PureComponent {
@ -23,6 +24,7 @@ export default class ImageLoader extends React.PureComponent {
state = { state = {
loading: true, loading: true,
error: false, error: false,
width: null,
} }
removers = []; removers = [];
@ -122,6 +124,7 @@ export default class ImageLoader extends React.PureComponent {
setCanvasRef = c => { setCanvasRef = c => {
this.canvas = c; this.canvas = c;
if (c) this.setState({ width: c.offsetWidth });
} }
render () { render () {
@ -135,6 +138,7 @@ export default class ImageLoader extends React.PureComponent {
return ( return (
<div className={className}> <div className={className}>
<LoadingBar loading={loading ? 1 : 0} className='loading-bar' style={{ width: this.state.width || width }} />
{loading ? ( {loading ? (
<canvas <canvas
className='image-loader__preview-canvas' className='image-loader__preview-canvas'

@ -13,5 +13,6 @@ export const me = getMeta('me');
export const searchEnabled = getMeta('search_enabled'); export const searchEnabled = getMeta('search_enabled');
export const maxChars = getMeta('max_toot_chars') || 500; export const maxChars = getMeta('max_toot_chars') || 500;
export const invitesEnabled = getMeta('invites_enabled'); export const invitesEnabled = getMeta('invites_enabled');
export const version = getMeta('version');
export default initialState; export default initialState;

@ -6,10 +6,10 @@
"account.direct": "Direct message @{name}", "account.direct": "Direct message @{name}",
"account.disclaimer_full": "Information below may reflect the user's profile incompletely.", "account.disclaimer_full": "Information below may reflect the user's profile incompletely.",
"account.domain_blocked": "Domain hidden", "account.domain_blocked": "Domain hidden",
"account.edit_profile": "Edit profile", "account.edit_profile": "Uprav profil",
"account.follow": "Follow", "account.follow": "Sleduj",
"account.followers": "Followers", "account.followers": "Sledovatelé",
"account.follows": "Follows", "account.follows": "Sleduje",
"account.follows_you": "Follows you", "account.follows_you": "Follows you",
"account.hide_reblogs": "Hide boosts from @{name}", "account.hide_reblogs": "Hide boosts from @{name}",
"account.media": "Media", "account.media": "Media",

@ -65,7 +65,7 @@
"compose_form.hashtag_warning": "Αυτό το τουτ δεν θα εμφανίζεται κάτω από κανένα hashtag καθώς είναι αφανές. Μόνο τα δημόσια τουτ μπορούν να αναζητηθούν ανά hashtag.", "compose_form.hashtag_warning": "Αυτό το τουτ δεν θα εμφανίζεται κάτω από κανένα hashtag καθώς είναι αφανές. Μόνο τα δημόσια τουτ μπορούν να αναζητηθούν ανά hashtag.",
"compose_form.lock_disclaimer": "Ο λογαριασμός σου δεν είναι {locked}. Οποιοσδήποτε μπορεί να σε ακολουθήσει για να δει τις δημοσιεύσεις σας προς τους ακολούθους σας.", "compose_form.lock_disclaimer": "Ο λογαριασμός σου δεν είναι {locked}. Οποιοσδήποτε μπορεί να σε ακολουθήσει για να δει τις δημοσιεύσεις σας προς τους ακολούθους σας.",
"compose_form.lock_disclaimer.lock": "κλειδωμένος", "compose_form.lock_disclaimer.lock": "κλειδωμένος",
"compose_form.placeholder": "Τι έχεις στο μυαλό σου;", "compose_form.placeholder": "Τι σκέφτεσαι;",
"compose_form.publish": "Τουτ", "compose_form.publish": "Τουτ",
"compose_form.publish_loud": "{publish}!", "compose_form.publish_loud": "{publish}!",
"compose_form.sensitive.marked": "Το πολυμέσο έχει σημειωθεί ως ευαίσθητο", "compose_form.sensitive.marked": "Το πολυμέσο έχει σημειωθεί ως ευαίσθητο",

@ -166,7 +166,7 @@
"navigation_bar.domain_blocks": "دامین‌های پنهان‌شده", "navigation_bar.domain_blocks": "دامین‌های پنهان‌شده",
"navigation_bar.edit_profile": "ویرایش نمایه", "navigation_bar.edit_profile": "ویرایش نمایه",
"navigation_bar.favourites": "پسندیده‌ها", "navigation_bar.favourites": "پسندیده‌ها",
"navigation_bar.filters": "Muted words", "navigation_bar.filters": "واژگان بی‌صداشده",
"navigation_bar.follow_requests": "درخواست‌های پیگیری", "navigation_bar.follow_requests": "درخواست‌های پیگیری",
"navigation_bar.info": "اطلاعات تکمیلی", "navigation_bar.info": "اطلاعات تکمیلی",
"navigation_bar.keyboard_shortcuts": "میان‌برهای صفحه‌کلید", "navigation_bar.keyboard_shortcuts": "میان‌برهای صفحه‌کلید",

@ -170,7 +170,7 @@
"navigation_bar.domain_blocks": "非表示にしたドメイン", "navigation_bar.domain_blocks": "非表示にしたドメイン",
"navigation_bar.edit_profile": "プロフィールを編集", "navigation_bar.edit_profile": "プロフィールを編集",
"navigation_bar.favourites": "お気に入り", "navigation_bar.favourites": "お気に入り",
"navigation_bar.filters": "Muted words", "navigation_bar.filters": "フィルター設定",
"navigation_bar.follow_requests": "フォローリクエスト", "navigation_bar.follow_requests": "フォローリクエスト",
"navigation_bar.info": "このインスタンスについて", "navigation_bar.info": "このインスタンスについて",
"navigation_bar.keyboard_shortcuts": "ホットキー", "navigation_bar.keyboard_shortcuts": "ホットキー",

@ -166,7 +166,7 @@
"navigation_bar.domain_blocks": "Verborgen domeinen", "navigation_bar.domain_blocks": "Verborgen domeinen",
"navigation_bar.edit_profile": "Profiel bewerken", "navigation_bar.edit_profile": "Profiel bewerken",
"navigation_bar.favourites": "Favorieten", "navigation_bar.favourites": "Favorieten",
"navigation_bar.filters": "Muted words", "navigation_bar.filters": "Genegeerde woorden",
"navigation_bar.follow_requests": "Volgverzoeken", "navigation_bar.follow_requests": "Volgverzoeken",
"navigation_bar.info": "Over deze server", "navigation_bar.info": "Over deze server",
"navigation_bar.keyboard_shortcuts": "Sneltoetsen", "navigation_bar.keyboard_shortcuts": "Sneltoetsen",

@ -166,7 +166,7 @@
"navigation_bar.domain_blocks": "Domenis resconduts", "navigation_bar.domain_blocks": "Domenis resconduts",
"navigation_bar.edit_profile": "Modificar lo perfil", "navigation_bar.edit_profile": "Modificar lo perfil",
"navigation_bar.favourites": "Favorits", "navigation_bar.favourites": "Favorits",
"navigation_bar.filters": "Muted words", "navigation_bar.filters": "Mots ignorats",
"navigation_bar.follow_requests": "Demandas dabonament", "navigation_bar.follow_requests": "Demandas dabonament",
"navigation_bar.info": "Mai informacions", "navigation_bar.info": "Mai informacions",
"navigation_bar.keyboard_shortcuts": "Acorchis clavièr", "navigation_bar.keyboard_shortcuts": "Acorchis clavièr",

@ -166,7 +166,7 @@
"navigation_bar.domain_blocks": "Domínios escondidos", "navigation_bar.domain_blocks": "Domínios escondidos",
"navigation_bar.edit_profile": "Editar perfil", "navigation_bar.edit_profile": "Editar perfil",
"navigation_bar.favourites": "Favoritos", "navigation_bar.favourites": "Favoritos",
"navigation_bar.filters": "Muted words", "navigation_bar.filters": "Palavras silenciadas",
"navigation_bar.follow_requests": "Seguidores pendentes", "navigation_bar.follow_requests": "Seguidores pendentes",
"navigation_bar.info": "Mais informações", "navigation_bar.info": "Mais informações",
"navigation_bar.keyboard_shortcuts": "Atalhos de teclado", "navigation_bar.keyboard_shortcuts": "Atalhos de teclado",

@ -7,7 +7,7 @@
"account.disclaimer_full": "Inofrmácie uvedené nižšie nemusia byť úplným odrazom uživateľovho účtu.", "account.disclaimer_full": "Inofrmácie uvedené nižšie nemusia byť úplným odrazom uživateľovho účtu.",
"account.domain_blocked": "Doména ukrytá", "account.domain_blocked": "Doména ukrytá",
"account.edit_profile": "Upraviť profil", "account.edit_profile": "Upraviť profil",
"account.follow": "Následovať", "account.follow": "Následuj",
"account.followers": "Sledujúci", "account.followers": "Sledujúci",
"account.follows": "Následuje", "account.follows": "Následuje",
"account.follows_you": "Následuje ťa", "account.follows_you": "Následuje ťa",

@ -1,4 +1,7 @@
import loadPolyfills from '../mastodon/load_polyfills'; import loadPolyfills from '../mastodon/load_polyfills';
import { start } from '../mastodon/common';
start();
function loaded() { function loaded() {
const TimelineContainer = require('../mastodon/containers/timeline_container').default; const TimelineContainer = require('../mastodon/containers/timeline_container').default;

@ -1,4 +1,7 @@
import loadPolyfills from '../mastodon/load_polyfills'; import loadPolyfills from '../mastodon/load_polyfills';
import { start } from '../mastodon/common';
start();
loadPolyfills().then(() => { loadPolyfills().then(() => {
require('../mastodon/main').default(); require('../mastodon/main').default();

@ -1,5 +1,8 @@
import loadPolyfills from '../mastodon/load_polyfills'; import loadPolyfills from '../mastodon/load_polyfills';
import ready from '../mastodon/ready'; import ready from '../mastodon/ready';
import { start } from '../mastodon/common';
start();
function main() { function main() {
const IntlRelativeFormat = require('intl-relativeformat').default; const IntlRelativeFormat = require('intl-relativeformat').default;

@ -1,4 +1,7 @@
import loadPolyfills from '../mastodon/load_polyfills'; import loadPolyfills from '../mastodon/load_polyfills';
import { start } from '../mastodon/common';
start();
function loaded() { function loaded() {
const ComposeContainer = require('../mastodon/containers/compose_container').default; const ComposeContainer = require('../mastodon/containers/compose_container').default;

@ -165,6 +165,11 @@
color: $valid-value-color; color: $valid-value-color;
font-weight: 500; font-weight: 500;
} }
.negative-hint {
color: $error-value-color;
font-weight: 500;
}
} }
.simple_form { .simple_form {

@ -1478,6 +1478,7 @@ a.account__display-name {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
flex-direction: column;
.image-loader__preview-canvas { .image-loader__preview-canvas {
max-width: $media-modal-media-max-width; max-width: $media-modal-media-max-width;
@ -1486,8 +1487,8 @@ a.account__display-name {
object-fit: contain; object-fit: contain;
} }
&.image-loader--loading .image-loader__preview-canvas { .loading-bar {
filter: blur(2px); position: relative;
} }
&.image-loader--amorphous .image-loader__preview-canvas { &.image-loader--amorphous .image-loader__preview-canvas {

@ -3,12 +3,16 @@
class LanguageDetector class LanguageDetector
include Singleton include Singleton
CHARACTER_THRESHOLD = 140
def initialize def initialize
@identifier = CLD3::NNetLanguageIdentifier.new(1, 2048) @identifier = CLD3::NNetLanguageIdentifier.new(1, 2048)
end end
def detect(text, account) def detect(text, account)
detect_language_code(text) || default_locale(account) input_text = prepare_text(text)
return if input_text.blank?
detect_language_code(input_text) || default_locale(account)
end end
def language_names def language_names
@ -23,8 +27,13 @@ class LanguageDetector
simplify_text(text).strip simplify_text(text).strip
end end
def unreliable_input?(text)
text.size < CHARACTER_THRESHOLD
end
def detect_language_code(text) def detect_language_code(text)
result = @identifier.find_language(prepare_text(text)) return if unreliable_input?(text)
result = @identifier.find_language(text)
iso6391(result.language.to_s).to_sym if result.reliable? iso6391(result.language.to_s).to_sym if result.reliable?
end end
@ -66,6 +75,6 @@ class LanguageDetector
end end
def default_locale(account) def default_locale(account)
account.user_locale&.to_sym account.user_locale&.to_sym || I18n.default_locale
end end
end end

@ -12,6 +12,8 @@ class PotentialFriendshipTracker
class << self class << self
def record(account_id, target_account_id, action) def record(account_id, target_account_id, action)
return if account_id == target_account_id
key = "interactions:#{account_id}" key = "interactions:#{account_id}"
weight = WEIGHTS[action] weight = WEIGHTS[action]

@ -0,0 +1,74 @@
# frozen_string_literal: true
# == Schema Information
#
# Table name: relays
#
# id :bigint(8) not null, primary key
# inbox_url :string default(""), not null
# enabled :boolean default(FALSE), not null
# follow_activity_id :string
# created_at :datetime not null
# updated_at :datetime not null
#
class Relay < ApplicationRecord
PRESET_RELAY = 'https://relay.joinmastodon.org/inbox'
validates :inbox_url, presence: true, uniqueness: true, url: true, if: :will_save_change_to_inbox_url?
scope :enabled, -> { where(enabled: true) }
before_destroy :ensure_disabled
def enable!
activity_id = ActivityPub::TagManager.instance.generate_uri_for(nil)
payload = Oj.dump(follow_activity(activity_id))
ActivityPub::DeliveryWorker.perform_async(payload, some_local_account.id, inbox_url)
update(enabled: true, follow_activity_id: activity_id)
end
def disable!
activity_id = ActivityPub::TagManager.instance.generate_uri_for(nil)
payload = Oj.dump(unfollow_activity(activity_id))
ActivityPub::DeliveryWorker.perform_async(payload, some_local_account.id, inbox_url)
update(enabled: false, follow_activity_id: nil)
end
private
def follow_activity(activity_id)
{
'@context': ActivityPub::TagManager::CONTEXT,
id: activity_id,
type: 'Follow',
actor: ActivityPub::TagManager.instance.uri_for(some_local_account),
object: ActivityPub::TagManager::COLLECTIONS[:public],
}
end
def unfollow_activity(activity_id)
{
'@context': ActivityPub::TagManager::CONTEXT,
id: activity_id,
type: 'Undo',
actor: ActivityPub::TagManager.instance.uri_for(some_local_account),
object: {
id: follow_activity_id,
type: 'Follow',
actor: ActivityPub::TagManager.instance.uri_for(some_local_account),
object: ActivityPub::TagManager::COLLECTIONS[:public],
},
}
end
def some_local_account
@some_local_account ||= Account.local.find_by(suspended: false)
end
def ensure_disabled
return unless enabled?
disable!
end
end

@ -0,0 +1,7 @@
# frozen_string_literal: true
class RelayPolicy < ApplicationPolicy
def update?
admin?
end
end

@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
class ActivityPub::DeleteActorSerializer < ActiveModel::Serializer class ActivityPub::DeleteActorSerializer < ActiveModel::Serializer
attributes :id, :type, :actor attributes :id, :type, :actor, :to
attribute :virtual_object, key: :object attribute :virtual_object, key: :object
def id def id
@ -19,4 +19,8 @@ class ActivityPub::DeleteActorSerializer < ActiveModel::Serializer
def virtual_object def virtual_object
actor actor
end end
def to
[ActivityPub::TagManager::COLLECTIONS[:public]]
end
end end

@ -17,7 +17,7 @@ class ActivityPub::DeleteSerializer < ActiveModel::Serializer
end end
end end
attributes :id, :type, :actor attributes :id, :type, :actor, :to
has_one :object, serializer: TombstoneSerializer has_one :object, serializer: TombstoneSerializer
@ -32,4 +32,8 @@ class ActivityPub::DeleteSerializer < ActiveModel::Serializer
def actor def actor
ActivityPub::TagManager.instance.uri_for(object.account) ActivityPub::TagManager.instance.uri_for(object.account)
end end
def to
[ActivityPub::TagManager::COLLECTIONS[:public]]
end
end end

@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
class ActivityPub::UndoAnnounceSerializer < ActiveModel::Serializer class ActivityPub::UndoAnnounceSerializer < ActiveModel::Serializer
attributes :id, :type, :actor attributes :id, :type, :actor, :to
has_one :object, serializer: ActivityPub::ActivitySerializer has_one :object, serializer: ActivityPub::ActivitySerializer
@ -16,4 +16,8 @@ class ActivityPub::UndoAnnounceSerializer < ActiveModel::Serializer
def actor def actor
ActivityPub::TagManager.instance.uri_for(object.account) ActivityPub::TagManager.instance.uri_for(object.account)
end end
def to
[ActivityPub::TagManager::COLLECTIONS[:public]]
end
end end

@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
class ActivityPub::UpdateSerializer < ActiveModel::Serializer class ActivityPub::UpdateSerializer < ActiveModel::Serializer
attributes :id, :type, :actor attributes :id, :type, :actor, :to
has_one :object, serializer: ActivityPub::ActorSerializer has_one :object, serializer: ActivityPub::ActorSerializer
@ -16,4 +16,8 @@ class ActivityPub::UpdateSerializer < ActiveModel::Serializer
def actor def actor
ActivityPub::TagManager.instance.uri_for(object) ActivityPub::TagManager.instance.uri_for(object)
end end
def to
[ActivityPub::TagManager::COLLECTIONS[:public]]
end
end end

@ -19,6 +19,7 @@ class InitialStateSerializer < ActiveModel::Serializer
domain: Rails.configuration.x.local_domain, domain: Rails.configuration.x.local_domain,
admin: object.admin&.id&.to_s, admin: object.admin&.id&.to_s,
search_enabled: Chewy.enabled?, search_enabled: Chewy.enabled?,
version: Mastodon::Version.to_s,
invites_enabled: Setting.min_invite_role == 'user', invites_enabled: Setting.min_invite_role == 'user',
} }

@ -90,6 +90,18 @@ class RemoveStatusService < BaseService
ActivityPub::DeliveryWorker.push_bulk(@account.followers.inboxes) do |inbox_url| ActivityPub::DeliveryWorker.push_bulk(@account.followers.inboxes) do |inbox_url|
[signed_activity_json, @account.id, inbox_url] [signed_activity_json, @account.id, inbox_url]
end end
relay! if relayable?
end
def relayable?
@status.public_visibility?
end
def relay!
ActivityPub::DeliveryWorker.push_bulk(Relay.enabled.pluck(:inbox_url)) do |inbox_url|
[signed_activity_json, @account.id, inbox_url]
end
end end
def salmon_xml def salmon_xml

@ -22,7 +22,13 @@ class SuspendAccountService < BaseService
end end
def purge_content! def purge_content!
ActivityPub::RawDistributionWorker.perform_async(delete_actor_json, @account.id) if @account.local? if @account.local?
ActivityPub::RawDistributionWorker.perform_async(delete_actor_json, @account.id)
ActivityPub::DeliveryWorker.push_bulk(Relay.enabled.pluck(:inbox_url)) do |inbox_url|
[delete_actor_json, @account.id, inbox_url]
end
end
@account.statuses.reorder(nil).find_in_batches do |statuses| @account.statuses.reorder(nil).find_in_batches do |statuses|
BatchedRemoveStatusService.new.call(statuses) BatchedRemoveStatusService.new.call(statuses)
@ -59,12 +65,14 @@ class SuspendAccountService < BaseService
end end
def delete_actor_json def delete_actor_json
return @delete_actor_json if defined?(@delete_actor_json)
payload = ActiveModelSerializers::SerializableResource.new( payload = ActiveModelSerializers::SerializableResource.new(
@account, @account,
serializer: ActivityPub::DeleteActorSerializer, serializer: ActivityPub::DeleteActorSerializer,
adapter: ActivityPub::Adapter adapter: ActivityPub::Adapter
).as_json ).as_json
Oj.dump(ActivityPub::LinkedDataSignature.new(payload).sign!(@account)) @delete_actor_json = Oj.dump(ActivityPub::LinkedDataSignature.new(payload).sign!(@account))
end end
end end

@ -0,0 +1,21 @@
%tr
%td
%samp= relay.inbox_url
%td
- if relay.enabled?
%span.positive-hint
= fa_icon('check')
= ' '
= t 'admin.relays.enabled'
- else
%span.negative-hint
= fa_icon('times')
= ' '
= t 'admin.relays.disabled'
%td
- if relay.enabled?
= table_link_to 'power-off', t('admin.relays.disable'), disable_admin_relay_path(relay), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }
- else
= table_link_to 'power-off', t('admin.relays.enable'), enable_admin_relay_path(relay), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }
= table_link_to 'times', t('admin.relays.delete'), admin_relay_path(relay), method: :delete, data: { confirm: t('admin.accounts.are_you_sure') }

@ -0,0 +1,20 @@
- content_for :page_title do
= t('admin.relays.title')
.simple_form
%p.hint= t('admin.relays.description_html')
= link_to @relays.empty? ? t('admin.relays.setup') : t('admin.relays.add_new'), new_admin_relay_path, class: 'block-button'
- unless @relays.empty?
%hr.spacer
.table-wrapper
%table.table
%thead
%tr
%th= t('admin.relays.inbox_url')
%th= t('admin.relays.status')
%th
%tbody
= render @relays

@ -0,0 +1,13 @@
- content_for :page_title do
= t('admin.relays.add_new')
= simple_form_for @relay, url: admin_relays_path do |f|
= render 'shared/error_messages', object: @relay
.field-group
= f.input :inbox_url, as: :string, wrapper: :with_block_label
.actions
= f.button :button, t('admin.relays.save_and_enable'), type: :submit
%p.hint.subtle-hint= t('admin.relays.enable_hint')

@ -14,6 +14,8 @@ class ActivityPub::DistributionWorker
ActivityPub::DeliveryWorker.push_bulk(inboxes) do |inbox_url| ActivityPub::DeliveryWorker.push_bulk(inboxes) do |inbox_url|
[signed_payload, @account.id, inbox_url] [signed_payload, @account.id, inbox_url]
end end
relay! if relayable?
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
true true
end end
@ -24,6 +26,10 @@ class ActivityPub::DistributionWorker
@status.direct_visibility? @status.direct_visibility?
end end
def relayable?
@status.public_visibility?
end
def inboxes def inboxes
@inboxes ||= @account.followers.inboxes @inboxes ||= @account.followers.inboxes
end end
@ -39,4 +45,10 @@ class ActivityPub::DistributionWorker
adapter: ActivityPub::Adapter adapter: ActivityPub::Adapter
).as_json ).as_json
end end
def relay!
ActivityPub::DeliveryWorker.push_bulk(Relay.enabled.pluck(:inbox_url)) do |inbox_url|
[signed_payload, @account.id, inbox_url]
end
end
end end

@ -9,7 +9,11 @@ class ActivityPub::UpdateDistributionWorker
@account = Account.find(account_id) @account = Account.find(account_id)
ActivityPub::DeliveryWorker.push_bulk(inboxes) do |inbox_url| ActivityPub::DeliveryWorker.push_bulk(inboxes) do |inbox_url|
[payload, @account.id, inbox_url] [signed_payload, @account.id, inbox_url]
end
ActivityPub::DeliveryWorker.push_bulk(Relay.enabled.pluck(:inbox_url)) do |inbox_url|
[signed_payload, @account.id, inbox_url]
end end
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
true true
@ -21,6 +25,10 @@ class ActivityPub::UpdateDistributionWorker
@inboxes ||= @account.followers.inboxes @inboxes ||= @account.followers.inboxes
end end
def signed_payload
@signed_payload ||= Oj.dump(ActivityPub::LinkedDataSignature.new(payload).sign!(@account))
end
def payload def payload
@payload ||= ActiveModelSerializers::SerializableResource.new( @payload ||= ActiveModelSerializers::SerializableResource.new(
@account, @account,

@ -1,7 +1,7 @@
--- ---
cs: cs:
about: about:
about_hashtag_html: Toto jsou veřejné příspěvky typu označené jako <strong>#%{hashtag}</strong>. Pokud máte účet kdekoliv na fediverse, můžete s nimi interagovat. about_hashtag_html: Toto jsou veřejné tooty označené jako <strong>#%{hashtag}</strong>. Pokud máte účet kdekoliv na fediverse, můžete s nimi interagovat.
about_mastodon_html: Mastodon je sociální síť založená na otevřených webových protokolech a svobodném, otevřeném softwaru. Je decentrovalizovaná jako e-mail. about_mastodon_html: Mastodon je sociální síť založená na otevřených webových protokolech a svobodném, otevřeném softwaru. Je decentrovalizovaná jako e-mail.
about_this: O této instanci about_this: O této instanci
administered_by: 'Server spravuje:' administered_by: 'Server spravuje:'
@ -18,7 +18,7 @@ cs:
features: features:
humane_approach_body: Mastodon, poučen z chyb jiných sociálních sítí, se snaží bojovat se zneužíváním sociálních sítí vytvářením etických možností. humane_approach_body: Mastodon, poučen z chyb jiných sociálních sítí, se snaží bojovat se zneužíváním sociálních sítí vytvářením etických možností.
humane_approach_title: Lidštější přístup humane_approach_title: Lidštější přístup
not_a_product_title: Jste osoba, ne produkt. not_a_product_title: Jste osoba, ne produkt
generic_description: "%{domain} je jedním serverem v síti" generic_description: "%{domain} je jedním serverem v síti"
learn_more: Zjistit více learn_more: Zjistit více
source_code: Zdrojový kód source_code: Zdrojový kód

@ -10,7 +10,7 @@ da:
contact_missing: Ikke sat contact_missing: Ikke sat
contact_unavailable: Ikke tilgængeligt contact_unavailable: Ikke tilgængeligt
description_headline: Hvad er %{domain}? description_headline: Hvad er %{domain}?
domain_count_after: andre instancer domain_count_after: andre instanser
domain_count_before: Forbundet til domain_count_before: Forbundet til
extended_description_html: | extended_description_html: |
<h3>Et godt sted for regler</h3> <h3>Et godt sted for regler</h3>
@ -27,7 +27,7 @@ da:
generic_description: "%{domain} er en server i netværket" generic_description: "%{domain} er en server i netværket"
hosted_on: Mostodon hostet på %{domain} hosted_on: Mostodon hostet på %{domain}
learn_more: Lær mere learn_more: Lær mere
other_instances: Liste over instancer other_instances: Liste over instanser
source_code: Kildekode source_code: Kildekode
status_count_after: statusser status_count_after: statusser
status_count_before: Som har skrevet status_count_before: Som har skrevet
@ -46,7 +46,7 @@ da:
people_who_follow: Folk der følger %{name} people_who_follow: Folk der følger %{name}
posts: Dyt posts: Dyt
posts_with_replies: Toots og svar posts_with_replies: Toots og svar
remote_follow: Følg fra andre instancer remote_follow: Følg fra andre instanser
reserved_username: Brugernavnet er reserveret reserved_username: Brugernavnet er reserveret
roles: roles:
admin: Administrator admin: Administrator
@ -256,6 +256,10 @@ da:
expired: Udløbet expired: Udløbet
title: Filtre title: Filtre
title: Invitationer title: Invitationer
relays:
setup: Opsæt en videresendelses forbindelse
status: Status
title: Videresendelser
reports: reports:
account: account:
note: notat note: notat
@ -297,7 +301,11 @@ da:
username: Kontakt brugernavn username: Kontakt brugernavn
hero: hero:
title: Billede af helt title: Billede af helt
peers_api_enabled:
title: Udgiv liste over opdagede instanser
registrations: registrations:
closed_message:
title: Besked for lukkede registreringer
deletion: deletion:
desc_html: Tillad alle at slette deres konto desc_html: Tillad alle at slette deres konto
title: Åben konto sletning title: Åben konto sletning
@ -338,6 +346,7 @@ da:
new_report: new_report:
body: "%{reporter} har anmeldt %{target}" body: "%{reporter} har anmeldt %{target}"
body_remote: Nogen fra %{domain} har anmeldt %{target} body_remote: Nogen fra %{domain} har anmeldt %{target}
subject: Ny anmeldelse for %{instance} (#%{id})
application_mailer: application_mailer:
notification_preferences: Ændre email indstillinger notification_preferences: Ændre email indstillinger
salutation: "%{name}," salutation: "%{name},"
@ -359,6 +368,9 @@ da:
migrate_account: Flyt til en anden konto migrate_account: Flyt til en anden konto
or: eller or: eller
or_log_in_with: Eller log in med or_log_in_with: Eller log in med
providers:
cas: CAS
saml: SAML
register: Opret dig register: Opret dig
register_elsewhere: Opret dig på en anden server register_elsewhere: Opret dig på en anden server
reset_password: Nulstil kodeord reset_password: Nulstil kodeord
@ -378,8 +390,15 @@ da:
distance_in_words: distance_in_words:
about_x_hours: "%{count}t" about_x_hours: "%{count}t"
about_x_months: "%{count} måneder" about_x_months: "%{count} måneder"
about_x_years: "%{count}år"
almost_x_years: "%{count}år"
half_a_minute: Lige nu half_a_minute: Lige nu
less_than_x_minutes: "%{count}m"
less_than_x_seconds: Lige nu less_than_x_seconds: Lige nu
over_x_years: "%{count}år"
x_days: "%{count}d"
x_minutes: "%{count}m"
x_months: "%{count}md"
x_seconds: "%{count}s" x_seconds: "%{count}s"
deletes: deletes:
bad_password_msg: Godt forsøg, hackere! Forkert kodeord bad_password_msg: Godt forsøg, hackere! Forkert kodeord
@ -401,6 +420,7 @@ da:
download: Hent dit arkiv download: Hent dit arkiv
size: Størrelse size: Størrelse
blocks: Du blokerer blocks: Du blokerer
csv: CSV
follows: Du følger follows: Du følger
mutes: Du dæmper mutes: Du dæmper
filters: filters:
@ -445,9 +465,13 @@ da:
expires_in_prompt: Aldrig expires_in_prompt: Aldrig
generate: Generer generate: Generer
invited_by: 'Du er blevet inviteret af:' invited_by: 'Du er blevet inviteret af:'
max_uses:
one: 1 benyttelse
other: "%{count} benyttelser"
max_uses_prompt: Ubegrænset max_uses_prompt: Ubegrænset
table: table:
expires_at: Udløber expires_at: Udløber
uses: Benyttelser
title: Inviter folk title: Inviter folk
media_attachments: media_attachments:
validations: validations:

@ -133,7 +133,7 @@ ja:
write:blocks: ユーザーのブロックやドメインの非表示 write:blocks: ユーザーのブロックやドメインの非表示
write:favourites: トゥートのお気に入り登録 write:favourites: トゥートのお気に入り登録
write:filters: フィルターの変更 write:filters: フィルターの変更
write:follows: フォローの変更 write:follows: あなたの代わりにフォロー、アンフォロー
write:lists: リストの変更 write:lists: リストの変更
write:media: メディアのアップロード write:media: メディアのアップロード
write:mutes: アカウントや会話のミュート write:mutes: アカウントや会話のミュート

@ -114,7 +114,29 @@ pt-BR:
application: application:
title: Autorização OAuth obrigatória title: Autorização OAuth obrigatória
scopes: scopes:
follow: seguir, bloquear, desbloquear e deixar de seguir outras contas follow: modificar as relações com outras contas
push: receber notificações push na sua conta push: receber suas notificações push
read: ler os dados da sua conta read: ler todos os dados da sua conta
write: postar em seu nome read:accounts: ver as informações da conta
read:blocks: ver seus bloqueios
read:favourites: ver seus favoritos
read:filters: ver seus filtros
read:follows: ver quem você segue
read:lists: ver suas listas
read:mutes: ver seus usuários silenciados
read:notifications: ver suas notificações
read:reports: ver suas denúncias
read:search: buscar em seu nome
read:statuses: ver todos os status
write: modificar todos os dados da sua conta
write:accounts: modificar seu perfil
write:blocks: bloquear contas e domínios
write:favourites: status favoritos
write:filters: criar filtros
write:follows: seguir pessoas
write:lists: criar listas
write:media: enviar arquivos de mídia
write:mutes: silenciar pessoas e conversas
write:notifications: limpar suas notificações
write:reports: reportar outras pessoas
write:statuses: publicar status

@ -261,6 +261,14 @@ el:
expired: Ληγμένες expired: Ληγμένες
title: Φίλτρο title: Φίλτρο
title: Προσκλήσεις title: Προσκλήσεις
relays:
add_new: Πρόσθεσε νέο ανταποκριτή (relay)
description_html: Ο <strong>ομοσπονδιακός ανταποκριτής</strong> είναι ένας ενδιάμεσος εξυπηρετητής (server) που ανταλλάσσει μεγάλους όγκους δημόσιων τουτ μεταξύ εξυπηρετητών που εγγράφονται και δημοσιεύουν σε αυτόν. <strong>Βοηθάει μικρούς και μεσαίους εξυπηρετητές να ανακαλύψουν περιεχόμενο στο fediverse</strong>, που υπό άλλες συνθήκες θα χρειαζόταν κάποιους τοπικούς χρήστες που να ακολουθούν χρήστες σε απομακρυσμένους εξυπηρετητές.
enable_hint: Μόλις ενεργοποιηθεί, ο εξυπηρετητής (server) σου θα εγγραφεί σε όλα τα δημόσια τουτ αυτού του ανταποκριτή (relay) και θα αρχίσει να προωθεί τα δικά του δημόσια τουτ σε αυτόν.
inbox_url: URL ανταποκριτή
setup: Όρισε μια σύνδεση ανταπόκρισης
status: Κατάσταση
title: Ανταποκριτές
report_notes: report_notes:
created_msg: Επιτυχής δημιουργία σημείωσης καταγγελίας! created_msg: Επιτυχής δημιουργία σημείωσης καταγγελίας!
destroyed_msg: Επιτυχής διαγραφή σημείωσης καταγγελίας! destroyed_msg: Επιτυχής διαγραφή σημείωσης καταγγελίας!
@ -316,6 +324,9 @@ el:
peers_api_enabled: peers_api_enabled:
desc_html: Ονόματα τομέων που αυτός ο κόμβος έχει ήδη συναντήσει στο fediverse desc_html: Ονόματα τομέων που αυτός ο κόμβος έχει ήδη συναντήσει στο fediverse
title: Δημοσίευση λίστας κόμβων που έχουν ανακαλυφθεί title: Δημοσίευση λίστας κόμβων που έχουν ανακαλυφθεί
preview_sensitive_media:
desc_html: Οι προεπισκοπήσεις συνδέσμων σε τρίτους ιστότοπους θα είναι ορατές ακόμα κι όταν το πολυμέσο έχει σημειωθεί ως ευαίσθητο
title: Εμφάνιση ευαίσθητων πολυμέσων στις προεπισκοπήσεις OpenGraph
registrations: registrations:
closed_message: closed_message:
desc_html: Εμφανίζεται στην εισαγωγική σελίδα όταν οι εγγραφές είναι κλειστές. Μπορείς να χρησιμοποιήσεις HTML tags desc_html: Εμφανίζεται στην εισαγωγική σελίδα όταν οι εγγραφές είναι κλειστές. Μπορείς να χρησιμοποιήσεις HTML tags

@ -261,6 +261,14 @@ en:
expired: Expired expired: Expired
title: Filter title: Filter
title: Invites title: Invites
relays:
add_new: Add new relay
description_html: A <strong>federation relay</strong> is an intermediary server that exchanges large volumes of public toots between servers that subscribe and publish to it. <strong>It can help small and medium servers discover content from the fediverse</strong>, which would otherwise require local users manually following other people on remote servers.
enable_hint: Once enabled, your server will subscribe to all public toots from this relay, and will begin sending this server's public toots to it.
inbox_url: Relay URL
setup: Setup a relay connection
status: Status
title: Relays
report_notes: report_notes:
created_msg: Report note successfully created! created_msg: Report note successfully created!
destroyed_msg: Report note successfully deleted! destroyed_msg: Report note successfully deleted!

@ -261,6 +261,14 @@ gl:
expired: Cadudado expired: Cadudado
title: Filtro title: Filtro
title: Convida title: Convida
relays:
add_new: Engadir un novo repetidor
description_html: Un <strong>repetidor da federación</strong> é un servidor intermedio que intercambia grandes volumes de toots públicos entre servidores que se suscriban e publiquen nel. <strong>Pode axudar a servidores pequenos e medios a descubrir contido no fediverso</strong>, o que de outro xeito precisaría que as usuarias locais seguisen a outra xente en servidores remotos.
enable_hint: Unha vez activado, o seu servidor suscribirase a todos os toots públicos de este servidor, e tamén comezará a eviar a el os toots públicos do servidor.
inbox_url: URL do repetidor
setup: Configurar a conexión ao repetidor
status: Estado
title: Repetidores
report_notes: report_notes:
created_msg: Creouse correctamente a nota do informe! created_msg: Creouse correctamente a nota do informe!
destroyed_msg: Nota do informe eliminouse con éxito! destroyed_msg: Nota do informe eliminouse con éxito!

@ -261,6 +261,11 @@ ja:
expired: 期限切れ expired: 期限切れ
title: フィルター title: フィルター
title: 招待 title: 招待
relays:
add_new: リレーを追加
inbox_url: Relay URL
status: ステータス
title: リレー
report_notes: report_notes:
created_msg: レポートメモを書き込みました! created_msg: レポートメモを書き込みました!
destroyed_msg: レポートメモを削除しました! destroyed_msg: レポートメモを削除しました!
@ -706,7 +711,7 @@ ja:
disallowed_hashtags: disallowed_hashtags:
one: '許可されていないハッシュタグが含まれています: %{tags}' one: '許可されていないハッシュタグが含まれています: %{tags}'
other: '許可されていないハッシュタグが含まれています: %{tags}' other: '許可されていないハッシュタグが含まれています: %{tags}'
language_detection: 自動的に言語を検出する language_detection: 自動検出
open_in_web: Webで開く open_in_web: Webで開く
over_character_limit: 上限は %{max}文字までです over_character_limit: 上限は %{max}文字までです
pin_errors: pin_errors:

@ -261,6 +261,14 @@ nl:
expired: Verlopen expired: Verlopen
title: Filter title: Filter
title: Uitnodigingen title: Uitnodigingen
relays:
add_new: Nieuwe relayserver toevoegen
description_html: Een <strong>federatie-relay</strong> is een tussenliggende server die grote hoeveelheden openbare toots uitwisselt tussen servers die zich hierop hebben geabonneerd. <strong>Het kan kleine en middelgrote servers helpen om content uit de fediverse te ontdekken</strong>, waarvoor anders lokale gebruikers handmatig mensen van externe servers moeten volgen.
enable_hint: Eenmaal ingeschakeld gaat jouw server zich op alle openbare toots van deze relayserver abonneren en stuurt het de openbare toots van jouw server naar de relayserver.
inbox_url: Relay-URL
setup: Een verbinding met een relayserver maken
status: Status
title: Relayservers
report_notes: report_notes:
created_msg: Opmerking bij gerapporteerde toot succesvol aangemaakt! created_msg: Opmerking bij gerapporteerde toot succesvol aangemaakt!
destroyed_msg: Opmerking bij gerapporteerde toot succesvol verwijderd! destroyed_msg: Opmerking bij gerapporteerde toot succesvol verwijderd!
@ -492,7 +500,7 @@ nl:
delete: Verwijderen delete: Verwijderen
title: Filters title: Filters
new: new:
title: Nieuwe filter toevoegen title: Nieuw filter toevoegen
followers: followers:
domain: Domein domain: Domein
explanation_html: Wanneer je de privacy van jouw toots wilt garanderen, moet je goed weten wie jouw volgers zijn. <strong>Toots die alleen aan jouw volgers zijn gericht, worden aan de Mastodonservers van jouw volgers afgeleverd.</strong> Daarom wil je ze misschien controleren en desnoods volgers verwijderen die zich op een Mastodonserver bevinden die jij niet vertrouwd. Bijvoorbeeld omdat de beheerder(s) of de software van zo'n server jouw privacy niet respecteert. explanation_html: Wanneer je de privacy van jouw toots wilt garanderen, moet je goed weten wie jouw volgers zijn. <strong>Toots die alleen aan jouw volgers zijn gericht, worden aan de Mastodonservers van jouw volgers afgeleverd.</strong> Daarom wil je ze misschien controleren en desnoods volgers verwijderen die zich op een Mastodonserver bevinden die jij niet vertrouwd. Bijvoorbeeld omdat de beheerder(s) of de software van zo'n server jouw privacy niet respecteert.

@ -25,6 +25,7 @@ da:
setting_hide_network: Hvem du følger og hvem der følger dig vil ikke blive vist på din profil setting_hide_network: Hvem du følger og hvem der følger dig vil ikke blive vist på din profil
setting_noindex: Påvirker din offentlige profil og status sider setting_noindex: Påvirker din offentlige profil og status sider
setting_theme: Påvirker hvordan Mastodon ser ud nåt du er logget ind via en hvilken som helst enhed. setting_theme: Påvirker hvordan Mastodon ser ud nåt du er logget ind via en hvilken som helst enhed.
whole_word: Når nøgle ordet eller udtrykket kun er alfabetisk, vil det kun blive brugt hvis det passer hele ordet
imports: imports:
data: CSV fil eksporteret fra en anden Mastodon instans data: CSV fil eksporteret fra en anden Mastodon instans
sessions: sessions:
@ -77,6 +78,7 @@ da:
type: Importtype type: Importtype
username: Brugernavn username: Brugernavn
username_or_email: Brugernavn eller Email username_or_email: Brugernavn eller Email
whole_word: Helt ord
interactions: interactions:
must_be_follower: Bloker notifikationer fra folk der ikke følger dig must_be_follower: Bloker notifikationer fra folk der ikke følger dig
must_be_following: Bloker notifikationer fra folk du ikke følger must_be_following: Bloker notifikationer fra folk du ikke følger

@ -48,7 +48,7 @@ de:
data: Daten data: Daten
display_name: Anzeigename display_name: Anzeigename
email: E-Mail-Adresse email: E-Mail-Adresse
expires_in: Gültig bis expires_in: Läuft ab
fields: Profil-Metadaten fields: Profil-Metadaten
header: Kopfbild header: Kopfbild
irreversible: Fallen lassen anstatt es zu verstecken irreversible: Fallen lassen anstatt es zu verstecken

@ -13,6 +13,7 @@ el:
other: απομένουν <span class="name-counter">%{count}</span> χαρακτήρες other: απομένουν <span class="name-counter">%{count}</span> χαρακτήρες
fields: Μπορείς να έχεις έως 4 σημειώσεις σε μορφή πίνακα στο προφίλ σου fields: Μπορείς να έχεις έως 4 σημειώσεις σε μορφή πίνακα στο προφίλ σου
header: PNG, GIF ή JPG. Έως 2MB. Θα μειωθεί σε διάσταση 700x335px header: PNG, GIF ή JPG. Έως 2MB. Θα μειωθεί σε διάσταση 700x335px
inbox_url: Αντέγραψε το URL της αρχικής σελίδας του ανταποκριτή (relay) που θέλεις να χρησιμοποιήσεις
irreversible: Τα φιλτραρισμένα τουτ θα εξαφανιστούν αμετάκλητα, ακόμα και αν το φίλτρο αργότερα αφαιρεθεί irreversible: Τα φιλτραρισμένα τουτ θα εξαφανιστούν αμετάκλητα, ακόμα και αν το φίλτρο αργότερα αφαιρεθεί
locale: Η γλώσσα του περιβάλλοντος χρήσης, των email και των ειδοποιήσεων ώθησης locale: Η γλώσσα του περιβάλλοντος χρήσης, των email και των ειδοποιήσεων ώθησης
locked: Απαιτεί να εγκρίνεις χειροκίνητα τους ακόλουθούς σου locked: Απαιτεί να εγκρίνεις χειροκίνητα τους ακόλουθούς σου
@ -25,6 +26,7 @@ el:
setting_hide_network: Το ποιους ακολουθείς και το ποιοι σε ακολουθούν δε θα φαίνεται στο προφίλ σου setting_hide_network: Το ποιους ακολουθείς και το ποιοι σε ακολουθούν δε θα φαίνεται στο προφίλ σου
setting_noindex: Επηρεάζει το δημόσιο προφίλ και τις δημοσιεύσεις σου setting_noindex: Επηρεάζει το δημόσιο προφίλ και τις δημοσιεύσεις σου
setting_theme: Επηρεάζει την εμφάνιση του Mastodon όταν συνδέεται από οποιαδήποτε συσκευή. setting_theme: Επηρεάζει την εμφάνιση του Mastodon όταν συνδέεται από οποιαδήποτε συσκευή.
whole_word: Όταν η λέξη ή η φράση κλειδί είναι μόνο αλφαριθμητική, θα εφαρμοστεί μόνο αν ταιριάζει με ολόκληρη τη λέξη
imports: imports:
data: Αρχείο CSV που έχει εξαχθεί από διαφορετικό κόμβο Mastodon data: Αρχείο CSV που έχει εξαχθεί από διαφορετικό κόμβο Mastodon
sessions: sessions:
@ -51,6 +53,7 @@ el:
expires_in: Λήξη μετά από expires_in: Λήξη μετά από
fields: Μετεδεδομένα προφίλ fields: Μετεδεδομένα προφίλ
header: Επικεφαλίδα header: Επικεφαλίδα
inbox_url: Το URL του inbox του ανταποκριτή (relay)
irreversible: Απόρριψη αντί για κρύψιμο irreversible: Απόρριψη αντί για κρύψιμο
locale: Γλώσσα περιβάλλοντος locale: Γλώσσα περιβάλλοντος
locked: Κλείδωμα λογαριασμού locked: Κλείδωμα λογαριασμού
@ -77,6 +80,7 @@ el:
type: Τύπος εισαγωγής type: Τύπος εισαγωγής
username: Όνομα χρηστη username: Όνομα χρηστη
username_or_email: Όνομα ή διεύθυνση email χρήστη username_or_email: Όνομα ή διεύθυνση email χρήστη
whole_word: Ολόκληρη λέξη
interactions: interactions:
must_be_follower: Μπλόκαρε τις ειδοποιήσεις από όσους δεν ακολουθείς must_be_follower: Μπλόκαρε τις ειδοποιήσεις από όσους δεν ακολουθείς
must_be_following: Μπλόκαρε τις ειδοποιήσεις που προέρχονται από άτομα που δεν τα ακολουθείς must_be_following: Μπλόκαρε τις ειδοποιήσεις που προέρχονται από άτομα που δεν τα ακολουθείς

@ -13,6 +13,7 @@ en:
other: <span class="name-counter">%{count}</span> characters left other: <span class="name-counter">%{count}</span> characters left
fields: You can have up to 4 items displayed as a table on your profile fields: You can have up to 4 items displayed as a table on your profile
header: PNG, GIF or JPG. At most 2MB. Will be downscaled to 700x335px header: PNG, GIF or JPG. At most 2MB. Will be downscaled to 700x335px
inbox_url: Copy the URL from the frontpage of the relay you want to use
irreversible: Filtered toots will disappear irreversibly, even if filter is later removed irreversible: Filtered toots will disappear irreversibly, even if filter is later removed
locale: The language of the user interface, e-mails and push notifications locale: The language of the user interface, e-mails and push notifications
locked: Requires you to manually approve followers locked: Requires you to manually approve followers
@ -52,6 +53,7 @@ en:
expires_in: Expire after expires_in: Expire after
fields: Profile metadata fields: Profile metadata
header: Header header: Header
inbox_url: URL of the relay inbox
irreversible: Drop instead of hide irreversible: Drop instead of hide
locale: Interface language locale: Interface language
locked: Lock account locked: Lock account

@ -13,6 +13,7 @@ fa:
other: <span class="name-counter">%{count}</span> حرف باقی مانده other: <span class="name-counter">%{count}</span> حرف باقی مانده
fields: شما می‌توانید تا چهار مورد را در یک جدول در نمایهٔ خود نمایش دهید fields: شما می‌توانید تا چهار مورد را در یک جدول در نمایهٔ خود نمایش دهید
header: یکی از قالب‌های PNG یا GIF یا JPG. بیشترین اندازه ۲ مگابایت. تصویر به اندازهٔ ۳۳۵×۷۰۰ پیکسل تبدیل خواهد شد header: یکی از قالب‌های PNG یا GIF یا JPG. بیشترین اندازه ۲ مگابایت. تصویر به اندازهٔ ۳۳۵×۷۰۰ پیکسل تبدیل خواهد شد
inbox_url: نشانی صفحهٔ اصلی رله‌ای را که می‌خواهید به کار ببرید کپی کنید
irreversible: بوق‌های فیلترشده به طور برگشت‌ناپذیری ناپدید می‌شوند، حتی اگر فیلتر را بعداً بردارید irreversible: بوق‌های فیلترشده به طور برگشت‌ناپذیری ناپدید می‌شوند، حتی اگر فیلتر را بعداً بردارید
locale: زبان محیط کاربری، ایمیل‌ها، و اعلان‌ها locale: زبان محیط کاربری، ایمیل‌ها، و اعلان‌ها
locked: باید پیگیران تازه را خودتان تأیید کنید locked: باید پیگیران تازه را خودتان تأیید کنید
@ -20,10 +21,12 @@ fa:
one: <span class="note-counter">1</span> حرف باقی مانده one: <span class="note-counter">1</span> حرف باقی مانده
other: <span class="note-counter">%{count}</span> حرف باقی مانده other: <span class="note-counter">%{count}</span> حرف باقی مانده
phrase: مستقل از کوچکی و بزرگی حروف، با متن اصلی یا هشدار محتوای بوق‌ها مقایسه می‌شود phrase: مستقل از کوچکی و بزرگی حروف، با متن اصلی یا هشدار محتوای بوق‌ها مقایسه می‌شود
scopes: واسط‌های برنامه‌نویسی که این برنامه به آن دسترسی دارد. اگر بالاترین سطح دسترسی را انتخاب کنید، دیگر نیازی به انتخاب سطح‌های پایینی ندارید.
setting_default_language: زبان نوشته‌های شما به طور خودکار تشخیص داده می‌شود، ولی این تشخصی همیشه دقیق نیست setting_default_language: زبان نوشته‌های شما به طور خودکار تشخیص داده می‌شود، ولی این تشخصی همیشه دقیق نیست
setting_hide_network: فهرست پیگیران شما و فهرست کسانی که شما پی می‌گیرید روی نمایهٔ شما دیده نخواهد شد setting_hide_network: فهرست پیگیران شما و فهرست کسانی که شما پی می‌گیرید روی نمایهٔ شما دیده نخواهد شد
setting_noindex: روی نمایهٔ عمومی و صفحهٔ نوشته‌های شما تأثیر می‌گذارد setting_noindex: روی نمایهٔ عمومی و صفحهٔ نوشته‌های شما تأثیر می‌گذارد
setting_theme: ظاهر ماستدون را وقتی که از هر دستگاهی به آن وارد می‌شوید تعیین می‌کند. setting_theme: ظاهر ماستدون را وقتی که از هر دستگاهی به آن وارد می‌شوید تعیین می‌کند.
whole_word: اگر کلیدواژه فقط دارای حروف و اعداد باشد، تنها وقتی پیدا می‌شود که با کل یک واژه در متن منطبق باشد، نه با بخشی از یک واژه
imports: imports:
data: پروندهٔ CSV که از سرور ماستدون دیگری برون‌سپاری شده data: پروندهٔ CSV که از سرور ماستدون دیگری برون‌سپاری شده
sessions: sessions:
@ -50,6 +53,7 @@ fa:
expires_in: تاریخ انقضا expires_in: تاریخ انقضا
fields: اطلاعات تکمیلی نمایه fields: اطلاعات تکمیلی نمایه
header: تصویر زمینه header: تصویر زمینه
inbox_url: نشانی صندوق ورودی رله
irreversible: به جای پنهان‌سازی، حذف کن irreversible: به جای پنهان‌سازی، حذف کن
locale: زبان محیط کاربری locale: زبان محیط کاربری
locked: خصوصی‌کردن حساب locked: خصوصی‌کردن حساب
@ -76,6 +80,7 @@ fa:
type: نوع درون‌ریزی type: نوع درون‌ریزی
username: نام کاربری (تنها حروف انگلیسی) username: نام کاربری (تنها حروف انگلیسی)
username_or_email: نام کاربری یا ایمیل username_or_email: نام کاربری یا ایمیل
whole_word: تطابق واژهٔ کامل
interactions: interactions:
must_be_follower: مسدودکردن اعلان‌های همه به جز پیگیران must_be_follower: مسدودکردن اعلان‌های همه به جز پیگیران
must_be_following: مسدودکردن اعلان‌های کسانی که شما پی نمی‌گیرید must_be_following: مسدودکردن اعلان‌های کسانی که شما پی نمی‌گیرید

@ -13,6 +13,7 @@ gl:
other: <span class="name-counter">%{count}</span> caracteres restantes other: <span class="name-counter">%{count}</span> caracteres restantes
fields: Pode ter ate 4 elementos no seu perfil mostrados como unha táboa fields: Pode ter ate 4 elementos no seu perfil mostrados como unha táboa
header: PNG, GIF ou JPG. Máximo 2MB. Será reducida a 700x335px header: PNG, GIF ou JPG. Máximo 2MB. Será reducida a 700x335px
inbox_url: Copiar o URL desde a páxina de inicio do repetidor que quere utilizar
irreversible: Os toots filtrados desaparecerán de xeito irreversible, incluso si despois se elimina o filtro irreversible: Os toots filtrados desaparecerán de xeito irreversible, incluso si despois se elimina o filtro
locale: O idioma da interface de usuaria, correos e notificacións locale: O idioma da interface de usuaria, correos e notificacións
locked: Require que vostede acepte as seguidoras de xeito manual locked: Require que vostede acepte as seguidoras de xeito manual
@ -25,6 +26,7 @@ gl:
setting_hide_network: Non se mostrará no seu perfil quen a segue e quen a está a seguir setting_hide_network: Non se mostrará no seu perfil quen a segue e quen a está a seguir
setting_noindex: Afecta ao seu perfil público e páxinas de estado setting_noindex: Afecta ao seu perfil público e páxinas de estado
setting_theme: Afecta ao aspecto de Mastodon en calquer dispositivo cando está conectada. setting_theme: Afecta ao aspecto de Mastodon en calquer dispositivo cando está conectada.
whole_word: Si a chave ou frase de paso é só alfanumérica, só se aplicará si concorda a palabra completa
imports: imports:
data: Ficheiro CSV exportado desde outra instancia Mastodon data: Ficheiro CSV exportado desde outra instancia Mastodon
sessions: sessions:
@ -51,6 +53,7 @@ gl:
expires_in: Caducidade despois de expires_in: Caducidade despois de
fields: Metadatos do perfil fields: Metadatos do perfil
header: Cabeceira header: Cabeceira
inbox_url: URL da caixa de entrada do repetidor
irreversible: Soltar en lugar de agochar irreversible: Soltar en lugar de agochar
locale: Idioma da interface locale: Idioma da interface
locked: Protexer conta locked: Protexer conta
@ -77,6 +80,7 @@ gl:
type: Tipo de importación type: Tipo de importación
username: Nome de usuaria username: Nome de usuaria
username_or_email: Nome de usuaria ou Correo-e username_or_email: Nome de usuaria ou Correo-e
whole_word: Palabra completa
interactions: interactions:
must_be_follower: Bloquear as notificacións de non-seguidoras must_be_follower: Bloquear as notificacións de non-seguidoras
must_be_following: Bloquea as notificacións de personas que non segue must_be_following: Bloquea as notificacións de personas que non segue

@ -40,7 +40,7 @@ ja:
chosen_languages: 表示する言語 chosen_languages: 表示する言語
confirm_new_password: 新しいパスワード(確認用) confirm_new_password: 新しいパスワード(確認用)
confirm_password: パスワード(確認用) confirm_password: パスワード(確認用)
context: フィルター対象 context: 除外対象
current_password: 現在のパスワード current_password: 現在のパスワード
data: データ data: データ
display_name: 表示名 display_name: 表示名
@ -48,6 +48,7 @@ ja:
expires_in: 有効期限 expires_in: 有効期限
fields: プロフィール補足情報 fields: プロフィール補足情報
header: ヘッダー header: ヘッダー
inbox_url: URL of the relay inbox
irreversible: 隠すのではなく除外する irreversible: 隠すのではなく除外する
locale: 言語 locale: 言語
locked: 承認制アカウントにする locked: 承認制アカウントにする
@ -56,7 +57,7 @@ ja:
note: プロフィール note: プロフィール
otp_attempt: 二段階認証コード otp_attempt: 二段階認証コード
password: パスワード password: パスワード
phrase: 単語または語句 phrase: キーワードまたはフレーズ
setting_auto_play_gif: アニメーションGIFを自動再生する setting_auto_play_gif: アニメーションGIFを自動再生する
setting_boost_modal: ブーストする前に確認ダイアログを表示する setting_boost_modal: ブーストする前に確認ダイアログを表示する
setting_default_language: 投稿する言語 setting_default_language: 投稿する言語

@ -20,10 +20,12 @@ ko:
one: <span class="note-counter">1</span> 글자 남음 one: <span class="note-counter">1</span> 글자 남음
other: <span class="note-counter">%{count}</span> 글자 남음 other: <span class="note-counter">%{count}</span> 글자 남음
phrase: 툿 내용이나 CW 내용 안에서 대소문자 구분 없이 매칭 됩니다 phrase: 툿 내용이나 CW 내용 안에서 대소문자 구분 없이 매칭 됩니다
scopes: 애플리케이션에 허용할 API들입니다. 최상위 스코프를 선택하면 개별적인 것은 선택하지 않아도 됩니다.
setting_default_language: 작성한 툿의 언어는 자동으로 인식할 수 있지만, 언제나 정확한 건 아닙니다 setting_default_language: 작성한 툿의 언어는 자동으로 인식할 수 있지만, 언제나 정확한 건 아닙니다
setting_hide_network: 나를 팔로우 하는 사람들과 내가 팔로우 하는 사람들이 내 프로필에 표시되지 않게 합니다 setting_hide_network: 나를 팔로우 하는 사람들과 내가 팔로우 하는 사람들이 내 프로필에 표시되지 않게 합니다
setting_noindex: 공개 프로필 및 각 툿페이지에 영향을 미칩니다 setting_noindex: 공개 프로필 및 각 툿페이지에 영향을 미칩니다
setting_theme: 로그인중인 모든 디바이스에 적용되는 디자인입니다. setting_theme: 로그인중인 모든 디바이스에 적용되는 디자인입니다.
whole_word: 키워드가 영문과 숫자로만 이루어 진 경우, 단어 전체에 매칭 되었을 때에만 작동하게 합니다
imports: imports:
data: 다른 마스토돈 인스턴스에서 추출된 CSV 파일 data: 다른 마스토돈 인스턴스에서 추출된 CSV 파일
sessions: sessions:
@ -76,6 +78,7 @@ ko:
type: 불러오기 종류 type: 불러오기 종류
username: 유저 이름 username: 유저 이름
username_or_email: 유저네임 또는 이메일 username_or_email: 유저네임 또는 이메일
whole_word: 단어 전체에 매칭
interactions: interactions:
must_be_follower: 나를 팔로우 하지 않는 사람에게서 온 알림을 차단 must_be_follower: 나를 팔로우 하지 않는 사람에게서 온 알림을 차단
must_be_following: 내가 팔로우 하지 않는 사람에게서 온 알림을 차단 must_be_following: 내가 팔로우 하지 않는 사람에게서 온 알림을 차단

@ -13,6 +13,7 @@ nl:
other: <span class="name-counter">%{count}</span> tekens over other: <span class="name-counter">%{count}</span> tekens over
fields: Je kan maximaal 4 items als een tabel op je profiel weergeven fields: Je kan maximaal 4 items als een tabel op je profiel weergeven
header: PNG, GIF of JPG. Maximaal 2MB. Wordt teruggeschaald naar 700x335px header: PNG, GIF of JPG. Maximaal 2MB. Wordt teruggeschaald naar 700x335px
inbox_url: Kopieer de URL van de voorpagina van de relayserver die je wil gebruiken
irreversible: Gefilterde toots verdwijnen onomkeerbaar, zelfs als de filter later wordt verwijderd irreversible: Gefilterde toots verdwijnen onomkeerbaar, zelfs als de filter later wordt verwijderd
locale: De taal van de gebruikersomgeving, e-mails en pushmeldingen locale: De taal van de gebruikersomgeving, e-mails en pushmeldingen
locked: Vereist dat je handmatig volgers moet accepteren locked: Vereist dat je handmatig volgers moet accepteren
@ -25,6 +26,7 @@ nl:
setting_hide_network: Wie jij volgt en wie jou volgen wordt niet op jouw profiel getoond setting_hide_network: Wie jij volgt en wie jou volgen wordt niet op jouw profiel getoond
setting_noindex: Heeft invloed op jouw openbare profiel en toots setting_noindex: Heeft invloed op jouw openbare profiel en toots
setting_theme: Heeft invloed op hoe de webapp van Mastodon eruitziet (op elk apparaat waarmee je inlogt). setting_theme: Heeft invloed op hoe de webapp van Mastodon eruitziet (op elk apparaat waarmee je inlogt).
whole_word: Wanneer het trefwoord of zinsdeel alfanumeriek is, wordt het alleen gefilterd wanneer het hele woord overeenkomt
imports: imports:
data: CSV-bestand dat op een andere Mastodonserver werd geëxporteerd data: CSV-bestand dat op een andere Mastodonserver werd geëxporteerd
sessions: sessions:
@ -51,6 +53,7 @@ nl:
expires_in: Vervalt na expires_in: Vervalt na
fields: Metadata profiel fields: Metadata profiel
header: Omslagfoto header: Omslagfoto
inbox_url: Inbox-URL van de relayserver
irreversible: Verwijderen in plaats van verbergen irreversible: Verwijderen in plaats van verbergen
locale: Taal van de gebruikersomgeving locale: Taal van de gebruikersomgeving
locked: Maak account besloten locked: Maak account besloten
@ -77,6 +80,7 @@ nl:
type: Importtype type: Importtype
username: Gebruikersnaam username: Gebruikersnaam
username_or_email: Gebruikersnaam of e-mailadres username_or_email: Gebruikersnaam of e-mailadres
whole_word: Heel woord
interactions: interactions:
must_be_follower: Meldingen van mensen die jou niet volgen blokkeren must_be_follower: Meldingen van mensen die jou niet volgen blokkeren
must_be_following: Meldingen van mensen die jij niet volgt blokkeren must_be_following: Meldingen van mensen die jij niet volgt blokkeren

@ -27,6 +27,7 @@ sk:
setting_hide_network: Koho následuješ, a kto následuje teba nebude zobrazené na tvojom profile setting_hide_network: Koho následuješ, a kto následuje teba nebude zobrazené na tvojom profile
setting_noindex: Ovplyvňuje verejný profil a statusy setting_noindex: Ovplyvňuje verejný profil a statusy
setting_theme: Toto ovplyvňuje ako Mastodon vyzerá pri prihlásení z hociakého zariadenia. setting_theme: Toto ovplyvňuje ako Mastodon vyzerá pri prihlásení z hociakého zariadenia.
whole_word: Ak je kľúčové slovo, alebo fráza poskladaná iba s písmen a čísel, bude použité iba ak sa zhoduje s celým výrazom
imports: imports:
data: CSV súbor vyexportovaný z inej Mastodon inštancie data: CSV súbor vyexportovaný z inej Mastodon inštancie
sessions: sessions:
@ -53,6 +54,7 @@ sk:
expires_in: Expirovať po expires_in: Expirovať po
fields: Metadáta profilu fields: Metadáta profilu
header: Obrázok v hlavičke header: Obrázok v hlavičke
inbox_url: URL adresa prechodnej schránky
irreversible: Zahoď, namiesto skritia irreversible: Zahoď, namiesto skritia
locale: Jazyk rozhrania locale: Jazyk rozhrania
locked: Zamknúť účet locked: Zamknúť účet
@ -79,6 +81,7 @@ sk:
type: Typ importu type: Typ importu
username: Prezývka username: Prezývka
username_or_email: Prezívka, alebo email username_or_email: Prezívka, alebo email
whole_word: Celé slovo
interactions: interactions:
must_be_follower: Blokovať oznámenia od užívateľov, ktorí ťa nesledujú must_be_follower: Blokovať oznámenia od užívateľov, ktorí ťa nesledujú
must_be_following: Blokovať oboznámenia ohľadom ľudí ktorých nesleduješ must_be_following: Blokovať oboznámenia ohľadom ľudí ktorých nesleduješ

@ -259,9 +259,12 @@ sk:
filter: filter:
all: Všetky all: Všetky
available: Dostupné available: Dostupné
expired: Expirované expired: Vypršalo
title: Filtrovať title: Filtrovať
title: Pozvánky title: Pozvánky
relays:
add_new: Pridaj novú priechodnú oporu
status: Stav
report_notes: report_notes:
created_msg: Poznámka o nahlásení úspešne vytvorená! created_msg: Poznámka o nahlásení úspešne vytvorená!
destroyed_msg: Poznámka o nahlásení úspešne vymazaná! destroyed_msg: Poznámka o nahlásení úspešne vymazaná!
@ -423,11 +426,11 @@ sk:
authorize_follow: authorize_follow:
already_following: Tento účet už následuješ already_following: Tento účet už následuješ
error: Naneštastie nastala chyba pri hľadaní vzdialeného účtu error: Naneštastie nastala chyba pri hľadaní vzdialeného účtu
follow: Následovať follow: Následuj
follow_request: 'Poslali ste požiadavku následovať užívateľa:' follow_request: 'Poslal/a si žiadosť následovať užívateľa:'
following: 'Podarilo sa! Teraz už následujete užívateľa:' following: 'Podarilo sa! Teraz už následuješ užívateľa:'
post_follow: post_follow:
close: Alebo môžete iba zatvoriť toto okno. close: Alebo môžeš iba zatvoriť toto okno.
return: Ukáž užívateľov profil return: Ukáž užívateľov profil
web: Prejdi do siete web: Prejdi do siete
title: Následuj %{acct} title: Následuj %{acct}
@ -635,6 +638,7 @@ sk:
browser: Prehliadač browser: Prehliadač
browsers: browsers:
alipay: Alipay alipay: Alipay
blackberry: RIM Blackberry
chrome: Google Chrome chrome: Google Chrome
edge: Microsoft Edge edge: Microsoft Edge
electron: Electron electron: Electron

@ -42,6 +42,7 @@ SimpleNavigation::Configuration.run do |navigation|
primary.item :admin, safe_join([fa_icon('cogs fw'), t('admin.title')]), proc { current_user.admin? ? edit_admin_settings_url : admin_custom_emojis_url }, if: proc { current_user.staff? } do |admin| primary.item :admin, safe_join([fa_icon('cogs fw'), t('admin.title')]), proc { current_user.admin? ? edit_admin_settings_url : admin_custom_emojis_url }, if: proc { current_user.staff? } do |admin|
admin.item :settings, safe_join([fa_icon('cogs fw'), t('admin.settings.title')]), edit_admin_settings_url, if: -> { current_user.admin? } admin.item :settings, safe_join([fa_icon('cogs fw'), t('admin.settings.title')]), edit_admin_settings_url, if: -> { current_user.admin? }
admin.item :custom_emojis, safe_join([fa_icon('smile-o fw'), t('admin.custom_emojis.title')]), admin_custom_emojis_url, highlights_on: %r{/admin/custom_emojis} admin.item :custom_emojis, safe_join([fa_icon('smile-o fw'), t('admin.custom_emojis.title')]), admin_custom_emojis_url, highlights_on: %r{/admin/custom_emojis}
admin.item :relays, safe_join([fa_icon('exchange fw'), t('admin.relays.title')]), admin_relays_url, if: -> { current_user.admin? }, highlights_on: %r{/admin/relays}
admin.item :subscriptions, safe_join([fa_icon('paper-plane-o fw'), t('admin.subscriptions.title')]), admin_subscriptions_url, if: -> { current_user.admin? } admin.item :subscriptions, safe_join([fa_icon('paper-plane-o fw'), t('admin.subscriptions.title')]), admin_subscriptions_url, if: -> { current_user.admin? }
admin.item :sidekiq, safe_join([fa_icon('diamond fw'), 'Sidekiq']), sidekiq_url, link_html: { target: 'sidekiq' }, if: -> { current_user.admin? } admin.item :sidekiq, safe_join([fa_icon('diamond fw'), 'Sidekiq']), sidekiq_url, link_html: { target: 'sidekiq' }, if: -> { current_user.admin? }
admin.item :pghero, safe_join([fa_icon('database fw'), 'PgHero']), pghero_url, link_html: { target: 'pghero' }, if: -> { current_user.admin? } admin.item :pghero, safe_join([fa_icon('database fw'), 'PgHero']), pghero_url, link_html: { target: 'pghero' }, if: -> { current_user.admin? }

@ -134,6 +134,13 @@ Rails.application.routes.draw do
resource :settings, only: [:edit, :update] resource :settings, only: [:edit, :update]
resources :invites, only: [:index, :create, :destroy] resources :invites, only: [:index, :create, :destroy]
resources :relays, only: [:index, :new, :create, :destroy] do
member do
post :enable
post :disable
end
end
resources :instances, only: [:index] do resources :instances, only: [:index] do
collection do collection do
post :resubscribe post :resubscribe

@ -16,6 +16,8 @@ if (process.env.VAGRANT) {
} }
module.exports = merge(sharedConfig, { module.exports = merge(sharedConfig, {
mode: 'development',
devtool: 'cheap-module-eval-source-map', devtool: 'cheap-module-eval-source-map',
stats: { stats: {

@ -1,15 +1,27 @@
const ExtractTextPlugin = require('extract-text-webpack-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { env } = require('../configuration.js'); const { env } = require('../configuration.js');
module.exports = { module.exports = {
test: /\.(scss|sass|css)$/i, test: /\.s?css$/i,
use: ExtractTextPlugin.extract({ use: [
fallback: 'style-loader', MiniCssExtractPlugin.loader,
use: [ {
{ loader: 'css-loader', options: { minimize: env.NODE_ENV === 'production' } }, loader: 'css-loader',
{ loader: 'postcss-loader', options: { sourceMap: true } }, options: {
'resolve-url-loader', minimize: env.NODE_ENV === 'production',
{ loader: 'sass-loader', options: { includePaths: ['app/javascript'] } }, },
], },
}), {
loader: 'postcss-loader',
options: {
sourceMap: true,
},
},
{
loader: 'sass-loader',
options: {
includePaths: ['app/javascript'],
},
},
],
}; };

@ -1,7 +1,7 @@
// Note: You must restart bin/webpack-dev-server for changes to take effect // Note: You must restart bin/webpack-dev-server for changes to take effect
const webpack = require('webpack');
const merge = require('webpack-merge'); const merge = require('webpack-merge');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const CompressionPlugin = require('compression-webpack-plugin'); const CompressionPlugin = require('compression-webpack-plugin');
const sharedConfig = require('./shared.js'); const sharedConfig = require('./shared.js');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
@ -36,6 +36,8 @@ if (process.env.S3_ENABLED === 'true') {
} }
module.exports = merge(sharedConfig, { module.exports = merge(sharedConfig, {
mode: 'production',
output: { output: {
filename: '[name]-[chunkhash].js', filename: '[name]-[chunkhash].js',
chunkFilename: '[name]-[chunkhash].js', chunkFilename: '[name]-[chunkhash].js',
@ -44,19 +46,28 @@ module.exports = merge(sharedConfig, {
devtool: 'source-map', // separate sourcemap file, suitable for production devtool: 'source-map', // separate sourcemap file, suitable for production
stats: 'normal', stats: 'normal',
plugins: [ optimization: {
new webpack.optimize.UglifyJsPlugin({ minimize: true,
sourceMap: true, minimizer: [
mangle: true, new UglifyJsPlugin({
sourceMap: true,
compress: { uglifyOptions: {
warnings: false, mangle: true,
},
output: { compress: {
comments: false, warnings: false,
}, },
}),
output: {
comments: false,
},
},
}),
],
},
plugins: [
new CompressionPlugin({ new CompressionPlugin({
asset: '[path].gz[query]', asset: '[path].gz[query]',
algorithm: compressionAlgorithm, algorithm: compressionAlgorithm,

@ -1,9 +1,9 @@
// Note: You must restart bin/webpack-dev-server for changes to take effect // Note: You must restart bin/webpack-dev-server for changes to take effect
const webpack = require('webpack'); const webpack = require('webpack');
const { join, resolve } = require('path'); const { basename, dirname, join, relative, resolve } = require('path');
const { sync } = require('glob'); const { sync } = require('glob');
const ExtractTextPlugin = require('extract-text-webpack-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const ManifestPlugin = require('webpack-manifest-plugin'); const ManifestPlugin = require('webpack-manifest-plugin');
const { env, settings, core, flavours, output, loadersDir } = require('./configuration.js'); const { env, settings, core, flavours, output, loadersDir } = require('./configuration.js');
const localePacks = require('./generateLocalePacks'); const localePacks = require('./generateLocalePacks');
@ -59,6 +59,25 @@ module.exports = {
publicPath: output.publicPath, publicPath: output.publicPath,
}, },
optimization: {
runtimeChunk: {
name: 'locales',
},
splitChunks: {
cacheGroups: {
default: false,
vendors: false,
locales: {
name: 'locales',
chunks: 'all',
minChunks: Infinity,
minSize: 0,
},
},
},
occurrenceOrder: true,
},
module: { module: {
rules: sync(join(loadersDir, '*.js')).map(loader => require(loader)), rules: sync(join(loadersDir, '*.js')).map(loader => require(loader)),
}, },
@ -72,17 +91,13 @@ module.exports = {
resource.request = resource.request.replace(/^history/, 'history/es'); resource.request = resource.request.replace(/^history/, 'history/es');
} }
), ),
new ExtractTextPlugin({ new MiniCssExtractPlugin({
filename: env.NODE_ENV === 'production' ? '[name]-[contenthash].css' : '[name].css', filename: env.NODE_ENV === 'production' ? '[name]-[contenthash].css' : '[name].css',
allChunks: true,
}), }),
new ManifestPlugin({ new ManifestPlugin({
publicPath: output.publicPath, publicPath: output.publicPath,
writeToFileEmit: true, writeToFileEmit: true,
}), filter: file => !file.isAsset || file.isModuleAsset,
new webpack.optimize.CommonsChunkPlugin({
name: 'locales',
minChunks: Infinity, // It doesn't make sense to use common chunks with multiple frontend support.
}), }),
], ],

@ -3,4 +3,6 @@
const merge = require('webpack-merge'); const merge = require('webpack-merge');
const sharedConfig = require('./shared.js'); const sharedConfig = require('./shared.js');
module.exports = merge(sharedConfig, {}); module.exports = merge(sharedConfig, {
mode: 'development',
});

@ -5,7 +5,7 @@ class RevertIndexChangeOnStatusesForApiV1AccountsAccountIdStatuses < ActiveRecor
def change def change
safety_assured do safety_assured do
add_index :statuses, [:account_id, :id, :visibility, :updated_at], order: { id: :desc }, algorithm: :concurrently, name: :index_statuses_20180106 unless index_exists?(:statuses, name: "index_statuses_20180106") add_index :statuses, [:account_id, :id, :visibility, :updated_at], order: { id: :desc }, algorithm: :concurrently, name: :index_statuses_20180106 unless index_name_exists?(:statuses, "index_statuses_20180106")
end end
# These index may not exists (see migration 20180514130000) # These index may not exists (see migration 20180514130000)

@ -0,0 +1,12 @@
class CreateRelays < ActiveRecord::Migration[5.2]
def change
create_table :relays do |t|
t.string :inbox_url, default: '', null: false
t.boolean :enabled, default: false, null: false, index: true
t.string :follow_activity_id
t.timestamps
end
end
end

@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2018_07_07_193142) do ActiveRecord::Schema.define(version: 2018_07_11_152640) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
@ -381,6 +381,15 @@ ActiveRecord::Schema.define(version: 2018_07_07_193142) do
t.index ["status_id", "preview_card_id"], name: "index_preview_cards_statuses_on_status_id_and_preview_card_id" t.index ["status_id", "preview_card_id"], name: "index_preview_cards_statuses_on_status_id_and_preview_card_id"
end end
create_table "relays", force: :cascade do |t|
t.string "inbox_url", default: "", null: false
t.boolean "enabled", default: false, null: false
t.string "follow_activity_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["enabled"], name: "index_relays_on_enabled"
end
create_table "report_notes", force: :cascade do |t| create_table "report_notes", force: :cascade do |t|
t.text "content", null: false t.text "content", null: false
t.bigint "report_id", null: false t.bigint "report_id", null: false

@ -5,14 +5,7 @@ module Paperclip
# to convert animated gifs to webm # to convert animated gifs to webm
class GifTranscoder < Paperclip::Processor class GifTranscoder < Paperclip::Processor
def make def make
num_frames = identify('-format %n :file', file: file.path).to_i return File.open(@file.path) unless needs_convert?
unless options[:style] == :original && num_frames > 1
tmp_file = Paperclip::TempfileFactory.new.generate(attachment.instance.file_file_name)
tmp_file << file.read
tmp_file.flush
return tmp_file
end
final_file = Paperclip::Transcoder.make(file, options, attachment) final_file = Paperclip::Transcoder.make(file, options, attachment)
@ -22,5 +15,12 @@ module Paperclip
final_file final_file
end end
private
def needs_convert?
num_frames = identify('-format %n :file', file: file.path).to_i
options[:style] == :original && num_frames > 1
end
end end
end end

@ -22,29 +22,29 @@
"dependencies": { "dependencies": {
"array-includes": "^3.0.3", "array-includes": "^3.0.3",
"atrament": "^0.2.3", "atrament": "^0.2.3",
"autoprefixer": "^7.1.6", "autoprefixer": "^8.6.5",
"axios": "~0.16.2", "axios": "~0.16.2",
"babel-core": "^6.25.0", "babel-core": "^6.26.3",
"babel-loader": "^7.1.1", "babel-loader": "^7.1.5",
"babel-plugin-lodash": "^3.3.2", "babel-plugin-lodash": "^3.3.4",
"babel-plugin-preval": "^1.6.1", "babel-plugin-preval": "^1.6.1",
"babel-plugin-react-intl": "^2.3.1", "babel-plugin-react-intl": "^2.4.0",
"babel-plugin-syntax-dynamic-import": "^6.18.0", "babel-plugin-syntax-dynamic-import": "^6.18.0",
"babel-plugin-transform-class-properties": "^6.24.1", "babel-plugin-transform-class-properties": "^6.24.1",
"babel-plugin-transform-decorators-legacy": "^1.3.4", "babel-plugin-transform-decorators-legacy": "^1.3.5",
"babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", "babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
"babel-plugin-transform-object-rest-spread": "^6.23.0", "babel-plugin-transform-object-rest-spread": "^6.23.0",
"babel-plugin-transform-react-inline-elements": "^6.22.0", "babel-plugin-transform-react-inline-elements": "^6.22.0",
"babel-plugin-transform-react-jsx-self": "^6.22.0", "babel-plugin-transform-react-jsx-self": "^6.22.0",
"babel-plugin-transform-react-jsx-source": "^6.22.0", "babel-plugin-transform-react-jsx-source": "^6.22.0",
"babel-plugin-transform-react-remove-prop-types": "^0.4.10", "babel-plugin-transform-react-remove-prop-types": "^0.4.13",
"babel-plugin-transform-runtime": "^6.23.0", "babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-env": "^1.6.1", "babel-preset-env": "^1.7.0",
"babel-preset-react": "^6.24.1", "babel-preset-react": "^6.24.1",
"classnames": "^2.2.5", "classnames": "^2.2.5",
"compression-webpack-plugin": "^1.0.1", "compression-webpack-plugin": "^1.1.11",
"cross-env": "^5.1.1", "cross-env": "^5.1.4",
"css-loader": "^0.28.4", "css-loader": "^0.28.11",
"detect-passive-events": "^1.0.2", "detect-passive-events": "^1.0.2",
"dotenv": "^4.0.0", "dotenv": "^4.0.0",
"emoji-mart": "Gargron/emoji-mart#build", "emoji-mart": "Gargron/emoji-mart#build",
@ -52,8 +52,7 @@
"escape-html": "^1.0.3", "escape-html": "^1.0.3",
"exif-js": "^2.3.0", "exif-js": "^2.3.0",
"express": "^4.16.2", "express": "^4.16.2",
"extract-text-webpack-plugin": "^3.0.2", "file-loader": "^1.1.11",
"file-loader": "^0.11.2",
"font-awesome": "^4.7.0", "font-awesome": "^4.7.0",
"glob": "^7.1.1", "glob": "^7.1.1",
"http-link-header": "^0.8.0", "http-link-header": "^0.8.0",
@ -64,27 +63,28 @@
"intl-messageformat": "^2.2.0", "intl-messageformat": "^2.2.0",
"intl-relativeformat": "^2.1.0", "intl-relativeformat": "^2.1.0",
"is-nan": "^1.2.1", "is-nan": "^1.2.1",
"js-yaml": "^3.9.0", "js-yaml": "^3.11.0",
"lodash": "^4.17.4", "lodash": "^4.17.5",
"mark-loader": "^0.1.6", "mark-loader": "^0.1.6",
"marky": "^1.2.0", "marky": "^1.2.0",
"mini-css-extract-plugin": "^0.4.1",
"mkdirp": "^0.5.1", "mkdirp": "^0.5.1",
"node-sass": "^4.7.2", "node-sass": "^4.9.2",
"npm-run-all": "^4.1.2", "npm-run-all": "^4.1.2",
"npmlog": "^4.1.2", "npmlog": "^4.1.2",
"object-assign": "^4.1.1", "object-assign": "^4.1.1",
"object-fit-images": "^3.2.3", "object-fit-images": "^3.2.3",
"object.values": "^1.0.4", "object.values": "^1.0.4",
"offline-plugin": "^4.8.3", "offline-plugin": "^5.0.5",
"path-complete-extname": "^0.1.0", "path-complete-extname": "^1.0.0",
"pg": "^6.4.0", "pg": "^6.4.0",
"postcss-loader": "^2.0.9", "postcss-loader": "^2.1.6",
"postcss-object-fit-images": "^1.1.2", "postcss-object-fit-images": "^1.1.2",
"postcss-smart-import": "^0.7.5", "postcss-smart-import": "^0.7.6",
"precss": "^2.0.0", "precss": "^3.1.2",
"prop-types": "^15.5.10", "prop-types": "^15.5.10",
"punycode": "^2.1.0", "punycode": "^2.1.0",
"rails-ujs": "^5.1.2", "rails-ujs": "^5.2.0",
"react": "^16.3.0", "react": "^16.3.0",
"react-dom": "^16.3.0", "react-dom": "^16.3.0",
"react-hotkeys": "^0.10.0", "react-hotkeys": "^0.10.0",
@ -99,7 +99,7 @@
"react-router-dom": "^4.1.1", "react-router-dom": "^4.1.1",
"react-router-scroll-4": "^1.0.0-beta.1", "react-router-scroll-4": "^1.0.0-beta.1",
"react-sparklines": "^1.7.0", "react-sparklines": "^1.7.0",
"react-swipeable-views": "^0.12.3", "react-swipeable-views": "0.12.13",
"react-textarea-autosize": "^5.2.1", "react-textarea-autosize": "^5.2.1",
"react-toggle": "^4.0.1", "react-toggle": "^4.0.1",
"redis": "^2.7.1", "redis": "^2.7.1",
@ -108,25 +108,26 @@
"redux-thunk": "^2.2.0", "redux-thunk": "^2.2.0",
"requestidlecallback": "^0.3.0", "requestidlecallback": "^0.3.0",
"reselect": "^3.0.1", "reselect": "^3.0.1",
"resolve-url-loader": "^2.2.0",
"rimraf": "^2.6.1", "rimraf": "^2.6.1",
"sass-loader": "^6.0.6", "sass-loader": "^7.0.3",
"stringz": "^0.3.0", "stringz": "^0.3.0",
"style-loader": "^0.19.0", "style-loader": "^0.21.0",
"substring-trie": "^1.0.2", "substring-trie": "^1.0.2",
"throng": "^4.0.0", "throng": "^4.0.0",
"tiny-queue": "^0.2.1", "tiny-queue": "^0.2.1",
"uglifyjs-webpack-plugin": "^1.2.7",
"uuid": "^3.1.0", "uuid": "^3.1.0",
"uws": "^8.14.0", "uws": "10.148.0",
"webpack": "^3.9.1", "webpack": "^4.16.0",
"webpack-bundle-analyzer": "^2.9.1", "webpack-bundle-analyzer": "^2.13.1",
"webpack-manifest-plugin": "^1.2.1", "webpack-cli": "^3.0.8",
"webpack-merge": "^4.1.1", "webpack-manifest-plugin": "^2.0.3",
"webpack-merge": "^4.1.3",
"websocket.js": "^0.1.12", "websocket.js": "^0.1.12",
"whatwg-url": "^6.4.1" "whatwg-url": "^6.4.1"
}, },
"devDependencies": { "devDependencies": {
"babel-eslint": "^8.2.3", "babel-eslint": "^8.2.6",
"enzyme": "^3.2.0", "enzyme": "^3.2.0",
"enzyme-adapter-react-16": "^1.1.0", "enzyme-adapter-react-16": "^1.1.0",
"eslint": "^4.19.1", "eslint": "^4.19.1",
@ -136,9 +137,9 @@
"eslint-plugin-react": "^7.8.2", "eslint-plugin-react": "^7.8.2",
"jest": "^21.2.1", "jest": "^21.2.1",
"raf": "^3.4.0", "raf": "^3.4.0",
"react-intl-translations-manager": "^5.0.0", "react-intl-translations-manager": "^5.0.3",
"react-test-renderer": "^16.2.0", "react-test-renderer": "^16.2.0",
"webpack-dev-server": "^2.9.5", "webpack-dev-server": "^3.1.4",
"yargs": "^8.0.2" "yargs": "^8.0.2"
}, },
"optionalDependencies": { "optionalDependencies": {

@ -0,0 +1,4 @@
Fabricator(:relay) do
inbox_url "https://example.com/inbox"
enabled true
end

@ -58,13 +58,14 @@ RSpec.describe StreamEntriesHelper, type: :helper do
expect(acct).to eq '@user@foreign_server.com' expect(acct).to eq '@user@foreign_server.com'
end end
it 'is the shortname for non embedded local accounts' do it 'is fully qualified for non embedded local accounts' do
allow(Rails.configuration.x).to receive(:local_domain).and_return('local_domain')
set_not_embedded_view set_not_embedded_view
account = Account.new(domain: nil, username: 'user') account = Account.new(domain: nil, username: 'user')
acct = helper.acct(account) acct = helper.acct(account)
expect(acct).to eq '@user' expect(acct).to eq '@user@local_domain'
end end
end end

@ -57,7 +57,7 @@ describe LanguageDetector do
end end
it 'detects spanish language' do it 'detects spanish language' do
string = 'Obtener un Hola y bienvenidos a Mastodon' string = 'Obtener un Hola y bienvenidos a Mastodon. Obtener un Hola y bienvenidos a Mastodon. Obtener un Hola y bienvenidos a Mastodon. Obtener un Hola y bienvenidos a Mastodon'
result = described_class.instance.detect(string, account_without_user_locale) result = described_class.instance.detect(string, account_without_user_locale)
expect(result).to eq :es expect(result).to eq :es
@ -86,7 +86,7 @@ describe LanguageDetector do
account = double(user_locale: 'fr') account = double(user_locale: 'fr')
result = described_class.instance.detect('', account) result = described_class.instance.detect('', account)
expect(result).to eq :fr expect(result).to eq nil
end end
it 'uses nil when account is present but has no locale' do it 'uses nil when account is present but has no locale' do

@ -0,0 +1,4 @@
require 'rails_helper'
RSpec.describe Relay, type: :model do
end

@ -192,7 +192,7 @@ const startWorker = (workerId) => {
return; return;
} }
client.query('SELECT oauth_access_tokens.resource_owner_id, users.account_id, users.filtered_languages FROM oauth_access_tokens INNER JOIN users ON oauth_access_tokens.resource_owner_id = users.id WHERE oauth_access_tokens.token = $1 AND oauth_access_tokens.revoked_at IS NULL LIMIT 1', [token], (err, result) => { client.query('SELECT oauth_access_tokens.resource_owner_id, users.account_id, users.chosen_languages FROM oauth_access_tokens INNER JOIN users ON oauth_access_tokens.resource_owner_id = users.id WHERE oauth_access_tokens.token = $1 AND oauth_access_tokens.revoked_at IS NULL LIMIT 1', [token], (err, result) => {
done(); done();
if (err) { if (err) {
@ -209,7 +209,7 @@ const startWorker = (workerId) => {
} }
req.accountId = result.rows[0].account_id; req.accountId = result.rows[0].account_id;
req.filteredLanguages = result.rows[0].filtered_languages; req.chosenLanguages = result.rows[0].chosen_languages;
next(); next();
}); });
@ -340,7 +340,7 @@ const startWorker = (workerId) => {
const targetAccountIds = [unpackedPayload.account.id].concat(unpackedPayload.mentions.map(item => item.id)); const targetAccountIds = [unpackedPayload.account.id].concat(unpackedPayload.mentions.map(item => item.id));
const accountDomain = unpackedPayload.account.acct.split('@')[1]; const accountDomain = unpackedPayload.account.acct.split('@')[1];
if (Array.isArray(req.filteredLanguages) && req.filteredLanguages.indexOf(unpackedPayload.language) !== -1) { if (Array.isArray(req.chosenLanguages) && unpackedPayload.language !== null && req.chosenLanguages.indexOf(unpackedPayload.language) === -1) {
log.silly(req.requestId, `Message ${unpackedPayload.id} filtered by language (${unpackedPayload.language})`); log.silly(req.requestId, `Message ${unpackedPayload.id} filtered by language (${unpackedPayload.language})`);
return; return;
} }

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save