I’ve since then (clearly took a while!) worked out two ways to achieve this. You can do it via the UI, which works well for small Categories (and small groups). It takes a bit of care to avoid firing off unhelpful notifications while you do so, but is very doable.
Alternatively, you can use the Rails Console (assuming you are self-hosted), which is faster and much more powerful.
From the UI
- Remove the other group members from the Group (but keep a list of usernames / emails so you can re-add them easily). This will avoid them being notified.
- Cycle through each topic in the Category, converting each one into a PM using the admin spanner menu
- I find this easiest to do by opening each topic in its own tab, and then moving across them one by one
- Add the Group to each of the Topics (now PMs)
- Add the Group members back into the group
- Tidy up / delete all the ‘small posts’ in each Group Message as desired
In the Rails Console
Access the console by entering the container and then calling up the console:
./launcher enter app
rails c
Set the Category and Group, and then copy the script below into the console:
category_id = =CategoryID=
group_name = '=GroupName='
group = Group.find_by('lower(name) = ?', group_name.downcase)
about_id = Category.find(category_id).topic_id
topic_ids = Topic.where(category_id: category_id).where.not(id: about_id).pluck(:id)
Topic.where(id: topic_ids).find_each do |topic|
topic.archetype = Archetype.private_message
topic.category_id = nil
topic.subtype = 'user_to_user'
topic.save!
TopicAllowedGroup.find_or_create_by!(topic_id: topic.id, group_id: group.id)
Post.where(topic_id: topic.id).pluck(:user_id).uniq.each do |uid|
TopicAllowedUser.find_or_create_by!(topic_id: topic.id, user_id: uid)
end
end
This doesn’t notify the users at all, and preserves the users participating in the posts nicely (just in case they aren’t in the Group).
Of note, you might need to run this subsequently in the Rails Console if you want to delete the Category before the background job recounts everything:
Jobs::CategoryStats.new.execute(category_id: category_id)
Script for the reverse (Group Inbox to Category), click to reveal
This script should send things back in the other direction nicely (untested)
category_id = =CategoryID=
group_name = '=GroupName='
group = Group.find_by('LOWER(name) = ?', group_name.downcase)
raise "Group not found" unless group
topic_ids = TopicAllowedGroup.where(group_id: group.id).pluck(:topic_id)
topics = Topic.where(id: topic_ids, archetype: Archetype.private_message, deleted_at: nil)
topics.find_each do |topic|
topic.archetype = Archetype.default # or "regular"
topic.subtype = nil
topic.category_id = target_category_id
topic.save!
end