diff --git a/.gitignore b/.gitignore index e617d15..78c1684 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,6 @@ doc/api doc/app public/files public/thumbs +config/deploy.rb +config/deploy +Capfile diff --git a/app/models/permission.rb b/app/models/permission.rb new file mode 100644 index 0000000..c2951ff --- /dev/null +++ b/app/models/permission.rb @@ -0,0 +1,19 @@ +class Permission < ActiveRecord::Base + # uncomment any of the following lines which is relevant to your application, + # or create your own with the name of the model which acts_as_permissible. + belongs_to :user + + belongs_to :role + + belongs_to :permissible, :polymorphic => true, :dependent => :destroy + + validates_presence_of :permissible_id, :permissible_type, :action + validates_format_of :action, :with => /^[a-z_]+$/ + validates_numericality_of :permissible_id + validates_uniqueness_of :action, :scope => [:permissible_id,:permissible_type] + + def to_hash + self.new_record? ? {} : {self.action => self.granted} + end + +end \ No newline at end of file diff --git a/app/models/role.rb b/app/models/role.rb new file mode 100644 index 0000000..d5c7310 --- /dev/null +++ b/app/models/role.rb @@ -0,0 +1,12 @@ +class Role < ActiveRecord::Base + has_many :role_memberships, :as => :roleable, :dependent => :destroy + has_many :roles, :through => :role_memberships, :source => :role + + has_many :roleables, :class_name => "RoleMembership", :foreign_key => "role_id", :dependent => :destroy + has_many :subroles, :through => :roleables, :source => :roleable, :source_type => 'Role' + has_many :users, :through => :roleables, :source => :roleable, :source_type => 'User' + + validates_uniqueness_of :name + + acts_as_permissible +end \ No newline at end of file diff --git a/app/models/role_membership.rb b/app/models/role_membership.rb new file mode 100644 index 0000000..9ebcbe2 --- /dev/null +++ b/app/models/role_membership.rb @@ -0,0 +1,36 @@ +class RoleMembership < ActiveRecord::Base + belongs_to :user + belongs_to :role + belongs_to :roleable, :polymorphic => true + + validates_presence_of :roleable_id, :roleable_type, :role_id + validates_uniqueness_of :role_id, :scope => [:roleable_id, :roleable_type] + validates_numericality_of :roleable_id, :role_id + validates_format_of :roleable_type, :with => /^[A-Z]{1}[a-z0-9]+([A-Z]{1}[a-z0-9]+)*$/ + validate :role_does_not_belong_to_itself_in_a_loop + + protected + def role_does_not_belong_to_itself_in_a_loop + if roleable_type == "Role" + if role_id == roleable_id + errors.add_to_base("A role cannot belong to itself.") + else + if belongs_to_itself_through_other?(roleable_id, role_id) + errors.add_to_base("A role cannot belong to a role which belongs to it.") + end + end + end + end + + def belongs_to_itself_through_other?(original_roleable_id, current_role_id) + if self.class.find(:first, :select => "id", :conditions => ["roleable_id=? AND roleable_type='Role' AND role_id=?",current_role_id,original_roleable_id]) + return true + else + memberships = self.class.find(:all, :select => "role_id", :conditions => ["roleable_id=? AND roleable_type='Role'",current_role_id]) + if memberships.any? {|membership| belongs_to_itself_through_other?(original_roleable_id,membership.role_id)} + return true + end + end + return false + end +end \ No newline at end of file diff --git a/app/models/user.rb b/app/models/user.rb index 04c7d17..d1d3345 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,3 +1,4 @@ class User < ActiveRecord::Base acts_as_authentic + acts_as_permissible end diff --git a/app/views/albums/show.html.erb b/app/views/albums/show.html.erb index a32a88b..53e85df 100644 --- a/app/views/albums/show.html.erb +++ b/app/views/albums/show.html.erb @@ -1,6 +1,11 @@ +

<%= @album.title %>

<% for photo in @album.photos %> <%= link_to image_tag( photo.path_modified_public("album") ), photo %> <% end %> +

<%= @album.description %>

+<% if current_user && current_user.has_permission?("see_album_note") %> +

<%= @album.note %>

+<% end %>
<%= link_to "Update album", edit_album_path(@album) %>
<%= link_to "Upload photos", upload_album_path(@album) %> diff --git a/config/environment.rb b/config/environment.rb index 6426342..f0db2a5 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -11,7 +11,8 @@ Rails::Initializer.run do |config| config.gem "authlogic" config.gem 'mime-types', :lib => 'mime/types' - #config.gem "image_science" + config.gem "image_science" + config.gem "mini_exiftool" config.load_paths += %W( #{RAILS_ROOT}/app/middleware ) @@ -19,12 +20,4 @@ Rails::Initializer.run do |config| config.i18n.default_locale = 'no-NB' - config.action_mailer.smtp_settings = { - :address => "smtp.gmail.com", - :port => 587, - :domain => "espen@inspired.no", - :authentication => :plain, - :user_name => "espen@inspired.no", - :password => "tkg5megmeg" - } end \ No newline at end of file diff --git a/db/migrate/20090604202928_create_permissions.rb b/db/migrate/20090604202928_create_permissions.rb new file mode 100644 index 0000000..9cdbb7b --- /dev/null +++ b/db/migrate/20090604202928_create_permissions.rb @@ -0,0 +1,16 @@ +class CreatePermissions < ActiveRecord::Migration + def self.up + create_table "permissions", :force => true do |t| + t.integer :permissible_id + t.string :permissible_type + t.string :action + t.boolean :granted + + t.timestamps + end + end + + def self.down + drop_table "permissions" + end +end \ No newline at end of file diff --git a/db/migrate/20090604202929_create_role_memberships.rb b/db/migrate/20090604202929_create_role_memberships.rb new file mode 100644 index 0000000..dc3d053 --- /dev/null +++ b/db/migrate/20090604202929_create_role_memberships.rb @@ -0,0 +1,15 @@ +class CreateRoleMemberships < ActiveRecord::Migration + def self.up + create_table :role_memberships do |t| + t.integer :roleable_id + t.string :roleable_type + t.integer :role_id + + t.timestamps + end + end + + def self.down + drop_table :role_memberships + end +end \ No newline at end of file diff --git a/db/migrate/20090604202930_create_roles.rb b/db/migrate/20090604202930_create_roles.rb new file mode 100644 index 0000000..8b34d74 --- /dev/null +++ b/db/migrate/20090604202930_create_roles.rb @@ -0,0 +1,13 @@ +class CreateRoles < ActiveRecord::Migration + def self.up + create_table :roles do |t| + t.string :name + + t.timestamps + end + end + + def self.down + drop_table :roles + end +end \ No newline at end of file diff --git a/db/schema.rb b/db/schema.rb index 026bffb..dba0b1f 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -9,7 +9,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20090602131547) do +ActiveRecord::Schema.define(:version => 20090604202930) do create_table "albums", :force => true do |t| t.string "title", :null => false @@ -37,6 +37,15 @@ ActiveRecord::Schema.define(:version => 20090602131547) do t.datetime "updated_at" end + create_table "permissions", :force => true do |t| + t.integer "permissible_id" + t.string "permissible_type" + t.string "action" + t.boolean "granted" + t.datetime "created_at" + t.datetime "updated_at" + end + create_table "photo_tags", :force => true do |t| t.integer "tag_id" t.integer "photo_id" @@ -55,6 +64,20 @@ ActiveRecord::Schema.define(:version => 20090602131547) do t.float "latitude" end + create_table "role_memberships", :force => true do |t| + t.integer "roleable_id" + t.string "roleable_type" + t.integer "role_id" + t.datetime "created_at" + t.datetime "updated_at" + end + + create_table "roles", :force => true do |t| + t.string "name" + t.datetime "created_at" + t.datetime "updated_at" + end + create_table "tags", :force => true do |t| t.string "title", :null => false t.datetime "created_at" diff --git a/lib/acts_as_permissible.rb b/lib/acts_as_permissible.rb new file mode 100644 index 0000000..994b310 --- /dev/null +++ b/lib/acts_as_permissible.rb @@ -0,0 +1,106 @@ +# ActsAsPermissible +module NoamBenAri + module Acts #:nodoc: + module Permissible #:nodoc: + + def self.included(base) + base.extend ClassMethods + end + + module ClassMethods + def acts_as_permissible + has_many :permissions, :as => :permissible, :dependent => :destroy + + has_many :role_memberships, :as => :roleable, :dependent => :destroy + has_many :roles, :through => :role_memberships, :source => :role + + include NoamBenAri::Acts::Permissible::InstanceMethods + extend NoamBenAri::Acts::Permissible::SingletonMethods + + alias_method :full_permissions_hash, :permissions_hash + end + end + + # This module contains class methods + module SingletonMethods + + # Helper method to lookup for permissions for a given object. + # This method is equivalent to obj.permissions. + def find_permissions_for(obj) + permissible = ActiveRecord::Base.send(:class_name_of_active_record_descendant, self).to_s + + Permission.find(:all, + :conditions => ["permissible_id = ? and permissible_type = ?", obj.id, permissible] + ) + end + end + + # This module contains instance methods + module InstanceMethods + + # returns permissions in hash form + # from all levels recursively + def permissions_hash + @permissions_hash ||= lambda do + @permissions_hash = permissions.inject({}) { |hsh,perm| hsh.merge(perm.to_hash) }.symbolize_keys! + roles.each do |role| + merge_permissions!(role.permissions_hash) + end + @permissions_hash + end.call() + end + + # accepts a permission identifier string or an array of permission identifier strings + # and return true if the user has all of the permissions given by the parameters + # false if not. + def has_permission?(*perms) + perms.all? {|perm| permissions_hash.include?(perm.to_sym) && (permissions_hash[perm.to_sym] == true) } + end + + # accepts a permission identifier string or an array of permission identifier strings + # and return true if the user has any of the permissions given by the parameters + # false if none. + def has_any_permission?(*perms) + perms.any? {|perm| permissions_hash.include?(perm.to_sym) && (permissions_hash[perm.to_sym] == true) } + end + + # Merges another permissible object's permissions into this permissible's permissions hash + # In the case of identical keys, a false value wins over a true value. + def merge_permissions!(other_permissions_hash) + permissions_hash.merge!(other_permissions_hash) {|key,oldval,newval| oldval.nil? ? newval : oldval && newval} + end + + # Resets permissions and then loads them. + def reload_permissions! + reset_permissions! + permissions_hash + end + + def roles_list + list = [] + roles.inject(list) do |list,role| + list << role.name + role.roles_list.inject(list) {|list,role| list << role} + end + list.uniq + end + + def in_role?(*role_names) + role_names.all? {|role| roles_list.include?(role) } + end + + def in_any_role?(*role_names) + role_names.any? {|role| roles_list.include?(role) } + end + + + private + # Nilifies permissions_hash instance variable. + def reset_permissions! + @permissions_hash = nil + end + + end + end + end +end diff --git a/spec/fixtures/permissions.yml b/spec/fixtures/permissions.yml new file mode 100644 index 0000000..f6f4025 --- /dev/null +++ b/spec/fixtures/permissions.yml @@ -0,0 +1,48 @@ +one: + id: 1 + permissible_id: 7 + permissible_type: "Permission" + action: "view_something" + granted: 1 +two: + id: 2 + permissible_id: 7 + permissible_type: "Permission" + action: "delete_something" + granted: 0 +three: + id: 3 + permissible_id: 8 + permissible_type: "Permission" + action: "view_something" + granted: 1 +four: + id: 4 + permissible_id: 8 + permissible_type: "Permission" + action: "delete_something" + granted: 1 +five: + id: 5 + permissible_id: 8 + permissible_type: "Permission" + action: "update_something" + granted: 1 +six: + id: 6 + permissible_id: 8 + permissible_type: "Permission" + action: "create_something" + granted: 0 +perm: + id: 7 + permissible_id: 47 + permissible_type: "User" + action: "non_important" + granted: 1 +perm2: + id: 8 + permissible_id: 48 + permissible_type: "User" + action: "non_important" + granted: 1 \ No newline at end of file diff --git a/spec/fixtures/role_memberships.yml b/spec/fixtures/role_memberships.yml new file mode 100644 index 0000000..73a00d8 --- /dev/null +++ b/spec/fixtures/role_memberships.yml @@ -0,0 +1,25 @@ +publishers_to_customers: + id: 1 + roleable_id: 1 + roleable_type: "Role" + role_id: 3 +advertisers_to_customers: + id: 2 + roleable_id: 2 + roleable_type: "Role" + role_id: 3 +admins_to_company: + id: 3 + roleable_id: 5 + roleable_type: "Role" + role_id: 4 +company_to_admins: + id: 4 + roleable_id: 4 + roleable_type: "Role" + role_id: 5 +publishers_to_company: + id: 5 + roleable_id: 1 + roleable_type: "Role" + role_id: 4 \ No newline at end of file diff --git a/spec/fixtures/roles.yml b/spec/fixtures/roles.yml new file mode 100644 index 0000000..36843a3 --- /dev/null +++ b/spec/fixtures/roles.yml @@ -0,0 +1,15 @@ +publishers: + id: 1 + name: "Publishers" +advertisers: + id: 2 + name: "Advertisers" +customers: + id: 3 + name: "Customers" +company: + id: 4 + name: "Company" +admins: + id: 5 + name: "Admins" \ No newline at end of file diff --git a/spec/models/acts_as_permissible_spec.rb b/spec/models/acts_as_permissible_spec.rb new file mode 100644 index 0000000..8e9b955 --- /dev/null +++ b/spec/models/acts_as_permissible_spec.rb @@ -0,0 +1,208 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +class Permission < ActiveRecord::Base + acts_as_permissible +end + +describe "acts_as_permissible" do + fixtures :permissions + + before(:each) do + @perm = permissions(:perm) + end + + describe "class methods" do + it "should find_permissions_for(obj) correctly" do + Permission.find_permissions_for(@perm).size.should == 2 + Permission.find_permissions_for(@perm).first.action.should == "view_something" + Permission.find_permissions_for(@perm).last.action.should == "delete_something" + end + end + + describe "permissions_hash" do + it "should return the correct permissions_hash" do + @perm.permissions_hash.should == {:view_something => true, :delete_something => false} + end + end + + describe "has_permission?" do + it "should return true if permission found" do + @perm.has_permission?("view_something").should == true + end + + it "should return false if permission not found" do + @perm.has_permission?("create_something").should == false + end + + it "should return false if permission found and is denied" do + @perm.has_permission?("delete_something").should == false + end + end + + describe "merge_permissions!" do + before(:each) do + @perm2 = permissions(:perm2) + @merged_permissions = @perm.merge_permissions!(@perm2.permissions_hash) + # {:update_something=>true, :view_something=>true, :delete_something=>false, :create_something=>false} + end + + it "should include all keys from both hashes" do + @merged_permissions.keys.should == + (@perm.permissions_hash.keys + @perm2.permissions_hash.keys).uniq + end + + it "should override identical keys with false value" do + @merged_permissions[:delete_something].should == false + end + end + + describe "reload_permissions!" do + before(:each) do + @original_hash = @perm.permissions_hash + @perm.permissions << Permission.new(:action => "add_something", :granted => true) + end + + it "should catch-up with database changes" do + @perm.permissions_hash.should == @original_hash + reloaded_hash = @perm.reload_permissions! + reloaded_hash.should_not == @original_hash + end + + it "should get the changes correctly" do + reloaded_hash = @perm.reload_permissions! + reloaded_hash.keys.should include(:add_something) + end + end + + describe "roles_list" do + before(:each) do + @perm.roles_list.should == [] + @mutables = Role.new(:name => "mutables") + @mutables.save! + @wierdos = Role.new(:name => "wierdos") + @wierdos.save! + @mutables.roles << @wierdos + end + + after(:each) do + @mutables.destroy + @wierdos.destroy + @perm.roles.reset + @perm.roles_list.should == [] + end + + it "should return the correct list" do + @perm.roles << @wierdos + @perm.roles_list.size.should == 1 + @perm.roles_list.should include("wierdos") + end + + it "should return the correct list including parent roles of roles recursively." do + @perm.roles << @mutables + @perm.roles_list.size.should == 2 + @perm.roles_list.should include("mutables") + @perm.roles_list.should include("wierdos") + end + end + + describe "in_role?" do + before(:each) do + @mutables = Role.new(:name => "mutables") + @mutables.save! + @immutables = Role.new(:name => "immutables") + @immutables.save! + end + + after(:each) do + @mutables.destroy + @immutables.destroy + @perm.roles.reset + end + + it "should return true if member of one" do + @perm.roles << @mutables + @perm.in_role?("mutables").should == true + end + + it "should return false if not a member" do + @perm.in_role?("mutables").should == false + end + + it "should return true if member of all" do + @perm.roles << @mutables + @perm.roles << @immutables + @perm.in_role?("mutables","immutables").should == true + end + + it "should return false if member of some" do + @perm.roles << @mutables + @perm.in_role?("mutables","immutables").should == false + end + end + + describe "in_any_role?" do + before(:each) do + @mutables = Role.new(:name => "mutables") + @mutables.save! + @immutables = Role.new(:name => "immutables") + @immutables.save! + end + + it "should return true if member of one" do + @perm.roles << @mutables + @perm.in_any_role?("mutables","immutables").should == true + end + + it "should return false if not a member" do + @perm.in_any_role?("mutables","immutables").should == false + end + + it "should return true if member of all" do + @perm.roles << @mutables + @perm.roles << @immutables + @perm.in_any_role?("mutables","immutables").should == true + end + end + + describe "full_permissions_hash" do + before(:each) do + @mutables = Role.new(:name => "mutables") + @mutables.save! + @mutable_permission = Permission.new(:permissible_id => @mutables.id, :permissible_type => @mutables.class.to_s, :action => "view_something", :granted => false) + @mutable_permission.save! + @immutables = Role.new(:name => "immutables") + @immutables.save! + @immutable_permission = Permission.new(:permissible_id => @immutables.id, :permissible_type => @immutables.class.to_s, :action => "download_something", :granted => true) + @immutable_permission.save! + end + + it "should return the correct hash if object doesn't belong to roles" do + @perm.roles.should == [] + @perm.full_permissions_hash.should == {:view_something=>true, :delete_something=>false} + end + + it "should return the correct hash if object belongs to one role" do + @perm.roles << @mutables + @perm.full_permissions_hash.should == {:view_something=>false, :delete_something=>false} + end + + it "should return the correct hash if object belongs to one role which belongs to another role" do + @mutables.roles << @immutables + @perm.roles << @mutables + @perm.full_permissions_hash.should == {:view_something=>false, :delete_something=>false, :download_something=>true} + end + + it "should return the correct hash if object belongs to 2 roles" do + @perm.roles << @immutables + @perm.roles << @mutables + @perm.full_permissions_hash.should == {:view_something=>false, :delete_something=>false, :download_something=>true} + end + + after(:each) do + @mutables.destroy + @immutables.destroy + @perm.roles.reset + end + end + +end diff --git a/spec/models/permission_spec.rb b/spec/models/permission_spec.rb new file mode 100644 index 0000000..9a3e4d9 --- /dev/null +++ b/spec/models/permission_spec.rb @@ -0,0 +1,51 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe Permission, "to_hash" do + before(:each) do + @permission = Permission.new(:permissible_id => 1, :permissible_type => "User", :action => "some_action", :granted => 1) + end + + it "to_hash returns {} if new record" do + @permission.to_hash.should == {} + end + + it "to_hash returns {action => granted}" do + @permission.save + @permission.to_hash.should == {"some_action" => true} + end + +end + +describe Permission, "validations" do + before(:each) do + @permission = Permission.new(:permissible_id => 1, :permissible_type => "User", :action => "some_action", :granted => 1) + end + + it "should be valid" do + @permission.should be_valid + end + + it "action should be unique to a permissible id and type" do + @permission.save + @permission2 = Permission.new(:permissible_id => 1, :permissible_type => "User", :action => "some_action", :granted => 0) + @permission2.should_not be_valid + end + + it "must have a permissible_id" do + @permission.permissible_id = nil + @permission.should_not be_valid + end + + it "must have a permissible_type" do + @permission.permissible_type = nil + @permission.should_not be_valid + end + + it "must have an action" do + @permission.action = nil + @permission.should_not be_valid + @permission.action = "" + @permission.should_not be_valid + end + +end diff --git a/spec/models/role_membership_spec.rb b/spec/models/role_membership_spec.rb new file mode 100644 index 0000000..d6de6d9 --- /dev/null +++ b/spec/models/role_membership_spec.rb @@ -0,0 +1,100 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe "RoleMembership" do + + describe "validations" do + before(:all) do + @roles = [] + @roles[0] = Role.new(:name => "role0") + @roles[1] = Role.new(:name => "role1") + @roles[2] = Role.new(:name => "role2") + @roles[3] = Role.new(:name => "role3") + @roles[4] = Role.new(:name => "role4") + @roles[5] = Role.new(:name => "role5") + @roles[6] = Role.new(:name => "role6") + @roles[7] = Role.new(:name => "role7") + @roles[8] = Role.new(:name => "role8") + @roles[9] = Role.new(:name => "role9") + @roles[10] = Role.new(:name => "role10") + @roles[11] = Role.new(:name => "role11") + @roles.each {|role| role.save!} + end + + before(:each) do + @membership = RoleMembership.new(:roleable_id => @roles[0].id, :roleable_type => "Role", :role_id => @roles[1].id) + end + + it "should be valid" do + @membership.should be_valid + end + + # roleable_id + it "should have a roleable_id" do + @membership.roleable_id = nil + @membership.should_not be_valid + end + + it "roleable_id should be an integer" do + @membership.roleable_id = "asd" + @membership.should_not be_valid + end + + # roleable_type + it "should have a roleable_type" do + @membership.roleable_type = nil + @membership.should_not be_valid + end + + it "roleable_type should be a string" do + @membership.roleable_type = 123 + @membership.should_not be_valid + end + + it "roleable_type should have a class name format" do + @membership.roleable_type = "asd" + @membership.should_not be_valid + @membership.roleable_type = "User" + @membership.should be_valid + @membership.roleable_type = "Some95WierdClassN4m3" + @membership.should be_valid + end + + # role_id + it "should have a role_id" do + @membership.role_id = nil + @membership.should_not be_valid + end + + it "role_id should be an integer" do + @membership.role_id = "asd" + @membership.should_not be_valid + end + + it "should not allow a role to belong to itself" do + @membership.role_id = @roles[0].id + @membership.should_not be_valid + end + + # roles cannot belong to each other in a loop + it "should not a allow a role to belong to a role which belongs to it in a loop" do + @roles[0].roles << @roles[1] + @roles[1].roles << @roles[2] + @roles[2].roles << @roles[3] + @roles[2].roles << @roles[4] + @roles[2].roles << @roles[5] + @roles[3].roles << @roles[6] + @roles[1].roles << @roles[7] + @roles[3].roles << @roles[8] + @roles[4].roles << @roles[9] + @roles[4].roles << @roles[10] + @roles[5].roles << @roles[11] + @membership3 = RoleMembership.new(:roleable_id => @roles[11].id, :roleable_type => "Role", :role_id => @roles[0].id) + @membership3.should_not be_valid + @membership3.errors.full_messages.should include("A role cannot belong to a role which belongs to it.") + end + + after(:all) do + @roles.each {|role| role.destroy} + end + end +end \ No newline at end of file diff --git a/spec/models/role_spec.rb b/spec/models/role_spec.rb new file mode 100644 index 0000000..c9a79e9 --- /dev/null +++ b/spec/models/role_spec.rb @@ -0,0 +1,53 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe "Role" do + + describe "validations" do + before(:each) do + @role = Role.new(:name => "Hunters") + end + + it "should be valid" do + @role.should be_valid + end + + it "should have a unique name" do + @role.save + @role2 = Role.new(:name => "Hunters") + @role2.should_not be_valid + end + end + + describe "associations" do + fixtures :roles, :role_memberships + + it "should get subgroups correctly" do + roles(:company).subroles.size.should == 2 + arr = [] + arr << roles(:publishers) + arr << roles(:admins) + roles(:company).subroles.should include(arr.first) + roles(:company).subroles.should include(arr.last) + + roles(:customers).subroles.size.should == 2 + arr = [] + arr << roles(:publishers) + arr << roles(:advertisers) + roles(:customers).subroles.should include(arr.first) + roles(:customers).subroles.should include(arr.last) + end + + it "should get roles correctly" do + roles(:publishers).roles.size.should == 2 + arr = [] + arr << roles(:customers) + arr << roles(:company) + roles(:publishers).roles.should == arr + + roles(:admins).roles.size.should == 1 + arr = [] + arr << roles(:company) + roles(:admins).roles.should == arr + end + end +end \ No newline at end of file