diff options
Diffstat (limited to 'app/models')
-rw-r--r-- | app/models/account.rb | 32 | ||||
-rw-r--r-- | app/models/domain_block.rb | 2 | ||||
-rw-r--r-- | app/models/follow_request.rb | 2 | ||||
-rw-r--r-- | app/models/media_attachment.rb | 18 | ||||
-rw-r--r-- | app/models/notification.rb | 4 | ||||
-rw-r--r-- | app/models/preview_card.rb | 20 | ||||
-rw-r--r-- | app/models/setting.rb | 50 | ||||
-rw-r--r-- | app/models/status.rb | 11 | ||||
-rw-r--r-- | app/models/user.rb | 7 | ||||
-rw-r--r-- | app/models/web.rb | 7 | ||||
-rw-r--r-- | app/models/web/setting.rb | 7 |
11 files changed, 135 insertions, 25 deletions
diff --git a/app/models/account.rb b/app/models/account.rb index 5c1f6e7c1..c2a41c4c6 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -62,8 +62,8 @@ class Account < ApplicationRecord scope :expiring, ->(time) { where(subscription_expires_at: nil).or(where('subscription_expires_at < ?', time)).remote.with_followers } scope :silenced, -> { where(silenced: true) } scope :suspended, -> { where(suspended: true) } - scope :recent, -> { reorder('id desc') } - scope :alphabetic, -> { order('domain ASC, username ASC') } + scope :recent, -> { reorder(id: :desc) } + scope :alphabetic, -> { order(domain: :asc, username: :asc) } def follow!(other_account) active_relationships.where(target_account: other_account).first_or_create!(target_account: other_account) @@ -104,7 +104,7 @@ class Account < ApplicationRecord end def subscribed? - !subscription_expires_at.nil? + !subscription_expires_at.blank? end def favourited?(status) @@ -125,13 +125,10 @@ class Account < ApplicationRecord def save_with_optional_avatar! save! - rescue ActiveRecord::RecordInvalid => invalid - if invalid.record.errors[:avatar_file_size] || invalid[:avatar_content_type] - self.avatar = nil - retry - end - - raise invalid + rescue ActiveRecord::RecordInvalid + self.avatar = nil + self[:avatar_remote_url] = '' + save! end def avatar_remote_url=(url) @@ -159,6 +156,7 @@ class Account < ApplicationRecord end def find_remote!(username, domain) + return if username.blank? where(arel_table[:username].matches(username.gsub(/[%_]/, '\\\\\0'))).where(domain.nil? ? { domain: nil } : arel_table[:domain].matches(domain.gsub(/[%_]/, '\\\\\0'))).take! end @@ -175,19 +173,25 @@ class Account < ApplicationRecord end def following_map(target_account_ids, account_id) - Follow.where(target_account_id: target_account_ids).where(account_id: account_id).map { |f| [f.target_account_id, true] }.to_h + follow_mapping(Follow.where(target_account_id: target_account_ids, account_id: account_id), :target_account_id) end def followed_by_map(target_account_ids, account_id) - Follow.where(account_id: target_account_ids).where(target_account_id: account_id).map { |f| [f.account_id, true] }.to_h + follow_mapping(Follow.where(account_id: target_account_ids, target_account_id: account_id), :account_id) end def blocking_map(target_account_ids, account_id) - Block.where(target_account_id: target_account_ids).where(account_id: account_id).map { |b| [b.target_account_id, true] }.to_h + follow_mapping(Block.where(target_account_id: target_account_ids, account_id: account_id), :target_account_id) end def requested_map(target_account_ids, account_id) - FollowRequest.where(target_account_id: target_account_ids).where(account_id: account_id).map { |r| [r.target_account_id, true] }.to_h + follow_mapping(FollowRequest.where(target_account_id: target_account_ids, account_id: account_id), :target_account_id) + end + + private + + def follow_mapping(query, field) + query.pluck(field).inject({}) { |mapping, id| mapping[id] = true; mapping } end end diff --git a/app/models/domain_block.rb b/app/models/domain_block.rb index 9075b90a0..b4606da60 100644 --- a/app/models/domain_block.rb +++ b/app/models/domain_block.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class DomainBlock < ApplicationRecord + enum severity: [:silence, :suspend] + validates :domain, presence: true, uniqueness: true def self.blocked?(domain) diff --git a/app/models/follow_request.rb b/app/models/follow_request.rb index 8eef3abf4..936ad0691 100644 --- a/app/models/follow_request.rb +++ b/app/models/follow_request.rb @@ -13,7 +13,7 @@ class FollowRequest < ApplicationRecord def authorize! account.follow!(target_account) - FeedManager.instance.merge_into_timeline(target_account, account) + MergeWorker.perform_async(target_account.id, account.id) destroy! end diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb index 2a5d23739..ecbed03e3 100644 --- a/app/models/media_attachment.rb +++ b/app/models/media_attachment.rb @@ -16,6 +16,7 @@ class MediaAttachment < ApplicationRecord validates :account, presence: true + scope :local, -> { where(remote_url: '') } default_scope { order('id asc') } def local? @@ -38,6 +39,12 @@ class MediaAttachment < ApplicationRecord image? ? 'image' : 'video' end + def to_param + shortcode + end + + before_create :set_shortcode + class << self private @@ -62,4 +69,15 @@ class MediaAttachment < ApplicationRecord end end end + + private + + def set_shortcode + return unless local? + + loop do + self.shortcode = SecureRandom.urlsafe_base64(14) + break if MediaAttachment.find_by(shortcode: shortcode).nil? + end + end end diff --git a/app/models/notification.rb b/app/models/notification.rb index c0b5c45a8..b7e8c9e71 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -39,9 +39,9 @@ class Notification < ApplicationRecord def target_status case type when :reblog - activity.reblog + activity&.reblog when :favourite, :mention - activity.status + activity&.status end end diff --git a/app/models/preview_card.rb b/app/models/preview_card.rb new file mode 100644 index 000000000..e59b05eb8 --- /dev/null +++ b/app/models/preview_card.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +class PreviewCard < ApplicationRecord + IMAGE_MIME_TYPES = ['image/jpeg', 'image/png', 'image/gif'].freeze + + belongs_to :status + + has_attached_file :image, styles: { original: '120x120#' }, convert_options: { all: '-quality 80 -strip' } + + validates :url, presence: true + validates_attachment_content_type :image, content_type: IMAGE_MIME_TYPES + validates_attachment_size :image, less_than: 1.megabytes + + def save_with_optional_image! + save! + rescue ActiveRecord::RecordInvalid + self.image = nil + save! + end +end diff --git a/app/models/setting.rb b/app/models/setting.rb new file mode 100644 index 000000000..3796253d4 --- /dev/null +++ b/app/models/setting.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +class Setting < RailsSettings::Base + source Rails.root.join('config/settings.yml') + namespace Rails.env + + def to_param + var + end + + class << self + def [](key) + return super(key) unless rails_initialized? + + val = Rails.cache.fetch(cache_key(key, @object)) do + db_val = object(key) + + if db_val + default_value = default_settings[key] + + return default_value.with_indifferent_access.merge!(db_val.value) if default_value.is_a?(Hash) + db_val.value + else + default_settings[key] + end + end + + val + end + + def all_as_records + vars = thing_scoped + records = vars.map { |r| [r.var, r] }.to_h + + default_settings.each do |key, default_value| + next if records.key?(key) || default_value.is_a?(Hash) + records[key] = Setting.new(var: key, value: default_value) + end + + records + end + + private + + def default_settings + return {} unless RailsSettings::Default.enabled? + RailsSettings::Default.instance + end + end +end diff --git a/app/models/status.rb b/app/models/status.rb index bc595c93b..651d0dbc9 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -1,12 +1,15 @@ # frozen_string_literal: true class Status < ApplicationRecord + include ActiveModel::Validations include Paginable include Streamable include Cacheable enum visibility: [:public, :unlisted, :private], _suffix: :visibility + belongs_to :application, class_name: 'Doorkeeper::Application' + belongs_to :account, inverse_of: :statuses belongs_to :in_reply_to_account, foreign_key: 'in_reply_to_account_id', class_name: 'Account' @@ -21,11 +24,12 @@ class Status < ApplicationRecord has_and_belongs_to_many :tags has_one :notification, as: :activity, dependent: :destroy + has_one :preview_card, dependent: :destroy validates :account, presence: true validates :uri, uniqueness: true, unless: 'local?' - validates :text, presence: true, length: { maximum: 500 }, if: proc { |s| s.local? && !s.reblog? } - validates :text, presence: true, if: proc { |s| !s.local? && !s.reblog? } + validates :text, presence: true, unless: 'reblog?' + validates_with StatusLengthValidator validates :reblog, uniqueness: { scope: :account, message: 'of status already exists' }, if: 'reblog?' default_scope { order('id desc') } @@ -33,7 +37,7 @@ class Status < ApplicationRecord scope :remote, -> { where.not(uri: nil) } scope :local, -> { where(uri: nil) } - cache_associated :account, :media_attachments, :tags, :stream_entry, mentions: :account, reblog: [:account, :stream_entry, :tags, :media_attachments, mentions: :account], thread: :account + cache_associated :account, :application, :media_attachments, :tags, :stream_entry, mentions: :account, reblog: [:account, :application, :stream_entry, :tags, :media_attachments, mentions: :account], thread: :account def local? uri.nil? @@ -171,6 +175,7 @@ class Status < ApplicationRecord before_validation do text.strip! + spoiler_text&.strip! self.reblog = reblog.reblog if reblog? && reblog.reblog? self.in_reply_to_account_id = (thread.account_id == account_id && thread.reply? ? thread.in_reply_to_account_id : thread.account_id) if reply? diff --git a/app/models/user.rb b/app/models/user.rb index d5a52da06..71d3ee0b8 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class User < ApplicationRecord + include Settings::Extend + devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :confirmable belongs_to :account, inverse_of: :user @@ -14,11 +16,6 @@ class User < ApplicationRecord scope :recent, -> { order('id desc') } scope :admins, -> { where(admin: true) } - has_settings do |s| - s.key :notification_emails, defaults: { follow: false, reblog: false, favourite: false, mention: false, follow_request: true } - s.key :interactions, defaults: { must_be_follower: false, must_be_following: false } - end - def send_devise_notification(notification, *args) devise_mailer.send(notification, self, *args).deliver_later end diff --git a/app/models/web.rb b/app/models/web.rb new file mode 100644 index 000000000..58654fd77 --- /dev/null +++ b/app/models/web.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module Web + def self.table_name_prefix + 'web_' + end +end diff --git a/app/models/web/setting.rb b/app/models/web/setting.rb new file mode 100644 index 000000000..3d601189b --- /dev/null +++ b/app/models/web/setting.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class Web::Setting < ApplicationRecord + belongs_to :user + + validates :user, uniqueness: true +end |