mirror of
https://github.com/discourse/discourse.git
synced 2025-05-23 19:54:14 +08:00
FEATURE: Create legal topics for set company name (#21620)
Legal topics, such as the Terms of Service and Privacy Policy topics do not make sense if the entity creating the community is not a company. These topics will be created and updated only when the company name is present and deleted when it is not.
This commit is contained in:
@ -18,12 +18,16 @@
|
|||||||
"faq"
|
"faq"
|
||||||
}}</LinkTo></li>
|
}}</LinkTo></li>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
{{#if (gt this.siteSettings.tos_topic_id 0)}}
|
||||||
<li class="nav-item-tos"><LinkTo @route="tos">{{i18n
|
<li class="nav-item-tos"><LinkTo @route="tos">{{i18n
|
||||||
"tos"
|
"tos"
|
||||||
}}</LinkTo></li>
|
}}</LinkTo></li>
|
||||||
|
{{/if}}
|
||||||
|
{{#if (gt this.siteSettings.privacy_topic_id 0)}}
|
||||||
<li class="nav-item-privacy"><LinkTo @route="privacy">{{i18n
|
<li class="nav-item-privacy"><LinkTo @route="privacy">{{i18n
|
||||||
"privacy"
|
"privacy"
|
||||||
}}</LinkTo></li>
|
}}</LinkTo></li>
|
||||||
|
{{/if}}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<section class="about description">
|
<section class="about description">
|
||||||
|
@ -10,8 +10,12 @@
|
|||||||
<li class='nav-item-faq'><a class='<%= @page == 'faq' ? 'active' : '' %>' href='<%=faq_path%>'><%= t 'js.faq' %></a></li>
|
<li class='nav-item-faq'><a class='<%= @page == 'faq' ? 'active' : '' %>' href='<%=faq_path%>'><%= t 'js.faq' %></a></li>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
<% if SiteSetting.tos_topic_id > 0 %>
|
||||||
<li class='nav-item-tos'><a href='<%= tos_path %>' class='<%= @page == 'tos' ? 'active' : '' %>'><%= t 'js.tos' %></a></li>
|
<li class='nav-item-tos'><a href='<%= tos_path %>' class='<%= @page == 'tos' ? 'active' : '' %>'><%= t 'js.tos' %></a></li>
|
||||||
|
<% end %>
|
||||||
|
<% if SiteSetting.privacy_topic_id > 0 %>
|
||||||
<li class='nav-item-privacy'><a href='<%= privacy_path %>' class='<%= @page == 'privacy' ? 'active' : '' %>'><%= t 'js.privacy' %></a></li>
|
<li class='nav-item-privacy'><a href='<%= privacy_path %>' class='<%= @page == 'privacy' ? 'active' : '' %>'><%= t 'js.privacy' %></a></li>
|
||||||
|
<% end %>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<% if staff? %>
|
<% if staff? %>
|
||||||
|
@ -66,21 +66,23 @@ DiscourseEvent.on(:site_setting_changed) do |name, old_value, new_value|
|
|||||||
|
|
||||||
Emoji.clear_cache && Discourse.request_refresh! if name == :emoji_deny_list
|
Emoji.clear_cache && Discourse.request_refresh! if name == :emoji_deny_list
|
||||||
|
|
||||||
if (name == :title || name == :site_description) &&
|
# Update seeded topics
|
||||||
topic = Topic.find_by(id: SiteSetting.welcome_topic_id)
|
if %i[title site_description].include?(name)
|
||||||
PostRevisor.new(topic.first_post, topic).revise!(
|
topics = SeedData::Topics.with_default_locale
|
||||||
Discourse.system_user,
|
topics.update(site_setting_names: ["welcome_topic_id"], skip_changed: true)
|
||||||
{
|
elsif %i[company_name contact_email governing_law city_for_disputes].include?(name)
|
||||||
title: I18n.t("discourse_welcome_topic.title", site_title: SiteSetting.title),
|
topics = SeedData::Topics.with_default_locale
|
||||||
raw:
|
%w[tos_topic_id privacy_topic_id].each do |site_setting|
|
||||||
I18n.t(
|
topic_id = SiteSetting.get(site_setting)
|
||||||
"discourse_welcome_topic.body",
|
if topic_id > 0 && Topic.with_deleted.exists?(id: topic_id)
|
||||||
base_path: Discourse.base_path,
|
if SiteSetting.company_name.blank?
|
||||||
site_title: SiteSetting.title,
|
topics.delete(site_setting_names: [site_setting], skip_changed: true)
|
||||||
site_description: SiteSetting.site_description,
|
else
|
||||||
),
|
topics.update(site_setting_names: [site_setting], skip_changed: true)
|
||||||
},
|
end
|
||||||
skip_revision: true,
|
elsif SiteSetting.company_name.present?
|
||||||
)
|
topics.create(site_setting_names: [site_setting])
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -2477,12 +2477,14 @@ uncategorized:
|
|||||||
tos_topic_id:
|
tos_topic_id:
|
||||||
default: -1
|
default: -1
|
||||||
hidden: true
|
hidden: true
|
||||||
|
client: true
|
||||||
guidelines_topic_id:
|
guidelines_topic_id:
|
||||||
default: -1
|
default: -1
|
||||||
hidden: true
|
hidden: true
|
||||||
privacy_topic_id:
|
privacy_topic_id:
|
||||||
default: -1
|
default: -1
|
||||||
hidden: true
|
hidden: true
|
||||||
|
client: true
|
||||||
welcome_topic_id:
|
welcome_topic_id:
|
||||||
default: -1
|
default: -1
|
||||||
hidden: true
|
hidden: true
|
||||||
|
@ -10,18 +10,28 @@ module SeedData
|
|||||||
@locale = locale
|
@locale = locale
|
||||||
end
|
end
|
||||||
|
|
||||||
def create(site_setting_names: nil, include_welcome_topics: true)
|
def create(site_setting_names: nil, include_welcome_topics: true, include_legal_topics: false)
|
||||||
I18n.with_locale(@locale) do
|
I18n.with_locale(@locale) do
|
||||||
topics(site_setting_names, include_welcome_topics).each { |params| create_topic(**params) }
|
topics(
|
||||||
|
site_setting_names: site_setting_names,
|
||||||
|
include_welcome_topics: include_welcome_topics,
|
||||||
|
include_legal_topics: include_legal_topics || SiteSetting.company_name.present?,
|
||||||
|
).each { |params| create_topic(**params) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def update(site_setting_names: nil, skip_changed: false)
|
def update(site_setting_names: nil, skip_changed: false)
|
||||||
I18n.with_locale(@locale) do
|
I18n.with_locale(@locale) do
|
||||||
topics(site_setting_names).each do |params|
|
topics(site_setting_names: site_setting_names).each do |params|
|
||||||
params.except!(:category, :after_create)
|
update_topic(**params.except(:category, :after_create), skip_changed: skip_changed)
|
||||||
params[:skip_changed] = skip_changed
|
end
|
||||||
update_topic(**params)
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete(site_setting_names: nil, skip_changed: false)
|
||||||
|
I18n.with_locale(@locale) do
|
||||||
|
topics(site_setting_names: site_setting_names).each do |params|
|
||||||
|
delete_topic(**params.slice(:site_setting_name), skip_changed: skip_changed)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -41,12 +51,14 @@ module SeedData
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def topics(site_setting_names = nil, include_welcome_topics = true)
|
def topics(site_setting_names: nil, include_welcome_topics: true, include_legal_topics: true)
|
||||||
staff_category = Category.find_by(id: SiteSetting.staff_category_id)
|
staff_category = Category.find_by(id: SiteSetting.staff_category_id)
|
||||||
|
|
||||||
topics = [
|
topics = []
|
||||||
|
|
||||||
# Terms of Service
|
# Terms of Service
|
||||||
{
|
if include_legal_topics
|
||||||
|
topics << {
|
||||||
site_setting_name: "tos_topic_id",
|
site_setting_name: "tos_topic_id",
|
||||||
title: I18n.t("tos_topic.title"),
|
title: I18n.t("tos_topic.title"),
|
||||||
raw:
|
raw:
|
||||||
@ -60,24 +72,28 @@ module SeedData
|
|||||||
),
|
),
|
||||||
category: staff_category,
|
category: staff_category,
|
||||||
static_first_reply: true,
|
static_first_reply: true,
|
||||||
},
|
}
|
||||||
|
end
|
||||||
|
|
||||||
# FAQ/Guidelines
|
# FAQ/Guidelines
|
||||||
{
|
topics << {
|
||||||
site_setting_name: "guidelines_topic_id",
|
site_setting_name: "guidelines_topic_id",
|
||||||
title: I18n.t("guidelines_topic.title"),
|
title: I18n.t("guidelines_topic.title"),
|
||||||
raw: I18n.t("guidelines_topic.body", base_path: Discourse.base_path),
|
raw: I18n.t("guidelines_topic.body", base_path: Discourse.base_path),
|
||||||
category: staff_category,
|
category: staff_category,
|
||||||
static_first_reply: true,
|
static_first_reply: true,
|
||||||
},
|
}
|
||||||
|
|
||||||
# Privacy Policy
|
# Privacy Policy
|
||||||
{
|
if include_legal_topics
|
||||||
|
topics << {
|
||||||
site_setting_name: "privacy_topic_id",
|
site_setting_name: "privacy_topic_id",
|
||||||
title: I18n.t("privacy_topic.title"),
|
title: I18n.t("privacy_topic.title"),
|
||||||
raw: I18n.t("privacy_topic.body"),
|
raw: I18n.t("privacy_topic.body"),
|
||||||
category: staff_category,
|
category: staff_category,
|
||||||
static_first_reply: true,
|
static_first_reply: true,
|
||||||
},
|
}
|
||||||
]
|
end
|
||||||
|
|
||||||
if include_welcome_topics
|
if include_welcome_topics
|
||||||
# Welcome Topic
|
# Welcome Topic
|
||||||
@ -152,27 +168,42 @@ module SeedData
|
|||||||
end
|
end
|
||||||
|
|
||||||
def update_topic(site_setting_name:, title:, raw:, static_first_reply: false, skip_changed:)
|
def update_topic(site_setting_name:, title:, raw:, static_first_reply: false, skip_changed:)
|
||||||
post = find_post(site_setting_name)
|
post = find_post(site_setting_name, deleted: true)
|
||||||
return if !post
|
return if !post
|
||||||
|
|
||||||
if !skip_changed || unchanged?(post)
|
if !skip_changed || unchanged?(post)
|
||||||
changes = { title: title, raw: raw }
|
if post.trashed?
|
||||||
post.revise(Discourse.system_user, changes, skip_validations: true)
|
PostDestroyer.new(Discourse.system_user, post).recover
|
||||||
|
post.reload
|
||||||
|
end
|
||||||
|
|
||||||
|
post.revise(Discourse.system_user, { title: title, raw: raw }, skip_validations: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
if static_first_reply && (reply = first_reply(post)) && (!skip_changed || unchanged?(reply))
|
if static_first_reply && (reply = first_reply(post)) && (!skip_changed || unchanged?(reply))
|
||||||
changes = { raw: first_reply_raw(title) }
|
reply.revise(Discourse.system_user, { raw: first_reply_raw(title) }, skip_validations: true)
|
||||||
reply.revise(Discourse.system_user, changes, skip_validations: true)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_post(site_setting_name)
|
def delete_topic(site_setting_name:, skip_changed:)
|
||||||
|
post = find_post(site_setting_name)
|
||||||
|
return if !post
|
||||||
|
|
||||||
|
PostDestroyer.new(Discourse.system_user, post).destroy if !skip_changed || unchanged?(post)
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_post(site_setting_name, deleted: false)
|
||||||
topic_id = SiteSetting.get(site_setting_name)
|
topic_id = SiteSetting.get(site_setting_name)
|
||||||
Post.find_by(topic_id: topic_id, post_number: 1) if topic_id > 0
|
return if topic_id < 1
|
||||||
|
|
||||||
|
posts = Post.where(topic_id: topic_id, post_number: 1)
|
||||||
|
posts = posts.with_deleted if deleted
|
||||||
|
posts.first
|
||||||
end
|
end
|
||||||
|
|
||||||
def unchanged?(post)
|
def unchanged?(post)
|
||||||
post.last_editor_id == Discourse::SYSTEM_USER_ID
|
post.last_editor_id == Discourse::SYSTEM_USER_ID &&
|
||||||
|
(!post.deleted_by_id || post.deleted_by_id == Discourse::SYSTEM_USER_ID)
|
||||||
end
|
end
|
||||||
|
|
||||||
def setting_value(site_setting_key)
|
def setting_value(site_setting_key)
|
||||||
|
@ -17,7 +17,7 @@ desc "ensure the asynchronously-created post_search_data index is present"
|
|||||||
task "annotate:ensure_all_indexes" => :environment do |task, args|
|
task "annotate:ensure_all_indexes" => :environment do |task, args|
|
||||||
# One of the indexes on post_search_data is created by a sidekiq job
|
# One of the indexes on post_search_data is created by a sidekiq job
|
||||||
# We need to do some acrobatics to create it on-demand
|
# We need to do some acrobatics to create it on-demand
|
||||||
SeedData::Topics.with_default_locale.create(include_welcome_topics: true)
|
SeedData::Topics.with_default_locale.create
|
||||||
SiteSetting.search_enable_recent_regular_posts_offset_size = 1
|
SiteSetting.search_enable_recent_regular_posts_offset_size = 1
|
||||||
Jobs::CreateRecentPostSearchIndexes.new.execute([])
|
Jobs::CreateRecentPostSearchIndexes.new.execute([])
|
||||||
end
|
end
|
||||||
|
@ -43,4 +43,54 @@ RSpec.describe "Setting changes" do
|
|||||||
expect(Reviewable.min_score_for_priority(:low)).not_to eq(new_threshold)
|
expect(Reviewable.min_score_for_priority(:low)).not_to eq(new_threshold)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#title and #site_description" do
|
||||||
|
before do
|
||||||
|
general_category = Fabricate(:category, name: "General")
|
||||||
|
SiteSetting.general_category_id = general_category.id
|
||||||
|
SeedData::Topics.with_default_locale.create(site_setting_names: ["welcome_topic_id"])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "updates the welcome topic when title changes" do
|
||||||
|
SiteSetting.title = SecureRandom.alphanumeric
|
||||||
|
|
||||||
|
topic = Topic.find(SiteSetting.welcome_topic_id)
|
||||||
|
expect(topic.title).to include(SiteSetting.title)
|
||||||
|
expect(topic.first_post.raw).to include(SiteSetting.title)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "updates the welcome topic when site_description changes" do
|
||||||
|
SiteSetting.site_description = SecureRandom.alphanumeric
|
||||||
|
|
||||||
|
topic = Topic.find(SiteSetting.welcome_topic_id)
|
||||||
|
expect(topic.first_post.raw).to include(SiteSetting.site_description)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#company_name" do
|
||||||
|
it "creates the TOS and Privacy topics" do
|
||||||
|
expect { SiteSetting.company_name = "Company Name" }.to change { Topic.count }.by(
|
||||||
|
2,
|
||||||
|
).and change { SiteSetting.tos_topic_id }.and change { SiteSetting.privacy_topic_id }
|
||||||
|
end
|
||||||
|
|
||||||
|
it "creates, updates and deletes the topic" do
|
||||||
|
# Topic is created
|
||||||
|
expect { SiteSetting.company_name = "Company Name" }.to change { Topic.count }.by(2)
|
||||||
|
topic = Topic.find(SiteSetting.tos_topic_id)
|
||||||
|
first_post = topic.first_post
|
||||||
|
expect(first_post.raw).to include("Company Name")
|
||||||
|
|
||||||
|
# Topic is edited
|
||||||
|
expect { SiteSetting.company_name = "Other Name" }.not_to change { Topic.count }
|
||||||
|
expect(first_post.reload.raw).to include("Other Name")
|
||||||
|
|
||||||
|
# Topic can be deleted
|
||||||
|
expect { SiteSetting.company_name = "" }.to change { Topic.count }.by(-2)
|
||||||
|
|
||||||
|
# Topic can be recovered and edited
|
||||||
|
SiteSetting.company_name = "New Name"
|
||||||
|
expect(first_post.reload.raw).to include("New Name")
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -11,7 +11,7 @@ RSpec.describe SeedData::Topics do
|
|||||||
end
|
end
|
||||||
|
|
||||||
def create_topic(name = "welcome_topic_id")
|
def create_topic(name = "welcome_topic_id")
|
||||||
subject.create(site_setting_names: [name])
|
subject.create(site_setting_names: [name], include_legal_topics: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#create" do
|
describe "#create" do
|
||||||
@ -71,6 +71,19 @@ RSpec.describe SeedData::Topics do
|
|||||||
|
|
||||||
expect { create_topic }.to_not change { Topic.count }
|
expect { create_topic }.to_not change { Topic.count }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "does not create a legal topic if company_name is not set" do
|
||||||
|
subject.create(site_setting_names: ["tos_topic_id"])
|
||||||
|
|
||||||
|
expect(SiteSetting.tos_topic_id).to eq(-1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "creates a legal topic if company_name is set" do
|
||||||
|
SiteSetting.company_name = "Company Name"
|
||||||
|
subject.create(site_setting_names: ["tos_topic_id"])
|
||||||
|
|
||||||
|
expect(SiteSetting.tos_topic_id).to_not eq(-1)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#update" do
|
describe "#update" do
|
||||||
@ -129,6 +142,29 @@ RSpec.describe SeedData::Topics do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#delete" do
|
||||||
|
def delete_topic(name = "welcome_topic_id", skip_changed: false)
|
||||||
|
subject.delete(site_setting_names: [name], skip_changed: skip_changed)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deletes the topic" do
|
||||||
|
create_topic
|
||||||
|
|
||||||
|
topic = Topic.last
|
||||||
|
|
||||||
|
expect { delete_topic }.to change { Topic.count }.by(-1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not delete the topic if changed" do
|
||||||
|
create_topic
|
||||||
|
|
||||||
|
topic = Topic.last
|
||||||
|
topic.first_post.revise(Fabricate(:admin), raw: "New text of first post.")
|
||||||
|
|
||||||
|
expect { delete_topic(skip_changed: true) }.not_to change { Topic.count }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "#reseed_options" do
|
describe "#reseed_options" do
|
||||||
it "returns only existing topics as options" do
|
it "returns only existing topics as options" do
|
||||||
create_topic("guidelines_topic_id")
|
create_topic("guidelines_topic_id")
|
||||||
|
Reference in New Issue
Block a user