mirror of
https://github.com/discourse/discourse.git
synced 2025-02-05 19:11:13 +00:00
1b56a55f50
The previous sidebar default tags and categories implementation did not allow for a user to configure their sidebar to have no categories or tags. This commit changes how the defaults are applied. When a user is being created, we create the SidebarSectionLink records based on the `default_sidebar_categories` and `default_sidebar_tags` site settings. SidebarSectionLink records are only created for categories and tags which the user has visibility on at the point of user creation. With this change, we're also adding the ability for admins to apply changes to the `default_sidebar_categories` and `default_sidebar_tags` site settings historically when changing their site setting. When a new category/tag has been added to the default, the new category/tag will be added to the sidebar for all users if the admin elects to apply the changes historically. Like wise when a tag/category is removed, the tag/category will be removed from the sidebar for all users if the admin elects to apply the changes historically. Internal Ref: /t/73500
94 lines
3.1 KiB
Ruby
94 lines
3.1 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
# A service class that backfills the changes to the default sidebar categories and tags site settings.
|
|
#
|
|
# When a category/tag is removed from the site settings, the `SidebarSectionLink` records associated with the category/tag
|
|
# are deleted.
|
|
#
|
|
# When a category/tag is added to the site settings, a `SidebarSectionLink` record for the associated category/tag are
|
|
# created for all users that do not already have a `SidebarSectionLink` record for the category/tag.
|
|
class SidebarSiteSettingsBackfiller
|
|
def initialize(setting_name, previous_value:, new_value:)
|
|
@setting_name = setting_name
|
|
|
|
@linkable_klass, previous_ids, new_ids =
|
|
case setting_name
|
|
when "default_sidebar_categories"
|
|
[
|
|
Category,
|
|
previous_value.split("|"),
|
|
new_value.split("|")
|
|
]
|
|
when "default_sidebar_tags"
|
|
klass = Tag
|
|
|
|
[
|
|
klass,
|
|
klass.where(name: previous_value.split("|")).pluck(:id),
|
|
klass.where(name: new_value.split("|")).pluck(:id)
|
|
]
|
|
else
|
|
raise 'Invalid setting_name'
|
|
end
|
|
|
|
@added_ids = new_ids - previous_ids
|
|
@removed_ids = previous_ids - new_ids
|
|
end
|
|
|
|
def backfill!
|
|
DistributedMutex.synchronize("backfill_sidebar_site_settings_#{@setting_name}") do
|
|
SidebarSectionLink.where(linkable_type: @linkable_klass.to_s, linkable_id: @removed_ids).delete_all
|
|
|
|
User.real.where(staged: false).select(:id).find_in_batches do |users|
|
|
rows = []
|
|
|
|
users.each do |user|
|
|
@added_ids.each do |linkable_id|
|
|
rows << { user_id: user[:id], linkable_type: @linkable_klass.to_s, linkable_id: linkable_id }
|
|
end
|
|
end
|
|
|
|
SidebarSectionLink.insert_all!(rows) if rows.present?
|
|
end
|
|
end
|
|
end
|
|
|
|
def number_of_users_to_backfill
|
|
select_statements = []
|
|
|
|
if @removed_ids.present?
|
|
select_statements.push(<<~SQL)
|
|
SELECT
|
|
sidebar_section_links.user_id
|
|
FROM sidebar_section_links
|
|
WHERE sidebar_section_links.linkable_type = '#{@linkable_klass.to_s}'
|
|
AND sidebar_section_links.linkable_id IN (#{@removed_ids.join(",")})
|
|
SQL
|
|
end
|
|
|
|
if @added_ids.present?
|
|
# Returns the ids of users that will receive the new additions by excluding the users that already have the additions
|
|
# Note that we want to avoid doing a left outer join against the "sidebar_section_links" table as PG will end up having
|
|
# to do a full table join for both tables first which is less efficient and can be slow on large sites.
|
|
select_statements.push(<<~SQL)
|
|
SELECT
|
|
users.id
|
|
FROM users
|
|
WHERE users.id NOT IN (
|
|
SELECT
|
|
sidebar_section_links.user_id
|
|
FROM sidebar_section_links
|
|
WHERE sidebar_section_links.linkable_type = '#{@linkable_klass.to_s}'
|
|
AND sidebar_section_links.linkable_id IN (#{@added_ids.join(",")})
|
|
) AND users.id > 0 AND NOT users.staged
|
|
SQL
|
|
end
|
|
|
|
DB.query_single(<<~SQL)[0]
|
|
SELECT
|
|
COUNT(*)
|
|
FROM (#{select_statements.join("\nUNION DISTINCT\n")}) AS user_ids
|
|
SQL
|
|
end
|
|
end
|