Topic Featured Links: move data from custom fields to topics and categories tables. Invert behaviour of topic_featured_link_allowed checkbox. Fix a bug with invalid topic records due to changing that category checkbox.

This commit is contained in:
Neil Lalonde 2016-12-15 17:46:43 -05:00
parent a2096a01fb
commit 923cf73c6e
17 changed files with 77 additions and 71 deletions

View File

@ -100,7 +100,8 @@ const Category = RestModel.extend({
allowed_tags: this.get('allowed_tags'), allowed_tags: this.get('allowed_tags'),
allowed_tag_groups: this.get('allowed_tag_groups'), allowed_tag_groups: this.get('allowed_tag_groups'),
sort_order: this.get('sort_order'), sort_order: this.get('sort_order'),
sort_ascending: this.get('sort_ascending') sort_ascending: this.get('sort_ascending'),
topic_featured_link_allowed: this.get('topic_featured_link_allowed')
}, },
type: id ? 'PUT' : 'POST' type: id ? 'PUT' : 'POST'
}); });
@ -169,18 +170,6 @@ const Category = RestModel.extend({
@computed("id") @computed("id")
isUncategorizedCategory(id) { isUncategorizedCategory(id) {
return id === Discourse.Site.currentProp("uncategorized_category_id"); return id === Discourse.Site.currentProp("uncategorized_category_id");
},
@computed('custom_fields.topic_featured_link_allowed')
topicFeaturedLinkAllowed: {
get(allowed) {
return allowed === "true";
},
set(value) {
value = value ? "true" : "false";
this.set("custom_fields.topic_featured_link_allowed", value);
return value;
}
} }
}); });

View File

@ -114,7 +114,8 @@ const DiscoveryCategoriesRoute = Discourse.Route.extend(OpenComposer, {
const model = this.store.createRecord('category', { const model = this.store.createRecord('category', {
color: "AB9364", text_color: "FFFFFF", group_permissions: [{group_name: everyoneName, permission_type: 1}], color: "AB9364", text_color: "FFFFFF", group_permissions: [{group_name: everyoneName, permission_type: 1}],
available_groups: groups.map(g => g.name), available_groups: groups.map(g => g.name),
allow_badges: true allow_badges: true,
topic_featured_link_allowed: true
}); });
showModal("edit-category", { model }); showModal("edit-category", { model });

View File

@ -23,7 +23,7 @@
<section class='field'> <section class='field'>
<div class="allowed-topic-featured-link-category"> <div class="allowed-topic-featured-link-category">
<label class="checkbox-label"> <label class="checkbox-label">
{{input type="checkbox" checked=category.topicFeaturedLinkAllowed}} {{input type="checkbox" checked=category.topic_featured_link_allowed}}
{{i18n 'category.topic_featured_link_allowed'}} {{i18n 'category.topic_featured_link_allowed'}}
</label> </label>
</div> </div>

View File

@ -240,6 +240,7 @@ class CategoriesController < ApplicationController
:topic_template, :topic_template,
:sort_order, :sort_order,
:sort_ascending, :sort_ascending,
:topic_featured_link_allowed,
:custom_fields => [params[:custom_fields].try(:keys)], :custom_fields => [params[:custom_fields].try(:keys)],
:permissions => [*p.try(:keys)], :permissions => [*p.try(:keys)],
:allowed_tags => [], :allowed_tags => [],

View File

@ -0,0 +1,28 @@
module Jobs
class MigrateFeaturedLinks < Jobs::Onceoff
def execute_onceoff(args)
TopicCustomField.where(name: "featured_link").find_each do |tcf|
if tcf.value.present?
Topic.where(id: tcf.topic_id).update_all(featured_link: tcf.value)
end
end
# Plugin behaviour: only categories explicitly allowed to have featured links can have them.
# All others implicitly DO NOT allow them.
# If no categories were explicitly allowed to have them, then all implicitly DID allow them.
allowed = CategoryCustomField.where(name: "topic_featured_link_allowed").where(value: "true").pluck(:category_id)
if !allowed.empty?
# all others are not allowed
Category.where.not(id: allowed).update_all(topic_featured_link_allowed: false)
else
not_allowed = CategoryCustomField.where(name: "topic_featured_link_allowed").where.not(value: "true").pluck(:category_id)
Category.where(id: not_allowed).update_all(topic_featured_link_allowed: false)
end
end
end
end

View File

@ -7,7 +7,6 @@ require_dependency 'text_cleaner'
require_dependency 'archetype' require_dependency 'archetype'
require_dependency 'html_prettify' require_dependency 'html_prettify'
require_dependency 'discourse_tagging' require_dependency 'discourse_tagging'
require_dependency 'discourse_featured_link'
class Topic < ActiveRecord::Base class Topic < ActiveRecord::Base
include ActionView::Helpers::SanitizeHelper include ActionView::Helpers::SanitizeHelper
@ -76,11 +75,12 @@ class Topic < ActiveRecord::Base
validates :featured_link, allow_nil: true, format: URI::regexp(%w(http https)) validates :featured_link, allow_nil: true, format: URI::regexp(%w(http https))
validate if: :featured_link do validate if: :featured_link do
errors.add(:featured_link, :invalid_category) unless Guardian.new.can_edit_featured_link?(category_id) errors.add(:featured_link, :invalid_category) unless !featured_link_changed? || Guardian.new.can_edit_featured_link?(category_id)
end end
before_validation do before_validation do
self.title = TextCleaner.clean_title(TextSentinel.title_sentinel(title).text) if errors[:title].empty? self.title = TextCleaner.clean_title(TextSentinel.title_sentinel(title).text) if errors[:title].empty?
self.featured_link.strip! if self.featured_link
end end
belongs_to :category belongs_to :category
@ -383,14 +383,6 @@ class Topic < ActiveRecord::Base
featured_topic_ids ? topics.where("topics.id NOT IN (?)", featured_topic_ids) : topics featured_topic_ids ? topics.where("topics.id NOT IN (?)", featured_topic_ids) : topics
end end
def featured_link
custom_fields[DiscourseFeaturedLink::CUSTOM_FIELD_NAME]
end
def featured_link=(link)
custom_fields[DiscourseFeaturedLink::CUSTOM_FIELD_NAME] = link.strip
end
def meta_data=(data) def meta_data=(data)
custom_fields.replace(data) custom_fields.replace(data)
end end

View File

@ -1,5 +1,4 @@
require_dependency 'avatar_lookup' require_dependency 'avatar_lookup'
require_dependency 'discourse_featured_link'
class TopicList class TopicList
include ActiveModel::Serialization include ActiveModel::Serialization
@ -28,7 +27,6 @@ class TopicList
end end
preloaded_custom_fields << DiscourseTagging::TAGS_FIELD_NAME if SiteSetting.tagging_enabled preloaded_custom_fields << DiscourseTagging::TAGS_FIELD_NAME if SiteSetting.tagging_enabled
preloaded_custom_fields << DiscourseFeaturedLink::CUSTOM_FIELD_NAME if SiteSetting.topic_featured_link_enabled
end end
def tags def tags

View File

@ -15,7 +15,8 @@ class CategorySerializer < BasicCategorySerializer
:allow_badges, :allow_badges,
:custom_fields, :custom_fields,
:allowed_tags, :allowed_tags,
:allowed_tag_groups :allowed_tag_groups,
:topic_featured_link_allowed
def group_permissions def group_permissions
@group_permissions ||= begin @group_permissions ||= begin

View File

@ -1909,7 +1909,7 @@ en:
tags_allowed_tag_groups: "Tag groups that can only be used in this category:" tags_allowed_tag_groups: "Tag groups that can only be used in this category:"
tags_placeholder: "(Optional) list of allowed tags" tags_placeholder: "(Optional) list of allowed tags"
tag_groups_placeholder: "(Optional) list of allowed tag groups" tag_groups_placeholder: "(Optional) list of allowed tag groups"
topic_featured_link_allowed: "Restricts editing the topic featured link in this category. Require site setting topic_featured_link_enabled is checked." topic_featured_link_allowed: "Allow featured links in this category"
delete: 'Delete Category' delete: 'Delete Category'
create: 'New Category' create: 'New Category'
create_long: 'Create a new category' create_long: 'Create a new category'

View File

@ -0,0 +1,6 @@
class MigrateFeaturedLinkFields < ActiveRecord::Migration
def change
add_column :topics, :featured_link, :string
add_column :categories, :topic_featured_link_allowed, :boolean, default: true
end
end

View File

@ -1,27 +0,0 @@
module DiscourseFeaturedLink
CUSTOM_FIELD_NAME = 'featured_link'.freeze
AdminDashboardData::GLOBAL_REPORTS << CUSTOM_FIELD_NAME
Report.add_report(CUSTOM_FIELD_NAME) do |report|
report.data = []
link_topics = TopicCustomField.where(name: CUSTOM_FIELD_NAME)
link_topics = link_topics.joins(:topic).where("topics.category_id = ?", report.category_id) if report.category_id
link_topics.where("topic_custom_fields.created_at >= ?", report.start_date)
.where("topic_custom_fields.created_at <= ?", report.end_date)
.group("DATE(topic_custom_fields.created_at)")
.order("DATE(topic_custom_fields.created_at)")
.count
.each { |date, count| report.data << { x: date, y: count } }
report.total = link_topics.count
report.prev30Days = link_topics.where("topic_custom_fields.created_at >= ?", report.start_date - 30.days)
.where("topic_custom_fields.created_at <= ?", report.start_date)
.count
end
def self.cache_onebox_link(link)
# If the link is pasted swiftly, onebox may not have time to cache it
Oneboxer.onebox(link, invalidate_oneboxes: false)
link
end
end

View File

@ -70,7 +70,6 @@ module CategoryGuardian
end end
def topic_featured_link_allowed_category_ids def topic_featured_link_allowed_category_ids
@topic_featured_link_allowed_category_ids = CategoryCustomField.where(name: "topic_featured_link_allowed", value: "true") @topic_featured_link_allowed_category_ids = Category.where(topic_featured_link_allowed: true).pluck(:id)
.pluck(:category_id)
end end
end end

View File

@ -106,8 +106,8 @@ module TopicGuardian
end end
def can_edit_featured_link?(category_id) def can_edit_featured_link?(category_id)
SiteSetting.topic_featured_link_enabled && return false unless SiteSetting.topic_featured_link_enabled
(topic_featured_link_allowed_category_ids.empty? || # no per category restrictions return !Category.where(topic_featured_link_allowed: false).exists? unless category_id # uncategorized
category_id && topic_featured_link_allowed_category_ids.include?(category_id.to_i)) # category restriction exists Category.where(id: category_id, topic_featured_link_allowed: true).exists?
end end
end end

View File

@ -5,7 +5,6 @@ require_dependency 'topic_creator'
require_dependency 'post_jobs_enqueuer' require_dependency 'post_jobs_enqueuer'
require_dependency 'distributed_mutex' require_dependency 'distributed_mutex'
require_dependency 'has_errors' require_dependency 'has_errors'
require_dependency 'discourse_featured_link'
class PostCreator class PostCreator
include HasErrors include HasErrors

View File

@ -2285,20 +2285,28 @@ describe Guardian do
before { SiteSetting.topic_featured_link_enabled = true } before { SiteSetting.topic_featured_link_enabled = true }
let(:guardian) { Guardian.new } let(:guardian) { Guardian.new }
it 'returns true if no category restricts editing link' do context "uncategorized" do
let!(:link_category) { Fabricate(:link_category) }
it "allows featured links if no categories forbid it" do
expect(guardian.can_edit_featured_link?(nil)).to eq(true) expect(guardian.can_edit_featured_link?(nil)).to eq(true)
expect(guardian.can_edit_featured_link?(5)).to eq(true) end
it "forbids featured links if a category forbids it" do
Fabricate(:category, topic_featured_link_allowed: false)
expect(guardian.can_edit_featured_link?(nil)).to eq(false)
end
end end
context 'when exist' do context 'when exist' do
let!(:category) { Fabricate(:category) } let!(:category) { Fabricate(:category, topic_featured_link_allowed: false) }
let!(:link_category) { Fabricate(:link_category) } let!(:link_category) { Fabricate(:link_category) }
it 'returns true if the category is listed' do it 'returns true if the category is listed' do
expect(guardian.can_edit_featured_link?(link_category.id)).to eq(true) expect(guardian.can_edit_featured_link?(link_category.id)).to eq(true)
end end
it 'returns false if the category is not listed' do it 'returns false if the category does not allow it' do
expect(guardian.can_edit_featured_link?(category.id)).to eq(false) expect(guardian.can_edit_featured_link?(category.id)).to eq(false)
end end
end end

View File

@ -27,5 +27,5 @@ Fabricator(:private_category, from: :category) do
end end
Fabricator(:link_category, from: :category) do Fabricator(:link_category, from: :category) do
before_validation { |category, transients| category.custom_fields['topic_featured_link_allowed'] = 'true' } before_validation { |category, transients| category.topic_featured_link_allowed = true }
end end

View File

@ -1755,7 +1755,7 @@ describe Topic do
topic.featured_link = ' https://github.com/discourse/discourse' topic.featured_link = ' https://github.com/discourse/discourse'
expect(topic.save).to be_truthy expect(topic.save).to be_truthy
expect(topic.custom_fields['featured_link']).to eq('https://github.com/discourse/discourse') expect(topic.featured_link).to eq('https://github.com/discourse/discourse')
end end
context 'when category restricts present' do context 'when category restricts present' do
@ -1766,13 +1766,24 @@ describe Topic do
it 'can save the featured link if it belongs to that category' do it 'can save the featured link if it belongs to that category' do
link_topic.featured_link = 'https://github.com/discourse/discourse' link_topic.featured_link = 'https://github.com/discourse/discourse'
expect(link_topic.save).to be_truthy expect(link_topic.save).to be_truthy
expect(link_topic.custom_fields['featured_link']).to eq('https://github.com/discourse/discourse') expect(link_topic.featured_link).to eq('https://github.com/discourse/discourse')
end end
it 'can not save the featured link if it belongs to that category' do it 'can not save the featured link if category does not allow it' do
topic.category = Fabricate(:category, topic_featured_link_allowed: false)
topic.featured_link = 'https://github.com/discourse/discourse' topic.featured_link = 'https://github.com/discourse/discourse'
expect(topic.save).to be_falsey expect(topic.save).to be_falsey
end end
it 'if category changes to disallow it, topic remains valid' do
t = Fabricate(:topic, category: link_category, featured_link: "https://github.com/discourse/discourse")
link_category.topic_featured_link_allowed = false
link_category.save!
t.reload
expect(t.valid?).to eq(true)
end
end end
end end
end end