Change user settings to be stored in a more optimal way (#23630)

Co-authored-by: Claire <claire.github-309c@sitedethib.com>
This commit is contained in:
Eugen Rochko
2023-03-30 14:44:00 +02:00
committed by GitHub
parent e7c3e55874
commit a9b5598c97
36 changed files with 817 additions and 525 deletions

View File

@ -13,7 +13,7 @@ class Api::V1::Accounts::CredentialsController < Api::BaseController
def update
@account = current_account
UpdateAccountService.new.call(@account, account_params, raise_error: true)
UserSettingsDecorator.new(current_user).update(user_settings_params) if user_settings_params
current_user.update(user_params) if user_params
ActivityPub::UpdateDistributionWorker.perform_async(@account.id)
render json: @account, serializer: REST::CredentialAccountSerializer
end
@ -34,15 +34,17 @@ class Api::V1::Accounts::CredentialsController < Api::BaseController
)
end
def user_settings_params
def user_params
return nil if params[:source].blank?
source_params = params.require(:source)
{
'setting_default_privacy' => source_params.fetch(:privacy, @account.user.setting_default_privacy),
'setting_default_sensitive' => source_params.fetch(:sensitive, @account.user.setting_default_sensitive),
'setting_default_language' => source_params.fetch(:language, @account.user.setting_default_language),
settings_attributes: {
default_privacy: source_params.fetch(:privacy, @account.user.setting_default_privacy),
default_sensitive: source_params.fetch(:sensitive, @account.user.setting_default_sensitive),
default_language: source_params.fetch(:language, @account.user.setting_default_language),
},
}
end
end

View File

@ -4,8 +4,6 @@ class Settings::PreferencesController < Settings::BaseController
def show; end
def update
user_settings.update(user_settings_params.to_h)
if current_user.update(user_params)
I18n.locale = current_user.locale
redirect_to after_update_redirect_path, notice: I18n.t('generic.changes_saved_msg')
@ -20,43 +18,7 @@ class Settings::PreferencesController < Settings::BaseController
settings_preferences_path
end
def user_settings
UserSettingsDecorator.new(current_user)
end
def user_params
params.require(:user).permit(
:locale,
chosen_languages: []
)
end
def user_settings_params
params.require(:user).permit(
:setting_default_privacy,
:setting_default_sensitive,
:setting_default_language,
:setting_unfollow_modal,
:setting_boost_modal,
:setting_delete_modal,
:setting_auto_play_gif,
:setting_display_media,
:setting_expand_spoilers,
:setting_reduce_motion,
:setting_disable_swiping,
:setting_system_font_ui,
:setting_noindex,
:setting_theme,
:setting_aggregate_reblogs,
:setting_show_application,
:setting_advanced_layout,
:setting_use_blurhash,
:setting_use_pending_items,
:setting_trends,
:setting_crop_images,
:setting_always_send_emails,
notification_emails: %i(follow follow_request reblog favourite mention report pending_account trending_tag appeal),
interactions: %i(must_be_follower must_be_following must_be_following_dm)
)
params.require(:user).permit(:locale, chosen_languages: [], settings_attributes: UserSettings.keys)
end
end

View File

@ -1,155 +0,0 @@
# frozen_string_literal: true
class UserSettingsDecorator
attr_reader :user, :settings
def initialize(user)
@user = user
end
def update(settings)
@settings = settings
process_update
end
private
def process_update
user.settings['notification_emails'] = merged_notification_emails if change?('notification_emails')
user.settings['interactions'] = merged_interactions if change?('interactions')
user.settings['default_privacy'] = default_privacy_preference if change?('setting_default_privacy')
user.settings['default_sensitive'] = default_sensitive_preference if change?('setting_default_sensitive')
user.settings['default_language'] = default_language_preference if change?('setting_default_language')
user.settings['unfollow_modal'] = unfollow_modal_preference if change?('setting_unfollow_modal')
user.settings['boost_modal'] = boost_modal_preference if change?('setting_boost_modal')
user.settings['delete_modal'] = delete_modal_preference if change?('setting_delete_modal')
user.settings['auto_play_gif'] = auto_play_gif_preference if change?('setting_auto_play_gif')
user.settings['display_media'] = display_media_preference if change?('setting_display_media')
user.settings['expand_spoilers'] = expand_spoilers_preference if change?('setting_expand_spoilers')
user.settings['reduce_motion'] = reduce_motion_preference if change?('setting_reduce_motion')
user.settings['disable_swiping'] = disable_swiping_preference if change?('setting_disable_swiping')
user.settings['system_font_ui'] = system_font_ui_preference if change?('setting_system_font_ui')
user.settings['noindex'] = noindex_preference if change?('setting_noindex')
user.settings['theme'] = theme_preference if change?('setting_theme')
user.settings['aggregate_reblogs'] = aggregate_reblogs_preference if change?('setting_aggregate_reblogs')
user.settings['show_application'] = show_application_preference if change?('setting_show_application')
user.settings['advanced_layout'] = advanced_layout_preference if change?('setting_advanced_layout')
user.settings['use_blurhash'] = use_blurhash_preference if change?('setting_use_blurhash')
user.settings['use_pending_items'] = use_pending_items_preference if change?('setting_use_pending_items')
user.settings['trends'] = trends_preference if change?('setting_trends')
user.settings['crop_images'] = crop_images_preference if change?('setting_crop_images')
user.settings['always_send_emails'] = always_send_emails_preference if change?('setting_always_send_emails')
end
def merged_notification_emails
user.settings['notification_emails'].merge coerced_settings('notification_emails').to_h
end
def merged_interactions
user.settings['interactions'].merge coerced_settings('interactions').to_h
end
def default_privacy_preference
settings['setting_default_privacy']
end
def default_sensitive_preference
boolean_cast_setting 'setting_default_sensitive'
end
def unfollow_modal_preference
boolean_cast_setting 'setting_unfollow_modal'
end
def boost_modal_preference
boolean_cast_setting 'setting_boost_modal'
end
def delete_modal_preference
boolean_cast_setting 'setting_delete_modal'
end
def system_font_ui_preference
boolean_cast_setting 'setting_system_font_ui'
end
def auto_play_gif_preference
boolean_cast_setting 'setting_auto_play_gif'
end
def display_media_preference
settings['setting_display_media']
end
def expand_spoilers_preference
boolean_cast_setting 'setting_expand_spoilers'
end
def reduce_motion_preference
boolean_cast_setting 'setting_reduce_motion'
end
def disable_swiping_preference
boolean_cast_setting 'setting_disable_swiping'
end
def noindex_preference
boolean_cast_setting 'setting_noindex'
end
def show_application_preference
boolean_cast_setting 'setting_show_application'
end
def theme_preference
settings['setting_theme']
end
def default_language_preference
settings['setting_default_language']
end
def aggregate_reblogs_preference
boolean_cast_setting 'setting_aggregate_reblogs'
end
def advanced_layout_preference
boolean_cast_setting 'setting_advanced_layout'
end
def use_blurhash_preference
boolean_cast_setting 'setting_use_blurhash'
end
def use_pending_items_preference
boolean_cast_setting 'setting_use_pending_items'
end
def trends_preference
boolean_cast_setting 'setting_trends'
end
def crop_images_preference
boolean_cast_setting 'setting_crop_images'
end
def always_send_emails_preference
boolean_cast_setting 'setting_always_send_emails'
end
def boolean_cast_setting(key)
ActiveModel::Type::Boolean.new.cast(settings[key])
end
def coerced_settings(key)
coerce_values settings.fetch(key, {})
end
def coerce_values(params_hash)
params_hash.transform_values { |x| ActiveModel::Type::Boolean.new.cast(x) }
end
def change?(key)
!settings[key].nil?
end
end

View File

@ -0,0 +1,19 @@
# frozen_string_literal: true
class UserSettingsSerializer
def self.load(value)
json = begin
if value.blank?
{}
else
Oj.load(value, symbol_keys: true)
end
end
UserSettings.new(json)
end
def self.dump(value)
Oj.dump(value.as_json)
end
end

View File

@ -0,0 +1,141 @@
# frozen_string_literal: true
module HasUserSettings
extend ActiveSupport::Concern
included do
serialize :settings, UserSettingsSerializer
end
def settings_attributes=(attributes)
settings.update(attributes)
end
def prefers_noindex?
settings['noindex']
end
def preferred_posting_language
valid_locale_cascade(settings['default_language'], locale, I18n.locale)
end
def setting_auto_play_gif
settings['web.auto_play']
end
def setting_default_sensitive
settings['default_sensitive']
end
def setting_unfollow_modal
settings['web.unfollow_modal']
end
def setting_boost_modal
settings['web.reblog_modal']
end
def setting_delete_modal
settings['web.delete_modal']
end
def setting_reduce_motion
settings['web.reduce_motion']
end
def setting_system_font_ui
settings['web.use_system_font']
end
def setting_noindex
settings['noindex']
end
def setting_theme
settings['theme']
end
def setting_display_media
settings['web.display_media']
end
def setting_expand_spoilers
settings['web.expand_content_warnings']
end
def setting_default_language
settings['default_language']
end
def setting_aggregate_reblogs
settings['aggregate_reblogs']
end
def setting_show_application
settings['show_application']
end
def setting_advanced_layout
settings['web.advanced_layout']
end
def setting_use_blurhash
settings['web.use_blurhash']
end
def setting_use_pending_items
settings['web.use_pending_items']
end
def setting_trends
settings['web.trends']
end
def setting_crop_images
settings['web.crop_images']
end
def setting_disable_swiping
settings['web.disable_swiping']
end
def setting_always_send_emails
settings['always_send_emails']
end
def setting_default_privacy
settings['default_privacy'] || (account.locked? ? 'private' : 'public')
end
def allows_report_emails?
settings['notification_emails.report']
end
def allows_pending_account_emails?
settings['notification_emails.pending_account']
end
def allows_appeal_emails?
settings['notification_emails.appeal']
end
def allows_trends_review_emails?
settings['notification_emails.trends']
end
def aggregates_reblogs?
settings['aggregate_reblogs']
end
def shows_application?
settings['show_application']
end
def show_all_media?
settings['web.display_media'] == 'show_all'
end
def hide_all_media?
settings['web.display_media'] == 'hide_all'
end
end

View File

@ -39,10 +39,11 @@
# webauthn_id :string
# sign_up_ip :inet
# role_id :bigint(8)
# settings :text
#
class User < ApplicationRecord
self.ignored_columns = %w(
self.ignored_columns += %w(
remember_created_at
remember_token
current_sign_in_ip
@ -51,9 +52,9 @@ class User < ApplicationRecord
filtered_languages
)
include Settings::Extend
include Redisable
include LanguagesHelper
include HasUserSettings
# The home and list feeds will be stored in Redis for this amount
# of time, and status fan-out to followers will include only people
@ -132,13 +133,6 @@ class User < ApplicationRecord
has_many :session_activations, dependent: :destroy
delegate :auto_play_gif, :default_sensitive, :unfollow_modal, :boost_modal, :delete_modal,
:reduce_motion, :system_font_ui, :noindex, :theme, :display_media,
:expand_spoilers, :default_language, :aggregate_reblogs, :show_application,
:advanced_layout, :use_blurhash, :use_pending_items, :trends, :crop_images,
:disable_swiping, :always_send_emails,
to: :settings, prefix: :setting, allow_nil: false
delegate :can?, to: :role
attr_reader :invite_code
@ -302,42 +296,6 @@ class User < ApplicationRecord
save!
end
def prefers_noindex?
setting_noindex
end
def preferred_posting_language
valid_locale_cascade(settings.default_language, locale, I18n.locale)
end
def setting_default_privacy
settings.default_privacy || (account.locked? ? 'private' : 'public')
end
def allows_report_emails?
settings.notification_emails['report']
end
def allows_pending_account_emails?
settings.notification_emails['pending_account']
end
def allows_appeal_emails?
settings.notification_emails['appeal']
end
def allows_trends_review_emails?
settings.notification_emails['trending_tag']
end
def aggregates_reblogs?
@aggregates_reblogs ||= settings.aggregate_reblogs
end
def shows_application?
@shows_application ||= settings.show_application
end
def token_for_app(app)
return nil if app.nil? || app.owner != self
@ -417,14 +375,6 @@ class User < ApplicationRecord
send_reset_password_instructions
end
def show_all_media?
setting_display_media == 'show_all'
end
def hide_all_media?
setting_display_media == 'hide_all'
end
protected
def send_devise_notification(notification, *args, **kwargs)
@ -494,7 +444,8 @@ class User < ApplicationRecord
def sanitize_languages
return if chosen_languages.nil?
chosen_languages.reject!(&:blank?)
chosen_languages.compact_blank!
self.chosen_languages = nil if chosen_languages.empty?
end

View File

@ -0,0 +1,99 @@
# frozen_string_literal: true
class UserSettings
class Error < StandardError; end
class KeyError < Error; end
include UserSettings::DSL
include UserSettings::Glue
setting :always_send_emails, default: false
setting :aggregate_reblogs, default: true
setting :theme, default: -> { ::Setting.theme }
setting :noindex, default: -> { ::Setting.noindex }
setting :show_application, default: true
setting :default_language, default: nil
setting :default_sensitive, default: false
setting :default_privacy, default: nil
namespace :web do
setting :crop_images, default: true
setting :advanced_layout, default: false
setting :trends, default: true
setting :use_blurhash, default: true
setting :use_pending_items, default: false
setting :use_system_font, default: false
setting :disable_swiping, default: false
setting :delete_modal, default: true
setting :reblog_modal, default: false
setting :unfollow_modal, default: true
setting :reduce_motion, default: false
setting :expand_content_warnings, default: false
setting :display_media, default: 'default', in: %w(default show_all hide_all)
setting :auto_play, default: false
end
namespace :notification_emails do
setting :follow, default: true
setting :reblog, default: false
setting :favourite, default: false
setting :mention, default: true
setting :follow_request, default: true
setting :report, default: true
setting :pending_account, default: true
setting :trends, default: true
setting :appeal, default: true
end
namespace :interactions do
setting :must_be_follower, default: false
setting :must_be_following, default: false
setting :must_be_following_dm, default: false
end
def initialize(original_hash)
@original_hash = original_hash || {}
end
def [](key)
key = key.to_sym
raise KeyError, "Undefined setting: #{key}" unless self.class.definition_for?(key)
if @original_hash.key?(key)
@original_hash[key]
else
self.class.definition_for(key).default_value
end
end
def []=(key, value)
key = key.to_sym
raise KeyError, "Undefined setting: #{key}" unless self.class.definition_for?(key)
typecast_value = self.class.definition_for(key).type_cast(value)
if typecast_value.nil?
@original_hash.delete(key)
else
@original_hash[key] = typecast_value
end
end
def update(params)
params.each do |k, v|
self[k] = v unless v.nil?
end
end
keys.each do |key|
define_method(key) do
self[key]
end
end
def as_json
@original_hash
end
end

View File

@ -0,0 +1,37 @@
# frozen_string_literal: true
module UserSettings::DSL
module ClassMethods
def setting(key, options = {})
@definitions ||= {}
UserSettings::Setting.new(key, options).tap do |s|
@definitions[s.key] = s
end
end
def namespace(key, &block)
@definitions ||= {}
UserSettings::Namespace.new(key).configure(&block).tap do |n|
@definitions.merge!(n.definitions)
end
end
def keys
@definitions.keys
end
def definition_for(key)
@definitions[key.to_sym]
end
def definition_for?(key)
@definitions.key?(key.to_sym)
end
end
def self.included(base)
base.extend ClassMethods
end
end

View File

@ -0,0 +1,23 @@
# frozen_string_literal: true
module UserSettings::Glue
def to_model
self
end
def to_key
''
end
def persisted?
false
end
def type_for_attribute(key)
self.class.definition_for(key)&.type
end
def has_attribute?(key) # rubocop:disable Naming/PredicateName
self.class.definition_for?(key)
end
end

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
class UserSettings::Namespace
attr_reader :name, :definitions
def initialize(name)
@name = name.to_sym
@definitions = {}
end
def configure(&block)
instance_eval(&block)
self
end
def setting(key, options = {})
UserSettings::Setting.new(key, options.merge(namespace: name)).tap do |s|
@definitions[s.key] = s
end
end
end

View File

@ -0,0 +1,48 @@
# frozen_string_literal: true
class UserSettings::Setting
attr_reader :name, :namespace, :in
def initialize(name, options = {})
@name = name.to_sym
@default_value = options[:default]
@namespace = options[:namespace]
@in = options[:in]
end
def default_value
if @default_value.respond_to?(:call)
@default_value.call
else
@default_value
end
end
def type
if @default_value.is_a?(TrueClass) || @default_value.is_a?(FalseClass)
ActiveModel::Type::Boolean.new
else
ActiveModel::Type::String.new
end
end
def type_cast(value)
if type.respond_to?(:cast)
type.cast(value)
else
value
end
end
def to_a
[key, default_value]
end
def key
if namespace
"#{namespace}.#{name}".to_sym
else
name
end
end
end

View File

@ -3,6 +3,11 @@
class NotifyService < BaseService
include Redisable
NON_EMAIL_TYPES = %i(
admin.report
admin.sign_up
).freeze
def call(recipient, type, activity)
@recipient = recipient
@activity = activity
@ -36,11 +41,11 @@ class NotifyService < BaseService
end
def optional_non_follower?
@recipient.user.settings.interactions['must_be_follower'] && !@notification.from_account.following?(@recipient)
@recipient.user.settings['interactions.must_be_follower'] && !@notification.from_account.following?(@recipient)
end
def optional_non_following?
@recipient.user.settings.interactions['must_be_following'] && !following_sender?
@recipient.user.settings['interactions.must_be_following'] && !following_sender?
end
def message?
@ -82,7 +87,7 @@ class NotifyService < BaseService
def optional_non_following_and_direct?
direct_message? &&
@recipient.user.settings.interactions['must_be_following_dm'] &&
@recipient.user.settings['interactions.must_be_following_dm'] &&
!following_sender? &&
!response_to_recipient?
end
@ -171,6 +176,6 @@ class NotifyService < BaseService
end
def send_email_for_notification_type?
@recipient.user.settings.notification_emails[@notification.type.to_s]
NON_EMAIL_TYPES.exclude?(@notification.type) && @recipient.user.settings["notification_emails.#{@notification.type}"]
end
end

View File

@ -9,57 +9,58 @@
.fields-group.fields-row__column.fields-row__column-6
= f.input :locale, collection: I18n.available_locales, wrapper: :with_label, include_blank: false, label_method: lambda { |locale| native_locale_name(locale) }, selected: I18n.locale, hint: false
.fields-group.fields-row__column.fields-row__column-6
= f.input :setting_theme, collection: Themes.instance.names, label_method: lambda { |theme| I18n.t("themes.#{theme}", default: theme) }, wrapper: :with_label, include_blank: false, hint: false
= f.simple_fields_for :settings, current_user.settings do |ff|
= ff.input :theme, collection: Themes.instance.names, label_method: lambda { |theme| I18n.t("themes.#{theme}", default: theme) }, wrapper: :with_label, include_blank: false, hint: false
- unless I18n.locale == :en
.flash-message.translation-prompt
#{t 'appearance.localization.body'} #{content_tag(:a, t('appearance.localization.guide_link_text'), href: t('appearance.localization.guide_link'), target: '_blank', rel: 'noopener')}
%h4= t 'appearance.advanced_web_interface'
= f.simple_fields_for :settings, current_user.settings do |ff|
%h4= t 'appearance.advanced_web_interface'
%p.hint= t 'appearance.advanced_web_interface_hint'
%p.hint= t 'appearance.advanced_web_interface_hint'
.fields-group
= f.input :setting_advanced_layout, as: :boolean, wrapper: :with_label, hint: false
.fields-group
= ff.input :'web.advanced_layout', wrapper: :with_label, hint: false, label: I18n.t('simple_form.labels.defaults.setting_advanced_layout')
%h4= t 'appearance.animations_and_accessibility'
%h4= t 'appearance.animations_and_accessibility'
.fields-group
= ff.input :'web.use_pending_items', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_use_pending_items'), hint: I18n.t('simple_form.hints.defaults.setting_use_pending_items')
.fields-group
= f.input :setting_use_pending_items, as: :boolean, wrapper: :with_label
.fields-group
= ff.input :'web.auto_play', wrapper: :with_label, recommended: true, label: I18n.t('simple_form.labels.defaults.setting_auto_play_gif')
= ff.input :'web.reduce_motion', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_reduce_motion')
= ff.input :'web.disable_swiping', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_disable_swiping')
= ff.input :'web.use_system_font', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_system_font_ui')
.fields-group
= f.input :setting_auto_play_gif, as: :boolean, wrapper: :with_label, recommended: true
= f.input :setting_reduce_motion, as: :boolean, wrapper: :with_label
= f.input :setting_disable_swiping, as: :boolean, wrapper: :with_label
= f.input :setting_system_font_ui, as: :boolean, wrapper: :with_label
%h4= t 'appearance.toot_layout'
%h4= t 'appearance.toot_layout'
.fields-group
= ff.input :'web.crop_images', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_crop_images')
.fields-group
= f.input :setting_crop_images, as: :boolean, wrapper: :with_label
%h4= t 'appearance.discovery'
%h4= t 'appearance.discovery'
.fields-group
= ff.input :'web.trends', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_trends')
.fields-group
= f.input :setting_trends, as: :boolean, wrapper: :with_label
%h4= t 'appearance.confirmation_dialogs'
%h4= t 'appearance.confirmation_dialogs'
.fields-group
= ff.input :'web.unfollow_modal', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_unfollow_modal')
= ff.input :'web.reblog_modal', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_boost_modal')
= ff.input :'web.delete_modal', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_delete_modal')
.fields-group
= f.input :setting_unfollow_modal, as: :boolean, wrapper: :with_label
= f.input :setting_boost_modal, as: :boolean, wrapper: :with_label
= f.input :setting_delete_modal, as: :boolean, wrapper: :with_label
%h4= t 'appearance.sensitive_content'
%h4= t 'appearance.sensitive_content'
.fields-group
= ff.input :'web.display_media', collection: ['default', 'show_all', 'hide_all'],label_method: lambda { |item| t("simple_form.hints.defaults.setting_display_media_#{item}") }, hint: false, as: :radio_buttons, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li', wrapper: :with_floating_label, label: I18n.t('simple_form.labels.defaults.setting_display_media')
.fields-group
= f.input :setting_display_media, collection: ['default', 'show_all', 'hide_all'], label_method: lambda { |item| t("simple_form.hints.defaults.setting_display_media_#{item}") }, hint: false, as: :radio_buttons, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li', wrapper: :with_floating_label
.fields-group
= ff.input :'web.use_blurhash', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_use_blurhash'), hint: I18n.t('simple_form.hints.defaults.setting_use_blurhash')
.fields-group
= f.input :setting_use_blurhash, as: :boolean, wrapper: :with_label
.fields-group
= f.input :setting_expand_spoilers, as: :boolean, wrapper: :with_label
.fields-group
= ff.input :'web.expand_content_warnings', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_expand_spoilers')
.actions
= f.button :button, t('generic.save_changes'), type: :submit

View File

@ -11,25 +11,25 @@
%p.hint= t 'notifications.email_events_hint'
.fields-group
= f.simple_fields_for :notification_emails, hash_to_object(current_user.settings.notification_emails) do |ff|
= ff.input :follow, as: :boolean, wrapper: :with_label
= ff.input :follow_request, as: :boolean, wrapper: :with_label
= ff.input :reblog, as: :boolean, wrapper: :with_label
= ff.input :favourite, as: :boolean, wrapper: :with_label
= ff.input :mention, as: :boolean, wrapper: :with_label
= ff.input :report, as: :boolean, wrapper: :with_label if current_user.can?(:manage_reports)
= ff.input :appeal, as: :boolean, wrapper: :with_label if current_user.can?(:manage_appeals)
= ff.input :pending_account, as: :boolean, wrapper: :with_label if current_user.can?(:manage_users)
= ff.input :trending_tag, as: :boolean, wrapper: :with_label if current_user.can?(:manage_taxonomies)
= f.simple_fields_for :settings, current_user.settings do |ff|
.fields-group
= ff.input :'notification_emails.follow', wrapper: :with_label, label: I18n.t('simple_form.labels.notification_emails.follow')
= ff.input :'notification_emails.follow_request', wrapper: :with_label, label: I18n.t('simple_form.labels.notification_emails.follow_request')
= ff.input :'notification_emails.reblog', wrapper: :with_label, label: I18n.t('simple_form.labels.notification_emails.reblog')
= ff.input :'notification_emails.favourite', wrapper: :with_label, label: I18n.t('simple_form.labels.notification_emails.favourite')
= ff.input :'notification_emails.mention', wrapper: :with_label, label: I18n.t('simple_form.labels.notification_emails.mention')
= ff.input :'notification_emails.report', wrapper: :with_label, label: I18n.t('simple_form.labels.notification_emails.report') if current_user.can?(:manage_reports)
= ff.input :'notification_emails.appeal', as: :boolean, wrapper: :with_label, label: I18n.t('simple_form.labels.notification_emails.appeal') if current_user.can?(:manage_appeals)
= ff.input :'notification_emails.pending_account', wrapper: :with_label, label: I18n.t('simple_form.labels.notification_emails.pending_account') if current_user.can?(:manage_users)
= ff.input :'notification_emails.trends', wrapper: :with_label, label: I18n.t('simple_form.labels.notification_emails.trending_tag') if current_user.can?(:manage_taxonomies)
.fields-group
= f.input :setting_always_send_emails, as: :boolean, wrapper: :with_label
.fields-group
= ff.input :always_send_emails, wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_always_send_emails'), hint: I18n.t('simple_form.hints.defaults.setting_always_send_emails')
%h4= t 'notifications.other_settings'
.fields-group
= f.simple_fields_for :interactions, hash_to_object(current_user.settings.interactions) do |ff|
= ff.input :must_be_follower, as: :boolean, wrapper: :with_label
= ff.input :must_be_following, as: :boolean, wrapper: :with_label
= ff.input :must_be_following_dm, as: :boolean, wrapper: :with_label
= f.simple_fields_for :settings, current_user.settings do |ff|
= ff.input :'interactions.must_be_follower', wrapper: :with_label, label: I18n.t('simple_form.labels.interactions.must_be_follower')
= ff.input :'interactions.must_be_following', wrapper: :with_label, label: I18n.t('simple_form.labels.interactions.must_be_following')
= ff.input :'interactions.must_be_following_dm', wrapper: :with_label, label: I18n.t('simple_form.labels.interactions.must_be_following_dm')

View File

@ -7,26 +7,27 @@
= simple_form_for current_user, url: settings_preferences_other_path, html: { method: :put, id: 'edit_preferences' } do |f|
= render 'shared/error_messages', object: current_user
.fields-group
= f.input :setting_noindex, as: :boolean, wrapper: :with_label
= f.simple_fields_for :settings, current_user.settings do |ff|
.fields-group
= ff.input :noindex, wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_noindex'), hint: I18n.t('simple_form.hints.defaults.setting_noindex')
.fields-group
= f.input :setting_aggregate_reblogs, as: :boolean, wrapper: :with_label, recommended: true
.fields-group
= ff.input :aggregate_reblogs, wrapper: :with_label, recommended: true, label: I18n.t('simple_form.labels.defaults.setting_aggregate_reblogs'), hint: I18n.t('simple_form.hints.defaults.setting_aggregate_reblogs')
%h4= t 'preferences.posting_defaults'
%h4= t 'preferences.posting_defaults'
.fields-row
.fields-group.fields-row__column.fields-row__column-6
= f.input :setting_default_privacy, collection: Status.selectable_visibilities, wrapper: :with_label, include_blank: false, label_method: lambda { |visibility| safe_join([I18n.t("statuses.visibilities.#{visibility}"), I18n.t("statuses.visibilities.#{visibility}_long")], ' - ') }, required: false, hint: false
.fields-row
.fields-group.fields-row__column.fields-row__column-6
= ff.input :default_privacy, collection: Status.selectable_visibilities, wrapper: :with_label, include_blank: false, label_method: lambda { |visibility| safe_join([I18n.t("statuses.visibilities.#{visibility}"), I18n.t("statuses.visibilities.#{visibility}_long")], ' - ') }, required: false, hint: false, label: I18n.t('simple_form.labels.defaults.setting_default_privacy')
.fields-group.fields-row__column.fields-row__column-6
= f.input :setting_default_language, collection: [nil] + filterable_languages, wrapper: :with_label, label_method: lambda { |locale| locale.nil? ? I18n.t('statuses.default_language') : native_locale_name(locale) }, required: false, include_blank: false, hint: false
.fields-group.fields-row__column.fields-row__column-6
= ff.input :default_language, collection: [nil] + filterable_languages, wrapper: :with_label, label_method: lambda { |locale| locale.nil? ? I18n.t('statuses.default_language') : native_locale_name(locale) }, required: false, include_blank: false, hint: false, label: I18n.t('simple_form.labels.defaults.setting_default_language')
.fields-group
= f.input :setting_default_sensitive, as: :boolean, wrapper: :with_label
.fields-group
= ff.input :default_sensitive, wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_default_sensitive'), hint: I18n.t('simple_form.hints.defaults.setting_default_sensitive')
.fields-group
= f.input :setting_show_application, as: :boolean, wrapper: :with_label, recommended: true
.fields-group
= ff.input :show_application, wrapper: :with_label, recommended: true, label: I18n.t('simple_form.labels.defaults.setting_show_application'), hint: I18n.t('simple_form.hints.defaults.setting_show_application')
%h4= t 'preferences.public_timelines'