From f2d71eae4b635fe0e35662b9aee17d98a4f0c2da Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 4 Jan 2018 01:21:38 +0100 Subject: [PATCH 01/15] Cache JSON of immutable ActivityPub representations (#6171) --- app/controllers/accounts_controller.rb | 12 ++++++---- .../activitypub/follows_controller.rb | 22 ++++++++++------- app/controllers/application_controller.rb | 14 ++++++++++- app/controllers/emojis_controller.rb | 10 ++++---- app/controllers/statuses_controller.rb | 24 ++++++++----------- 5 files changed, 49 insertions(+), 33 deletions(-) diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index 75915b3371..69fd20e27f 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -2,7 +2,8 @@ class AccountsController < ApplicationController include AccountControllerConcern - include SignatureVerification + + before_action :set_cache_headers def show respond_to do |format| @@ -26,10 +27,11 @@ class AccountsController < ApplicationController end format.json do - render json: @account, - serializer: ActivityPub::ActorSerializer, - adapter: ActivityPub::Adapter, - content_type: 'application/activity+json' + skip_session! + + render_cached_json(['activitypub', 'actor', @account.cache_key], content_type: 'application/activity+json') do + ActiveModelSerializers::SerializableResource.new(@account, serializer: ActivityPub::ActorSerializer, adapter: ActivityPub::Adapter) + end end end end diff --git a/app/controllers/activitypub/follows_controller.rb b/app/controllers/activitypub/follows_controller.rb index 8b1cddeb4d..038bcbabc2 100644 --- a/app/controllers/activitypub/follows_controller.rb +++ b/app/controllers/activitypub/follows_controller.rb @@ -4,15 +4,19 @@ class ActivityPub::FollowsController < Api::BaseController include SignatureVerification def show - render( - json: FollowRequest.includes(:account).references(:account).find_by!( - id: params.require(:id), - accounts: { domain: nil, username: params.require(:account_username) }, - target_account: signed_request_account - ), - serializer: ActivityPub::FollowSerializer, - adapter: ActivityPub::Adapter, - content_type: 'application/activity+json' + render json: follow_request, + serializer: ActivityPub::FollowSerializer, + adapter: ActivityPub::Adapter, + content_type: 'application/activity+json' + end + + private + + def follow_request + FollowRequest.includes(:account).references(:account).find_by!( + id: params.require(:id), + accounts: { domain: nil, username: params.require(:account_username) }, + target_account: signed_request_account ) end end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 51a978f440..e17d1f26e3 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -123,11 +123,23 @@ class ApplicationController < ActionController::Base end def render_cached_json(cache_key, **options) + options[:expires_in] ||= 3.minutes + cache_key = cache_key.join(':') if cache_key.is_a?(Enumerable) + content_type = options.delete(:content_type) || 'application/json' + data = Rails.cache.fetch(cache_key, { raw: true }.merge(options)) do yield.to_json end expires_in options[:expires_in], public: true - render json: data + render json: data, content_type: content_type + end + + def set_cache_headers + response.headers['Vary'] = 'Accept' + end + + def skip_session! + request.session_options[:skip] = true end end diff --git a/app/controllers/emojis_controller.rb b/app/controllers/emojis_controller.rb index a82b9340bf..c9725ccc0d 100644 --- a/app/controllers/emojis_controller.rb +++ b/app/controllers/emojis_controller.rb @@ -2,14 +2,16 @@ class EmojisController < ApplicationController before_action :set_emoji + before_action :set_cache_headers def show respond_to do |format| format.json do - render json: @emoji, - serializer: ActivityPub::EmojiSerializer, - adapter: ActivityPub::Adapter, - content_type: 'application/activity+json' + skip_session! + + render_cached_json(['activitypub', 'emoji', @emoji.cache_key], content_type: 'application/activity+json') do + ActiveModelSerializers::SerializableResource.new(@emoji, serializer: ActivityPub::EmojiSerializer, adapter: ActivityPub::Adapter) + end end end end diff --git a/app/controllers/statuses_controller.rb b/app/controllers/statuses_controller.rb index c00b9f034e..1a440fd599 100644 --- a/app/controllers/statuses_controller.rb +++ b/app/controllers/statuses_controller.rb @@ -10,7 +10,7 @@ class StatusesController < ApplicationController before_action :set_link_headers before_action :check_account_suspension before_action :redirect_to_original, only: [:show] - before_action { response.headers['Vary'] = 'Accept' } + before_action :set_cache_headers def show respond_to do |format| @@ -22,25 +22,21 @@ class StatusesController < ApplicationController end format.json do - render json: @status, - serializer: ActivityPub::NoteSerializer, - adapter: ActivityPub::Adapter, - content_type: 'application/activity+json' - - # Allow HTTP caching for 3 minutes if the status is public - unless @stream_entry.hidden? - request.session_options[:skip] = true - expires_in(3.minutes, public: true) + skip_session! unless @stream_entry.hidden? + + render_cached_json(['activitypub', 'note', @status.cache_key], content_type: 'application/activity+json') do + ActiveModelSerializers::SerializableResource.new(@status, serializer: ActivityPub::NoteSerializer, adapter: ActivityPub::Adapter) end end end end def activity - render json: @status, - serializer: ActivityPub::ActivitySerializer, - adapter: ActivityPub::Adapter, - content_type: 'application/activity+json' + skip_session! + + render_cached_json(['activitypub', 'activity', @status.cache_key], content_type: 'application/activity+json') do + ActiveModelSerializers::SerializableResource.new(@status, serializer: ActivityPub::ActivitySerializer, adapter: ActivityPub::Adapter) + end end def embed From 321be04a5f0c14d873e98683d79f3fa6e14c352c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 4 Jan 2018 02:56:00 +0100 Subject: [PATCH 02/15] Fix OpenSSL dependency in ostatus2 (#6174) --- Gemfile.lock | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 1b7af06a49..f3887b2b8a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -299,13 +299,11 @@ GEM sidekiq (>= 3.5.0) statsd-ruby (~> 1.2.0) oj (3.3.9) - openssl (2.0.6) orm_adapter (0.5.0) - ostatus2 (2.0.1) + ostatus2 (2.0.2) addressable (~> 2.4) http (~> 2.0) nokogiri (~> 1.6) - openssl (~> 2.0) ox (2.8.2) paperclip (5.1.0) activemodel (>= 4.2.0) From 73e1c12daaf8c8cac980d6e5c7456bf2346cd2d4 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 4 Jan 2018 02:56:23 +0100 Subject: [PATCH 03/15] Fix nil error in log_target_from_history helper (#6173) --- app/helpers/admin/action_logs_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/helpers/admin/action_logs_helper.rb b/app/helpers/admin/action_logs_helper.rb index e85243e57e..4475034a50 100644 --- a/app/helpers/admin/action_logs_helper.rb +++ b/app/helpers/admin/action_logs_helper.rb @@ -34,7 +34,7 @@ module Admin::ActionLogsHelper link_to attributes['domain'], "https://#{attributes['domain']}" when 'Status' tmp_status = Status.new(attributes) - link_to tmp_status.account.acct, TagManager.instance.url_for(tmp_status) + link_to tmp_status.account&.acct || "##{tmp_status.account_id}", TagManager.instance.url_for(tmp_status) end end From b080a075509c208d78f788ebd9ebf6579b27b69a Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Thu, 4 Jan 2018 10:56:54 +0900 Subject: [PATCH 04/15] Rearrange items in Getting Started navigation (#6126) Though the subsections are representing features such as navigation and settings, they are categorized by the ways how they are implemented (internal navigation or external links.) They are irrelevant and some arrangements were confusing because of that. (It is nonsense that instance information is in settings subsection, for example.) This fixes the issue by rearranging. --- .../mastodon/features/getting_started/index.js | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/app/javascript/mastodon/features/getting_started/index.js b/app/javascript/mastodon/features/getting_started/index.js index 3c1619c240..ee789e1809 100644 --- a/app/javascript/mastodon/features/getting_started/index.js +++ b/app/javascript/mastodon/features/getting_started/index.js @@ -70,30 +70,28 @@ export default class GettingStarted extends ImmutablePureComponent { navItems.push( , - , - + ); if (myAccount.get('locked')) { - navItems.push(); + navItems.push(); } - navItems.push( - , - - ); - if (multiColumn) { - navItems.push(); + navItems.push(); } + navItems.push(); + return (
{navItems} - + + +
From 289355749f1ec927e939786e894261d59dbbd2f8 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 4 Jan 2018 04:56:04 +0100 Subject: [PATCH 05/15] Fix FetchAtomService not finding alternatives if there's a Link header (#6170) without them, such as is the case with GNU social Fixes the ability to find GNU social accounts via URL in search and when using remote follow function --- app/services/fetch_atom_service.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/services/fetch_atom_service.rb b/app/services/fetch_atom_service.rb index 1c47a22da4..c01e8d071e 100644 --- a/app/services/fetch_atom_service.rb +++ b/app/services/fetch_atom_service.rb @@ -50,7 +50,7 @@ class FetchAtomService < BaseService @unsupported_activity = true nil end - elsif @response['Link'] && !terminal + elsif @response['Link'] && !terminal && link_header.find_link(%w(rel alternate)) process_headers elsif @response.mime_type == 'text/html' && !terminal process_html @@ -70,8 +70,6 @@ class FetchAtomService < BaseService end def process_headers - link_header = LinkHeader.parse(@response['Link'].is_a?(Array) ? @response['Link'].first : @response['Link']) - json_link = link_header.find_link(%w(rel alternate), %w(type application/activity+json)) || link_header.find_link(%w(rel alternate), ['type', 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"']) atom_link = link_header.find_link(%w(rel alternate), %w(type application/atom+xml)) @@ -80,4 +78,8 @@ class FetchAtomService < BaseService result end + + def link_header + @link_header ||= LinkHeader.parse(@response['Link'].is_a?(Array) ? @response['Link'].first : @response['Link']) + end end From 22e3acfd5656b5c2cf4e7b9460f9f9e43031a79f Mon Sep 17 00:00:00 2001 From: muan Date: Thu, 4 Jan 2018 12:00:50 +0800 Subject: [PATCH 06/15] Improve Traditional Chinese translation (#6166) * Improve Traditional Chinese translations * Sort alphabetically --- app/javascript/mastodon/locales/zh-TW.json | 24 +++++++------- config/locales/simple_form.zh-TW.yml | 11 ++++++- config/locales/zh-TW.yml | 37 ++++++++++++++++++---- 3 files changed, 52 insertions(+), 20 deletions(-) diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json index 876fb0e138..65b174ab5e 100644 --- a/app/javascript/mastodon/locales/zh-TW.json +++ b/app/javascript/mastodon/locales/zh-TW.json @@ -64,8 +64,8 @@ "confirmations.block.message": "你確定要封鎖 {name} ?", "confirmations.delete.confirm": "刪除", "confirmations.delete.message": "你確定要刪除這個狀態?", - "confirmations.delete_list.confirm": "Delete", - "confirmations.delete_list.message": "Are you sure you want to permanently delete this list?", + "confirmations.delete_list.confirm": "刪除", + "confirmations.delete_list.message": "確定要永久性地刪除這個名單嗎?", "confirmations.domain_block.confirm": "隱藏整個網域", "confirmations.domain_block.message": "你真的真的確定要隱藏整個 {domain} ?多數情況下,比較推薦封鎖或消音幾個特定目標就好。", "confirmations.mute.confirm": "消音", @@ -128,14 +128,14 @@ "lightbox.close": "關閉", "lightbox.next": "繼續", "lightbox.previous": "回退", - "lists.account.add": "Add to list", - "lists.account.remove": "Remove from list", - "lists.delete": "Delete list", - "lists.edit": "Edit list", - "lists.new.create": "Add list", - "lists.new.title_placeholder": "New list title", - "lists.search": "Search among people you follow", - "lists.subheading": "Your lists", + "lists.account.add": "加到名單裡", + "lists.account.remove": "從名單中移除", + "lists.delete": "刪除名單", + "lists.edit": "修改名單", + "lists.new.create": "新增名單", + "lists.new.title_placeholder": "名單名稱", + "lists.search": "搜尋您關注的使用者", + "lists.subheading": "您的名單", "loading_indicator.label": "讀取中...", "media_gallery.toggle_visible": "切換可見性", "missing_indicator.label": "找不到", @@ -146,8 +146,8 @@ "navigation_bar.favourites": "最愛", "navigation_bar.follow_requests": "關注請求", "navigation_bar.info": "關於本站", - "navigation_bar.keyboard_shortcuts": "Keyboard shortcuts", - "navigation_bar.lists": "Lists", + "navigation_bar.keyboard_shortcuts": "快速鍵", + "navigation_bar.lists": "名單", "navigation_bar.logout": "登出", "navigation_bar.mutes": "消音的使用者", "navigation_bar.pins": "置頂貼文", diff --git a/config/locales/simple_form.zh-TW.yml b/config/locales/simple_form.zh-TW.yml index c82f07e2dc..b5edaea729 100644 --- a/config/locales/simple_form.zh-TW.yml +++ b/config/locales/simple_form.zh-TW.yml @@ -21,7 +21,7 @@ zh-TW: data: 資料 display_name: 顯示名稱 email: 電子信箱 - filtered_languages: 封鎖下面语言的文章 + filtered_languages: 封鎖下面語言的文章 header: 個人頁面頂部 locale: 語言 locked: 將帳號轉為「私密」 @@ -29,7 +29,16 @@ zh-TW: note: 簡介 otp_attempt: 雙因子驗證碼 password: 密碼 + setting_auto_play_gif: 自動播放 GIFs + setting_boost_modal: 轉推前跳出確認視窗 setting_default_privacy: 文章預設隱私度 + setting_default_sensitive: 預設我的內容為敏感內容 + setting_delete_modal: 刪推前跳出確認視窗 + setting_noindex: 不被搜尋引擎檢索 + setting_reduce_motion: 減低動畫效果 + setting_system_font_ui: 使用系統預設字體 + setting_theme: 網站主題 + setting_unfollow_modal: 取消關注前跳出確認視窗 type: 匯入資料類型 username: 使用者名稱 interactions: diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index 7a66a64cad..e73dbf9ccf 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -55,7 +55,7 @@ zh-TW: perform_full_suspension: 進行停權 profile_url: 個人檔案網址 public: 公開 - push_subscription_expires: PuSH 訂閱逾期 + push_subscription_expires: 推播訂閱過期 salmon_url: Salmon URL silence: 靜音 statuses: 狀態 @@ -133,12 +133,14 @@ zh-TW: forgot_password: 忘記密碼? login: 登入 logout: 登出 + migrate_account: 轉移到另一個帳號 + migrate_account_html: 想要將這個帳號指向另一個帳號可到到這裡設定。 register: 註冊 resend_confirmation: 重寄驗證信 reset_password: 重設密碼 set_new_password: 設定新密碼 authorize_follow: - error: 對不起,尋找這個跨站使用者的過程發生錯誤 + error: 對不起,搜尋遠端使用者出現錯誤 follow: 關注 title: 關注 %{acct} datetime: @@ -165,7 +167,16 @@ zh-TW: blocks: 您封鎖的使用者 csv: CSV follows: 您關注的使用者 + mutes: 您靜音的使用者 storage: 儲存空間大小 + followers: + domain: 網域 + explanation_html: 為確保個人隱私,您必須知道有哪些使用者正關注你。您的私密內容會被發送到所有您有被關注的服務站上。如果您不信任這些服務站的管理者,您可以選擇檢查或刪除您的關注者。 + followers_count: 關注者數 + lock_link: 鎖住你的帳號 + purge: 移除關注者 + unlocked_warning_html: 所有人都可以關注並檢索你的隱藏狀態。%{lock_link}以檢查或拒絕關注。 + unlocked_warning_title: 你的帳號是公開的 generic: changes_saved_msg: 已成功儲存修改 powered_by: 網站由 %{link} 開發 @@ -179,6 +190,7 @@ zh-TW: types: blocking: 您封鎖的使用者名單 following: 您關注的使用者名單 + muting: 您靜音的使用者名單 upload: 上傳 landing_strip_html: "%{name} 是一個在 %{link_to_root_path} 的使用者。只要您有任何 Mastodon 服務站、或者聯盟網站的帳號,便可以跨站關注此站使用者,或者與他們互動。" landing_strip_signup_html: 如果您沒有這些帳號,歡迎在這裡註冊。 @@ -231,15 +243,26 @@ zh-TW: missing_resource: 無法找到資源 proceed: 下一步 prompt: 您希望關注︰ + sessions: + activity: 最近活動 + browser: 瀏覽器 + current_session: 目前的 session + description: "%{platform} 上的 %{browser}" + explanation: 這些是現在正登入於你的 Mastodon 帳號的瀏覽器。 + revoke: 取消 + revoke_success: Session 取消成功。 settings: authorized_apps: 已授權應用程式 back: 回到 Mastodon + development: 開發 edit_profile: 修改個人資料 export: 匯出 + followers: 授權追蹤者 import: 匯入 + notifications: 通知 preferences: 偏好設定 settings: 設定 - two_factor_authentication: 雙因子認證 + two_factor_authentication: 兩階段認證 statuses: open_in_web: 以網頁開啟 over_character_limit: 超過了 %{max} 字的限制 @@ -257,14 +280,14 @@ zh-TW: default: "%Y年%-m月%d日 %H:%M" two_factor_authentication: code_hint: 請輸入您認證器產生的代碼,以進行認證 - description_html: 當您啟用雙因子認證後,您登入時將需要使您手機、或其他種類認證器產生的代碼。 + description_html: 啟用兩階段認證後,登入時將需要使手機、或其他種類認證器產生的代碼。 disable: 停用 enable: 啟用 - enabled_success: 已成功啟用雙因子認證 - instructions_html: "請用您手機的認證器應用程式(如 Google Authenticator、Authy),掃描這裡的 QR 圖形碼。在雙因子認證啟用後,您登入時將須要使用此應用程式產生的認證碼。" + enabled_success: 已成功啟用兩階段認證 + instructions_html: "請用您手機的認證器應用程式(如 Google Authenticator、Authy),掃描這裡的 QR 圖形碼。在兩階段認證啟用後,您登入時將須要使用此應用程式產生的認證碼。" manual_instructions: 如果您無法掃描 QR 圖形碼,請手動輸入︰ setup: 設定 wrong_code: 您輸入的認證碼並不正確!可能伺服器時間和您手機不一致,請檢查您手機的時間,或與本站管理員聯絡。 users: invalid_email: 信箱地址格式不正確 - invalid_otp_token: 雙因子認證碼不正確 + invalid_otp_token: 兩階段認證碼不正確 From 662fa866eed476b43c34f2ef34f0c2ccc101b807 Mon Sep 17 00:00:00 2001 From: ThibG Date: Thu, 4 Jan 2018 14:39:38 +0100 Subject: [PATCH 07/15] Make sure private toots remain private and do not end up in HTTP caches (#6175) --- app/controllers/application_controller.rb | 3 ++- app/controllers/statuses_controller.rb | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index e17d1f26e3..f59f2725b6 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -124,6 +124,7 @@ class ApplicationController < ActionController::Base def render_cached_json(cache_key, **options) options[:expires_in] ||= 3.minutes + options[:public] ||= true cache_key = cache_key.join(':') if cache_key.is_a?(Enumerable) content_type = options.delete(:content_type) || 'application/json' @@ -131,7 +132,7 @@ class ApplicationController < ActionController::Base yield.to_json end - expires_in options[:expires_in], public: true + expires_in options[:expires_in], public: options[:public] render json: data, content_type: content_type end diff --git a/app/controllers/statuses_controller.rb b/app/controllers/statuses_controller.rb index 1a440fd599..367ea34e78 100644 --- a/app/controllers/statuses_controller.rb +++ b/app/controllers/statuses_controller.rb @@ -24,7 +24,7 @@ class StatusesController < ApplicationController format.json do skip_session! unless @stream_entry.hidden? - render_cached_json(['activitypub', 'note', @status.cache_key], content_type: 'application/activity+json') do + render_cached_json(['activitypub', 'note', @status.cache_key], content_type: 'application/activity+json', public: !@stream_entry.hidden?) do ActiveModelSerializers::SerializableResource.new(@status, serializer: ActivityPub::NoteSerializer, adapter: ActivityPub::Adapter) end end @@ -34,7 +34,7 @@ class StatusesController < ApplicationController def activity skip_session! - render_cached_json(['activitypub', 'activity', @status.cache_key], content_type: 'application/activity+json') do + render_cached_json(['activitypub', 'activity', @status.cache_key], content_type: 'application/activity+json', public: !@stream_entry.hidden?) do ActiveModelSerializers::SerializableResource.new(@status, serializer: ActivityPub::ActivitySerializer, adapter: ActivityPub::Adapter) end end From c647ce902b110a856c772d70b8e76b977afc0e83 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 4 Jan 2018 14:40:49 +0100 Subject: [PATCH 08/15] Send one Delete of Actor in ActivityPub when account is suspended (#6172) --- .../activitypub/delete_actor_serializer.rb | 22 +++++++++++ app/services/batched_remove_status_service.rb | 38 +------------------ app/services/suspend_account_service.rb | 12 ++++++ 3 files changed, 35 insertions(+), 37 deletions(-) create mode 100644 app/serializers/activitypub/delete_actor_serializer.rb diff --git a/app/serializers/activitypub/delete_actor_serializer.rb b/app/serializers/activitypub/delete_actor_serializer.rb new file mode 100644 index 0000000000..dfea9db4ab --- /dev/null +++ b/app/serializers/activitypub/delete_actor_serializer.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +class ActivityPub::DeleteActorSerializer < ActiveModel::Serializer + attributes :id, :type, :actor + attribute :virtual_object, key: :object + + def id + [ActivityPub::TagManager.instance.uri_for(object), '#delete'].join + end + + def type + 'Delete' + end + + def actor + ActivityPub::TagManager.instance.uri_for(object) + end + + def virtual_object + actor + end +end diff --git a/app/services/batched_remove_status_service.rb b/app/services/batched_remove_status_service.rb index 6b6b0c418d..e2763c2b9d 100644 --- a/app/services/batched_remove_status_service.rb +++ b/app/services/batched_remove_status_service.rb @@ -17,9 +17,7 @@ class BatchedRemoveStatusService < BaseService @stream_entry_batches = [] @salmon_batches = [] - @activity_json_batches = [] @json_payloads = statuses.map { |s| [s.id, Oj.dump(event: :delete, payload: s.id.to_s)] }.to_h - @activity_json = {} @activity_xml = {} # Ensure that rendered XML reflects destroyed state @@ -32,10 +30,7 @@ class BatchedRemoveStatusService < BaseService unpush_from_home_timelines(account, account_statuses) unpush_from_list_timelines(account, account_statuses) - if account.local? - batch_stream_entries(account, account_statuses) - batch_activity_json(account, account_statuses) - end + batch_stream_entries(account, account_statuses) if account.local? end # Cannot be batched @@ -46,7 +41,6 @@ class BatchedRemoveStatusService < BaseService Pubsubhubbub::RawDistributionWorker.push_bulk(@stream_entry_batches) { |batch| batch } NotificationWorker.push_bulk(@salmon_batches) { |batch| batch } - ActivityPub::DeliveryWorker.push_bulk(@activity_json_batches) { |batch| batch } end private @@ -57,22 +51,6 @@ class BatchedRemoveStatusService < BaseService end end - def batch_activity_json(account, statuses) - account.followers.inboxes.each do |inbox_url| - statuses.each do |status| - @activity_json_batches << [build_json(status), account.id, inbox_url] - end - end - - statuses.each do |status| - other_recipients = (status.mentions + status.reblogs).map(&:account).reject(&:local?).select(&:activitypub?).uniq(&:id) - - other_recipients.each do |target_account| - @activity_json_batches << [build_json(status), account.id, target_account.inbox_url] - end - end - end - def unpush_from_home_timelines(account, statuses) recipients = account.followers.local.to_a @@ -123,23 +101,9 @@ class BatchedRemoveStatusService < BaseService Redis.current end - def build_json(status) - return @activity_json[status.id] if @activity_json.key?(status.id) - - @activity_json[status.id] = sign_json(status, ActiveModelSerializers::SerializableResource.new( - status, - serializer: status.reblog? ? ActivityPub::UndoAnnounceSerializer : ActivityPub::DeleteSerializer, - adapter: ActivityPub::Adapter - ).as_json) - end - def build_xml(stream_entry) return @activity_xml[stream_entry.id] if @activity_xml.key?(stream_entry.id) @activity_xml[stream_entry.id] = stream_entry_to_xml(stream_entry) end - - def sign_json(status, json) - Oj.dump(ActivityPub::LinkedDataSignature.new(json).sign!(status.account)) - end end diff --git a/app/services/suspend_account_service.rb b/app/services/suspend_account_service.rb index 958b28cdcf..56fa2d8dd1 100644 --- a/app/services/suspend_account_service.rb +++ b/app/services/suspend_account_service.rb @@ -22,6 +22,8 @@ class SuspendAccountService < BaseService end def purge_content! + ActivityPub::RawDistributionWorker.perform_async(delete_actor_json, @account.id) if @account.local? + @account.statuses.reorder(nil).find_in_batches do |statuses| BatchedRemoveStatusService.new.call(statuses) end @@ -54,4 +56,14 @@ class SuspendAccountService < BaseService def destroy_all(association) association.in_batches.destroy_all end + + def delete_actor_json + payload = ActiveModelSerializers::SerializableResource.new( + @account, + serializer: ActivityPub::DeleteActorSerializer, + adapter: ActivityPub::Adapter + ).as_json + + Oj.dump(ActivityPub::LinkedDataSignature.new(payload).sign!(@account)) + end end From 1f2034932ba0f6975f933b3b5712641a3cb67724 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Miko=C5=82ajczak?= Date: Thu, 4 Jan 2018 15:15:29 +0100 Subject: [PATCH 09/15] i18n: Update Polish translation (#6176) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcin Mikołajczak --- config/locales/pl.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/locales/pl.yml b/config/locales/pl.yml index fd5177a965..94bd0a5926 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -160,6 +160,7 @@ pl: update_status: "%{name} zaktualizował wpis użytkownika %{target}" title: Dziennik działań administracyjnych custom_emojis: + by_domain: Według domeny copied_msg: Pomyślnie utworzono lokalną kopię emoji copy: Kopiuj copy_failed_msg: Nie udało się utworzyć lokalnej kopii emoji @@ -612,6 +613,7 @@ pl: private: Nie możesz przypiąć niepublicznego wpisu reblog: Nie możesz przypiąć podbicia wpisu show_more: Pokaż więcej + title: '%{name}: "%{quote}"' visibilities: private: Tylko dla śledzących private_long: Widoczne tylko dla osób, które Cię śledzą From f92399cfe7c2137cefc6f7d095e66273dcf1ebb7 Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Thu, 4 Jan 2018 23:36:55 +0900 Subject: [PATCH 10/15] Fallback default thumbnail in instance status API (#6177) --- app/helpers/routing_helper.rb | 5 +++++ app/serializers/rest/instance_serializer.rb | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app/helpers/routing_helper.rb b/app/helpers/routing_helper.rb index 11894a8952..998b7566fb 100644 --- a/app/helpers/routing_helper.rb +++ b/app/helpers/routing_helper.rb @@ -4,6 +4,7 @@ module RoutingHelper extend ActiveSupport::Concern include Rails.application.routes.url_helpers include ActionView::Helpers::AssetTagHelper + include Webpacker::Helper included do def default_url_options @@ -17,6 +18,10 @@ module RoutingHelper URI.join(root_url, source).to_s end + def full_pack_url(source, **options) + full_asset_url(asset_pack_path(source, options)) + end + private def use_storage? diff --git a/app/serializers/rest/instance_serializer.rb b/app/serializers/rest/instance_serializer.rb index 2898011fd8..ae1dbe6b59 100644 --- a/app/serializers/rest/instance_serializer.rb +++ b/app/serializers/rest/instance_serializer.rb @@ -27,7 +27,7 @@ class REST::InstanceSerializer < ActiveModel::Serializer end def thumbnail - full_asset_url(instance_presenter.thumbnail.file.url) if instance_presenter.thumbnail + instance_presenter.thumbnail ? full_asset_url(instance_presenter.thumbnail.file.url) : full_pack_url('preview.jpg') end def stats From a0273c2c5ef3b683170031163c83d971e4259550 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 4 Jan 2018 16:40:26 +0100 Subject: [PATCH 11/15] Bump version to 2.1.1 (#6164) --- lib/mastodon/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mastodon/version.rb b/lib/mastodon/version.rb index ca129da809..0077687694 100644 --- a/lib/mastodon/version.rb +++ b/lib/mastodon/version.rb @@ -13,7 +13,7 @@ module Mastodon end def patch - 0 + 1 end def pre From d2fcd64c318ca5f039d6fefb695c209a0833ec99 Mon Sep 17 00:00:00 2001 From: unarist Date: Fri, 5 Jan 2018 03:38:29 +0900 Subject: [PATCH 12/15] Use disable_ddl_transaction! to prevent warnings on migration (#6183) Migration is wrapped by transaction, so manual `commit_db_transaction` without transaction restarting causes "there is no transaction in progress" warnings. We should use `disable_ddl_transaction!` instead, if we can omit transaction completely. --- db/migrate/20171129172043_add_index_on_stream_entries.rb | 3 ++- .../20171226094803_more_faster_index_on_notifications.rb | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/db/migrate/20171129172043_add_index_on_stream_entries.rb b/db/migrate/20171129172043_add_index_on_stream_entries.rb index 478530c7fd..181c4f2882 100644 --- a/db/migrate/20171129172043_add_index_on_stream_entries.rb +++ b/db/migrate/20171129172043_add_index_on_stream_entries.rb @@ -1,6 +1,7 @@ class AddIndexOnStreamEntries < ActiveRecord::Migration[5.1] + disable_ddl_transaction! + def change - commit_db_transaction add_index :stream_entries, [:account_id, :activity_type, :id], algorithm: :concurrently remove_index :stream_entries, name: :index_stream_entries_on_account_id end diff --git a/db/migrate/20171226094803_more_faster_index_on_notifications.rb b/db/migrate/20171226094803_more_faster_index_on_notifications.rb index b2e53b82dd..0273a4e7c1 100644 --- a/db/migrate/20171226094803_more_faster_index_on_notifications.rb +++ b/db/migrate/20171226094803_more_faster_index_on_notifications.rb @@ -1,6 +1,7 @@ class MoreFasterIndexOnNotifications < ActiveRecord::Migration[5.1] + disable_ddl_transaction! + def change - commit_db_transaction add_index :notifications, [:account_id, :id], order: { id: :desc }, algorithm: :concurrently remove_index :notifications, name: :index_notifications_on_id_and_account_id_and_activity_type end From 9bef64b3d3d7e20841c87db8c059887ff8a7b809 Mon Sep 17 00:00:00 2001 From: Lynx Kotoura Date: Fri, 5 Jan 2018 03:38:46 +0900 Subject: [PATCH 13/15] Fix overflowing audit logs (#6184) --- app/javascript/styles/mastodon/admin.scss | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/javascript/styles/mastodon/admin.scss b/app/javascript/styles/mastodon/admin.scss index bddea557b7..0c343e1df1 100644 --- a/app/javascript/styles/mastodon/admin.scss +++ b/app/javascript/styles/mastodon/admin.scss @@ -398,10 +398,12 @@ } } + &__content { + max-width: calc(100% - 90px); + } + &__title { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; + word-wrap: break-word; } &__timestamp { @@ -415,7 +417,7 @@ color: $ui-primary-color; font-family: 'mastodon-font-monospace', monospace; font-size: 12px; - white-space: nowrap; + word-wrap: break-word; min-height: 20px; } From bc5487a1c2ccd9f440df2ac96e54ef8d241bdb9f Mon Sep 17 00:00:00 2001 From: Patrick Figel Date: Fri, 5 Jan 2018 00:15:35 +0100 Subject: [PATCH 14/15] Fix email confirmation link not updating email (#6187) A change introduced in #6125 prevents `Devise::Models::Confirmable#confirm` from being called for existing users, which in turn leads to `email` not being set to `unconfirmed_email`, breaking email updates. This also adds a test that would've caught this issue. --- app/models/user.rb | 8 ++-- .../auth/confirmations_controller_spec.rb | 40 ++++++++++++++----- spec/models/user_spec.rb | 8 ++++ 3 files changed, 42 insertions(+), 14 deletions(-) diff --git a/app/models/user.rb b/app/models/user.rb index a82a7d28a0..9459db7fe4 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -126,18 +126,18 @@ class User < ApplicationRecord end def confirm - return if confirmed? + new_user = !confirmed? super - update_statistics! + update_statistics! if new_user end def confirm! - return if confirmed? + new_user = !confirmed? skip_confirmation! save! - update_statistics! + update_statistics! if new_user end def promote! diff --git a/spec/controllers/auth/confirmations_controller_spec.rb b/spec/controllers/auth/confirmations_controller_spec.rb index 2ec36c060b..80a06c43ab 100644 --- a/spec/controllers/auth/confirmations_controller_spec.rb +++ b/spec/controllers/auth/confirmations_controller_spec.rb @@ -12,20 +12,40 @@ describe Auth::ConfirmationsController, type: :controller do end describe 'GET #show' do - let!(:user) { Fabricate(:user, confirmation_token: 'foobar', confirmed_at: nil) } + context 'when user is unconfirmed' do + let!(:user) { Fabricate(:user, confirmation_token: 'foobar', confirmed_at: nil) } - before do - allow(BootstrapTimelineWorker).to receive(:perform_async) - @request.env['devise.mapping'] = Devise.mappings[:user] - get :show, params: { confirmation_token: 'foobar' } - end + before do + allow(BootstrapTimelineWorker).to receive(:perform_async) + @request.env['devise.mapping'] = Devise.mappings[:user] + get :show, params: { confirmation_token: 'foobar' } + end + + it 'redirects to login' do + expect(response).to redirect_to(new_user_session_path) + end - it 'redirects to login' do - expect(response).to redirect_to(new_user_session_path) + it 'queues up bootstrapping of home timeline' do + expect(BootstrapTimelineWorker).to have_received(:perform_async).with(user.account_id) + end end - it 'queues up bootstrapping of home timeline' do - expect(BootstrapTimelineWorker).to have_received(:perform_async).with(user.account_id) + context 'when user is updating email' do + let!(:user) { Fabricate(:user, confirmation_token: 'foobar', unconfirmed_email: 'new-email@example.com') } + + before do + allow(BootstrapTimelineWorker).to receive(:perform_async) + @request.env['devise.mapping'] = Devise.mappings[:user] + get :show, params: { confirmation_token: 'foobar' } + end + + it 'redirects to login' do + expect(response).to redirect_to(new_user_session_path) + end + + it 'does not queue up bootstrapping of home timeline' do + expect(BootstrapTimelineWorker).to_not have_received(:perform_async) + end end end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 5ed7ed88b2..8171c939a9 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -148,6 +148,14 @@ RSpec.describe User, type: :model do end end + describe '#confirm' do + it 'sets email to unconfirmed_email' do + user = Fabricate.build(:user, confirmed_at: Time.now.utc, unconfirmed_email: 'new-email@example.com') + user.confirm + expect(user.email).to eq 'new-email@example.com' + end + end + describe '#disable_two_factor!' do it 'saves false for otp_required_for_login' do user = Fabricate.build(:user, otp_required_for_login: true) From fb3a2ddd24141e987c9c7f890d626183ec3d8783 Mon Sep 17 00:00:00 2001 From: Branko Kokanovic Date: Thu, 4 Jan 2018 23:16:06 +0000 Subject: [PATCH 15/15] Small translation fixes for Serbian (and sr@Latn too) (#6188) --- app/javascript/mastodon/locales/sr-Latn.json | 27 +++++++++++--------- app/javascript/mastodon/locales/sr.json | 24 ++++++++--------- config/locales/sr-Latn.yml | 6 ++--- config/locales/sr.yml | 6 ++--- 4 files changed, 33 insertions(+), 30 deletions(-) diff --git a/app/javascript/mastodon/locales/sr-Latn.json b/app/javascript/mastodon/locales/sr-Latn.json index 971ffb5c56..88631e332d 100644 --- a/app/javascript/mastodon/locales/sr-Latn.json +++ b/app/javascript/mastodon/locales/sr-Latn.json @@ -11,7 +11,7 @@ "account.media": "Mediji", "account.mention": "Pomeni korisnika @{name}", "account.moved_to": "{name} se pomerio na:", - "account.mute": "Mutiraj @{name}", + "account.mute": "Ućutkaj korisnika @{name}", "account.mute_notifications": "Isključi obaveštenja od korisnika @{name}", "account.posts": "Statusa", "account.report": "Prijavi @{name}", @@ -21,7 +21,7 @@ "account.unblock": "Odblokiraj korisnika @{name}", "account.unblock_domain": "Odblokiraj domen {domain}", "account.unfollow": "Otprati", - "account.unmute": "Odmutiraj @{name}", + "account.unmute": "Ukloni ućutkavanje korisniku @{name}", "account.unmute_notifications": "Uključi nazad obaveštenja od korisnika @{name}", "account.view_full_profile": "Vidi ceo profil", "boost_modal.combo": "Možete pritisnuti {combo} da preskočite ovo sledeći put", @@ -37,10 +37,10 @@ "column.follow_requests": "Zahtevi za praćenje", "column.home": "Početna", "column.lists": "Liste", - "column.mutes": "Mutirani korisnici", + "column.mutes": "Ućutkani korisnici", "column.notifications": "Obaveštenja", "column.pins": "Prikačeni tutovi", - "column.public": "Združena lajna", + "column.public": "Federisana lajna", "column_back_button.label": "Nazad", "column_header.hide_settings": "Sakrij postavke", "column_header.moveLeft_settings": "Pomeri kolonu ulevo", @@ -50,6 +50,7 @@ "column_header.unpin": "Otkači", "column_subheading.navigation": "Navigacija", "column_subheading.settings": "Postavke", + "compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.", "compose_form.lock_disclaimer": "Vaš nalog nije {locked}. Svako može da Vas zaprati i da vidi objave namenjene samo Vašim pratiocima.", "compose_form.lock_disclaimer.lock": "zaključan", "compose_form.placeholder": "Šta Vam je na umu?", @@ -66,9 +67,9 @@ "confirmations.delete_list.confirm": "Obriši", "confirmations.delete_list.message": "Da li ste sigurni da želite da bespovratno obrišete ovu listu?", "confirmations.domain_block.confirm": "Sakrij ceo domen", - "confirmations.domain_block.message": "Da li ste stvarno, stvarno sigurno da želite da blokirate ceo domen {domain}? U većini slučajeva, par dobrih blokiranja ili mutiranja su dovoljna i preporučljiva.", - "confirmations.mute.confirm": "Mutiraj", - "confirmations.mute.message": "Da li stvarno želite da mutirate korisnika {name}?", + "confirmations.domain_block.message": "Da li ste stvarno, stvarno sigurno da želite da blokirate ceo domen {domain}? U većini slučajeva, par dobrih blokiranja ili ućutkavanja su dovoljna i preporučljiva.", + "confirmations.mute.confirm": "Ućutkaj", + "confirmations.mute.message": "Da li stvarno želite da ućutkate korisnika {name}?", "confirmations.unfollow.confirm": "Otprati", "confirmations.unfollow.message": "Da li ste sigurni da želite da otpratite korisnika {name}?", "embed.instructions": "Ugradi ovaj status na Vaš veb sajt kopiranjem koda ispod.", @@ -148,10 +149,10 @@ "navigation_bar.keyboard_shortcuts": "Prečice na tastaturi", "navigation_bar.lists": "Liste", "navigation_bar.logout": "Odjava", - "navigation_bar.mutes": "Mutirani korisnici", + "navigation_bar.mutes": "Ućutkani korisnici", "navigation_bar.pins": "Prikačeni tutovi", "navigation_bar.preferences": "Podešavanja", - "navigation_bar.public_timeline": "Združena lajna", + "navigation_bar.public_timeline": "Federisana lajna", "notification.favourite": "{name} je stavio Vaš status kao omiljeni", "notification.follow": "{name} Vas je zapratio", "notification.mention": "{name} Vas je pomenuo", @@ -169,7 +170,7 @@ "notifications.column_settings.sound": "Puštaj zvuk", "onboarding.done": "Gotovo", "onboarding.next": "Sledeće", - "onboarding.page_five.public_timelines": "Lokalna lajna prikazuje sve javne statuse od svih na domenu {domain}. Združena lajna prikazuje javne statuse od svih ljudi koje prate korisnici sa domena {domain}. Ovo su javne lajne, sjajan način da otkrijete nove ljude.", + "onboarding.page_five.public_timelines": "Lokalna lajna prikazuje sve javne statuse od svih na domenu {domain}. Federisana lajna prikazuje javne statuse od svih ljudi koje prate korisnici sa domena {domain}. Ovo su javne lajne, sjajan način da otkrijete nove ljude.", "onboarding.page_four.home": "Početna lajna prikazuje statuse ljudi koje Vi pratite.", "onboarding.page_four.notifications": "Kolona sa obaveštenjima Vam prikazuje kada neko priča sa Vama.", "onboarding.page_one.federation": "Mastodont je mreža nezavisnih servera koji se uvezuju da naprave jednu veću društvenu mrežu. Ove servere zovemo instancama.", @@ -213,6 +214,7 @@ "search_popout.tips.user": "korisnik", "search_results.total": "{count, number} {count, plural, one {rezultat} few {rezultata} other {rezultata}}", "standalone.public_title": "Pogled iznutra...", + "status.block": "Block @{name}", "status.cannot_reblog": "Ovaj status ne može da se podrži", "status.delete": "Obriši", "status.embed": "Ugradi na sajt", @@ -221,7 +223,8 @@ "status.media_hidden": "Multimedija sakrivena", "status.mention": "Pomeni korisnika @{name}", "status.more": "Još", - "status.mute_conversation": "Mutiraj prepisku", + "status.mute": "Mute @{name}", + "status.mute_conversation": "Ućutkaj prepisku", "status.open": "Proširi ovaj status", "status.pin": "Prikači na profil", "status.reblog": "Podrži", @@ -237,7 +240,7 @@ "status.unmute_conversation": "Uključi prepisku", "status.unpin": "Otkači sa profila", "tabs_bar.compose": "Napiši", - "tabs_bar.federated_timeline": "Združeno", + "tabs_bar.federated_timeline": "Federisano", "tabs_bar.home": "Početna", "tabs_bar.local_timeline": "Lokalno", "tabs_bar.notifications": "Obaveštenja", diff --git a/app/javascript/mastodon/locales/sr.json b/app/javascript/mastodon/locales/sr.json index 7824be2b27..e65c02ab7f 100644 --- a/app/javascript/mastodon/locales/sr.json +++ b/app/javascript/mastodon/locales/sr.json @@ -11,7 +11,7 @@ "account.media": "Медији", "account.mention": "Помени корисника @{name}", "account.moved_to": "{name} се померио на:", - "account.mute": "Мутирај @{name}", + "account.mute": "Ућуткај корисника @{name}", "account.mute_notifications": "Искључи обавештења од корисника @{name}", "account.posts": "Статуса", "account.report": "Пријави @{name}", @@ -21,7 +21,7 @@ "account.unblock": "Одблокирај корисника @{name}", "account.unblock_domain": "Одблокирај домен {domain}", "account.unfollow": "Отпрати", - "account.unmute": "Одмутирај @{name}", + "account.unmute": "Уклони ућуткавање кориснику @{name}", "account.unmute_notifications": "Укључи назад обавештења од корисника @{name}", "account.view_full_profile": "Види цео профил", "boost_modal.combo": "Можете притиснути {combo} да прескочите ово следећи пут", @@ -37,10 +37,10 @@ "column.follow_requests": "Захтеви за праћење", "column.home": "Почетна", "column.lists": "Листе", - "column.mutes": "Мутирани корисници", + "column.mutes": "Ућуткани корисници", "column.notifications": "Обавештења", "column.pins": "Прикачени тутови", - "column.public": "Здружена лајна", + "column.public": "Федерисана лајна", "column_back_button.label": "Назад", "column_header.hide_settings": "Сакриј поставке", "column_header.moveLeft_settings": "Помери колону улево", @@ -67,9 +67,9 @@ "confirmations.delete_list.confirm": "Обриши", "confirmations.delete_list.message": "Да ли сте сигурни да желите да бесповратно обришете ову листу?", "confirmations.domain_block.confirm": "Сакриј цео домен", - "confirmations.domain_block.message": "Да ли сте стварно, стварно сигурно да желите да блокирате цео домен {domain}? У већини случајева, пар добрих блокирања или мутирања су довољна и препоручљива.", - "confirmations.mute.confirm": "Мутирај", - "confirmations.mute.message": "Да ли стварно желите да мутирате корисника {name}?", + "confirmations.domain_block.message": "Да ли сте стварно, стварно сигурно да желите да блокирате цео домен {domain}? У већини случајева, пар добрих блокирања или ућуткавања су довољна и препоручљива.", + "confirmations.mute.confirm": "Ућуткај", + "confirmations.mute.message": "Да ли стварно желите да ућуткате корисника {name}?", "confirmations.unfollow.confirm": "Отпрати", "confirmations.unfollow.message": "Да ли сте сигурни да желите да отпратите корисника {name}?", "embed.instructions": "Угради овај статус на Ваш веб сајт копирањем кода испод.", @@ -149,10 +149,10 @@ "navigation_bar.keyboard_shortcuts": "Пречице на тастатури", "navigation_bar.lists": "Листе", "navigation_bar.logout": "Одјава", - "navigation_bar.mutes": "Мутирани корисници", + "navigation_bar.mutes": "Ућуткани корисници", "navigation_bar.pins": "Прикачени тутови", "navigation_bar.preferences": "Подешавања", - "navigation_bar.public_timeline": "Здружена лајна", + "navigation_bar.public_timeline": "Федерисана лајна", "notification.favourite": "{name} је ставио Ваш статус као омиљени", "notification.follow": "{name} Вас је запратио", "notification.mention": "{name} Вас је поменуо", @@ -170,7 +170,7 @@ "notifications.column_settings.sound": "Пуштај звук", "onboarding.done": "Готово", "onboarding.next": "Следеће", - "onboarding.page_five.public_timelines": "Локална лајна приказује све јавне статусе од свих на домену {domain}. Здружена лајна приказује јавне статусе од свих људи које прате корисници са домена {domain}. Ово су јавне лајне, сјајан начин да откријете нове људе.", + "onboarding.page_five.public_timelines": "Локална лајна приказује све јавне статусе од свих на домену {domain}. Федерисана лајна приказује јавне статусе од свих људи које прате корисници са домена {domain}. Ово су јавне лајне, сјајан начин да откријете нове људе.", "onboarding.page_four.home": "Почетна лајна приказује статусе људи које Ви пратите.", "onboarding.page_four.notifications": "Колона са обавештењима Вам приказује када неко прича са Вама.", "onboarding.page_one.federation": "Мастодонт је мрежа независних сервера који се увезују да направе једну већу друштвену мрежу. Ове сервере зовемо инстанцама.", @@ -224,7 +224,7 @@ "status.mention": "Помени корисника @{name}", "status.more": "Још", "status.mute": "Mute @{name}", - "status.mute_conversation": "Мутирај преписку", + "status.mute_conversation": "Ућуткај преписку", "status.open": "Прошири овај статус", "status.pin": "Прикачи на профил", "status.reblog": "Подржи", @@ -240,7 +240,7 @@ "status.unmute_conversation": "Укључи преписку", "status.unpin": "Откачи са профила", "tabs_bar.compose": "Напиши", - "tabs_bar.federated_timeline": "Здружено", + "tabs_bar.federated_timeline": "Федерисано", "tabs_bar.home": "Почетна", "tabs_bar.local_timeline": "Локално", "tabs_bar.notifications": "Обавештења", diff --git a/config/locales/sr-Latn.yml b/config/locales/sr-Latn.yml index 45fb1c1bae..964a82d643 100644 --- a/config/locales/sr-Latn.yml +++ b/config/locales/sr-Latn.yml @@ -409,8 +409,8 @@ sr-Latn: exports: blocks: Blokirali ste csv: CSV - follows: PRatite - mutes: Mutirali ste + follows: Pratite + mutes: Ućutkali ste storage: Multimedijalno skladište followers: domain: Domen @@ -441,7 +441,7 @@ sr-Latn: types: blocking: Lista blokiranja following: Lista pratilaca - muting: Lista mutiranih + muting: Lista ućutkanih upload: Otpremi in_memoriam_html: In Memoriam. invites: diff --git a/config/locales/sr.yml b/config/locales/sr.yml index 6961ff8414..57ccf2008c 100644 --- a/config/locales/sr.yml +++ b/config/locales/sr.yml @@ -409,8 +409,8 @@ sr: exports: blocks: Блокирали сте csv: CSV - follows: ПРатите - mutes: Мутирали сте + follows: Пратите + mutes: Ућуткали сте storage: Мултимедијално складиште followers: domain: Домен @@ -441,7 +441,7 @@ sr: types: blocking: Листа блокирања following: Листа пратилаца - muting: Листа мутираних + muting: Листа ућутканих upload: Отпреми in_memoriam_html: In Memoriam. invites: