diff --git a/app/assets/javascripts/discourse/controllers/edit_category_controller.js b/app/assets/javascripts/discourse/controllers/edit_category_controller.js
index 2035fa4a5..5786c0cbe 100644
--- a/app/assets/javascripts/discourse/controllers/edit_category_controller.js
+++ b/app/assets/javascripts/discourse/controllers/edit_category_controller.js
@@ -101,14 +101,12 @@ Discourse.EditCategoryController = Discourse.ObjectController.extend(Discourse.M
return false;
},
- addGroup: function(){
- this.get('model').addGroup(this.get("selectedGroup"));
+ addPermission: function(group, permission_id){
+ this.get('model').addPermission({group_name: group + "", permission: Discourse.PermissionType.create({id: permission_id})});
},
- removeGroup: function(group){
- // OBVIOUS, Ember treats this as Ember.String, we need a real string here
- group = group + "";
- this.get('model').removeGroup(group);
+ removePermission: function(permission){
+ this.get('model').removePermission(permission);
},
saveCategory: function() {
diff --git a/app/assets/javascripts/discourse/models/category.js b/app/assets/javascripts/discourse/models/category.js
index b7d755cca..4c63b01ce 100644
--- a/app/assets/javascripts/discourse/models/category.js
+++ b/app/assets/javascripts/discourse/models/category.js
@@ -11,9 +11,21 @@ Discourse.Category = Discourse.Model.extend({
init: function() {
this._super();
this.set("availableGroups", Em.A(this.get("available_groups")));
- this.set("groups", Em.A(this.groups));
+ this.set("permissions", Em.A(_.map(this.group_permissions, function(elem){
+ return {
+ group_name: elem.group_name,
+ permission: Discourse.PermissionType.create({id: elem.permission_type})
+ };
+ })));
},
+ availablePermissions: function(){
+ return [ Discourse.PermissionType.create({id: Discourse.PermissionType.FULL}),
+ Discourse.PermissionType.create({id: Discourse.PermissionType.CREATE_POST}),
+ Discourse.PermissionType.create({id: Discourse.PermissionType.READONLY})
+ ];
+ }.property(),
+
searchContext: function() {
return ({ type: 'category', id: this.get('id'), category: this });
}.property('id'),
@@ -37,15 +49,20 @@ Discourse.Category = Discourse.Model.extend({
}
return Discourse.ajax(url, {
- data: {
+ contentType: 'application/json',
+ dataType: 'json',
+ data: JSON.stringify({
name: this.get('name'),
color: this.get('color'),
text_color: this.get('text_color'),
hotness: this.get('hotness'),
secure: this.get('secure'),
- group_names: this.get('groups').join(","),
+ permissions: _.map(
+ this.get('permissions'), function(p){
+ return { group_name: p.group_name, permission_type: p.permission.id};
+ }),
auto_close_days: this.get('auto_close_days')
- },
+ }),
type: this.get('id') ? 'PUT' : 'POST'
});
},
@@ -54,22 +71,30 @@ Discourse.Category = Discourse.Model.extend({
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);
+ addPermission: function(permission){
+ this.get("permissions").addObject(permission);
+ this.get("availableGroups").removeObject(permission.group_name);
},
- removeGroup: function(group){
- this.get("groups").removeObject(group);
- this.get("availableGroups").addObject(group);
+ removePermission: function(permission){
+ this.get("permissions").removeObject(permission);
+ this.get("availableGroups").addObject(permission.group_name);
},
// note, this is used in a data attribute, data attributes get downcased
// to avoid confusion later on using this naming here.
description_text: function(){
return $("
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index fc1f7ef2c..0b1bdc7ca 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -102,7 +102,7 @@ class ApplicationController < ActionController::Base
guardian.current_user.sync_notification_channel_position
end
- store_preloaded("site", Site.cached_json(current_user))
+ store_preloaded("site", Site.cached_json(guardian))
if current_user.present?
store_preloaded("currentUser", MultiJson.dump(CurrentUserSerializer.new(current_user, root: false)))
diff --git a/app/controllers/categories_controller.rb b/app/controllers/categories_controller.rb
index 65256a617..de5c1e833 100644
--- a/app/controllers/categories_controller.rb
+++ b/app/controllers/categories_controller.rb
@@ -53,7 +53,7 @@ class CategoriesController < ApplicationController
end
def category_param_keys
- [required_param_keys, :hotness, :secure, :group_names, :auto_close_days].flatten!
+ [required_param_keys, :hotness, :read_restricted, :permissions, :auto_close_days].flatten!
end
def category_params
diff --git a/app/models/category.rb b/app/models/category.rb
index 85943642c..d4a7594ef 100644
--- a/app/models/category.rb
+++ b/app/models/category.rb
@@ -22,6 +22,7 @@ class Category < ActiveRecord::Base
before_validation :ensure_slug
after_save :invalidate_site_cache
+ before_save :apply_permissions
after_create :create_category_definition
after_create :publish_categories_list
after_destroy :invalidate_site_cache
@@ -34,16 +35,49 @@ class Category < ActiveRecord::Base
scope :secured, ->(guardian = nil) {
ids = guardian.secure_category_ids if guardian
if ids.present?
- where("NOT categories.secure or categories.id in (:cats)", cats: ids)
+ where("NOT categories.read_restricted or categories.id in (:cats)", cats: ids)
else
- where("NOT categories.secure")
+ where("NOT categories.read_restricted")
end
}
+ scope :topic_create_allowed, ->(guardian) {
+ scoped_to_permissions(guardian, [:full])
+ }
+
+ scope :post_create_allowed, ->(guardian) {
+ scoped_to_permissions(guardian, [:create_post, :full])
+ }
delegate :post_template, to: 'self.class'
attr_accessor :displayable_topics
+
+ def self.scoped_to_permissions(guardian, permission_types)
+ if guardian && guardian.is_staff?
+ scoped
+ else
+ permission_types = permission_types.map{ |permission_type|
+ CategoryGroup.permission_types[permission_type]
+ }
+ where("categories.id in (
+ SELECT c.id FROM categories c
+ WHERE (
+ NOT c.read_restricted AND
+ NOT EXISTS(
+ SELECT 1 FROM category_groups cg WHERE cg.category_id = categories.id )
+ ) OR EXISTS(
+ SELECT 1 FROM category_groups cg
+ WHERE permission_type in (?) AND
+ cg.category_id = categories.id AND
+ group_id IN (
+ SELECT g.group_id FROM group_users g where g.user_id = ?
+ )
+ )
+ )", permission_types,(!guardian || guardian.user.blank?) ? -1 : guardian.user.id)
+ end
+ end
+
# Internal: Update category stats: # of topics in past year, month, week for
# all categories.
def self.update_stats
@@ -119,28 +153,65 @@ class Category < ActiveRecord::Base
end
end
- def deny(group)
- if group == :all
- self.secure = true
- end
+ # will reset permission on a topic to a particular
+ # set.
+ #
+ # Available permissions are, :full, :create_post, :readonly
+ # hash can be:
+ #
+ # :everyone => :full - everyone has everything
+ # :everyone => :readonly, :staff => :full
+ # 7 => 1 # you can pass a group_id and permission id
+ def set_permissions(permissions)
+ self.read_restricted, @permissions = Category.resolve_permissions(permissions)
+
+ # Ideally we can just call .clear here, but it runs SQL, we only want to run it
+ # on save.
end
- def allow(group)
- if group == :all
- self.secure = false
- # this is kind of annoying, there should be a clean way of queuing this stuff
- category_groups.destroy_all unless new_record?
- else
- groups.push(group)
+ def apply_permissions
+ if @permissions
+ category_groups.destroy_all
+ @permissions.each do |group_id, permission_type|
+ category_groups.build(group_id: group_id, permission_type: permission_type)
+ end
+ @permissions = nil
end
end
def secure_group_ids
- if self.secure
+ if self.read_restricted?
groups.pluck("groups.id")
end
end
+
+ def self.resolve_permissions(permissions)
+ read_restricted = true
+
+ everyone = Group::AUTO_GROUPS[:everyone]
+ full = CategoryGroup.permission_types[:full]
+
+ mapped = permissions.map do |group,permission|
+ group = group.id if Group === group
+
+ # subtle, using Group[] ensures the group exists in the DB
+ group = Group[group].id unless Fixnum === group
+ permission = CategoryGroup.permission_types[permission] unless Fixnum === permission
+
+ [group, permission]
+ end
+
+ mapped.each do |group, permission|
+ if group == everyone && permission == full
+ return [false, []]
+ end
+
+ read_restricted = false if group == everyone
+ end
+
+ [read_restricted, mapped]
+ end
end
# == Schema Information
@@ -162,7 +233,7 @@ end
# description :text
# text_color :string(6) default("FFFFFF"), not null
# hotness :float default(5.0), not null
-# secure :boolean default(FALSE), not null
+# read_restricted :boolean default(FALSE), not null
# auto_close_days :float
#
# Indexes
diff --git a/app/models/category_group.rb b/app/models/category_group.rb
index 679c062e9..49cf5172b 100644
--- a/app/models/category_group.rb
+++ b/app/models/category_group.rb
@@ -1,16 +1,22 @@
class CategoryGroup < ActiveRecord::Base
belongs_to :category
belongs_to :group
+
+ def self.permission_types
+ @permission_types ||= Enum.new(:full, :create_post, :readonly)
+ end
+
end
# == Schema Information
#
# Table name: category_groups
#
-# id :integer not null, primary key
-# category_id :integer not null
-# group_id :integer not null
-# created_at :datetime not null
-# updated_at :datetime not null
+# id :integer not null, primary key
+# category_id :integer not null
+# group_id :integer not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# permission_type :integer default(1)
#
diff --git a/app/models/group.rb b/app/models/group.rb
index 3d45987b0..f6fc1623f 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -10,6 +10,7 @@ class Group < ActiveRecord::Base
validate :name_format_validator
AUTO_GROUPS = {
+ :everyone => 0,
:admins => 1,
:moderators => 2,
:staff => 3,
@@ -34,6 +35,10 @@ class Group < ActiveRecord::Base
group.save!
end
+ # the everyone group is special, it can include non-users so there is no
+ # way to have the membership in a table
+ return group if name == :everyone
+
group.name = I18n.t("groups.default_names.#{name}")
# don't allow shoddy localization to break this
diff --git a/app/models/invite.rb b/app/models/invite.rb
index 9a5acc73b..e64ecaaff 100644
--- a/app/models/invite.rb
+++ b/app/models/invite.rb
@@ -59,6 +59,7 @@ end
# created_at :datetime not null
# updated_at :datetime not null
# deleted_at :datetime
+# deleted_by_id :integer
#
# Indexes
#
diff --git a/app/models/post.rb b/app/models/post.rb
index c2d4901f1..ad33a0860 100644
--- a/app/models/post.rb
+++ b/app/models/post.rb
@@ -412,6 +412,8 @@ end
# percent_rank :float default(1.0)
# notify_user_count :integer default(0), not null
# like_score :integer default(0), not null
+# deleted_by_id :integer
+# nuked_user :boolean default(FALSE)
#
# Indexes
#
diff --git a/app/models/site.rb b/app/models/site.rb
index e94871d24..60acda463 100644
--- a/app/models/site.rb
+++ b/app/models/site.rb
@@ -27,7 +27,7 @@ class Site
def categories
Category
- .secured(@guardian)
+ .topic_create_allowed(@guardian)
.latest
.includes(:topic_only_relative_url)
end
diff --git a/app/models/topic.rb b/app/models/topic.rb
index f2702df10..d57e539de 100644
--- a/app/models/topic.rb
+++ b/app/models/topic.rb
@@ -103,9 +103,9 @@ class Topic < ActiveRecord::Base
# Query conditions
condition =
if ids.present?
- ["NOT c.secure or c.id in (:cats)", cats: ids]
+ ["NOT c.read_restricted or c.id in (:cats)", cats: ids]
else
- ["NOT c.secure"]
+ ["NOT c.read_restricted"]
end
where("category_id IS NULL OR category_id IN (
@@ -629,8 +629,8 @@ class Topic < ActiveRecord::Base
self
end
- def secure_category?
- category && category.secure
+ def read_restricted_category?
+ category && category.read_restricted
end
private
@@ -692,6 +692,7 @@ end
# auto_close_at :datetime
# auto_close_user_id :integer
# auto_close_started_at :datetime
+# deleted_by_id :integer
#
# Indexes
#
diff --git a/app/models/topic_tracking_state.rb b/app/models/topic_tracking_state.rb
index b6f816a65..507f3bc25 100644
--- a/app/models/topic_tracking_state.rb
+++ b/app/models/topic_tracking_state.rb
@@ -113,11 +113,11 @@ class TopicTrackingState
((#{unread}) OR (#{new})) AND
(topics.visible OR u.admin OR u.moderator) AND
topics.deleted_at IS NULL AND
- ( category_id IS NULL OR NOT c.secure OR category_id IN (
+ ( category_id IS NULL OR NOT c.read_restricted OR category_id IN (
SELECT c2.id FROM categories c2
JOIN category_groups cg ON cg.category_id = c2.id
JOIN group_users gu ON gu.user_id = u.id AND cg.group_id = gu.group_id
- WHERE c2.secure )
+ WHERE c2.read_restricted )
)
SQL
diff --git a/app/models/user.rb b/app/models/user.rb
index 77eddf656..59e84962f 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -486,10 +486,14 @@ class User < ActiveRecord::Base
end
def secure_category_ids
- cats = self.staff? ? Category.select(:id).where(secure: true) : secure_categories.select('categories.id')
+ cats = self.staff? ? Category.select(:id).where(read_restricted: true) : secure_categories.select('categories.id')
cats.map { |c| c.id }.sort
end
+ def topic_create_allowed_category_ids
+ Category.topic_create_allowed(self.id).select(:id)
+ end
+
# Flag all posts from a user as spam
def flag_linked_posts_as_spam
admin = Discourse.system_user
@@ -660,6 +664,7 @@ end
# topic_reply_count :integer default(0), not null
# blocked :boolean default(FALSE)
# dynamic_favicon :boolean default(FALSE), not null
+# title :string(255)
#
# Indexes
#
diff --git a/app/models/user_action.rb b/app/models/user_action.rb
index 595ed3e4b..6f7f25364 100644
--- a/app/models/user_action.rb
+++ b/app/models/user_action.rb
@@ -179,7 +179,7 @@ ORDER BY p.created_at desc
# move into Topic perhaps
group_ids = nil
- if topic && topic.category && topic.category.secure
+ if topic && topic.category && topic.category.read_restricted
group_ids = topic.category.groups.pluck("groups.id")
end
@@ -232,11 +232,11 @@ ORDER BY p.created_at desc
unless guardian.is_staff?
allowed = guardian.secure_category_ids
if allowed.present?
- builder.where("( c.secure IS NULL OR
- c.secure = 'f' OR
- (c.secure = 't' and c.id in (:cats)) )", cats: guardian.secure_category_ids )
+ builder.where("( c.read_restricted IS NULL OR
+ NOT c.read_restricted OR
+ (c.read_restricted and c.id in (:cats)) )", cats: guardian.secure_category_ids )
else
- builder.where("(c.secure IS NULL OR c.secure = 'f')")
+ builder.where("(c.read_restricted IS NULL OR NOT c.read_restricted)")
end
end
end
diff --git a/app/serializers/basic_category_serializer.rb b/app/serializers/basic_category_serializer.rb
index 1ef190744..18e166c68 100644
--- a/app/serializers/basic_category_serializer.rb
+++ b/app/serializers/basic_category_serializer.rb
@@ -9,6 +9,6 @@ class BasicCategorySerializer < ApplicationSerializer
:description,
:topic_url,
:hotness,
- :secure
+ :read_restricted
end
diff --git a/app/serializers/category_serializer.rb b/app/serializers/category_serializer.rb
index 95c851c28..03a484e12 100644
--- a/app/serializers/category_serializer.rb
+++ b/app/serializers/category_serializer.rb
@@ -1,13 +1,24 @@
class CategorySerializer < BasicCategorySerializer
- attributes :secure, :groups, :available_groups, :auto_close_days
+ attributes :read_restricted, :groups, :available_groups, :auto_close_days, :group_permissions
- def groups
- @groups ||= object.groups.order("name").all.map(&:name)
+ def group_permissions
+ @group_permissions ||= begin
+ perms = object.category_groups.joins(:group).order("groups.name").map do |cg|
+ {
+ permission_type: cg.permission_type,
+ group_name: cg.group.name
+ }
+ end
+ if perms.length == 0 && !object.read_restricted
+ perms << {permission_type: CategoryGroup.permission_types[:full], group_name: :everyone}
+ end
+ perms
+ end
end
def available_groups
- Group.order("name").map(&:name) - groups
+ Group.order("name").pluck(:name) - group_permissions.map{|g| g[:group_name]}
end
end
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 58faf0b70..8ad56b92b 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -999,6 +999,11 @@ en:
browser_update: 'Unfortunately,
your browser is too old to work on this Discourse forum. Please
upgrade your browser.'
+ permission_types:
+ full: "Create Topics, Create Posts and Read"
+ create_post: "Create Posts and Read"
+ readonly: "Read Only"
+
# This section is exported to the javascript for i18n in the admin section
admin_js:
type_to_filter: "type to filter..."
@@ -1245,3 +1250,4 @@ en:
title: 'Settings'
reset: 'reset to default'
none: 'none'
+
diff --git a/db/migrate/20130712041133_add_permission_type_to_category_groups.rb b/db/migrate/20130712041133_add_permission_type_to_category_groups.rb
new file mode 100644
index 000000000..ae227562e
--- /dev/null
+++ b/db/migrate/20130712041133_add_permission_type_to_category_groups.rb
@@ -0,0 +1,9 @@
+class AddPermissionTypeToCategoryGroups < ActiveRecord::Migration
+ def change
+ # 1 is full permissions
+ add_column :category_groups, :permission_type, :integer, default: 1
+
+ # secure is ambiguous after this change, it should be read_restricted
+ rename_column :categories, :secure, :read_restricted
+ end
+end
diff --git a/lib/guardian.rb b/lib/guardian.rb
index f4949aaf9..a58e791b8 100644
--- a/lib/guardian.rb
+++ b/lib/guardian.rb
@@ -7,6 +7,7 @@ class Guardian
def staff?; false; end
def approved?; false; end
def secure_category_ids; []; end
+ def topic_create_allowed_category_ids; []; end
def has_trust_level?(level); false; end
end
@@ -328,7 +329,7 @@ class Guardian
topic.deleted_at.nil? &&
# not secure, or I can see it
- (not(topic.secure_category?) || can_see_category?(topic.category)) &&
+ (not(topic.read_restricted_category?) || can_see_category?(topic.category)) &&
# not private, or I am allowed (or an admin)
(not(topic.private_message?) || authenticated? && (topic.all_allowed_users.where(id: @user.id).exists? || is_admin?))
@@ -340,7 +341,7 @@ class Guardian
end
def can_see_category?(category)
- not(category.secure) || secure_category_ids.include?(category.id)
+ not(category.read_restricted) || secure_category_ids.include?(category.id)
end
def can_vote?(post, opts={})
@@ -378,6 +379,10 @@ class Guardian
@secure_category_ids ||= @user.secure_category_ids
end
+ def topic_create_allowed_category_ids
+ @topic_create_allowed_category_ids ||= @user.topic_create_allowed_category_ids
+ end
+
private
def is_my_own?(obj)
diff --git a/lib/post_creator.rb b/lib/post_creator.rb
index 9bbbd50f7..18fffcc26 100644
--- a/lib/post_creator.rb
+++ b/lib/post_creator.rb
@@ -116,7 +116,7 @@ class PostCreator
protected
def secure_group_ids(topic)
- @secure_group_ids ||= if topic.category && topic.category.secure?
+ @secure_group_ids ||= if topic.category && topic.category.read_restricted?
topic.category.secure_group_ids
end
end
diff --git a/lib/search.rb b/lib/search.rb
index 033a0acbb..d68b06c70 100644
--- a/lib/search.rb
+++ b/lib/search.rb
@@ -160,9 +160,9 @@ class Search
.order("topics.bumped_at DESC")
if secure_category_ids.present?
- posts = posts.where("(categories.id IS NULL) OR (NOT categories.secure) OR (categories.id IN (?))", secure_category_ids)
+ posts = posts.where("(categories.id IS NULL) OR (NOT categories.read_restricted) OR (categories.id IN (?))", secure_category_ids)
else
- posts = posts.where("(categories.id IS NULL) OR (NOT categories.secure)")
+ posts = posts.where("(categories.id IS NULL) OR (NOT categories.read_restricted)")
end
posts.limit(limit)
end
diff --git a/lib/sql_builder.rb b/lib/sql_builder.rb
index c06539dcd..9858144ea 100644
--- a/lib/sql_builder.rb
+++ b/lib/sql_builder.rb
@@ -18,9 +18,9 @@ class SqlBuilder
def secure_category(secure_category_ids, category_alias = 'c')
if secure_category_ids.present?
- where("NOT COALESCE(" << category_alias << ".secure, false) OR " << category_alias << ".id IN (:secure_category_ids)", secure_category_ids: secure_category_ids)
+ where("NOT COALESCE(" << category_alias << ".read_restricted, false) OR " << category_alias << ".id IN (:secure_category_ids)", secure_category_ids: secure_category_ids)
else
- where("NOT COALESCE(" << category_alias << ".secure, false)")
+ where("NOT COALESCE(" << category_alias << ".read_restricted, false)")
end
self
end
diff --git a/lib/topic_query.rb b/lib/topic_query.rb
index eaaedd729..dc01917a0 100644
--- a/lib/topic_query.rb
+++ b/lib/topic_query.rb
@@ -239,9 +239,9 @@ class TopicQuery
unless @user && @user.moderator?
category_ids = @user.secure_category_ids if @user
if category_ids.present?
- result = result.where('categories.secure IS NULL OR categories.secure = ? OR categories.id IN (?)', false, category_ids)
+ result = result.where('categories.read_restricted IS NULL OR categories.read_restricted = ? OR categories.id IN (?)', false, category_ids)
else
- result = result.where('categories.secure IS NULL OR categories.secure = ?', false)
+ result = result.where('categories.read_restricted IS NULL OR categories.read_restricted = ?', false)
end
end
diff --git a/spec/components/category_list_spec.rb b/spec/components/category_list_spec.rb
index a6eb8515e..537788a3d 100644
--- a/spec/components/category_list_spec.rb
+++ b/spec/components/category_list_spec.rb
@@ -41,8 +41,7 @@ describe CategoryList do
cat = Fabricate(:category)
topic = Fabricate(:topic, category: cat)
- cat.deny(:all)
- cat.allow(Group[:admins])
+ cat.set_permissions(:admins => :full)
cat.save
CategoryList.new(Guardian.new admin).categories.count.should == 1
diff --git a/spec/components/guardian_spec.rb b/spec/components/guardian_spec.rb
index 4278df2b8..63f707fb2 100644
--- a/spec/components/guardian_spec.rb
+++ b/spec/components/guardian_spec.rb
@@ -215,8 +215,9 @@ describe Guardian do
it 'correctly handles groups' do
group = Fabricate(:group)
- category = Fabricate(:category, secure: true)
- category.allow(group)
+ category = Fabricate(:category, read_restricted: true)
+ category.set_permissions(group => :full)
+ category.save
topic = Fabricate(:topic, category: category)
diff --git a/spec/components/post_creator_spec.rb b/spec/components/post_creator_spec.rb
index 3289db853..98f29bb01 100644
--- a/spec/components/post_creator_spec.rb
+++ b/spec/components/post_creator_spec.rb
@@ -62,8 +62,7 @@ describe PostCreator do
admin = Fabricate(:admin)
cat = Fabricate(:category)
- cat.deny(:all)
- cat.allow(Group[:admins])
+ cat.set_permissions(:admins => :full)
cat.save
created_post = nil
diff --git a/spec/components/search_spec.rb b/spec/components/search_spec.rb
index 82868b408..0d5a204f1 100644
--- a/spec/components/search_spec.rb
+++ b/spec/components/search_spec.rb
@@ -171,8 +171,7 @@ describe Search do
topic.category_id = category.id
topic.save
- category.deny(:all)
- category.allow(Group[:staff])
+ category.set_permissions(:staff => :full)
category.save
result(nil).should_not be_present
@@ -211,7 +210,7 @@ describe Search do
r[:title].should == category.name
r[:url].should == "/category/#{category.slug}"
- category.deny(:all)
+ category.set_permissions({})
category.save
result.should_not be_present
diff --git a/spec/components/topic_query_spec.rb b/spec/components/topic_query_spec.rb
index 9433e4d74..7ae551735 100644
--- a/spec/components/topic_query_spec.rb
+++ b/spec/components/topic_query_spec.rb
@@ -14,9 +14,8 @@ describe TopicQuery do
context 'secure category' do
it "filters categories out correctly" do
category = Fabricate(:category)
- category.deny(:all)
group = Fabricate(:group)
- category.allow(group)
+ category.set_permissions(group => :full)
category.save
topic = Fabricate(:topic, category: category)
diff --git a/spec/controllers/categories_controller_spec.rb b/spec/controllers/categories_controller_spec.rb
index fba156c52..b71fecdd2 100644
--- a/spec/controllers/categories_controller_spec.rb
+++ b/spec/controllers/categories_controller_spec.rb
@@ -134,11 +134,11 @@ describe CategoriesController do
describe 'success' do
before do
- # might as well test this as well
- @category.allow(Group[:admins])
+ # might as well test this while at it
+ @category.set_permissions(:admins => :full)
@category.save
- xhr :put, :update, id: @category.id, name: 'science', color: '000', text_color: '0ff', group_names: Group[:staff].name, secure: 'true'
+ xhr :put, :update, id: @category.id, name: 'science', color: '000', text_color: '0ff', group_names: Group[:staff].name, read_restricted: 'true'
@category.reload
end
@@ -146,7 +146,7 @@ describe CategoriesController do
@category.name.should == 'science'
@category.color.should == '000'
@category.text_color.should == '0ff'
- @category.secure?.should be_true
+ @category.read_restricted?.should be_true
@category.groups.count.should == 1
end
end
diff --git a/spec/models/category_featured_topic_spec.rb b/spec/models/category_featured_topic_spec.rb
index e4d7d1045..bde98f0ee 100644
--- a/spec/models/category_featured_topic_spec.rb
+++ b/spec/models/category_featured_topic_spec.rb
@@ -15,8 +15,7 @@ describe CategoryFeaturedTopic do
# so much dancing, I am thinking fixures make sense here.
user.change_trust_level!(:basic)
- category.deny(:all)
- category.allow(Group[:trust_level_1])
+ category.set_permissions(:trust_level_1 => :full)
category.save
uncategorized_post = PostCreator.create(user, raw: "this is my new post 123 post", title: "hello world")
diff --git a/spec/models/category_spec.rb b/spec/models/category_spec.rb
index 0c3f8d12e..f2d69c375 100644
--- a/spec/models/category_spec.rb
+++ b/spec/models/category_spec.rb
@@ -18,6 +18,57 @@ describe Category do
it { should have_many :category_featured_topics }
it { should have_many :featured_topics }
+
+ describe "resolve_permissions" do
+ it "can determine read_restricted" do
+ read_restricted, resolved = Category.resolve_permissions(:everyone => :full)
+
+ read_restricted.should be_false
+ resolved.should == []
+ end
+ end
+
+ describe "topic_create_allowed and post_create_allowed" do
+ it "works" do
+ default_category = Fabricate(:category)
+ full_category = Fabricate(:category)
+ can_post_category = Fabricate(:category)
+ can_read_category = Fabricate(:category)
+
+
+ user = Fabricate(:user)
+ group = Fabricate(:group)
+ group.add(user)
+ group.save
+
+ admin = Fabricate(:admin)
+
+ full_category.set_permissions(group => :full)
+ full_category.save
+
+ can_post_category.set_permissions(group => :create_post)
+ can_post_category.save
+
+ can_read_category.set_permissions(group => :readonly)
+ can_read_category.save
+
+ guardian = Guardian.new(admin)
+ Category.topic_create_allowed(guardian).count.should == 4
+ Category.post_create_allowed(guardian).count.should == 4
+ Category.secured(guardian).count.should == 4
+
+ guardian = Guardian.new(user)
+ Category.secured(guardian).count.should == 4
+ Category.post_create_allowed(guardian).count.should == 3
+ Category.topic_create_allowed(guardian).count.should == 2 # explicitly allowed once, default allowed once
+ end
+
+ end
+
+ describe "post_create_allowed" do
+
+ end
+
describe "security" do
let(:category) { Fabricate(:category) }
let(:category_2) { Fabricate(:category) }
@@ -25,20 +76,20 @@ describe Category do
let(:group) { Fabricate(:group) }
it "secures categories correctly" do
- category.secure?.should be_false
+ category.read_restricted?.should be_false
- category.deny(:all)
- category.secure?.should be_true
+ category.set_permissions({})
+ category.read_restricted?.should be_true
- category.allow(:all)
- category.secure?.should be_false
+ category.set_permissions(:everyone => :full)
+ category.read_restricted?.should be_false
user.secure_categories.should be_empty
group.add(user)
group.save
- category.allow(group)
+ category.set_permissions(group.id => :full)
category.save
user.reload
@@ -47,13 +98,13 @@ describe Category do
it "lists all secured categories correctly" do
group.add(user)
- category.allow(group)
+ category.set_permissions(group.id => :full)
+ category.save
+ category_2.set_permissions(group.id => :full)
+ category_2.save
- Category.secured.should == [category]
-
- category_2.allow(group)
-
- Category.secured.should =~ [category, category_2]
+ Category.secured.should =~ []
+ Category.secured(Guardian.new(user)).should =~ [category, category_2]
end
end
diff --git a/spec/models/site_spec.rb b/spec/models/site_spec.rb
new file mode 100644
index 000000000..a4ffd55a3
--- /dev/null
+++ b/spec/models/site_spec.rb
@@ -0,0 +1,16 @@
+require 'spec_helper'
+require_dependency 'site'
+
+describe Site do
+ it "omits categories users can not write to from the category list" do
+ category = Fabricate(:category)
+ user = Fabricate(:user)
+
+ Site.new(Guardian.new(user)).categories.count.should == 1
+
+ category.set_permissions(:everyone => :create_post)
+ category.save
+
+ Site.new(Guardian.new(user)).categories.count.should == 0
+ end
+end
diff --git a/spec/models/topic_link_spec.rb b/spec/models/topic_link_spec.rb
index 29d7422a2..d2d960afb 100644
--- a/spec/models/topic_link_spec.rb
+++ b/spec/models/topic_link_spec.rb
@@ -258,8 +258,7 @@ describe TopicLink do
TopicLink.topic_summary(Guardian.new, post.topic_id).count.should == 1
TopicLink.counts_for(Guardian.new, post.topic, [post]).length.should == 1
- category.deny(:all)
- category.allow(Group[:staff])
+ category.set_permissions(:staff => :full)
category.save
admin = Fabricate(:admin)
diff --git a/spec/models/topic_spec.rb b/spec/models/topic_spec.rb
index fef822306..9b13a30c3 100644
--- a/spec/models/topic_spec.rb
+++ b/spec/models/topic_spec.rb
@@ -192,7 +192,7 @@ describe Topic do
context "secure categories" do
let(:user) { Fabricate(:user) }
- let(:category) { Fabricate(:category, secure: true) }
+ let(:category) { Fabricate(:category, read_restricted: true) }
before do
topic.category = category
@@ -1263,7 +1263,7 @@ describe Topic do
describe 'secured' do
it 'can remove secure groups' do
- category = Fabricate(:category, secure: true)
+ category = Fabricate(:category, read_restricted: true)
topic = Fabricate(:topic, category: category)
Topic.secured(Guardian.new(nil)).count.should == 0
@@ -1280,17 +1280,17 @@ describe Topic do
let(:category){ Category.new }
it "is true if the category is secure" do
- category.stubs(:secure).returns(true)
- Topic.new(:category => category).should be_secure_category
+ category.stubs(:read_restricted).returns(true)
+ Topic.new(:category => category).should be_read_restricted_category
end
it "is false if the category is not secure" do
- category.stubs(:secure).returns(false)
- Topic.new(:category => category).should_not be_secure_category
+ category.stubs(:read_restricted).returns(false)
+ Topic.new(:category => category).should_not be_read_restricted_category
end
it "is false if there is no category" do
- Topic.new(:category => nil).should_not be_secure_category
+ Topic.new(:category => nil).should_not be_read_restricted_category
end
end
diff --git a/spec/models/topic_tracking_state_spec.rb b/spec/models/topic_tracking_state_spec.rb
index af9348736..aabfda329 100644
--- a/spec/models/topic_tracking_state_spec.rb
+++ b/spec/models/topic_tracking_state_spec.rb
@@ -51,7 +51,7 @@ describe TopicTrackingState do
row.user_id.should == post.user_id
# when we have no permission to see a category, don't show its stats
- category = Fabricate(:category, secure: true)
+ category = Fabricate(:category, read_restricted: true)
post.topic.category_id = category.id
post.topic.save
diff --git a/spec/models/user_action_spec.rb b/spec/models/user_action_spec.rb
index 8a1e5b7dc..2f5bdea4d 100644
--- a/spec/models/user_action_spec.rb
+++ b/spec/models/user_action_spec.rb
@@ -68,7 +68,7 @@ describe UserAction do
# groups
- category = Fabricate(:category, secure: true)
+ category = Fabricate(:category, read_restricted: true)
public_topic.recover!
public_topic.category = category
@@ -82,7 +82,7 @@ describe UserAction do
group.add(u)
group.save
- category.allow(group)
+ category.set_permissions(group => :full)
category.save
stats_for_user(u).should == [UserAction::NEW_TOPIC]