diff options
Diffstat (limited to 'app/models')
-rw-r--r-- | app/models/account.rb | 8 | ||||
-rw-r--r-- | app/models/account_stat.rb | 42 | ||||
-rw-r--r-- | app/models/concerns/account_counters.rb | 60 | ||||
-rw-r--r-- | app/models/concerns/account_interactions.rb | 2 | ||||
-rw-r--r-- | app/models/concerns/expireable.rb | 2 | ||||
-rw-r--r-- | app/models/concerns/omniauthable.rb | 1 | ||||
-rw-r--r-- | app/models/direct_feed.rb | 2 | ||||
-rw-r--r-- | app/models/notification.rb | 12 | ||||
-rw-r--r-- | app/models/report.rb | 2 | ||||
-rw-r--r-- | app/models/user.rb | 2 |
10 files changed, 71 insertions, 62 deletions
diff --git a/app/models/account.rb b/app/models/account.rb index b03cbbdf4..2e7d9f543 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -27,7 +27,6 @@ # header_file_size :integer # header_updated_at :datetime # avatar_remote_url :string -# subscription_expires_at :datetime # locked :boolean default(FALSE), not null # header_remote_url :string default(""), not null # last_webfingered_at :datetime @@ -55,6 +54,8 @@ # class Account < ApplicationRecord + self.ignored_columns = %w(subscription_expires_at) + USERNAME_RE = /[a-z0-9_]+([a-z0-9_\.-]+[a-z0-9_]+)?/i MENTION_RE = /(?<=^|[^\/[:word:]])@((#{USERNAME_RE})(?:@[[:word:]\.\-]+[a-z0-9]+)?)/i @@ -97,7 +98,6 @@ class Account < ApplicationRecord scope :remote, -> { where.not(domain: nil) } scope :local, -> { where(domain: nil) } - scope :expiring, ->(time) { remote.where.not(subscription_expires_at: nil).where('subscription_expires_at < ?', time) } scope :partitioned, -> { order(Arel.sql('row_number() over (partition by domain)')) } scope :silenced, -> { where.not(silenced_at: nil) } scope :suspended, -> { where.not(suspended_at: nil) } @@ -194,10 +194,6 @@ class Account < ApplicationRecord "acct:#{local_username_and_domain}" end - def subscribed? - subscription_expires_at.present? - end - def searchable? !(suspended? || moved?) end diff --git a/app/models/account_stat.rb b/app/models/account_stat.rb index e70b54d79..a826a9af3 100644 --- a/app/models/account_stat.rb +++ b/app/models/account_stat.rb @@ -18,46 +18,4 @@ class AccountStat < ApplicationRecord belongs_to :account, inverse_of: :account_stat update_index('accounts#account', :account) - - def increment_count!(key) - update(attributes_for_increment(key)) - rescue ActiveRecord::StaleObjectError, ActiveRecord::RecordNotUnique - begin - reload_with_id - rescue ActiveRecord::RecordNotFound - return - end - - retry - end - - def decrement_count!(key) - update(attributes_for_decrement(key)) - rescue ActiveRecord::StaleObjectError, ActiveRecord::RecordNotUnique - begin - reload_with_id - rescue ActiveRecord::RecordNotFound - return - end - - retry - end - - private - - def attributes_for_increment(key) - attrs = { key => public_send(key) + 1 } - attrs[:last_status_at] = Time.now.utc if key == :statuses_count - attrs - end - - def attributes_for_decrement(key) - attrs = { key => [public_send(key) - 1, 0].max } - attrs - end - - def reload_with_id - self.id = self.class.find_by!(account: account).id if new_record? - reload - end end diff --git a/app/models/concerns/account_counters.rb b/app/models/concerns/account_counters.rb index 6e25e1905..fd3f161ad 100644 --- a/app/models/concerns/account_counters.rb +++ b/app/models/concerns/account_counters.rb @@ -3,6 +3,8 @@ module AccountCounters extend ActiveSupport::Concern + ALLOWED_COUNTER_KEYS = %i(statuses_count following_count followers_count).freeze + included do has_one :account_stat, inverse_of: :account after_save :save_account_stat @@ -14,11 +16,65 @@ module AccountCounters :following_count=, :followers_count, :followers_count=, - :increment_count!, - :decrement_count!, :last_status_at, to: :account_stat + # @param [Symbol] key + def increment_count!(key) + update_count!(key, 1) + end + + # @param [Symbol] key + def decrement_count!(key) + update_count!(key, -1) + end + + # @param [Symbol] key + # @param [Integer] value + def update_count!(key, value) + raise ArgumentError, "Invalid key #{key}" unless ALLOWED_COUNTER_KEYS.include?(key) + raise ArgumentError, 'Do not call update_count! on dirty objects' if association(:account_stat).loaded? && account_stat&.changed? && account_stat.changed_attribute_names_to_save == %w(id) + + value = value.to_i + default_value = value.positive? ? value : 0 + + # We do an upsert using manually written SQL, as Rails' upsert method does + # not seem to support writing expressions in the UPDATE clause, but only + # re-insert the provided values instead. + # Even ARel seem to be missing proper handling of upserts. + sql = if value.positive? && key == :statuses_count + <<-SQL.squish + INSERT INTO account_stats(account_id, #{key}, created_at, updated_at, last_status_at) + VALUES (:account_id, :default_value, now(), now(), now()) + ON CONFLICT (account_id) DO UPDATE + SET #{key} = account_stats.#{key} + :value, + last_status_at = now(), + lock_version = account_stats.lock_version + 1, + updated_at = now() + RETURNING id; + SQL + else + <<-SQL.squish + INSERT INTO account_stats(account_id, #{key}, created_at, updated_at) + VALUES (:account_id, :default_value, now(), now()) + ON CONFLICT (account_id) DO UPDATE + SET #{key} = account_stats.#{key} + :value, + lock_version = account_stats.lock_version + 1, + updated_at = now() + RETURNING id; + SQL + end + + sql = AccountStat.sanitize_sql([sql, account_id: id, default_value: default_value, value: value]) + account_stat_id = AccountStat.connection.exec_query(sql)[0]['id'] + + # Reload account_stat if it was loaded, taking into account newly-created unsaved records + if association(:account_stat).loaded? + account_stat.id = account_stat_id if account_stat.new_record? + account_stat.reload + end + end + def account_stat super || build_account_stat end diff --git a/app/models/concerns/account_interactions.rb b/app/models/concerns/account_interactions.rb index 974f57820..51e8e04a8 100644 --- a/app/models/concerns/account_interactions.rb +++ b/app/models/concerns/account_interactions.rb @@ -67,7 +67,7 @@ module AccountInteractions private def follow_mapping(query, field) - query.pluck(field).each_with_object({}) { |id, mapping| mapping[id] = true } + query.pluck(field).index_with(true) end end diff --git a/app/models/concerns/expireable.rb b/app/models/concerns/expireable.rb index a66a4661b..4d902abcb 100644 --- a/app/models/concerns/expireable.rb +++ b/app/models/concerns/expireable.rb @@ -17,7 +17,7 @@ module Expireable end def expires_in=(interval) - self.expires_at = interval.to_i.seconds.from_now if interval.present? + self.expires_at = interval.present? ? interval.to_i.seconds.from_now : nil @expires_in = interval end diff --git a/app/models/concerns/omniauthable.rb b/app/models/concerns/omniauthable.rb index 79d671d10..791a94911 100644 --- a/app/models/concerns/omniauthable.rb +++ b/app/models/concerns/omniauthable.rb @@ -68,7 +68,6 @@ module Omniauthable def user_params_from_auth(email, auth) { email: email || "#{TEMP_EMAIL_PREFIX}-#{auth.uid}-#{auth.provider}.com", - password: Devise.friendly_token[0, 20], agreement: true, external: true, account_attributes: { diff --git a/app/models/direct_feed.rb b/app/models/direct_feed.rb index c0b8a0a35..1f2448070 100644 --- a/app/models/direct_feed.rb +++ b/app/models/direct_feed.rb @@ -24,7 +24,7 @@ class DirectFeed < Feed statuses = Status.as_direct_timeline(@account, limit, max_id, since_id, min_id) return statuses if statuses.empty? max_id = statuses.last.id - statuses = statuses.reject { |status| FeedManager.instance.filter?(:direct, status, @account.id) } + statuses = statuses.reject { |status| FeedManager.instance.filter?(:direct, status, @account) } return statuses unless statuses.empty? end end diff --git a/app/models/notification.rb b/app/models/notification.rb index 98a6a618f..3bf9dd483 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -49,12 +49,12 @@ class Notification < ApplicationRecord belongs_to :from_account, class_name: 'Account', optional: true belongs_to :activity, polymorphic: true, optional: true - belongs_to :mention, foreign_type: 'Mention', foreign_key: 'activity_id', optional: true - belongs_to :status, foreign_type: 'Status', foreign_key: 'activity_id', optional: true - belongs_to :follow, foreign_type: 'Follow', foreign_key: 'activity_id', optional: true - belongs_to :follow_request, foreign_type: 'FollowRequest', foreign_key: 'activity_id', optional: true - belongs_to :favourite, foreign_type: 'Favourite', foreign_key: 'activity_id', optional: true - belongs_to :poll, foreign_type: 'Poll', foreign_key: 'activity_id', optional: true + belongs_to :mention, foreign_key: 'activity_id', optional: true + belongs_to :status, foreign_key: 'activity_id', optional: true + belongs_to :follow, foreign_key: 'activity_id', optional: true + belongs_to :follow_request, foreign_key: 'activity_id', optional: true + belongs_to :favourite, foreign_key: 'activity_id', optional: true + belongs_to :poll, foreign_key: 'activity_id', optional: true validates :type, inclusion: { in: TYPES } diff --git a/app/models/report.rb b/app/models/report.rb index cd08120e4..ef41547d9 100644 --- a/app/models/report.rb +++ b/app/models/report.rb @@ -32,7 +32,7 @@ class Report < ApplicationRecord scope :unresolved, -> { where(action_taken: false) } scope :resolved, -> { where(action_taken: true) } - scope :with_accounts, -> { includes([:account, :target_account, :action_taken_by_account, :assigned_account].each_with_object({}) { |k, h| h[k] = { user: [:invite_request, :invite] } }) } + scope :with_accounts, -> { includes([:account, :target_account, :action_taken_by_account, :assigned_account].index_with({ user: [:invite_request, :invite] })) } validates :comment, length: { maximum: 1000 } diff --git a/app/models/user.rb b/app/models/user.rb index 023dc3609..eb5b95c2b 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -468,7 +468,7 @@ class User < ApplicationRecord end def validate_email_dns? - email_changed? && !(Rails.env.test? || Rails.env.development?) + email_changed? && !external? && !(Rails.env.test? || Rails.env.development?) end def invite_text_required? |