diff options
Diffstat (limited to 'app/models')
31 files changed, 214 insertions, 82 deletions
diff --git a/app/models/account.rb b/app/models/account.rb index 85684c259..a4b8e1c0b 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -41,10 +41,11 @@ # shared_inbox_url :string default(""), not null # followers_url :string default(""), not null # protocol :integer default("ostatus"), not null +# memorial :boolean default(FALSE), not null # class Account < ApplicationRecord - MENTION_RE = /(?:^|[^\/[:word:]])@(([a-z0-9_]+)(?:@[a-z0-9\.\-]+[a-z0-9]+)?)/i + MENTION_RE = /(?<=^|[^\/[:word:]])@(([a-z0-9_]+)(?:@[a-z0-9\.\-]+[a-z0-9]+)?)/i include AccountAvatar include AccountFinderConcern @@ -52,6 +53,7 @@ class Account < ApplicationRecord include AccountInteractions include Attachmentable include Remotable + include Paginable MAX_NOTE_LENGTH = 500 @@ -96,6 +98,10 @@ class Account < ApplicationRecord has_many :account_moderation_notes, dependent: :destroy has_many :targeted_moderation_notes, class_name: 'AccountModerationNote', foreign_key: :target_account_id, dependent: :destroy + # Lists + has_many :list_accounts, inverse_of: :account, dependent: :destroy + has_many :lists, through: :list_accounts + scope :remote, -> { where.not(domain: nil) } scope :local, -> { where(domain: nil) } scope :without_followers, -> { where(followers_count: 0) } @@ -116,6 +122,8 @@ class Account < ApplicationRecord :current_sign_in_at, :confirmed?, :admin?, + :moderator?, + :staff?, :locale, to: :user, prefix: true, @@ -152,6 +160,20 @@ class Account < ApplicationRecord ResolveRemoteAccountService.new.call(acct) end + def unsuspend! + transaction do + user&.enable! if local? + update!(suspended: false) + end + end + + def memorialize! + transaction do + user&.disable! if local? + update!(memorial: true) + end + end + def keypair @keypair ||= OpenSSL::PKey::RSA.new(private_key || public_key) end diff --git a/app/models/account_domain_block.rb b/app/models/account_domain_block.rb index fb695e473..35810b6c2 100644 --- a/app/models/account_domain_block.rb +++ b/app/models/account_domain_block.rb @@ -3,11 +3,11 @@ # # Table name: account_domain_blocks # +# id :integer not null, primary key # domain :string # created_at :datetime not null # updated_at :datetime not null # account_id :integer -# id :integer not null, primary key # class AccountDomainBlock < ApplicationRecord diff --git a/app/models/block.rb b/app/models/block.rb index a913782ed..284abfe4c 100644 --- a/app/models/block.rb +++ b/app/models/block.rb @@ -3,10 +3,10 @@ # # Table name: blocks # +# id :integer not null, primary key # created_at :datetime not null # updated_at :datetime not null # account_id :integer not null -# id :integer not null, primary key # target_account_id :integer not null # diff --git a/app/models/concerns/account_finder_concern.rb b/app/models/concerns/account_finder_concern.rb index 561c7ab9f..2e8a7fb37 100644 --- a/app/models/concerns/account_finder_concern.rb +++ b/app/models/concerns/account_finder_concern.rb @@ -44,7 +44,7 @@ module AccountFinderConcern end def with_usernames - Account.where.not(username: [nil, '']) + Account.where.not(username: '') end def matching_username diff --git a/app/models/concerns/account_interactions.rb b/app/models/concerns/account_interactions.rb index a68f7c3d8..c41f92581 100644 --- a/app/models/concerns/account_interactions.rb +++ b/app/models/concerns/account_interactions.rb @@ -23,7 +23,7 @@ module AccountInteractions def muting_map(target_account_ids, account_id) Mute.where(target_account_id: target_account_ids, account_id: account_id).each_with_object({}) do |mute, mapping| mapping[mute.target_account_id] = { - notifications: mute.hide_notifications? + notifications: mute.hide_notifications?, } end end @@ -91,8 +91,7 @@ module AccountInteractions mute = mute_relationships.create_with(hide_notifications: notifications).find_or_create_by!(target_account: other_account) # When toggling a mute between hiding and allowing notifications, the mute will already exist, so the find_or_create_by! call will return the existing Mute without updating the hide_notifications attribute. Therefore, we check that hide_notifications? is what we want and set it if it isn't. if mute.hide_notifications? != notifications - mute.hide_notifications = notifications - mute.save! + mute.update!(hide_notifications: notifications) end end diff --git a/app/models/conversation_mute.rb b/app/models/conversation_mute.rb index 8d2399adf..248cdfe6e 100644 --- a/app/models/conversation_mute.rb +++ b/app/models/conversation_mute.rb @@ -3,9 +3,9 @@ # # Table name: conversation_mutes # +# id :integer not null, primary key # conversation_id :integer not null # account_id :integer not null -# id :integer not null, primary key # class ConversationMute < ApplicationRecord diff --git a/app/models/custom_emoji.rb b/app/models/custom_emoji.rb index 28b6a2b0b..a77b53c98 100644 --- a/app/models/custom_emoji.rb +++ b/app/models/custom_emoji.rb @@ -25,6 +25,8 @@ class CustomEmoji < ApplicationRecord :(#{SHORTCODE_RE_FRAGMENT}): (?=[^[:alnum:]:]|$)/x + has_one :local_counterpart, -> { where(domain: nil) }, class_name: 'CustomEmoji', primary_key: :shortcode, foreign_key: :shortcode + has_attached_file :image, styles: { static: { format: 'png', convert_options: '-coalesce -strip' } } validates_attachment :image, content_type: { content_type: 'image/png' }, presence: true, size: { in: 0..50.kilobytes } diff --git a/app/models/domain_block.rb b/app/models/domain_block.rb index 1268290bc..aea8919af 100644 --- a/app/models/domain_block.rb +++ b/app/models/domain_block.rb @@ -3,12 +3,12 @@ # # Table name: domain_blocks # +# id :integer not null, primary key # domain :string default(""), not null # created_at :datetime not null # updated_at :datetime not null # severity :integer default("silence") # reject_media :boolean default(FALSE), not null -# id :integer not null, primary key # class DomainBlock < ApplicationRecord diff --git a/app/models/email_domain_block.rb b/app/models/email_domain_block.rb index 839038bea..a104810d1 100644 --- a/app/models/email_domain_block.rb +++ b/app/models/email_domain_block.rb @@ -4,14 +4,33 @@ # Table name: email_domain_blocks # # id :integer not null, primary key -# domain :string not null +# domain :string default(""), not null # created_at :datetime not null # updated_at :datetime not null # class EmailDomainBlock < ApplicationRecord + before_validation :normalize_domain + + validates :domain, presence: true, uniqueness: true + def self.block?(email) - domain = email.gsub(/.+@([^.]+)/, '\1') + _, domain = email.split('@', 2) + + return true if domain.nil? + + begin + domain = TagManager.instance.normalize_domain(domain) + rescue Addressable::URI::InvalidURIError + return true + end + where(domain: domain).exists? end + + private + + def normalize_domain + self.domain = TagManager.instance.normalize_domain(domain) + end end diff --git a/app/models/favourite.rb b/app/models/favourite.rb index d28d5c05b..c38838f2a 100644 --- a/app/models/favourite.rb +++ b/app/models/favourite.rb @@ -3,10 +3,10 @@ # # Table name: favourites # +# id :integer not null, primary key # created_at :datetime not null # updated_at :datetime not null # account_id :integer not null -# id :integer not null, primary key # status_id :integer not null # diff --git a/app/models/feed.rb b/app/models/feed.rb index 5f7b7877a..d99f1ffb2 100644 --- a/app/models/feed.rb +++ b/app/models/feed.rb @@ -1,36 +1,27 @@ # frozen_string_literal: true class Feed - def initialize(type, account) - @type = type - @account = account + def initialize(type, id) + @type = type + @id = id end def get(limit, max_id = nil, since_id = nil) - if redis.exists("account:#{@account.id}:regeneration") - from_database(limit, max_id, since_id) - else - from_redis(limit, max_id, since_id) - end + from_redis(limit, max_id, since_id) end - private + protected def from_redis(limit, max_id, since_id) max_id = '+inf' if max_id.blank? since_id = '-inf' if since_id.blank? unhydrated = redis.zrevrangebyscore(key, "(#{max_id}", "(#{since_id}", limit: [0, limit], with_scores: true).map(&:first).map(&:to_i) - Status.where(id: unhydrated).cache_ids - end - def from_database(limit, max_id, since_id) - Status.as_home_timeline(@account) - .paginate_by_max_id(limit, max_id, since_id) - .reject { |status| FeedManager.instance.filter?(:home, status, @account.id) } + Status.where(id: unhydrated).cache_ids end def key - FeedManager.instance.key(@type, @account.id) + FeedManager.instance.key(@type, @id) end def redis diff --git a/app/models/follow.rb b/app/models/follow.rb index a8ddcb7f0..3fb665afc 100644 --- a/app/models/follow.rb +++ b/app/models/follow.rb @@ -3,10 +3,10 @@ # # Table name: follows # +# id :integer not null, primary key # created_at :datetime not null # updated_at :datetime not null # account_id :integer not null -# id :integer not null, primary key # target_account_id :integer not null # show_reblogs :boolean default(TRUE), not null # diff --git a/app/models/follow_request.rb b/app/models/follow_request.rb index 1a1c52382..ebf6959ce 100644 --- a/app/models/follow_request.rb +++ b/app/models/follow_request.rb @@ -3,10 +3,10 @@ # # Table name: follow_requests # +# id :integer not null, primary key # created_at :datetime not null # updated_at :datetime not null # account_id :integer not null -# id :integer not null, primary key # target_account_id :integer not null # show_reblogs :boolean default(TRUE), not null # @@ -28,7 +28,5 @@ class FollowRequest < ApplicationRecord destroy! end - def reject! - destroy! - end + alias reject! destroy! end diff --git a/app/models/home_feed.rb b/app/models/home_feed.rb new file mode 100644 index 000000000..b943a34ce --- /dev/null +++ b/app/models/home_feed.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +class HomeFeed < Feed + def initialize(account) + @type = :home + @id = account.id + @account = account + end + + def get(limit, max_id = nil, since_id = nil) + if redis.exists("account:#{@account.id}:regeneration") + from_database(limit, max_id, since_id) + else + super + end + end + + private + + def from_database(limit, max_id, since_id) + Status.as_home_timeline(@account) + .paginate_by_max_id(limit, max_id, since_id) + .reject { |status| FeedManager.instance.filter?(:home, status, @account.id) } + end +end diff --git a/app/models/import.rb b/app/models/import.rb index 8ae7e3a46..091fb3044 100644 --- a/app/models/import.rb +++ b/app/models/import.rb @@ -3,6 +3,7 @@ # # Table name: imports # +# id :integer not null, primary key # type :integer not null # approved :boolean default(FALSE), not null # created_at :datetime not null @@ -12,7 +13,6 @@ # data_file_size :integer # data_updated_at :datetime # account_id :integer not null -# id :integer not null, primary key # class Import < ApplicationRecord diff --git a/app/models/list.rb b/app/models/list.rb new file mode 100644 index 000000000..5d7ba0065 --- /dev/null +++ b/app/models/list.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# == Schema Information +# +# Table name: lists +# +# id :integer not null, primary key +# account_id :integer +# title :string default(""), not null +# created_at :datetime not null +# updated_at :datetime not null +# + +class List < ApplicationRecord + include Paginable + + belongs_to :account + + has_many :list_accounts, inverse_of: :list, dependent: :destroy + has_many :accounts, through: :list_accounts + + validates :title, presence: true +end diff --git a/app/models/list_account.rb b/app/models/list_account.rb new file mode 100644 index 000000000..c08239aa0 --- /dev/null +++ b/app/models/list_account.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# == Schema Information +# +# Table name: list_accounts +# +# id :integer not null, primary key +# list_id :integer not null +# account_id :integer not null +# follow_id :integer not null +# + +class ListAccount < ApplicationRecord + belongs_to :list, required: true + belongs_to :account, required: true + belongs_to :follow, required: true + + before_validation :set_follow + + private + + def set_follow + self.follow = Follow.find_by(account_id: list.account_id, target_account_id: account.id) + end +end diff --git a/app/models/list_feed.rb b/app/models/list_feed.rb new file mode 100644 index 000000000..f371e4ed9 --- /dev/null +++ b/app/models/list_feed.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +class ListFeed < Feed + def initialize(list) + @type = :list + @id = list.id + end +end diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb index f6c8879c5..368ccef3a 100644 --- a/app/models/media_attachment.rb +++ b/app/models/media_attachment.rb @@ -10,12 +10,12 @@ # file_file_size :integer # file_updated_at :datetime # remote_url :string default(""), not null -# account_id :integer # created_at :datetime not null # updated_at :datetime not null # shortcode :string # type :integer default("image"), not null # file_meta :json +# account_id :integer # description :text # diff --git a/app/models/mention.rb b/app/models/mention.rb index 3700c781c..14533e6a9 100644 --- a/app/models/mention.rb +++ b/app/models/mention.rb @@ -3,11 +3,11 @@ # # Table name: mentions # +# id :integer not null, primary key # status_id :integer # created_at :datetime not null # updated_at :datetime not null # account_id :integer -# id :integer not null, primary key # class Mention < ApplicationRecord diff --git a/app/models/mute.rb b/app/models/mute.rb index bcd3d247c..ca984641a 100644 --- a/app/models/mute.rb +++ b/app/models/mute.rb @@ -3,12 +3,12 @@ # # Table name: mutes # +# id :integer not null, primary key # created_at :datetime not null # updated_at :datetime not null +# hide_notifications :boolean default(TRUE), not null # account_id :integer not null -# id :integer not null, primary key # target_account_id :integer not null -# hide_notifications :boolean default(TRUE), not null # class Mute < ApplicationRecord diff --git a/app/models/notification.rb b/app/models/notification.rb index 0a5d987cf..a3ffb1f45 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -4,11 +4,11 @@ # Table name: notifications # # id :integer not null, primary key -# account_id :integer # activity_id :integer # activity_type :string # created_at :datetime not null # updated_at :datetime not null +# account_id :integer # from_account_id :integer # diff --git a/app/models/report.rb b/app/models/report.rb index bffb42b48..c36f8db0a 100644 --- a/app/models/report.rb +++ b/app/models/report.rb @@ -3,6 +3,7 @@ # # Table name: reports # +# id :integer not null, primary key # status_ids :integer default([]), not null, is an Array # comment :text default(""), not null # action_taken :boolean default(FALSE), not null @@ -10,7 +11,6 @@ # updated_at :datetime not null # account_id :integer not null # action_taken_by_account_id :integer -# id :integer not null, primary key # target_account_id :integer not null # diff --git a/app/models/session_activation.rb b/app/models/session_activation.rb index c1645223b..d19489b36 100644 --- a/app/models/session_activation.rb +++ b/app/models/session_activation.rb @@ -4,24 +4,24 @@ # Table name: session_activations # # id :integer not null, primary key -# user_id :integer not null # session_id :string not null # created_at :datetime not null # updated_at :datetime not null # user_agent :string default(""), not null # ip :inet # access_token_id :integer +# user_id :integer not null # web_push_subscription_id :integer # -# id :integer not null, primary key -# user_id :integer not null +# id :bigint not null, primary key +# user_id :bigint not null # session_id :string not null # created_at :datetime not null # updated_at :datetime not null # user_agent :string default(""), not null # ip :inet -# access_token_id :integer +# access_token_id :bigint # class SessionActivation < ApplicationRecord diff --git a/app/models/setting.rb b/app/models/setting.rb index a14f156a1..df93590ce 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -3,12 +3,12 @@ # # Table name: settings # +# id :integer not null, primary key # var :string not null # value :text # thing_type :string # created_at :datetime # updated_at :datetime -# id :integer not null, primary key # thing_id :integer # diff --git a/app/models/status.rb b/app/models/status.rb index d78a921b5..172d3a665 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -5,7 +5,6 @@ # # id :integer not null, primary key # uri :string -# account_id :integer not null # text :text default(""), not null # created_at :datetime not null # updated_at :datetime not null @@ -14,8 +13,6 @@ # url :string # sensitive :boolean default(FALSE), not null # visibility :integer default("public"), not null -# in_reply_to_account_id :integer -# application_id :integer # spoiler_text :text default(""), not null # reply :boolean default(FALSE), not null # favourites_count :integer default(0), not null @@ -23,6 +20,9 @@ # language :string # conversation_id :integer # local :boolean +# account_id :integer not null +# application_id :integer +# in_reply_to_account_id :integer # class Status < ApplicationRecord diff --git a/app/models/stream_entry.rb b/app/models/stream_entry.rb index 720cd518c..36fe487dc 100644 --- a/app/models/stream_entry.rb +++ b/app/models/stream_entry.rb @@ -3,13 +3,13 @@ # # Table name: stream_entries # +# id :integer not null, primary key # activity_id :integer # activity_type :string # created_at :datetime not null # updated_at :datetime not null # hidden :boolean default(FALSE), not null # account_id :integer -# id :integer not null, primary key # class StreamEntry < ApplicationRecord diff --git a/app/models/subscription.rb b/app/models/subscription.rb index 39860196b..7f2eeab91 100644 --- a/app/models/subscription.rb +++ b/app/models/subscription.rb @@ -3,6 +3,7 @@ # # Table name: subscriptions # +# id :integer not null, primary key # callback_url :string default(""), not null # secret :string # expires_at :datetime @@ -12,7 +13,6 @@ # last_successful_delivery_at :datetime # domain :string # account_id :integer not null -# id :integer not null, primary key # class Subscription < ApplicationRecord diff --git a/app/models/user.rb b/app/models/user.rb index 325e27f44..b9b228c00 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -5,7 +5,6 @@ # # id :integer not null, primary key # email :string default(""), not null -# account_id :integer not null # created_at :datetime not null # updated_at :datetime not null # encrypted_password :string default(""), not null @@ -31,10 +30,14 @@ # last_emailed_at :datetime # otp_backup_codes :string is an Array # filtered_languages :string default([]), not null, is an Array +# account_id :integer not null +# disabled :boolean default(FALSE), not null +# moderator :boolean default(FALSE), not null # class User < ApplicationRecord include Settings::Extend + ACTIVE_DURATION = 14.days devise :registerable, :recoverable, @@ -51,8 +54,10 @@ class User < ApplicationRecord validates :locale, inclusion: I18n.available_locales.map(&:to_s), if: :locale? validates_with BlacklistedEmailValidator, if: :email_changed? - scope :recent, -> { order(id: :desc) } - scope :admins, -> { where(admin: true) } + scope :recent, -> { order(id: :desc) } + scope :admins, -> { where(admin: true) } + scope :moderators, -> { where(moderator: true) } + scope :staff, -> { admins.or(moderators) } scope :confirmed, -> { where.not(confirmed_at: nil) } scope :inactive, -> { where(arel_table[:current_sign_in_at].lt(ACTIVE_DURATION.ago)) } scope :active, -> { confirmed.where(arel_table[:current_sign_in_at].gteq(ACTIVE_DURATION.ago)).joins(:account).where(accounts: { suspended: false }) } @@ -68,54 +73,71 @@ 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, + to: :settings, prefix: :setting, allow_nil: false + def confirmed? confirmed_at.present? end - def disable_two_factor! - self.otp_required_for_login = false - otp_backup_codes&.clear - save! - end - - def setting_default_privacy - settings.default_privacy || (account.locked? ? 'private' : 'public') + def staff? + admin? || moderator? end - def setting_default_sensitive - settings.default_sensitive + def role + if admin? + 'admin' + elsif moderator? + 'moderator' + else + 'user' + end end - def setting_unfollow_modal - settings.unfollow_modal + def disable! + update!(disabled: true, + last_sign_in_at: current_sign_in_at, + current_sign_in_at: nil) end - def setting_boost_modal - settings.boost_modal + def enable! + update!(disabled: false) end - def setting_delete_modal - settings.delete_modal + def confirm! + skip_confirmation! + save! end - def setting_auto_play_gif - settings.auto_play_gif + def promote! + if moderator? + update!(moderator: false, admin: true) + elsif !admin? + update!(moderator: true) + end end - def setting_reduce_motion - settings.reduce_motion + def demote! + if admin? + update!(admin: false, moderator: true) + elsif moderator? + update!(moderator: false) + end end - def setting_system_font_ui - settings.system_font_ui + def disable_two_factor! + self.otp_required_for_login = false + otp_backup_codes&.clear + save! end - def setting_noindex - settings.noindex + def active_for_authentication? + super && !disabled? end - def setting_theme - settings.theme + def setting_default_privacy + settings.default_privacy || (account.locked? ? 'private' : 'public') end def token_for_app(a) diff --git a/app/models/web/push_subscription.rb b/app/models/web/push_subscription.rb index cb15dfa37..5aee92d27 100644 --- a/app/models/web/push_subscription.rb +++ b/app/models/web/push_subscription.rb @@ -24,12 +24,12 @@ class Web::PushSubscription < ApplicationRecord end def pushable?(notification) - data && data.key?('alerts') && data['alerts'][notification.type.to_s] + data&.key?('alerts') && data['alerts'][notification.type.to_s] end def as_payload payload = { id: id, endpoint: endpoint } - payload[:alerts] = data['alerts'] if data && data.key?('alerts') + payload[:alerts] = data['alerts'] if data&.key?('alerts') payload end diff --git a/app/models/web/setting.rb b/app/models/web/setting.rb index 1b0bfb2b7..12b9d1226 100644 --- a/app/models/web/setting.rb +++ b/app/models/web/setting.rb @@ -3,10 +3,10 @@ # # Table name: web_settings # +# id :integer not null, primary key # data :json # created_at :datetime not null # updated_at :datetime not null -# id :integer not null, primary key # user_id :integer # |