diff options
author | Thibaut Girka <thib@sitedethib.com> | 2020-09-28 14:13:30 +0200 |
---|---|---|
committer | Thibaut Girka <thib@sitedethib.com> | 2020-09-28 14:13:30 +0200 |
commit | a7aedebc310ad7d387c508f7b0198a567a408fe6 (patch) | |
tree | 53fe5fd79302e796ced8000904e46edd84dc1319 /app/models | |
parent | 787d5d728923393f12421a480b3c7aee789a11fe (diff) | |
parent | d88a79b4566869ede24958fbff946e357bbb3cb9 (diff) |
Merge branch 'master' into glitch-soc/merge-upstream
Conflicts: - `Gemfile.lock`: Not a real conflict, upstream updated dependencies that were too close to glitch-soc-only ones in the file. - `app/controllers/oauth/authorized_applications_controller.rb`: Upstream changed the logic surrounding suspended accounts. Minor conflict due to glitch-soc's theming system. Ported upstream changes. - `app/controllers/settings/base_controller.rb`: Upstream refactored and changed the logic surrounding suspended accounts. Minor conflict due to glitch-soc's theming system. Ported upstream changes. - `app/controllers/settings/sessions_controller.rb`: Upstream refactored and changed the logic surrounding suspended accounts. Minor conflict due to glitch-soc's theming system. Ported upstream changes. - `app/models/user.rb`: Upstream refactored and changed the logic surrounding suspended accounts. Minor conflict due to glitch-soc not preventing moved accounts from logging in. Ported upstream changes while keeping the ability for moved accounts to log in. - `app/policies/status_policy.rb`: Upstream refactored and changed the logic surrounding suspended accounts. Minor conflict due to glitch-soc's local-only toots. Ported upstream changes. - `app/serializers/rest/account_serializer.rb`: Upstream refactored and changed the logic surrounding suspended accounts. Minor conflict due to glitch-soc's ability to hide followers count. Ported upstream changes. - `app/services/process_mentions_service.rb`: Upstream refactored and changed the logic surrounding suspended accounts. Minor conflict due to glitch-soc's local-only toots. Ported upstream changes. - `package.json`: Not a real conflict, upstream updated dependencies that were too close to glitch-soc-only ones in the file.
Diffstat (limited to 'app/models')
-rw-r--r-- | app/models/account.rb | 9 | ||||
-rw-r--r-- | app/models/account_conversation.rb | 5 | ||||
-rw-r--r-- | app/models/account_deletion_request.rb | 20 | ||||
-rw-r--r-- | app/models/admin/account_action.rb | 4 | ||||
-rw-r--r-- | app/models/concerns/account_associations.rb | 3 | ||||
-rw-r--r-- | app/models/concerns/account_interactions.rb | 26 | ||||
-rw-r--r-- | app/models/concerns/paginable.rb | 5 | ||||
-rw-r--r-- | app/models/feed.rb | 4 | ||||
-rw-r--r-- | app/models/follow.rb | 3 | ||||
-rw-r--r-- | app/models/follow_request.rb | 3 | ||||
-rw-r--r-- | app/models/form/account_batch.rb | 2 | ||||
-rw-r--r-- | app/models/invite.rb | 2 | ||||
-rw-r--r-- | app/models/notification.rb | 47 | ||||
-rw-r--r-- | app/models/status.rb | 10 | ||||
-rw-r--r-- | app/models/tag_feed.rb | 2 | ||||
-rw-r--r-- | app/models/user.rb | 4 | ||||
-rw-r--r-- | app/models/webauthn_credential.rb | 2 |
17 files changed, 97 insertions, 54 deletions
diff --git a/app/models/account.rb b/app/models/account.rb index 0b3c48543..3a6b38181 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -226,23 +226,20 @@ class Account < ApplicationRecord def suspend!(date = Time.now.utc) transaction do - user&.disable! if local? + create_deletion_request! update!(suspended_at: date) end end def unsuspend! transaction do - user&.enable! if local? + deletion_request&.destroy! update!(suspended_at: nil) end end def memorialize! - transaction do - user&.disable! if local? - update!(memorial: true) - end + update!(memorial: true) end def sign? diff --git a/app/models/account_conversation.rb b/app/models/account_conversation.rb index 5e2ddd083..56fd13543 100644 --- a/app/models/account_conversation.rb +++ b/app/models/account_conversation.rb @@ -38,15 +38,16 @@ class AccountConversation < ApplicationRecord class << self def to_a_paginated_by_id(limit, options = {}) if options[:min_id] - paginate_by_min_id(limit, options[:min_id]).reverse + paginate_by_min_id(limit, options[:min_id], options[:max_id]).reverse else paginate_by_max_id(limit, options[:max_id], options[:since_id]).to_a end end - def paginate_by_min_id(limit, min_id = nil) + def paginate_by_min_id(limit, min_id = nil, max_id = nil) query = order(arel_table[:last_status_id].asc).limit(limit) query = query.where(arel_table[:last_status_id].gt(min_id)) if min_id.present? + query = query.where(arel_table[:last_status_id].lt(max_id)) if max_id.present? query end diff --git a/app/models/account_deletion_request.rb b/app/models/account_deletion_request.rb new file mode 100644 index 000000000..7d0c346cc --- /dev/null +++ b/app/models/account_deletion_request.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +# == Schema Information +# +# Table name: account_deletion_requests +# +# id :bigint(8) not null, primary key +# account_id :bigint(8) +# created_at :datetime not null +# updated_at :datetime not null +# +class AccountDeletionRequest < ApplicationRecord + DELAY_TO_DELETION = 30.days.freeze + + belongs_to :account + + def due_at + created_at + DELAY_TO_DELETION + end +end diff --git a/app/models/admin/account_action.rb b/app/models/admin/account_action.rb index b30a82369..c4ac09520 100644 --- a/app/models/admin/account_action.rb +++ b/app/models/admin/account_action.rb @@ -134,7 +134,7 @@ class Admin::AccountAction end def process_email! - UserMailer.warning(target_account.user, warning, status_ids).deliver_now! if warnable? + UserMailer.warning(target_account.user, warning, status_ids).deliver_later! if warnable? end def warnable? @@ -142,7 +142,7 @@ class Admin::AccountAction end def status_ids - @report.status_ids if @report && include_statuses + report.status_ids if report && include_statuses end def reports diff --git a/app/models/concerns/account_associations.rb b/app/models/concerns/account_associations.rb index cca3a17fa..98849f8fc 100644 --- a/app/models/concerns/account_associations.rb +++ b/app/models/concerns/account_associations.rb @@ -60,5 +60,8 @@ module AccountAssociations # Hashtags has_and_belongs_to_many :tags has_many :featured_tags, -> { includes(:tag) }, dependent: :destroy, inverse_of: :account + + # Account deletion requests + has_one :deletion_request, class_name: 'AccountDeletionRequest', inverse_of: :account, dependent: :destroy end end diff --git a/app/models/concerns/account_interactions.rb b/app/models/concerns/account_interactions.rb index be7211f2c..427ebdae2 100644 --- a/app/models/concerns/account_interactions.rb +++ b/app/models/concerns/account_interactions.rb @@ -8,6 +8,7 @@ module AccountInteractions Follow.where(target_account_id: target_account_ids, account_id: account_id).each_with_object({}) do |follow, mapping| mapping[follow.target_account_id] = { reblogs: follow.show_reblogs?, + notify: follow.notify?, } end end @@ -36,6 +37,7 @@ module AccountInteractions FollowRequest.where(target_account_id: target_account_ids, account_id: account_id).each_with_object({}) do |follow_request, mapping| mapping[follow_request.target_account_id] = { reblogs: follow_request.show_reblogs?, + notify: follow_request.notify?, } end end @@ -95,25 +97,29 @@ module AccountInteractions has_many :announcement_mutes, dependent: :destroy end - def follow!(other_account, reblogs: nil, uri: nil, rate_limit: false) - reblogs = true if reblogs.nil? - - rel = active_relationships.create_with(show_reblogs: reblogs, uri: uri, rate_limit: rate_limit) + def follow!(other_account, reblogs: nil, notify: nil, uri: nil, rate_limit: false) + rel = active_relationships.create_with(show_reblogs: reblogs.nil? ? true : reblogs, notify: notify.nil? ? false : notify, uri: uri, rate_limit: rate_limit) .find_or_create_by!(target_account: other_account) - rel.update!(show_reblogs: reblogs) + rel.show_reblogs = reblogs unless reblogs.nil? + rel.notify = notify unless notify.nil? + + rel.save! if rel.changed? + remove_potential_friendship(other_account) rel end - def request_follow!(other_account, reblogs: nil, uri: nil, rate_limit: false) - reblogs = true if reblogs.nil? - - rel = follow_requests.create_with(show_reblogs: reblogs, uri: uri, rate_limit: rate_limit) + def request_follow!(other_account, reblogs: nil, notify: nil, uri: nil, rate_limit: false) + rel = follow_requests.create_with(show_reblogs: reblogs.nil? ? true : reblogs, notify: notify.nil? ? false : notify, uri: uri, rate_limit: rate_limit) .find_or_create_by!(target_account: other_account) - rel.update!(show_reblogs: reblogs) + rel.show_reblogs = reblogs unless reblogs.nil? + rel.notify = notify unless notify.nil? + + rel.save! if rel.changed? + remove_potential_friendship(other_account) rel diff --git a/app/models/concerns/paginable.rb b/app/models/concerns/paginable.rb index 760cc3df4..62e39f671 100644 --- a/app/models/concerns/paginable.rb +++ b/app/models/concerns/paginable.rb @@ -14,15 +14,16 @@ module Paginable # Differs from :paginate_by_max_id in that it gives the results immediately following min_id, # whereas since_id gives the items with largest id, but with since_id as a cutoff. # Results will be in ascending order by id. - scope :paginate_by_min_id, ->(limit, min_id = nil) { + scope :paginate_by_min_id, ->(limit, min_id = nil, max_id = nil) { query = reorder(arel_table[:id]).limit(limit) query = query.where(arel_table[:id].gt(min_id)) if min_id.present? + query = query.where(arel_table[:id].lt(max_id)) if max_id.present? query } def self.to_a_paginated_by_id(limit, options = {}) if options[:min_id].present? - paginate_by_min_id(limit, options[:min_id]).reverse + paginate_by_min_id(limit, options[:min_id], options[:max_id]).reverse else paginate_by_max_id(limit, options[:max_id], options[:since_id]).to_a end diff --git a/app/models/feed.rb b/app/models/feed.rb index 36e0c1e0a..f51dcfab1 100644 --- a/app/models/feed.rb +++ b/app/models/feed.rb @@ -20,12 +20,12 @@ class Feed protected def from_redis(limit, max_id, since_id, min_id) + max_id = '+inf' if max_id.blank? if min_id.blank? - 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) else - unhydrated = redis.zrangebyscore(key, "(#{min_id}", '+inf', limit: [0, limit], with_scores: true).map(&:first).map(&:to_i) + unhydrated = redis.zrangebyscore(key, "(#{min_id}", "(#{max_id}", limit: [0, limit], with_scores: true).map(&:first).map(&:to_i) end Status.where(id: unhydrated).cache_ids diff --git a/app/models/follow.rb b/app/models/follow.rb index f3e48a2ed..0b4ddbf3f 100644 --- a/app/models/follow.rb +++ b/app/models/follow.rb @@ -10,6 +10,7 @@ # target_account_id :bigint(8) not null # show_reblogs :boolean default(TRUE), not null # uri :string +# notify :boolean default(FALSE), not null # class Follow < ApplicationRecord @@ -34,7 +35,7 @@ class Follow < ApplicationRecord end def revoke_request! - FollowRequest.create!(account: account, target_account: target_account, show_reblogs: show_reblogs, uri: uri) + FollowRequest.create!(account: account, target_account: target_account, show_reblogs: show_reblogs, notify: notify, uri: uri) destroy! end diff --git a/app/models/follow_request.rb b/app/models/follow_request.rb index 3325e264c..c1f19149b 100644 --- a/app/models/follow_request.rb +++ b/app/models/follow_request.rb @@ -10,6 +10,7 @@ # target_account_id :bigint(8) not null # show_reblogs :boolean default(TRUE), not null # uri :string +# notify :boolean default(FALSE), not null # class FollowRequest < ApplicationRecord @@ -28,7 +29,7 @@ class FollowRequest < ApplicationRecord validates_with FollowLimitValidator, on: :create def authorize! - account.follow!(target_account, reblogs: show_reblogs, uri: uri) + account.follow!(target_account, reblogs: show_reblogs, notify: notify, uri: uri) MergeWorker.perform_async(target_account.id, account.id) if account.local? destroy! end diff --git a/app/models/form/account_batch.rb b/app/models/form/account_batch.rb index 0b285fde9..7b9e40f68 100644 --- a/app/models/form/account_batch.rb +++ b/app/models/form/account_batch.rb @@ -69,6 +69,6 @@ class Form::AccountBatch records = accounts.includes(:user) records.each { |account| authorize(account.user, :reject?) } - .each { |account| SuspendAccountService.new.call(account, reserve_email: false, reserve_username: false) } + .each { |account| DeleteAccountService.new.call(account, reserve_email: false, reserve_username: false) } end end diff --git a/app/models/invite.rb b/app/models/invite.rb index 29d25eae8..7ea4e2f98 100644 --- a/app/models/invite.rb +++ b/app/models/invite.rb @@ -28,7 +28,7 @@ class Invite < ApplicationRecord before_validation :set_code def valid_for_use? - (max_uses.nil? || uses < max_uses) && !expired? && !(user.nil? || user.disabled?) + (max_uses.nil? || uses < max_uses) && !expired? && user&.functional? end private diff --git a/app/models/notification.rb b/app/models/notification.rb index ad7528f50..e83123c97 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -10,21 +10,34 @@ # updated_at :datetime not null # account_id :bigint(8) not null # from_account_id :bigint(8) not null +# type :string # class Notification < ApplicationRecord + self.inheritance_column = nil + include Paginable include Cacheable - TYPE_CLASS_MAP = { - mention: 'Mention', - reblog: 'Status', - follow: 'Follow', - follow_request: 'FollowRequest', - favourite: 'Favourite', - poll: 'Poll', + LEGACY_TYPE_CLASS_MAP = { + 'Mention' => :mention, + 'Status' => :reblog, + 'Follow' => :follow, + 'FollowRequest' => :follow_request, + 'Favourite' => :favourite, + 'Poll' => :poll, }.freeze + TYPES = %i( + mention + status + reblog + follow + follow_request + favourite + poll + ).freeze + STATUS_INCLUDES = [:account, :application, :preloadable_poll, :media_attachments, :tags, active_mentions: :account, reblog: [:account, :application, :preloadable_poll, :media_attachments, :tags, active_mentions: :account]].freeze belongs_to :account, optional: true @@ -38,26 +51,30 @@ class Notification < ApplicationRecord belongs_to :favourite, foreign_type: 'Favourite', foreign_key: 'activity_id', optional: true belongs_to :poll, foreign_type: 'Poll', foreign_key: 'activity_id', optional: true - validates :account_id, uniqueness: { scope: [:activity_type, :activity_id] } - validates :activity_type, inclusion: { in: TYPE_CLASS_MAP.values } + validates :type, inclusion: { in: TYPES } + + scope :without_suspended, -> { joins(:from_account).merge(Account.without_suspended) } scope :browserable, ->(exclude_types = [], account_id = nil) { - types = TYPE_CLASS_MAP.values - activity_types_from_types(exclude_types) + types = TYPES - exclude_types.map(&:to_sym) + if account_id.nil? - where(activity_type: types) + where(type: types) else - where(activity_type: types, from_account_id: account_id) + where(type: types, from_account_id: account_id) end } cache_associated :from_account, status: STATUS_INCLUDES, mention: [status: STATUS_INCLUDES], favourite: [:account, status: STATUS_INCLUDES], follow: :account, follow_request: :account, poll: [status: STATUS_INCLUDES] def type - @type ||= TYPE_CLASS_MAP.invert[activity_type].to_sym + @type ||= (super || LEGACY_TYPE_CLASS_MAP[activity_type]).to_sym end def target_status case type + when :status + status when :reblog status&.reblog when :favourite @@ -86,10 +103,6 @@ class Notification < ApplicationRecord item.target_status.account = accounts[item.target_status.account_id] if item.target_status end end - - def activity_types_from_types(types) - types.map { |type| TYPE_CLASS_MAP[type.to_sym] }.compact - end end after_initialize :set_from_account diff --git a/app/models/status.rb b/app/models/status.rb index 8495927af..d1ac2e4f2 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -93,19 +93,19 @@ class Status < ApplicationRecord scope :without_replies, -> { where('statuses.reply = FALSE OR statuses.in_reply_to_account_id = statuses.account_id') } scope :without_reblogs, -> { where('statuses.reblog_of_id IS NULL') } scope :with_public_visibility, -> { where(visibility: :public) } - scope :tagged_with, ->(tag) { joins(:statuses_tags).where(statuses_tags: { tag_id: tag }) } + scope :tagged_with, ->(tag_ids) { joins(:statuses_tags).where(statuses_tags: { tag_id: tag_ids }) } scope :in_chosen_languages, ->(account) { where(language: nil).or where(language: account.chosen_languages) } scope :excluding_silenced_accounts, -> { left_outer_joins(:account).where(accounts: { silenced_at: nil }) } scope :including_silenced_accounts, -> { left_outer_joins(:account).where.not(accounts: { silenced_at: nil }) } scope :not_excluded_by_account, ->(account) { where.not(account_id: account.excluded_from_timeline_account_ids) } scope :not_domain_blocked_by_account, ->(account) { account.excluded_from_timeline_domains.blank? ? left_outer_joins(:account) : left_outer_joins(:account).where('accounts.domain IS NULL OR accounts.domain NOT IN (?)', account.excluded_from_timeline_domains) } - scope :tagged_with_all, ->(tags) { - Array(tags).map(&:id).map(&:to_i).reduce(self) do |result, id| + scope :tagged_with_all, ->(tag_ids) { + Array(tag_ids).reduce(self) do |result, id| result.joins("INNER JOIN statuses_tags t#{id} ON t#{id}.status_id = statuses.id AND t#{id}.tag_id = #{id}") end } - scope :tagged_with_none, ->(tags) { - Array(tags).map(&:id).map(&:to_i).reduce(self) do |result, id| + scope :tagged_with_none, ->(tag_ids) { + Array(tag_ids).reduce(self) do |result, id| result.joins("LEFT OUTER JOIN statuses_tags t#{id} ON t#{id}.status_id = statuses.id AND t#{id}.tag_id = #{id}") .where("t#{id}.tag_id IS NULL") end diff --git a/app/models/tag_feed.rb b/app/models/tag_feed.rb index baff55020..a7d583a7e 100644 --- a/app/models/tag_feed.rb +++ b/app/models/tag_feed.rb @@ -53,6 +53,6 @@ class TagFeed < PublicFeed end def tags_for(names) - Tag.matching_name(Array(names).take(LIMIT_PER_MODE)) if names.present? + Tag.matching_name(Array(names).take(LIMIT_PER_MODE)).pluck(:id) if names.present? end end diff --git a/app/models/user.rb b/app/models/user.rb index 4467362e1..6cd2ca6bd 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -169,7 +169,7 @@ class User < ApplicationRecord end def active_for_authentication? - true + !account.memorial? end def suspicious_sign_in?(ip) @@ -177,7 +177,7 @@ class User < ApplicationRecord end def functional? - confirmed? && approved? && !disabled? && !account.suspended? + confirmed? && approved? && !disabled? && !account.suspended? && !account.memorial? end def unconfirmed_or_pending? diff --git a/app/models/webauthn_credential.rb b/app/models/webauthn_credential.rb index 4129ce539..7d423e38d 100644 --- a/app/models/webauthn_credential.rb +++ b/app/models/webauthn_credential.rb @@ -18,5 +18,5 @@ class WebauthnCredential < ApplicationRecord validates :external_id, uniqueness: true validates :nickname, uniqueness: { scope: :user_id } validates :sign_count, - numericality: { only_integer: true, greater_than_or_equal_to: 0, less_than_or_equal_to: 2**32 - 1 } + numericality: { only_integer: true, greater_than_or_equal_to: 0, less_than_or_equal_to: 2**63 - 1 } end |