canvas-lms/lib/data_fixup/populate_conversation_root_...

126 lines
5.1 KiB
Ruby

module DataFixup::PopulateConversationRootAccountIds
def self.run
conn = Conversation.connection
adapter_name = conn.adapter_name.downcase
cmocs = []
# we'll be populating root_account_ids from ConversationMessage#context_id,
# since that already tracks the root account id. but there are some
# exceptions where it's currently null, so we need to fix them first...
Conversation.transaction do
# old context messages (before conversations)
temp_table_options = adapter_name =~ /mysql/ ? 'engine=innodb' : 'AS'
root_account_id_default = adapter_name =~ /postgres/ ? "CAST(0 AS BIGINT)" : "0"
conn.execute <<-SQL
CREATE TEMPORARY TABLE _conversation_message_old_contexts #{temp_table_options}
SELECT m.id AS conversation_message_id, cm.context_type, cm.context_id, #{root_account_id_default} AS root_account_id
FROM conversation_messages m, context_messages cm
WHERE m.context_message_id IS NOT NULL AND m.context_message_id = cm.id AND m.context_id IS NULL
SQL
conn.add_index :_conversation_message_old_contexts, :conversation_message_id, :name => '_cmoc_cmid_index'
conn.execute "ANALYZE _conversation_message_old_contexts" if adapter_name =~ /postgres/
conn.execute <<-SQL
UPDATE _conversation_message_old_contexts
SET root_account_id = (
SELECT root_account_id
FROM courses
WHERE id = _conversation_message_old_contexts.context_id
)
WHERE context_type = 'Course'
SQL
conn.execute <<-SQL
UPDATE _conversation_message_old_contexts
SET root_account_id = (
SELECT root_account_id
FROM groups
WHERE groups.id = _conversation_message_old_contexts.context_id
)
WHERE context_type = 'Group'
SQL
cmocs = conn.select_all("SELECT conversation_message_id, root_account_id FROM _conversation_message_old_contexts WHERE root_account_id IS NOT NULL ORDER BY conversation_message_id")
conn.execute "DROP TABLE _conversation_message_old_contexts"
end
cmocs.each_slice(1000) do |rows|
conn.execute <<-SQL
UPDATE conversation_messages
SET context_type = 'Account',
context_id = CASE id #{rows.map{ |r| "WHEN #{r['conversation_message_id']} THEN #{r['root_account_id']} "}.join} END
WHERE
id IN (#{rows.map{ |r| r['conversation_message_id'] }.join(', ')})
SQL
end
# submission comments
cmscs = conn.select_all("SELECT id FROM conversation_messages WHERE context_id IS NULL AND asset_id IS NOT NULL AND asset_type = 'Submission' ORDER BY id")
cmscs.map{ |r| r['id'] }.each_slice(1000) do |ids|
conn.execute <<-SQL
UPDATE conversation_messages
SET context_type = 'Account',
context_id = (
SELECT root_account_id
FROM submissions s, assignments a, courses c
WHERE s.id = asset_id AND a.id = assignment_id
AND a.context_type = 'Course' AND a.context_id = c.id
)
WHERE
id IN (#{ids.join(', ')})
SQL
end
# in case there was any garbage data (like an assignment w/o a course, or a context message that couldn't link back to an account)
conn.execute "UPDATE conversation_messages SET context_type = NULL WHERE context_type IS NOT NULL AND context_id IS NULL"
convos = conn.select_all("SELECT id FROM conversations ORDER BY id")
convos.map{ |r| r['id'] }.each_slice(1000) do |ids|
case adapter_name
when /mysql/
conn.execute <<-SQL
UPDATE conversations
SET root_account_ids = (
SELECT GROUP_CONCAT(DISTINCT context_id ORDER BY context_id SEPARATOR ',')
FROM conversation_messages
WHERE conversation_id = conversations.id
AND context_id IS NOT NULL
)
WHERE id IN (#{ids.join(', ')})
SQL
when /postgres/
conn.execute <<-SQL
UPDATE conversations
SET root_account_ids = (
SELECT STRING_AGG(context_id::TEXT, ',' ORDER BY context_id)
FROM (
SELECT DISTINCT context_id FROM conversation_messages
WHERE conversation_id = conversations.id
AND context_id IS NOT NULL
) ids
)
WHERE id IN (#{ids.join(', ')})
SQL
else
conn.execute <<-SQL
UPDATE conversations
SET root_account_ids = (
SELECT GROUP_CONCAT(DISTINCT context_id)
FROM conversation_messages
WHERE conversation_id = conversations.id
AND context_id IS NOT NULL
)
WHERE id IN (#{ids.join(', ')})
SQL
# any w/ multiple accounts will have to be reordered in ruby
Conversation.where(Conversation.wildcard(:root_account_ids, ',')).find_each do |c|
c.root_account_ids = c.root_account_ids # does a reorder
c.save if c.root_account_ids_changed?
end
end
end
end
end