FEATURE: Locale support for seeded categories and topics (#7110)
This commit is contained in:
parent
d91b47064e
commit
3fd04df781
|
@ -0,0 +1,42 @@
|
|||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
|
||||
export default Ember.Controller.extend(ModalFunctionality, {
|
||||
loading: true,
|
||||
reseeding: false,
|
||||
categories: null,
|
||||
topics: null,
|
||||
|
||||
onShow() {
|
||||
ajax("/admin/customize/reseed")
|
||||
.then(result => {
|
||||
this.setProperties({
|
||||
categories: result.categories,
|
||||
topics: result.topics
|
||||
});
|
||||
})
|
||||
.finally(() => this.set("loading", false));
|
||||
},
|
||||
|
||||
_extractSelectedIds(items) {
|
||||
return items.filter(item => item.selected).map(item => item.id);
|
||||
},
|
||||
|
||||
actions: {
|
||||
reseed() {
|
||||
this.set("reseeding", true);
|
||||
ajax("/admin/customize/reseed", {
|
||||
data: {
|
||||
category_ids: this._extractSelectedIds(this.categories),
|
||||
topic_ids: this._extractSelectedIds(this.topics)
|
||||
},
|
||||
method: "POST"
|
||||
})
|
||||
.then(
|
||||
() => this.send("closeModal"),
|
||||
() => bootbox.alert(I18n.t("generic_error"))
|
||||
)
|
||||
.finally(() => this.set("reseeding", false));
|
||||
}
|
||||
}
|
||||
});
|
|
@ -1,3 +1,5 @@
|
|||
import showModal from "discourse/lib/show-modal";
|
||||
|
||||
export default Ember.Route.extend({
|
||||
queryParams: {
|
||||
q: { replace: true },
|
||||
|
@ -13,5 +15,11 @@ export default Ember.Route.extend({
|
|||
|
||||
setupController(controller, model) {
|
||||
controller.set("siteTexts", model);
|
||||
},
|
||||
|
||||
actions: {
|
||||
showReseedModal() {
|
||||
showModal("admin-reseed", { admin: true });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
{{#d-modal-body title="admin.reseed.modal.title" subtitle="admin.reseed.modal.subtitle" class="reseed-modal"}}
|
||||
{{#conditional-loading-spinner condition=loading}}
|
||||
{{#if categories}}
|
||||
<fieldset>
|
||||
<legend class="options-group-title">{{i18n "admin.reseed.modal.categories"}}</legend>
|
||||
|
||||
{{#each categories as |category|}}
|
||||
<label>
|
||||
{{input class="option" type="checkbox" checked=category.selected}}
|
||||
<span>{{category.name}}</span>
|
||||
</label>
|
||||
{{/each}}
|
||||
</fieldset>
|
||||
{{/if}}
|
||||
|
||||
<br>
|
||||
|
||||
{{#if topics}}
|
||||
<fieldset>
|
||||
<legend class="options-group-title">{{i18n "admin.reseed.modal.topics"}}</legend>
|
||||
|
||||
{{#each topics as |topic|}}
|
||||
<label>
|
||||
{{input class="option" type="checkbox" checked=topic.selected}}
|
||||
<span>{{topic.name}}</span>
|
||||
</label>
|
||||
{{/each}}
|
||||
</fieldset>
|
||||
{{/if}}
|
||||
{{/conditional-loading-spinner}}
|
||||
{{/d-modal-body}}
|
||||
|
||||
<div class="modal-footer">
|
||||
{{d-button action=(action "reseed") class="btn-danger" label="go_ahead" disabled=reseeding}}
|
||||
{{d-modal-cancel close=(route-action "closeModal")}}
|
||||
</div>
|
|
@ -7,12 +7,20 @@
|
|||
autofocus="true"
|
||||
key-up=(action "search")}}
|
||||
|
||||
<div class='extra-options'>
|
||||
<div class="reseed">
|
||||
{{d-button action=(route-action "showReseedModal")
|
||||
class="btn-default"
|
||||
label="admin.reseed.action.label"
|
||||
title="admin.reseed.action.title"
|
||||
icon="sync"}}
|
||||
</div>
|
||||
|
||||
<p class="filter-options">
|
||||
<label>
|
||||
{{input type="checkbox" checked=overridden click=(action "toggleOverridden")}}
|
||||
{{i18n 'admin.site_text.show_overriden'}}
|
||||
</label>
|
||||
</div>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{{#conditional-loading-spinner condition=searching}}
|
||||
|
|
|
@ -204,11 +204,8 @@ $mobile-breakpoint: 700px;
|
|||
font-size: $font-0;
|
||||
width: 50%;
|
||||
}
|
||||
.extra-options {
|
||||
.reseed {
|
||||
float: right;
|
||||
input[type="checkbox"] {
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
.text-highlight {
|
||||
|
|
|
@ -781,3 +781,15 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.reseed-modal {
|
||||
.options-group-title {
|
||||
font-size: $font-up-2;
|
||||
font-weight: bold;
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.option {
|
||||
margin-left: 1em;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,6 +78,31 @@ class Admin::SiteTextsController < Admin::AdminController
|
|||
render_serialized(site_text, SiteTextSerializer, root: 'site_text', rest_serializer: true)
|
||||
end
|
||||
|
||||
def get_reseed_options
|
||||
render_json_dump(
|
||||
categories: SeedData::Categories.with_default_locale.reseed_options,
|
||||
topics: SeedData::Topics.with_default_locale.reseed_options
|
||||
)
|
||||
end
|
||||
|
||||
def reseed
|
||||
hijack do
|
||||
if params[:category_ids].present?
|
||||
SeedData::Categories.with_default_locale.update(
|
||||
site_setting_names: params[:category_ids]
|
||||
)
|
||||
end
|
||||
|
||||
if params[:topic_ids].present?
|
||||
SeedData::Topics.with_default_locale.update(
|
||||
site_setting_names: params[:topic_ids]
|
||||
)
|
||||
end
|
||||
|
||||
render json: success_json
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def record_for(k, value = nil)
|
||||
|
|
|
@ -4227,6 +4227,17 @@ en:
|
|||
add: "Add"
|
||||
filter: "Search (URL or External URL)"
|
||||
|
||||
reseed:
|
||||
action:
|
||||
label: "Reseed…"
|
||||
title: "Update content created by Discourse with latest translations"
|
||||
|
||||
modal:
|
||||
title: "Reseed"
|
||||
subtitle: "Update seeded categories and topics with latest translations"
|
||||
categories: "Categories"
|
||||
topics: "Topics"
|
||||
|
||||
wizard_js:
|
||||
wizard:
|
||||
done: "Done"
|
||||
|
|
|
@ -578,6 +578,8 @@ en:
|
|||
|
||||
[trust]: https://blog.discourse.org/2018/06/understanding-discourse-trust-levels/
|
||||
|
||||
admin_quick_start_title: "READ ME FIRST: Admin Quick Start Guide"
|
||||
|
||||
category:
|
||||
topic_prefix: "About the %{category} category"
|
||||
replace_paragraph: "(Replace this first paragraph with a brief description of your new category. This guidance will appear in the category selection area, so try to keep it below 200 characters.)"
|
||||
|
@ -1266,7 +1268,7 @@ en:
|
|||
site_settings:
|
||||
censored_words: "Words that will be automatically replaced with ■■■■"
|
||||
delete_old_hidden_posts: "Auto-delete any hidden posts that stay hidden for more than 30 days."
|
||||
default_locale: "The default language of this Discourse instance"
|
||||
default_locale: "The default language of this Discourse instance. You can reseed system generated categories and topics at <a href='%{base_path}/admin/customize/site_texts' target='_blank'>Customize / Text Content</a>."
|
||||
allow_user_locale: "Allow users to choose their own language interface preference"
|
||||
set_locale_from_accept_language_header: "set interface language for anonymous users from their web browser's language headers. (EXPERIMENTAL, does not work with anonymous cache)"
|
||||
support_mixed_text_direction: "Support mixed left-to-right and right-to-left text directions."
|
||||
|
|
|
@ -226,6 +226,9 @@ Discourse::Application.routes.draw do
|
|||
delete 'site_texts/:id.json' => 'site_texts#revert', constraints: { id: /[\w.\-\+]+/i }
|
||||
delete 'site_texts/:id' => 'site_texts#revert', constraints: { id: /[\w.\-\+]+/i }
|
||||
|
||||
get 'reseed' => 'site_texts#get_reseed_options'
|
||||
post 'reseed' => 'site_texts#reseed'
|
||||
|
||||
get 'email_templates' => 'email_templates#index'
|
||||
get 'email_templates/(:id)' => 'email_templates#show', constraints: { id: /[0-9a-z_.]+/ }
|
||||
put 'email_templates/(:id)' => 'email_templates#update', constraints: { id: /[0-9a-z_.]+/ }
|
||||
|
|
|
@ -1771,6 +1771,15 @@ uncategorized:
|
|||
privacy_topic_id:
|
||||
default: -1
|
||||
hidden: true
|
||||
welcome_topic_id:
|
||||
default: -1
|
||||
hidden: true
|
||||
lounge_welcome_topic_id:
|
||||
default: -1
|
||||
hidden: true
|
||||
admin_quick_start_topic_id:
|
||||
default: -1
|
||||
hidden: true
|
||||
|
||||
bootstrap_mode_min_users:
|
||||
default: 50
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
require 'migration/column_dropper'
|
||||
|
||||
# fix any bust caches post initial migration
|
||||
ActiveRecord::Base.send(:subclasses).each { |m| m.reset_column_information }
|
||||
|
||||
SiteSetting.refresh!
|
||||
uncat_id = SiteSetting.uncategorized_category_id
|
||||
uncat_id = -1 unless Numeric === uncat_id
|
||||
|
||||
if uncat_id == -1 || !Category.exists?(uncat_id)
|
||||
puts "Seeding uncategorized category!"
|
||||
|
||||
count = DB.exec "SELECT 1 FROM categories WHERE lower(name) = 'uncategorized'"
|
||||
name = 'Uncategorized'
|
||||
name << SecureRandom.hex if count > 0
|
||||
|
||||
result = DB.query_single "INSERT INTO categories
|
||||
(name,color,slug,description,text_color, user_id, created_at, updated_at, position, name_lower)
|
||||
VALUES ('#{name}', '0088CC', 'uncategorized', '', 'FFFFFF', -1, now(), now(), 1, '#{name.downcase}' )
|
||||
RETURNING id
|
||||
"
|
||||
category_id = result.first.to_i
|
||||
|
||||
DB.exec "DELETE FROM site_settings where name = 'uncategorized_category_id'"
|
||||
DB.exec "INSERT INTO site_settings(name, data_type, value, created_at, updated_at)
|
||||
VALUES ('uncategorized_category_id', 3, #{category_id}, now(), now())"
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
# fix any bust caches post initial migration
|
||||
ActiveRecord::Base.send(:subclasses).each { |m| m.reset_column_information }
|
||||
SiteSetting.refresh!
|
|
@ -0,0 +1,3 @@
|
|||
if !Rails.env.test?
|
||||
SeedData::Categories.with_default_locale.create
|
||||
end
|
|
@ -1,43 +0,0 @@
|
|||
unless Rails.env.test?
|
||||
lounge = Category.find_by(id: SiteSetting.lounge_category_id)
|
||||
if lounge && lounge.created_at == lounge.updated_at &&
|
||||
!lounge.group_ids.include?(Group[:trust_level_3].id)
|
||||
|
||||
# The category for users with trust level 3 has been created.
|
||||
# Add initial permissions and description. They can be changed later.
|
||||
|
||||
Category.transaction do
|
||||
lounge.group_names = ['trust_level_3']
|
||||
unless lounge.save
|
||||
puts lounge.errors.full_messages
|
||||
raise "Failed to set permissions on trust level 3 lounge category!"
|
||||
end
|
||||
|
||||
if lounge.topic_id.nil?
|
||||
creator = PostCreator.new(Discourse.system_user,
|
||||
raw: I18n.t('vip_category_description'),
|
||||
title: I18n.t('category.topic_prefix', category: lounge.name),
|
||||
category: lounge.name,
|
||||
archetype: Archetype.default,
|
||||
skip_validations: true
|
||||
)
|
||||
post = creator.create
|
||||
|
||||
unless post && post.id
|
||||
puts post.errors.full_messages if post
|
||||
puts creator.errors.inspect
|
||||
raise "Failed to create description for trust level 3 lounge!"
|
||||
end
|
||||
|
||||
lounge.topic_id = post.topic.id
|
||||
unless lounge.save
|
||||
puts lounge.errors.full_messages
|
||||
puts "Failed to set the lounge description topic!"
|
||||
end
|
||||
|
||||
# Reset topic count because we don't count the description topic
|
||||
DB.exec "UPDATE categories SET topic_count = 0 WHERE id = #{lounge.id}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,31 +0,0 @@
|
|||
unless Rails.env.test?
|
||||
meta = Category.find_by(id: SiteSetting.meta_category_id)
|
||||
if meta && !meta.topic_id
|
||||
|
||||
Category.transaction do
|
||||
creator = PostCreator.new(Discourse.system_user,
|
||||
raw: I18n.t('meta_category_description'),
|
||||
title: I18n.t('category.topic_prefix', category: meta.name),
|
||||
category: meta.name,
|
||||
archetype: Archetype.default
|
||||
)
|
||||
post = creator.create
|
||||
|
||||
unless post && post.id
|
||||
puts post.errors.full_messages if post
|
||||
puts creator.errors.inspect
|
||||
raise "Failed meta topic"
|
||||
end
|
||||
|
||||
meta.set_permissions(everyone: :full)
|
||||
meta.topic_id = post.topic.id
|
||||
unless meta.save
|
||||
puts meta.errors.full_messages
|
||||
puts "Failed to set the meta description and permission!"
|
||||
end
|
||||
|
||||
# Reset topic count because we don't count the description topic
|
||||
DB.exec "UPDATE categories SET topic_count = 0 WHERE id = #{meta.id}"
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,40 +0,0 @@
|
|||
unless Rails.env.test?
|
||||
staff = Category.find_by(id: SiteSetting.staff_category_id)
|
||||
if staff && !staff.group_ids.include?(Group[:staff].id)
|
||||
|
||||
# Add permissions and a description to the Staff category.
|
||||
|
||||
Category.transaction do
|
||||
staff.group_names = ['staff']
|
||||
unless staff.save
|
||||
puts staff.errors.full_messages
|
||||
raise "Failed to set permissions on the Staff category!"
|
||||
end
|
||||
|
||||
if staff.topic_id.nil?
|
||||
creator = PostCreator.new(Discourse.system_user,
|
||||
raw: I18n.t('staff_category_description'),
|
||||
title: I18n.t('category.topic_prefix', category: staff.name),
|
||||
category: staff.name,
|
||||
archetype: Archetype.default
|
||||
)
|
||||
post = creator.create
|
||||
|
||||
unless post && post.id
|
||||
puts post.errors.full_messages if post
|
||||
puts creator.errors.inspect
|
||||
raise "Failed to create description for Staff category!"
|
||||
end
|
||||
|
||||
staff.topic_id = post.topic.id
|
||||
unless staff.save
|
||||
puts staff.errors.full_messages
|
||||
puts "Failed to set the Staff category description topic!"
|
||||
end
|
||||
|
||||
# Reset topic count because we don't count the description topic
|
||||
DB.exec "UPDATE categories SET topic_count = 0 WHERE id = #{staff.id}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -2,64 +2,14 @@ User.reset_column_information
|
|||
Topic.reset_column_information
|
||||
Post.reset_column_information
|
||||
|
||||
staff = Category.find_by(id: SiteSetting.staff_category_id)
|
||||
seed_welcome_topics = (Topic.where('id NOT IN (SELECT topic_id from categories where topic_id is not null)').count == 0 && !Rails.env.test?)
|
||||
if !Rails.env.test?
|
||||
topics_exist = Topic.where(<<~SQL).exists?
|
||||
id NOT IN (
|
||||
SELECT topic_id
|
||||
FROM categories
|
||||
WHERE topic_id IS NOT NULL
|
||||
)
|
||||
SQL
|
||||
|
||||
unless Rails.env.test?
|
||||
def create_static_page_topic(site_setting_key, title_key, body_key, body_override, category, description, params = {})
|
||||
unless SiteSetting.send(site_setting_key) > 0
|
||||
creator = PostCreator.new(Discourse.system_user,
|
||||
title: I18n.t(title_key, default: I18n.t(title_key, locale: :en)),
|
||||
raw: body_override.present? ? body_override : I18n.t(body_key, params.merge(default: I18n.t(body_key, params.merge(locale: :en)))),
|
||||
skip_validations: true,
|
||||
category: category ? category.name : nil)
|
||||
post = creator.create
|
||||
|
||||
raise "Failed to create the #{description} topic! #{creator.errors.full_messages.join('. ')}" if creator.errors.present?
|
||||
|
||||
SiteSetting.send("#{site_setting_key}=", post.topic_id)
|
||||
|
||||
_reply = PostCreator.create(Discourse.system_user,
|
||||
raw: I18n.t('static_topic_first_reply', page_name: I18n.t(title_key, default: I18n.t(title_key, locale: :en))),
|
||||
skip_validations: true,
|
||||
topic_id: post.topic_id)
|
||||
end
|
||||
end
|
||||
|
||||
create_static_page_topic('tos_topic_id', 'tos_topic.title', "tos_topic.body", nil, staff, "terms of service",
|
||||
company_name: SiteSetting.company_name.presence || "company_name",
|
||||
base_url: Discourse.base_url,
|
||||
contact_email: SiteSetting.contact_email.presence || "contact_email",
|
||||
governing_law: SiteSetting.governing_law.presence || "governing_law",
|
||||
city_for_disputes: SiteSetting.city_for_disputes.presence || "city_for_disputes")
|
||||
|
||||
create_static_page_topic('guidelines_topic_id', 'guidelines_topic.title', "guidelines_topic.body", nil, staff, "guidelines", base_path: Discourse.base_path)
|
||||
|
||||
create_static_page_topic('privacy_topic_id', 'privacy_topic.title', "privacy_topic.body", nil, staff, "privacy policy")
|
||||
end
|
||||
|
||||
if seed_welcome_topics
|
||||
puts "Seeding welcome topics"
|
||||
|
||||
post = PostCreator.create(Discourse.system_user, raw: I18n.t('discourse_welcome_topic.body', base_path: Discourse.base_path), title: I18n.t('discourse_welcome_topic.title'), skip_validations: true)
|
||||
post.topic.update_pinned(true, true)
|
||||
TopicCustomField.create(topic_id: post.topic.id, name: "is_welcome_topic", value: "true")
|
||||
|
||||
lounge = Category.find_by(id: SiteSetting.lounge_category_id)
|
||||
if lounge
|
||||
post = PostCreator.create(Discourse.system_user, raw: I18n.t('lounge_welcome.body', base_path: Discourse.base_path), title: I18n.t('lounge_welcome.title'), skip_validations: true, category: lounge.name)
|
||||
post.topic.update_pinned(true)
|
||||
end
|
||||
|
||||
filename = DiscoursePluginRegistry.seed_data["admin_quick_start_filename"]
|
||||
if filename.nil? || !File.exists?(filename)
|
||||
filename = Rails.root + 'docs/ADMIN-QUICK-START-GUIDE.md'
|
||||
end
|
||||
|
||||
welcome = File.read(filename)
|
||||
PostCreator.create(Discourse.system_user,
|
||||
raw: welcome,
|
||||
title: DiscoursePluginRegistry.seed_data["admin_quick_start_title"] || "READ ME FIRST: Admin Quick Start Guide",
|
||||
skip_validations: true,
|
||||
category: staff ? staff.name : nil)
|
||||
SeedData::Topics.with_default_locale.create(include_welcome_topics: !topics_exist)
|
||||
end
|
||||
|
|
|
@ -1,38 +1,5 @@
|
|||
class AddLoungeCategory < ActiveRecord::Migration[4.2]
|
||||
def up
|
||||
return if Rails.env.test?
|
||||
|
||||
I18n.overrides_disabled do
|
||||
result = DB.exec "SELECT 1 FROM site_settings where name = 'lounge_category_id'"
|
||||
if result == 0
|
||||
description = I18n.t('vip_category_description')
|
||||
|
||||
default_name = I18n.t('vip_category_name')
|
||||
name = if DB.exec("SELECT 1 FROM categories where name = '#{default_name}'") == 0
|
||||
default_name
|
||||
else
|
||||
"CHANGE_ME"
|
||||
end
|
||||
|
||||
result = DB.query_single "INSERT INTO categories
|
||||
(name, color, text_color, created_at, updated_at, user_id, slug, description, read_restricted, position)
|
||||
VALUES (:name, 'A461EF', '652D90', now(), now(), -1, '', :description, true, 3)
|
||||
RETURNING id", name: name, description: description
|
||||
|
||||
category_id = result.first.to_i
|
||||
|
||||
DB.exec "UPDATE categories SET slug = :slug
|
||||
WHERE id = :category_id",
|
||||
slug: Slug.for(name, "#{category_id}-category"), category_id: category_id
|
||||
|
||||
execute "INSERT INTO site_settings(name, data_type, value, created_at, updated_at)
|
||||
VALUES ('lounge_category_id', 3, #{category_id.to_i}, now(), now())"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
# Don't reverse this change. There is so much logic around deleting a category that it's messy
|
||||
# to try to do in sql. The up method will just make sure never to create the category twice.
|
||||
def change
|
||||
# replaced by fixture
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,34 +1,5 @@
|
|||
class AddMetaCategory < ActiveRecord::Migration[4.2]
|
||||
def up
|
||||
return if Rails.env.test?
|
||||
|
||||
I18n.overrides_disabled do
|
||||
result = DB.exec "SELECT 1 FROM site_settings where name = 'meta_category_id'"
|
||||
if result == 0
|
||||
description = I18n.t('meta_category_description')
|
||||
name = I18n.t('meta_category_name')
|
||||
|
||||
if DB.exec("SELECT 1 FROM categories where name ilike :name", name: name) == 0
|
||||
result = DB.query_single "INSERT INTO categories
|
||||
(name, color, text_color, created_at, updated_at, user_id, slug, description, read_restricted, position)
|
||||
VALUES (:name, '808281', 'FFFFFF', now(), now(), -1, :slug, :description, true, 1)
|
||||
RETURNING id", name: name, slug: '', description: description
|
||||
|
||||
category_id = result.first.to_i
|
||||
|
||||
DB.exec "UPDATE categories SET slug=:slug WHERE id=:category_id",
|
||||
slug: Slug.for(name, "#{category_id}-category"), category_id: category_id
|
||||
|
||||
execute "INSERT INTO site_settings(name, data_type, value, created_at, updated_at)
|
||||
VALUES ('meta_category_id', 3, #{category_id}, now(), now())"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
# Don't reverse this change. There is so much logic around deleting a category that it's messy
|
||||
# to try to do in sql. The up method will just make sure never to create the category twice.
|
||||
def change
|
||||
# replaced by fixture
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,33 +1,5 @@
|
|||
class AddStaffCategory < ActiveRecord::Migration[4.2]
|
||||
def up
|
||||
return if Rails.env.test?
|
||||
|
||||
I18n.overrides_disabled do
|
||||
result = DB.exec "SELECT 1 FROM site_settings where name = 'staff_category_id'"
|
||||
if result == 0
|
||||
description = I18n.t('staff_category_description')
|
||||
name = I18n.t('staff_category_name')
|
||||
|
||||
if DB.exec("SELECT 1 FROM categories where name ilike :name", name: name) == 0
|
||||
|
||||
result = DB.query_single "INSERT INTO categories
|
||||
(name, color, text_color, created_at, updated_at, user_id, slug, description, read_restricted, position)
|
||||
VALUES (:name, 'E45735', 'FFFFFF', now(), now(), -1, '', :description, true, 2)
|
||||
RETURNING id", name: name, description: description
|
||||
|
||||
category_id = result.first.to_i
|
||||
|
||||
DB.exec "UPDATE categories SET slug=:slug WHERE id=:category_id",
|
||||
slug: Slug.for(name, "#{category_id}-category"), category_id: category_id
|
||||
|
||||
DB.exec "INSERT INTO site_settings(name, data_type, value, created_at, updated_at)
|
||||
VALUES ('staff_category_id', 3, #{category_id.to_i}, now(), now())"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
# Do nothing
|
||||
def change
|
||||
# replaced by fixture
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
class AddMissingTopicIdSiteSettings < ActiveRecord::Migration[5.2]
|
||||
def up
|
||||
# Welcome Topic
|
||||
execute <<~SQL
|
||||
INSERT INTO site_settings(name, data_type, value, created_at, updated_at)
|
||||
SELECT 'welcome_topic_id', 3, topic_id, created_at, updated_at
|
||||
FROM topic_custom_fields
|
||||
WHERE name = 'is_welcome_topic' AND value = 'true' AND NOT EXISTS(
|
||||
SELECT 1
|
||||
FROM site_settings
|
||||
WHERE name = 'welcome_topic_id'
|
||||
)
|
||||
LIMIT 1
|
||||
SQL
|
||||
|
||||
execute <<~SQL
|
||||
DELETE FROM topic_custom_fields
|
||||
WHERE name = 'is_welcome_topic' AND value = 'true'
|
||||
SQL
|
||||
|
||||
# Lounge Welcome Topic
|
||||
execute <<~SQL
|
||||
INSERT INTO site_settings(name, data_type, value, created_at, updated_at)
|
||||
SELECT 'lounge_welcome_topic_id', 3, id, created_at, updated_at
|
||||
FROM topics
|
||||
WHERE title = 'Welcome to the Lounge' AND NOT EXISTS(
|
||||
SELECT 1
|
||||
FROM site_settings
|
||||
WHERE name = 'lounge_welcome_topic_id'
|
||||
) AND category_id = (
|
||||
SELECT value::INT
|
||||
FROM site_settings
|
||||
WHERE name = 'lounge_category_id'
|
||||
)
|
||||
ORDER BY created_at
|
||||
LIMIT 1
|
||||
SQL
|
||||
|
||||
# Admin Quick Start Guide
|
||||
execute <<~SQL
|
||||
INSERT INTO site_settings(name, data_type, value, created_at, updated_at)
|
||||
SELECT 'admin_quick_start_topic_id', 3, id, created_at, updated_at
|
||||
FROM topics
|
||||
WHERE title IN ('READ ME FIRST: Admin Quick Start Guide', 'READ ME FIRST: Getting Started') AND NOT EXISTS(
|
||||
SELECT 1
|
||||
FROM site_settings
|
||||
WHERE name = 'admin_quick_start_topic_id'
|
||||
)
|
||||
ORDER BY created_at
|
||||
LIMIT 1
|
||||
SQL
|
||||
end
|
||||
|
||||
def down
|
||||
execute <<~SQL
|
||||
INSERT INTO topic_custom_fields(topic_id, name, value, created_at, updated_at)
|
||||
SELECT value::INTEGER, 'is_welcome_topic', 'true', created_at, updated_at
|
||||
FROM site_settings
|
||||
WHERE name = 'welcome_topic_id'
|
||||
SQL
|
||||
|
||||
execute <<~SQL
|
||||
DELETE FROM site_settings
|
||||
WHERE name IN ('welcome_topic_id', 'lounge_welcome_topic_id', 'admin_quick_start_topic_id')
|
||||
SQL
|
||||
end
|
||||
end
|
|
@ -29,11 +29,9 @@ class IntroductionUpdater
|
|||
end
|
||||
|
||||
def find_welcome_post
|
||||
topic_id = TopicCustomField
|
||||
.where(name: "is_welcome_topic", value: "true")
|
||||
.pluck(:topic_id)
|
||||
topic_id = SiteSetting.welcome_topic_id
|
||||
|
||||
if topic_id.blank?
|
||||
if topic_id <= 0
|
||||
title = I18n.t("discourse_welcome_topic.title")
|
||||
topic_id = find_topic_id(title)
|
||||
end
|
||||
|
|
|
@ -0,0 +1,174 @@
|
|||
module SeedData
|
||||
class Categories
|
||||
def self.with_default_locale
|
||||
SeedData::Categories.new(SiteSetting.default_locale)
|
||||
end
|
||||
|
||||
def initialize(locale)
|
||||
@locale = locale
|
||||
end
|
||||
|
||||
def create(site_setting_names: nil)
|
||||
I18n.with_locale(@locale) do
|
||||
categories(site_setting_names).each { |params| create_category(params) }
|
||||
end
|
||||
end
|
||||
|
||||
def update(site_setting_names: nil, skip_changed: false)
|
||||
I18n.with_locale(@locale) do
|
||||
categories(site_setting_names).each do |params|
|
||||
params.slice!(:site_setting_name, :name, :description)
|
||||
params[:skip_changed] = skip_changed
|
||||
update_category(params)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def reseed_options
|
||||
I18n.with_locale(@locale) do
|
||||
categories.map do |params|
|
||||
category = find_category(params[:site_setting_name])
|
||||
next unless category
|
||||
|
||||
{
|
||||
id: params[:site_setting_name],
|
||||
name: category.name,
|
||||
selected: unchanged?(category)
|
||||
}
|
||||
end.compact
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def categories(site_setting_names = nil)
|
||||
categories = [
|
||||
{
|
||||
site_setting_name: 'uncategorized_category_id',
|
||||
name: I18n.t('uncategorized_category_name'),
|
||||
description: nil,
|
||||
position: 0,
|
||||
color: '0088CC',
|
||||
text_color: 'FFFFFF',
|
||||
permissions: { everyone: :full },
|
||||
force_permissions: true,
|
||||
force_existence: true
|
||||
},
|
||||
{
|
||||
site_setting_name: 'meta_category_id',
|
||||
name: I18n.t('meta_category_name'),
|
||||
description: I18n.t('meta_category_description'),
|
||||
position: 1,
|
||||
color: '808281',
|
||||
text_color: 'FFFFFF',
|
||||
permissions: { everyone: :full },
|
||||
force_permissions: true
|
||||
},
|
||||
{
|
||||
site_setting_name: 'staff_category_id',
|
||||
name: I18n.t('staff_category_name'),
|
||||
description: I18n.t('staff_category_description'),
|
||||
position: 2,
|
||||
color: 'E45735',
|
||||
text_color: 'FFFFFF',
|
||||
permissions: { staff: :full },
|
||||
force_permissions: true
|
||||
},
|
||||
{
|
||||
site_setting_name: 'lounge_category_id',
|
||||
name: I18n.t('vip_category_name'),
|
||||
description: I18n.t('vip_category_description'),
|
||||
position: 3,
|
||||
color: 'A461EF',
|
||||
text_color: '652D90',
|
||||
permissions: { trust_level_3: :full },
|
||||
force_permissions: false
|
||||
}
|
||||
]
|
||||
|
||||
if site_setting_names
|
||||
categories.select! { |c| site_setting_names.include?(c[:site_setting_name]) }
|
||||
end
|
||||
|
||||
categories
|
||||
end
|
||||
|
||||
def create_category(site_setting_name:, name:, description:, position:, color:, text_color:,
|
||||
permissions:, force_permissions:, force_existence: false)
|
||||
category_id = SiteSetting.send(site_setting_name)
|
||||
|
||||
if should_create_category?(category_id, force_existence)
|
||||
category = Category.new(
|
||||
name: unused_category_name(category_id, name),
|
||||
description: description,
|
||||
user_id: Discourse::SYSTEM_USER_ID,
|
||||
position: position,
|
||||
color: color,
|
||||
text_color: text_color
|
||||
)
|
||||
|
||||
category.skip_category_definition = true if description.blank?
|
||||
category.set_permissions(permissions)
|
||||
category.save!
|
||||
|
||||
SiteSetting.send("#{site_setting_name}=", category.id)
|
||||
elsif category = Category.find_by(id: category_id)
|
||||
if description.present? && (category.topic_id.blank? || !Topic.exists?(category.topic_id))
|
||||
category.description = description
|
||||
category.create_category_definition
|
||||
end
|
||||
|
||||
if force_permissions
|
||||
category.set_permissions(permissions)
|
||||
category.save! if category.changed?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def should_create_category?(category_id, force_existence)
|
||||
if category_id > 0
|
||||
force_existence ? !Category.exists?(category_id) : false
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
def unused_category_name(category_id, name)
|
||||
category_exists = Category.where(
|
||||
'id <> :id AND LOWER(name) = :name',
|
||||
id: category_id,
|
||||
name: name.downcase
|
||||
).exists?
|
||||
|
||||
category_exists ? "#{name}#{SecureRandom.hex}" : name
|
||||
end
|
||||
|
||||
def update_category(site_setting_name:, name:, description:, skip_changed:)
|
||||
category = find_category(site_setting_name)
|
||||
return if !category || (skip_changed && !unchanged?(category))
|
||||
|
||||
name = unused_category_name(category.id, name)
|
||||
category.name = name
|
||||
category.slug = Slug.for(name, '')
|
||||
category.save!
|
||||
|
||||
if description.present? && description_post = category&.topic&.first_post
|
||||
changes = { title: I18n.t("category.topic_prefix", category: name), raw: description }
|
||||
description_post.revise(Discourse.system_user, changes, skip_validations: true)
|
||||
end
|
||||
end
|
||||
|
||||
def find_category(site_setting_name)
|
||||
category_id = SiteSetting.send(site_setting_name)
|
||||
Category.find_by(id: category_id) if category_id > 0
|
||||
end
|
||||
|
||||
def unchanged?(category)
|
||||
if description_post = category&.topic&.first_post
|
||||
return description_post.last_editor_id == Discourse::SYSTEM_USER_ID
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,197 @@
|
|||
module SeedData
|
||||
class Topics
|
||||
def self.with_default_locale
|
||||
SeedData::Topics.new(SiteSetting.default_locale)
|
||||
end
|
||||
|
||||
def initialize(locale)
|
||||
@locale = locale
|
||||
end
|
||||
|
||||
def create(site_setting_names: nil, include_welcome_topics: true)
|
||||
I18n.with_locale(@locale) do
|
||||
topics(site_setting_names, include_welcome_topics).each do |params|
|
||||
create_topic(params)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def update(site_setting_names: nil, skip_changed: false)
|
||||
I18n.with_locale(@locale) do
|
||||
topics(site_setting_names).each do |params|
|
||||
params.except!(:category, :after_create)
|
||||
params[:skip_changed] = skip_changed
|
||||
update_topic(params)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def reseed_options
|
||||
I18n.with_locale(@locale) do
|
||||
topics.map do |params|
|
||||
post = find_post(params[:site_setting_name])
|
||||
next unless post
|
||||
|
||||
{
|
||||
id: params[:site_setting_name],
|
||||
name: post.topic.title,
|
||||
selected: unchanged?(post)
|
||||
}
|
||||
end.compact
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def topics(site_setting_names = nil, include_welcome_topics = true)
|
||||
staff_category = Category.find_by(id: SiteSetting.staff_category_id)
|
||||
|
||||
topics = [
|
||||
# Terms of Service
|
||||
{
|
||||
site_setting_name: 'tos_topic_id',
|
||||
title: I18n.t('tos_topic.title'),
|
||||
raw: I18n.t('tos_topic.body',
|
||||
company_name: setting_value('company_name'),
|
||||
base_url: Discourse.base_url,
|
||||
contact_email: setting_value('contact_email'),
|
||||
governing_law: setting_value('governing_law'),
|
||||
city_for_disputes: setting_value('city_for_disputes')
|
||||
),
|
||||
category: staff_category,
|
||||
static_first_reply: true
|
||||
},
|
||||
|
||||
# FAQ/Guidelines
|
||||
{
|
||||
site_setting_name: 'guidelines_topic_id',
|
||||
title: I18n.t('guidelines_topic.title'),
|
||||
raw: I18n.t('guidelines_topic.body', base_path: Discourse.base_path),
|
||||
category: staff_category,
|
||||
static_first_reply: true
|
||||
},
|
||||
|
||||
# Privacy Policy
|
||||
{
|
||||
site_setting_name: 'privacy_topic_id',
|
||||
title: I18n.t('privacy_topic.title'),
|
||||
raw: I18n.t('privacy_topic.body'),
|
||||
category: staff_category,
|
||||
static_first_reply: true
|
||||
}
|
||||
]
|
||||
|
||||
if include_welcome_topics
|
||||
# Welcome Topic
|
||||
topics << {
|
||||
site_setting_name: 'welcome_topic_id',
|
||||
title: I18n.t('discourse_welcome_topic.title'),
|
||||
raw: I18n.t('discourse_welcome_topic.body', base_path: Discourse.base_path),
|
||||
after_create: proc do |post|
|
||||
post.topic.update_pinned(true, true)
|
||||
end
|
||||
}
|
||||
|
||||
# Lounge Welcome Topic
|
||||
if lounge_category = Category.find_by(id: SiteSetting.lounge_category_id)
|
||||
topics << {
|
||||
site_setting_name: 'lounge_welcome_topic_id',
|
||||
title: I18n.t('lounge_welcome.title'),
|
||||
raw: I18n.t('lounge_welcome.body', base_path: Discourse.base_path),
|
||||
category: lounge_category,
|
||||
after_create: proc do |post|
|
||||
post.topic.update_pinned(true)
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
# Admin Quick Start Guide
|
||||
topics << {
|
||||
site_setting_name: 'admin_quick_start_topic_id',
|
||||
title: DiscoursePluginRegistry.seed_data['admin_quick_start_title'] || I18n.t('admin_quick_start_title'),
|
||||
raw: admin_quick_start_raw,
|
||||
category: staff_category
|
||||
}
|
||||
end
|
||||
|
||||
if site_setting_names
|
||||
topics.select! { |t| site_setting_names.include?(t[:site_setting_name]) }
|
||||
end
|
||||
|
||||
topics
|
||||
end
|
||||
|
||||
def create_topic(site_setting_name:, title:, raw:, category: nil, static_first_reply: false, after_create: nil)
|
||||
topic_id = SiteSetting.send(site_setting_name)
|
||||
return if topic_id > 0 || Topic.find_by(id: topic_id)
|
||||
|
||||
post = PostCreator.create!(
|
||||
Discourse.system_user,
|
||||
title: title,
|
||||
raw: raw,
|
||||
skip_validations: true,
|
||||
category: category&.name
|
||||
)
|
||||
|
||||
if static_first_reply
|
||||
PostCreator.create!(
|
||||
Discourse.system_user,
|
||||
raw: first_reply_raw(title),
|
||||
skip_validations: true,
|
||||
topic_id: post.topic_id
|
||||
)
|
||||
end
|
||||
|
||||
after_create&.call(post)
|
||||
|
||||
SiteSetting.send("#{site_setting_name}=", post.topic_id)
|
||||
end
|
||||
|
||||
def update_topic(site_setting_name:, title:, raw:, static_first_reply: false, skip_changed:)
|
||||
post = find_post(site_setting_name)
|
||||
return if !post
|
||||
|
||||
if !skip_changed || unchanged?(post)
|
||||
changes = { title: title, raw: raw }
|
||||
post.revise(Discourse.system_user, changes, skip_validations: true)
|
||||
end
|
||||
|
||||
if static_first_reply && (reply = first_reply(post)) && (!skip_changed || unchanged?(reply))
|
||||
changes = { raw: first_reply_raw(title) }
|
||||
reply.revise(Discourse.system_user, changes, skip_validations: true)
|
||||
end
|
||||
end
|
||||
|
||||
def find_post(site_setting_name)
|
||||
topic_id = SiteSetting.send(site_setting_name)
|
||||
Post.find_by(topic_id: topic_id, post_number: 1) if topic_id > 0
|
||||
end
|
||||
|
||||
def unchanged?(post)
|
||||
post.last_editor_id == Discourse::SYSTEM_USER_ID
|
||||
end
|
||||
|
||||
def setting_value(site_setting_key)
|
||||
SiteSetting.send(site_setting_key).presence || "<ins>#{site_setting_key}</ins>"
|
||||
end
|
||||
|
||||
def first_reply(post)
|
||||
Post.find_by(topic_id: post.topic_id, post_number: 2, user_id: Discourse::SYSTEM_USER_ID)
|
||||
end
|
||||
|
||||
def first_reply_raw(topic_title)
|
||||
I18n.t('static_topic_first_reply', page_name: topic_title)
|
||||
end
|
||||
|
||||
def admin_quick_start_raw
|
||||
quick_start_filename = DiscoursePluginRegistry.seed_data["admin_quick_start_filename"]
|
||||
|
||||
if !quick_start_filename || !File.exist?(quick_start_filename)
|
||||
# TODO Make the quick start guide translatable
|
||||
quick_start_filename = File.join(Rails.root, 'docs', 'ADMIN-QUICK-START-GUIDE.md')
|
||||
end
|
||||
|
||||
File.read(quick_start_filename)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -55,3 +55,16 @@ task "i18n:check", [:locale] => [:environment] do |_, args|
|
|||
puts ""
|
||||
exit 1 unless failed_locales.empty?
|
||||
end
|
||||
|
||||
desc "Update seeded topics and categories with latest translations"
|
||||
task "i18n:reseed", [:locale] => [:environment] do |_, args|
|
||||
locale = args[:locale]&.to_sym
|
||||
|
||||
if locale.blank? || !I18n.locale_available?(locale)
|
||||
puts "ERROR: Expecting rake i18n:reseed[locale]"
|
||||
exit 1
|
||||
end
|
||||
|
||||
SeedData::Categories.new(locale).update
|
||||
SeedData::Topics.new(locale).update
|
||||
end
|
||||
|
|
|
@ -64,39 +64,3 @@ task "topics:apply_autoclose" => :environment do
|
|||
|
||||
puts "", "Done"
|
||||
end
|
||||
|
||||
def update_static_page_topic(locale, site_setting_key, title_key, body_key, params = {})
|
||||
topic = Topic.find(SiteSetting.send(site_setting_key))
|
||||
|
||||
if (topic && post = topic.first_post)
|
||||
post.revise(Discourse.system_user,
|
||||
title: I18n.t(title_key, locale: locale),
|
||||
raw: I18n.t(body_key, params.merge(locale: locale)))
|
||||
|
||||
puts "", "Topic for #{site_setting_key} updated"
|
||||
else
|
||||
puts "", "Topic for #{site_setting_key} not found"
|
||||
end
|
||||
end
|
||||
|
||||
desc "Update static topics (ToS, Privacy, Guidelines) with latest translated content"
|
||||
task "topics:update_static", [:locale] => [:environment] do |_, args|
|
||||
locale = args[:locale]&.to_sym
|
||||
|
||||
if locale.blank? || !I18n.locale_available?(locale)
|
||||
puts "ERROR: Expecting rake topics:update_static[locale]"
|
||||
exit 1
|
||||
end
|
||||
|
||||
update_static_page_topic(locale, "tos_topic_id", "tos_topic.title", "tos_topic.body",
|
||||
company_name: SiteSetting.company_name.presence || "company_name",
|
||||
base_url: Discourse.base_url,
|
||||
contact_email: SiteSetting.contact_email.presence || "contact_email",
|
||||
governing_law: SiteSetting.governing_law.presence || "governing_law",
|
||||
city_for_disputes: SiteSetting.city_for_disputes.presence || "city_for_disputes")
|
||||
|
||||
update_static_page_topic(locale, "guidelines_topic_id", "guidelines_topic.title", "guidelines_topic.body",
|
||||
base_path: Discourse.base_path)
|
||||
|
||||
update_static_page_topic(locale, "privacy_topic_id", "privacy_topic.title", "privacy_topic.body")
|
||||
end
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
require_dependency 'introduction_updater'
|
||||
require_dependency 'emoji_set_site_setting'
|
||||
require_dependency 'seed_data/categories'
|
||||
require_dependency 'seed_data/topics'
|
||||
|
||||
class Wizard
|
||||
class Builder
|
||||
|
@ -26,7 +28,15 @@ class Wizard
|
|||
step.on_update do |updater|
|
||||
old_locale = SiteSetting.default_locale
|
||||
updater.apply_setting(:default_locale)
|
||||
updater.refresh_required = true if old_locale != updater.fields[:default_locale]
|
||||
|
||||
if old_locale != updater.fields[:default_locale]
|
||||
Scheduler::Defer.later "Reseed" do
|
||||
SeedData::Categories.with_default_locale.update(skip_changed: true)
|
||||
SeedData::Topics.with_default_locale.update(skip_changed: true)
|
||||
end
|
||||
|
||||
updater.refresh_required = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -95,7 +105,7 @@ class Wizard
|
|||
|
||||
step.on_update do |updater|
|
||||
update_tos do |raw|
|
||||
replace_company(updater, raw, 'contact_email')
|
||||
replace_setting_value(updater, raw, 'contact_email')
|
||||
end
|
||||
|
||||
updater.apply_settings(:contact_email, :contact_url)
|
||||
|
@ -111,9 +121,9 @@ class Wizard
|
|||
|
||||
step.on_update do |updater|
|
||||
update_tos do |raw|
|
||||
replace_company(updater, raw, 'company_name')
|
||||
replace_company(updater, raw, 'governing_law')
|
||||
replace_company(updater, raw, 'city_for_disputes')
|
||||
replace_setting_value(updater, raw, 'company_name')
|
||||
replace_setting_value(updater, raw, 'governing_law')
|
||||
replace_setting_value(updater, raw, 'city_for_disputes')
|
||||
end
|
||||
|
||||
updater.apply_settings(:company_name, :governing_law, :city_for_disputes)
|
||||
|
@ -273,14 +283,14 @@ class Wizard
|
|||
|
||||
protected
|
||||
|
||||
def replace_company(updater, raw, field_name)
|
||||
def replace_setting_value(updater, raw, field_name)
|
||||
old_value = SiteSetting.send(field_name)
|
||||
old_value = field_name if old_value.blank?
|
||||
|
||||
new_value = updater.fields[field_name.to_sym]
|
||||
new_value = field_name if new_value.blank?
|
||||
|
||||
raw.gsub!(old_value, new_value)
|
||||
raw.gsub!("<ins>#{old_value}</ins>", new_value) || raw.gsub!(old_value, new_value)
|
||||
end
|
||||
|
||||
def reserved_usernames
|
||||
|
|
|
@ -12,8 +12,8 @@ describe IntroductionUpdater do
|
|||
topic
|
||||
end
|
||||
|
||||
it "finds the welcome topic by custom field" do
|
||||
TopicCustomField.create(topic_id: welcome_topic.id, name: "is_welcome_topic", value: "true")
|
||||
it "finds the welcome topic by site setting" do
|
||||
SiteSetting.welcome_topic_id = welcome_topic.id
|
||||
expect(subject.get_summary).to eq(welcome_post_raw)
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
require 'rails_helper'
|
||||
require 'seed_data/categories'
|
||||
|
||||
describe SeedData::Categories do
|
||||
subject { SeedData::Categories.with_default_locale }
|
||||
|
||||
def create_category(name = "staff_category_id")
|
||||
subject.create(site_setting_names: [name])
|
||||
end
|
||||
|
||||
def description_post(category)
|
||||
Post.find_by(topic_id: category.topic_id)
|
||||
end
|
||||
|
||||
describe "#create" do
|
||||
def permissions(group, type)
|
||||
{
|
||||
group_id: Group::AUTO_GROUPS[group],
|
||||
permission_type: CategoryGroup.permission_types[type]
|
||||
}
|
||||
end
|
||||
|
||||
it "creates a missing category" do
|
||||
expect { create_category }
|
||||
.to change { Category.count }.by(1)
|
||||
.and change { Topic.count }.by(1)
|
||||
|
||||
category = Category.last
|
||||
expect(category.name).to eq(I18n.t("staff_category_name"))
|
||||
expect(category.topic_id).to be_present
|
||||
expect(category.user_id).to eq(Discourse::SYSTEM_USER_ID)
|
||||
expect(category.category_groups.count).to eq(1)
|
||||
expect(category.category_groups.first).to have_attributes(permissions(:staff, :full))
|
||||
expect(Topic.exists?(category.topic_id))
|
||||
expect(description_post(category).raw).to eq(I18n.t("staff_category_description"))
|
||||
expect(SiteSetting.staff_category_id).to eq(category.id)
|
||||
end
|
||||
|
||||
context "with existing category" do
|
||||
before { create_category }
|
||||
|
||||
it "does not create another category" do
|
||||
expect { create_category }
|
||||
.to change { Category.count }.by(0)
|
||||
.and change { Topic.count }.by(0)
|
||||
end
|
||||
|
||||
it "creates a missing 'About Category' topic" do
|
||||
category = Category.last
|
||||
Topic.delete(category.topic_id)
|
||||
|
||||
expect { create_category }
|
||||
.to change { Category.count }.by(0)
|
||||
.and change { Topic.count }.by(1)
|
||||
|
||||
category.reload
|
||||
expect(description_post(category).raw).to eq(I18n.t("staff_category_description"))
|
||||
end
|
||||
|
||||
it "overwrites permissions when permissions are forced" do
|
||||
category = Category.last
|
||||
category.set_permissions(everyone: :full)
|
||||
category.save!
|
||||
|
||||
expect(category.category_groups.count).to eq(0)
|
||||
|
||||
expect { create_category }
|
||||
.to change { CategoryGroup.count }.by(1)
|
||||
|
||||
category.reload
|
||||
expect(category.category_groups.count).to eq(1)
|
||||
expect(category.category_groups.first).to have_attributes(permissions(:staff, :full))
|
||||
end
|
||||
end
|
||||
|
||||
it "does not override permissions of existing category when not forced" do
|
||||
create_category("lounge_category_id")
|
||||
|
||||
category = Category.last
|
||||
category.set_permissions(trust_level_2: :full)
|
||||
category.save!
|
||||
|
||||
expect(category.category_groups.first).to have_attributes(permissions(:trust_level_2, :full))
|
||||
|
||||
expect { create_category("lounge_category_id") }
|
||||
.to change { CategoryGroup.count }.by(0)
|
||||
|
||||
category.reload
|
||||
expect(category.category_groups.first).to have_attributes(permissions(:trust_level_2, :full))
|
||||
end
|
||||
end
|
||||
|
||||
describe "#update" do
|
||||
def update_category(name = "staff_category_id", skip_changed: false)
|
||||
subject.update(site_setting_names: [name], skip_changed: skip_changed)
|
||||
end
|
||||
|
||||
before do
|
||||
create_category
|
||||
Category.last.update!(name: "Foo", slug: "foo")
|
||||
end
|
||||
|
||||
it "updates an existing category" do
|
||||
category = Category.last
|
||||
description_post(category).revise(Discourse.system_user, raw: "Description for Foo category.")
|
||||
|
||||
update_category
|
||||
|
||||
category.reload
|
||||
expect(category.name).to eq(I18n.t("staff_category_name"))
|
||||
expect(category.slug).to eq(Slug.for(I18n.t("staff_category_name")))
|
||||
expect(description_post(category).raw).to eq(I18n.t("staff_category_description"))
|
||||
end
|
||||
|
||||
it "skips category when `skip_changed` is true and description was changed" do
|
||||
category = Category.last
|
||||
description_post(category).revise(Fabricate(:admin), raw: "Description for Foo category.")
|
||||
|
||||
update_category(skip_changed: true)
|
||||
|
||||
category.reload
|
||||
expect(category.name).to eq("Foo")
|
||||
expect(category.slug).to eq("foo")
|
||||
expect(description_post(category).raw).to eq("Description for Foo category.")
|
||||
end
|
||||
|
||||
it "works when the category name is already used by another category" do
|
||||
Fabricate(:category, name: I18n.t("staff_category_name"))
|
||||
|
||||
update_category
|
||||
|
||||
category = Category.find(SiteSetting.staff_category_id)
|
||||
expect(category.name).to_not eq(I18n.t("staff_category_name"))
|
||||
expect(category.name).to start_with(I18n.t("staff_category_name"))
|
||||
end
|
||||
end
|
||||
|
||||
describe "#reseed_options" do
|
||||
it "returns only existing categories as options" do
|
||||
create_category("meta_category_id")
|
||||
create_category("lounge_category_id")
|
||||
Post.last.revise(Fabricate(:admin), raw: "Hello world")
|
||||
|
||||
expected_options = [
|
||||
{ id: "uncategorized_category_id", name: I18n.t("uncategorized_category_name"), selected: true },
|
||||
{ id: "meta_category_id", name: I18n.t("meta_category_name"), selected: true },
|
||||
{ id: "lounge_category_id", name: I18n.t("vip_category_name"), selected: false }
|
||||
]
|
||||
|
||||
expect(subject.reseed_options).to eq(expected_options)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,122 @@
|
|||
require 'rails_helper'
|
||||
require 'seed_data/topics'
|
||||
|
||||
describe SeedData::Topics do
|
||||
subject { SeedData::Topics.with_default_locale }
|
||||
|
||||
def create_topic(name = "welcome_topic_id")
|
||||
subject.create(site_setting_names: [name])
|
||||
end
|
||||
|
||||
describe "#create" do
|
||||
it "creates a missing topic" do
|
||||
expect { create_topic }
|
||||
.to change { Topic.count }.by(1)
|
||||
.and change { Post.count }.by(1)
|
||||
|
||||
topic = Topic.last
|
||||
expect(topic.title).to eq(I18n.t("discourse_welcome_topic.title"))
|
||||
expect(topic.first_post.raw).to eq(I18n.t('discourse_welcome_topic.body', base_path: Discourse.base_path).rstrip)
|
||||
expect(topic.category_id).to eq(SiteSetting.uncategorized_category_id)
|
||||
expect(topic.user_id).to eq(Discourse::SYSTEM_USER_ID)
|
||||
expect(topic.pinned_globally).to eq(true)
|
||||
expect(topic.pinned_at).to be_present
|
||||
expect(topic.pinned_until).to be_nil
|
||||
expect(SiteSetting.welcome_topic_id).to eq(topic.id)
|
||||
end
|
||||
|
||||
it "creates a missing topic and a reply when `static_first_reply` is true" do
|
||||
staff_category = Fabricate(:category, name: "Staff")
|
||||
SiteSetting.staff_category_id = staff_category.id
|
||||
|
||||
expect { create_topic("privacy_topic_id") }
|
||||
.to change { Topic.count }.by(1)
|
||||
.and change { Post.count }.by(2)
|
||||
|
||||
topic = Topic.last
|
||||
expect(topic.category_id).to eq(SiteSetting.staff_category_id)
|
||||
expect(topic.posts_count).to eq(2)
|
||||
expect(topic.pinned_globally).to eq(false)
|
||||
expect(topic.pinned_at).to be_nil
|
||||
expect(topic.pinned_until).to be_nil
|
||||
|
||||
post = Post.last
|
||||
expect(post.topic_id).to eq(topic.id)
|
||||
expect(post.user_id).to eq(Discourse::SYSTEM_USER_ID)
|
||||
expect(post.raw).to eq(I18n.t("static_topic_first_reply", page_name: topic.title).rstrip)
|
||||
end
|
||||
|
||||
it "does not create a topic when it already exists" do
|
||||
topic = Fabricate(:topic)
|
||||
SiteSetting.welcome_topic_id = topic.id
|
||||
|
||||
expect { create_topic }.to_not change { Topic.count }
|
||||
end
|
||||
|
||||
it "does not create a topic when the site setting points to non-existent topic" do
|
||||
SiteSetting.welcome_topic_id = (Topic.maximum(:id) || 0) + 1
|
||||
|
||||
expect { create_topic }.to_not change { Topic.count }
|
||||
end
|
||||
end
|
||||
|
||||
describe "#update" do
|
||||
def update_topic(name = "welcome_topic_id", skip_changed: false)
|
||||
subject.update(site_setting_names: [name], skip_changed: skip_changed)
|
||||
end
|
||||
|
||||
it "updates the changed topic" do
|
||||
create_topic
|
||||
|
||||
topic = Topic.last
|
||||
topic.update!(title: "New topic title")
|
||||
topic.first_post.revise(Discourse.system_user, raw: "New text of first post.")
|
||||
|
||||
update_topic
|
||||
topic.reload
|
||||
|
||||
expect(topic.title).to eq(I18n.t("discourse_welcome_topic.title"))
|
||||
expect(topic.first_post.raw).to eq(I18n.t('discourse_welcome_topic.body', base_path: Discourse.base_path).rstrip)
|
||||
end
|
||||
|
||||
it "updates an existing first reply when `static_first_reply` is true" do
|
||||
create_topic("privacy_topic_id")
|
||||
|
||||
post = Post.last
|
||||
post.revise(Discourse.system_user, raw: "New text of first reply.")
|
||||
|
||||
update_topic("privacy_topic_id")
|
||||
post.reload
|
||||
|
||||
expect(post.raw).to eq(I18n.t("static_topic_first_reply", page_name: I18n.t('privacy_topic.title')).rstrip)
|
||||
end
|
||||
|
||||
it "does not update a change topic and `skip_changed` is true" do
|
||||
create_topic
|
||||
|
||||
topic = Topic.last
|
||||
topic.update!(title: "New topic title")
|
||||
topic.first_post.revise(Fabricate(:admin), raw: "New text of first post.")
|
||||
|
||||
update_topic(skip_changed: true)
|
||||
|
||||
expect(topic.title).to eq("New topic title")
|
||||
expect(topic.first_post.raw).to eq("New text of first post.")
|
||||
end
|
||||
end
|
||||
|
||||
describe "#reseed_options" do
|
||||
it "returns only existing topics as options" do
|
||||
create_topic("guidelines_topic_id")
|
||||
create_topic("welcome_topic_id")
|
||||
Post.last.revise(Fabricate(:admin), title: "Changed Topic Title", raw: "Hello world")
|
||||
|
||||
expected_options = [
|
||||
{ id: "guidelines_topic_id", name: I18n.t("guidelines_topic.title"), selected: true },
|
||||
{ id: "welcome_topic_id", name: "Changed Topic Title", selected: false }
|
||||
]
|
||||
|
||||
expect(subject.reseed_options).to eq(expected_options)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -28,7 +28,11 @@ RSpec.describe Admin::SiteTextsController do
|
|||
put "/admin/customize/site_texts/some_key.json", params: {
|
||||
site_text: { value: 'foo' }
|
||||
}
|
||||
expect(response.status).to eq(404)
|
||||
|
||||
put "/admin/customize/reseed.json", params: {
|
||||
category_ids: [], topic_ids: []
|
||||
}
|
||||
expect(response.status).to eq(404)
|
||||
end
|
||||
end
|
||||
|
@ -243,5 +247,57 @@ RSpec.describe Admin::SiteTextsController do
|
|||
expect(json['site_text']['value']).to_not eq(ru_mf_text)
|
||||
end
|
||||
end
|
||||
|
||||
context "reseeding" do
|
||||
before do
|
||||
staff_category = Fabricate(
|
||||
:category,
|
||||
name: "Staff EN",
|
||||
user: Discourse.system_user
|
||||
)
|
||||
SiteSetting.staff_category_id = staff_category.id
|
||||
|
||||
guidelines_topic = Fabricate(
|
||||
:topic,
|
||||
title: "The English Guidelines",
|
||||
category: @staff_category,
|
||||
user: Discourse.system_user
|
||||
)
|
||||
Fabricate(:post, topic: guidelines_topic, user: Discourse.system_user)
|
||||
SiteSetting.guidelines_topic_id = guidelines_topic.id
|
||||
end
|
||||
|
||||
describe '#get_reseed_options' do
|
||||
it 'returns correct json' do
|
||||
get "/admin/customize/reseed.json"
|
||||
expect(response.status).to eq(200)
|
||||
|
||||
expected_reseed_options = {
|
||||
categories: [
|
||||
{ id: "uncategorized_category_id", name: I18n.t("uncategorized_category_name"), selected: true },
|
||||
{ id: "staff_category_id", name: "Staff EN", selected: true }
|
||||
],
|
||||
topics: [{ id: "guidelines_topic_id", name: "The English Guidelines", selected: true }]
|
||||
}
|
||||
|
||||
expect(JSON.parse(response.body, symbolize_names: true)).to eq(expected_reseed_options)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#reseed' do
|
||||
it 'reseeds categories and topics' do
|
||||
SiteSetting.default_locale = :de
|
||||
|
||||
post "/admin/customize/reseed.json", params: {
|
||||
category_ids: ["staff_category_id"],
|
||||
topic_ids: ["guidelines_topic_id"]
|
||||
}
|
||||
expect(response.status).to eq(200)
|
||||
|
||||
expect(Category.find(SiteSetting.staff_category_id).name).to eq(I18n.t("staff_category_name"))
|
||||
expect(Topic.find(SiteSetting.guidelines_topic_id).title).to eq(I18n.t("guidelines_topic.title"))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -13,7 +13,7 @@ QUnit.test("search for a key", async assert => {
|
|||
assert.ok(exists(".site-text.overridden"));
|
||||
|
||||
// Only show overridden
|
||||
await click(".extra-options input");
|
||||
await click(".search-area .filter-options input");
|
||||
assert.equal(
|
||||
currentURL(),
|
||||
"/admin/customize/site_texts?overridden=true&q=Test"
|
||||
|
|
Loading…
Reference in New Issue