mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-11-23 23:58:31 -05:00
UI still a tad rough, but we have a first pass of secure categories
This commit is contained in:
parent
4030722a8f
commit
942f168ab6
16 changed files with 127 additions and 42 deletions
|
@ -9,7 +9,7 @@
|
||||||
<li>{{#linkTo 'adminSiteContents'}}{{i18n admin.site_content.title}}{{/linkTo}}</li>
|
<li>{{#linkTo 'adminSiteContents'}}{{i18n admin.site_content.title}}{{/linkTo}}</li>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<li>{{#linkTo 'adminUsersList.active'}}{{i18n admin.users.title}}{{/linkTo}}</li>
|
<li>{{#linkTo 'adminUsersList.active'}}{{i18n admin.users.title}}{{/linkTo}}</li>
|
||||||
<!--<li>{{#linkTo 'admin.groups'}}{{i18n admin.groups.title}}{{/linkTo}}</li>-->
|
<li>{{#linkTo 'admin.groups'}}{{i18n admin.groups.title}}{{/linkTo}}</li>
|
||||||
<li>{{#linkTo 'admin.email_logs'}}{{i18n admin.email_logs.title}}{{/linkTo}}</li>
|
<li>{{#linkTo 'admin.email_logs'}}{{i18n admin.email_logs.title}}{{/linkTo}}</li>
|
||||||
<li>{{#linkTo 'adminFlags.active'}}{{i18n admin.flags.title}}{{/linkTo}}</li>
|
<li>{{#linkTo 'adminFlags.active'}}{{i18n admin.flags.title}}{{/linkTo}}</li>
|
||||||
{{#if Discourse.currentUser.admin}}
|
{{#if Discourse.currentUser.admin}}
|
||||||
|
|
|
@ -15,6 +15,9 @@ Discourse.Category = Discourse.Model.extend({
|
||||||
if (!this.get('color')) this.set('color', Discourse.SiteSettings.uncategorized_color);
|
if (!this.get('color')) this.set('color', Discourse.SiteSettings.uncategorized_color);
|
||||||
if (!this.get('text_color')) this.set('text_color', Discourse.SiteSettings.uncategorized_text_color);
|
if (!this.get('text_color')) this.set('text_color', Discourse.SiteSettings.uncategorized_text_color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.set("availableGroups", Em.A(this.get("available_groups")));
|
||||||
|
this.set("groups", Em.A(this.groups));
|
||||||
},
|
},
|
||||||
|
|
||||||
url: function() {
|
url: function() {
|
||||||
|
@ -40,7 +43,9 @@ Discourse.Category = Discourse.Model.extend({
|
||||||
name: this.get('name'),
|
name: this.get('name'),
|
||||||
color: this.get('color'),
|
color: this.get('color'),
|
||||||
text_color: this.get('text_color'),
|
text_color: this.get('text_color'),
|
||||||
hotness: this.get('hotness')
|
hotness: this.get('hotness'),
|
||||||
|
secure: this.get('secure'),
|
||||||
|
group_names: this.get('groups').join(",")
|
||||||
},
|
},
|
||||||
type: this.get('id') ? 'PUT' : 'POST'
|
type: this.get('id') ? 'PUT' : 'POST'
|
||||||
});
|
});
|
||||||
|
@ -48,6 +53,17 @@ Discourse.Category = Discourse.Model.extend({
|
||||||
|
|
||||||
destroy: function(callback) {
|
destroy: function(callback) {
|
||||||
return Discourse.ajax("/categories/" + (this.get('slug') || this.get('id')), { type: 'DELETE' });
|
return Discourse.ajax("/categories/" + (this.get('slug') || this.get('id')), { type: 'DELETE' });
|
||||||
|
},
|
||||||
|
|
||||||
|
addGroup: function(group){
|
||||||
|
this.get("groups").addObject(group);
|
||||||
|
this.get("availableGroups").removeObject(group);
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
removeGroup: function(group){
|
||||||
|
this.get("groups").removeObject(group);
|
||||||
|
this.get("availableGroups").addObject(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -23,10 +23,30 @@
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section class='field'>
|
||||||
|
<label>{{i18n category.security}}</label>
|
||||||
|
<label>
|
||||||
|
{{view Ember.Checkbox checkedBinding="secure"}}
|
||||||
|
{{i18n category.is_secure}}
|
||||||
|
</label>
|
||||||
|
{{#if secure}}
|
||||||
|
<div>
|
||||||
|
{{i18n category.allowed_groups}}
|
||||||
|
{{#each groups}}
|
||||||
|
{{this}} <a {{action removeGroup this target="view"}}>x</a>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
{{view Ember.Select contentBinding="availableGroups" valueBinding="view.selectedGroup"}}
|
||||||
|
<button {{action addGroup target="view"}}>{{i18n category.add_group}}</button>
|
||||||
|
{{/if}}
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Sam, disabled for now
|
||||||
<section class='field'>
|
<section class='field'>
|
||||||
<label>{{i18n category.hotness}}</label>
|
<label>{{i18n category.hotness}}</label>
|
||||||
{{view Discourse.HotnessView hotnessBinding="hotness"}}
|
{{view Discourse.HotnessView hotnessBinding="hotness"}}
|
||||||
</section>
|
</section>
|
||||||
|
-->
|
||||||
{{/unless}}
|
{{/unless}}
|
||||||
|
|
||||||
<section class='field'>
|
<section class='field'>
|
||||||
|
@ -58,4 +78,4 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{/with}}
|
{{/with}}
|
||||||
|
|
|
@ -93,6 +93,16 @@ Discourse.EditCategoryView = Discourse.ModalBodyView.extend({
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
addGroup: function(){
|
||||||
|
this.get("category").addGroup(this.get("selectedGroup"));
|
||||||
|
},
|
||||||
|
|
||||||
|
removeGroup: function(group){
|
||||||
|
// OBVIOUS, Ember treats this as Ember.String, we need a real string here
|
||||||
|
group = group + "";
|
||||||
|
this.get("category").removeGroup(group);
|
||||||
|
},
|
||||||
|
|
||||||
saveCategory: function() {
|
saveCategory: function() {
|
||||||
var categoryView = this;
|
var categoryView = this;
|
||||||
this.set('saving', true);
|
this.set('saving', true);
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
padding-top: 4px;
|
padding-top: 4px;
|
||||||
padding-left: 15px;
|
padding-left: 15px;
|
||||||
max-width: 320px;
|
max-width: 300px;
|
||||||
|
|
||||||
.colorpicker {
|
.colorpicker {
|
||||||
border: 1px solid $darkish_gray;
|
border: 1px solid $darkish_gray;
|
||||||
|
|
|
@ -265,7 +265,6 @@ body {
|
||||||
}
|
}
|
||||||
select, textarea {
|
select, textarea {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
height: 18px;
|
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
margin-bottom: 9px;
|
margin-bottom: 9px;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
|
|
@ -48,7 +48,7 @@ class CategoriesController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def category_param_keys
|
def category_param_keys
|
||||||
[required_param_keys, :hotness].flatten!
|
[required_param_keys, :hotness, :secure, :group_names].flatten!
|
||||||
end
|
end
|
||||||
|
|
||||||
def category_params
|
def category_params
|
||||||
|
|
|
@ -92,7 +92,7 @@ class PostsController < ApplicationController
|
||||||
|
|
||||||
result = {post: post_serializer.as_json}
|
result = {post: post_serializer.as_json}
|
||||||
if revisor.category_changed.present?
|
if revisor.category_changed.present?
|
||||||
result[:category] = CategorySerializer.new(revisor.category_changed, scope: guardian, root: false).as_json
|
result[:category] = BasicCategorySerializer.new(revisor.category_changed, scope: guardian, root: false).as_json
|
||||||
end
|
end
|
||||||
|
|
||||||
render_json_dump(result)
|
render_json_dump(result)
|
||||||
|
|
|
@ -99,6 +99,15 @@ class Category < ActiveRecord::Base
|
||||||
self.secure
|
self.secure
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def group_names=(names)
|
||||||
|
# this line bothers me, destroying in AR can not seem to be queued, thinking of extending it
|
||||||
|
category_groups.destroy_all unless new_record?
|
||||||
|
ids = Group.where(name: names.split(",")).select(:id).map(&:id)
|
||||||
|
ids.each do |id|
|
||||||
|
category_groups.build(group_id: id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def deny(group)
|
def deny(group)
|
||||||
if group == :all
|
if group == :all
|
||||||
self.secure = true
|
self.secure = true
|
||||||
|
@ -108,7 +117,8 @@ class Category < ActiveRecord::Base
|
||||||
def allow(group)
|
def allow(group)
|
||||||
if group == :all
|
if group == :all
|
||||||
self.secure = false
|
self.secure = false
|
||||||
category_groups.clear
|
# this is kind of annoying, there should be a clean way of queuing this stuff
|
||||||
|
category_groups.destroy_all unless new_record?
|
||||||
else
|
else
|
||||||
groups.push(group)
|
groups.push(group)
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,7 +9,15 @@ class CategoryList
|
||||||
.includes(:featured_users)
|
.includes(:featured_users)
|
||||||
.where('topics.visible' => true)
|
.where('topics.visible' => true)
|
||||||
.order('categories.topics_week desc, categories.topics_month desc, categories.topics_year desc')
|
.order('categories.topics_week desc, categories.topics_month desc, categories.topics_year desc')
|
||||||
.to_a
|
|
||||||
|
allowed_ids = current_user ? current_user.secure_category_ids : nil
|
||||||
|
if allowed_ids.present?
|
||||||
|
@categories = @categories.where("categories.secure = 'f' OR categories.id in (?)", allowed_ids)
|
||||||
|
else
|
||||||
|
@categories = @categories.where("categories.secure = 'f'")
|
||||||
|
end
|
||||||
|
|
||||||
|
@categories = @categories.to_a
|
||||||
|
|
||||||
# Support for uncategorized topics
|
# Support for uncategorized topics
|
||||||
uncategorized_topics = Topic
|
uncategorized_topics = Topic
|
||||||
|
|
|
@ -564,7 +564,7 @@ class User < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
def secure_category_ids
|
def secure_category_ids
|
||||||
cats = self.moderator? ? Category.select(:id).where(:secure, true) : secure_categories.select('categories.id')
|
cats = self.staff? ? Category.select(:id).where(secure: true) : secure_categories.select('categories.id')
|
||||||
cats.map{|c| c.id}
|
cats.map{|c| c.id}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
13
app/serializers/basic_category_serializer.rb
Normal file
13
app/serializers/basic_category_serializer.rb
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
class BasicCategorySerializer < ApplicationSerializer
|
||||||
|
|
||||||
|
attributes :id,
|
||||||
|
:name,
|
||||||
|
:color,
|
||||||
|
:text_color,
|
||||||
|
:slug,
|
||||||
|
:topic_count,
|
||||||
|
:description,
|
||||||
|
:topic_url,
|
||||||
|
:hotness
|
||||||
|
|
||||||
|
end
|
|
@ -1,13 +1,13 @@
|
||||||
class CategorySerializer < ApplicationSerializer
|
class CategorySerializer < BasicCategorySerializer
|
||||||
|
|
||||||
attributes :id,
|
attributes :secure, :groups, :available_groups
|
||||||
:name,
|
|
||||||
:color,
|
def groups
|
||||||
:text_color,
|
@groups ||= object.groups.order("name").all.map(&:name)
|
||||||
:slug,
|
end
|
||||||
:topic_count,
|
|
||||||
:description,
|
def available_groups
|
||||||
:topic_url,
|
Group.order("name").map(&:name) - groups
|
||||||
:hotness
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -758,6 +758,11 @@ en:
|
||||||
change_in_category_topic: "Edit Description"
|
change_in_category_topic: "Edit Description"
|
||||||
hotness: "Hotness"
|
hotness: "Hotness"
|
||||||
already_used: 'This color has been used by another category'
|
already_used: 'This color has been used by another category'
|
||||||
|
is_secure: "Secure category?"
|
||||||
|
add_group: "Add Group"
|
||||||
|
security: "Security"
|
||||||
|
allowed_groups: "Allowed Groups:"
|
||||||
|
|
||||||
|
|
||||||
flagging:
|
flagging:
|
||||||
title: 'Why are you flagging this post?'
|
title: 'Why are you flagging this post?'
|
||||||
|
|
|
@ -16,23 +16,11 @@ describe CategoryList do
|
||||||
let!(:topic) { Fabricate(:topic)}
|
let!(:topic) { Fabricate(:topic)}
|
||||||
let(:category) { category_list.categories.first }
|
let(:category) { category_list.categories.first }
|
||||||
|
|
||||||
it "has a category" do
|
it "has the right category" do
|
||||||
category.should be_present
|
category.should be_present
|
||||||
end
|
|
||||||
|
|
||||||
it "has the uncategorized label" do
|
|
||||||
category.name.should == SiteSetting.uncategorized_name
|
category.name.should == SiteSetting.uncategorized_name
|
||||||
end
|
|
||||||
|
|
||||||
it "has the uncategorized slug" do
|
|
||||||
category.slug.should == SiteSetting.uncategorized_name
|
category.slug.should == SiteSetting.uncategorized_name
|
||||||
end
|
|
||||||
|
|
||||||
it "has one topic this week" do
|
|
||||||
category.topics_week.should == 1
|
category.topics_week.should == 1
|
||||||
end
|
|
||||||
|
|
||||||
it "contains the topic in featured_topics" do
|
|
||||||
category.featured_topics.should == [topic]
|
category.featured_topics.should == [topic]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -40,6 +28,23 @@ describe CategoryList do
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "security" do
|
||||||
|
it "properly hide secure categories" do
|
||||||
|
admin = Fabricate(:admin)
|
||||||
|
user = Fabricate(:user)
|
||||||
|
|
||||||
|
cat = Fabricate(:category)
|
||||||
|
topic = Fabricate(:topic, category: cat)
|
||||||
|
cat.deny(:all)
|
||||||
|
cat.allow(Group[:admins])
|
||||||
|
cat.save
|
||||||
|
|
||||||
|
CategoryList.new(admin).categories.count.should == 1
|
||||||
|
CategoryList.new(user).categories.count.should == 0
|
||||||
|
CategoryList.new(nil).categories.count.should == 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context "with a category" do
|
context "with a category" do
|
||||||
|
|
||||||
let!(:topic_category) { Fabricate(:category) }
|
let!(:topic_category) { Fabricate(:category) }
|
||||||
|
|
|
@ -134,22 +134,21 @@ describe CategoriesController do
|
||||||
|
|
||||||
describe 'success' do
|
describe 'success' do
|
||||||
before do
|
before do
|
||||||
xhr :put, :update, id: @category.id, name: 'science', color: '000', text_color: '0ff'
|
# might as well test this as well
|
||||||
|
@category.allow(Group[:admins])
|
||||||
|
@category.save
|
||||||
|
|
||||||
|
xhr :put, :update, id: @category.id, name: 'science', color: '000', text_color: '0ff', group_names: Group[:staff].name, secure: 'true'
|
||||||
@category.reload
|
@category.reload
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'updates the name' do
|
it 'updates the group correctly' do
|
||||||
@category.name.should == 'science'
|
@category.name.should == 'science'
|
||||||
end
|
|
||||||
|
|
||||||
it 'updates the color' do
|
|
||||||
@category.color.should == '000'
|
@category.color.should == '000'
|
||||||
end
|
|
||||||
|
|
||||||
it 'updates the text color' do
|
|
||||||
@category.text_color.should == '0ff'
|
@category.text_color.should == '0ff'
|
||||||
|
@category.secure?.should be_true
|
||||||
|
@category.groups.count.should == 1
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue