diff options
author | Starfall <us@starfall.systems> | 2023-01-17 11:41:05 -0600 |
---|---|---|
committer | Starfall <us@starfall.systems> | 2023-01-17 11:41:05 -0600 |
commit | 1f9c919b8769f5b0a3424ef343e0049d33d656e3 (patch) | |
tree | 1853486629da4b3b76192fe8756e8d4f6d71adcb /app/models | |
parent | 957c21273ff42d5b2b4a5e16b7869bbb09aeb865 (diff) | |
parent | 13227e1dafd308dfe1a3effc3379b766274809b3 (diff) |
Merge remote-tracking branch 'glitch/main'
Diffstat (limited to 'app/models')
-rw-r--r-- | app/models/account.rb | 19 | ||||
-rw-r--r-- | app/models/account_filter.rb | 2 | ||||
-rw-r--r-- | app/models/admin/status_batch_action.rb | 16 | ||||
-rw-r--r-- | app/models/concerns/account_interactions.rb | 4 | ||||
-rw-r--r-- | app/models/concerns/omniauthable.rb | 9 | ||||
-rw-r--r-- | app/models/form/admin_settings.rb | 20 | ||||
-rw-r--r-- | app/models/media_attachment.rb | 2 | ||||
-rw-r--r-- | app/models/relay.rb | 5 | ||||
-rw-r--r-- | app/models/status.rb | 31 | ||||
-rw-r--r-- | app/models/tag.rb | 22 | ||||
-rw-r--r-- | app/models/user.rb | 17 | ||||
-rw-r--r-- | app/models/webhook.rb | 1 |
12 files changed, 104 insertions, 44 deletions
diff --git a/app/models/account.rb b/app/models/account.rb index 6b3bd3af5..d9511999b 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -339,9 +339,15 @@ class Account < ApplicationRecord def save_with_optional_media! save! - rescue ActiveRecord::RecordInvalid - self.avatar = nil - self.header = nil + rescue ActiveRecord::RecordInvalid => e + errors = e.record.errors.errors + errors.each do |err| + if err.attribute == :avatar + self.avatar = nil + elsif err.attribute == :header + self.header = nil + end + end save! end @@ -498,7 +504,8 @@ class Account < ApplicationRecord <<-SQL.squish SELECT accounts.*, - (count(f.id) + 1) * ts_rank_cd(#{TEXTSEARCH}, to_tsquery('simple', :tsquery), 32) AS rank + (count(f.id) + 1) * ts_rank_cd(#{TEXTSEARCH}, to_tsquery('simple', :tsquery), 32) AS rank, + count(f.id) AS followed FROM accounts LEFT OUTER JOIN follows AS f ON (accounts.id = f.account_id AND f.target_account_id = :id) OR (accounts.id = f.target_account_id AND f.account_id = :id) LEFT JOIN users ON accounts.id = users.account_id @@ -506,8 +513,8 @@ class Account < ApplicationRecord AND accounts.suspended_at IS NULL AND accounts.moved_to_account_id IS NULL AND (accounts.domain IS NOT NULL OR (users.approved = TRUE AND users.confirmed_at IS NOT NULL)) - GROUP BY accounts.id - ORDER BY rank DESC + GROUP BY accounts.id, s.id + ORDER BY followed DESC, rank DESC LIMIT :limit OFFSET :offset SQL end diff --git a/app/models/account_filter.rb b/app/models/account_filter.rb index 3a4ac0492..d27bb46fc 100644 --- a/app/models/account_filter.rb +++ b/app/models/account_filter.rb @@ -81,7 +81,7 @@ class AccountFilter when 'suspended' Account.suspended when 'disabled' - accounts_with_users.merge(User.disabled) + accounts_with_users.merge(User.disabled).without_suspended when 'silenced' Account.silenced when 'sensitized' diff --git a/app/models/admin/status_batch_action.rb b/app/models/admin/status_batch_action.rb index 0f019b854..39cd7d0eb 100644 --- a/app/models/admin/status_batch_action.rb +++ b/app/models/admin/status_batch_action.rb @@ -73,7 +73,7 @@ class Admin::StatusBatchAction # Can't use a transaction here because UpdateStatusService queues # Sidekiq jobs statuses.includes(:media_attachments, :preview_cards).find_each do |status| - next unless status.with_media? || status.with_preview_card? + next if status.discarded? || !(status.with_media? || status.with_preview_card?) authorize([:admin, status], :update?) @@ -89,15 +89,15 @@ class Admin::StatusBatchAction report.resolve!(current_account) log_action(:resolve, report) end - - @warning = target_account.strikes.create!( - action: :mark_statuses_as_sensitive, - account: current_account, - report: report, - status_ids: status_ids - ) end + @warning = target_account.strikes.create!( + action: :mark_statuses_as_sensitive, + account: current_account, + report: report, + status_ids: status_ids + ) + UserMailer.warning(target_account.user, @warning).deliver_later! if warnable? end diff --git a/app/models/concerns/account_interactions.rb b/app/models/concerns/account_interactions.rb index 15c49f2fe..de8bf338f 100644 --- a/app/models/concerns/account_interactions.rb +++ b/app/models/concerns/account_interactions.rb @@ -44,6 +44,10 @@ module AccountInteractions end end + def requested_by_map(target_account_ids, account_id) + follow_mapping(FollowRequest.where(account_id: target_account_ids, target_account_id: account_id), :account_id) + end + def endorsed_map(target_account_ids, account_id) follow_mapping(AccountPin.where(account_id: account_id, target_account_id: target_account_ids), :target_account_id) end diff --git a/app/models/concerns/omniauthable.rb b/app/models/concerns/omniauthable.rb index a90d5d888..feac0a1f5 100644 --- a/app/models/concerns/omniauthable.rb +++ b/app/models/concerns/omniauthable.rb @@ -55,7 +55,14 @@ module Omniauthable user = User.new(user_params_from_auth(email, auth)) - user.account.avatar_remote_url = auth.info.image if /\A#{URI::DEFAULT_PARSER.make_regexp(%w(http https))}\z/.match?(auth.info.image) + begin + if /\A#{URI::DEFAULT_PARSER.make_regexp(%w(http https))}\z/.match?(auth.info.image) + user.account.avatar_remote_url = auth.info.image + end + rescue Mastodon::UnexpectedResponseError + user.account.avatar_remote_url = nil + end + user.skip_confirmation! if email_is_verified user.save! user diff --git a/app/models/form/admin_settings.rb b/app/models/form/admin_settings.rb index b53a82db2..b595529f8 100644 --- a/app/models/form/admin_settings.rb +++ b/app/models/form/admin_settings.rb @@ -83,6 +83,7 @@ class Form::AdminSettings validates :show_domain_blocks_rationale, inclusion: { in: %w(disabled users all) }, if: -> { defined?(@show_domain_blocks_rationale) } validates :media_cache_retention_period, :content_cache_retention_period, :backups_retention_period, numericality: { only_integer: true }, allow_blank: true, if: -> { defined?(@media_cache_retention_period) || defined?(@content_cache_retention_period) || defined?(@backups_retention_period) } validates :site_short_description, length: { maximum: 200 }, if: -> { defined?(@site_short_description) } + validate :validate_site_uploads KEYS.each do |key| define_method(key) do @@ -104,11 +105,16 @@ class Form::AdminSettings define_method("#{key}=") do |file| value = public_send(key) value.file = file + rescue Mastodon::DimensionsValidationError => e + errors.add(key.to_sym, e.message) end end def save - return false unless valid? + # NOTE: Annoyingly, files are processed and can error out before + # validations are called, and `valid?` clears errors… + # So for now, return early if errors aren't empty. + return false unless errors.empty? && valid? KEYS.each do |key| next if PSEUDO_KEYS.include?(key) || !instance_variable_defined?("@#{key}") @@ -141,4 +147,16 @@ class Form::AdminSettings value end end + + def validate_site_uploads + UPLOAD_KEYS.each do |key| + next unless instance_variable_defined?("@#{key}") + upload = instance_variable_get("@#{key}") + next if upload.valid? + + upload.errors.each do |error| + errors.import(error, attribute: key) + end + end + end end diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb index f2b34e4cd..4dd3042ab 100644 --- a/app/models/media_attachment.rb +++ b/app/models/media_attachment.rb @@ -210,6 +210,8 @@ class MediaAttachment < ApplicationRecord default_scope { order(id: :asc) } + attr_accessor :skip_download + def local? remote_url.blank? end diff --git a/app/models/relay.rb b/app/models/relay.rb index d6ddd30ed..c66bfe4ff 100644 --- a/app/models/relay.rb +++ b/app/models/relay.rb @@ -18,6 +18,7 @@ class Relay < ApplicationRecord scope :enabled, -> { accepted } + before_validation :strip_url before_destroy :ensure_disabled alias enabled? accepted? @@ -74,4 +75,8 @@ class Relay < ApplicationRecord def ensure_disabled disable! if enabled? end + + def strip_url + inbox_url&.strip! + end end diff --git a/app/models/status.rb b/app/models/status.rb index 6cfe19d23..14b7a39fe 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -31,7 +31,7 @@ # class Status < ApplicationRecord - before_destroy :unlink_from_conversations + before_destroy :unlink_from_conversations! include Discard::Model include Paginable @@ -314,15 +314,14 @@ class Status < ApplicationRecord after_create_commit :store_uri, if: :local? after_create_commit :update_statistics, if: :local? - around_create Mastodon::Snowflake::Callbacks - - before_create :set_locality - before_validation :prepare_contents, if: :local? before_validation :set_reblog before_validation :set_visibility before_validation :set_conversation before_validation :set_local + before_create :set_locality + + around_create Mastodon::Snowflake::Callbacks after_create :set_poll_id @@ -504,6 +503,17 @@ class Status < ApplicationRecord update_attribute(:deleted_at, discard_time) end + def unlink_from_conversations! + return unless direct_visibility? + + inbox_owners = mentioned_accounts.local + inbox_owners += [account] if account.local? + + inbox_owners.each do |inbox_owner| + AccountConversation.remove_status(inbox_owner, self) + end + end + private def update_status_stat!(attrs) @@ -587,15 +597,4 @@ class Status < ApplicationRecord reblog&.decrement_count!(:reblogs_count) if reblog? thread&.decrement_count!(:replies_count) if in_reply_to_id.present? && distributable? end - - def unlink_from_conversations - return unless direct_visibility? - - inbox_owners = mentioned_accounts.local - inbox_owners += [account] if account.local? - - inbox_owners.each do |inbox_owner| - AccountConversation.remove_status(inbox_owner, self) - end - end end diff --git a/app/models/tag.rb b/app/models/tag.rb index b66f85423..47a05d00a 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -26,8 +26,12 @@ class Tag < ApplicationRecord has_many :featured_tags, dependent: :destroy, inverse_of: :tag has_many :followers, through: :passive_relationships, source: :account - HASHTAG_SEPARATORS = "_\u00B7\u200c" - HASHTAG_NAME_PAT = "([[:word:]_][[:word:]#{HASHTAG_SEPARATORS}]*[[:alpha:]#{HASHTAG_SEPARATORS}][[:word:]#{HASHTAG_SEPARATORS}]*[[:word:]_])|([[:word:]_]*[[:alpha:]][[:word:]_]*)" + HASHTAG_SEPARATORS = "_\u00B7\u30FB\u200c" + HASHTAG_FIRST_SEQUENCE_CHUNK_ONE = "[[:word:]_][[:word:]#{HASHTAG_SEPARATORS}]*[[:alpha:]#{HASHTAG_SEPARATORS}]" + HASHTAG_FIRST_SEQUENCE_CHUNK_TWO = "[[:word:]#{HASHTAG_SEPARATORS}]*[[:word:]_]" + HASHTAG_FIRST_SEQUENCE = "(#{HASHTAG_FIRST_SEQUENCE_CHUNK_ONE}#{HASHTAG_FIRST_SEQUENCE_CHUNK_TWO})" + HASTAG_LAST_SEQUENCE = '([[:word:]_]*[[:alpha:]][[:word:]_]*)' + HASHTAG_NAME_PAT = "#{HASHTAG_FIRST_SEQUENCE}|#{HASTAG_LAST_SEQUENCE}" HASHTAG_RE = /(?:^|[^\/\)\w])#(#{HASHTAG_NAME_PAT})/i HASHTAG_NAME_RE = /\A(#{HASHTAG_NAME_PAT})\z/i @@ -45,7 +49,11 @@ class Tag < ApplicationRecord scope :listable, -> { where(listable: [true, nil]) } scope :trendable, -> { Setting.trendable_by_default ? where(trendable: [true, nil]) : where(trendable: true) } scope :not_trendable, -> { where(trendable: false) } - scope :recently_used, ->(account) { joins(:statuses).where(statuses: { id: account.statuses.select(:id).limit(1000) }).group(:id).order(Arel.sql('count(*) desc')) } + scope :recently_used, ->(account) { + joins(:statuses) + .where(statuses: { id: account.statuses.select(:id).limit(1000) }) + .group(:id).order(Arel.sql('count(*) desc')) + } scope :matches_name, ->(term) { where(arel_table[:name].lower.matches(arel_table.lower("#{sanitize_sql_like(Tag.normalize(term))}%"), nil, true)) } # Search with case-sensitive to use B-tree index update_index('tags', :self) @@ -105,7 +113,8 @@ class Tag < ApplicationRecord names = Array(name_or_names).map { |str| [normalize(str), str] }.uniq(&:first) names.map do |(normalized_name, display_name)| - tag = matching_name(normalized_name).first || create(name: normalized_name, display_name: display_name.gsub(HASHTAG_INVALID_CHARS_RE, '')) + tag = matching_name(normalized_name).first || create(name: normalized_name, + display_name: display_name.gsub(HASHTAG_INVALID_CHARS_RE, '')) yield tag if block_given? @@ -154,6 +163,9 @@ class Tag < ApplicationRecord end def validate_display_name_change - errors.add(:display_name, I18n.t('tags.does_not_match_previous_name')) unless HashtagNormalizer.new.normalize(display_name).casecmp(name.mb_chars).zero? + unless HashtagNormalizer.new.normalize(display_name).casecmp(name.mb_chars).zero? + errors.add(:display_name, + I18n.t('tags.does_not_match_previous_name')) + end end end diff --git a/app/models/user.rb b/app/models/user.rb index 209bfa521..2e3c067ec 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -386,6 +386,15 @@ class User < ApplicationRecord super end + def revoke_access! + Doorkeeper::AccessGrant.by_resource_owner(self).update_all(revoked_at: Time.now.utc) + + Doorkeeper::AccessToken.by_resource_owner(self).in_batches do |batch| + batch.update_all(revoked_at: Time.now.utc) + Web::PushSubscription.where(access_token_id: batch).delete_all + end + end + def reset_password! # First, change password to something random and deactivate all sessions transaction do @@ -394,12 +403,7 @@ class User < ApplicationRecord end # Then, remove all authorized applications and connected push subscriptions - Doorkeeper::AccessGrant.by_resource_owner(self).in_batches.update_all(revoked_at: Time.now.utc) - - Doorkeeper::AccessToken.by_resource_owner(self).in_batches do |batch| - batch.update_all(revoked_at: Time.now.utc) - Web::PushSubscription.where(access_token_id: batch).delete_all - end + revoke_access! # Finally, send a reset password prompt to the user send_reset_password_instructions @@ -494,6 +498,7 @@ class User < ApplicationRecord BootstrapTimelineWorker.perform_async(account_id) ActivityTracker.increment('activity:accounts:local') UserMailer.welcome(self).deliver_later + TriggerWebhookWorker.perform_async('account.approved', 'Account', account_id) end def prepare_returning_user! diff --git a/app/models/webhook.rb b/app/models/webhook.rb index 431edd75d..4aafb1257 100644 --- a/app/models/webhook.rb +++ b/app/models/webhook.rb @@ -15,6 +15,7 @@ class Webhook < ApplicationRecord EVENTS = %w( + account.approved account.created report.created ).freeze |