Merge remote-tracking branch 'tootsuite/master' into glitchsoc/master
This commit is contained in:
commit
c69a23ae46
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -70,30 +70,28 @@ export default class GettingStarted extends ImmutablePureComponent {
|
|||
|
||||
navItems.push(
|
||||
<ColumnLink key='4' icon='star' text={intl.formatMessage(messages.favourites)} to='/favourites' />,
|
||||
<ColumnLink key='5' icon='thumb-tack' text={intl.formatMessage(messages.pins)} to='/pinned' />,
|
||||
<ColumnLink key='6' icon='bars' text={intl.formatMessage(messages.lists)} to='/lists' />
|
||||
<ColumnLink key='5' icon='bars' text={intl.formatMessage(messages.lists)} to='/lists' />
|
||||
);
|
||||
|
||||
if (myAccount.get('locked')) {
|
||||
navItems.push(<ColumnLink key='7' icon='users' text={intl.formatMessage(messages.follow_requests)} to='/follow_requests' />);
|
||||
navItems.push(<ColumnLink key='6' icon='users' text={intl.formatMessage(messages.follow_requests)} to='/follow_requests' />);
|
||||
}
|
||||
|
||||
navItems.push(
|
||||
<ColumnLink key='8' icon='volume-off' text={intl.formatMessage(messages.mutes)} to='/mutes' />,
|
||||
<ColumnLink key='9' icon='ban' text={intl.formatMessage(messages.blocks)} to='/blocks' />
|
||||
);
|
||||
|
||||
if (multiColumn) {
|
||||
navItems.push(<ColumnLink key='10' icon='question' text={intl.formatMessage(messages.keyboard_shortcuts)} to='/keyboard-shortcuts' />);
|
||||
navItems.push(<ColumnLink key='7' icon='question' text={intl.formatMessage(messages.keyboard_shortcuts)} to='/keyboard-shortcuts' />);
|
||||
}
|
||||
|
||||
navItems.push(<ColumnLink key='8' icon='book' text={intl.formatMessage(messages.info)} href='/about/more' />);
|
||||
|
||||
return (
|
||||
<Column icon='asterisk' heading={intl.formatMessage(messages.heading)} hideHeadingOnMobile>
|
||||
<div className='getting-started__wrapper'>
|
||||
<ColumnSubheading text={intl.formatMessage(messages.navigation_subheading)} />
|
||||
{navItems}
|
||||
<ColumnSubheading text={intl.formatMessage(messages.settings_subheading)} />
|
||||
<ColumnLink icon='book' text={intl.formatMessage(messages.info)} href='/about/more' />
|
||||
<ColumnLink icon='thumb-tack' text={intl.formatMessage(messages.pins)} to='/pinned' />
|
||||
<ColumnLink icon='volume-off' text={intl.formatMessage(messages.mutes)} to='/mutes' />
|
||||
<ColumnLink icon='ban' text={intl.formatMessage(messages.blocks)} to='/blocks' />
|
||||
<ColumnLink icon='cog' text={intl.formatMessage(messages.preferences)} href='/settings/preferences' />
|
||||
<ColumnLink icon='sign-out' text={intl.formatMessage(messages.sign_out)} href='/auth/sign_out' method='delete' />
|
||||
</div>
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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": "Обавештења",
|
||||
|
|
|
@ -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": "置頂貼文",
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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!
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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ą
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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: 想要將這個帳號指向另一個帳號可到<a href="%{path}">到這裡設定</a>。
|
||||
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: 為確保個人隱私,您必須知道有哪些使用者正關注你。<strong>您的私密內容會被發送到所有您有被關注的服務站上</strong>。如果您不信任這些服務站的管理者,您可以選擇檢查或刪除您的關注者。
|
||||
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: "<strong>%{name}</strong> 是一個在 %{link_to_root_path} 的使用者。只要您有任何 Mastodon 服務站、或者聯盟網站的帳號,便可以跨站關注此站使用者,或者與他們互動。"
|
||||
landing_strip_signup_html: 如果您沒有這些帳號,歡迎在<a href="%{sign_up_path}">這裡註冊</a>。
|
||||
|
@ -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: 當您啟用<strong>雙因子認證</strong>後,您登入時將需要使您手機、或其他種類認證器產生的代碼。
|
||||
description_html: 啟用<strong>兩階段認證</strong>後,登入時將需要使手機、或其他種類認證器產生的代碼。
|
||||
disable: 停用
|
||||
enable: 啟用
|
||||
enabled_success: 已成功啟用雙因子認證
|
||||
instructions_html: "<strong>請用您手機的認證器應用程式(如 Google Authenticator、Authy),掃描這裡的 QR 圖形碼</strong>。在雙因子認證啟用後,您登入時將須要使用此應用程式產生的認證碼。"
|
||||
enabled_success: 已成功啟用兩階段認證
|
||||
instructions_html: "<strong>請用您手機的認證器應用程式(如 Google Authenticator、Authy),掃描這裡的 QR 圖形碼</strong>。在兩階段認證啟用後,您登入時將須要使用此應用程式產生的認證碼。"
|
||||
manual_instructions: 如果您無法掃描 QR 圖形碼,請手動輸入︰
|
||||
setup: 設定
|
||||
wrong_code: 您輸入的認證碼並不正確!可能伺服器時間和您手機不一致,請檢查您手機的時間,或與本站管理員聯絡。
|
||||
users:
|
||||
invalid_email: 信箱地址格式不正確
|
||||
invalid_otp_token: 雙因子認證碼不正確
|
||||
invalid_otp_token: 兩階段認證碼不正確
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -13,7 +13,7 @@ module Mastodon
|
|||
end
|
||||
|
||||
def patch
|
||||
0
|
||||
1
|
||||
end
|
||||
|
||||
def pre
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue