Merge pull request #578 from ThibG/glitch-soc/merge-upstream
Merge upstream changes
This commit is contained in:
commit
6eee447159
81 changed files with 3216 additions and 1806 deletions
2
.nvmrc
2
.nvmrc
|
@ -1 +1 @@
|
|||
6
|
||||
8
|
||||
|
|
2
Aptfile
2
Aptfile
|
@ -5,6 +5,8 @@ libidn11
|
|||
libidn11-dev
|
||||
libpq-dev
|
||||
libprotobuf-dev
|
||||
libssl-dev
|
||||
libxdamage1
|
||||
libxfixes3
|
||||
protobuf-compiler
|
||||
zlib1g-dev
|
||||
|
|
23
Dockerfile
23
Dockerfile
|
@ -1,3 +1,4 @@
|
|||
FROM node:8.11.3-alpine as node
|
||||
FROM ruby:2.4.4-alpine3.6
|
||||
|
||||
LABEL maintainer="https://github.com/tootsuite/mastodon" \
|
||||
|
@ -11,8 +12,6 @@ ENV PATH=/mastodon/bin:$PATH \
|
|||
RAILS_ENV=production \
|
||||
NODE_ENV=production
|
||||
|
||||
ARG YARN_VERSION=1.3.2
|
||||
ARG YARN_DOWNLOAD_SHA256=6cfe82e530ef0837212f13e45c1565ba53f5199eec2527b85ecbcd88bf26821d
|
||||
ARG LIBICONV_VERSION=1.15
|
||||
ARG LIBICONV_DOWNLOAD_SHA256=ccf536620a45458d26ba83887a983b96827001e92a13847b45e4925cc8913178
|
||||
|
||||
|
@ -20,6 +19,11 @@ EXPOSE 3000 4000
|
|||
|
||||
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 \
|
||||
&& apk add -t build-dependencies \
|
||||
build-base \
|
||||
|
@ -39,20 +43,13 @@ RUN apk -U upgrade \
|
|||
imagemagick \
|
||||
libidn \
|
||||
libpq \
|
||||
nodejs \
|
||||
nodejs-npm \
|
||||
protobuf \
|
||||
tini \
|
||||
tzdata \
|
||||
&& 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/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" \
|
||||
&& echo "$LIBICONV_DOWNLOAD_SHA256 *libiconv.tar.gz" | sha256sum -c - \
|
||||
&& 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 \
|
||||
&& bundle install -j$(getconf _NPROCESSORS_ONLN) --deployment --without test development \
|
||||
&& yarn --pure-lockfile \
|
||||
&& yarn install --pure-lockfile --ignore-engines \
|
||||
&& yarn cache clean
|
||||
|
||||
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
|
||||
|
||||
VOLUME /mastodon/public/system /mastodon/public/assets /mastodon/public/packs
|
||||
VOLUME /mastodon/public/system
|
||||
|
||||
USER mastodon
|
||||
|
||||
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", "--"]
|
||||
|
|
58
app/controllers/admin/relays_controller.rb
Normal file
58
app/controllers/admin/relays_controller.rb
Normal file
|
@ -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
|
||||
|
||||
def acct(account)
|
||||
if embedded_view? && account.local?
|
||||
if account.local?
|
||||
"@#{account.acct}@#{Rails.configuration.x.local_domain}"
|
||||
else
|
||||
"@#{account.acct}"
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
// This file will be loaded on admin pages, regardless of theme.
|
||||
|
||||
import { delegate } from 'rails-ujs';
|
||||
import { start } from '../mastodon/common';
|
||||
|
||||
start();
|
||||
|
||||
function handleDeleteStatus(event) {
|
||||
const [data] = event.detail;
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
// This file will be loaded on all pages, regardless of theme.
|
||||
|
||||
import { start } from 'rails-ujs';
|
||||
import 'font-awesome/css/font-awesome.css';
|
||||
|
||||
require.context('../images/', true);
|
||||
|
||||
start();
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
import { start } from 'rails-ujs';
|
||||
|
||||
start();
|
||||
|
||||
import 'flavours/glitch/styles/index.scss';
|
||||
|
||||
// This ensures that webpack compiles our images.
|
||||
|
|
|
@ -128,7 +128,7 @@ export function expandDomainBlocks() {
|
|||
return (dispatch, getState) => {
|
||||
const url = getState().getIn(['domain_lists', 'blocks', 'next']);
|
||||
|
||||
if (url === null) {
|
||||
if (!url) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
8
app/javascript/mastodon/common.js
Normal file
8
app/javascript/mastodon/common.js
Normal file
|
@ -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 ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
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 { List as ImmutableList } from 'immutable';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
@ -149,7 +149,7 @@ export default class GettingStarted extends ImmutablePureComponent {
|
|||
<FormattedMessage
|
||||
id='getting_started.open_source_notice'
|
||||
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>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import { LoadingBar } from 'react-redux-loading-bar';
|
||||
import ZoomableImage from './zoomable_image';
|
||||
|
||||
export default class ImageLoader extends React.PureComponent {
|
||||
|
@ -23,6 +24,7 @@ export default class ImageLoader extends React.PureComponent {
|
|||
state = {
|
||||
loading: true,
|
||||
error: false,
|
||||
width: null,
|
||||
}
|
||||
|
||||
removers = [];
|
||||
|
@ -122,6 +124,7 @@ export default class ImageLoader extends React.PureComponent {
|
|||
|
||||
setCanvasRef = c => {
|
||||
this.canvas = c;
|
||||
if (c) this.setState({ width: c.offsetWidth });
|
||||
}
|
||||
|
||||
render () {
|
||||
|
@ -135,6 +138,7 @@ export default class ImageLoader extends React.PureComponent {
|
|||
|
||||
return (
|
||||
<div className={className}>
|
||||
<LoadingBar loading={loading ? 1 : 0} className='loading-bar' style={{ width: this.state.width || width }} />
|
||||
{loading ? (
|
||||
<canvas
|
||||
className='image-loader__preview-canvas'
|
||||
|
|
|
@ -13,5 +13,6 @@ export const me = getMeta('me');
|
|||
export const searchEnabled = getMeta('search_enabled');
|
||||
export const maxChars = getMeta('max_toot_chars') || 500;
|
||||
export const invitesEnabled = getMeta('invites_enabled');
|
||||
export const version = getMeta('version');
|
||||
|
||||
export default initialState;
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
"account.direct": "Direct message @{name}",
|
||||
"account.disclaimer_full": "Information below may reflect the user's profile incompletely.",
|
||||
"account.domain_blocked": "Domain hidden",
|
||||
"account.edit_profile": "Edit profile",
|
||||
"account.follow": "Follow",
|
||||
"account.followers": "Followers",
|
||||
"account.follows": "Follows",
|
||||
"account.edit_profile": "Uprav profil",
|
||||
"account.follow": "Sleduj",
|
||||
"account.followers": "Sledovatelé",
|
||||
"account.follows": "Sleduje",
|
||||
"account.follows_you": "Follows you",
|
||||
"account.hide_reblogs": "Hide boosts from @{name}",
|
||||
"account.media": "Media",
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
"compose_form.hashtag_warning": "Αυτό το τουτ δεν θα εμφανίζεται κάτω από κανένα hashtag καθώς είναι αφανές. Μόνο τα δημόσια τουτ μπορούν να αναζητηθούν ανά hashtag.",
|
||||
"compose_form.lock_disclaimer": "Ο λογαριασμός σου δεν είναι {locked}. Οποιοσδήποτε μπορεί να σε ακολουθήσει για να δει τις δημοσιεύσεις σας προς τους ακολούθους σας.",
|
||||
"compose_form.lock_disclaimer.lock": "κλειδωμένος",
|
||||
"compose_form.placeholder": "Τι έχεις στο μυαλό σου;",
|
||||
"compose_form.placeholder": "Τι σκέφτεσαι;",
|
||||
"compose_form.publish": "Τουτ",
|
||||
"compose_form.publish_loud": "{publish}!",
|
||||
"compose_form.sensitive.marked": "Το πολυμέσο έχει σημειωθεί ως ευαίσθητο",
|
||||
|
|
|
@ -166,7 +166,7 @@
|
|||
"navigation_bar.domain_blocks": "دامینهای پنهانشده",
|
||||
"navigation_bar.edit_profile": "ویرایش نمایه",
|
||||
"navigation_bar.favourites": "پسندیدهها",
|
||||
"navigation_bar.filters": "Muted words",
|
||||
"navigation_bar.filters": "واژگان بیصداشده",
|
||||
"navigation_bar.follow_requests": "درخواستهای پیگیری",
|
||||
"navigation_bar.info": "اطلاعات تکمیلی",
|
||||
"navigation_bar.keyboard_shortcuts": "میانبرهای صفحهکلید",
|
||||
|
|
|
@ -170,7 +170,7 @@
|
|||
"navigation_bar.domain_blocks": "非表示にしたドメイン",
|
||||
"navigation_bar.edit_profile": "プロフィールを編集",
|
||||
"navigation_bar.favourites": "お気に入り",
|
||||
"navigation_bar.filters": "Muted words",
|
||||
"navigation_bar.filters": "フィルター設定",
|
||||
"navigation_bar.follow_requests": "フォローリクエスト",
|
||||
"navigation_bar.info": "このインスタンスについて",
|
||||
"navigation_bar.keyboard_shortcuts": "ホットキー",
|
||||
|
|
|
@ -166,7 +166,7 @@
|
|||
"navigation_bar.domain_blocks": "Verborgen domeinen",
|
||||
"navigation_bar.edit_profile": "Profiel bewerken",
|
||||
"navigation_bar.favourites": "Favorieten",
|
||||
"navigation_bar.filters": "Muted words",
|
||||
"navigation_bar.filters": "Genegeerde woorden",
|
||||
"navigation_bar.follow_requests": "Volgverzoeken",
|
||||
"navigation_bar.info": "Over deze server",
|
||||
"navigation_bar.keyboard_shortcuts": "Sneltoetsen",
|
||||
|
|
|
@ -166,7 +166,7 @@
|
|||
"navigation_bar.domain_blocks": "Domenis resconduts",
|
||||
"navigation_bar.edit_profile": "Modificar lo perfil",
|
||||
"navigation_bar.favourites": "Favorits",
|
||||
"navigation_bar.filters": "Muted words",
|
||||
"navigation_bar.filters": "Mots ignorats",
|
||||
"navigation_bar.follow_requests": "Demandas d’abonament",
|
||||
"navigation_bar.info": "Mai informacions",
|
||||
"navigation_bar.keyboard_shortcuts": "Acorchis clavièr",
|
||||
|
|
|
@ -166,7 +166,7 @@
|
|||
"navigation_bar.domain_blocks": "Domínios escondidos",
|
||||
"navigation_bar.edit_profile": "Editar perfil",
|
||||
"navigation_bar.favourites": "Favoritos",
|
||||
"navigation_bar.filters": "Muted words",
|
||||
"navigation_bar.filters": "Palavras silenciadas",
|
||||
"navigation_bar.follow_requests": "Seguidores pendentes",
|
||||
"navigation_bar.info": "Mais informações",
|
||||
"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.domain_blocked": "Doména ukrytá",
|
||||
"account.edit_profile": "Upraviť profil",
|
||||
"account.follow": "Následovať",
|
||||
"account.follow": "Následuj",
|
||||
"account.followers": "Sledujúci",
|
||||
"account.follows": "Následuje",
|
||||
"account.follows_you": "Následuje ťa",
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
import loadPolyfills from '../mastodon/load_polyfills';
|
||||
import { start } from '../mastodon/common';
|
||||
|
||||
start();
|
||||
|
||||
function loaded() {
|
||||
const TimelineContainer = require('../mastodon/containers/timeline_container').default;
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
import loadPolyfills from '../mastodon/load_polyfills';
|
||||
import { start } from '../mastodon/common';
|
||||
|
||||
start();
|
||||
|
||||
loadPolyfills().then(() => {
|
||||
require('../mastodon/main').default();
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import loadPolyfills from '../mastodon/load_polyfills';
|
||||
import ready from '../mastodon/ready';
|
||||
import { start } from '../mastodon/common';
|
||||
|
||||
start();
|
||||
|
||||
function main() {
|
||||
const IntlRelativeFormat = require('intl-relativeformat').default;
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
import loadPolyfills from '../mastodon/load_polyfills';
|
||||
import { start } from '../mastodon/common';
|
||||
|
||||
start();
|
||||
|
||||
function loaded() {
|
||||
const ComposeContainer = require('../mastodon/containers/compose_container').default;
|
||||
|
|
|
@ -165,6 +165,11 @@
|
|||
color: $valid-value-color;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.negative-hint {
|
||||
color: $error-value-color;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.simple_form {
|
||||
|
|
|
@ -1478,6 +1478,7 @@ a.account__display-name {
|
|||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
|
||||
.image-loader__preview-canvas {
|
||||
max-width: $media-modal-media-max-width;
|
||||
|
@ -1486,8 +1487,8 @@ a.account__display-name {
|
|||
object-fit: contain;
|
||||
}
|
||||
|
||||
&.image-loader--loading .image-loader__preview-canvas {
|
||||
filter: blur(2px);
|
||||
.loading-bar {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
&.image-loader--amorphous .image-loader__preview-canvas {
|
||||
|
|
|
@ -3,12 +3,16 @@
|
|||
class LanguageDetector
|
||||
include Singleton
|
||||
|
||||
CHARACTER_THRESHOLD = 140
|
||||
|
||||
def initialize
|
||||
@identifier = CLD3::NNetLanguageIdentifier.new(1, 2048)
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
def language_names
|
||||
|
@ -23,8 +27,13 @@ class LanguageDetector
|
|||
simplify_text(text).strip
|
||||
end
|
||||
|
||||
def unreliable_input?(text)
|
||||
text.size < CHARACTER_THRESHOLD
|
||||
end
|
||||
|
||||
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?
|
||||
end
|
||||
|
||||
|
@ -66,6 +75,6 @@ class LanguageDetector
|
|||
end
|
||||
|
||||
def default_locale(account)
|
||||
account.user_locale&.to_sym
|
||||
account.user_locale&.to_sym || I18n.default_locale
|
||||
end
|
||||
end
|
||||
|
|
|
@ -12,6 +12,8 @@ class PotentialFriendshipTracker
|
|||
|
||||
class << self
|
||||
def record(account_id, target_account_id, action)
|
||||
return if account_id == target_account_id
|
||||
|
||||
key = "interactions:#{account_id}"
|
||||
weight = WEIGHTS[action]
|
||||
|
||||
|
|
74
app/models/relay.rb
Normal file
74
app/models/relay.rb
Normal file
|
@ -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
|
7
app/policies/relay_policy.rb
Normal file
7
app/policies/relay_policy.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class RelayPolicy < ApplicationPolicy
|
||||
def update?
|
||||
admin?
|
||||
end
|
||||
end
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ActivityPub::DeleteActorSerializer < ActiveModel::Serializer
|
||||
attributes :id, :type, :actor
|
||||
attributes :id, :type, :actor, :to
|
||||
attribute :virtual_object, key: :object
|
||||
|
||||
def id
|
||||
|
@ -19,4 +19,8 @@ class ActivityPub::DeleteActorSerializer < ActiveModel::Serializer
|
|||
def virtual_object
|
||||
actor
|
||||
end
|
||||
|
||||
def to
|
||||
[ActivityPub::TagManager::COLLECTIONS[:public]]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -17,7 +17,7 @@ class ActivityPub::DeleteSerializer < ActiveModel::Serializer
|
|||
end
|
||||
end
|
||||
|
||||
attributes :id, :type, :actor
|
||||
attributes :id, :type, :actor, :to
|
||||
|
||||
has_one :object, serializer: TombstoneSerializer
|
||||
|
||||
|
@ -32,4 +32,8 @@ class ActivityPub::DeleteSerializer < ActiveModel::Serializer
|
|||
def actor
|
||||
ActivityPub::TagManager.instance.uri_for(object.account)
|
||||
end
|
||||
|
||||
def to
|
||||
[ActivityPub::TagManager::COLLECTIONS[:public]]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ActivityPub::UndoAnnounceSerializer < ActiveModel::Serializer
|
||||
attributes :id, :type, :actor
|
||||
attributes :id, :type, :actor, :to
|
||||
|
||||
has_one :object, serializer: ActivityPub::ActivitySerializer
|
||||
|
||||
|
@ -16,4 +16,8 @@ class ActivityPub::UndoAnnounceSerializer < ActiveModel::Serializer
|
|||
def actor
|
||||
ActivityPub::TagManager.instance.uri_for(object.account)
|
||||
end
|
||||
|
||||
def to
|
||||
[ActivityPub::TagManager::COLLECTIONS[:public]]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ActivityPub::UpdateSerializer < ActiveModel::Serializer
|
||||
attributes :id, :type, :actor
|
||||
attributes :id, :type, :actor, :to
|
||||
|
||||
has_one :object, serializer: ActivityPub::ActorSerializer
|
||||
|
||||
|
@ -16,4 +16,8 @@ class ActivityPub::UpdateSerializer < ActiveModel::Serializer
|
|||
def actor
|
||||
ActivityPub::TagManager.instance.uri_for(object)
|
||||
end
|
||||
|
||||
def to
|
||||
[ActivityPub::TagManager::COLLECTIONS[:public]]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -19,6 +19,7 @@ class InitialStateSerializer < ActiveModel::Serializer
|
|||
domain: Rails.configuration.x.local_domain,
|
||||
admin: object.admin&.id&.to_s,
|
||||
search_enabled: Chewy.enabled?,
|
||||
version: Mastodon::Version.to_s,
|
||||
invites_enabled: Setting.min_invite_role == 'user',
|
||||
}
|
||||
|
||||
|
|
|
@ -90,6 +90,18 @@ class RemoveStatusService < BaseService
|
|||
ActivityPub::DeliveryWorker.push_bulk(@account.followers.inboxes) do |inbox_url|
|
||||
[signed_activity_json, @account.id, inbox_url]
|
||||
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
|
||||
|
||||
def salmon_xml
|
||||
|
|
|
@ -22,7 +22,13 @@ class SuspendAccountService < BaseService
|
|||
end
|
||||
|
||||
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|
|
||||
BatchedRemoveStatusService.new.call(statuses)
|
||||
|
@ -59,12 +65,14 @@ class SuspendAccountService < BaseService
|
|||
end
|
||||
|
||||
def delete_actor_json
|
||||
return @delete_actor_json if defined?(@delete_actor_json)
|
||||
|
||||
payload = ActiveModelSerializers::SerializableResource.new(
|
||||
@account,
|
||||
serializer: ActivityPub::DeleteActorSerializer,
|
||||
adapter: ActivityPub::Adapter
|
||||
).as_json
|
||||
|
||||
Oj.dump(ActivityPub::LinkedDataSignature.new(payload).sign!(@account))
|
||||
@delete_actor_json = Oj.dump(ActivityPub::LinkedDataSignature.new(payload).sign!(@account))
|
||||
end
|
||||
end
|
||||
|
|
21
app/views/admin/relays/_relay.html.haml
Normal file
21
app/views/admin/relays/_relay.html.haml
Normal file
|
@ -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') }
|
20
app/views/admin/relays/index.html.haml
Normal file
20
app/views/admin/relays/index.html.haml
Normal file
|
@ -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
|
||||
|
13
app/views/admin/relays/new.html.haml
Normal file
13
app/views/admin/relays/new.html.haml
Normal file
|
@ -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|
|
||||
[signed_payload, @account.id, inbox_url]
|
||||
end
|
||||
|
||||
relay! if relayable?
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
true
|
||||
end
|
||||
|
@ -24,6 +26,10 @@ class ActivityPub::DistributionWorker
|
|||
@status.direct_visibility?
|
||||
end
|
||||
|
||||
def relayable?
|
||||
@status.public_visibility?
|
||||
end
|
||||
|
||||
def inboxes
|
||||
@inboxes ||= @account.followers.inboxes
|
||||
end
|
||||
|
@ -39,4 +45,10 @@ class ActivityPub::DistributionWorker
|
|||
adapter: ActivityPub::Adapter
|
||||
).as_json
|
||||
end
|
||||
|
||||
def relay!
|
||||
ActivityPub::DeliveryWorker.push_bulk(Relay.enabled.pluck(:inbox_url)) do |inbox_url|
|
||||
[signed_payload, @account.id, inbox_url]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,7 +9,11 @@ class ActivityPub::UpdateDistributionWorker
|
|||
@account = Account.find(account_id)
|
||||
|
||||
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
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
true
|
||||
|
@ -21,6 +25,10 @@ class ActivityPub::UpdateDistributionWorker
|
|||
@inboxes ||= @account.followers.inboxes
|
||||
end
|
||||
|
||||
def signed_payload
|
||||
@signed_payload ||= Oj.dump(ActivityPub::LinkedDataSignature.new(payload).sign!(@account))
|
||||
end
|
||||
|
||||
def payload
|
||||
@payload ||= ActiveModelSerializers::SerializableResource.new(
|
||||
@account,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
cs:
|
||||
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_this: O této instanci
|
||||
administered_by: 'Server spravuje:'
|
||||
|
@ -18,7 +18,7 @@ cs:
|
|||
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_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"
|
||||
learn_more: Zjistit více
|
||||
source_code: Zdrojový kód
|
||||
|
|
|
@ -10,7 +10,7 @@ da:
|
|||
contact_missing: Ikke sat
|
||||
contact_unavailable: Ikke tilgængeligt
|
||||
description_headline: Hvad er %{domain}?
|
||||
domain_count_after: andre instancer
|
||||
domain_count_after: andre instanser
|
||||
domain_count_before: Forbundet til
|
||||
extended_description_html: |
|
||||
<h3>Et godt sted for regler</h3>
|
||||
|
@ -27,7 +27,7 @@ da:
|
|||
generic_description: "%{domain} er en server i netværket"
|
||||
hosted_on: Mostodon hostet på %{domain}
|
||||
learn_more: Lær mere
|
||||
other_instances: Liste over instancer
|
||||
other_instances: Liste over instanser
|
||||
source_code: Kildekode
|
||||
status_count_after: statusser
|
||||
status_count_before: Som har skrevet
|
||||
|
@ -46,7 +46,7 @@ da:
|
|||
people_who_follow: Folk der følger %{name}
|
||||
posts: Dyt
|
||||
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
|
||||
roles:
|
||||
admin: Administrator
|
||||
|
@ -256,6 +256,10 @@ da:
|
|||
expired: Udløbet
|
||||
title: Filtre
|
||||
title: Invitationer
|
||||
relays:
|
||||
setup: Opsæt en videresendelses forbindelse
|
||||
status: Status
|
||||
title: Videresendelser
|
||||
reports:
|
||||
account:
|
||||
note: notat
|
||||
|
@ -297,7 +301,11 @@ da:
|
|||
username: Kontakt brugernavn
|
||||
hero:
|
||||
title: Billede af helt
|
||||
peers_api_enabled:
|
||||
title: Udgiv liste over opdagede instanser
|
||||
registrations:
|
||||
closed_message:
|
||||
title: Besked for lukkede registreringer
|
||||
deletion:
|
||||
desc_html: Tillad alle at slette deres konto
|
||||
title: Åben konto sletning
|
||||
|
@ -338,6 +346,7 @@ da:
|
|||
new_report:
|
||||
body: "%{reporter} har anmeldt %{target}"
|
||||
body_remote: Nogen fra %{domain} har anmeldt %{target}
|
||||
subject: Ny anmeldelse for %{instance} (#%{id})
|
||||
application_mailer:
|
||||
notification_preferences: Ændre email indstillinger
|
||||
salutation: "%{name},"
|
||||
|
@ -359,6 +368,9 @@ da:
|
|||
migrate_account: Flyt til en anden konto
|
||||
or: eller
|
||||
or_log_in_with: Eller log in med
|
||||
providers:
|
||||
cas: CAS
|
||||
saml: SAML
|
||||
register: Opret dig
|
||||
register_elsewhere: Opret dig på en anden server
|
||||
reset_password: Nulstil kodeord
|
||||
|
@ -378,8 +390,15 @@ da:
|
|||
distance_in_words:
|
||||
about_x_hours: "%{count}t"
|
||||
about_x_months: "%{count} måneder"
|
||||
about_x_years: "%{count}år"
|
||||
almost_x_years: "%{count}år"
|
||||
half_a_minute: Lige nu
|
||||
less_than_x_minutes: "%{count}m"
|
||||
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"
|
||||
deletes:
|
||||
bad_password_msg: Godt forsøg, hackere! Forkert kodeord
|
||||
|
@ -401,6 +420,7 @@ da:
|
|||
download: Hent dit arkiv
|
||||
size: Størrelse
|
||||
blocks: Du blokerer
|
||||
csv: CSV
|
||||
follows: Du følger
|
||||
mutes: Du dæmper
|
||||
filters:
|
||||
|
@ -445,9 +465,13 @@ da:
|
|||
expires_in_prompt: Aldrig
|
||||
generate: Generer
|
||||
invited_by: 'Du er blevet inviteret af:'
|
||||
max_uses:
|
||||
one: 1 benyttelse
|
||||
other: "%{count} benyttelser"
|
||||
max_uses_prompt: Ubegrænset
|
||||
table:
|
||||
expires_at: Udløber
|
||||
uses: Benyttelser
|
||||
title: Inviter folk
|
||||
media_attachments:
|
||||
validations:
|
||||
|
|
|
@ -133,7 +133,7 @@ ja:
|
|||
write:blocks: ユーザーのブロックやドメインの非表示
|
||||
write:favourites: トゥートのお気に入り登録
|
||||
write:filters: フィルターの変更
|
||||
write:follows: フォローの変更
|
||||
write:follows: あなたの代わりにフォロー、アンフォロー
|
||||
write:lists: リストの変更
|
||||
write:media: メディアのアップロード
|
||||
write:mutes: アカウントや会話のミュート
|
||||
|
|
|
@ -114,7 +114,29 @@ pt-BR:
|
|||
application:
|
||||
title: Autorização OAuth obrigatória
|
||||
scopes:
|
||||
follow: seguir, bloquear, desbloquear e deixar de seguir outras contas
|
||||
push: receber notificações push na sua conta
|
||||
read: ler os dados da sua conta
|
||||
write: postar em seu nome
|
||||
follow: modificar as relações com outras contas
|
||||
push: receber suas notificações push
|
||||
read: ler todos os dados da sua conta
|
||||
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: Ληγμένες
|
||||
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:
|
||||
created_msg: Επιτυχής δημιουργία σημείωσης καταγγελίας!
|
||||
destroyed_msg: Επιτυχής διαγραφή σημείωσης καταγγελίας!
|
||||
|
@ -316,6 +324,9 @@ el:
|
|||
peers_api_enabled:
|
||||
desc_html: Ονόματα τομέων που αυτός ο κόμβος έχει ήδη συναντήσει στο fediverse
|
||||
title: Δημοσίευση λίστας κόμβων που έχουν ανακαλυφθεί
|
||||
preview_sensitive_media:
|
||||
desc_html: Οι προεπισκοπήσεις συνδέσμων σε τρίτους ιστότοπους θα είναι ορατές ακόμα κι όταν το πολυμέσο έχει σημειωθεί ως ευαίσθητο
|
||||
title: Εμφάνιση ευαίσθητων πολυμέσων στις προεπισκοπήσεις OpenGraph
|
||||
registrations:
|
||||
closed_message:
|
||||
desc_html: Εμφανίζεται στην εισαγωγική σελίδα όταν οι εγγραφές είναι κλειστές. Μπορείς να χρησιμοποιήσεις HTML tags
|
||||
|
|
|
@ -261,6 +261,14 @@ en:
|
|||
expired: Expired
|
||||
title: Filter
|
||||
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:
|
||||
created_msg: Report note successfully created!
|
||||
destroyed_msg: Report note successfully deleted!
|
||||
|
|
|
@ -261,6 +261,14 @@ gl:
|
|||
expired: Cadudado
|
||||
title: Filtro
|
||||
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:
|
||||
created_msg: Creouse correctamente a nota do informe!
|
||||
destroyed_msg: Nota do informe eliminouse con éxito!
|
||||
|
|
|
@ -261,6 +261,11 @@ ja:
|
|||
expired: 期限切れ
|
||||
title: フィルター
|
||||
title: 招待
|
||||
relays:
|
||||
add_new: リレーを追加
|
||||
inbox_url: Relay URL
|
||||
status: ステータス
|
||||
title: リレー
|
||||
report_notes:
|
||||
created_msg: レポートメモを書き込みました!
|
||||
destroyed_msg: レポートメモを削除しました!
|
||||
|
@ -706,7 +711,7 @@ ja:
|
|||
disallowed_hashtags:
|
||||
one: '許可されていないハッシュタグが含まれています: %{tags}'
|
||||
other: '許可されていないハッシュタグが含まれています: %{tags}'
|
||||
language_detection: 自動的に言語を検出する
|
||||
language_detection: 自動検出
|
||||
open_in_web: Webで開く
|
||||
over_character_limit: 上限は %{max}文字までです
|
||||
pin_errors:
|
||||
|
|
|
@ -261,6 +261,14 @@ nl:
|
|||
expired: Verlopen
|
||||
title: Filter
|
||||
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:
|
||||
created_msg: Opmerking bij gerapporteerde toot succesvol aangemaakt!
|
||||
destroyed_msg: Opmerking bij gerapporteerde toot succesvol verwijderd!
|
||||
|
@ -492,7 +500,7 @@ nl:
|
|||
delete: Verwijderen
|
||||
title: Filters
|
||||
new:
|
||||
title: Nieuwe filter toevoegen
|
||||
title: Nieuw filter toevoegen
|
||||
followers:
|
||||
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.
|
||||
|
|
|
@ -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_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.
|
||||
whole_word: Når nøgle ordet eller udtrykket kun er alfabetisk, vil det kun blive brugt hvis det passer hele ordet
|
||||
imports:
|
||||
data: CSV fil eksporteret fra en anden Mastodon instans
|
||||
sessions:
|
||||
|
@ -77,6 +78,7 @@ da:
|
|||
type: Importtype
|
||||
username: Brugernavn
|
||||
username_or_email: Brugernavn eller Email
|
||||
whole_word: Helt ord
|
||||
interactions:
|
||||
must_be_follower: Bloker notifikationer fra folk der ikke følger dig
|
||||
must_be_following: Bloker notifikationer fra folk du ikke følger
|
||||
|
|
|
@ -48,7 +48,7 @@ de:
|
|||
data: Daten
|
||||
display_name: Anzeigename
|
||||
email: E-Mail-Adresse
|
||||
expires_in: Gültig bis
|
||||
expires_in: Läuft ab
|
||||
fields: Profil-Metadaten
|
||||
header: Kopfbild
|
||||
irreversible: Fallen lassen anstatt es zu verstecken
|
||||
|
|
|
@ -13,6 +13,7 @@ el:
|
|||
other: απομένουν <span class="name-counter">%{count}</span> χαρακτήρες
|
||||
fields: Μπορείς να έχεις έως 4 σημειώσεις σε μορφή πίνακα στο προφίλ σου
|
||||
header: PNG, GIF ή JPG. Έως 2MB. Θα μειωθεί σε διάσταση 700x335px
|
||||
inbox_url: Αντέγραψε το URL της αρχικής σελίδας του ανταποκριτή (relay) που θέλεις να χρησιμοποιήσεις
|
||||
irreversible: Τα φιλτραρισμένα τουτ θα εξαφανιστούν αμετάκλητα, ακόμα και αν το φίλτρο αργότερα αφαιρεθεί
|
||||
locale: Η γλώσσα του περιβάλλοντος χρήσης, των email και των ειδοποιήσεων ώθησης
|
||||
locked: Απαιτεί να εγκρίνεις χειροκίνητα τους ακόλουθούς σου
|
||||
|
@ -25,6 +26,7 @@ el:
|
|||
setting_hide_network: Το ποιους ακολουθείς και το ποιοι σε ακολουθούν δε θα φαίνεται στο προφίλ σου
|
||||
setting_noindex: Επηρεάζει το δημόσιο προφίλ και τις δημοσιεύσεις σου
|
||||
setting_theme: Επηρεάζει την εμφάνιση του Mastodon όταν συνδέεται από οποιαδήποτε συσκευή.
|
||||
whole_word: Όταν η λέξη ή η φράση κλειδί είναι μόνο αλφαριθμητική, θα εφαρμοστεί μόνο αν ταιριάζει με ολόκληρη τη λέξη
|
||||
imports:
|
||||
data: Αρχείο CSV που έχει εξαχθεί από διαφορετικό κόμβο Mastodon
|
||||
sessions:
|
||||
|
@ -51,6 +53,7 @@ el:
|
|||
expires_in: Λήξη μετά από
|
||||
fields: Μετεδεδομένα προφίλ
|
||||
header: Επικεφαλίδα
|
||||
inbox_url: Το URL του inbox του ανταποκριτή (relay)
|
||||
irreversible: Απόρριψη αντί για κρύψιμο
|
||||
locale: Γλώσσα περιβάλλοντος
|
||||
locked: Κλείδωμα λογαριασμού
|
||||
|
@ -77,6 +80,7 @@ el:
|
|||
type: Τύπος εισαγωγής
|
||||
username: Όνομα χρηστη
|
||||
username_or_email: Όνομα ή διεύθυνση email χρήστη
|
||||
whole_word: Ολόκληρη λέξη
|
||||
interactions:
|
||||
must_be_follower: Μπλόκαρε τις ειδοποιήσεις από όσους δεν ακολουθείς
|
||||
must_be_following: Μπλόκαρε τις ειδοποιήσεις που προέρχονται από άτομα που δεν τα ακολουθείς
|
||||
|
|
|
@ -13,6 +13,7 @@ en:
|
|||
other: <span class="name-counter">%{count}</span> characters left
|
||||
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
|
||||
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
|
||||
locale: The language of the user interface, e-mails and push notifications
|
||||
locked: Requires you to manually approve followers
|
||||
|
@ -52,6 +53,7 @@ en:
|
|||
expires_in: Expire after
|
||||
fields: Profile metadata
|
||||
header: Header
|
||||
inbox_url: URL of the relay inbox
|
||||
irreversible: Drop instead of hide
|
||||
locale: Interface language
|
||||
locked: Lock account
|
||||
|
|
|
@ -13,6 +13,7 @@ fa:
|
|||
other: <span class="name-counter">%{count}</span> حرف باقی مانده
|
||||
fields: شما میتوانید تا چهار مورد را در یک جدول در نمایهٔ خود نمایش دهید
|
||||
header: یکی از قالبهای PNG یا GIF یا JPG. بیشترین اندازه ۲ مگابایت. تصویر به اندازهٔ ۳۳۵×۷۰۰ پیکسل تبدیل خواهد شد
|
||||
inbox_url: نشانی صفحهٔ اصلی رلهای را که میخواهید به کار ببرید کپی کنید
|
||||
irreversible: بوقهای فیلترشده به طور برگشتناپذیری ناپدید میشوند، حتی اگر فیلتر را بعداً بردارید
|
||||
locale: زبان محیط کاربری، ایمیلها، و اعلانها
|
||||
locked: باید پیگیران تازه را خودتان تأیید کنید
|
||||
|
@ -20,10 +21,12 @@ fa:
|
|||
one: <span class="note-counter">1</span> حرف باقی مانده
|
||||
other: <span class="note-counter">%{count}</span> حرف باقی مانده
|
||||
phrase: مستقل از کوچکی و بزرگی حروف، با متن اصلی یا هشدار محتوای بوقها مقایسه میشود
|
||||
scopes: واسطهای برنامهنویسی که این برنامه به آن دسترسی دارد. اگر بالاترین سطح دسترسی را انتخاب کنید، دیگر نیازی به انتخاب سطحهای پایینی ندارید.
|
||||
setting_default_language: زبان نوشتههای شما به طور خودکار تشخیص داده میشود، ولی این تشخصی همیشه دقیق نیست
|
||||
setting_hide_network: فهرست پیگیران شما و فهرست کسانی که شما پی میگیرید روی نمایهٔ شما دیده نخواهد شد
|
||||
setting_noindex: روی نمایهٔ عمومی و صفحهٔ نوشتههای شما تأثیر میگذارد
|
||||
setting_theme: ظاهر ماستدون را وقتی که از هر دستگاهی به آن وارد میشوید تعیین میکند.
|
||||
whole_word: اگر کلیدواژه فقط دارای حروف و اعداد باشد، تنها وقتی پیدا میشود که با کل یک واژه در متن منطبق باشد، نه با بخشی از یک واژه
|
||||
imports:
|
||||
data: پروندهٔ CSV که از سرور ماستدون دیگری برونسپاری شده
|
||||
sessions:
|
||||
|
@ -50,6 +53,7 @@ fa:
|
|||
expires_in: تاریخ انقضا
|
||||
fields: اطلاعات تکمیلی نمایه
|
||||
header: تصویر زمینه
|
||||
inbox_url: نشانی صندوق ورودی رله
|
||||
irreversible: به جای پنهانسازی، حذف کن
|
||||
locale: زبان محیط کاربری
|
||||
locked: خصوصیکردن حساب
|
||||
|
@ -76,6 +80,7 @@ fa:
|
|||
type: نوع درونریزی
|
||||
username: نام کاربری (تنها حروف انگلیسی)
|
||||
username_or_email: نام کاربری یا ایمیل
|
||||
whole_word: تطابق واژهٔ کامل
|
||||
interactions:
|
||||
must_be_follower: مسدودکردن اعلانهای همه به جز پیگیران
|
||||
must_be_following: مسدودکردن اعلانهای کسانی که شما پی نمیگیرید
|
||||
|
|
|
@ -13,6 +13,7 @@ gl:
|
|||
other: <span class="name-counter">%{count}</span> caracteres restantes
|
||||
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
|
||||
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
|
||||
locale: O idioma da interface de usuaria, correos e notificacións
|
||||
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_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.
|
||||
whole_word: Si a chave ou frase de paso é só alfanumérica, só se aplicará si concorda a palabra completa
|
||||
imports:
|
||||
data: Ficheiro CSV exportado desde outra instancia Mastodon
|
||||
sessions:
|
||||
|
@ -51,6 +53,7 @@ gl:
|
|||
expires_in: Caducidade despois de
|
||||
fields: Metadatos do perfil
|
||||
header: Cabeceira
|
||||
inbox_url: URL da caixa de entrada do repetidor
|
||||
irreversible: Soltar en lugar de agochar
|
||||
locale: Idioma da interface
|
||||
locked: Protexer conta
|
||||
|
@ -77,6 +80,7 @@ gl:
|
|||
type: Tipo de importación
|
||||
username: Nome de usuaria
|
||||
username_or_email: Nome de usuaria ou Correo-e
|
||||
whole_word: Palabra completa
|
||||
interactions:
|
||||
must_be_follower: Bloquear as notificacións de non-seguidoras
|
||||
must_be_following: Bloquea as notificacións de personas que non segue
|
||||
|
|
|
@ -40,7 +40,7 @@ ja:
|
|||
chosen_languages: 表示する言語
|
||||
confirm_new_password: 新しいパスワード(確認用)
|
||||
confirm_password: パスワード(確認用)
|
||||
context: フィルター対象
|
||||
context: 除外対象
|
||||
current_password: 現在のパスワード
|
||||
data: データ
|
||||
display_name: 表示名
|
||||
|
@ -48,6 +48,7 @@ ja:
|
|||
expires_in: 有効期限
|
||||
fields: プロフィール補足情報
|
||||
header: ヘッダー
|
||||
inbox_url: URL of the relay inbox
|
||||
irreversible: 隠すのではなく除外する
|
||||
locale: 言語
|
||||
locked: 承認制アカウントにする
|
||||
|
@ -56,7 +57,7 @@ ja:
|
|||
note: プロフィール
|
||||
otp_attempt: 二段階認証コード
|
||||
password: パスワード
|
||||
phrase: 単語または語句
|
||||
phrase: キーワードまたはフレーズ
|
||||
setting_auto_play_gif: アニメーションGIFを自動再生する
|
||||
setting_boost_modal: ブーストする前に確認ダイアログを表示する
|
||||
setting_default_language: 投稿する言語
|
||||
|
|
|
@ -20,10 +20,12 @@ ko:
|
|||
one: <span class="note-counter">1</span> 글자 남음
|
||||
other: <span class="note-counter">%{count}</span> 글자 남음
|
||||
phrase: 툿 내용이나 CW 내용 안에서 대소문자 구분 없이 매칭 됩니다
|
||||
scopes: 애플리케이션에 허용할 API들입니다. 최상위 스코프를 선택하면 개별적인 것은 선택하지 않아도 됩니다.
|
||||
setting_default_language: 작성한 툿의 언어는 자동으로 인식할 수 있지만, 언제나 정확한 건 아닙니다
|
||||
setting_hide_network: 나를 팔로우 하는 사람들과 내가 팔로우 하는 사람들이 내 프로필에 표시되지 않게 합니다
|
||||
setting_noindex: 공개 프로필 및 각 툿페이지에 영향을 미칩니다
|
||||
setting_theme: 로그인중인 모든 디바이스에 적용되는 디자인입니다.
|
||||
whole_word: 키워드가 영문과 숫자로만 이루어 진 경우, 단어 전체에 매칭 되었을 때에만 작동하게 합니다
|
||||
imports:
|
||||
data: 다른 마스토돈 인스턴스에서 추출된 CSV 파일
|
||||
sessions:
|
||||
|
@ -76,6 +78,7 @@ ko:
|
|||
type: 불러오기 종류
|
||||
username: 유저 이름
|
||||
username_or_email: 유저네임 또는 이메일
|
||||
whole_word: 단어 전체에 매칭
|
||||
interactions:
|
||||
must_be_follower: 나를 팔로우 하지 않는 사람에게서 온 알림을 차단
|
||||
must_be_following: 내가 팔로우 하지 않는 사람에게서 온 알림을 차단
|
||||
|
|
|
@ -13,6 +13,7 @@ nl:
|
|||
other: <span class="name-counter">%{count}</span> tekens over
|
||||
fields: Je kan maximaal 4 items als een tabel op je profiel weergeven
|
||||
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
|
||||
locale: De taal van de gebruikersomgeving, e-mails en pushmeldingen
|
||||
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_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).
|
||||
whole_word: Wanneer het trefwoord of zinsdeel alfanumeriek is, wordt het alleen gefilterd wanneer het hele woord overeenkomt
|
||||
imports:
|
||||
data: CSV-bestand dat op een andere Mastodonserver werd geëxporteerd
|
||||
sessions:
|
||||
|
@ -51,6 +53,7 @@ nl:
|
|||
expires_in: Vervalt na
|
||||
fields: Metadata profiel
|
||||
header: Omslagfoto
|
||||
inbox_url: Inbox-URL van de relayserver
|
||||
irreversible: Verwijderen in plaats van verbergen
|
||||
locale: Taal van de gebruikersomgeving
|
||||
locked: Maak account besloten
|
||||
|
@ -77,6 +80,7 @@ nl:
|
|||
type: Importtype
|
||||
username: Gebruikersnaam
|
||||
username_or_email: Gebruikersnaam of e-mailadres
|
||||
whole_word: Heel woord
|
||||
interactions:
|
||||
must_be_follower: Meldingen van mensen die jou niet volgen 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_noindex: Ovplyvňuje verejný profil a statusy
|
||||
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:
|
||||
data: CSV súbor vyexportovaný z inej Mastodon inštancie
|
||||
sessions:
|
||||
|
@ -53,6 +54,7 @@ sk:
|
|||
expires_in: Expirovať po
|
||||
fields: Metadáta profilu
|
||||
header: Obrázok v hlavičke
|
||||
inbox_url: URL adresa prechodnej schránky
|
||||
irreversible: Zahoď, namiesto skritia
|
||||
locale: Jazyk rozhrania
|
||||
locked: Zamknúť účet
|
||||
|
@ -79,6 +81,7 @@ sk:
|
|||
type: Typ importu
|
||||
username: Prezývka
|
||||
username_or_email: Prezívka, alebo email
|
||||
whole_word: Celé slovo
|
||||
interactions:
|
||||
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š
|
||||
|
|
|
@ -259,9 +259,12 @@ sk:
|
|||
filter:
|
||||
all: Všetky
|
||||
available: Dostupné
|
||||
expired: Expirované
|
||||
expired: Vypršalo
|
||||
title: Filtrovať
|
||||
title: Pozvánky
|
||||
relays:
|
||||
add_new: Pridaj novú priechodnú oporu
|
||||
status: Stav
|
||||
report_notes:
|
||||
created_msg: Poznámka o nahlásení úspešne vytvorená!
|
||||
destroyed_msg: Poznámka o nahlásení úspešne vymazaná!
|
||||
|
@ -423,11 +426,11 @@ sk:
|
|||
authorize_follow:
|
||||
already_following: Tento účet už následuješ
|
||||
error: Naneštastie nastala chyba pri hľadaní vzdialeného účtu
|
||||
follow: Následovať
|
||||
follow_request: 'Poslali ste požiadavku následovať užívateľa:'
|
||||
following: 'Podarilo sa! Teraz už následujete užívateľa:'
|
||||
follow: Následuj
|
||||
follow_request: 'Poslal/a si žiadosť následovať užívateľa:'
|
||||
following: 'Podarilo sa! Teraz už následuješ užívateľa:'
|
||||
post_follow:
|
||||
close: Alebo môžete iba zatvoriť toto okno.
|
||||
close: Alebo môžeš iba zatvoriť toto okno.
|
||||
return: Ukáž užívateľov profil
|
||||
web: Prejdi do siete
|
||||
title: Následuj %{acct}
|
||||
|
@ -635,6 +638,7 @@ sk:
|
|||
browser: Prehliadač
|
||||
browsers:
|
||||
alipay: Alipay
|
||||
blackberry: RIM Blackberry
|
||||
chrome: Google Chrome
|
||||
edge: Microsoft Edge
|
||||
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|
|
||||
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 :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 :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? }
|
||||
|
|
|
@ -134,6 +134,13 @@ Rails.application.routes.draw do
|
|||
resource :settings, only: [:edit, :update]
|
||||
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
|
||||
collection do
|
||||
post :resubscribe
|
||||
|
|
|
@ -16,6 +16,8 @@ if (process.env.VAGRANT) {
|
|||
}
|
||||
|
||||
module.exports = merge(sharedConfig, {
|
||||
mode: 'development',
|
||||
|
||||
devtool: 'cheap-module-eval-source-map',
|
||||
|
||||
stats: {
|
||||
|
|
|
@ -1,15 +1,27 @@
|
|||
const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const { env } = require('../configuration.js');
|
||||
|
||||
module.exports = {
|
||||
test: /\.(scss|sass|css)$/i,
|
||||
use: ExtractTextPlugin.extract({
|
||||
fallback: 'style-loader',
|
||||
test: /\.s?css$/i,
|
||||
use: [
|
||||
{ loader: 'css-loader', options: { minimize: env.NODE_ENV === 'production' } },
|
||||
{ loader: 'postcss-loader', options: { sourceMap: true } },
|
||||
'resolve-url-loader',
|
||||
{ loader: 'sass-loader', options: { includePaths: ['app/javascript'] } },
|
||||
MiniCssExtractPlugin.loader,
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
minimize: env.NODE_ENV === 'production',
|
||||
},
|
||||
},
|
||||
{
|
||||
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
|
||||
|
||||
const webpack = require('webpack');
|
||||
const merge = require('webpack-merge');
|
||||
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
|
||||
const CompressionPlugin = require('compression-webpack-plugin');
|
||||
const sharedConfig = require('./shared.js');
|
||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
||||
|
@ -36,6 +36,8 @@ if (process.env.S3_ENABLED === 'true') {
|
|||
}
|
||||
|
||||
module.exports = merge(sharedConfig, {
|
||||
mode: 'production',
|
||||
|
||||
output: {
|
||||
filename: '[name]-[chunkhash].js',
|
||||
chunkFilename: '[name]-[chunkhash].js',
|
||||
|
@ -44,9 +46,13 @@ module.exports = merge(sharedConfig, {
|
|||
devtool: 'source-map', // separate sourcemap file, suitable for production
|
||||
stats: 'normal',
|
||||
|
||||
plugins: [
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
optimization: {
|
||||
minimize: true,
|
||||
minimizer: [
|
||||
new UglifyJsPlugin({
|
||||
sourceMap: true,
|
||||
|
||||
uglifyOptions: {
|
||||
mangle: true,
|
||||
|
||||
compress: {
|
||||
|
@ -56,7 +62,12 @@ module.exports = merge(sharedConfig, {
|
|||
output: {
|
||||
comments: false,
|
||||
},
|
||||
},
|
||||
}),
|
||||
],
|
||||
},
|
||||
|
||||
plugins: [
|
||||
new CompressionPlugin({
|
||||
asset: '[path].gz[query]',
|
||||
algorithm: compressionAlgorithm,
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
// Note: You must restart bin/webpack-dev-server for changes to take effect
|
||||
|
||||
const webpack = require('webpack');
|
||||
const { join, resolve } = require('path');
|
||||
const { basename, dirname, join, relative, resolve } = require('path');
|
||||
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 { env, settings, core, flavours, output, loadersDir } = require('./configuration.js');
|
||||
const localePacks = require('./generateLocalePacks');
|
||||
|
@ -59,6 +59,25 @@ module.exports = {
|
|||
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: {
|
||||
rules: sync(join(loadersDir, '*.js')).map(loader => require(loader)),
|
||||
},
|
||||
|
@ -72,17 +91,13 @@ module.exports = {
|
|||
resource.request = resource.request.replace(/^history/, 'history/es');
|
||||
}
|
||||
),
|
||||
new ExtractTextPlugin({
|
||||
new MiniCssExtractPlugin({
|
||||
filename: env.NODE_ENV === 'production' ? '[name]-[contenthash].css' : '[name].css',
|
||||
allChunks: true,
|
||||
}),
|
||||
new ManifestPlugin({
|
||||
publicPath: output.publicPath,
|
||||
writeToFileEmit: true,
|
||||
}),
|
||||
new webpack.optimize.CommonsChunkPlugin({
|
||||
name: 'locales',
|
||||
minChunks: Infinity, // It doesn't make sense to use common chunks with multiple frontend support.
|
||||
filter: file => !file.isAsset || file.isModuleAsset,
|
||||
}),
|
||||
],
|
||||
|
||||
|
|
|
@ -3,4 +3,6 @@
|
|||
const merge = require('webpack-merge');
|
||||
const sharedConfig = require('./shared.js');
|
||||
|
||||
module.exports = merge(sharedConfig, {});
|
||||
module.exports = merge(sharedConfig, {
|
||||
mode: 'development',
|
||||
});
|
||||
|
|
|
@ -5,7 +5,7 @@ class RevertIndexChangeOnStatusesForApiV1AccountsAccountIdStatuses < ActiveRecor
|
|||
|
||||
def change
|
||||
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
|
||||
|
||||
# These index may not exists (see migration 20180514130000)
|
||||
|
|
12
db/migrate/20180711152640_create_relays.rb
Normal file
12
db/migrate/20180711152640_create_relays.rb
Normal file
|
@ -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
|
11
db/schema.rb
11
db/schema.rb
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# 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
|
||||
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"
|
||||
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|
|
||||
t.text "content", null: false
|
||||
t.bigint "report_id", null: false
|
||||
|
|
|
@ -5,14 +5,7 @@ module Paperclip
|
|||
# to convert animated gifs to webm
|
||||
class GifTranscoder < Paperclip::Processor
|
||||
def make
|
||||
num_frames = identify('-format %n :file', file: file.path).to_i
|
||||
|
||||
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
|
||||
return File.open(@file.path) unless needs_convert?
|
||||
|
||||
final_file = Paperclip::Transcoder.make(file, options, attachment)
|
||||
|
||||
|
@ -22,5 +15,12 @@ module Paperclip
|
|||
|
||||
final_file
|
||||
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
|
||||
|
|
71
package.json
71
package.json
|
@ -22,29 +22,29 @@
|
|||
"dependencies": {
|
||||
"array-includes": "^3.0.3",
|
||||
"atrament": "^0.2.3",
|
||||
"autoprefixer": "^7.1.6",
|
||||
"autoprefixer": "^8.6.5",
|
||||
"axios": "~0.16.2",
|
||||
"babel-core": "^6.25.0",
|
||||
"babel-loader": "^7.1.1",
|
||||
"babel-plugin-lodash": "^3.3.2",
|
||||
"babel-core": "^6.26.3",
|
||||
"babel-loader": "^7.1.5",
|
||||
"babel-plugin-lodash": "^3.3.4",
|
||||
"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-transform-class-properties": "^6.24.1",
|
||||
"babel-plugin-transform-decorators-legacy": "^1.3.4",
|
||||
"babel-plugin-transform-es2015-modules-commonjs": "^6.24.1",
|
||||
"babel-plugin-transform-decorators-legacy": "^1.3.5",
|
||||
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
|
||||
"babel-plugin-transform-object-rest-spread": "^6.23.0",
|
||||
"babel-plugin-transform-react-inline-elements": "^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-remove-prop-types": "^0.4.10",
|
||||
"babel-plugin-transform-react-remove-prop-types": "^0.4.13",
|
||||
"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",
|
||||
"classnames": "^2.2.5",
|
||||
"compression-webpack-plugin": "^1.0.1",
|
||||
"cross-env": "^5.1.1",
|
||||
"css-loader": "^0.28.4",
|
||||
"compression-webpack-plugin": "^1.1.11",
|
||||
"cross-env": "^5.1.4",
|
||||
"css-loader": "^0.28.11",
|
||||
"detect-passive-events": "^1.0.2",
|
||||
"dotenv": "^4.0.0",
|
||||
"emoji-mart": "Gargron/emoji-mart#build",
|
||||
|
@ -52,8 +52,7 @@
|
|||
"escape-html": "^1.0.3",
|
||||
"exif-js": "^2.3.0",
|
||||
"express": "^4.16.2",
|
||||
"extract-text-webpack-plugin": "^3.0.2",
|
||||
"file-loader": "^0.11.2",
|
||||
"file-loader": "^1.1.11",
|
||||
"font-awesome": "^4.7.0",
|
||||
"glob": "^7.1.1",
|
||||
"http-link-header": "^0.8.0",
|
||||
|
@ -64,27 +63,28 @@
|
|||
"intl-messageformat": "^2.2.0",
|
||||
"intl-relativeformat": "^2.1.0",
|
||||
"is-nan": "^1.2.1",
|
||||
"js-yaml": "^3.9.0",
|
||||
"lodash": "^4.17.4",
|
||||
"js-yaml": "^3.11.0",
|
||||
"lodash": "^4.17.5",
|
||||
"mark-loader": "^0.1.6",
|
||||
"marky": "^1.2.0",
|
||||
"mini-css-extract-plugin": "^0.4.1",
|
||||
"mkdirp": "^0.5.1",
|
||||
"node-sass": "^4.7.2",
|
||||
"node-sass": "^4.9.2",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"npmlog": "^4.1.2",
|
||||
"object-assign": "^4.1.1",
|
||||
"object-fit-images": "^3.2.3",
|
||||
"object.values": "^1.0.4",
|
||||
"offline-plugin": "^4.8.3",
|
||||
"path-complete-extname": "^0.1.0",
|
||||
"offline-plugin": "^5.0.5",
|
||||
"path-complete-extname": "^1.0.0",
|
||||
"pg": "^6.4.0",
|
||||
"postcss-loader": "^2.0.9",
|
||||
"postcss-loader": "^2.1.6",
|
||||
"postcss-object-fit-images": "^1.1.2",
|
||||
"postcss-smart-import": "^0.7.5",
|
||||
"precss": "^2.0.0",
|
||||
"postcss-smart-import": "^0.7.6",
|
||||
"precss": "^3.1.2",
|
||||
"prop-types": "^15.5.10",
|
||||
"punycode": "^2.1.0",
|
||||
"rails-ujs": "^5.1.2",
|
||||
"rails-ujs": "^5.2.0",
|
||||
"react": "^16.3.0",
|
||||
"react-dom": "^16.3.0",
|
||||
"react-hotkeys": "^0.10.0",
|
||||
|
@ -99,7 +99,7 @@
|
|||
"react-router-dom": "^4.1.1",
|
||||
"react-router-scroll-4": "^1.0.0-beta.1",
|
||||
"react-sparklines": "^1.7.0",
|
||||
"react-swipeable-views": "^0.12.3",
|
||||
"react-swipeable-views": "0.12.13",
|
||||
"react-textarea-autosize": "^5.2.1",
|
||||
"react-toggle": "^4.0.1",
|
||||
"redis": "^2.7.1",
|
||||
|
@ -108,25 +108,26 @@
|
|||
"redux-thunk": "^2.2.0",
|
||||
"requestidlecallback": "^0.3.0",
|
||||
"reselect": "^3.0.1",
|
||||
"resolve-url-loader": "^2.2.0",
|
||||
"rimraf": "^2.6.1",
|
||||
"sass-loader": "^6.0.6",
|
||||
"sass-loader": "^7.0.3",
|
||||
"stringz": "^0.3.0",
|
||||
"style-loader": "^0.19.0",
|
||||
"style-loader": "^0.21.0",
|
||||
"substring-trie": "^1.0.2",
|
||||
"throng": "^4.0.0",
|
||||
"tiny-queue": "^0.2.1",
|
||||
"uglifyjs-webpack-plugin": "^1.2.7",
|
||||
"uuid": "^3.1.0",
|
||||
"uws": "^8.14.0",
|
||||
"webpack": "^3.9.1",
|
||||
"webpack-bundle-analyzer": "^2.9.1",
|
||||
"webpack-manifest-plugin": "^1.2.1",
|
||||
"webpack-merge": "^4.1.1",
|
||||
"uws": "10.148.0",
|
||||
"webpack": "^4.16.0",
|
||||
"webpack-bundle-analyzer": "^2.13.1",
|
||||
"webpack-cli": "^3.0.8",
|
||||
"webpack-manifest-plugin": "^2.0.3",
|
||||
"webpack-merge": "^4.1.3",
|
||||
"websocket.js": "^0.1.12",
|
||||
"whatwg-url": "^6.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-eslint": "^8.2.3",
|
||||
"babel-eslint": "^8.2.6",
|
||||
"enzyme": "^3.2.0",
|
||||
"enzyme-adapter-react-16": "^1.1.0",
|
||||
"eslint": "^4.19.1",
|
||||
|
@ -136,9 +137,9 @@
|
|||
"eslint-plugin-react": "^7.8.2",
|
||||
"jest": "^21.2.1",
|
||||
"raf": "^3.4.0",
|
||||
"react-intl-translations-manager": "^5.0.0",
|
||||
"react-intl-translations-manager": "^5.0.3",
|
||||
"react-test-renderer": "^16.2.0",
|
||||
"webpack-dev-server": "^2.9.5",
|
||||
"webpack-dev-server": "^3.1.4",
|
||||
"yargs": "^8.0.2"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
|
|
4
spec/fabricators/relay_fabricator.rb
Normal file
4
spec/fabricators/relay_fabricator.rb
Normal file
|
@ -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'
|
||||
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
|
||||
account = Account.new(domain: nil, username: 'user')
|
||||
|
||||
acct = helper.acct(account)
|
||||
|
||||
expect(acct).to eq '@user'
|
||||
expect(acct).to eq '@user@local_domain'
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ describe LanguageDetector do
|
|||
end
|
||||
|
||||
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)
|
||||
|
||||
expect(result).to eq :es
|
||||
|
@ -86,7 +86,7 @@ describe LanguageDetector do
|
|||
account = double(user_locale: 'fr')
|
||||
result = described_class.instance.detect('', account)
|
||||
|
||||
expect(result).to eq :fr
|
||||
expect(result).to eq nil
|
||||
end
|
||||
|
||||
it 'uses nil when account is present but has no locale' do
|
||||
|
|
4
spec/models/relay_spec.rb
Normal file
4
spec/models/relay_spec.rb
Normal file
|
@ -0,0 +1,4 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Relay, type: :model do
|
||||
end
|
|
@ -192,7 +192,7 @@ const startWorker = (workerId) => {
|
|||
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();
|
||||
|
||||
if (err) {
|
||||
|
@ -209,7 +209,7 @@ const startWorker = (workerId) => {
|
|||
}
|
||||
|
||||
req.accountId = result.rows[0].account_id;
|
||||
req.filteredLanguages = result.rows[0].filtered_languages;
|
||||
req.chosenLanguages = result.rows[0].chosen_languages;
|
||||
|
||||
next();
|
||||
});
|
||||
|
@ -340,7 +340,7 @@ const startWorker = (workerId) => {
|
|||
const targetAccountIds = [unpackedPayload.account.id].concat(unpackedPayload.mentions.map(item => item.id));
|
||||
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})`);
|
||||
return;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue