Merge branch 'main' into glitch-soc/merge-upstream
Conflicts: - `app/helpers/accounts_helper.rb`: Conflict due to upstream changing how followers count is displayed while we have an option to hide followers count. Ported upstream change. - `app/views/accounts/_header.html.haml`: Conflict due to upstream changing how followers count is displayed while we have an option to hide followers count. Ported upstream change. - `app/views/directories/index.html.haml`: Conflict due to upstream changing how followers count is displayed while we have an option to hide followers count. Ported upstream change.
This commit is contained in:
commit
3160e050a9
4
Gemfile
4
Gemfile
|
@ -6,7 +6,7 @@ ruby '>= 2.5.0', '< 3.1.0'
|
||||||
gem 'pkg-config', '~> 1.4'
|
gem 'pkg-config', '~> 1.4'
|
||||||
|
|
||||||
gem 'puma', '~> 5.3'
|
gem 'puma', '~> 5.3'
|
||||||
gem 'rails', '~> 6.1.3'
|
gem 'rails', '~> 6.1.4'
|
||||||
gem 'sprockets', '~> 3.7.2'
|
gem 'sprockets', '~> 3.7.2'
|
||||||
gem 'thor', '~> 1.1'
|
gem 'thor', '~> 1.1'
|
||||||
gem 'rack', '~> 2.2.3'
|
gem 'rack', '~> 2.2.3'
|
||||||
|
@ -24,7 +24,7 @@ gem 'paperclip', '~> 6.0'
|
||||||
gem 'blurhash', '~> 0.1'
|
gem 'blurhash', '~> 0.1'
|
||||||
|
|
||||||
gem 'active_model_serializers', '~> 0.10'
|
gem 'active_model_serializers', '~> 0.10'
|
||||||
gem 'addressable', '~> 2.7'
|
gem 'addressable', '~> 2.8'
|
||||||
gem 'bootsnap', '~> 1.6.0', require: false
|
gem 'bootsnap', '~> 1.6.0', require: false
|
||||||
gem 'browser'
|
gem 'browser'
|
||||||
gem 'charlock_holmes', '~> 0.7.7'
|
gem 'charlock_holmes', '~> 0.7.7'
|
||||||
|
|
128
Gemfile.lock
128
Gemfile.lock
|
@ -1,40 +1,40 @@
|
||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
actioncable (6.1.3.2)
|
actioncable (6.1.4)
|
||||||
actionpack (= 6.1.3.2)
|
actionpack (= 6.1.4)
|
||||||
activesupport (= 6.1.3.2)
|
activesupport (= 6.1.4)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
websocket-driver (>= 0.6.1)
|
websocket-driver (>= 0.6.1)
|
||||||
actionmailbox (6.1.3.2)
|
actionmailbox (6.1.4)
|
||||||
actionpack (= 6.1.3.2)
|
actionpack (= 6.1.4)
|
||||||
activejob (= 6.1.3.2)
|
activejob (= 6.1.4)
|
||||||
activerecord (= 6.1.3.2)
|
activerecord (= 6.1.4)
|
||||||
activestorage (= 6.1.3.2)
|
activestorage (= 6.1.4)
|
||||||
activesupport (= 6.1.3.2)
|
activesupport (= 6.1.4)
|
||||||
mail (>= 2.7.1)
|
mail (>= 2.7.1)
|
||||||
actionmailer (6.1.3.2)
|
actionmailer (6.1.4)
|
||||||
actionpack (= 6.1.3.2)
|
actionpack (= 6.1.4)
|
||||||
actionview (= 6.1.3.2)
|
actionview (= 6.1.4)
|
||||||
activejob (= 6.1.3.2)
|
activejob (= 6.1.4)
|
||||||
activesupport (= 6.1.3.2)
|
activesupport (= 6.1.4)
|
||||||
mail (~> 2.5, >= 2.5.4)
|
mail (~> 2.5, >= 2.5.4)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
actionpack (6.1.3.2)
|
actionpack (6.1.4)
|
||||||
actionview (= 6.1.3.2)
|
actionview (= 6.1.4)
|
||||||
activesupport (= 6.1.3.2)
|
activesupport (= 6.1.4)
|
||||||
rack (~> 2.0, >= 2.0.9)
|
rack (~> 2.0, >= 2.0.9)
|
||||||
rack-test (>= 0.6.3)
|
rack-test (>= 0.6.3)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
||||||
actiontext (6.1.3.2)
|
actiontext (6.1.4)
|
||||||
actionpack (= 6.1.3.2)
|
actionpack (= 6.1.4)
|
||||||
activerecord (= 6.1.3.2)
|
activerecord (= 6.1.4)
|
||||||
activestorage (= 6.1.3.2)
|
activestorage (= 6.1.4)
|
||||||
activesupport (= 6.1.3.2)
|
activesupport (= 6.1.4)
|
||||||
nokogiri (>= 1.8.5)
|
nokogiri (>= 1.8.5)
|
||||||
actionview (6.1.3.2)
|
actionview (6.1.4)
|
||||||
activesupport (= 6.1.3.2)
|
activesupport (= 6.1.4)
|
||||||
builder (~> 3.1)
|
builder (~> 3.1)
|
||||||
erubi (~> 1.4)
|
erubi (~> 1.4)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
|
@ -45,28 +45,28 @@ GEM
|
||||||
case_transform (>= 0.2)
|
case_transform (>= 0.2)
|
||||||
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
|
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
|
||||||
active_record_query_trace (1.8)
|
active_record_query_trace (1.8)
|
||||||
activejob (6.1.3.2)
|
activejob (6.1.4)
|
||||||
activesupport (= 6.1.3.2)
|
activesupport (= 6.1.4)
|
||||||
globalid (>= 0.3.6)
|
globalid (>= 0.3.6)
|
||||||
activemodel (6.1.3.2)
|
activemodel (6.1.4)
|
||||||
activesupport (= 6.1.3.2)
|
activesupport (= 6.1.4)
|
||||||
activerecord (6.1.3.2)
|
activerecord (6.1.4)
|
||||||
activemodel (= 6.1.3.2)
|
activemodel (= 6.1.4)
|
||||||
activesupport (= 6.1.3.2)
|
activesupport (= 6.1.4)
|
||||||
activestorage (6.1.3.2)
|
activestorage (6.1.4)
|
||||||
actionpack (= 6.1.3.2)
|
actionpack (= 6.1.4)
|
||||||
activejob (= 6.1.3.2)
|
activejob (= 6.1.4)
|
||||||
activerecord (= 6.1.3.2)
|
activerecord (= 6.1.4)
|
||||||
activesupport (= 6.1.3.2)
|
activesupport (= 6.1.4)
|
||||||
marcel (~> 1.0.0)
|
marcel (~> 1.0.0)
|
||||||
mini_mime (~> 1.0.2)
|
mini_mime (>= 1.1.0)
|
||||||
activesupport (6.1.3.2)
|
activesupport (6.1.4)
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||||
i18n (>= 1.6, < 2)
|
i18n (>= 1.6, < 2)
|
||||||
minitest (>= 5.1)
|
minitest (>= 5.1)
|
||||||
tzinfo (~> 2.0)
|
tzinfo (~> 2.0)
|
||||||
zeitwerk (~> 2.3)
|
zeitwerk (~> 2.3)
|
||||||
addressable (2.7.0)
|
addressable (2.8.0)
|
||||||
public_suffix (>= 2.0.2, < 5.0)
|
public_suffix (>= 2.0.2, < 5.0)
|
||||||
airbrussh (1.4.0)
|
airbrussh (1.4.0)
|
||||||
sshkit (>= 1.6.1, != 1.7.0)
|
sshkit (>= 1.6.1, != 1.7.0)
|
||||||
|
@ -353,7 +353,7 @@ GEM
|
||||||
mimemagic (0.3.10)
|
mimemagic (0.3.10)
|
||||||
nokogiri (~> 1)
|
nokogiri (~> 1)
|
||||||
rake
|
rake
|
||||||
mini_mime (1.0.3)
|
mini_mime (1.1.0)
|
||||||
mini_portile2 (2.5.3)
|
mini_portile2 (2.5.3)
|
||||||
minitest (5.14.4)
|
minitest (5.14.4)
|
||||||
msgpack (1.4.2)
|
msgpack (1.4.2)
|
||||||
|
@ -374,7 +374,7 @@ GEM
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||||
sidekiq (>= 3.5)
|
sidekiq (>= 3.5)
|
||||||
statsd-ruby (~> 1.4, >= 1.4.0)
|
statsd-ruby (~> 1.4, >= 1.4.0)
|
||||||
oj (3.11.7)
|
oj (3.11.8)
|
||||||
omniauth (1.9.1)
|
omniauth (1.9.1)
|
||||||
hashie (>= 3.4.6)
|
hashie (>= 3.4.6)
|
||||||
rack (>= 1.6.2, < 3)
|
rack (>= 1.6.2, < 3)
|
||||||
|
@ -443,20 +443,20 @@ GEM
|
||||||
rack
|
rack
|
||||||
rack-test (1.1.0)
|
rack-test (1.1.0)
|
||||||
rack (>= 1.0, < 3)
|
rack (>= 1.0, < 3)
|
||||||
rails (6.1.3.2)
|
rails (6.1.4)
|
||||||
actioncable (= 6.1.3.2)
|
actioncable (= 6.1.4)
|
||||||
actionmailbox (= 6.1.3.2)
|
actionmailbox (= 6.1.4)
|
||||||
actionmailer (= 6.1.3.2)
|
actionmailer (= 6.1.4)
|
||||||
actionpack (= 6.1.3.2)
|
actionpack (= 6.1.4)
|
||||||
actiontext (= 6.1.3.2)
|
actiontext (= 6.1.4)
|
||||||
actionview (= 6.1.3.2)
|
actionview (= 6.1.4)
|
||||||
activejob (= 6.1.3.2)
|
activejob (= 6.1.4)
|
||||||
activemodel (= 6.1.3.2)
|
activemodel (= 6.1.4)
|
||||||
activerecord (= 6.1.3.2)
|
activerecord (= 6.1.4)
|
||||||
activestorage (= 6.1.3.2)
|
activestorage (= 6.1.4)
|
||||||
activesupport (= 6.1.3.2)
|
activesupport (= 6.1.4)
|
||||||
bundler (>= 1.15.0)
|
bundler (>= 1.15.0)
|
||||||
railties (= 6.1.3.2)
|
railties (= 6.1.4)
|
||||||
sprockets-rails (>= 2.0.0)
|
sprockets-rails (>= 2.0.0)
|
||||||
rails-controller-testing (1.0.5)
|
rails-controller-testing (1.0.5)
|
||||||
actionpack (>= 5.0.1.rc1)
|
actionpack (>= 5.0.1.rc1)
|
||||||
|
@ -472,11 +472,11 @@ GEM
|
||||||
railties (>= 6.0.0, < 7)
|
railties (>= 6.0.0, < 7)
|
||||||
rails-settings-cached (0.6.6)
|
rails-settings-cached (0.6.6)
|
||||||
rails (>= 4.2.0)
|
rails (>= 4.2.0)
|
||||||
railties (6.1.3.2)
|
railties (6.1.4)
|
||||||
actionpack (= 6.1.3.2)
|
actionpack (= 6.1.4)
|
||||||
activesupport (= 6.1.3.2)
|
activesupport (= 6.1.4)
|
||||||
method_source
|
method_source
|
||||||
rake (>= 0.8.7)
|
rake (>= 0.13)
|
||||||
thor (~> 1.0)
|
thor (~> 1.0)
|
||||||
rainbow (3.0.0)
|
rainbow (3.0.0)
|
||||||
rake (13.0.3)
|
rake (13.0.3)
|
||||||
|
@ -525,7 +525,7 @@ GEM
|
||||||
rspec-support (3.10.2)
|
rspec-support (3.10.2)
|
||||||
rspec_junit_formatter (0.4.1)
|
rspec_junit_formatter (0.4.1)
|
||||||
rspec-core (>= 2, < 4, != 2.12.0)
|
rspec-core (>= 2, < 4, != 2.12.0)
|
||||||
rubocop (1.18.1)
|
rubocop (1.18.2)
|
||||||
parallel (~> 1.10)
|
parallel (~> 1.10)
|
||||||
parser (>= 3.0.0.0)
|
parser (>= 3.0.0.0)
|
||||||
rainbow (>= 2.2.2, < 4.0)
|
rainbow (>= 2.2.2, < 4.0)
|
||||||
|
@ -536,7 +536,7 @@ GEM
|
||||||
unicode-display_width (>= 1.4.0, < 3.0)
|
unicode-display_width (>= 1.4.0, < 3.0)
|
||||||
rubocop-ast (1.7.0)
|
rubocop-ast (1.7.0)
|
||||||
parser (>= 3.0.1.1)
|
parser (>= 3.0.1.1)
|
||||||
rubocop-rails (2.11.1)
|
rubocop-rails (2.11.2)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
rack (>= 1.1)
|
rack (>= 1.1)
|
||||||
rubocop (>= 1.7.0, < 2.0)
|
rubocop (>= 1.7.0, < 2.0)
|
||||||
|
@ -570,7 +570,7 @@ GEM
|
||||||
sidekiq (>= 3)
|
sidekiq (>= 3)
|
||||||
thwait
|
thwait
|
||||||
tilt (>= 1.4.0)
|
tilt (>= 1.4.0)
|
||||||
sidekiq-unique-jobs (7.1.1)
|
sidekiq-unique-jobs (7.1.2)
|
||||||
brpoplpush-redis_script (> 0.1.1, <= 2.0.0)
|
brpoplpush-redis_script (> 0.1.1, <= 2.0.0)
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.5)
|
concurrent-ruby (~> 1.0, >= 1.0.5)
|
||||||
sidekiq (>= 5.0, < 7.0)
|
sidekiq (>= 5.0, < 7.0)
|
||||||
|
@ -659,7 +659,7 @@ GEM
|
||||||
webpush (0.3.8)
|
webpush (0.3.8)
|
||||||
hkdf (~> 0.2)
|
hkdf (~> 0.2)
|
||||||
jwt (~> 2.0)
|
jwt (~> 2.0)
|
||||||
websocket-driver (0.7.3)
|
websocket-driver (0.7.5)
|
||||||
websocket-extensions (>= 0.1.0)
|
websocket-extensions (>= 0.1.0)
|
||||||
websocket-extensions (0.1.5)
|
websocket-extensions (0.1.5)
|
||||||
wisper (2.0.1)
|
wisper (2.0.1)
|
||||||
|
@ -674,7 +674,7 @@ PLATFORMS
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
active_model_serializers (~> 0.10)
|
active_model_serializers (~> 0.10)
|
||||||
active_record_query_trace (~> 1.8)
|
active_record_query_trace (~> 1.8)
|
||||||
addressable (~> 2.7)
|
addressable (~> 2.8)
|
||||||
annotate (~> 3.1)
|
annotate (~> 3.1)
|
||||||
aws-sdk-s3 (~> 1.96)
|
aws-sdk-s3 (~> 1.96)
|
||||||
better_errors (~> 2.9)
|
better_errors (~> 2.9)
|
||||||
|
@ -758,7 +758,7 @@ DEPENDENCIES
|
||||||
rack (~> 2.2.3)
|
rack (~> 2.2.3)
|
||||||
rack-attack (~> 6.5)
|
rack-attack (~> 6.5)
|
||||||
rack-cors (~> 1.1)
|
rack-cors (~> 1.1)
|
||||||
rails (~> 6.1.3)
|
rails (~> 6.1.4)
|
||||||
rails-controller-testing (~> 1.0)
|
rails-controller-testing (~> 1.0)
|
||||||
rails-i18n (~> 6.0)
|
rails-i18n (~> 6.0)
|
||||||
rails-settings-cached (~> 0.6)
|
rails-settings-cached (~> 0.6)
|
||||||
|
|
|
@ -11,7 +11,11 @@ class ActivityPub::OutboxesController < ActivityPub::BaseController
|
||||||
before_action :set_cache_headers
|
before_action :set_cache_headers
|
||||||
|
|
||||||
def show
|
def show
|
||||||
expires_in(page_requested? ? 0 : 3.minutes, public: public_fetch_mode? && !(signed_request_account.present? && page_requested?))
|
if page_requested?
|
||||||
|
expires_in(1.minute, public: public_fetch_mode? && signed_request_account.nil?)
|
||||||
|
else
|
||||||
|
expires_in(3.minutes, public: public_fetch_mode?)
|
||||||
|
end
|
||||||
render json: outbox_presenter, serializer: ActivityPub::OutboxSerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json'
|
render json: outbox_presenter, serializer: ActivityPub::OutboxSerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -76,4 +80,8 @@ class ActivityPub::OutboxesController < ActivityPub::BaseController
|
||||||
def set_account
|
def set_account
|
||||||
@account = params[:account_username].present? ? Account.find_local!(username_param) : Account.representative
|
@account = params[:account_username].present? ? Account.find_local!(username_param) : Account.representative
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def set_cache_headers
|
||||||
|
response.headers['Vary'] = 'Signature' if authorized_fetch_mode? || page_requested?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,9 +6,9 @@ module Admin
|
||||||
|
|
||||||
def create
|
def create
|
||||||
authorize @user, :reset_password?
|
authorize @user, :reset_password?
|
||||||
@user.send_reset_password_instructions
|
@user.reset_password!
|
||||||
log_action :reset_password, @user
|
log_action :reset_password, @user
|
||||||
redirect_to admin_accounts_path
|
redirect_to admin_account_path(@user.account_id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Admin
|
||||||
|
class SignInTokenAuthenticationsController < BaseController
|
||||||
|
before_action :set_target_user
|
||||||
|
|
||||||
|
def create
|
||||||
|
authorize @user, :enable_sign_in_token_auth?
|
||||||
|
@user.update(skip_sign_in_token: false)
|
||||||
|
log_action :enable_sign_in_token_auth, @user
|
||||||
|
redirect_to admin_account_path(@user.account_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
authorize @user, :disable_sign_in_token_auth?
|
||||||
|
@user.update(skip_sign_in_token: true)
|
||||||
|
log_action :disable_sign_in_token_auth, @user
|
||||||
|
redirect_to admin_account_path(@user.account_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_target_user
|
||||||
|
@user = User.find(params[:user_id])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -9,7 +9,7 @@ module Admin
|
||||||
@user.disable_two_factor!
|
@user.disable_two_factor!
|
||||||
log_action :disable_2fa, @user
|
log_action :disable_2fa, @user
|
||||||
UserMailer.two_factor_disabled(@user).deliver_later!
|
UserMailer.two_factor_disabled(@user).deliver_later!
|
||||||
redirect_to admin_accounts_path
|
redirect_to admin_account_path(@user.account_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -4,7 +4,6 @@ module WellKnown
|
||||||
class WebfingerController < ActionController::Base
|
class WebfingerController < ActionController::Base
|
||||||
include RoutingHelper
|
include RoutingHelper
|
||||||
|
|
||||||
before_action { response.headers['Vary'] = 'Accept' }
|
|
||||||
before_action :set_account
|
before_action :set_account
|
||||||
before_action :check_account_suspension
|
before_action :check_account_suspension
|
||||||
|
|
||||||
|
@ -39,10 +38,12 @@ module WellKnown
|
||||||
end
|
end
|
||||||
|
|
||||||
def bad_request
|
def bad_request
|
||||||
|
expires_in(3.minutes, public: true)
|
||||||
head 400
|
head 400
|
||||||
end
|
end
|
||||||
|
|
||||||
def not_found
|
def not_found
|
||||||
|
expires_in(3.minutes, public: true)
|
||||||
head 404
|
head 404
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -84,19 +84,19 @@ module AccountsHelper
|
||||||
def account_description(account)
|
def account_description(account)
|
||||||
prepend_stats = [
|
prepend_stats = [
|
||||||
[
|
[
|
||||||
number_to_human(account.statuses_count, strip_insignificant_zeros: true),
|
number_to_human(account.statuses_count, precision: 3, strip_insignificant_zeros: true),
|
||||||
I18n.t('accounts.posts', count: account.statuses_count),
|
I18n.t('accounts.posts', count: account.statuses_count),
|
||||||
].join(' '),
|
].join(' '),
|
||||||
|
|
||||||
[
|
[
|
||||||
number_to_human(account.following_count, strip_insignificant_zeros: true),
|
number_to_human(account.following_count, precision: 3, strip_insignificant_zeros: true),
|
||||||
I18n.t('accounts.following', count: account.following_count),
|
I18n.t('accounts.following', count: account.following_count),
|
||||||
].join(' '),
|
].join(' '),
|
||||||
]
|
]
|
||||||
|
|
||||||
unless hide_followers_count?(account)
|
unless hide_followers_count?(account)
|
||||||
prepend_stats << [
|
prepend_stats << [
|
||||||
number_to_human(account.followers_count, strip_insignificant_zeros: true),
|
number_to_human(account.followers_count, precision: 3, strip_insignificant_zeros: true),
|
||||||
I18n.t('accounts.followers', count: account.followers_count),
|
I18n.t('accounts.followers', count: account.followers_count),
|
||||||
].join(' ')
|
].join(' ')
|
||||||
end
|
end
|
||||||
|
|
|
@ -14,6 +14,17 @@ module ApplicationHelper
|
||||||
ku
|
ku
|
||||||
).freeze
|
).freeze
|
||||||
|
|
||||||
|
def friendly_number_to_human(number, **options)
|
||||||
|
# By default, the number of precision digits used by number_to_human
|
||||||
|
# is looked up from the locales definition, and rails-i18n comes with
|
||||||
|
# values that don't seem to make much sense for many languages, so
|
||||||
|
# override these values with a default of 3 digits of precision.
|
||||||
|
options[:precision] = 3
|
||||||
|
options[:strip_insignificant_zeros] = true
|
||||||
|
|
||||||
|
number_to_human(number, **options)
|
||||||
|
end
|
||||||
|
|
||||||
def active_nav_class(*paths)
|
def active_nav_class(*paths)
|
||||||
paths.any? { |path| current_page?(path) } ? 'active' : ''
|
paths.any? { |path| current_page?(path) } ? 'active' : ''
|
||||||
end
|
end
|
||||||
|
|
|
@ -7291,6 +7291,7 @@ noscript {
|
||||||
&__account {
|
&__account {
|
||||||
display: flex;
|
display: flex;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.account__avatar {
|
.account__avatar {
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
class AccountStat < ApplicationRecord
|
class AccountStat < ApplicationRecord
|
||||||
self.locking_column = nil
|
self.locking_column = nil
|
||||||
|
self.ignored_columns = %w(lock_version)
|
||||||
|
|
||||||
belongs_to :account, inverse_of: :account_stat
|
belongs_to :account, inverse_of: :account_stat
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
# sign_in_token_sent_at :datetime
|
# sign_in_token_sent_at :datetime
|
||||||
# webauthn_id :string
|
# webauthn_id :string
|
||||||
# sign_up_ip :inet
|
# sign_up_ip :inet
|
||||||
|
# skip_sign_in_token :boolean
|
||||||
#
|
#
|
||||||
|
|
||||||
class User < ApplicationRecord
|
class User < ApplicationRecord
|
||||||
|
@ -200,7 +201,7 @@ class User < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def suspicious_sign_in?(ip)
|
def suspicious_sign_in?(ip)
|
||||||
!otp_required_for_login? && current_sign_in_at.present? && current_sign_in_at < 2.weeks.ago && !recent_ip?(ip)
|
!otp_required_for_login? && !skip_sign_in_token? && current_sign_in_at.present? && !recent_ip?(ip)
|
||||||
end
|
end
|
||||||
|
|
||||||
def functional?
|
def functional?
|
||||||
|
@ -329,12 +330,32 @@ class User < ApplicationRecord
|
||||||
super
|
super
|
||||||
end
|
end
|
||||||
|
|
||||||
def reset_password!(new_password, new_password_confirmation)
|
def reset_password(new_password, new_password_confirmation)
|
||||||
return false if encrypted_password.blank?
|
return false if encrypted_password.blank?
|
||||||
|
|
||||||
super
|
super
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def reset_password!
|
||||||
|
# First, change password to something random, invalidate the remember-me token,
|
||||||
|
# and deactivate all sessions
|
||||||
|
transaction do
|
||||||
|
update(remember_token: nil, remember_created_at: nil, password: SecureRandom.hex)
|
||||||
|
session_activations.destroy_all
|
||||||
|
end
|
||||||
|
|
||||||
|
# Then, remove all authorized applications and connected push subscriptions
|
||||||
|
Doorkeeper::AccessGrant.by_resource_owner(self).in_batches.update_all(revoked_at: Time.now.utc)
|
||||||
|
|
||||||
|
Doorkeeper::AccessToken.by_resource_owner(self).in_batches do |batch|
|
||||||
|
batch.update_all(revoked_at: Time.now.utc)
|
||||||
|
Web::PushSubscription.where(access_token_id: batch).delete_all
|
||||||
|
end
|
||||||
|
|
||||||
|
# Finally, send a reset password prompt to the user
|
||||||
|
send_reset_password_instructions
|
||||||
|
end
|
||||||
|
|
||||||
def show_all_media?
|
def show_all_media?
|
||||||
setting_display_media == 'show_all'
|
setting_display_media == 'show_all'
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,6 +13,14 @@ class UserPolicy < ApplicationPolicy
|
||||||
admin? && !record.staff?
|
admin? && !record.staff?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def disable_sign_in_token_auth?
|
||||||
|
staff?
|
||||||
|
end
|
||||||
|
|
||||||
|
def enable_sign_in_token_auth?
|
||||||
|
staff?
|
||||||
|
end
|
||||||
|
|
||||||
def confirm?
|
def confirm?
|
||||||
staff? && !record.confirmed?
|
staff? && !record.confirmed?
|
||||||
end
|
end
|
||||||
|
|
|
@ -16,11 +16,11 @@
|
||||||
.row__information-board
|
.row__information-board
|
||||||
.information-board__section
|
.information-board__section
|
||||||
%span= t 'about.user_count_before'
|
%span= t 'about.user_count_before'
|
||||||
%strong= number_to_human @instance_presenter.user_count, strip_insignificant_zeros: true
|
%strong= friendly_number_to_human @instance_presenter.user_count
|
||||||
%span= t 'about.user_count_after', count: @instance_presenter.user_count
|
%span= t 'about.user_count_after', count: @instance_presenter.user_count
|
||||||
.information-board__section
|
.information-board__section
|
||||||
%span= t 'about.status_count_before'
|
%span= t 'about.status_count_before'
|
||||||
%strong= number_to_human @instance_presenter.status_count, strip_insignificant_zeros: true
|
%strong= friendly_number_to_human @instance_presenter.status_count
|
||||||
%span= t 'about.status_count_after', count: @instance_presenter.status_count
|
%span= t 'about.status_count_after', count: @instance_presenter.status_count
|
||||||
.row__mascot
|
.row__mascot
|
||||||
.landing-page__mascot
|
.landing-page__mascot
|
||||||
|
|
|
@ -70,10 +70,10 @@
|
||||||
|
|
||||||
.hero-widget__counters__wrapper
|
.hero-widget__counters__wrapper
|
||||||
.hero-widget__counter
|
.hero-widget__counter
|
||||||
%strong= number_to_human @instance_presenter.user_count, strip_insignificant_zeros: true
|
%strong= friendly_number_to_human @instance_presenter.user_count
|
||||||
%span= t 'about.user_count_after', count: @instance_presenter.user_count
|
%span= t 'about.user_count_after', count: @instance_presenter.user_count
|
||||||
.hero-widget__counter
|
.hero-widget__counter
|
||||||
%strong= number_to_human @instance_presenter.active_user_count, strip_insignificant_zeros: true
|
%strong= friendly_number_to_human @instance_presenter.active_user_count
|
||||||
%span
|
%span
|
||||||
= t 'about.active_count_after'
|
= t 'about.active_count_after'
|
||||||
%abbr{ title: t('about.active_footnote') } *
|
%abbr{ title: t('about.active_footnote') } *
|
||||||
|
|
|
@ -15,17 +15,17 @@
|
||||||
.details-counters
|
.details-counters
|
||||||
.counter{ class: active_nav_class(short_account_url(account), short_account_with_replies_url(account), short_account_media_url(account)) }
|
.counter{ class: active_nav_class(short_account_url(account), short_account_with_replies_url(account), short_account_media_url(account)) }
|
||||||
= link_to short_account_url(account), class: 'u-url u-uid', title: number_with_delimiter(account.statuses_count) do
|
= link_to short_account_url(account), class: 'u-url u-uid', title: number_with_delimiter(account.statuses_count) do
|
||||||
%span.counter-number= number_to_human account.statuses_count, strip_insignificant_zeros: true
|
%span.counter-number= friendly_number_to_human account.statuses_count
|
||||||
%span.counter-label= t('accounts.posts', count: account.statuses_count)
|
%span.counter-label= t('accounts.posts', count: account.statuses_count)
|
||||||
|
|
||||||
.counter{ class: active_nav_class(account_following_index_url(account)) }
|
.counter{ class: active_nav_class(account_following_index_url(account)) }
|
||||||
= link_to account_following_index_url(account), title: number_with_delimiter(account.following_count) do
|
= link_to account_following_index_url(account), title: number_with_delimiter(account.following_count) do
|
||||||
%span.counter-number= number_to_human account.following_count, strip_insignificant_zeros: true
|
%span.counter-number= friendly_number_to_human account.following_count
|
||||||
%span.counter-label= t('accounts.following', count: account.following_count)
|
%span.counter-label= t('accounts.following', count: account.following_count)
|
||||||
|
|
||||||
.counter{ class: active_nav_class(account_followers_url(account)) }
|
.counter{ class: active_nav_class(account_followers_url(account)) }
|
||||||
= link_to account_followers_url(account), title: hide_followers_count?(account) ? nil : number_with_delimiter(account.followers_count) do
|
= link_to account_followers_url(account), title: hide_followers_count?(account) ? nil : number_with_delimiter(account.followers_count) do
|
||||||
%span.counter-number= hide_followers_count?(account) ? '-' : (number_to_human account.followers_count, strip_insignificant_zeros: true)
|
%span.counter-number= hide_followers_count?(account) ? '-' : (friendly_number_to_human account.followers_count)
|
||||||
%span.counter-label= t('accounts.followers', count: account.followers_count)
|
%span.counter-label= t('accounts.followers', count: account.followers_count)
|
||||||
.spacer
|
.spacer
|
||||||
.public-account-header__tabs__tabs__buttons
|
.public-account-header__tabs__tabs__buttons
|
||||||
|
@ -36,8 +36,8 @@
|
||||||
|
|
||||||
.public-account-header__extra__links
|
.public-account-header__extra__links
|
||||||
= link_to account_following_index_url(account) do
|
= link_to account_following_index_url(account) do
|
||||||
%strong= number_to_human account.following_count, strip_insignificant_zeros: true
|
%strong= friendly_number_to_human account.following_count
|
||||||
= t('accounts.following', count: account.following_count)
|
= t('accounts.following', count: account.following_count)
|
||||||
= link_to account_followers_url(account) do
|
= link_to account_followers_url(account) do
|
||||||
%strong= hide_followers_count?(account) ? '-' : (number_to_human account.followers_count, strip_insignificant_zeros: true)
|
%strong= hide_followers_count?(account) ? '-' : (friendly_number_to_human account.followers_count)
|
||||||
= t('accounts.followers', count: account.followers_count)
|
= t('accounts.followers', count: account.followers_count)
|
||||||
|
|
|
@ -81,6 +81,6 @@
|
||||||
= t('accounts.nothing_here')
|
= t('accounts.nothing_here')
|
||||||
- else
|
- else
|
||||||
%time.formatted{ datetime: featured_tag.last_status_at.iso8601, title: l(featured_tag.last_status_at) }= l featured_tag.last_status_at
|
%time.formatted{ datetime: featured_tag.last_status_at.iso8601, title: l(featured_tag.last_status_at) }= l featured_tag.last_status_at
|
||||||
.trends__item__current= number_to_human featured_tag.statuses_count, strip_insignificant_zeros: true
|
.trends__item__current= friendly_number_to_human featured_tag.statuses_count
|
||||||
|
|
||||||
= render 'application/sidebar'
|
= render 'application/sidebar'
|
||||||
|
|
|
@ -129,6 +129,27 @@
|
||||||
- else
|
- else
|
||||||
= t('admin.accounts.confirming')
|
= t('admin.accounts.confirming')
|
||||||
%td= table_link_to 'refresh', t('admin.accounts.resend_confirmation.send'), resend_admin_account_confirmation_path(@account.id), method: :post if can?(:confirm, @account.user)
|
%td= table_link_to 'refresh', t('admin.accounts.resend_confirmation.send'), resend_admin_account_confirmation_path(@account.id), method: :post if can?(:confirm, @account.user)
|
||||||
|
%tr
|
||||||
|
%th{ rowspan: can?(:reset_password, @account.user) ? 2 : 1 }= t('admin.accounts.security')
|
||||||
|
%td{ rowspan: can?(:reset_password, @account.user) ? 2 : 1 }
|
||||||
|
- if @account.user&.two_factor_enabled?
|
||||||
|
= t 'admin.accounts.security_measures.password_and_2fa'
|
||||||
|
- elsif @account.user&.skip_sign_in_token?
|
||||||
|
= t 'admin.accounts.security_measures.only_password'
|
||||||
|
- else
|
||||||
|
= t 'admin.accounts.security_measures.password_and_sign_in_token'
|
||||||
|
%td
|
||||||
|
- if @account.user&.two_factor_enabled?
|
||||||
|
= table_link_to 'unlock', t('admin.accounts.disable_two_factor_authentication'), admin_user_two_factor_authentication_path(@account.user.id), method: :delete if can?(:disable_2fa, @account.user)
|
||||||
|
- elsif @account.user&.skip_sign_in_token?
|
||||||
|
= table_link_to 'lock', t('admin.accounts.enable_sign_in_token_auth'), admin_user_sign_in_token_authentication_path(@account.user.id), method: :post if can?(:enable_sign_in_token_auth, @account.user)
|
||||||
|
- else
|
||||||
|
= table_link_to 'unlock', t('admin.accounts.disable_sign_in_token_auth'), admin_user_sign_in_token_authentication_path(@account.user.id), method: :delete if can?(:disable_sign_in_token_auth, @account.user)
|
||||||
|
|
||||||
|
- if can?(:reset_password, @account.user)
|
||||||
|
%tr
|
||||||
|
%td
|
||||||
|
= table_link_to 'key', t('admin.accounts.reset_password'), admin_account_reset_path(@account.id), method: :create, data: { confirm: t('admin.accounts.are_you_sure') }
|
||||||
|
|
||||||
%tr
|
%tr
|
||||||
%th= t('simple_form.labels.defaults.locale')
|
%th= t('simple_form.labels.defaults.locale')
|
||||||
|
@ -221,9 +242,6 @@
|
||||||
|
|
||||||
%div
|
%div
|
||||||
- if @account.local?
|
- if @account.local?
|
||||||
= link_to t('admin.accounts.reset_password'), admin_account_reset_path(@account.id), method: :create, class: 'button' if can?(:reset_password, @account.user)
|
|
||||||
- if @account.user&.otp_required_for_login?
|
|
||||||
= link_to t('admin.accounts.disable_two_factor_authentication'), admin_user_two_factor_authentication_path(@account.user.id), method: :delete, class: 'button' if can?(:disable_2fa, @account.user)
|
|
||||||
- if !@account.memorial? && @account.user_approved?
|
- if !@account.memorial? && @account.user_approved?
|
||||||
= link_to t('admin.accounts.memorialize'), memorialize_admin_account_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button button--destructive' if can?(:memorialize, @account)
|
= link_to t('admin.accounts.memorialize'), memorialize_admin_account_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button button--destructive' if can?(:memorialize, @account)
|
||||||
- else
|
- else
|
||||||
|
|
|
@ -13,42 +13,42 @@
|
||||||
%div
|
%div
|
||||||
= link_to admin_accounts_url(local: 1, recent: 1) do
|
= link_to admin_accounts_url(local: 1, recent: 1) do
|
||||||
.dashboard__counters__num{ title: number_with_delimiter(@users_count, strip_insignificant_zeros: true) }
|
.dashboard__counters__num{ title: number_with_delimiter(@users_count, strip_insignificant_zeros: true) }
|
||||||
= number_to_human @users_count, strip_insignificant_zeros: true
|
= friendly_number_to_human @users_count
|
||||||
.dashboard__counters__label= t 'admin.dashboard.total_users'
|
.dashboard__counters__label= t 'admin.dashboard.total_users'
|
||||||
%div
|
%div
|
||||||
%div
|
%div
|
||||||
.dashboard__counters__num{ title: number_with_delimiter(@registrations_week, strip_insignificant_zeros: true) }
|
.dashboard__counters__num{ title: number_with_delimiter(@registrations_week, strip_insignificant_zeros: true) }
|
||||||
= number_to_human @registrations_week, strip_insignificant_zeros: true
|
= friendly_number_to_human @registrations_week
|
||||||
.dashboard__counters__label= t 'admin.dashboard.week_users_new'
|
.dashboard__counters__label= t 'admin.dashboard.week_users_new'
|
||||||
%div
|
%div
|
||||||
%div
|
%div
|
||||||
.dashboard__counters__num{ title: number_with_delimiter(@logins_week, strip_insignificant_zeros: true) }
|
.dashboard__counters__num{ title: number_with_delimiter(@logins_week, strip_insignificant_zeros: true) }
|
||||||
= number_to_human @logins_week, strip_insignificant_zeros: true
|
= friendly_number_to_human @logins_week
|
||||||
.dashboard__counters__label= t 'admin.dashboard.week_users_active'
|
.dashboard__counters__label= t 'admin.dashboard.week_users_active'
|
||||||
%div
|
%div
|
||||||
= link_to admin_pending_accounts_path do
|
= link_to admin_pending_accounts_path do
|
||||||
.dashboard__counters__num{ title: number_with_delimiter(@pending_users_count, strip_insignificant_zeros: true) }
|
.dashboard__counters__num{ title: number_with_delimiter(@pending_users_count, strip_insignificant_zeros: true) }
|
||||||
= number_to_human @pending_users_count, strip_insignificant_zeros: true
|
= friendly_number_to_human @pending_users_count
|
||||||
.dashboard__counters__label= t 'admin.dashboard.pending_users'
|
.dashboard__counters__label= t 'admin.dashboard.pending_users'
|
||||||
%div
|
%div
|
||||||
= link_to admin_reports_url do
|
= link_to admin_reports_url do
|
||||||
.dashboard__counters__num{ title: number_with_delimiter(@reports_count, strip_insignificant_zeros: true) }
|
.dashboard__counters__num{ title: number_with_delimiter(@reports_count, strip_insignificant_zeros: true) }
|
||||||
= number_to_human @reports_count, strip_insignificant_zeros: true
|
= friendly_number_to_human @reports_count
|
||||||
.dashboard__counters__label= t 'admin.dashboard.open_reports'
|
.dashboard__counters__label= t 'admin.dashboard.open_reports'
|
||||||
%div
|
%div
|
||||||
= link_to admin_tags_path(pending_review: '1') do
|
= link_to admin_tags_path(pending_review: '1') do
|
||||||
.dashboard__counters__num{ title: number_with_delimiter(@pending_tags_count, strip_insignificant_zeros: true) }
|
.dashboard__counters__num{ title: number_with_delimiter(@pending_tags_count, strip_insignificant_zeros: true) }
|
||||||
= number_to_human @pending_tags_count, strip_insignificant_zeros: true
|
= friendly_number_to_human @pending_tags_count
|
||||||
.dashboard__counters__label= t 'admin.dashboard.pending_tags'
|
.dashboard__counters__label= t 'admin.dashboard.pending_tags'
|
||||||
%div
|
%div
|
||||||
%div
|
%div
|
||||||
.dashboard__counters__num{ title: number_with_delimiter(@interactions_week, strip_insignificant_zeros: true) }
|
.dashboard__counters__num{ title: number_with_delimiter(@interactions_week, strip_insignificant_zeros: true) }
|
||||||
= number_to_human @interactions_week, strip_insignificant_zeros: true
|
= friendly_number_to_human @interactions_week
|
||||||
.dashboard__counters__label= t 'admin.dashboard.week_interactions'
|
.dashboard__counters__label= t 'admin.dashboard.week_interactions'
|
||||||
%div
|
%div
|
||||||
= link_to sidekiq_url do
|
= link_to sidekiq_url do
|
||||||
.dashboard__counters__num{ title: number_with_delimiter(@queue_backlog, strip_insignificant_zeros: true) }
|
.dashboard__counters__num{ title: number_with_delimiter(@queue_backlog, strip_insignificant_zeros: true) }
|
||||||
= number_to_human @queue_backlog, strip_insignificant_zeros: true
|
= friendly_number_to_human @queue_backlog
|
||||||
.dashboard__counters__label= t 'admin.dashboard.backlog'
|
.dashboard__counters__label= t 'admin.dashboard.backlog'
|
||||||
|
|
||||||
.dashboard__widgets
|
.dashboard__widgets
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
%tr
|
%tr
|
||||||
%td= account_link_to account
|
%td= account_link_to account
|
||||||
%td.accounts-table__count.optional
|
%td.accounts-table__count.optional
|
||||||
= number_to_human account.statuses_count, strip_insignificant_zeros: true
|
= friendly_number_to_human account.statuses_count
|
||||||
%small= t('accounts.posts', count: account.statuses_count).downcase
|
%small= t('accounts.posts', count: account.statuses_count).downcase
|
||||||
%td.accounts-table__count.optional
|
%td.accounts-table__count.optional
|
||||||
= number_to_human account.followers_count, strip_insignificant_zeros: true
|
= friendly_number_to_human account.followers_count
|
||||||
%small= t('accounts.followers', count: account.followers_count).downcase
|
%small= t('accounts.followers', count: account.followers_count).downcase
|
||||||
%td.accounts-table__count
|
%td.accounts-table__count
|
||||||
- if account.last_status_at.present?
|
- if account.last_status_at.present?
|
||||||
|
|
|
@ -30,4 +30,4 @@
|
||||||
= ' / '
|
= ' / '
|
||||||
%span.negative-hint
|
%span.negative-hint
|
||||||
= t('admin.instances.delivery.unavailable_message')
|
= t('admin.instances.delivery.unavailable_message')
|
||||||
.trends__item__current{ title: t('admin.instances.known_accounts', count: instance.accounts_count) }= number_to_human instance.accounts_count, strip_insignificant_zeros: true
|
.trends__item__current{ title: t('admin.instances.known_accounts', count: instance.accounts_count) }= friendly_number_to_human instance.accounts_count
|
||||||
|
|
|
@ -16,4 +16,4 @@
|
||||||
= fa_icon 'fire fw'
|
= fa_icon 'fire fw'
|
||||||
= t('admin.tags.trending_right_now')
|
= t('admin.tags.trending_right_now')
|
||||||
|
|
||||||
.trends__item__current= number_to_human tag.history.first[:uses], strip_insignificant_zeros: true
|
.trends__item__current= friendly_number_to_human tag.history.first[:uses]
|
||||||
|
|
|
@ -39,10 +39,10 @@
|
||||||
|
|
||||||
.directory__card__extra
|
.directory__card__extra
|
||||||
.accounts-table__count
|
.accounts-table__count
|
||||||
= number_to_human account.statuses_count, strip_insignificant_zeros: true
|
= friendly_number_to_human account.statuses_count
|
||||||
%small= t('accounts.posts', count: account.statuses_count).downcase
|
%small= t('accounts.posts', count: account.statuses_count).downcase
|
||||||
.accounts-table__count
|
.accounts-table__count
|
||||||
= hide_followers_count?(account) ? '-' : (number_to_human account.followers_count, strip_insignificant_zeros: true)
|
= hide_followers_count?(account) ? '-' : (friendly_number_to_human account.followers_count)
|
||||||
%small= t('accounts.followers', count: account.followers_count).downcase
|
%small= t('accounts.followers', count: account.followers_count).downcase
|
||||||
.accounts-table__count
|
.accounts-table__count
|
||||||
- if account.last_status_at.present?
|
- if account.last_status_at.present?
|
||||||
|
|
|
@ -9,10 +9,10 @@
|
||||||
= interrelationships_icon(@relationships, account.id)
|
= interrelationships_icon(@relationships, account.id)
|
||||||
%td= account_link_to account
|
%td= account_link_to account
|
||||||
%td.accounts-table__count.optional
|
%td.accounts-table__count.optional
|
||||||
= number_to_human account.statuses_count, strip_insignificant_zeros: true
|
= friendly_number_to_human account.statuses_count
|
||||||
%small= t('accounts.posts', count: account.statuses_count).downcase
|
%small= t('accounts.posts', count: account.statuses_count).downcase
|
||||||
%td.accounts-table__count.optional
|
%td.accounts-table__count.optional
|
||||||
= number_to_human account.followers_count, strip_insignificant_zeros: true
|
= friendly_number_to_human account.followers_count
|
||||||
%small= t('accounts.followers', count: account.followers_count).downcase
|
%small= t('accounts.followers', count: account.followers_count).downcase
|
||||||
%td.accounts-table__count
|
%td.accounts-table__count
|
||||||
- if account.last_status_at.present?
|
- if account.last_status_at.present?
|
||||||
|
|
|
@ -28,4 +28,4 @@
|
||||||
- else
|
- else
|
||||||
%time{ datetime: featured_tag.last_status_at.iso8601, title: l(featured_tag.last_status_at) }= l featured_tag.last_status_at
|
%time{ datetime: featured_tag.last_status_at.iso8601, title: l(featured_tag.last_status_at) }= l featured_tag.last_status_at
|
||||||
= table_link_to 'trash', t('filters.index.delete'), settings_featured_tag_path(featured_tag), method: :delete, data: { confirm: t('admin.accounts.are_you_sure') }
|
= table_link_to 'trash', t('filters.index.delete'), settings_featured_tag_path(featured_tag), method: :delete, data: { confirm: t('admin.accounts.are_you_sure') }
|
||||||
.trends__item__current= number_to_human featured_tag.statuses_count, strip_insignificant_zeros: true
|
.trends__item__current= friendly_number_to_human featured_tag.statuses_count
|
||||||
|
|
|
@ -55,18 +55,18 @@
|
||||||
= fa_icon('reply')
|
= fa_icon('reply')
|
||||||
- else
|
- else
|
||||||
= fa_icon('reply-all')
|
= fa_icon('reply-all')
|
||||||
%span.detailed-status__reblogs>= number_to_human status.replies_count, strip_insignificant_zeros: true
|
%span.detailed-status__reblogs>= friendly_number_to_human status.replies_count
|
||||||
= " "
|
= " "
|
||||||
·
|
·
|
||||||
- if status.public_visibility? || status.unlisted_visibility?
|
- if status.public_visibility? || status.unlisted_visibility?
|
||||||
= link_to remote_interaction_path(status, type: :reblog), class: 'modal-button detailed-status__link' do
|
= link_to remote_interaction_path(status, type: :reblog), class: 'modal-button detailed-status__link' do
|
||||||
= fa_icon('retweet')
|
= fa_icon('retweet')
|
||||||
%span.detailed-status__reblogs>= number_to_human status.reblogs_count, strip_insignificant_zeros: true
|
%span.detailed-status__reblogs>= friendly_number_to_human status.reblogs_count
|
||||||
= " "
|
= " "
|
||||||
·
|
·
|
||||||
= link_to remote_interaction_path(status, type: :favourite), class: 'modal-button detailed-status__link' do
|
= link_to remote_interaction_path(status, type: :favourite), class: 'modal-button detailed-status__link' do
|
||||||
= fa_icon('star')
|
= fa_icon('star')
|
||||||
%span.detailed-status__favorites>= number_to_human status.favourites_count, strip_insignificant_zeros: true
|
%span.detailed-status__favorites>= friendly_number_to_human status.favourites_count
|
||||||
= " "
|
= " "
|
||||||
|
|
||||||
- if user_signed_in?
|
- if user_signed_in?
|
||||||
|
|
|
@ -44,7 +44,7 @@ en:
|
||||||
rejecting_media: 'Media files from these servers will not be processed or stored, and no thumbnails will be displayed, requiring manual click-through to the original file:'
|
rejecting_media: 'Media files from these servers will not be processed or stored, and no thumbnails will be displayed, requiring manual click-through to the original file:'
|
||||||
rejecting_media_title: Filtered media
|
rejecting_media_title: Filtered media
|
||||||
silenced: 'Posts from these servers will be hidden in public timelines and conversations, and no notifications will be generated from their users interactions, unless you are following them:'
|
silenced: 'Posts from these servers will be hidden in public timelines and conversations, and no notifications will be generated from their users interactions, unless you are following them:'
|
||||||
silenced_title: Silenced servers
|
silenced_title: Limited servers
|
||||||
suspended: 'No data from these servers will be processed, stored or exchanged, making any interaction or communication with users from these servers impossible:'
|
suspended: 'No data from these servers will be processed, stored or exchanged, making any interaction or communication with users from these servers impossible:'
|
||||||
suspended_title: Suspended servers
|
suspended_title: Suspended servers
|
||||||
unavailable_content_html: Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.
|
unavailable_content_html: Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.
|
||||||
|
@ -119,6 +119,7 @@ en:
|
||||||
demote: Demote
|
demote: Demote
|
||||||
destroyed_msg: "%{username}'s data is now queued to be deleted imminently"
|
destroyed_msg: "%{username}'s data is now queued to be deleted imminently"
|
||||||
disable: Freeze
|
disable: Freeze
|
||||||
|
disable_sign_in_token_auth: Disable e-mail token authentication
|
||||||
disable_two_factor_authentication: Disable 2FA
|
disable_two_factor_authentication: Disable 2FA
|
||||||
disabled: Frozen
|
disabled: Frozen
|
||||||
display_name: Display name
|
display_name: Display name
|
||||||
|
@ -127,6 +128,7 @@ en:
|
||||||
email: Email
|
email: Email
|
||||||
email_status: Email status
|
email_status: Email status
|
||||||
enable: Unfreeze
|
enable: Unfreeze
|
||||||
|
enable_sign_in_token_auth: Enable e-mail token authentication
|
||||||
enabled: Enabled
|
enabled: Enabled
|
||||||
enabled_msg: Successfully unfroze %{username}'s account
|
enabled_msg: Successfully unfroze %{username}'s account
|
||||||
followers: Followers
|
followers: Followers
|
||||||
|
@ -151,7 +153,7 @@ en:
|
||||||
active: Active
|
active: Active
|
||||||
all: All
|
all: All
|
||||||
pending: Pending
|
pending: Pending
|
||||||
silenced: Silenced
|
silenced: Limited
|
||||||
suspended: Suspended
|
suspended: Suspended
|
||||||
title: Moderation
|
title: Moderation
|
||||||
moderation_notes: Moderation notes
|
moderation_notes: Moderation notes
|
||||||
|
@ -191,8 +193,12 @@ en:
|
||||||
search: Search
|
search: Search
|
||||||
search_same_email_domain: Other users with the same e-mail domain
|
search_same_email_domain: Other users with the same e-mail domain
|
||||||
search_same_ip: Other users with the same IP
|
search_same_ip: Other users with the same IP
|
||||||
sensitive: Sensitive
|
security_measures:
|
||||||
sensitized: marked as sensitive
|
only_password: Only password
|
||||||
|
password_and_2fa: Password and 2FA
|
||||||
|
password_and_sign_in_token: Password and e-mail token
|
||||||
|
sensitive: Force-sensitive
|
||||||
|
sensitized: Marked as sensitive
|
||||||
shared_inbox_url: Shared inbox URL
|
shared_inbox_url: Shared inbox URL
|
||||||
show:
|
show:
|
||||||
created_reports: Made reports
|
created_reports: Made reports
|
||||||
|
@ -207,10 +213,10 @@ en:
|
||||||
time_in_queue: Waiting in queue %{time}
|
time_in_queue: Waiting in queue %{time}
|
||||||
title: Accounts
|
title: Accounts
|
||||||
unconfirmed_email: Unconfirmed email
|
unconfirmed_email: Unconfirmed email
|
||||||
undo_sensitized: Undo sensitive
|
undo_sensitized: Undo force-sensitive
|
||||||
undo_silenced: Undo silence
|
undo_silenced: Undo limit
|
||||||
undo_suspension: Undo suspension
|
undo_suspension: Undo suspension
|
||||||
unsilenced_msg: Successfully unlimited %{username}'s account
|
unsilenced_msg: Successfully undid limit of %{username}'s account
|
||||||
unsubscribe: Unsubscribe
|
unsubscribe: Unsubscribe
|
||||||
unsuspended_msg: Successfully unsuspended %{username}'s account
|
unsuspended_msg: Successfully unsuspended %{username}'s account
|
||||||
username: Username
|
username: Username
|
||||||
|
@ -236,14 +242,16 @@ en:
|
||||||
destroy_custom_emoji: Delete Custom Emoji
|
destroy_custom_emoji: Delete Custom Emoji
|
||||||
destroy_domain_allow: Delete Domain Allow
|
destroy_domain_allow: Delete Domain Allow
|
||||||
destroy_domain_block: Delete Domain Block
|
destroy_domain_block: Delete Domain Block
|
||||||
destroy_email_domain_block: Delete e-mail domain block
|
destroy_email_domain_block: Delete E-mail Domain Block
|
||||||
destroy_ip_block: Delete IP rule
|
destroy_ip_block: Delete IP rule
|
||||||
destroy_status: Delete Post
|
destroy_status: Delete Post
|
||||||
destroy_unavailable_domain: Delete Unavailable Domain
|
destroy_unavailable_domain: Delete Unavailable Domain
|
||||||
disable_2fa_user: Disable 2FA
|
disable_2fa_user: Disable 2FA
|
||||||
disable_custom_emoji: Disable Custom Emoji
|
disable_custom_emoji: Disable Custom Emoji
|
||||||
|
disable_sign_in_token_auth_user: Disable E-mail Token Authentication for User
|
||||||
disable_user: Disable User
|
disable_user: Disable User
|
||||||
enable_custom_emoji: Enable Custom Emoji
|
enable_custom_emoji: Enable Custom Emoji
|
||||||
|
enable_sign_in_token_auth_user: Enable E-mail Token Authentication for User
|
||||||
enable_user: Enable User
|
enable_user: Enable User
|
||||||
memorialize_account: Memorialize Account
|
memorialize_account: Memorialize Account
|
||||||
promote_user: Promote User
|
promote_user: Promote User
|
||||||
|
@ -251,12 +259,12 @@ en:
|
||||||
reopen_report: Reopen Report
|
reopen_report: Reopen Report
|
||||||
reset_password_user: Reset Password
|
reset_password_user: Reset Password
|
||||||
resolve_report: Resolve Report
|
resolve_report: Resolve Report
|
||||||
sensitive_account: Mark the media in your account as sensitive
|
sensitive_account: Force-Sensitive Account
|
||||||
silence_account: Silence Account
|
silence_account: Limit Account
|
||||||
suspend_account: Suspend Account
|
suspend_account: Suspend Account
|
||||||
unassigned_report: Unassign Report
|
unassigned_report: Unassign Report
|
||||||
unsensitive_account: Unmark the media in your account as sensitive
|
unsensitive_account: Undo Force-Sensitive Account
|
||||||
unsilence_account: Unsilence Account
|
unsilence_account: Undo Limit Account
|
||||||
unsuspend_account: Unsuspend Account
|
unsuspend_account: Unsuspend Account
|
||||||
update_announcement: Update Announcement
|
update_announcement: Update Announcement
|
||||||
update_custom_emoji: Update Custom Emoji
|
update_custom_emoji: Update Custom Emoji
|
||||||
|
@ -285,8 +293,10 @@ en:
|
||||||
destroy_unavailable_domain_html: "%{name} resumed delivery to domain %{target}"
|
destroy_unavailable_domain_html: "%{name} resumed delivery to domain %{target}"
|
||||||
disable_2fa_user_html: "%{name} disabled two factor requirement for user %{target}"
|
disable_2fa_user_html: "%{name} disabled two factor requirement for user %{target}"
|
||||||
disable_custom_emoji_html: "%{name} disabled emoji %{target}"
|
disable_custom_emoji_html: "%{name} disabled emoji %{target}"
|
||||||
|
disable_sign_in_token_auth_user_html: "%{name} disabled e-mail token authentication for %{target}"
|
||||||
disable_user_html: "%{name} disabled login for user %{target}"
|
disable_user_html: "%{name} disabled login for user %{target}"
|
||||||
enable_custom_emoji_html: "%{name} enabled emoji %{target}"
|
enable_custom_emoji_html: "%{name} enabled emoji %{target}"
|
||||||
|
enable_sign_in_token_auth_user_html: "%{name} enabled e-mail token authentication for %{target}"
|
||||||
enable_user_html: "%{name} enabled login for user %{target}"
|
enable_user_html: "%{name} enabled login for user %{target}"
|
||||||
memorialize_account_html: "%{name} turned %{target}'s account into a memoriam page"
|
memorialize_account_html: "%{name} turned %{target}'s account into a memoriam page"
|
||||||
promote_user_html: "%{name} promoted user %{target}"
|
promote_user_html: "%{name} promoted user %{target}"
|
||||||
|
@ -295,11 +305,11 @@ en:
|
||||||
reset_password_user_html: "%{name} reset password of user %{target}"
|
reset_password_user_html: "%{name} reset password of user %{target}"
|
||||||
resolve_report_html: "%{name} resolved report %{target}"
|
resolve_report_html: "%{name} resolved report %{target}"
|
||||||
sensitive_account_html: "%{name} marked %{target}'s media as sensitive"
|
sensitive_account_html: "%{name} marked %{target}'s media as sensitive"
|
||||||
silence_account_html: "%{name} silenced %{target}'s account"
|
silence_account_html: "%{name} limited %{target}'s account"
|
||||||
suspend_account_html: "%{name} suspended %{target}'s account"
|
suspend_account_html: "%{name} suspended %{target}'s account"
|
||||||
unassigned_report_html: "%{name} unassigned report %{target}"
|
unassigned_report_html: "%{name} unassigned report %{target}"
|
||||||
unsensitive_account_html: "%{name} unmarked %{target}'s media as sensitive"
|
unsensitive_account_html: "%{name} unmarked %{target}'s media as sensitive"
|
||||||
unsilence_account_html: "%{name} unsilenced %{target}'s account"
|
unsilence_account_html: "%{name} undid limit of %{target}'s account"
|
||||||
unsuspend_account_html: "%{name} unsuspended %{target}'s account"
|
unsuspend_account_html: "%{name} unsuspended %{target}'s account"
|
||||||
update_announcement_html: "%{name} updated announcement %{target}"
|
update_announcement_html: "%{name} updated announcement %{target}"
|
||||||
update_custom_emoji_html: "%{name} updated emoji %{target}"
|
update_custom_emoji_html: "%{name} updated emoji %{target}"
|
||||||
|
@ -421,14 +431,14 @@ en:
|
||||||
rejecting_media: rejecting media files
|
rejecting_media: rejecting media files
|
||||||
rejecting_reports: rejecting reports
|
rejecting_reports: rejecting reports
|
||||||
severity:
|
severity:
|
||||||
silence: silenced
|
silence: limited
|
||||||
suspend: suspended
|
suspend: suspended
|
||||||
show:
|
show:
|
||||||
affected_accounts:
|
affected_accounts:
|
||||||
one: One account in the database affected
|
one: One account in the database affected
|
||||||
other: "%{count} accounts in the database affected"
|
other: "%{count} accounts in the database affected"
|
||||||
retroactive:
|
retroactive:
|
||||||
silence: Unsilence existing affected accounts from this domain
|
silence: Undo limit of existing affected accounts from this domain
|
||||||
suspend: Unsuspend existing affected accounts from this domain
|
suspend: Unsuspend existing affected accounts from this domain
|
||||||
title: Undo domain block for %{domain}
|
title: Undo domain block for %{domain}
|
||||||
undo: Undo
|
undo: Undo
|
||||||
|
|
|
@ -285,6 +285,7 @@ Rails.application.routes.draw do
|
||||||
|
|
||||||
resources :users, only: [] do
|
resources :users, only: [] do
|
||||||
resource :two_factor_authentication, only: [:destroy]
|
resource :two_factor_authentication, only: [:destroy]
|
||||||
|
resource :sign_in_token_authentication, only: [:create, :destroy]
|
||||||
end
|
end
|
||||||
|
|
||||||
resources :custom_emojis, only: [:index, :new, :create] do
|
resources :custom_emojis, only: [:index, :new, :create] do
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
class AddSkipSignInTokenToUsers < ActiveRecord::Migration[6.1]
|
||||||
|
def change
|
||||||
|
add_column :users, :skip_sign_in_token, :boolean
|
||||||
|
end
|
||||||
|
end
|
|
@ -929,6 +929,7 @@ ActiveRecord::Schema.define(version: 2021_06_30_000137) do
|
||||||
t.datetime "sign_in_token_sent_at"
|
t.datetime "sign_in_token_sent_at"
|
||||||
t.string "webauthn_id"
|
t.string "webauthn_id"
|
||||||
t.inet "sign_up_ip"
|
t.inet "sign_up_ip"
|
||||||
|
t.boolean "skip_sign_in_token"
|
||||||
t.index ["account_id"], name: "index_users_on_account_id"
|
t.index ["account_id"], name: "index_users_on_account_id"
|
||||||
t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
|
t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
|
||||||
t.index ["created_by_application_id"], name: "index_users_on_created_by_application_id"
|
t.index ["created_by_application_id"], name: "index_users_on_created_by_application_id"
|
||||||
|
|
1
dist/mastodon-sidekiq.service
vendored
1
dist/mastodon-sidekiq.service
vendored
|
@ -9,6 +9,7 @@ WorkingDirectory=/home/mastodon/live
|
||||||
Environment="RAILS_ENV=production"
|
Environment="RAILS_ENV=production"
|
||||||
Environment="DB_POOL=25"
|
Environment="DB_POOL=25"
|
||||||
Environment="MALLOC_ARENA_MAX=2"
|
Environment="MALLOC_ARENA_MAX=2"
|
||||||
|
Environment="LD_PRELOAD=libjemalloc.so"
|
||||||
ExecStart=/home/mastodon/.rbenv/shims/bundle exec sidekiq -c 25
|
ExecStart=/home/mastodon/.rbenv/shims/bundle exec sidekiq -c 25
|
||||||
TimeoutSec=15
|
TimeoutSec=15
|
||||||
Restart=always
|
Restart=always
|
||||||
|
|
1
dist/mastodon-web.service
vendored
1
dist/mastodon-web.service
vendored
|
@ -8,6 +8,7 @@ User=mastodon
|
||||||
WorkingDirectory=/home/mastodon/live
|
WorkingDirectory=/home/mastodon/live
|
||||||
Environment="RAILS_ENV=production"
|
Environment="RAILS_ENV=production"
|
||||||
Environment="PORT=3000"
|
Environment="PORT=3000"
|
||||||
|
Environment="LD_PRELOAD=libjemalloc.so"
|
||||||
ExecStart=/home/mastodon/.rbenv/shims/bundle exec puma -C config/puma.rb
|
ExecStart=/home/mastodon/.rbenv/shims/bundle exec puma -C config/puma.rb
|
||||||
ExecReload=/bin/kill -SIGUSR1 $MAINPID
|
ExecReload=/bin/kill -SIGUSR1 $MAINPID
|
||||||
TimeoutSec=15
|
TimeoutSec=15
|
||||||
|
|
|
@ -54,7 +54,8 @@ module Mastodon
|
||||||
|
|
||||||
option :email, required: true
|
option :email, required: true
|
||||||
option :confirmed, type: :boolean
|
option :confirmed, type: :boolean
|
||||||
option :role, default: 'user'
|
option :role, default: 'user', enum: %w(user moderator admin)
|
||||||
|
option :skip_sign_in_token, type: :boolean
|
||||||
option :reattach, type: :boolean
|
option :reattach, type: :boolean
|
||||||
option :force, type: :boolean
|
option :force, type: :boolean
|
||||||
desc 'create USERNAME', 'Create a new user'
|
desc 'create USERNAME', 'Create a new user'
|
||||||
|
@ -68,6 +69,9 @@ module Mastodon
|
||||||
With the --role option one of "user", "admin" or "moderator"
|
With the --role option one of "user", "admin" or "moderator"
|
||||||
can be supplied. Defaults to "user"
|
can be supplied. Defaults to "user"
|
||||||
|
|
||||||
|
With the --skip-sign-in-token option, you can ensure that
|
||||||
|
the user is never asked for an e-mailed security code.
|
||||||
|
|
||||||
With the --reattach option, the new user will be reattached
|
With the --reattach option, the new user will be reattached
|
||||||
to a given existing username of an old account. If the old
|
to a given existing username of an old account. If the old
|
||||||
account is still in use by someone else, you can supply
|
account is still in use by someone else, you can supply
|
||||||
|
@ -77,7 +81,7 @@ module Mastodon
|
||||||
def create(username)
|
def create(username)
|
||||||
account = Account.new(username: username)
|
account = Account.new(username: username)
|
||||||
password = SecureRandom.hex
|
password = SecureRandom.hex
|
||||||
user = User.new(email: options[:email], password: password, agreement: true, approved: true, admin: options[:role] == 'admin', moderator: options[:role] == 'moderator', confirmed_at: options[:confirmed] ? Time.now.utc : nil, bypass_invite_request_check: true)
|
user = User.new(email: options[:email], password: password, agreement: true, approved: true, admin: options[:role] == 'admin', moderator: options[:role] == 'moderator', confirmed_at: options[:confirmed] ? Time.now.utc : nil, bypass_invite_request_check: true, skip_sign_in_token: options[:skip_sign_in_token])
|
||||||
|
|
||||||
if options[:reattach]
|
if options[:reattach]
|
||||||
account = Account.find_local(username) || Account.new(username: username)
|
account = Account.find_local(username) || Account.new(username: username)
|
||||||
|
@ -113,7 +117,7 @@ module Mastodon
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
option :role
|
option :role, enum: %w(user moderator admin)
|
||||||
option :email
|
option :email
|
||||||
option :confirm, type: :boolean
|
option :confirm, type: :boolean
|
||||||
option :enable, type: :boolean
|
option :enable, type: :boolean
|
||||||
|
@ -121,6 +125,7 @@ module Mastodon
|
||||||
option :disable_2fa, type: :boolean
|
option :disable_2fa, type: :boolean
|
||||||
option :approve, type: :boolean
|
option :approve, type: :boolean
|
||||||
option :reset_password, type: :boolean
|
option :reset_password, type: :boolean
|
||||||
|
option :skip_sign_in_token, type: :boolean
|
||||||
desc 'modify USERNAME', 'Modify a user'
|
desc 'modify USERNAME', 'Modify a user'
|
||||||
long_desc <<-LONG_DESC
|
long_desc <<-LONG_DESC
|
||||||
Modify a user account.
|
Modify a user account.
|
||||||
|
@ -142,6 +147,9 @@ module Mastodon
|
||||||
|
|
||||||
With the --reset-password option, the user's password is replaced by
|
With the --reset-password option, the user's password is replaced by
|
||||||
a randomly-generated one, printed in the output.
|
a randomly-generated one, printed in the output.
|
||||||
|
|
||||||
|
With the --skip-sign-in-token option, you can ensure that
|
||||||
|
the user is never asked for an e-mailed security code.
|
||||||
LONG_DESC
|
LONG_DESC
|
||||||
def modify(username)
|
def modify(username)
|
||||||
user = Account.find_local(username)&.user
|
user = Account.find_local(username)&.user
|
||||||
|
@ -163,6 +171,7 @@ module Mastodon
|
||||||
user.disabled = true if options[:disable]
|
user.disabled = true if options[:disable]
|
||||||
user.approved = true if options[:approve]
|
user.approved = true if options[:approve]
|
||||||
user.otp_required_for_login = false if options[:disable_2fa]
|
user.otp_required_for_login = false if options[:disable_2fa]
|
||||||
|
user.skip_sign_in_token = options[:skip_sign_in_token] unless options[:skip_sign_in_token].nil?
|
||||||
user.confirm if options[:confirm]
|
user.confirm if options[:confirm]
|
||||||
|
|
||||||
if user.save
|
if user.save
|
||||||
|
|
|
@ -17,6 +17,7 @@ module Mastodon
|
||||||
option :verbose, type: :boolean, aliases: [:v]
|
option :verbose, type: :boolean, aliases: [:v]
|
||||||
option :dry_run, type: :boolean
|
option :dry_run, type: :boolean
|
||||||
option :limited_federation_mode, type: :boolean
|
option :limited_federation_mode, type: :boolean
|
||||||
|
option :by_uri, type: :boolean
|
||||||
desc 'purge [DOMAIN...]', 'Remove accounts from a DOMAIN without a trace'
|
desc 'purge [DOMAIN...]', 'Remove accounts from a DOMAIN without a trace'
|
||||||
long_desc <<-LONG_DESC
|
long_desc <<-LONG_DESC
|
||||||
Remove all accounts from a given DOMAIN without leaving behind any
|
Remove all accounts from a given DOMAIN without leaving behind any
|
||||||
|
@ -26,6 +27,12 @@ module Mastodon
|
||||||
When the --limited-federation-mode option is given, instead of purging accounts
|
When the --limited-federation-mode option is given, instead of purging accounts
|
||||||
from a single domain, all accounts from domains that have not been explicitly allowed
|
from a single domain, all accounts from domains that have not been explicitly allowed
|
||||||
are removed from the database.
|
are removed from the database.
|
||||||
|
|
||||||
|
When the --by-uri option is given, DOMAIN is used to match the domain part of actor
|
||||||
|
URIs rather than the domain part of the webfinger handle. For instance, an account
|
||||||
|
that has the handle `foo@bar.com` but whose profile is at the URL
|
||||||
|
`https://mastodon-bar.com/users/foo`, would be purged by either
|
||||||
|
`tootctl domains purge bar.com` or `tootctl domains purge --by-uri mastodon-bar.com`.
|
||||||
LONG_DESC
|
LONG_DESC
|
||||||
def purge(*domains)
|
def purge(*domains)
|
||||||
dry_run = options[:dry_run] ? ' (DRY RUN)' : ''
|
dry_run = options[:dry_run] ? ' (DRY RUN)' : ''
|
||||||
|
@ -34,7 +41,11 @@ module Mastodon
|
||||||
if options[:limited_federation_mode]
|
if options[:limited_federation_mode]
|
||||||
Account.remote.where.not(domain: DomainAllow.pluck(:domain))
|
Account.remote.where.not(domain: DomainAllow.pluck(:domain))
|
||||||
elsif !domains.empty?
|
elsif !domains.empty?
|
||||||
Account.remote.where(domain: domains)
|
if options[:by_uri]
|
||||||
|
domains.map { |domain| Account.remote.where(Account.arel_table[:uri].matches("https://#{domain}/%", false, true)) }.reduce(:or)
|
||||||
|
else
|
||||||
|
Account.remote.where(domain: domains)
|
||||||
|
end
|
||||||
else
|
else
|
||||||
say('No domain(s) given', :red)
|
say('No domain(s) given', :red)
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
|
@ -69,7 +69,7 @@
|
||||||
"@babel/runtime": "^7.14.6",
|
"@babel/runtime": "^7.14.6",
|
||||||
"@gamestdio/websocket": "^0.3.2",
|
"@gamestdio/websocket": "^0.3.2",
|
||||||
"@github/webauthn-json": "^0.5.7",
|
"@github/webauthn-json": "^0.5.7",
|
||||||
"@rails/ujs": "^6.1.3",
|
"@rails/ujs": "^6.1.4",
|
||||||
"array-includes": "^3.1.3",
|
"array-includes": "^3.1.3",
|
||||||
"atrament": "0.2.4",
|
"atrament": "0.2.4",
|
||||||
"arrow-key-navigation": "^1.2.0",
|
"arrow-key-navigation": "^1.2.0",
|
||||||
|
@ -171,14 +171,14 @@
|
||||||
"webpack-cli": "^3.3.12",
|
"webpack-cli": "^3.3.12",
|
||||||
"webpack-merge": "^5.8.0",
|
"webpack-merge": "^5.8.0",
|
||||||
"wicg-inert": "^3.1.1",
|
"wicg-inert": "^3.1.1",
|
||||||
"ws": "^7.5.1"
|
"ws": "^7.5.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@testing-library/jest-dom": "^5.14.1",
|
"@testing-library/jest-dom": "^5.14.1",
|
||||||
"@testing-library/react": "^11.2.7",
|
"@testing-library/react": "^11.2.7",
|
||||||
"babel-eslint": "^10.1.0",
|
"babel-eslint": "^10.1.0",
|
||||||
"babel-jest": "^27.0.6",
|
"babel-jest": "^27.0.6",
|
||||||
"eslint": "^7.29.0",
|
"eslint": "^7.30.0",
|
||||||
"eslint-plugin-import": "~2.23.4",
|
"eslint-plugin-import": "~2.23.4",
|
||||||
"eslint-plugin-jsx-a11y": "~6.4.1",
|
"eslint-plugin-jsx-a11y": "~6.4.1",
|
||||||
"eslint-plugin-promise": "~5.1.0",
|
"eslint-plugin-promise": "~5.1.0",
|
||||||
|
|
|
@ -55,6 +55,10 @@ RSpec.describe ActivityPub::OutboxesController, type: :controller do
|
||||||
|
|
||||||
it_behaves_like 'cachable response'
|
it_behaves_like 'cachable response'
|
||||||
|
|
||||||
|
it 'does not have a Vary header' do
|
||||||
|
expect(response.headers['Vary']).to be_nil
|
||||||
|
end
|
||||||
|
|
||||||
context 'when account is permanently suspended' do
|
context 'when account is permanently suspended' do
|
||||||
before do
|
before do
|
||||||
account.suspend!
|
account.suspend!
|
||||||
|
@ -96,6 +100,10 @@ RSpec.describe ActivityPub::OutboxesController, type: :controller do
|
||||||
|
|
||||||
it_behaves_like 'cachable response'
|
it_behaves_like 'cachable response'
|
||||||
|
|
||||||
|
it 'returns Vary header with Signature' do
|
||||||
|
expect(response.headers['Vary']).to include 'Signature'
|
||||||
|
end
|
||||||
|
|
||||||
context 'when account is permanently suspended' do
|
context 'when account is permanently suspended' do
|
||||||
before do
|
before do
|
||||||
account.suspend!
|
account.suspend!
|
||||||
|
@ -144,7 +152,7 @@ RSpec.describe ActivityPub::OutboxesController, type: :controller do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns private Cache-Control header' do
|
it 'returns private Cache-Control header' do
|
||||||
expect(response.headers['Cache-Control']).to eq 'max-age=0, private'
|
expect(response.headers['Cache-Control']).to eq 'max-age=60, private'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -170,7 +178,7 @@ RSpec.describe ActivityPub::OutboxesController, type: :controller do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns private Cache-Control header' do
|
it 'returns private Cache-Control header' do
|
||||||
expect(response.headers['Cache-Control']).to eq 'max-age=0, private'
|
expect(response.headers['Cache-Control']).to eq 'max-age=60, private'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -195,7 +203,7 @@ RSpec.describe ActivityPub::OutboxesController, type: :controller do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns private Cache-Control header' do
|
it 'returns private Cache-Control header' do
|
||||||
expect(response.headers['Cache-Control']).to eq 'max-age=0, private'
|
expect(response.headers['Cache-Control']).to eq 'max-age=60, private'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -220,7 +228,7 @@ RSpec.describe ActivityPub::OutboxesController, type: :controller do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns private Cache-Control header' do
|
it 'returns private Cache-Control header' do
|
||||||
expect(response.headers['Cache-Control']).to eq 'max-age=0, private'
|
expect(response.headers['Cache-Control']).to eq 'max-age=60, private'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -16,7 +16,7 @@ describe Admin::ResetsController do
|
||||||
|
|
||||||
post :create, params: { account_id: account.id }
|
post :create, params: { account_id: account.id }
|
||||||
|
|
||||||
expect(response).to redirect_to(admin_accounts_path)
|
expect(response).to redirect_to(admin_account_path(account.id))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,12 +15,12 @@ describe Admin::TwoFactorAuthenticationsController do
|
||||||
user.update(otp_required_for_login: true)
|
user.update(otp_required_for_login: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'redirects to admin accounts page' do
|
it 'redirects to admin account page' do
|
||||||
delete :destroy, params: { user_id: user.id }
|
delete :destroy, params: { user_id: user.id }
|
||||||
|
|
||||||
user.reload
|
user.reload
|
||||||
expect(user.otp_enabled?).to eq false
|
expect(user.otp_enabled?).to eq false
|
||||||
expect(response).to redirect_to(admin_accounts_path)
|
expect(response).to redirect_to(admin_account_path(user.account_id))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -38,13 +38,13 @@ describe Admin::TwoFactorAuthenticationsController do
|
||||||
nickname: 'Security Key')
|
nickname: 'Security Key')
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'redirects to admin accounts page' do
|
it 'redirects to admin account page' do
|
||||||
delete :destroy, params: { user_id: user.id }
|
delete :destroy, params: { user_id: user.id }
|
||||||
|
|
||||||
user.reload
|
user.reload
|
||||||
expect(user.otp_enabled?).to eq false
|
expect(user.otp_enabled?).to eq false
|
||||||
expect(user.webauthn_enabled?).to eq false
|
expect(user.webauthn_enabled?).to eq false
|
||||||
expect(response).to redirect_to(admin_accounts_path)
|
expect(response).to redirect_to(admin_account_path(user.account_id))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -24,6 +24,10 @@ describe WellKnown::WebfingerController, type: :controller do
|
||||||
expect(response).to have_http_status(200)
|
expect(response).to have_http_status(200)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'does not set a Vary header' do
|
||||||
|
expect(response.headers['Vary']).to be_nil
|
||||||
|
end
|
||||||
|
|
||||||
it 'returns application/jrd+json' do
|
it 'returns application/jrd+json' do
|
||||||
expect(response.media_type).to eq 'application/jrd+json'
|
expect(response.media_type).to eq 'application/jrd+json'
|
||||||
end
|
end
|
||||||
|
|
|
@ -37,7 +37,7 @@ describe TagFeed, type: :service do
|
||||||
expect(results).to include both
|
expect(results).to include both
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'handles being passed non existant tag names' do
|
it 'handles being passed non existent tag names' do
|
||||||
results = described_class.new(tag1, nil, any: ['wark']).get(20)
|
results = described_class.new(tag1, nil, any: ['wark']).get(20)
|
||||||
expect(results).to include status1
|
expect(results).to include status1
|
||||||
expect(results).to_not include status2
|
expect(results).to_not include status2
|
||||||
|
|
|
@ -344,6 +344,34 @@ RSpec.describe User, type: :model do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#reset_password!' do
|
||||||
|
subject(:user) { Fabricate(:user, password: 'foobar12345') }
|
||||||
|
|
||||||
|
let!(:session_activation) { Fabricate(:session_activation, user: user) }
|
||||||
|
let!(:access_token) { Fabricate(:access_token, resource_owner_id: user.id) }
|
||||||
|
let!(:web_push_subscription) { Fabricate(:web_push_subscription, access_token: access_token) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
user.reset_password!
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'changes the password immediately' do
|
||||||
|
expect(user.external_or_valid_password?('foobar12345')).to be false
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'deactivates all sessions' do
|
||||||
|
expect(user.session_activations.count).to eq 0
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'revokes all access tokens' do
|
||||||
|
expect(Doorkeeper::AccessToken.active_for(user).count).to eq 0
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'removes push subscriptions' do
|
||||||
|
expect(Web::PushSubscription.where(user: user).or(Web::PushSubscription.where(access_token: access_token)).count).to eq 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '#confirm!' do
|
describe '#confirm!' do
|
||||||
subject(:user) { Fabricate(:user, confirmed_at: confirmed_at) }
|
subject(:user) { Fabricate(:user, confirmed_at: confirmed_at) }
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,37 @@
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe BootstrapTimelineService, type: :service do
|
RSpec.describe BootstrapTimelineService, type: :service do
|
||||||
|
subject { BootstrapTimelineService.new }
|
||||||
|
|
||||||
|
context 'when the new user has registered from an invite' do
|
||||||
|
let(:service) { double }
|
||||||
|
let(:autofollow) { false }
|
||||||
|
let(:inviter) { Fabricate(:user, confirmed_at: 2.days.ago) }
|
||||||
|
let(:invite) { Fabricate(:invite, user: inviter, max_uses: nil, expires_at: 1.hour.from_now, autofollow: autofollow) }
|
||||||
|
let(:new_user) { Fabricate(:user, invite_code: invite.code) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(FollowService).to receive(:new).and_return(service)
|
||||||
|
allow(service).to receive(:call)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the invite has auto-follow enabled' do
|
||||||
|
let(:autofollow) { true }
|
||||||
|
|
||||||
|
it 'calls FollowService to follow the inviter' do
|
||||||
|
subject.call(new_user.account)
|
||||||
|
expect(service).to have_received(:call).with(new_user.account, inviter.account)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the invite does not have auto-follow enable' do
|
||||||
|
let(:autofollow) { false }
|
||||||
|
|
||||||
|
it 'calls FollowService to follow the inviter' do
|
||||||
|
subject.call(new_user.account)
|
||||||
|
expect(service).to_not have_received(:call)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
39
yarn.lock
39
yarn.lock
|
@ -1129,6 +1129,20 @@
|
||||||
resolved "https://registry.yarnpkg.com/@github/webauthn-json/-/webauthn-json-0.5.7.tgz#143bc67f6e0f75f8d188e565741507bb08c31214"
|
resolved "https://registry.yarnpkg.com/@github/webauthn-json/-/webauthn-json-0.5.7.tgz#143bc67f6e0f75f8d188e565741507bb08c31214"
|
||||||
integrity sha512-SUYsttDxFSvWvvJssJpwzjmRCqYfdfqC9VCmAHQYfdKCVelyJteCHo9/lK1CB72mx/jrl6cFNY08aua4J2jIyg==
|
integrity sha512-SUYsttDxFSvWvvJssJpwzjmRCqYfdfqC9VCmAHQYfdKCVelyJteCHo9/lK1CB72mx/jrl6cFNY08aua4J2jIyg==
|
||||||
|
|
||||||
|
"@humanwhocodes/config-array@^0.5.0":
|
||||||
|
version "0.5.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9"
|
||||||
|
integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==
|
||||||
|
dependencies:
|
||||||
|
"@humanwhocodes/object-schema" "^1.2.0"
|
||||||
|
debug "^4.1.1"
|
||||||
|
minimatch "^3.0.4"
|
||||||
|
|
||||||
|
"@humanwhocodes/object-schema@^1.2.0":
|
||||||
|
version "1.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz#87de7af9c231826fdd68ac7258f77c429e0e5fcf"
|
||||||
|
integrity sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==
|
||||||
|
|
||||||
"@istanbuljs/load-nyc-config@^1.0.0":
|
"@istanbuljs/load-nyc-config@^1.0.0":
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced"
|
resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced"
|
||||||
|
@ -1370,10 +1384,10 @@
|
||||||
resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.11.tgz#aeb16f50649a91af79dbe36574b66d0f9e4d9f71"
|
resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.11.tgz#aeb16f50649a91af79dbe36574b66d0f9e4d9f71"
|
||||||
integrity sha512-3NsZsJIA/22P3QUyrEDNA2D133H4j224twJrdipXN38dpnIOzAbUDtOwkcJ5pXmn75w7LSQDjA4tO9dm1XlqlA==
|
integrity sha512-3NsZsJIA/22P3QUyrEDNA2D133H4j224twJrdipXN38dpnIOzAbUDtOwkcJ5pXmn75w7LSQDjA4tO9dm1XlqlA==
|
||||||
|
|
||||||
"@rails/ujs@^6.1.3":
|
"@rails/ujs@^6.1.4":
|
||||||
version "6.1.3"
|
version "6.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/@rails/ujs/-/ujs-6.1.3.tgz#90ef26caa0925492b1a3b1495db09cfbe49e745e"
|
resolved "https://registry.yarnpkg.com/@rails/ujs/-/ujs-6.1.4.tgz#093d5341595a02089ed309dec40f3c37da7b1b10"
|
||||||
integrity sha512-9mip5o+LVouWAqLMNJWhxda+D5uP+4RziNECgOGJlL6k3rc5SC/ljCHpV9Cym4i3oeGZkpZJ2tu4frCwt84kzQ==
|
integrity sha512-O3lEzL5DYbxppMdsFSw36e4BHIlfz/xusynwXGv3l2lhSlvah41qviRpsoAlKXxl37nZAqK+UUF5cnGGK45Mfw==
|
||||||
|
|
||||||
"@sinonjs/commons@^1.7.0":
|
"@sinonjs/commons@^1.7.0":
|
||||||
version "1.8.1"
|
version "1.8.1"
|
||||||
|
@ -4441,13 +4455,14 @@ eslint@^2.7.0:
|
||||||
text-table "~0.2.0"
|
text-table "~0.2.0"
|
||||||
user-home "^2.0.0"
|
user-home "^2.0.0"
|
||||||
|
|
||||||
eslint@^7.29.0:
|
eslint@^7.30.0:
|
||||||
version "7.29.0"
|
version "7.30.0"
|
||||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.29.0.tgz#ee2a7648f2e729485e4d0bd6383ec1deabc8b3c0"
|
resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.30.0.tgz#6d34ab51aaa56112fd97166226c9a97f505474f8"
|
||||||
integrity sha512-82G/JToB9qIy/ArBzIWG9xvvwL3R86AlCjtGw+A29OMZDqhTybz/MByORSukGxeI+YPCR4coYyITKk8BFH9nDA==
|
integrity sha512-VLqz80i3as3NdloY44BQSJpFw534L9Oh+6zJOUaViV4JPd+DaHwutqP7tcpkW3YiXbK6s05RZl7yl7cQn+lijg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/code-frame" "7.12.11"
|
"@babel/code-frame" "7.12.11"
|
||||||
"@eslint/eslintrc" "^0.4.2"
|
"@eslint/eslintrc" "^0.4.2"
|
||||||
|
"@humanwhocodes/config-array" "^0.5.0"
|
||||||
ajv "^6.10.0"
|
ajv "^6.10.0"
|
||||||
chalk "^4.0.0"
|
chalk "^4.0.0"
|
||||||
cross-spawn "^7.0.2"
|
cross-spawn "^7.0.2"
|
||||||
|
@ -11715,10 +11730,10 @@ ws@^6.2.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
async-limiter "~1.0.0"
|
async-limiter "~1.0.0"
|
||||||
|
|
||||||
ws@^7.2.3, ws@^7.3.1, ws@^7.5.1:
|
ws@^7.2.3, ws@^7.3.1, ws@^7.5.2:
|
||||||
version "7.5.1"
|
version "7.5.2"
|
||||||
resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.1.tgz#44fc000d87edb1d9c53e51fbc69a0ac1f6871d66"
|
resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.2.tgz#09cc8fea3bec1bc5ed44ef51b42f945be36900f6"
|
||||||
integrity sha512-2c6faOUH/nhoQN6abwMloF7Iyl0ZS2E9HGtsiLrWn0zOOMWlhtDmdf/uihDt6jnuCxgtwGBNy6Onsoy2s2O2Ow==
|
integrity sha512-lkF7AWRicoB9mAgjeKbGqVUekLnSNO4VjKVnuPHpQeOxZOErX6BPXwJk70nFslRCEEA8EVW7ZjKwXaP9N+1sKQ==
|
||||||
|
|
||||||
xml-name-validator@^3.0.0:
|
xml-name-validator@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
|
|
Loading…
Reference in a new issue