From c10f4bdb037d87444a76e52e85f046e7e59d753a 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 75915b337..69fd20e27 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 8b1cddeb4..038bcbabc 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 51a978f44..e17d1f26e 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 a82b9340b..c9725ccc0 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 c00b9f034..1a440fd59 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 ff924f95bbb9ed728bbc95cab1651cc788e1351b 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 1b7af06a4..f3887b2b8 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 02e3e1ec09e8885dbaeb063afd4d3d3f1f32031c 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 e85243e57..4475034a5 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 256c2b1de05e5c622ab914f6f353ed0a94d2faaa 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 3c1619c24..ee789e180 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 7d4f4f9aab7253540a69d2e80ba5414ae57a6582 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 1c47a22da..c01e8d071 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 89daeb43a88321d6568eeb6ffac68bdc810e41b5 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 876fb0e13..65b174ab5 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 c82f07e2d..b5edaea72 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 7a66a64ca..e73dbf9cc 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 3bee0996c509f4b416096094061edbc9c10f5632 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 e17d1f26e..f59f2725b 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 1a440fd59..367ea34e7 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 02ba03d6dba9e5633013e50366daabe573759168 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 000000000..dfea9db4a --- /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 6b6b0c418..e2763c2b9 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 958b28cdc..56fa2d8dd 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 c61dd918a24761b7a96cb9e65e6943238f630715 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 fd5177a96..94bd0a592 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 3c189642561f27925803448059e212718e4a2497 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 11894a895..998b7566f 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 2898011fd..ae1dbe6b5 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 7571c37c991c7bcaf83c524105f4a3b64b19670c 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 ca129da80..007768769 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 7347d4f8bb6471c892d4feb58e1e0a4d13a229c4 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 478530c7f..181c4f288 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 b2e53b82d..0273a4e7c 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 49e296e1b03ffe2b17fb390b6ad298172b25040f 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 bddea557b..0c343e1df 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 5ec25ff3e1c53a4feab1e9b9a3f1660cca538c23 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 a82a7d28a..9459db7fe 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 2ec36c060..80a06c43a 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 5ed7ed88b..8171c939a 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 d872902997c29e228001b71a4a3ede589e346f5d 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 971ffb5c5..88631e332 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 7824be2b2..e65c02ab7 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 45fb1c1ba..964a82d64 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 6961ff841..57ccf2008 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: