diff options
author | Ondřej Hruška <ondra@ondrovo.com> | 2017-09-28 09:12:17 +0200 |
---|---|---|
committer | Ondřej Hruška <ondra@ondrovo.com> | 2017-09-28 09:12:17 +0200 |
commit | 9330ea1f4d34b6ef4ce6e841f1aa931a7f10f749 (patch) | |
tree | 81e346b3d9ca532b3d252135d82ce20f61780a36 /app/models | |
parent | 06e299cef591b63bd96f320eadc873b047cd2664 (diff) | |
parent | 4aea3f88a6d30f102a79c2da7fcfac96465ba1a8 (diff) |
Merge commit '4aea3f88a6d30f102a79c2da7fcfac96465ba1a8' into merging-upstream
Diffstat (limited to 'app/models')
-rw-r--r-- | app/models/account.rb | 5 | ||||
-rw-r--r-- | app/models/concerns/remotable.rb | 4 | ||||
-rw-r--r-- | app/models/custom_emoji.rb | 38 | ||||
-rw-r--r-- | app/models/instance_filter.rb | 28 | ||||
-rw-r--r-- | app/models/media_attachment.rb | 10 | ||||
-rw-r--r-- | app/models/site_upload.rb | 44 | ||||
-rw-r--r-- | app/models/status.rb | 9 |
7 files changed, 132 insertions, 6 deletions
diff --git a/app/models/account.rb b/app/models/account.rb index ac27c7923..1b996e3cc 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -106,6 +106,7 @@ class Account < ApplicationRecord scope :by_domain_accounts, -> { group(:domain).select(:domain, 'COUNT(*) AS accounts_count').order('accounts_count desc') } scope :matches_username, ->(value) { where(arel_table[:username].matches("#{value}%")) } scope :matches_display_name, ->(value) { where(arel_table[:display_name].matches("#{value}%")) } + scope :matches_domain, ->(value) { where(arel_table[:domain].matches("%#{value}%")) } delegate :email, :current_sign_in_ip, @@ -174,6 +175,10 @@ class Account < ApplicationRecord end class << self + def readonly_attributes + super - %w(statuses_count following_count followers_count) + end + def domains reorder(nil).pluck('distinct accounts.domain') end diff --git a/app/models/concerns/remotable.rb b/app/models/concerns/remotable.rb index 270043a9e..990035b34 100644 --- a/app/models/concerns/remotable.rb +++ b/app/models/concerns/remotable.rb @@ -27,9 +27,11 @@ module Remotable matches = response.headers['content-disposition']&.match(/filename="([^"]*)"/) filename = matches.nil? ? parsed_url.path.split('/').last : matches[1] + basename = SecureRandom.hex(8) + extname = File.extname(filename) send("#{attachment_name}=", StringIO.new(response.to_s)) - send("#{attachment_name}_file_name=", filename) + send("#{attachment_name}_file_name=", basename + extname) self[attribute_name] = url if has_attribute?(attribute_name) rescue HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError, Paperclip::Errors::NotIdentifiedByImageMagickError, Addressable::URI::InvalidURIError => e diff --git a/app/models/custom_emoji.rb b/app/models/custom_emoji.rb new file mode 100644 index 000000000..f4d3b16a0 --- /dev/null +++ b/app/models/custom_emoji.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true +# == Schema Information +# +# Table name: custom_emojis +# +# id :integer not null, primary key +# shortcode :string default(""), not null +# domain :string +# image_file_name :string +# image_content_type :string +# image_file_size :integer +# image_updated_at :datetime +# created_at :datetime not null +# updated_at :datetime not null +# + +class CustomEmoji < ApplicationRecord + SHORTCODE_RE_FRAGMENT = '[a-zA-Z0-9_]{2,}' + + SCAN_RE = /(?<=[^[:alnum:]:]|\n|^) + :(#{SHORTCODE_RE_FRAGMENT}): + (?=[^[:alnum:]:]|$)/x + + has_attached_file :image + + validates_attachment :image, content_type: { content_type: 'image/png' }, presence: true, size: { in: 0..50.kilobytes } + validates :shortcode, uniqueness: { scope: :domain }, format: { with: /\A#{SHORTCODE_RE_FRAGMENT}\z/ }, length: { minimum: 2 } + + include Remotable + + class << self + def from_text(text, domain) + return [] if text.blank? + shortcodes = text.scan(SCAN_RE).map(&:first) + where(shortcode: shortcodes, domain: domain) + end + end +end diff --git a/app/models/instance_filter.rb b/app/models/instance_filter.rb new file mode 100644 index 000000000..5073cf1fa --- /dev/null +++ b/app/models/instance_filter.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +class InstanceFilter + attr_reader :params + + def initialize(params) + @params = params + end + + def results + scope = Account.remote.by_domain_accounts + params.each do |key, value| + scope.merge!(scope_for(key, value)) if value.present? + end + scope + end + + private + + def scope_for(key, value) + case key.to_s + when 'domain_name' + Account.matches_domain(value) + else + raise "Unknown filter: #{key}" + end + end +end diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb index d83ca44f1..d913e7372 100644 --- a/app/models/media_attachment.rb +++ b/app/models/media_attachment.rb @@ -56,15 +56,21 @@ class MediaAttachment < ApplicationRecord validates :account, presence: true - scope :attached, -> { where.not(status_id: nil) } + scope :attached, -> { where.not(status_id: nil) } scope :unattached, -> { where(status_id: nil) } - scope :local, -> { where(remote_url: '') } + scope :local, -> { where(remote_url: '') } + scope :remote, -> { where.not(remote_url: '') } + default_scope { order(id: :asc) } def local? remote_url.blank? end + def needs_redownload? + file.blank? && remote_url.present? + end + def to_param shortcode end diff --git a/app/models/site_upload.rb b/app/models/site_upload.rb new file mode 100644 index 000000000..8ffdc8313 --- /dev/null +++ b/app/models/site_upload.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true +# == Schema Information +# +# Table name: site_uploads +# +# id :integer not null, primary key +# var :string default(""), not null +# file_file_name :string +# file_content_type :string +# file_file_size :integer +# file_updated_at :datetime +# meta :json +# created_at :datetime not null +# updated_at :datetime not null +# + +class SiteUpload < ApplicationRecord + has_attached_file :file + + validates_attachment_content_type :file, content_type: /\Aimage\/.*\z/ + validates :var, presence: true, uniqueness: true + + before_save :set_meta + after_commit :clear_cache + + def cache_key + "site_uploads/#{var}" + end + + private + + def set_meta + tempfile = file.queued_for_write[:original] + + return if tempfile.nil? + + geometry = Paperclip::Geometry.from_file(tempfile) + self.meta = { width: geometry.width.to_i, height: geometry.height.to_i } + end + + def clear_cache + Rails.cache.delete(cache_key) + end +end diff --git a/app/models/status.rb b/app/models/status.rb index 514cab2e4..326d128d6 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -55,7 +55,7 @@ class Status < ApplicationRecord has_one :notification, as: :activity, dependent: :destroy has_one :stream_entry, as: :activity, inverse_of: :status - validates :uri, uniqueness: true, unless: :local? + validates :uri, uniqueness: true, presence: true, unless: :local? validates :text, presence: true, unless: :reblog? validates_with StatusLengthValidator validates :reblog, uniqueness: { scope: :account }, if: :reblog? @@ -70,7 +70,6 @@ class Status < ApplicationRecord 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 :local_only, -> { left_outer_joins(:account).where(accounts: { domain: nil }) } scope :excluding_silenced_accounts, -> { left_outer_joins(:account).where(accounts: { silenced: false }) } scope :including_silenced_accounts, -> { left_outer_joins(:account).where(accounts: { silenced: true }) } scope :not_excluded_by_account, ->(account) { where.not(account_id: account.excluded_from_timeline_account_ids) } @@ -132,6 +131,10 @@ class Status < ApplicationRecord !sensitive? && media_attachments.any? end + def emojis + CustomEmoji.from_text(text, account.domain) + end + after_create :store_uri, if: :local? before_validation :prepare_contents, if: :local? @@ -221,7 +224,7 @@ class Status < ApplicationRecord private def timeline_scope(local_only = false) - starting_scope = local_only ? Status.local_only : Status + starting_scope = local_only ? Status.local : Status starting_scope .with_public_visibility .without_reblogs |