Merge branch 'main' into glitch-soc/merge-upstream
Conflicts: - `README.md`: Upstream added a link to the roadmap, but we have a completely different README. Kept ours. - `app/models/media_attachment.rb`: Upstream upped media attachment limits. Updated the default according to upstream's. - `db/migrate/20180831171112_create_bookmarks.rb`: Upstream changed the migration compatibility level. Did so too. - `config/initializers/content_security_policy.rb`: Upstream refactored this file but we have a different version. Kept our version. - `app/controllers/settings/preferences_controller.rb`: Upstream completely refactored user settings storage, and glitch-soc has a different set of settings. The file does not directly references individual settings anymore. Applied upstream changes. - `app/lib/user_settings_decorator.rb`: Upstream completely refactored user settings storage, and glitch-soc has a different set of settings. The file got removed entirely. Removed it as well. - `app/models/user.rb`: Upstream completely refactored user settings storage, and glitch-soc has a different set of settings. References to individual settings have been removed from the file. Removed them as well. - `app/views/settings/preferences/appearance/show.html.haml`: Upstream completely refactored user settings storage, and glitch-soc has a different set of settings. Applied upstream's changes and ported ours back. - `app/views/settings/preferences/notifications/show.html.haml`: Upstream completely refactored user settings storage, and glitch-soc has a different set of settings. Applied upstream's changes and ported ours back. - `app/views/settings/preferences/other/show.html.haml`: Upstream completely refactored user settings storage, and glitch-soc has a different set of settings. Applied upstream's changes and ported ours back. - `config/settings.yml`: Upstream completely refactored user settings storage, and glitch-soc has a different set of settings. In particular, upstream removed user-specific and unused settings. Did the same in glitch-soc. - `spec/controllers/application_controller_spec.rb`: Conflicts due to glitch-soc's theming system. Mostly kept our version, as upstream messed up the tests.
This commit is contained in:
@@ -53,7 +53,7 @@
|
||||
#
|
||||
|
||||
class Account < ApplicationRecord
|
||||
self.ignored_columns = %w(
|
||||
self.ignored_columns += %w(
|
||||
subscription_expires_at
|
||||
secret
|
||||
remote_url
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
class AccountStat < ApplicationRecord
|
||||
self.locking_column = nil
|
||||
self.ignored_columns = %w(lock_version)
|
||||
self.ignored_columns += %w(lock_version)
|
||||
|
||||
belongs_to :account, inverse_of: :account_stat
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#
|
||||
|
||||
class Admin::ActionLog < ApplicationRecord
|
||||
self.ignored_columns = %w(
|
||||
self.ignored_columns += %w(
|
||||
recorded_changes
|
||||
)
|
||||
|
||||
|
||||
@@ -18,6 +18,6 @@
|
||||
class Backup < ApplicationRecord
|
||||
belongs_to :user, inverse_of: :backups
|
||||
|
||||
has_attached_file :dump, s3_permissions: 'private'
|
||||
has_attached_file :dump, s3_permissions: ->(*) { ENV['S3_PERMISSION'] == '' ? nil : 'private' }
|
||||
validates_attachment_content_type :dump, content_type: /\Aapplication/
|
||||
end
|
||||
|
||||
@@ -5,7 +5,7 @@ require 'mime/types/columnar'
|
||||
module Attachmentable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
MAX_MATRIX_LIMIT = 16_777_216 # 4096x4096px or approx. 16MB
|
||||
MAX_MATRIX_LIMIT = 33_177_600 # 7680x4320px or approx. 847MB in RAM
|
||||
GIF_MATRIX_LIMIT = 921_600 # 1280x720px
|
||||
|
||||
# For some file extensions, there exist different content
|
||||
|
||||
141
app/models/concerns/has_user_settings.rb
Normal file
141
app/models/concerns/has_user_settings.rb
Normal 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
|
||||
@@ -15,7 +15,7 @@
|
||||
#
|
||||
|
||||
class CustomFilter < ApplicationRecord
|
||||
self.ignored_columns = %w(whole_word irreversible)
|
||||
self.ignored_columns += %w(whole_word irreversible)
|
||||
|
||||
alias_attribute :title, :phrase
|
||||
alias_attribute :filter_action, :action
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#
|
||||
|
||||
class EmailDomainBlock < ApplicationRecord
|
||||
self.ignored_columns = %w(
|
||||
self.ignored_columns += %w(
|
||||
ips
|
||||
last_refresh_at
|
||||
)
|
||||
|
||||
@@ -39,11 +39,11 @@ class MediaAttachment < ApplicationRecord
|
||||
|
||||
MAX_DESCRIPTION_LENGTH = 1_500
|
||||
|
||||
IMAGE_LIMIT = (ENV['MAX_IMAGE_SIZE'] || 10.megabytes).to_i
|
||||
VIDEO_LIMIT = (ENV['MAX_VIDEO_SIZE'] || 40.megabytes).to_i
|
||||
IMAGE_LIMIT = (ENV['MAX_IMAGE_SIZE'] || 16.megabytes).to_i
|
||||
VIDEO_LIMIT = (ENV['MAX_VIDEO_SIZE'] || 99.megabytes).to_i
|
||||
|
||||
MAX_VIDEO_MATRIX_LIMIT = 2_304_000 # 1920x1200px
|
||||
MAX_VIDEO_FRAME_RATE = 60
|
||||
MAX_VIDEO_MATRIX_LIMIT = 8_294_400 # 3840x2160px
|
||||
MAX_VIDEO_FRAME_RATE = 120
|
||||
|
||||
IMAGE_FILE_EXTENSIONS = %w(.jpg .jpeg .png .gif .webp .heic .heif .avif).freeze
|
||||
VIDEO_FILE_EXTENSIONS = %w(.webm .mp4 .m4v .mov).freeze
|
||||
@@ -69,7 +69,7 @@ class MediaAttachment < ApplicationRecord
|
||||
|
||||
IMAGE_STYLES = {
|
||||
original: {
|
||||
pixels: 2_073_600, # 1920x1080px
|
||||
pixels: 8_294_400, # 3840x2160px
|
||||
file_geometry_parser: FastGeometryParser,
|
||||
}.freeze,
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ class PreviewCard < ApplicationRecord
|
||||
include Attachmentable
|
||||
|
||||
IMAGE_MIME_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'].freeze
|
||||
LIMIT = 1.megabytes
|
||||
LIMIT = 2.megabytes
|
||||
|
||||
BLURHASH_OPTIONS = {
|
||||
x_comp: 4,
|
||||
@@ -121,7 +121,7 @@ class PreviewCard < ApplicationRecord
|
||||
def image_styles(file)
|
||||
styles = {
|
||||
original: {
|
||||
geometry: '400x400>',
|
||||
pixels: 230_400, # 640x360px
|
||||
file_geometry_parser: FastGeometryParser,
|
||||
convert_options: '-coalesce',
|
||||
blurhash: BLURHASH_OPTIONS,
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#
|
||||
|
||||
class Report < ApplicationRecord
|
||||
self.ignored_columns = %w(action_taken)
|
||||
self.ignored_columns += %w(action_taken)
|
||||
|
||||
include Paginable
|
||||
include RateLimitable
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
class StatusEdit < ApplicationRecord
|
||||
include RateLimitable
|
||||
|
||||
self.ignored_columns = %w(
|
||||
self.ignored_columns += %w(
|
||||
media_attachments_changed
|
||||
)
|
||||
|
||||
|
||||
@@ -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, :favourite_modal, :delete_modal,
|
||||
:reduce_motion, :system_font_ui, :noindex, :flavour, :skin, :display_media, :hide_followers_count,
|
||||
:expand_spoilers, :default_language, :aggregate_reblogs, :show_application,
|
||||
:advanced_layout, :use_blurhash, :use_pending_items, :trends, :crop_images,
|
||||
:disable_swiping, :always_send_emails, :default_content_type, :system_emoji_font,
|
||||
to: :settings, prefix: :setting, allow_nil: false
|
||||
|
||||
delegate :can?, to: :role
|
||||
|
||||
attr_reader :invite_code
|
||||
@@ -303,50 +297,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_trending_tags_review_emails?
|
||||
settings.notification_emails['trending_tag']
|
||||
end
|
||||
|
||||
def allows_trending_links_review_emails?
|
||||
settings.notification_emails['trending_link']
|
||||
end
|
||||
|
||||
def allows_trending_statuses_review_emails?
|
||||
settings.notification_emails['trending_status']
|
||||
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
|
||||
|
||||
@@ -426,14 +376,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)
|
||||
@@ -503,7 +445,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
|
||||
|
||||
|
||||
99
app/models/user_settings.rb
Normal file
99
app/models/user_settings.rb
Normal 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
|
||||
37
app/models/user_settings/dsl.rb
Normal file
37
app/models/user_settings/dsl.rb
Normal 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
|
||||
23
app/models/user_settings/glue.rb
Normal file
23
app/models/user_settings/glue.rb
Normal 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
|
||||
21
app/models/user_settings/namespace.rb
Normal file
21
app/models/user_settings/namespace.rb
Normal 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
|
||||
49
app/models/user_settings/setting.rb
Normal file
49
app/models/user_settings/setting.rb
Normal file
@@ -0,0 +1,49 @@
|
||||
# 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
|
||||
case default_value
|
||||
when TrueClass, 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
|
||||
Reference in New Issue
Block a user