diff --git a/Gemfile.lock b/Gemfile.lock
index 58c59ad356..f6986cb4d6 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)
diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb
index 31144fe053..c9725ed007 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|
@@ -27,10 +28,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 46367f2026..679b94f1ef 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -198,11 +198,24 @@ class ApplicationController < ActionController::Base
end
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'
+
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
+ expires_in options[:expires_in], public: options[:public]
+ 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 6a635fba2c..d67fac0e55 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|
@@ -23,25 +23,21 @@ class StatusesController < ApplicationController
end
format.json do
- render json: @status,
- serializer: ActivityPub::NoteSerializer,
- adapter: ActivityPub::Adapter,
- content_type: 'application/activity+json'
+ skip_session! unless @stream_entry.hidden?
- # 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)
+ 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
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', public: !@stream_entry.hidden?) do
+ ActiveModelSerializers::SerializableResource.new(@status, serializer: ActivityPub::ActivitySerializer, adapter: ActivityPub::Adapter)
+ end
end
def embed
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
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/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}
-
+
+
+
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/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/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;
}
diff --git a/app/models/user.rb b/app/models/user.rb
index 231271f73b..855ae908d2 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/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/serializers/rest/instance_serializer.rb b/app/serializers/rest/instance_serializer.rb
index abbacc3747..65907dad2f 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 max_toot_chars
diff --git a/app/services/batched_remove_status_service.rb b/app/services/batched_remove_status_service.rb
index 21c7752081..cb65a22565 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
@@ -47,7 +42,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
@@ -58,22 +52,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
@@ -134,23 +112,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/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
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
diff --git a/config/locales/pl.yml b/config/locales/pl.yml
index 8b6d97b94b..0d24367d91 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
@@ -620,6 +621,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ą
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/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:
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: 兩階段認證碼不正確
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
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
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' }
+ 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 'queues up bootstrapping of home timeline' do
+ expect(BootstrapTimelineWorker).to have_received(:perform_async).with(user.account_id)
+ end
end
- it 'redirects to login' do
- expect(response).to redirect_to(new_user_session_path)
- end
+ context 'when user is updating email' do
+ let!(:user) { Fabricate(:user, confirmation_token: 'foobar', unconfirmed_email: 'new-email@example.com') }
- it 'queues up bootstrapping of home timeline' do
- expect(BootstrapTimelineWorker).to have_received(:perform_async).with(user.account_id)
+ 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)