about summary refs log tree commit diff
path: root/app/models
diff options
context:
space:
mode:
authorOndřej Hruška <ondra@ondrovo.com>2017-09-28 09:12:17 +0200
committerOndřej Hruška <ondra@ondrovo.com>2017-09-28 09:12:17 +0200
commit9330ea1f4d34b6ef4ce6e841f1aa931a7f10f749 (patch)
tree81e346b3d9ca532b3d252135d82ce20f61780a36 /app/models
parent06e299cef591b63bd96f320eadc873b047cd2664 (diff)
parent4aea3f88a6d30f102a79c2da7fcfac96465ba1a8 (diff)
Merge commit '4aea3f88a6d30f102a79c2da7fcfac96465ba1a8' into merging-upstream
Diffstat (limited to 'app/models')
-rw-r--r--app/models/account.rb5
-rw-r--r--app/models/concerns/remotable.rb4
-rw-r--r--app/models/custom_emoji.rb38
-rw-r--r--app/models/instance_filter.rb28
-rw-r--r--app/models/media_attachment.rb10
-rw-r--r--app/models/site_upload.rb44
-rw-r--r--app/models/status.rb9
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