Skip to content

Commit

Permalink
first version
Browse files Browse the repository at this point in the history
  • Loading branch information
kristianmandrup committed Aug 27, 2010
0 parents commit 163f0e3
Show file tree
Hide file tree
Showing 23 changed files with 568 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .document
@@ -0,0 +1,5 @@
README.rdoc
lib/**/*.rb
bin/*
features/**/*.feature
LICENSE
21 changes: 21 additions & 0 deletions .gitignore
@@ -0,0 +1,21 @@
## MAC OS
.DS_Store

## TEXTMATE
*.tmproj
tmtags

## EMACS
*~
\#*
.\#*

## VIM
*.swp

## PROJECT::GENERAL
coverage
rdoc
pkg

## PROJECT::SPECIFIC
1 change: 1 addition & 0 deletions .rspec
@@ -0,0 +1 @@
--format nested --color
20 changes: 20 additions & 0 deletions LICENSE
@@ -0,0 +1,20 @@
Copyright (c) 2009 Kristian Mandrup

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
77 changes: 77 additions & 0 deletions README.markdown
@@ -0,0 +1,77 @@
# CanCan Permits

Adds the concept of centralized Permits for use with CanCan permission system.

## Install

<code>gem install cancan-permits</code>

## Usage

* Define Roles that Users can have
* Define which Roles are available
* Define a Permit for each Role.
* For each Permit, define what that Role can do

To add Roles to your app, you might consider using a *roles* gem such as *roles_generic*

### Define which Roles are available

You can override the default configuration here:

<pre>
module Permits::Roles
def self.available
# return symbols array of Roles available to users
end
end
</pre>

By default it returns User.roles if such exists, otherwise it returns [:guest, :admin] by default.

### Define a Permit for each Role.

_Note:_ You might consider using the Permits generator in order to generate your permits for you (see below)

<pre>
module RolePermit
class Admin < Base
def initialize(ability)
super
end

def permit?(user, request=nil)
super
return if !role_match? user

can :manage, :all
end
end
end
</pre>

## Permits Generator

Options
* --orm : The ORM to use (active_record, data_mapper, mongoid, mongo_mapper)
* --roles : The roles for which to generate permits ; default Guest (read all) and Admin (manage all)

Note, by default the Permits generator will attempt to discover which roles are currently defined as available to the system
and generate permits for those roles (using some conventions - TODO). Any roles specified in the --roles option are merged
with the roles found to be available in the app.

<code>$ rails g permits --orm active_record --roles guest author admin</code>

## Note on Patches/Pull Requests

* Fork the project.
* Make your feature addition or bug fix.
* Add tests for it. This is important so I don't break it in a
future version unintentionally.
* Commit, do not mess with rakefile, version, or history.
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
* Send me a pull request. Bonus points for topic branches.

## Copyright

Copyright (c) 2010 Kristian Mandrup. See LICENSE for details.
19 changes: 19 additions & 0 deletions Rakefile
@@ -0,0 +1,19 @@
begin
require 'jeweler'
Jeweler::Tasks.new do |gem|
gem.name = "cancan-permits"
gem.summary = %Q{TODO: one-line summary of your gem}
gem.description = %Q{TODO: longer description of your gem}
gem.email = "kmandrup@gmail.com"
gem.homepage = "http://github.com/kristianmandrup/cancan-permits"
gem.authors = ["Kristian Mandrup"]
gem.add_development_dependency "rspec", "~> 2.0.0"
gem.add_dependency 'cancan', "~> 1.3"
gem.add_dependency 'require_all', "~> 1.1"
gem.add_dependency 'sugar-high', "~> 0.1"
end
Jeweler::GemcutterTasks.new
rescue LoadError
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
end

3 changes: 3 additions & 0 deletions lib/cancan-permits.rb
@@ -0,0 +1,3 @@
require 'cancan'
require 'require_all'
require_all File.dirname(__FILE__) + '/cancan-permits'
6 changes: 6 additions & 0 deletions lib/cancan-permits/namespaces.rb
@@ -0,0 +1,6 @@
module Permits
modules :ability, :roles
end

module Permit
end
40 changes: 40 additions & 0 deletions lib/cancan-permits/permit/base_permit.rb
@@ -0,0 +1,40 @@
module Permit
class Base
attr_reader :ability

def initialize(ability)
@ability = ability
end

def permit?(user, request=nil)
false
end

def can(action, subject, conditions = nil, &block)
can_definitions << CanCan::CanDefinition.new(true, action, subject, conditions, block)
end

def cannot(action, subject, conditions = nil, &block)
can_definitions << CanCan::CanDefinition.new(false, action, subject, conditions, block)
end

def owns(user, clazz, ownership_relation = :user_id, user_id_attribute = :id)
begin
user_id = user.send :"#{user_id_attribute}"
rescue
raise ArgumentError, "ERROR (owns) - The user of class #{user.class} does not respond to ##{user_id_attribute}"
end
can :manage, clazz, ownership_relation => user_id
end

protected

def role_match? user
user.has_role? self.class.last_name.downcase.to_sym
end

def can_definitions
ability.send :can_definitions
end
end
end
19 changes: 19 additions & 0 deletions lib/cancan-permits/permits/abiity.rb
@@ -0,0 +1,19 @@
module Permits
class Ability
include CanCan::Ability

# set up each RolePermit instance to share this same Ability
# so that the can and cannot operations work on the same permission collection!
def self.role_permits ability
@role_permits = Permits::Roles.available.inject([]) do |permits, role|
permits << "Permit::#{role.to_s.camelize}".constantize.new(ability)
end
end

def initialize(user, request=nil)
# put ability logic here!
user ||= Guest.new
Ability.role_permits(self).each{|role_permit| role_permit.permit?(user, request) }
end
end
end
9 changes: 9 additions & 0 deletions lib/cancan-permits/permits/roles.rb
@@ -0,0 +1,9 @@
module Permits::Roles
def self.available
if Module.const_defined? :User
User.roles if User.respond_to? roles
else
[:guest, :admin]
end
end
end
29 changes: 29 additions & 0 deletions lib/generators/permits/permits_generator.rb
@@ -0,0 +1,29 @@
require 'sugar-high/array'

class PermitsGenerator < Rails::Generators::Base
desc "Creates a Permit for each role in 'app/permits' and ensures that the permit folder is added to Rails load path."

class_option :roles, :type => :array, :default => [], :desc => "Roles to create permits for"
# ORM to use
class_option :orm, :type => :string, :desc => "ORM to use", :default => 'active_record'

source_root File.dirname(__FILE__) + '/templates'

def main_flow
template_permit :admin, :admin_permit
roles.each do |role|
template_permit role if !role == :admin
end
end

protected

# TODO: merge with any registered roles in application
def roles
options[:roles].uniq.to_symbols
end

def template_permit name, template_name=nil
template "#{template_name || :permit}.rb", "app/permits/#{name}_permit.rb"
end
end
14 changes: 14 additions & 0 deletions lib/generators/permits/templates/admin_permit.rb
@@ -0,0 +1,14 @@
module Permit
class Admin < Base
def initialize(ability)
super
end

def permit?(user, request=nil)
super
return if !role_match? user

can :manage, :all
end
end
end
15 changes: 15 additions & 0 deletions lib/generators/permits/templates/permit.rb
@@ -0,0 +1,15 @@
module Permit
class <%= permit_name %> < Base
def initialize(ability)
super
end

def permit?(user, request=nil)
super
return if !role_match? user

# can :create, Comment
# owns(user, Comment)
end
end
end
19 changes: 19 additions & 0 deletions spec/cancan-permits/fixtures/ability.rb
@@ -0,0 +1,19 @@
module AuthAssistant
class Ability
include CanCan::Ability

# set up each RolePermit instance to share this same Ability
# so that the can and cannot operations work on the same permission collection!
def self.role_permits ability
@role_permits = AuthAssistant::Roles.available.inject([]) do |permits, role|
permits << "RolePermit::#{role.to_s.camelize}".constantize.new(ability)
end
end

def initialize(user, request=nil)
# put ability logic here!
user ||= Guest.new
Ability.role_permits(self).each{|role_permit| role_permit.permit?(user, request) }
end
end
end
14 changes: 14 additions & 0 deletions spec/cancan-permits/fixtures/permits/admin_permit.rb
@@ -0,0 +1,14 @@
module RolePermit
class Admin < Base
def initialize(ability)
super
end

def permit?(user, request=nil)
super
return if !role_match? user

can :manage, :all
end
end
end
26 changes: 26 additions & 0 deletions spec/cancan-permits/fixtures/permits/editor_permit.rb
@@ -0,0 +1,26 @@
module RolePermit
class Editor < Base
def initialize(ability)
super
end

def permit?(user, request=nil)
super
return if !role_match? user

# uses default user_id
owns(user, Comment)
#
owns(user, Post, :writer)
#
owns(user, Article, :author, :name)

# a user can manage comments he/she created
# can :manage, Comment do |comment|
# comment.try(:user) == user
# end

# can :create, Comment
end
end
end
25 changes: 25 additions & 0 deletions spec/cancan-permits/fixtures/permits/guest_permit.rb
@@ -0,0 +1,25 @@
module RolePermit
class Guest < Base
def initialize(ability)
super
end

def permit?(user, request=nil)
super
return if !role_match? user

can :read, [Comment, Post]
can [:update, :destroy], [Comment]
can :create, Article

# owns(user, Comment)

# a user can manage comments he/she created
# can :manage, Comment do |comment|
# comment.try(:user) == user
# end

# can :create, Comment
end
end
end

0 comments on commit 163f0e3

Please sign in to comment.