-
-
Notifications
You must be signed in to change notification settings - Fork 6.8k
/
20181024224956_migrate_account_conversations.rb
134 lines (103 loc) · 4.32 KB
/
20181024224956_migrate_account_conversations.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# frozen_string_literal: true
require_relative '../../lib/mastodon/migration_warning'
class MigrateAccountConversations < ActiveRecord::Migration[5.2]
include Mastodon::MigrationWarning
disable_ddl_transaction!
class MigrationAccount < ApplicationRecord
self.table_name = :accounts
has_many :mentions, inverse_of: :account, dependent: :destroy, class_name: 'MigrationMention', foreign_key: :account_id
end
class MigrationConversation < ApplicationRecord
self.table_name = :conversations
end
class MigrationStatus < ApplicationRecord
self.table_name = :statuses
belongs_to :account, class_name: 'MigrationAccount'
has_many :mentions, dependent: :destroy, inverse_of: :status, class_name: 'MigrationMention', foreign_key: :status_id
scope :local, -> { where(local: true).or(where(uri: nil)) }
enum visibility: { public: 0, unlisted: 1, private: 2, direct: 3, limited: 4 }, _suffix: :visibility
has_many :active_mentions, -> { active }, class_name: 'MigrationMention', inverse_of: :status, foreign_key: :status_id
end
class MigrationMention < ApplicationRecord
self.table_name = :mentions
belongs_to :account, inverse_of: :mentions, class_name: 'MigrationAccount'
belongs_to :status, -> { unscope(where: :deleted_at) }, class_name: 'MigrationStatus'
scope :active, -> { where(silent: false) }
delegate(
:username,
:acct,
to: :account,
prefix: true
)
end
class MigrationNotification < ApplicationRecord
self.table_name = :notifications
belongs_to :account, optional: true, class_name: 'MigrationAccount'
belongs_to :activity, polymorphic: true, optional: true
belongs_to :status, foreign_key: 'activity_id', optional: true, class_name: 'MigrationStatus'
belongs_to :mention, foreign_key: 'activity_id', optional: true, class_name: 'MigrationMention'
def target_status
mention&.status
end
end
class MigrationAccountConversation < ApplicationRecord
self.table_name = :account_conversations
belongs_to :account, class_name: 'MigrationAccount'
belongs_to :conversation, class_name: 'MigrationConversation'
belongs_to :last_status, -> { unscope(where: :deleted_at) }, class_name: 'MigrationStatus'
before_validation :set_last_status
class << self
def add_status(recipient, status)
conversation = find_or_initialize_by(account: recipient, conversation_id: status.conversation_id, participant_account_ids: participants_from_status(recipient, status))
return conversation if conversation.status_ids.include?(status.id)
conversation.status_ids << status.id
conversation.unread = status.account_id != recipient.id
conversation.save
conversation
rescue ActiveRecord::StaleObjectError
retry
end
private
def participants_from_status(recipient, status)
((status.active_mentions.pluck(:account_id) + [status.account_id]).uniq - [recipient.id]).sort
end
end
private
def set_last_status
self.status_ids = status_ids.sort
self.last_status_id = status_ids.last
end
end
def up
migration_duration_warning
migrated = 0
last_time = Time.zone.now
local_direct_statuses.includes(:account, mentions: :account).find_each do |status|
MigrationAccountConversation.add_status(status.account, status)
migrated += 1
if Time.zone.now - last_time > 1
say_progress(migrated)
last_time = Time.zone.now
end
end
notifications_about_direct_statuses.includes(:account, mention: { status: [:account, { mentions: :account }] }).find_each do |notification|
MigrationAccountConversation.add_status(notification.account, notification.target_status)
migrated += 1
if Time.zone.now - last_time > 1
say_progress(migrated)
last_time = Time.zone.now
end
end
end
def down; end
private
def say_progress(migrated)
say "Migrated #{migrated} rows", true
end
def local_direct_statuses
MigrationStatus.unscoped.local.where(visibility: :direct)
end
def notifications_about_direct_statuses
MigrationNotification.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 })
end
end