about summary refs log tree commit diff
path: root/app/models
diff options
context:
space:
mode:
Diffstat (limited to 'app/models')
-rw-r--r--app/models/account.rb18
-rw-r--r--app/models/concerns/domain_normalizable.rb15
-rw-r--r--app/models/domain_block.rb10
-rw-r--r--app/models/email_domain_block.rb8
-rw-r--r--app/models/export.rb38
-rw-r--r--app/models/form/status_batch.rb2
-rw-r--r--app/models/report_note.rb2
-rw-r--r--app/models/user.rb15
8 files changed, 79 insertions, 29 deletions
diff --git a/app/models/account.rb b/app/models/account.rb
index 99fcbf778..67d9a583e 100644
--- a/app/models/account.rb
+++ b/app/models/account.rb
@@ -44,6 +44,7 @@
 #  fields                  :jsonb
 #  actor_type              :string
 #  discoverable            :boolean
+#  also_known_as           :string           is an Array
 #
 
 class Account < ApplicationRecord
@@ -59,6 +60,7 @@ class Account < ApplicationRecord
   include Attachmentable
   include Paginable
   include AccountCounters
+  include DomainNormalizable
 
   MAX_DISPLAY_NAME_LENGTH = (ENV['MAX_DISPLAY_NAME_CHARS'] || 30).to_i
   MAX_NOTE_LENGTH = (ENV['MAX_BIO_CHARS'] || 500).to_i
@@ -87,6 +89,7 @@ class Account < ApplicationRecord
   scope :silenced, -> { where(silenced: true) }
   scope :suspended, -> { where(suspended: true) }
   scope :without_suspended, -> { where(suspended: false) }
+  scope :without_silenced, -> { where(silenced: false) }
   scope :recent, -> { reorder(id: :desc) }
   scope :bots, -> { where(actor_type: %w(Application Service)) }
   scope :alphabetic, -> { order(domain: :asc, username: :asc) }
@@ -94,8 +97,8 @@ class Account < ApplicationRecord
   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}%")) }
-  scope :searchable, -> { where(suspended: false).where(moved_to_account_id: nil) }
-  scope :discoverable, -> { searchable.where(silenced: false).where(discoverable: true).joins(:account_stat).where(AccountStat.arel_table[:followers_count].gteq(MIN_FOLLOWERS_DISCOVERY)).by_recent_status }
+  scope :searchable, -> { without_suspended.where(moved_to_account_id: nil) }
+  scope :discoverable, -> { searchable.without_silenced.where(discoverable: true).joins(:account_stat).where(AccountStat.arel_table[:followers_count].gteq(MIN_FOLLOWERS_DISCOVERY)).by_recent_status }
   scope :tagged_with, ->(tag) { joins(:accounts_tags).where(accounts_tags: { tag_id: tag }) }
   scope :by_recent_status, -> { order(Arel.sql('(case when account_stats.last_status_at is null then 1 else 0 end) asc, account_stats.last_status_at desc')) }
   scope :popular, -> { order('account_stats.followers_count desc') }
@@ -142,6 +145,10 @@ class Account < ApplicationRecord
     "#{username}@#{Rails.configuration.x.local_domain}"
   end
 
+  def local_followers_count
+    Follow.where(target_account_id: id).count
+  end
+
   def to_webfinger_s
     "acct:#{local_username_and_domain}"
   end
@@ -226,6 +233,10 @@ class Account < ApplicationRecord
     end
   end
 
+  def also_known_as
+    self[:also_known_as] || []
+  end
+
   def fields
     (self[:fields] || []).map { |f| Field.new(self, f) }
   end
@@ -459,7 +470,6 @@ class Account < ApplicationRecord
   end
 
   before_create :generate_keys
-  before_validation :normalize_domain
   before_validation :prepare_contents, if: :local?
   before_destroy :clean_feed_manager
 
@@ -497,7 +507,7 @@ class Account < ApplicationRecord
   def normalize_domain
     return if local?
 
-    self.domain = TagManager.instance.normalize_domain(domain)
+    super
   end
 
   def emojifiable_text
diff --git a/app/models/concerns/domain_normalizable.rb b/app/models/concerns/domain_normalizable.rb
new file mode 100644
index 000000000..dff3e5414
--- /dev/null
+++ b/app/models/concerns/domain_normalizable.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module DomainNormalizable
+  extend ActiveSupport::Concern
+
+  included do
+    before_validation :normalize_domain
+  end
+
+  private
+
+  def normalize_domain
+    self.domain = TagManager.instance.normalize_domain(domain)
+  end
+end
diff --git a/app/models/domain_block.rb b/app/models/domain_block.rb
index b828a9d71..1064ea7c8 100644
--- a/app/models/domain_block.rb
+++ b/app/models/domain_block.rb
@@ -13,6 +13,8 @@
 #
 
 class DomainBlock < ApplicationRecord
+  include DomainNormalizable
+
   enum severity: [:silence, :suspend, :noop]
 
   attr_accessor :retroactive
@@ -25,12 +27,4 @@ class DomainBlock < ApplicationRecord
   def self.blocked?(domain)
     where(domain: domain, severity: :suspend).exists?
   end
-
-  before_validation :normalize_domain
-
-  private
-
-  def normalize_domain
-    self.domain = TagManager.instance.normalize_domain(domain)
-  end
 end
diff --git a/app/models/email_domain_block.rb b/app/models/email_domain_block.rb
index 10490375b..0fcd36477 100644
--- a/app/models/email_domain_block.rb
+++ b/app/models/email_domain_block.rb
@@ -10,7 +10,7 @@
 #
 
 class EmailDomainBlock < ApplicationRecord
-  before_validation :normalize_domain
+  include DomainNormalizable
 
   validates :domain, presence: true, uniqueness: true
 
@@ -27,10 +27,4 @@ class EmailDomainBlock < ApplicationRecord
 
     where(domain: domain).exists?
   end
-
-  private
-
-  def normalize_domain
-    self.domain = TagManager.instance.normalize_domain(domain)
-  end
 end
diff --git a/app/models/export.rb b/app/models/export.rb
index 0eeac0dc0..a2520e9c2 100644
--- a/app/models/export.rb
+++ b/app/models/export.rb
@@ -9,15 +9,33 @@ class Export
   end
 
   def to_blocked_accounts_csv
-    to_csv account.blocking
+    to_csv account.blocking.select(:username, :domain)
   end
 
   def to_muted_accounts_csv
-    to_csv account.muting
+    to_csv account.muting.select(:username, :domain)
   end
 
   def to_following_accounts_csv
-    to_csv account.following
+    to_csv account.following.select(:username, :domain)
+  end
+
+  def to_lists_csv
+    CSV.generate do |csv|
+      account.owned_lists.select(:title).each do |list|
+        list.accounts.select(:username, :domain).each do |account|
+          csv << [list.title, acct(account)]
+        end
+      end
+    end
+  end
+
+  def to_blocked_domains_csv
+    CSV.generate do |csv|
+      account.domain_blocks.pluck(:domain).each do |domain|
+        csv << [domain]
+      end
+    end
   end
 
   def total_storage
@@ -32,6 +50,10 @@ class Export
     account.following_count
   end
 
+  def total_lists
+    account.owned_lists.count
+  end
+
   def total_followers
     account.followers_count
   end
@@ -44,13 +66,21 @@ class Export
     account.muting.count
   end
 
+  def total_domain_blocks
+    account.domain_blocks.count
+  end
+
   private
 
   def to_csv(accounts)
     CSV.generate do |csv|
       accounts.each do |account|
-        csv << [(account.local? ? account.local_username_and_domain : account.acct)]
+        csv << [acct(account)]
       end
     end
   end
+
+  def acct(account)
+    account.local? ? account.local_username_and_domain : account.acct
+  end
 end
diff --git a/app/models/form/status_batch.rb b/app/models/form/status_batch.rb
index 8f5fd1fa2..898728067 100644
--- a/app/models/form/status_batch.rb
+++ b/app/models/form/status_batch.rb
@@ -6,8 +6,6 @@ class Form::StatusBatch
 
   attr_accessor :status_ids, :action, :current_account
 
-  ACTION_TYPE = %w(nsfw_on nsfw_off delete).freeze
-
   def save
     case action
     when 'nsfw_on', 'nsfw_off'
diff --git a/app/models/report_note.rb b/app/models/report_note.rb
index 54b416577..6d7167e0e 100644
--- a/app/models/report_note.rb
+++ b/app/models/report_note.rb
@@ -15,7 +15,7 @@ class ReportNote < ApplicationRecord
   belongs_to :account
   belongs_to :report, inverse_of: :notes, touch: true
 
-  scope :latest, -> { reorder('created_at ASC') }
+  scope :latest, -> { reorder(created_at: :desc) }
 
   validates :content, presence: true, length: { maximum: 500 }
 end
diff --git a/app/models/user.rb b/app/models/user.rb
index a6c25342a..83ccce948 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -36,6 +36,7 @@
 #  invite_id                 :bigint(8)
 #  remember_token            :string
 #  chosen_languages          :string           is an Array
+#  created_by_application_id :bigint(8)
 #
 
 class User < ApplicationRecord
@@ -49,7 +50,7 @@ class User < ApplicationRecord
   # every day. Raising the duration reduces the amount of expensive
   # RegenerationWorker jobs that need to be run when those people come
   # to check their feed
-  ACTIVE_DURATION = ENV.fetch('USER_ACTIVE_DAYS', 7).to_i.days
+  ACTIVE_DURATION = ENV.fetch('USER_ACTIVE_DAYS', 7).to_i.days.freeze
 
   devise :two_factor_authenticatable,
          otp_secret_encryption_key: Rails.configuration.x.otp_secret
@@ -66,6 +67,7 @@ class User < ApplicationRecord
 
   belongs_to :account, inverse_of: :user
   belongs_to :invite, counter_cache: :uses, optional: true
+  belongs_to :created_by_application, class_name: 'Doorkeeper::Application', optional: true
   accepts_nested_attributes_for :account
 
   has_many :applications, class_name: 'Doorkeeper::Application', as: :owner
@@ -74,15 +76,18 @@ class User < ApplicationRecord
   validates :locale, inclusion: I18n.available_locales.map(&:to_s), if: :locale?
   validates_with BlacklistedEmailValidator, if: :email_changed?
   validates_with EmailMxValidator, if: :validate_email_dns?
+  validates :agreement, acceptance: { allow_nil: false, accept: [true, 'true', '1'] }, on: :create
 
   scope :recent, -> { order(id: :desc) }
   scope :admins, -> { where(admin: true) }
   scope :moderators, -> { where(moderator: true) }
   scope :staff, -> { admins.or(moderators) }
   scope :confirmed, -> { where.not(confirmed_at: nil) }
+  scope :enabled, -> { where(disabled: false) }
   scope :inactive, -> { where(arel_table[:current_sign_in_at].lt(ACTIVE_DURATION.ago)) }
   scope :active, -> { confirmed.where(arel_table[:current_sign_in_at].gteq(ACTIVE_DURATION.ago)).joins(:account).where(accounts: { suspended: false }) }
   scope :matches_email, ->(value) { where(arel_table[:email].matches("#{value}%")) }
+  scope :emailable, -> { confirmed.enabled.joins(:account).merge(Account.searchable) }
 
   before_validation :sanitize_languages
 
@@ -136,6 +141,10 @@ class User < ApplicationRecord
     confirmed_at.present?
   end
 
+  def invited?
+    invite_id.present?
+  end
+
   def staff?
     admin? || moderator?
   end
@@ -294,7 +303,7 @@ class User < ApplicationRecord
       end
 
     if resource.blank?
-      resource = new(email: attributes[:email])
+      resource = new(email: attributes[:email], agreement: true)
       if Devise.check_at_sign && !resource[:email].index('@')
         resource[:email] = Rpam2.getenv(resource.find_pam_service, attributes[:email], attributes[:password], 'email', false)
         resource[:email] = "#{attributes[:email]}@#{resource.find_pam_suffix}" unless resource[:email]
@@ -307,7 +316,7 @@ class User < ApplicationRecord
     resource = joins(:account).find_by(accounts: { username: attributes[Devise.ldap_uid.to_sym].first })
 
     if resource.blank?
-      resource = new(email: attributes[:mail].first, account_attributes: { username: attributes[Devise.ldap_uid.to_sym].first })
+      resource = new(email: attributes[:mail].first, agreement: true, account_attributes: { username: attributes[Devise.ldap_uid.to_sym].first })
       resource.ldap_setup(attributes)
     end