account.rb 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  1. # frozen_string_literal: true
  2. # == Schema Information
  3. #
  4. # Table name: accounts
  5. #
  6. # id :bigint(8) not null, primary key
  7. # username :string default(""), not null
  8. # domain :string
  9. # private_key :text
  10. # public_key :text default(""), not null
  11. # created_at :datetime not null
  12. # updated_at :datetime not null
  13. # note :text default(""), not null
  14. # display_name :string default(""), not null
  15. # uri :string default(""), not null
  16. # url :string
  17. # avatar_file_name :string
  18. # avatar_content_type :string
  19. # avatar_file_size :integer
  20. # avatar_updated_at :datetime
  21. # header_file_name :string
  22. # header_content_type :string
  23. # header_file_size :integer
  24. # header_updated_at :datetime
  25. # avatar_remote_url :string
  26. # locked :boolean default(FALSE), not null
  27. # header_remote_url :string default(""), not null
  28. # last_webfingered_at :datetime
  29. # inbox_url :string default(""), not null
  30. # outbox_url :string default(""), not null
  31. # shared_inbox_url :string default(""), not null
  32. # followers_url :string default(""), not null
  33. # protocol :integer default("ostatus"), not null
  34. # memorial :boolean default(FALSE), not null
  35. # moved_to_account_id :bigint(8)
  36. # featured_collection_url :string
  37. # fields :jsonb
  38. # actor_type :string
  39. # discoverable :boolean
  40. # also_known_as :string is an Array
  41. # silenced_at :datetime
  42. # suspended_at :datetime
  43. # hide_collections :boolean
  44. # avatar_storage_schema_version :integer
  45. # header_storage_schema_version :integer
  46. # devices_url :string
  47. # suspension_origin :integer
  48. # sensitized_at :datetime
  49. # trendable :boolean
  50. # reviewed_at :datetime
  51. # requested_review_at :datetime
  52. # indexable :boolean default(FALSE), not null
  53. #
  54. class Account < ApplicationRecord
  55. self.ignored_columns += %w(
  56. subscription_expires_at
  57. secret
  58. remote_url
  59. salmon_url
  60. hub_url
  61. trust_level
  62. )
  63. BACKGROUND_REFRESH_INTERVAL = 1.week.freeze
  64. USERNAME_RE = /[a-z0-9_]+([a-z0-9_.-]+[a-z0-9_]+)?/i
  65. MENTION_RE = %r{(?<![=/[:word:]])@((#{USERNAME_RE})(?:@[[:word:].-]+[[:word:]]+)?)}i
  66. URL_PREFIX_RE = %r{\Ahttp(s?)://[^/]+}
  67. USERNAME_ONLY_RE = /\A#{USERNAME_RE}\z/i
  68. include Attachmentable # Load prior to Avatar & Header concerns
  69. include Account::Associations
  70. include Account::Avatar
  71. include Account::Counters
  72. include Account::FinderConcern
  73. include Account::Header
  74. include Account::Interactions
  75. include Account::Merging
  76. include Account::Search
  77. include Account::StatusesSearch
  78. include DomainMaterializable
  79. include DomainNormalizable
  80. include Paginable
  81. enum protocol: { ostatus: 0, activitypub: 1 }
  82. enum suspension_origin: { local: 0, remote: 1 }, _prefix: true
  83. validates :username, presence: true
  84. validates_with UniqueUsernameValidator, if: -> { will_save_change_to_username? }
  85. # Remote user validations, also applies to internal actors
  86. validates :username, format: { with: USERNAME_ONLY_RE }, if: -> { (!local? || actor_type == 'Application') && will_save_change_to_username? }
  87. # Remote user validations
  88. validates :uri, presence: true, unless: :local?, on: :create
  89. # Local user validations
  90. validates :username, format: { with: /\A[a-z0-9_]+\z/i }, length: { maximum: 30 }, if: -> { local? && will_save_change_to_username? && actor_type != 'Application' }
  91. validates_with UnreservedUsernameValidator, if: -> { local? && will_save_change_to_username? && actor_type != 'Application' }
  92. validates :display_name, length: { maximum: 30 }, if: -> { local? && will_save_change_to_display_name? }
  93. validates :note, note_length: { maximum: 500 }, if: -> { local? && will_save_change_to_note? }
  94. validates :fields, length: { maximum: 4 }, if: -> { local? && will_save_change_to_fields? }
  95. validates :uri, absence: true, if: :local?, on: :create
  96. validates :inbox_url, absence: true, if: :local?, on: :create
  97. validates :shared_inbox_url, absence: true, if: :local?, on: :create
  98. validates :followers_url, absence: true, if: :local?, on: :create
  99. scope :remote, -> { where.not(domain: nil) }
  100. scope :local, -> { where(domain: nil) }
  101. scope :partitioned, -> { order(Arel.sql('row_number() over (partition by domain)')) }
  102. scope :silenced, -> { where.not(silenced_at: nil) }
  103. scope :suspended, -> { where.not(suspended_at: nil) }
  104. scope :sensitized, -> { where.not(sensitized_at: nil) }
  105. scope :without_suspended, -> { where(suspended_at: nil) }
  106. scope :without_silenced, -> { where(silenced_at: nil) }
  107. scope :without_instance_actor, -> { where.not(id: -99) }
  108. scope :recent, -> { reorder(id: :desc) }
  109. scope :bots, -> { where(actor_type: %w(Application Service)) }
  110. scope :groups, -> { where(actor_type: 'Group') }
  111. scope :alphabetic, -> { order(domain: :asc, username: :asc) }
  112. scope :matches_username, ->(value) { where('lower((username)::text) LIKE lower(?)', "#{value}%") }
  113. scope :matches_display_name, ->(value) { where(arel_table[:display_name].matches("#{value}%")) }
  114. scope :matches_domain, ->(value) { where(arel_table[:domain].matches("%#{value}%")) }
  115. scope :without_unapproved, -> { left_outer_joins(:user).merge(User.approved.confirmed).or(remote) }
  116. scope :searchable, -> { without_unapproved.without_suspended.where(moved_to_account_id: nil) }
  117. scope :discoverable, -> { searchable.without_silenced.where(discoverable: true).joins(:account_stat) }
  118. scope :followable_by, ->(account) { joins(arel_table.join(Follow.arel_table, Arel::Nodes::OuterJoin).on(arel_table[:id].eq(Follow.arel_table[:target_account_id]).and(Follow.arel_table[:account_id].eq(account.id))).join_sources).where(Follow.arel_table[:id].eq(nil)).joins(arel_table.join(FollowRequest.arel_table, Arel::Nodes::OuterJoin).on(arel_table[:id].eq(FollowRequest.arel_table[:target_account_id]).and(FollowRequest.arel_table[:account_id].eq(account.id))).join_sources).where(FollowRequest.arel_table[:id].eq(nil)) }
  119. scope :by_recent_status, -> { includes(:account_stat).merge(AccountStat.order('last_status_at DESC NULLS LAST')).references(:account_stat) }
  120. scope :by_recent_sign_in, -> { order(Arel.sql('users.current_sign_in_at DESC NULLS LAST')) }
  121. scope :popular, -> { order('account_stats.followers_count desc') }
  122. scope :by_domain_and_subdomains, ->(domain) { where(domain: Instance.by_domain_and_subdomains(domain).select(:domain)) }
  123. scope :not_excluded_by_account, ->(account) { where.not(id: account.excluded_from_timeline_account_ids) }
  124. scope :not_domain_blocked_by_account, ->(account) { where(arel_table[:domain].eq(nil).or(arel_table[:domain].not_in(account.excluded_from_timeline_domains))) }
  125. after_update_commit :trigger_update_webhooks
  126. delegate :email,
  127. :unconfirmed_email,
  128. :current_sign_in_at,
  129. :created_at,
  130. :sign_up_ip,
  131. :confirmed?,
  132. :approved?,
  133. :pending?,
  134. :disabled?,
  135. :unconfirmed?,
  136. :unconfirmed_or_pending?,
  137. :role,
  138. :locale,
  139. :shows_application?,
  140. :prefers_noindex?,
  141. :time_zone,
  142. to: :user,
  143. prefix: true,
  144. allow_nil: true
  145. delegate :chosen_languages, to: :user, prefix: false, allow_nil: true
  146. update_index('accounts', :self)
  147. def local?
  148. domain.nil?
  149. end
  150. def moved?
  151. moved_to_account_id.present?
  152. end
  153. def bot?
  154. %w(Application Service).include? actor_type
  155. end
  156. def instance_actor?
  157. id == -99
  158. end
  159. alias bot bot?
  160. def bot=(val)
  161. self.actor_type = ActiveModel::Type::Boolean.new.cast(val) ? 'Service' : 'Person'
  162. end
  163. def group?
  164. actor_type == 'Group'
  165. end
  166. alias group group?
  167. def acct
  168. local? ? username : "#{username}@#{domain}"
  169. end
  170. def pretty_acct
  171. local? ? username : "#{username}@#{Addressable::IDNA.to_unicode(domain)}"
  172. end
  173. def local_username_and_domain
  174. "#{username}@#{Rails.configuration.x.local_domain}"
  175. end
  176. def local_followers_count
  177. Follow.where(target_account_id: id).count
  178. end
  179. def to_webfinger_s
  180. "acct:#{local_username_and_domain}"
  181. end
  182. def possibly_stale?
  183. last_webfingered_at.nil? || last_webfingered_at <= 1.day.ago
  184. end
  185. def schedule_refresh_if_stale!
  186. return unless last_webfingered_at.present? && last_webfingered_at <= BACKGROUND_REFRESH_INTERVAL.ago
  187. AccountRefreshWorker.perform_in(rand(6.hours.to_i), id)
  188. end
  189. def refresh!
  190. ResolveAccountService.new.call(acct) unless local?
  191. end
  192. def silenced?
  193. silenced_at.present?
  194. end
  195. def silence!(date = Time.now.utc)
  196. update!(silenced_at: date)
  197. end
  198. def unsilence!
  199. update!(silenced_at: nil)
  200. end
  201. def suspended?
  202. suspended_at.present? && !instance_actor?
  203. end
  204. def suspended_permanently?
  205. suspended? && deletion_request.nil?
  206. end
  207. def suspended_temporarily?
  208. suspended? && deletion_request.present?
  209. end
  210. alias unavailable? suspended?
  211. alias permanently_unavailable? suspended_permanently?
  212. def suspend!(date: Time.now.utc, origin: :local, block_email: true)
  213. transaction do
  214. create_deletion_request!
  215. update!(suspended_at: date, suspension_origin: origin)
  216. create_canonical_email_block! if block_email
  217. end
  218. end
  219. def unsuspend!
  220. transaction do
  221. deletion_request&.destroy!
  222. update!(suspended_at: nil, suspension_origin: nil)
  223. destroy_canonical_email_block!
  224. end
  225. end
  226. def sensitized?
  227. sensitized_at.present?
  228. end
  229. def sensitize!(date = Time.now.utc)
  230. update!(sensitized_at: date)
  231. end
  232. def unsensitize!
  233. update!(sensitized_at: nil)
  234. end
  235. def memorialize!
  236. update!(memorial: true)
  237. end
  238. def trendable?
  239. boolean_with_default('trendable', Setting.trendable_by_default)
  240. end
  241. def sign?
  242. true
  243. end
  244. def previous_strikes_count
  245. strikes.where(overruled_at: nil).count
  246. end
  247. def keypair
  248. @keypair ||= OpenSSL::PKey::RSA.new(private_key || public_key)
  249. end
  250. def tags_as_strings=(tag_names)
  251. hashtags_map = Tag.find_or_create_by_names(tag_names).index_by(&:name)
  252. # Remove hashtags that are to be deleted
  253. tags.each do |tag|
  254. if hashtags_map.key?(tag.name)
  255. hashtags_map.delete(tag.name)
  256. else
  257. tags.delete(tag)
  258. end
  259. end
  260. # Add hashtags that were so far missing
  261. hashtags_map.each_value do |tag|
  262. tags << tag
  263. end
  264. end
  265. def also_known_as
  266. self[:also_known_as] || []
  267. end
  268. def fields
  269. (self[:fields] || []).filter_map do |f|
  270. Account::Field.new(self, f)
  271. rescue
  272. nil
  273. end
  274. end
  275. def fields_attributes=(attributes)
  276. fields = []
  277. old_fields = self[:fields] || []
  278. old_fields = [] if old_fields.is_a?(Hash)
  279. if attributes.is_a?(Hash)
  280. attributes.each_value do |attr|
  281. next if attr[:name].blank?
  282. previous = old_fields.find { |item| item['value'] == attr[:value] }
  283. attr[:verified_at] = previous['verified_at'] if previous && previous['verified_at'].present?
  284. fields << attr
  285. end
  286. end
  287. self[:fields] = fields
  288. end
  289. DEFAULT_FIELDS_SIZE = 4
  290. def build_fields
  291. return if fields.size >= DEFAULT_FIELDS_SIZE
  292. tmp = self[:fields] || []
  293. tmp = [] if tmp.is_a?(Hash)
  294. (DEFAULT_FIELDS_SIZE - tmp.size).times do
  295. tmp << { name: '', value: '' }
  296. end
  297. self.fields = tmp
  298. end
  299. def save_with_optional_media!
  300. save!
  301. rescue ActiveRecord::RecordInvalid => e
  302. errors = e.record.errors.errors
  303. errors.each do |err|
  304. if err.attribute == :avatar
  305. self.avatar = nil
  306. elsif err.attribute == :header
  307. self.header = nil
  308. end
  309. end
  310. save!
  311. end
  312. def hides_followers?
  313. hide_collections?
  314. end
  315. def hides_following?
  316. hide_collections?
  317. end
  318. def object_type
  319. :person
  320. end
  321. def to_param
  322. username
  323. end
  324. def to_log_human_identifier
  325. acct
  326. end
  327. def excluded_from_timeline_account_ids
  328. Rails.cache.fetch("exclude_account_ids_for:#{id}") { block_relationships.pluck(:target_account_id) + blocked_by_relationships.pluck(:account_id) + mute_relationships.pluck(:target_account_id) }
  329. end
  330. def excluded_from_timeline_domains
  331. Rails.cache.fetch("exclude_domains_for:#{id}") { domain_blocks.pluck(:domain) }
  332. end
  333. def preferred_inbox_url
  334. shared_inbox_url.presence || inbox_url
  335. end
  336. def synchronization_uri_prefix
  337. return 'local' if local?
  338. @synchronization_uri_prefix ||= "#{uri[URL_PREFIX_RE]}/"
  339. end
  340. def requires_review?
  341. reviewed_at.nil?
  342. end
  343. def reviewed?
  344. reviewed_at.present?
  345. end
  346. def requested_review?
  347. requested_review_at.present?
  348. end
  349. def requires_review_notification?
  350. requires_review? && !requested_review?
  351. end
  352. class << self
  353. def readonly_attributes
  354. super - %w(statuses_count following_count followers_count)
  355. end
  356. def inboxes
  357. urls = reorder(nil).where(protocol: :activitypub).group(:preferred_inbox_url).pluck(Arel.sql("coalesce(nullif(accounts.shared_inbox_url, ''), accounts.inbox_url) AS preferred_inbox_url"))
  358. DeliveryFailureTracker.without_unavailable(urls)
  359. end
  360. def from_text(text)
  361. return [] if text.blank?
  362. text.scan(MENTION_RE).map { |match| match.first.split('@', 2) }.uniq.filter_map do |(username, domain)|
  363. domain = if TagManager.instance.local_domain?(domain)
  364. nil
  365. else
  366. TagManager.instance.normalize_domain(domain)
  367. end
  368. EntityCache.instance.mention(username, domain)
  369. end
  370. end
  371. def inverse_alias(key, original_key)
  372. define_method(:"#{key}=") do |value|
  373. public_send(:"#{original_key}=", !ActiveModel::Type::Boolean.new.cast(value))
  374. end
  375. define_method(key) do
  376. !public_send(original_key)
  377. end
  378. end
  379. end
  380. inverse_alias :show_collections, :hide_collections
  381. inverse_alias :unlocked, :locked
  382. def emojis
  383. @emojis ||= CustomEmoji.from_text(emojifiable_text, domain)
  384. end
  385. before_validation :prepare_contents, if: :local?
  386. before_validation :prepare_username, on: :create
  387. before_create :generate_keys
  388. before_destroy :clean_feed_manager
  389. def ensure_keys!
  390. return unless local? && private_key.blank? && public_key.blank?
  391. generate_keys
  392. save!
  393. end
  394. private
  395. def prepare_contents
  396. display_name&.strip!
  397. note&.strip!
  398. end
  399. def prepare_username
  400. username&.squish!
  401. end
  402. def generate_keys
  403. return unless local? && private_key.blank? && public_key.blank?
  404. keypair = OpenSSL::PKey::RSA.new(2048)
  405. self.private_key = keypair.to_pem
  406. self.public_key = keypair.public_key.to_pem
  407. end
  408. def normalize_domain
  409. return if local?
  410. super
  411. end
  412. def emojifiable_text
  413. [note, display_name, fields.map(&:name), fields.map(&:value)].join(' ')
  414. end
  415. def clean_feed_manager
  416. FeedManager.instance.clean_feeds!(:home, [id])
  417. end
  418. def create_canonical_email_block!
  419. return unless local? && user_email.present?
  420. begin
  421. CanonicalEmailBlock.create(reference_account: self, email: user_email)
  422. rescue ActiveRecord::RecordNotUnique
  423. # A canonical e-mail block may already exist for the same e-mail
  424. end
  425. end
  426. def destroy_canonical_email_block!
  427. return unless local?
  428. CanonicalEmailBlock.where(reference_account: self).delete_all
  429. end
  430. # NOTE: the `account.created` webhook is triggered by the `User` model, not `Account`.
  431. def trigger_update_webhooks
  432. TriggerWebhookWorker.perform_async('account.updated', 'Account', id) if local?
  433. end
  434. end