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

Merge upstream changes
th-downstream
ThibG 4 years ago committed by GitHub
commit 400f4eedf4

@ -1,4 +1,3 @@
https://github.com/heroku/heroku-buildpack-apt https://github.com/heroku/heroku-buildpack-apt
https://github.com/Scalingo/ffmpeg-buildpack https://github.com/Scalingo/ffmpeg-buildpack
https://github.com/Scalingo/nodejs-buildpack
https://github.com/Scalingo/ruby-buildpack https://github.com/Scalingo/ruby-buildpack

@ -72,11 +72,12 @@ aliases:
- run: - run:
name: Set bundler settings name: Set bundler settings
command: | command: |
bundle config clean 'true' bundle config --local clean 'true'
bundle config deployment 'true' bundle config --local deployment 'true'
bundle config with 'pam_authentication' bundle config --local with 'pam_authentication'
bundle config without 'development production' bundle config --local without 'development production'
bundle config frozen 'true' bundle config --local frozen 'true'
bundle config --local path $BUNDLE_PATH
- run: - run:
name: Install bundler dependencies name: Install bundler dependencies
command: bundle check || (bundle install && bundle clean) command: bundle check || (bundle install && bundle clean)

@ -88,9 +88,6 @@
{ {
"url": "https://github.com/heroku/heroku-buildpack-apt" "url": "https://github.com/heroku/heroku-buildpack-apt"
}, },
{
"url": "heroku/nodejs"
},
{ {
"url": "heroku/ruby" "url": "heroku/ruby"
} }

@ -58,6 +58,7 @@ class Api::V1::StatusesController < Api::BaseController
@status.discard @status.discard
RemovalWorker.perform_async(@status.id, redraft: true) RemovalWorker.perform_async(@status.id, redraft: true)
@status.account.statuses_count = @status.account.statuses_count - 1
render json: @status, serializer: REST::StatusSerializer, source_requested: true render json: @status, serializer: REST::StatusSerializer, source_requested: true
end end

@ -56,7 +56,7 @@ class ApplicationController < ActionController::Base
end end
def store_current_location def store_current_location
store_location_for(:user, request.url) unless request.format == :json store_location_for(:user, request.url) unless [:json, :rss].include?(request.format&.to_sym)
end end
def require_admin! def require_admin!

@ -37,7 +37,7 @@ export function counterRenderer(counterType, isBold = true) {
return (displayNumber, pluralReady) => ( return (displayNumber, pluralReady) => (
<FormattedMessage <FormattedMessage
id='account.following_counter' id='account.following_counter'
defaultMessage='{count, plural, other {{counter} Following}}' defaultMessage='{count, plural, one {{counter} Following} other {{counter} Following}}'
values={{ values={{
count: pluralReady, count: pluralReady,
counter: renderCounter(displayNumber), counter: renderCounter(displayNumber),

@ -20,7 +20,7 @@ const mapStateToProps = (state, { scrollKey }) => {
}; };
}; };
export default @connect(mapStateToProps) export default @connect(mapStateToProps, null, null, { forwardRef: true })
class ScrollableList extends PureComponent { class ScrollableList extends PureComponent {
static contextTypes = { static contextTypes = {

@ -385,10 +385,3 @@
.directory__tag > div { .directory__tag > div {
box-shadow: none; box-shadow: none;
} }
.audio-player .video-player__controls button,
.audio-player .video-player__time-sep,
.audio-player .video-player__time-current,
.audio-player .video-player__time-total {
color: $primary-text-color;
}

@ -163,7 +163,6 @@ export function submitCompose(routerHistory) {
// To make the app more responsive, immediately push the status // To make the app more responsive, immediately push the status
// into the columns // into the columns
const insertIfOnline = timelineId => { const insertIfOnline = timelineId => {
const timeline = getState().getIn(['timelines', timelineId]); const timeline = getState().getIn(['timelines', timelineId]);
@ -181,6 +180,7 @@ export function submitCompose(routerHistory) {
if (!response.data.local_only) { if (!response.data.local_only) {
insertIfOnline('public'); insertIfOnline('public');
} }
insertIfOnline(`account:${response.data.account.id}`);
} }
}).catch(function (error) { }).catch(function (error) {
dispatch(submitComposeFail(error)); dispatch(submitComposeFail(error));

@ -3,7 +3,7 @@ import openDB from '../storage/db';
import { evictStatus } from '../storage/modifier'; import { evictStatus } from '../storage/modifier';
import { deleteFromTimelines } from './timelines'; import { deleteFromTimelines } from './timelines';
import { importFetchedStatus, importFetchedStatuses, importAccount, importStatus } from './importer'; import { importFetchedStatus, importFetchedStatuses, importAccount, importStatus, importFetchedAccount } from './importer';
import { ensureComposeIsVisible } from './compose'; import { ensureComposeIsVisible } from './compose';
export const STATUS_FETCH_REQUEST = 'STATUS_FETCH_REQUEST'; export const STATUS_FETCH_REQUEST = 'STATUS_FETCH_REQUEST';
@ -155,6 +155,7 @@ export function deleteStatus(id, routerHistory, withRedraft = false) {
evictStatus(id); evictStatus(id);
dispatch(deleteStatusSuccess(id)); dispatch(deleteStatusSuccess(id));
dispatch(deleteFromTimelines(id)); dispatch(deleteFromTimelines(id));
dispatch(importFetchedAccount(response.data.account));
if (withRedraft) { if (withRedraft) {
dispatch(redraft(status, response.data.text)); dispatch(redraft(status, response.data.text));

@ -72,6 +72,7 @@ const refreshHomeTimelineAndNotification = (dispatch, done) => {
}; };
export const connectUserStream = () => connectTimelineStream('home', 'user', refreshHomeTimelineAndNotification); export const connectUserStream = () => connectTimelineStream('home', 'user', refreshHomeTimelineAndNotification);
export const connectUserTimelineStream = (accountId) => connectTimelineStream(`account:${accountId}`, 'user');
export const connectCommunityStream = ({ onlyMedia } = {}) => connectTimelineStream(`community${onlyMedia ? ':media' : ''}`, `public:local${onlyMedia ? ':media' : ''}`); export const connectCommunityStream = ({ onlyMedia } = {}) => connectTimelineStream(`community${onlyMedia ? ':media' : ''}`, `public:local${onlyMedia ? ':media' : ''}`);
export const connectPublicStream = ({ onlyMedia, onlyRemote } = {}) => connectTimelineStream(`public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`, `public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`); export const connectPublicStream = ({ onlyMedia, onlyRemote } = {}) => connectTimelineStream(`public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`, `public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`);
export const connectHashtagStream = (id, tag, local, accept) => connectTimelineStream(`hashtag:${id}${local ? ':local' : ''}`, `hashtag${local ? ':local' : ''}&tag=${tag}`, null, accept); export const connectHashtagStream = (id, tag, local, accept) => connectTimelineStream(`hashtag:${id}${local ? ':local' : ''}`, `hashtag${local ? ':local' : ''}&tag=${tag}`, null, accept);

@ -37,7 +37,7 @@ export function counterRenderer(counterType, isBold = true) {
return (displayNumber, pluralReady) => ( return (displayNumber, pluralReady) => (
<FormattedMessage <FormattedMessage
id='account.following_counter' id='account.following_counter'
defaultMessage='{count, plural, other {{counter} Following}}' defaultMessage='{count, plural, one {{counter} Following} other {{counter} Following}}'
values={{ values={{
count: pluralReady, count: pluralReady,
counter: renderCounter(displayNumber), counter: renderCounter(displayNumber),

@ -20,7 +20,7 @@ const mapStateToProps = (state, { scrollKey }) => {
}; };
}; };
export default @connect(mapStateToProps) export default @connect(mapStateToProps, null, null, { forwardRef: true })
class ScrollableList extends PureComponent { class ScrollableList extends PureComponent {
static contextTypes = { static contextTypes = {

@ -15,6 +15,8 @@ import { FormattedMessage } from 'react-intl';
import { fetchAccountIdentityProofs } from '../../actions/identity_proofs'; import { fetchAccountIdentityProofs } from '../../actions/identity_proofs';
import MissingIndicator from 'mastodon/components/missing_indicator'; import MissingIndicator from 'mastodon/components/missing_indicator';
import TimelineHint from 'mastodon/components/timeline_hint'; import TimelineHint from 'mastodon/components/timeline_hint';
import { me } from 'mastodon/initial_state';
import { connectUserTimelineStream } from '../../actions/streaming';
const emptyList = ImmutableList(); const emptyList = ImmutableList();
@ -73,6 +75,12 @@ class AccountTimeline extends ImmutablePureComponent {
this.props.dispatch(expandAccountTimeline(accountId, { withReplies })); this.props.dispatch(expandAccountTimeline(accountId, { withReplies }));
} }
componentDidMount () {
if (this.props.params.accountId === me) {
this.disconnect = this.props.dispatch(connectUserTimelineStream(me));
}
}
componentWillReceiveProps (nextProps) { componentWillReceiveProps (nextProps) {
if ((nextProps.params.accountId !== this.props.params.accountId && nextProps.params.accountId) || nextProps.withReplies !== this.props.withReplies) { if ((nextProps.params.accountId !== this.props.params.accountId && nextProps.params.accountId) || nextProps.withReplies !== this.props.withReplies) {
this.props.dispatch(fetchAccount(nextProps.params.accountId)); this.props.dispatch(fetchAccount(nextProps.params.accountId));
@ -86,6 +94,13 @@ class AccountTimeline extends ImmutablePureComponent {
} }
} }
componentWillUnmount () {
if (this.disconnect) {
this.disconnect();
this.disconnect = null;
}
}
handleLoadMore = maxId => { handleLoadMore = maxId => {
this.props.dispatch(expandAccountTimeline(this.props.params.accountId, { maxId, withReplies: this.props.withReplies })); this.props.dispatch(expandAccountTimeline(this.props.params.accountId, { maxId, withReplies: this.props.withReplies }));
} }

@ -16,7 +16,7 @@
"account.followers": "مُتابِعون", "account.followers": "مُتابِعون",
"account.followers.empty": "لا أحد يتبع هذا الحساب بعد.", "account.followers.empty": "لا أحد يتبع هذا الحساب بعد.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "هذا الحساب لا يتبع أحدًا بعد.", "account.follows.empty": "هذا الحساب لا يتبع أحدًا بعد.",
"account.follows_you": "يتابعك", "account.follows_you": "يتابعك",
"account.hide_reblogs": "إخفاء ترقيات @{name}", "account.hide_reblogs": "إخفاء ترقيات @{name}",

@ -16,7 +16,7 @@
"account.followers": "Siguidores", "account.followers": "Siguidores",
"account.followers.empty": "Naide sigue a esti usuariu entá.", "account.followers.empty": "Naide sigue a esti usuariu entá.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "Esti usuariu entá nun sigue a naide.", "account.follows.empty": "Esti usuariu entá nun sigue a naide.",
"account.follows_you": "Síguete", "account.follows_you": "Síguete",
"account.hide_reblogs": "Anubrir les comparticiones de @{name}", "account.hide_reblogs": "Anubrir les comparticiones de @{name}",

@ -16,7 +16,7 @@
"account.followers": "Последователи", "account.followers": "Последователи",
"account.followers.empty": "Все още никой не следва този потребител.", "account.followers.empty": "Все още никой не следва този потребител.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "Този потребител все още не следва никого.", "account.follows.empty": "Този потребител все още не следва никого.",
"account.follows_you": "Твой последовател", "account.follows_you": "Твой последовател",
"account.hide_reblogs": "Hide boosts from @{name}", "account.hide_reblogs": "Hide boosts from @{name}",

@ -16,7 +16,7 @@
"account.followers": "অনুসরণকারী", "account.followers": "অনুসরণকারী",
"account.followers.empty": "এই সদস্যকে এখনো কেউ অনুসরণ করে না।.", "account.followers.empty": "এই সদস্যকে এখনো কেউ অনুসরণ করে না।.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "এই সদস্য কাওকে এখনো অনুসরণ করেন না.", "account.follows.empty": "এই সদস্য কাওকে এখনো অনুসরণ করেন না.",
"account.follows_you": "আপনাকে অনুসরণ করে", "account.follows_you": "আপনাকে অনুসরণ করে",
"account.hide_reblogs": "@{name}'র সমর্থনগুলি লুকিয়ে ফেলুন", "account.hide_reblogs": "@{name}'র সমর্থনগুলি লুকিয়ে ফেলুন",

@ -16,7 +16,7 @@
"account.followers": "Sledující", "account.followers": "Sledující",
"account.followers.empty": "Tohoto uživatele ještě nikdo nesleduje.", "account.followers.empty": "Tohoto uživatele ještě nikdo nesleduje.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "Tento uživatel ještě nikoho nesleduje.", "account.follows.empty": "Tento uživatel ještě nikoho nesleduje.",
"account.follows_you": "Sleduje vás", "account.follows_you": "Sleduje vás",
"account.hide_reblogs": "Skrýt boosty od uživatele @{name}", "account.hide_reblogs": "Skrýt boosty od uživatele @{name}",

@ -16,7 +16,7 @@
"account.followers": "Dilynwyr", "account.followers": "Dilynwyr",
"account.followers.empty": "Nid oes neb yn dilyn y defnyddiwr hwn eto.", "account.followers.empty": "Nid oes neb yn dilyn y defnyddiwr hwn eto.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "Nid yw'r defnyddiwr hwn yn dilyn unrhyw un eto.", "account.follows.empty": "Nid yw'r defnyddiwr hwn yn dilyn unrhyw un eto.",
"account.follows_you": "Yn eich dilyn chi", "account.follows_you": "Yn eich dilyn chi",
"account.hide_reblogs": "Cuddio bwstiau o @{name}", "account.hide_reblogs": "Cuddio bwstiau o @{name}",

@ -16,7 +16,7 @@
"account.followers": "Følgere", "account.followers": "Følgere",
"account.followers.empty": "Der er endnu ingen der følger denne bruger.", "account.followers.empty": "Der er endnu ingen der følger denne bruger.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "Denne bruger følger endnu ikke nogen.", "account.follows.empty": "Denne bruger følger endnu ikke nogen.",
"account.follows_you": "Følger dig", "account.follows_you": "Følger dig",
"account.hide_reblogs": "Skjul fremhævelserne fra @{name}", "account.hide_reblogs": "Skjul fremhævelserne fra @{name}",

@ -146,7 +146,7 @@
"id": "account.statuses_counter" "id": "account.statuses_counter"
}, },
{ {
"defaultMessage": "{count, plural, other {{counter} Following}}", "defaultMessage": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"id": "account.following_counter" "id": "account.following_counter"
}, },
{ {
@ -2659,6 +2659,22 @@
"defaultMessage": "Boost", "defaultMessage": "Boost",
"id": "status.reblog" "id": "status.reblog"
}, },
{
"defaultMessage": "Public",
"id": "privacy.public.short"
},
{
"defaultMessage": "Unlisted",
"id": "privacy.unlisted.short"
},
{
"defaultMessage": "Followers-only",
"id": "privacy.private.short"
},
{
"defaultMessage": "Direct",
"id": "privacy.direct.short"
},
{ {
"defaultMessage": "You can press {combo} to skip this next time", "defaultMessage": "You can press {combo} to skip this next time",
"id": "boost_modal.combo" "id": "boost_modal.combo"

@ -16,7 +16,7 @@
"account.followers": "Followers", "account.followers": "Followers",
"account.followers.empty": "No one follows this user yet.", "account.followers.empty": "No one follows this user yet.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "This user doesn't follow anyone yet.", "account.follows.empty": "This user doesn't follow anyone yet.",
"account.follows_you": "Follows you", "account.follows_you": "Follows you",
"account.hide_reblogs": "Hide boosts from @{name}", "account.hide_reblogs": "Hide boosts from @{name}",

@ -16,7 +16,7 @@
"account.followers": "Jälgijad", "account.followers": "Jälgijad",
"account.followers.empty": "Keegi ei jälgi seda kasutajat veel.", "account.followers.empty": "Keegi ei jälgi seda kasutajat veel.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "See kasutaja ei jälgi veel kedagi.", "account.follows.empty": "See kasutaja ei jälgi veel kedagi.",
"account.follows_you": "Jälgib Teid", "account.follows_you": "Jälgib Teid",
"account.hide_reblogs": "Peida upitused kasutajalt @{name}", "account.hide_reblogs": "Peida upitused kasutajalt @{name}",

@ -16,7 +16,7 @@
"account.followers": "Jarraitzaileak", "account.followers": "Jarraitzaileak",
"account.followers.empty": "Ez du inork erabiltzaile hau jarraitzen oraindik.", "account.followers.empty": "Ez du inork erabiltzaile hau jarraitzen oraindik.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "Erabiltzaile honek ez du inor jarraitzen oraindik.", "account.follows.empty": "Erabiltzaile honek ez du inor jarraitzen oraindik.",
"account.follows_you": "Jarraitzen dizu", "account.follows_you": "Jarraitzen dizu",
"account.hide_reblogs": "Ezkutatu @{name}(r)en bultzadak", "account.hide_reblogs": "Ezkutatu @{name}(r)en bultzadak",

@ -16,7 +16,7 @@
"account.followers": "Seuraajaa", "account.followers": "Seuraajaa",
"account.followers.empty": "Tällä käyttäjällä ei ole vielä seuraajia.", "account.followers.empty": "Tällä käyttäjällä ei ole vielä seuraajia.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "Tämä käyttäjä ei vielä seuraa ketään.", "account.follows.empty": "Tämä käyttäjä ei vielä seuraa ketään.",
"account.follows_you": "Seuraa sinua", "account.follows_you": "Seuraa sinua",
"account.hide_reblogs": "Piilota buustaukset käyttäjältä @{name}", "account.hide_reblogs": "Piilota buustaukset käyttäjältä @{name}",

@ -16,7 +16,7 @@
"account.followers": "Followers", "account.followers": "Followers",
"account.followers.empty": "No one follows this user yet.", "account.followers.empty": "No one follows this user yet.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "This user doesn't follow anyone yet.", "account.follows.empty": "This user doesn't follow anyone yet.",
"account.follows_you": "Follows you", "account.follows_you": "Follows you",
"account.hide_reblogs": "Hide boosts from @{name}", "account.hide_reblogs": "Hide boosts from @{name}",

@ -16,7 +16,7 @@
"account.followers": "עוקבים", "account.followers": "עוקבים",
"account.followers.empty": "אף אחד לא עוקב אחר המשתמש הזה עדיין.", "account.followers.empty": "אף אחד לא עוקב אחר המשתמש הזה עדיין.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "משתמש זה לא עוקב אחר אף אחד עדיין.", "account.follows.empty": "משתמש זה לא עוקב אחר אף אחד עדיין.",
"account.follows_you": "במעקב אחריך", "account.follows_you": "במעקב אחריך",
"account.hide_reblogs": "להסתיר הידהודים מאת @{name}", "account.hide_reblogs": "להסתיר הידהודים מאת @{name}",

@ -16,7 +16,7 @@
"account.followers": "फॉलोवर", "account.followers": "फॉलोवर",
"account.followers.empty": "कोई भी इस यूज़र् को फ़ॉलो नहीं करता है", "account.followers.empty": "कोई भी इस यूज़र् को फ़ॉलो नहीं करता है",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "यह यूज़र् अभी तक किसी को फॉलो नहीं करता है।", "account.follows.empty": "यह यूज़र् अभी तक किसी को फॉलो नहीं करता है।",
"account.follows_you": "आपको फॉलो करता है", "account.follows_you": "आपको फॉलो करता है",
"account.hide_reblogs": "@{name} के बूस्ट छुपाएं", "account.hide_reblogs": "@{name} के बूस्ट छुपाएं",

@ -16,7 +16,7 @@
"account.followers": "Sljedbenici", "account.followers": "Sljedbenici",
"account.followers.empty": "No one follows this user yet.", "account.followers.empty": "No one follows this user yet.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "This user doesn't follow anyone yet.", "account.follows.empty": "This user doesn't follow anyone yet.",
"account.follows_you": "te slijedi", "account.follows_you": "te slijedi",
"account.hide_reblogs": "Hide boosts from @{name}", "account.hide_reblogs": "Hide boosts from @{name}",

@ -16,7 +16,7 @@
"account.followers": "Pengikut", "account.followers": "Pengikut",
"account.followers.empty": "Tidak ada satupun yang mengkuti pengguna ini saat ini.", "account.followers.empty": "Tidak ada satupun yang mengkuti pengguna ini saat ini.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "Pengguna ini belum mengikuti siapapun.", "account.follows.empty": "Pengguna ini belum mengikuti siapapun.",
"account.follows_you": "Mengikuti anda", "account.follows_you": "Mengikuti anda",
"account.hide_reblogs": "Sembunyikan boosts dari @{name}", "account.hide_reblogs": "Sembunyikan boosts dari @{name}",

@ -16,7 +16,7 @@
"account.followers": "Sequanti", "account.followers": "Sequanti",
"account.followers.empty": "No one follows this user yet.", "account.followers.empty": "No one follows this user yet.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "This user doesn't follow anyone yet.", "account.follows.empty": "This user doesn't follow anyone yet.",
"account.follows_you": "Sequas tu", "account.follows_you": "Sequas tu",
"account.hide_reblogs": "Hide boosts from @{name}", "account.hide_reblogs": "Hide boosts from @{name}",

@ -16,7 +16,7 @@
"account.followers": "Fylgjendur", "account.followers": "Fylgjendur",
"account.followers.empty": "Ennþá fylgist enginn með þessum notanda.", "account.followers.empty": "Ennþá fylgist enginn með þessum notanda.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "Þessi notandi fylgist ennþá ekki með neinum.", "account.follows.empty": "Þessi notandi fylgist ennþá ekki með neinum.",
"account.follows_you": "Fylgir þér", "account.follows_you": "Fylgir þér",
"account.hide_reblogs": "Fela endurbirtingar fyrir @{name}", "account.hide_reblogs": "Fela endurbirtingar fyrir @{name}",

@ -16,7 +16,7 @@
"account.followers": "მიმდევრები", "account.followers": "მიმდევრები",
"account.followers.empty": "No one follows this user yet.", "account.followers.empty": "No one follows this user yet.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "This user doesn't follow anyone yet.", "account.follows.empty": "This user doesn't follow anyone yet.",
"account.follows_you": "მოგყვებათ", "account.follows_you": "მოგყვებათ",
"account.hide_reblogs": "დაიმალოს ბუსტები @{name}-სგან", "account.hide_reblogs": "დაიმალოს ბუსტები @{name}-სგან",

@ -16,7 +16,7 @@
"account.followers": "Imeḍfaren", "account.followers": "Imeḍfaren",
"account.followers.empty": "Ar tura, ulac yiwen i yeṭṭafaṛen amseqdac-agi.", "account.followers.empty": "Ar tura, ulac yiwen i yeṭṭafaṛen amseqdac-agi.",
"account.followers_counter": "{count, plural, one {{count} n umeḍfar} other {{count} n imeḍfaren}}", "account.followers_counter": "{count, plural, one {{count} n umeḍfar} other {{count} n imeḍfaren}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "Ar tura, amseqdac-agi ur yeṭṭafaṛ yiwen.", "account.follows.empty": "Ar tura, amseqdac-agi ur yeṭṭafaṛ yiwen.",
"account.follows_you": "Yeṭṭafaṛ-ik", "account.follows_you": "Yeṭṭafaṛ-ik",
"account.hide_reblogs": "Ffer ayen i ibeṭṭu @{name}", "account.hide_reblogs": "Ffer ayen i ibeṭṭu @{name}",

@ -16,7 +16,7 @@
"account.followers": "Оқырмандар", "account.followers": "Оқырмандар",
"account.followers.empty": "Әлі ешкім жазылмаған.", "account.followers.empty": "Әлі ешкім жазылмаған.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "Ешкімге жазылмапты.", "account.follows.empty": "Ешкімге жазылмапты.",
"account.follows_you": "Сізге жазылыпты", "account.follows_you": "Сізге жазылыпты",
"account.hide_reblogs": "@{name} атты қолданушының әрекеттерін жасыру", "account.hide_reblogs": "@{name} атты қолданушының әрекеттерін жасыру",

@ -16,7 +16,7 @@
"account.followers": "Followers", "account.followers": "Followers",
"account.followers.empty": "No one follows this user yet.", "account.followers.empty": "No one follows this user yet.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "This user doesn't follow anyone yet.", "account.follows.empty": "This user doesn't follow anyone yet.",
"account.follows_you": "Follows you", "account.follows_you": "Follows you",
"account.hide_reblogs": "Hide boosts from @{name}", "account.hide_reblogs": "Hide boosts from @{name}",

@ -16,7 +16,7 @@
"account.followers": "Followers", "account.followers": "Followers",
"account.followers.empty": "No one follows this user yet.", "account.followers.empty": "No one follows this user yet.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "This user doesn't follow anyone yet.", "account.follows.empty": "This user doesn't follow anyone yet.",
"account.follows_you": "Follows you", "account.follows_you": "Follows you",
"account.hide_reblogs": "Hide boosts from @{name}", "account.hide_reblogs": "Hide boosts from @{name}",

@ -16,7 +16,7 @@
"account.followers": "Followers", "account.followers": "Followers",
"account.followers.empty": "No one follows this user yet.", "account.followers.empty": "No one follows this user yet.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "This user doesn't follow anyone yet.", "account.follows.empty": "This user doesn't follow anyone yet.",
"account.follows_you": "Follows you", "account.follows_you": "Follows you",
"account.hide_reblogs": "Hide boosts from @{name}", "account.hide_reblogs": "Hide boosts from @{name}",

@ -16,7 +16,7 @@
"account.followers": "Sekotāji", "account.followers": "Sekotāji",
"account.followers.empty": "Šim lietotājam nav sekotāju.", "account.followers.empty": "Šim lietotājam nav sekotāju.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "Šis lietotājs pagaidām nevienam neseko.", "account.follows.empty": "Šis lietotājs pagaidām nevienam neseko.",
"account.follows_you": "Seko tev", "account.follows_you": "Seko tev",
"account.hide_reblogs": "Paslēpt paceltos ierakstus no lietotāja @{name}", "account.hide_reblogs": "Paslēpt paceltos ierakstus no lietotāja @{name}",

@ -16,7 +16,7 @@
"account.followers": "Следбеници", "account.followers": "Следбеници",
"account.followers.empty": "Никој не го следи овој корисник сеуште.", "account.followers.empty": "Никој не го следи овој корисник сеуште.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "Корисникот не следи никој сеуште.", "account.follows.empty": "Корисникот не следи никој сеуште.",
"account.follows_you": "Те следи тебе", "account.follows_you": "Те следи тебе",
"account.hide_reblogs": "Сокриј буст од @{name}", "account.hide_reblogs": "Сокриј буст од @{name}",

@ -16,7 +16,7 @@
"account.followers": "പിന്തുടരുന്നവർ", "account.followers": "പിന്തുടരുന്നവർ",
"account.followers.empty": "ഈ ഉപയോക്താവിനെ ആരും ഇതുവരെ പിന്തുടരുന്നില്ല.", "account.followers.empty": "ഈ ഉപയോക്താവിനെ ആരും ഇതുവരെ പിന്തുടരുന്നില്ല.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "ഈ ഉപയോക്താവ് ആരേയും ഇതുവരെ പിന്തുടരുന്നില്ല.", "account.follows.empty": "ഈ ഉപയോക്താവ് ആരേയും ഇതുവരെ പിന്തുടരുന്നില്ല.",
"account.follows_you": "നിങ്ങളെ പിന്തുടരുന്നു", "account.follows_you": "നിങ്ങളെ പിന്തുടരുന്നു",
"account.hide_reblogs": "@{name} ബൂസ്റ്റ് ചെയ്തവ മറയ്കുക", "account.hide_reblogs": "@{name} ബൂസ്റ്റ് ചെയ്തവ മറയ്കുക",

@ -16,7 +16,7 @@
"account.followers": "अनुयायी", "account.followers": "अनुयायी",
"account.followers.empty": "ह्या वापरकर्त्याचा आतापर्यंत कोणी अनुयायी नाही.", "account.followers.empty": "ह्या वापरकर्त्याचा आतापर्यंत कोणी अनुयायी नाही.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "हा वापरकर्ता अजूनपर्यंत कोणाचा अनुयायी नाही.", "account.follows.empty": "हा वापरकर्ता अजूनपर्यंत कोणाचा अनुयायी नाही.",
"account.follows_you": "तुमचा अनुयायी आहे", "account.follows_you": "तुमचा अनुयायी आहे",
"account.hide_reblogs": "@{name} पासून सर्व बूस्ट लपवा", "account.hide_reblogs": "@{name} पासून सर्व बूस्ट लपवा",

@ -16,7 +16,7 @@
"account.followers": "Followers", "account.followers": "Followers",
"account.followers.empty": "No one follows this user yet.", "account.followers.empty": "No one follows this user yet.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "This user doesn't follow anyone yet.", "account.follows.empty": "This user doesn't follow anyone yet.",
"account.follows_you": "Follows you", "account.follows_you": "Follows you",
"account.hide_reblogs": "Hide boosts from @{name}", "account.hide_reblogs": "Hide boosts from @{name}",

@ -16,7 +16,7 @@
"account.followers": "Volgers", "account.followers": "Volgers",
"account.followers.empty": "Niemand volgt nog deze gebruiker.", "account.followers.empty": "Niemand volgt nog deze gebruiker.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "Deze gebruiker volgt nog niemand.", "account.follows.empty": "Deze gebruiker volgt nog niemand.",
"account.follows_you": "Volgt jou", "account.follows_you": "Volgt jou",
"account.hide_reblogs": "Verberg boosts van @{name}", "account.hide_reblogs": "Verberg boosts van @{name}",

@ -16,7 +16,7 @@
"account.followers": "Fylgjarar", "account.followers": "Fylgjarar",
"account.followers.empty": "Ingen fylgjer denne brukaren enno.", "account.followers.empty": "Ingen fylgjer denne brukaren enno.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "Denne brukaren fylgjer ikkje nokon enno.", "account.follows.empty": "Denne brukaren fylgjer ikkje nokon enno.",
"account.follows_you": "Fylgjer deg", "account.follows_you": "Fylgjer deg",
"account.hide_reblogs": "Gøym fremhevingar frå @{name}", "account.hide_reblogs": "Gøym fremhevingar frå @{name}",

@ -16,7 +16,7 @@
"account.followers": "Følgere", "account.followers": "Følgere",
"account.followers.empty": "Ingen følger denne brukeren ennå.", "account.followers.empty": "Ingen følger denne brukeren ennå.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "Denne brukeren følger ikke noen enda.", "account.follows.empty": "Denne brukeren følger ikke noen enda.",
"account.follows_you": "Følger deg", "account.follows_you": "Følger deg",
"account.hide_reblogs": "Skjul fremhevinger fra @{name}", "account.hide_reblogs": "Skjul fremhevinger fra @{name}",

@ -16,7 +16,7 @@
"account.followers": "Seguidors", "account.followers": "Seguidors",
"account.followers.empty": "Degun sèc pas aqueste utilizaire pel moment.", "account.followers.empty": "Degun sèc pas aqueste utilizaire pel moment.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "Aqueste utilizaire sèc pas degun pel moment.", "account.follows.empty": "Aqueste utilizaire sèc pas degun pel moment.",
"account.follows_you": "Vos sèc", "account.follows_you": "Vos sèc",
"account.hide_reblogs": "Rescondre los partatges de @{name}", "account.hide_reblogs": "Rescondre los partatges de @{name}",

@ -16,7 +16,7 @@
"account.followers": "Śledzący", "account.followers": "Śledzący",
"account.followers.empty": "Nikt jeszcze nie śledzi tego użytkownika.", "account.followers.empty": "Nikt jeszcze nie śledzi tego użytkownika.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "Ten użytkownik nie śledzi jeszcze nikogo.", "account.follows.empty": "Ten użytkownik nie śledzi jeszcze nikogo.",
"account.follows_you": "Śledzi Cię", "account.follows_you": "Śledzi Cię",
"account.hide_reblogs": "Ukryj podbicia od @{name}", "account.hide_reblogs": "Ukryj podbicia od @{name}",

@ -16,7 +16,7 @@
"account.followers": "Urmăritori", "account.followers": "Urmăritori",
"account.followers.empty": "Acest utilizator nu are încă urmăritori.", "account.followers.empty": "Acest utilizator nu are încă urmăritori.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "Acest utilizator nu urmărește pe nimeni încă.", "account.follows.empty": "Acest utilizator nu urmărește pe nimeni încă.",
"account.follows_you": "Te urmărește", "account.follows_you": "Te urmărește",
"account.hide_reblogs": "Ascunde impulsurile de la @{name}", "account.hide_reblogs": "Ascunde impulsurile de la @{name}",

@ -16,7 +16,7 @@
"account.followers": "Sighiduras", "account.followers": "Sighiduras",
"account.followers.empty": "Nemos sighit ancora custa persone.", "account.followers.empty": "Nemos sighit ancora custa persone.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "Custa persone non sighit ancora a nemos.", "account.follows.empty": "Custa persone non sighit ancora a nemos.",
"account.follows_you": "Ti sighit", "account.follows_you": "Ti sighit",
"account.hide_reblogs": "Cua is cumpartziduras de @{name}", "account.hide_reblogs": "Cua is cumpartziduras de @{name}",

@ -16,7 +16,7 @@
"account.followers": "Sledujúci", "account.followers": "Sledujúci",
"account.followers.empty": "Tohto používateľa ešte nikto nenásleduje.", "account.followers.empty": "Tohto používateľa ešte nikto nenásleduje.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "Tento používateľ ešte nikoho nenasleduje.", "account.follows.empty": "Tento používateľ ešte nikoho nenasleduje.",
"account.follows_you": "Nasleduje ťa", "account.follows_you": "Nasleduje ťa",
"account.hide_reblogs": "Skry vyzdvihnutia od @{name}", "account.hide_reblogs": "Skry vyzdvihnutia od @{name}",

@ -16,7 +16,7 @@
"account.followers": "Sledilci", "account.followers": "Sledilci",
"account.followers.empty": "Nihče ne sledi temu uporabniku.", "account.followers.empty": "Nihče ne sledi temu uporabniku.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "Ta uporabnik še ne sledi nikomur.", "account.follows.empty": "Ta uporabnik še ne sledi nikomur.",
"account.follows_you": "Sledi tebi", "account.follows_you": "Sledi tebi",
"account.hide_reblogs": "Skrij spodbude od @{name}", "account.hide_reblogs": "Skrij spodbude od @{name}",

@ -16,7 +16,7 @@
"account.followers": "Pratioca", "account.followers": "Pratioca",
"account.followers.empty": "No one follows this user yet.", "account.followers.empty": "No one follows this user yet.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "This user doesn't follow anyone yet.", "account.follows.empty": "This user doesn't follow anyone yet.",
"account.follows_you": "Prati Vas", "account.follows_you": "Prati Vas",
"account.hide_reblogs": "Sakrij podrške koje daje korisnika @{name}", "account.hide_reblogs": "Sakrij podrške koje daje korisnika @{name}",

@ -16,7 +16,7 @@
"account.followers": "Пратиоци", "account.followers": "Пратиоци",
"account.followers.empty": "Тренутно нико не прати овог корисника.", "account.followers.empty": "Тренутно нико не прати овог корисника.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "Корисник тренутно не прати никога.", "account.follows.empty": "Корисник тренутно не прати никога.",
"account.follows_you": "Прати Вас", "account.follows_you": "Прати Вас",
"account.hide_reblogs": "Сакриј подршке које даје корисника @{name}", "account.hide_reblogs": "Сакриј подршке које даје корисника @{name}",

@ -16,7 +16,7 @@
"account.followers": "Följare", "account.followers": "Följare",
"account.followers.empty": "Ingen följer denna användare än.", "account.followers.empty": "Ingen följer denna användare än.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "Denna användare följer inte någon än.", "account.follows.empty": "Denna användare följer inte någon än.",
"account.follows_you": "Följer dig", "account.follows_you": "Följer dig",
"account.hide_reblogs": "Dölj knuffar från @{name}", "account.hide_reblogs": "Dölj knuffar från @{name}",

@ -16,7 +16,7 @@
"account.followers": "Followers", "account.followers": "Followers",
"account.followers.empty": "No one follows this user yet.", "account.followers.empty": "No one follows this user yet.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "This user doesn't follow anyone yet.", "account.follows.empty": "This user doesn't follow anyone yet.",
"account.follows_you": "Follows you", "account.follows_you": "Follows you",
"account.hide_reblogs": "Hide boosts from @{name}", "account.hide_reblogs": "Hide boosts from @{name}",

@ -16,7 +16,7 @@
"account.followers": "பின்தொடர்பவர்கள்", "account.followers": "பின்தொடர்பவர்கள்",
"account.followers.empty": "இதுவரை யாரும் இந்த பயனரைப் பின்தொடரவில்லை.", "account.followers.empty": "இதுவரை யாரும் இந்த பயனரைப் பின்தொடரவில்லை.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "இந்த பயனர் இதுவரை யாரையும் பின்தொடரவில்லை.", "account.follows.empty": "இந்த பயனர் இதுவரை யாரையும் பின்தொடரவில்லை.",
"account.follows_you": "உங்களைப் பின்தொடர்கிறார்", "account.follows_you": "உங்களைப் பின்தொடர்கிறார்",
"account.hide_reblogs": "இருந்து ஊக்கியாக மறை @{name}", "account.hide_reblogs": "இருந்து ஊக்கியாக மறை @{name}",

@ -16,7 +16,7 @@
"account.followers": "Followers", "account.followers": "Followers",
"account.followers.empty": "No one follows this user yet.", "account.followers.empty": "No one follows this user yet.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "This user doesn't follow anyone yet.", "account.follows.empty": "This user doesn't follow anyone yet.",
"account.follows_you": "Follows you", "account.follows_you": "Follows you",
"account.hide_reblogs": "Hide boosts from @{name}", "account.hide_reblogs": "Hide boosts from @{name}",

@ -16,7 +16,7 @@
"account.followers": "అనుచరులు", "account.followers": "అనుచరులు",
"account.followers.empty": "ఈ వినియోగదారుడిని ఇంకా ఎవరూ అనుసరించడంలేదు.", "account.followers.empty": "ఈ వినియోగదారుడిని ఇంకా ఎవరూ అనుసరించడంలేదు.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "ఈ వినియోగదారి ఇంకా ఎవరినీ అనుసరించడంలేదు.", "account.follows.empty": "ఈ వినియోగదారి ఇంకా ఎవరినీ అనుసరించడంలేదు.",
"account.follows_you": "మిమ్మల్ని అనుసరిస్తున్నారు", "account.follows_you": "మిమ్మల్ని అనుసరిస్తున్నారు",
"account.hide_reblogs": "@{name} నుంచి బూస్ట్ లను దాచిపెట్టు", "account.hide_reblogs": "@{name} నుంచి బూస్ట్ లను దాచిపెట్టు",

@ -16,7 +16,7 @@
"account.followers": "ผู้ติดตาม", "account.followers": "ผู้ติดตาม",
"account.followers.empty": "ยังไม่มีใครติดตามผู้ใช้นี้", "account.followers.empty": "ยังไม่มีใครติดตามผู้ใช้นี้",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "ผู้ใช้นี้ยังไม่ได้ติดตามใคร", "account.follows.empty": "ผู้ใช้นี้ยังไม่ได้ติดตามใคร",
"account.follows_you": "ติดตามคุณ", "account.follows_you": "ติดตามคุณ",
"account.hide_reblogs": "ซ่อนการดันจาก @{name}", "account.hide_reblogs": "ซ่อนการดันจาก @{name}",

@ -16,7 +16,7 @@
"account.followers": "Takipçi", "account.followers": "Takipçi",
"account.followers.empty": "Henüz kimse bu kullanıcıyı takip etmiyor.", "account.followers.empty": "Henüz kimse bu kullanıcıyı takip etmiyor.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "Bu kullanıcı henüz kimseyi takip etmiyor.", "account.follows.empty": "Bu kullanıcı henüz kimseyi takip etmiyor.",
"account.follows_you": "Seni takip ediyor", "account.follows_you": "Seni takip ediyor",
"account.hide_reblogs": "@{name} kişisinin yinelemelerini gizle", "account.hide_reblogs": "@{name} kişisinin yinelemelerini gizle",

@ -16,7 +16,7 @@
"account.followers": "Followers", "account.followers": "Followers",
"account.followers.empty": "No one follows this user yet.", "account.followers.empty": "No one follows this user yet.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "This user doesn't follow anyone yet.", "account.follows.empty": "This user doesn't follow anyone yet.",
"account.follows_you": "Follows you", "account.follows_you": "Follows you",
"account.hide_reblogs": "Hide boosts from @{name}", "account.hide_reblogs": "Hide boosts from @{name}",

@ -16,7 +16,7 @@
"account.followers": "Підписники", "account.followers": "Підписники",
"account.followers.empty": "Ніхто ще не підписався на цього користувача.", "account.followers.empty": "Ніхто ще не підписався на цього користувача.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "Цей користувач ще ні на кого не підписався.", "account.follows.empty": "Цей користувач ще ні на кого не підписався.",
"account.follows_you": "Підписаний(-а) на вас", "account.follows_you": "Підписаний(-а) на вас",
"account.hide_reblogs": "Сховати передмухи від @{name}", "account.hide_reblogs": "Сховати передмухи від @{name}",

@ -16,7 +16,7 @@
"account.followers": "پیروکار", "account.followers": "پیروکار",
"account.followers.empty": "\"ہنوز اس صارف کی کوئی پیروی نہیں کرتا\".", "account.followers.empty": "\"ہنوز اس صارف کی کوئی پیروی نہیں کرتا\".",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "\"یہ صارف ہنوز کسی کی پیروی نہیں کرتا ہے\".", "account.follows.empty": "\"یہ صارف ہنوز کسی کی پیروی نہیں کرتا ہے\".",
"account.follows_you": "آپ کا پیروکار ہے", "account.follows_you": "آپ کا پیروکار ہے",
"account.hide_reblogs": "@{name} سے فروغ چھپائیں", "account.hide_reblogs": "@{name} سے فروغ چھپائیں",

@ -16,7 +16,7 @@
"account.followers": "關注的人", "account.followers": "關注的人",
"account.followers.empty": "尚沒有人關注這位使用者。", "account.followers.empty": "尚沒有人關注這位使用者。",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "這位使用者尚未關注任何使用者。", "account.follows.empty": "這位使用者尚未關注任何使用者。",
"account.follows_you": "關注你", "account.follows_you": "關注你",
"account.hide_reblogs": "隱藏 @{name} 的轉推", "account.hide_reblogs": "隱藏 @{name} 的轉推",

@ -16,7 +16,7 @@
"account.followers": "關注者", "account.followers": "關注者",
"account.followers.empty": "尚沒有人關注這位使用者。", "account.followers.empty": "尚沒有人關注這位使用者。",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
"account.following_counter": "{count, plural, other {{counter} Following}}", "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
"account.follows.empty": "這位使用者尚未關注任何使用者。", "account.follows.empty": "這位使用者尚未關注任何使用者。",
"account.follows_you": "關注了你", "account.follows_you": "關注了你",
"account.hide_reblogs": "隱藏來自 @{name} 的轉推", "account.hide_reblogs": "隱藏來自 @{name} 的轉推",

@ -767,10 +767,3 @@ html {
.compose-form .compose-form__warning { .compose-form .compose-form__warning {
box-shadow: none; box-shadow: none;
} }
.audio-player .video-player__controls button,
.audio-player .video-player__time-sep,
.audio-player .video-player__time-current,
.audio-player .video-player__time-total {
color: $primary-text-color;
}

@ -157,6 +157,34 @@ class ActivityPub::Activity
fetch_remote_original_status fetch_remote_original_status
end end
def dereference_object!
return unless @object.is_a?(String)
return if invalid_origin?(@object)
object = fetch_resource(@object, true, signed_fetch_account)
return unless object.present? && object.is_a?(Hash) && supported_context?(object)
@object = object
end
def signed_fetch_account
first_mentioned_local_account || first_local_follower
end
def first_mentioned_local_account
audience = (as_array(@json['to']) + as_array(@json['cc'])).uniq
local_usernames = audience.select { |uri| ActivityPub::TagManager.instance.local_uri?(uri) }
.map { |uri| ActivityPub::TagManager.instance.uri_to_local_id(uri, :username) }
return if local_usernames.empty?
Account.local.where(username: local_usernames).first
end
def first_local_follower
@account.followers.local.first
end
def follow_request_from_object def follow_request_from_object
@follow_request ||= FollowRequest.find_by(target_account: @account, uri: object_uri) unless object_uri.nil? @follow_request ||= FollowRequest.find_by(target_account: @account, uri: object_uri) unless object_uri.nil?
end end

@ -4,15 +4,17 @@ class ActivityPub::Activity::Announce < ActivityPub::Activity
def perform def perform
return reject_payload! if delete_arrived_first?(@json['id']) || !related_to_local_activity? return reject_payload! if delete_arrived_first?(@json['id']) || !related_to_local_activity?
RedisLock.acquire(lock_options) do |lock|
if lock.acquired?
original_status = status_from_object original_status = status_from_object
return reject_payload! if original_status.nil? || !announceable?(original_status) return reject_payload! if original_status.nil? || !announceable?(original_status)
status = Status.find_by(account: @account, reblog: original_status) @status = Status.find_by(account: @account, reblog: original_status)
return status unless status.nil? return @status unless @status.nil?
status = Status.create!( @status = Status.create!(
account: @account, account: @account,
reblog: original_status, reblog: original_status,
uri: @json['id'], uri: @json['id'],
@ -21,8 +23,13 @@ class ActivityPub::Activity::Announce < ActivityPub::Activity
visibility: visibility_from_audience visibility: visibility_from_audience
) )
distribute(status) distribute(@status)
status else
raise Mastodon::RaceConditionError
end
end
@status
end end
private private
@ -54,4 +61,8 @@ class ActivityPub::Activity::Announce < ActivityPub::Activity
def reblog_of_local_status? def reblog_of_local_status?
status_from_uri(object_uri)&.account&.local? status_from_uri(object_uri)&.account&.local?
end end
def lock_options
{ redis: Redis.current, key: "announce:#{@object['id']}" }
end
end end

@ -4,7 +4,12 @@ class ActivityPub::Activity::Block < ActivityPub::Activity
def perform def perform
target_account = account_from_uri(object_uri) target_account = account_from_uri(object_uri)
return if target_account.nil? || !target_account.local? || @account.blocking?(target_account) return if target_account.nil? || !target_account.local?
if @account.blocking?(target_account)
@account.block_relationships.find_by(target_account: target_account).update(uri: @json['id']) if @json['id'].present?
return
end
UnfollowService.new.call(target_account, @account) if target_account.following?(@account) UnfollowService.new.call(target_account, @account) if target_account.following?(@account)

@ -2,6 +2,8 @@
class ActivityPub::Activity::Create < ActivityPub::Activity class ActivityPub::Activity::Create < ActivityPub::Activity
def perform def perform
dereference_object!
case @object['type'] case @object['type']
when 'EncryptedMessage' when 'EncryptedMessage'
create_encrypted_message create_encrypted_message

@ -13,11 +13,62 @@ class ActivityPub::Activity::Undo < ActivityPub::Activity
undo_like undo_like
when 'Block' when 'Block'
undo_block undo_block
when nil
handle_reference
end end
end end
private private
def handle_reference
# Some implementations do not inline the object, and as we don't have a
# global index, we have to guess what object it is.
return if object_uri.nil?
try_undo_announce || try_undo_accept || try_undo_follow || try_undo_like || try_undo_block || delete_later!(object_uri)
end
def try_undo_announce
status = Status.where.not(reblog_of_id: nil).find_by(uri: object_uri, account: @account)
if status.present?
RemoveStatusService.new.call(status)
true
else
false
end
end
def try_undo_accept
# We can't currently handle `Undo Accept` as we don't record `Accept`'s uri
false
end
def try_undo_follow
follow = @account.follow_requests.find_by(uri: object_uri) || @account.active_relationships.find_by(uri: object_uri)
if follow.present?
follow.destroy
true
else
false
end
end
def try_undo_like
# There is an index on accounts, but an account may have *many* favs, so this may be too costly
false
end
def try_undo_block
block = @account.block_relationships.find_by(uri: object_uri)
if block.present?
UnblockService.new.call(@account, block.target_account)
true
else
false
end
end
def undo_announce def undo_announce
return if object_uri.nil? return if object_uri.nil?

@ -4,6 +4,8 @@ class ActivityPub::Activity::Update < ActivityPub::Activity
SUPPORTED_TYPES = %w(Application Group Organization Person Service).freeze SUPPORTED_TYPES = %w(Application Group Organization Person Service).freeze
def perform def perform
dereference_object!
if equals_or_includes_any?(@object['type'], SUPPORTED_TYPES) if equals_or_includes_any?(@object['type'], SUPPORTED_TYPES)
update_account update_account
elsif equals_or_includes_any?(@object['type'], %w(Question)) elsif equals_or_includes_any?(@object['type'], %w(Question))

@ -7,6 +7,7 @@ module Mastodon
class HostValidationError < ValidationError; end class HostValidationError < ValidationError; end
class LengthValidationError < ValidationError; end class LengthValidationError < ValidationError; end
class DimensionsValidationError < ValidationError; end class DimensionsValidationError < ValidationError; end
class StreamValidationError < ValidationError; end
class RaceConditionError < Error; end class RaceConditionError < Error; end
class RateLimitExceededError < Error; end class RateLimitExceededError < Error; end

@ -139,9 +139,15 @@ class FeedManager
end end
def clear_from_timeline(account, target_account) def clear_from_timeline(account, target_account)
# Clear from timeline all statuses from or mentionning target_account
timeline_key = key(:home, account.id) timeline_key = key(:home, account.id)
timeline_status_ids = redis.zrange(timeline_key, 0, -1) timeline_status_ids = redis.zrange(timeline_key, 0, -1)
target_statuses = Status.where(id: timeline_status_ids, account: target_account) statuses = Status.where(id: timeline_status_ids).select(:id, :reblog_of_id, :account_id).to_a
reblogged_ids = Status.where(id: statuses.map(&:reblog_of_id).compact, account: target_account).pluck(:id)
with_mentions_ids = Mention.active.where(status_id: statuses.flat_map { |s| [s.id, s.reblog_of_id] }.compact, account: target_account).pluck(:status_id)
target_statuses = statuses.filter do |status|
status.account_id == target_account.id || reblogged_ids.include?(status.reblog_of_id) || with_mentions_ids.include?(status.id) || with_mentions_ids.include?(status.reblog_of_id)
end
target_statuses.each do |status| target_statuses.each do |status|
unpush_from_home(account, status) unpush_from_home(account, status)

@ -29,7 +29,7 @@ module Remotable
rescue Mastodon::UnexpectedResponseError, HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError => e rescue Mastodon::UnexpectedResponseError, HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError => e
Rails.logger.debug "Error fetching remote #{attachment_name}: #{e}" Rails.logger.debug "Error fetching remote #{attachment_name}: #{e}"
raise e unless suppress_errors raise e unless suppress_errors
rescue Paperclip::Errors::NotIdentifiedByImageMagickError, Addressable::URI::InvalidURIError, Mastodon::HostValidationError, Mastodon::LengthValidationError, Paperclip::Error, Mastodon::DimensionsValidationError => e rescue Paperclip::Errors::NotIdentifiedByImageMagickError, Addressable::URI::InvalidURIError, Mastodon::HostValidationError, Mastodon::LengthValidationError, Paperclip::Error, Mastodon::DimensionsValidationError, Mastodon::StreamValidationError => e
Rails.logger.debug "Error fetching remote #{attachment_name}: #{e}" Rails.logger.debug "Error fetching remote #{attachment_name}: #{e}"
end end

@ -336,6 +336,7 @@ class MediaAttachment < ApplicationRecord
return unless movie.valid? return unless movie.valid?
raise Mastodon::StreamValidationError, 'Video has no video stream' if movie.width.nil? || movie.frame_rate.nil?
raise Mastodon::DimensionsValidationError, "#{movie.width}x#{movie.height} videos are not supported" if movie.width * movie.height > MAX_VIDEO_MATRIX_LIMIT raise Mastodon::DimensionsValidationError, "#{movie.width}x#{movie.height} videos are not supported" if movie.width * movie.height > MAX_VIDEO_MATRIX_LIMIT
raise Mastodon::DimensionsValidationError, "#{movie.frame_rate.to_i}fps videos are not supported" if movie.frame_rate > MAX_VIDEO_FRAME_RATE raise Mastodon::DimensionsValidationError, "#{movie.frame_rate.to_i}fps videos are not supported" if movie.frame_rate > MAX_VIDEO_FRAME_RATE
end end

@ -4,7 +4,7 @@ class REST::MediaAttachmentSerializer < ActiveModel::Serializer
include RoutingHelper include RoutingHelper
attributes :id, :type, :url, :preview_url, attributes :id, :type, :url, :preview_url,
:remote_url, :text_url, :meta, :remote_url, :preview_remote_url, :text_url, :meta,
:description, :blurhash :description, :blurhash
def id def id
@ -35,6 +35,10 @@ class REST::MediaAttachmentSerializer < ActiveModel::Serializer
end end
end end
def preview_remote_url
object.thumbnail_remote_url.presence
end
def text_url def text_url
object.local? ? medium_url(object) : nil object.local? ? medium_url(object) : nil
end end

@ -12,7 +12,7 @@ class UpdateAccountService < BaseService
check_links(account) check_links(account)
process_hashtags(account) process_hashtags(account)
end end
rescue Mastodon::DimensionsValidationError => de rescue Mastodon::DimensionsValidationError, Mastodon::StreamValidationError => de
account.errors.add(:avatar, de.message) account.errors.add(:avatar, de.message)
false false
end end

@ -3,7 +3,7 @@
class ActivityPub::ProcessingWorker class ActivityPub::ProcessingWorker
include Sidekiq::Worker include Sidekiq::Worker
sidekiq_options backtrace: true sidekiq_options backtrace: true, retry: 8
def perform(account_id, body, delivered_to_account_id = nil) def perform(account_id, body, delivered_to_account_id = nil)
ActivityPub::ProcessCollectionService.new.call(body, Account.find(account_id), override_timestamps: true, delivered_to_account_id: delivered_to_account_id, delivery: true) ActivityPub::ProcessCollectionService.new.call(body, Account.find(account_id), override_timestamps: true, delivered_to_account_id: delivered_to_account_id, delivery: true)

@ -16,6 +16,12 @@ ingress:
kubernetes.io/ingress.class: nginx kubernetes.io/ingress.class: nginx
kubernetes.io/tls-acme: "true" kubernetes.io/tls-acme: "true"
# cert-manager.io/cluster-issuer: "letsencrypt" # cert-manager.io/cluster-issuer: "letsencrypt"
#
# ensure that NGINX's upload size matches Mastodon's
# for the K8s ingress controller:
# nginx.ingress.kubernetes.io/proxy-body-size: 40m
# for the NGINX ingress controller:
# nginx.org/client-max-body-size: 40m
# this value is used for LOCAL_DOMAIN # this value is used for LOCAL_DOMAIN
hostname: mastodon.local hostname: mastodon.local
tls: tls:

@ -18,7 +18,7 @@ module Paperclip
@type_from_mime_magic ||= begin @type_from_mime_magic ||= begin
begin begin
File.open(@file.path) do |file| File.open(@file.path) do |file|
MimeMagic.by_magic(file)&.type MimeMagic.by_magic(file)&.type || ''
end end
rescue Errno::ENOENT rescue Errno::ENOENT
'' ''

@ -110,7 +110,7 @@
"intl-relativeformat": "^6.4.3", "intl-relativeformat": "^6.4.3",
"is-nan": "^1.3.0", "is-nan": "^1.3.0",
"js-yaml": "^3.13.1", "js-yaml": "^3.13.1",
"lodash": "^4.17.14", "lodash": "^4.17.19",
"mark-loader": "^0.1.6", "mark-loader": "^0.1.6",
"marky": "^1.2.1", "marky": "^1.2.1",
"mini-css-extract-plugin": "^0.9.0", "mini-css-extract-plugin": "^0.9.0",

@ -5,6 +5,21 @@ RSpec.describe AccountsController, type: :controller do
let(:account) { Fabricate(:user).account } let(:account) { Fabricate(:user).account }
shared_examples 'cachable response' do
it 'does not set cookies' do
expect(response.cookies).to be_empty
expect(response.headers['Set-Cookies']).to be nil
end
it 'does not set sessions' do
expect(session).to be_empty
end
it 'returns public Cache-Control header' do
expect(response.headers['Cache-Control']).to include 'public'
end
end
describe 'GET #show' do describe 'GET #show' do
let(:format) { 'html' } let(:format) { 'html' }
@ -323,9 +338,7 @@ RSpec.describe AccountsController, type: :controller do
expect(response.content_type).to eq 'application/activity+json' expect(response.content_type).to eq 'application/activity+json'
end end
it 'returns public Cache-Control header' do it_behaves_like 'cachable response'
expect(response.headers['Cache-Control']).to include 'public'
end
it 'renders account' do it 'renders account' do
json = body_as_json json = body_as_json
@ -343,9 +356,7 @@ RSpec.describe AccountsController, type: :controller do
expect(response.content_type).to eq 'application/activity+json' expect(response.content_type).to eq 'application/activity+json'
end end
it 'returns public Cache-Control header' do it_behaves_like 'cachable response'
expect(response.headers['Cache-Control']).to include 'public'
end
it 'returns Vary header with Signature' do it 'returns Vary header with Signature' do
expect(response.headers['Vary']).to include 'Signature' expect(response.headers['Vary']).to include 'Signature'
@ -401,9 +412,7 @@ RSpec.describe AccountsController, type: :controller do
expect(response.content_type).to eq 'application/activity+json' expect(response.content_type).to eq 'application/activity+json'
end end
it 'returns public Cache-Control header' do it_behaves_like 'cachable response'
expect(response.headers['Cache-Control']).to include 'public'
end
it 'renders account' do it 'renders account' do
json = body_as_json json = body_as_json
@ -447,9 +456,7 @@ RSpec.describe AccountsController, type: :controller do
expect(response).to have_http_status(200) expect(response).to have_http_status(200)
end end
it 'returns public Cache-Control header' do it_behaves_like 'cachable response'
expect(response.headers['Cache-Control']).to include 'public'
end
end end
context do context do

@ -6,6 +6,21 @@ RSpec.describe ActivityPub::CollectionsController, type: :controller do
let!(:account) { Fabricate(:account) } let!(:account) { Fabricate(:account) }
let(:remote_account) { nil } let(:remote_account) { nil }
shared_examples 'cachable response' do
it 'does not set cookies' do
expect(response.cookies).to be_empty
expect(response.headers['Set-Cookies']).to be nil
end
it 'does not set sessions' do
expect(session).to be_empty
end
it 'returns public Cache-Control header' do
expect(response.headers['Cache-Control']).to include 'public'
end
end
before do before do
allow(controller).to receive(:signed_request_account).and_return(remote_account) allow(controller).to receive(:signed_request_account).and_return(remote_account)
@ -31,9 +46,7 @@ RSpec.describe ActivityPub::CollectionsController, type: :controller do
expect(response.content_type).to eq 'application/activity+json' expect(response.content_type).to eq 'application/activity+json'
end end
it 'returns public Cache-Control header' do it_behaves_like 'cachable response'
expect(response.headers['Cache-Control']).to include 'public'
end
it 'returns orderedItems with pinned statuses' do it 'returns orderedItems with pinned statuses' do
json = body_as_json json = body_as_json
@ -58,9 +71,7 @@ RSpec.describe ActivityPub::CollectionsController, type: :controller do
expect(response.content_type).to eq 'application/activity+json' expect(response.content_type).to eq 'application/activity+json'
end end
it 'returns public Cache-Control header' do it_behaves_like 'cachable response'
expect(response.headers['Cache-Control']).to include 'public'
end
it 'returns orderedItems with pinned statuses' do it 'returns orderedItems with pinned statuses' do
json = body_as_json json = body_as_json

@ -3,6 +3,21 @@ require 'rails_helper'
RSpec.describe ActivityPub::OutboxesController, type: :controller do RSpec.describe ActivityPub::OutboxesController, type: :controller do
let!(:account) { Fabricate(:account) } let!(:account) { Fabricate(:account) }
shared_examples 'cachable response' do
it 'does not set cookies' do
expect(response.cookies).to be_empty
expect(response.headers['Set-Cookies']).to be nil
end
it 'does not set sessions' do
expect(session).to be_empty
end
it 'returns public Cache-Control header' do
expect(response.headers['Cache-Control']).to include 'public'
end
end
before do before do
Fabricate(:status, account: account, visibility: :public) Fabricate(:status, account: account, visibility: :public)
Fabricate(:status, account: account, visibility: :unlisted) Fabricate(:status, account: account, visibility: :unlisted)
@ -39,9 +54,7 @@ RSpec.describe ActivityPub::OutboxesController, type: :controller do
expect(json[:totalItems]).to eq 4 expect(json[:totalItems]).to eq 4
end end
it 'returns public Cache-Control header' do it_behaves_like 'cachable response'
expect(response.headers['Cache-Control']).to include 'public'
end
end end
context 'with page requested' do context 'with page requested' do
@ -62,9 +75,7 @@ RSpec.describe ActivityPub::OutboxesController, type: :controller do
expect(json[:orderedItems].all? { |item| item[:to].include?(ActivityPub::TagManager::COLLECTIONS[:public]) || item[:cc].include?(ActivityPub::TagManager::COLLECTIONS[:public]) }).to be true expect(json[:orderedItems].all? { |item| item[:to].include?(ActivityPub::TagManager::COLLECTIONS[:public]) || item[:cc].include?(ActivityPub::TagManager::COLLECTIONS[:public]) }).to be true
end end
it 'returns public Cache-Control header' do it_behaves_like 'cachable response'
expect(response.headers['Cache-Control']).to include 'public'
end
end end
end end

@ -7,6 +7,21 @@ RSpec.describe ActivityPub::RepliesController, type: :controller do
let(:remote_reply_id) { nil } let(:remote_reply_id) { nil }
let(:remote_account) { nil } let(:remote_account) { nil }
shared_examples 'cachable response' do
it 'does not set cookies' do
expect(response.cookies).to be_empty
expect(response.headers['Set-Cookies']).to be nil
end
it 'does not set sessions' do
expect(session).to be_empty
end
it 'returns public Cache-Control header' do
expect(response.headers['Cache-Control']).to include 'public'
end
end
before do before do
allow(controller).to receive(:signed_request_account).and_return(remote_account) allow(controller).to receive(:signed_request_account).and_return(remote_account)
@ -36,9 +51,7 @@ RSpec.describe ActivityPub::RepliesController, type: :controller do
expect(response.content_type).to eq 'application/activity+json' expect(response.content_type).to eq 'application/activity+json'
end end
it 'returns public Cache-Control header' do it_behaves_like 'cachable response'
expect(response.headers['Cache-Control']).to include 'public'
end
it 'returns items with account\'s own replies' do it 'returns items with account\'s own replies' do
json = body_as_json json = body_as_json
@ -87,9 +100,7 @@ RSpec.describe ActivityPub::RepliesController, type: :controller do
expect(response.content_type).to eq 'application/activity+json' expect(response.content_type).to eq 'application/activity+json'
end end
it 'returns public Cache-Control header' do it_behaves_like 'cachable response'
expect(response.headers['Cache-Control']).to include 'public'
end
context 'without only_other_accounts' do context 'without only_other_accounts' do
it 'returns items with account\'s own replies' do it 'returns items with account\'s own replies' do

@ -5,6 +5,21 @@ require 'rails_helper'
describe StatusesController do describe StatusesController do
render_views render_views
shared_examples 'cachable response' do
it 'does not set cookies' do
expect(response.cookies).to be_empty
expect(response.headers['Set-Cookies']).to be nil
end
it 'does not set sessions' do
expect(session).to be_empty
end
it 'returns public Cache-Control header' do
expect(response.headers['Cache-Control']).to include 'public'
end
end
describe 'GET #show' do describe 'GET #show' do
let(:account) { Fabricate(:account) } let(:account) { Fabricate(:account) }
let(:status) { Fabricate(:status, account: account) } let(:status) { Fabricate(:status, account: account) }
@ -80,9 +95,7 @@ describe StatusesController do
expect(response.headers['Vary']).to eq 'Accept' expect(response.headers['Vary']).to eq 'Accept'
end end
it 'returns public Cache-Control header' do it_behaves_like 'cachable response'
expect(response.headers['Cache-Control']).to include 'public'
end
it 'returns Content-Type header' do it 'returns Content-Type header' do
expect(response.headers['Content-Type']).to include 'application/activity+json' expect(response.headers['Content-Type']).to include 'application/activity+json'
@ -470,9 +483,7 @@ describe StatusesController do
expect(response.headers['Vary']).to eq 'Accept' expect(response.headers['Vary']).to eq 'Accept'
end end
it 'returns public Cache-Control header' do it_behaves_like 'cachable response'
expect(response.headers['Cache-Control']).to include 'public'
end
it 'returns Content-Type header' do it 'returns Content-Type header' do
expect(response.headers['Content-Type']).to include 'application/activity+json' expect(response.headers['Content-Type']).to include 'application/activity+json'

@ -28,6 +28,28 @@ RSpec.describe ActivityPub::Activity::Block do
end end
end end
context 'when the recipient is already blocked' do
before do
sender.block!(recipient, uri: 'old')
end
describe '#perform' do
subject { described_class.new(json, sender) }
before do
subject.perform
end
it 'creates a block from sender to recipient' do
expect(sender.blocking?(recipient)).to be true
end
it 'sets the uri to that of last received block activity' do
expect(sender.block_relationships.find_by(target_account: recipient).uri).to eq 'foo'
end
end
end
context 'when the recipient follows the sender' do context 'when the recipient follows the sender' do
before do before do
recipient.follow!(sender) recipient.follow!(sender)

@ -50,6 +50,19 @@ RSpec.describe ActivityPub::Activity::Undo do
expect(sender.reblogged?(status)).to be false expect(sender.reblogged?(status)).to be false
end end
end end
context 'with only object uri' do
let(:object_json) { 'bar' }
before do
Fabricate(:status, reblog: status, account: sender, uri: 'bar')
end
it 'deletes the reblog by uri' do
subject.perform
expect(sender.reblogged?(status)).to be false
end
end
end end
context 'with Accept' do context 'with Accept' do
@ -91,14 +104,23 @@ RSpec.describe ActivityPub::Activity::Undo do
end end
before do before do
sender.block!(recipient) sender.block!(recipient, uri: 'bar')
end
it 'deletes block from sender to recipient' do
subject.perform
expect(sender.blocking?(recipient)).to be false
end end
context 'with only object uri' do
let(:object_json) { 'bar' }
it 'deletes block from sender to recipient' do it 'deletes block from sender to recipient' do
subject.perform subject.perform
expect(sender.blocking?(recipient)).to be false expect(sender.blocking?(recipient)).to be false
end end
end end
end
context 'with Follow' do context 'with Follow' do
let(:recipient) { Fabricate(:account) } let(:recipient) { Fabricate(:account) }
@ -113,14 +135,23 @@ RSpec.describe ActivityPub::Activity::Undo do
end end
before do before do
sender.follow!(recipient) sender.follow!(recipient, uri: 'bar')
end
it 'deletes follow from sender to recipient' do
subject.perform
expect(sender.following?(recipient)).to be false
end end
context 'with only object uri' do
let(:object_json) { 'bar' }
it 'deletes follow from sender to recipient' do it 'deletes follow from sender to recipient' do
subject.perform subject.perform
expect(sender.following?(recipient)).to be false expect(sender.following?(recipient)).to be false
end end
end end
end
context 'with Like' do context 'with Like' do
let(:status) { Fabricate(:status) } let(:status) { Fabricate(:status) }

@ -531,4 +531,29 @@ RSpec.describe FeedManager do
expect(Redis.current).to have_received(:publish).with("timeline:#{receiver.id}", deletion) expect(Redis.current).to have_received(:publish).with("timeline:#{receiver.id}", deletion)
end end
end end
describe '#clear_from_timeline' do
let(:account) { Fabricate(:account) }
let(:followed_account) { Fabricate(:account) }
let(:target_account) { Fabricate(:account) }
let(:status_1) { Fabricate(:status, account: followed_account) }
let(:status_2) { Fabricate(:status, account: target_account) }
let(:status_3) { Fabricate(:status, account: followed_account, mentions: [Fabricate(:mention, account: target_account)]) }
let(:status_4) { Fabricate(:status, mentions: [Fabricate(:mention, account: target_account)]) }
let(:status_5) { Fabricate(:status, account: followed_account, reblog: status_4) }
let(:status_6) { Fabricate(:status, account: followed_account, reblog: status_2) }
let(:status_7) { Fabricate(:status, account: followed_account) }
before do
[status_1, status_3, status_5, status_6, status_7].each do |status|
Redis.current.zadd("feed:home:#{account.id}", status.id, status.id)
end
end
it 'correctly cleans the timeline' do
FeedManager.instance.clear_from_timeline(account, target_account)
expect(Redis.current.zrange("feed:home:#{account.id}", 0, -1)).to eq [status_1.id.to_s, status_7.id.to_s]
end
end
end end

@ -6979,10 +6979,10 @@ lodash.uniq@^4.5.0:
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.3.0, lodash@~4.17.12: lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.3.0, lodash@~4.17.12:
version "4.17.15" version "4.17.19"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b"
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==
loglevel@^1.6.8: loglevel@^1.6.8:
version "1.6.8" version "1.6.8"

Loading…
Cancel
Save