20181024224956_migrate_account_conversations.rb 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. # frozen_string_literal: true
  2. require_relative '../../lib/mastodon/migration_warning'
  3. class MigrateAccountConversations < ActiveRecord::Migration[5.2]
  4. include Mastodon::MigrationWarning
  5. disable_ddl_transaction!
  6. class Mention < ApplicationRecord
  7. belongs_to :account, inverse_of: :mentions
  8. belongs_to :status, -> { unscope(where: :deleted_at) }
  9. delegate(
  10. :username,
  11. :acct,
  12. to: :account,
  13. prefix: true
  14. )
  15. end
  16. class Notification < ApplicationRecord
  17. belongs_to :account, optional: true
  18. belongs_to :activity, polymorphic: true, optional: true
  19. belongs_to :status, foreign_key: 'activity_id', optional: true
  20. belongs_to :mention, foreign_key: 'activity_id', optional: true
  21. def target_status
  22. mention&.status
  23. end
  24. end
  25. class AccountConversation < ApplicationRecord
  26. belongs_to :account
  27. belongs_to :conversation
  28. belongs_to :last_status, -> { unscope(where: :deleted_at) }, class_name: 'Status'
  29. before_validation :set_last_status
  30. class << self
  31. def add_status(recipient, status)
  32. conversation = find_or_initialize_by(account: recipient, conversation_id: status.conversation_id, participant_account_ids: participants_from_status(recipient, status))
  33. return conversation if conversation.status_ids.include?(status.id)
  34. conversation.status_ids << status.id
  35. conversation.unread = status.account_id != recipient.id
  36. conversation.save
  37. conversation
  38. rescue ActiveRecord::StaleObjectError
  39. retry
  40. end
  41. private
  42. def participants_from_status(recipient, status)
  43. ((status.active_mentions.pluck(:account_id) + [status.account_id]).uniq - [recipient.id]).sort
  44. end
  45. end
  46. private
  47. def set_last_status
  48. self.status_ids = status_ids.sort
  49. self.last_status_id = status_ids.last
  50. end
  51. end
  52. def up
  53. migration_duration_warning
  54. migrated = 0
  55. last_time = Time.zone.now
  56. local_direct_statuses.includes(:account, mentions: :account).find_each do |status|
  57. AccountConversation.add_status(status.account, status)
  58. migrated += 1
  59. if Time.zone.now - last_time > 1
  60. say_progress(migrated)
  61. last_time = Time.zone.now
  62. end
  63. end
  64. notifications_about_direct_statuses.includes(:account, mention: { status: [:account, mentions: :account] }).find_each do |notification|
  65. AccountConversation.add_status(notification.account, notification.target_status)
  66. migrated += 1
  67. if Time.zone.now - last_time > 1
  68. say_progress(migrated)
  69. last_time = Time.zone.now
  70. end
  71. end
  72. end
  73. def down; end
  74. private
  75. def say_progress(migrated)
  76. say "Migrated #{migrated} rows", true
  77. end
  78. def local_direct_statuses
  79. Status.unscoped.local.where(visibility: :direct)
  80. end
  81. def notifications_about_direct_statuses
  82. Notification.joins('INNER JOIN mentions ON mentions.id = notifications.activity_id INNER JOIN statuses ON statuses.id = mentions.status_id').where(activity_type: 'Mention', statuses: { visibility: :direct })
  83. end
  84. end