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:
@@ -11,7 +11,11 @@ class ActivityPub::OutboxesController < ActivityPub::BaseController
|
||||
before_action :set_cache_headers
|
||||
|
||||
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'
|
||||
end
|
||||
|
||||
@@ -76,4 +80,8 @@ class ActivityPub::OutboxesController < ActivityPub::BaseController
|
||||
def set_account
|
||||
@account = params[:account_username].present? ? Account.find_local!(username_param) : Account.representative
|
||||
end
|
||||
|
||||
def set_cache_headers
|
||||
response.headers['Vary'] = 'Signature' if authorized_fetch_mode? || page_requested?
|
||||
end
|
||||
end
|
||||
|
@@ -6,9 +6,9 @@ module Admin
|
||||
|
||||
def create
|
||||
authorize @user, :reset_password?
|
||||
@user.send_reset_password_instructions
|
||||
@user.reset_password!
|
||||
log_action :reset_password, @user
|
||||
redirect_to admin_accounts_path
|
||||
redirect_to admin_account_path(@user.account_id)
|
||||
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!
|
||||
log_action :disable_2fa, @user
|
||||
UserMailer.two_factor_disabled(@user).deliver_later!
|
||||
redirect_to admin_accounts_path
|
||||
redirect_to admin_account_path(@user.account_id)
|
||||
end
|
||||
|
||||
private
|
||||
|
@@ -4,7 +4,6 @@ module WellKnown
|
||||
class WebfingerController < ActionController::Base
|
||||
include RoutingHelper
|
||||
|
||||
before_action { response.headers['Vary'] = 'Accept' }
|
||||
before_action :set_account
|
||||
before_action :check_account_suspension
|
||||
|
||||
@@ -39,10 +38,12 @@ module WellKnown
|
||||
end
|
||||
|
||||
def bad_request
|
||||
expires_in(3.minutes, public: true)
|
||||
head 400
|
||||
end
|
||||
|
||||
def not_found
|
||||
expires_in(3.minutes, public: true)
|
||||
head 404
|
||||
end
|
||||
|
||||
|
@@ -84,19 +84,19 @@ module AccountsHelper
|
||||
def account_description(account)
|
||||
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),
|
||||
].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),
|
||||
].join(' '),
|
||||
]
|
||||
|
||||
unless hide_followers_count?(account)
|
||||
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),
|
||||
].join(' ')
|
||||
end
|
||||
|
@@ -14,6 +14,17 @@ module ApplicationHelper
|
||||
ku
|
||||
).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)
|
||||
paths.any? { |path| current_page?(path) } ? 'active' : ''
|
||||
end
|
||||
|
@@ -7291,6 +7291,7 @@ noscript {
|
||||
&__account {
|
||||
display: flex;
|
||||
text-decoration: none;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.account__avatar {
|
||||
|
@@ -15,6 +15,7 @@
|
||||
|
||||
class AccountStat < ApplicationRecord
|
||||
self.locking_column = nil
|
||||
self.ignored_columns = %w(lock_version)
|
||||
|
||||
belongs_to :account, inverse_of: :account_stat
|
||||
|
||||
|
@@ -42,6 +42,7 @@
|
||||
# sign_in_token_sent_at :datetime
|
||||
# webauthn_id :string
|
||||
# sign_up_ip :inet
|
||||
# skip_sign_in_token :boolean
|
||||
#
|
||||
|
||||
class User < ApplicationRecord
|
||||
@@ -200,7 +201,7 @@ class User < ApplicationRecord
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
def functional?
|
||||
@@ -329,12 +330,32 @@ class User < ApplicationRecord
|
||||
super
|
||||
end
|
||||
|
||||
def reset_password!(new_password, new_password_confirmation)
|
||||
def reset_password(new_password, new_password_confirmation)
|
||||
return false if encrypted_password.blank?
|
||||
|
||||
super
|
||||
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?
|
||||
setting_display_media == 'show_all'
|
||||
end
|
||||
|
@@ -13,6 +13,14 @@ class UserPolicy < ApplicationPolicy
|
||||
admin? && !record.staff?
|
||||
end
|
||||
|
||||
def disable_sign_in_token_auth?
|
||||
staff?
|
||||
end
|
||||
|
||||
def enable_sign_in_token_auth?
|
||||
staff?
|
||||
end
|
||||
|
||||
def confirm?
|
||||
staff? && !record.confirmed?
|
||||
end
|
||||
|
@@ -16,11 +16,11 @@
|
||||
.row__information-board
|
||||
.information-board__section
|
||||
%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
|
||||
.information-board__section
|
||||
%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
|
||||
.row__mascot
|
||||
.landing-page__mascot
|
||||
|
@@ -70,10 +70,10 @@
|
||||
|
||||
.hero-widget__counters__wrapper
|
||||
.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
|
||||
.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
|
||||
= t 'about.active_count_after'
|
||||
%abbr{ title: t('about.active_footnote') } *
|
||||
|
@@ -15,17 +15,17 @@
|
||||
.details-counters
|
||||
.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
|
||||
%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)
|
||||
|
||||
.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
|
||||
%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)
|
||||
|
||||
.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
|
||||
%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)
|
||||
.spacer
|
||||
.public-account-header__tabs__tabs__buttons
|
||||
@@ -36,8 +36,8 @@
|
||||
|
||||
.public-account-header__extra__links
|
||||
= 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)
|
||||
= 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)
|
||||
|
@@ -81,6 +81,6 @@
|
||||
= t('accounts.nothing_here')
|
||||
- else
|
||||
%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'
|
||||
|
@@ -129,6 +129,27 @@
|
||||
- else
|
||||
= 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)
|
||||
%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
|
||||
%th= t('simple_form.labels.defaults.locale')
|
||||
@@ -221,9 +242,6 @@
|
||||
|
||||
%div
|
||||
- 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?
|
||||
= 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
|
||||
|
@@ -13,42 +13,42 @@
|
||||
%div
|
||||
= link_to admin_accounts_url(local: 1, recent: 1) do
|
||||
.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'
|
||||
%div
|
||||
%div
|
||||
.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'
|
||||
%div
|
||||
%div
|
||||
.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'
|
||||
%div
|
||||
= link_to admin_pending_accounts_path do
|
||||
.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'
|
||||
%div
|
||||
= link_to admin_reports_url do
|
||||
.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'
|
||||
%div
|
||||
= link_to admin_tags_path(pending_review: '1') do
|
||||
.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'
|
||||
%div
|
||||
%div
|
||||
.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'
|
||||
%div
|
||||
= link_to sidekiq_url do
|
||||
.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__widgets
|
||||
|
@@ -7,10 +7,10 @@
|
||||
%tr
|
||||
%td= account_link_to account
|
||||
%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
|
||||
%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
|
||||
%td.accounts-table__count
|
||||
- if account.last_status_at.present?
|
||||
|
@@ -30,4 +30,4 @@
|
||||
= ' / '
|
||||
%span.negative-hint
|
||||
= 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'
|
||||
= 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
|
||||
.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
|
||||
.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
|
||||
.accounts-table__count
|
||||
- if account.last_status_at.present?
|
||||
|
@@ -9,10 +9,10 @@
|
||||
= interrelationships_icon(@relationships, account.id)
|
||||
%td= account_link_to account
|
||||
%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
|
||||
%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
|
||||
%td.accounts-table__count
|
||||
- if account.last_status_at.present?
|
||||
|
@@ -28,4 +28,4 @@
|
||||
- else
|
||||
%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') }
|
||||
.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')
|
||||
- else
|
||||
= 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?
|
||||
= link_to remote_interaction_path(status, type: :reblog), class: 'modal-button detailed-status__link' do
|
||||
= 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
|
||||
= 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?
|
||||
|
Reference in New Issue
Block a user