Module: CanDo

Defined in:
lib/cando.rb,
lib/models/role.rb,
lib/models/user.rb,
lib/models/capability.rb

Defined Under Namespace

Classes: Capability, ConfigCannotBlockError, ConfigConnectionError, ConfigDBError, DBNotConnected, Role, User

Constant Summary collapse

@@cannot_block_proc =
nil

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.cannot_block(&block) ⇒ Object

Block to be executed if can("user", :cap) { } will not be executed due to missing capability

  • the block needs to accept two arguments |user_urn, capability|

  • this function should be called in the init method (see there for an example).

  • if this block gets executed, it’ll have the context of the can(...){ } call



68
69
70
71
72
73
74
75
76
77
# File 'lib/cando.rb', line 68

def self.cannot_block(&block)
  if !block
    raise ConfigCannotBlockError.new("CanDo#cannot_block expects block")
  end
  if block.arity != 2
    raise ConfigCannotBlockError.new("CanDo#cannot_block expects block expecting two arguments |user_urn, capability|")
  end

  @@cannot_block_proc = block
end

.connect(connection) ⇒ Object

Connect to database

Pass in a connection string of the form

mysql://user:passwd@host:port/database

Raises CanDo::ConfigConnectionError or CanDo::ConfigDBError when problems occur



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/cando.rb', line 86

def self.connect(connection)
  if connection =~ /sqlite/
    raise ConfigDBError.new("sqlite is not supported as it misses certain constraints")
  end

  begin
    @db = Sequel.connect(connection)
    @db.test_connection
    @db
  rescue => e
    raise ConfigConnectionError.new(<<-EOF
Error connecting to database. Be sure to pass in a database config like 'mysql://cando_user:cando_passwd@localhost/cando':
#{e.message}
EOF
    )
  end
end

.dbObject

Return current database connection

raises DBNotConnected exception if CanDo is not connected to a db



26
27
28
# File 'lib/cando.rb', line 26

def self.db
  @db or raise DBNotConnected.new("CanDo is not connected to a database")
end

.init(&block) ⇒ Object

Initializes CanDo

This method should be called during boot up to configure CanDo with the db connection and the cannot_block:

CanDo.init do
  # this will be executed if the user does not have the
  # asked-for capability (only applies if 'can' is passed a block)
  cannot_block do |user_urn, capability|
    raise "#{user_urn} can not #{capability} .. user capabilities are: #{capabilities(user_urn)}"
  end

  connect "mysql://cando_user:cando_passwd@host:port/database"
end



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/cando.rb', line 46

def self.init(&block)
  CanDo.instance_eval &block

  begin
    Sequel::Model.db.test_connection
  rescue ::Sequel::Error => e
    raise DBNotConnected.new("No database connection established. Have you called 'connect' within the 'CanDo.init' block? Sequel error message is:\n#{e.message}")
  end

  Dir.glob(File.expand_path("#{__FILE__}/../models/*.rb")).each do |model|
    require_relative model
  end

  Sequel::Model.db
end

Instance Method Details

#assign_roles(user, roles) ⇒ Object

Assign role(s) to a user

assign_roles("user_urn", ["role_name", role_object])
  • if no user with that id exist, a new one will be created

  • if a role does not exist, an CanDo::Role::UndefinedRole is raised

  • you can pass in a role object or just role names (see example above)

  • pass in an empty array to remove all roles from user



154
155
156
# File 'lib/cando.rb', line 154

def assign_roles(user, roles)
  CanDo::User.find_or_create(:id => user).assign_roles(roles)
end

#can(user_urn, capability) ⇒ Object

Method to check whether a user has a certain capability

It can be used in two manners:

  • pass it a block which is only executed if the user has the capability:

    can("user_urn", :capability) do
      puts "woohoo"
    end
    

this will execute cannot_block if user is missing this capability.

  • use as an expression that return true or false/nil

    if can("user_urn", :capability) do
       puts "woohoo"
    else
       puts "epic fail"
    end
    


124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/cando.rb', line 124

def can(user_urn, capability)
  user = CanDo::User.find(:id => user_urn)
  has_permission = user && user.can(capability)
  if block_given?
    if has_permission
     return yield
    end
    if @@cannot_block_proc
      self.instance_exec user_urn, capability, &@@cannot_block_proc
    end
  end

  has_permission
end

#capabilities(user) ⇒ Object

Get user’s capabilities

returns an array of strings



171
172
173
174
175
176
# File 'lib/cando.rb', line 171

def capabilities(user)
  user = CanDo::User.first(:id => user)
  return [] unless user

  user.capabilities.map{|x| x.to_sym }
end

#define_role(role, capabilities) ⇒ Object

Define or redefine a role

Capabilities will be created if they don’t exist yet



142
143
144
# File 'lib/cando.rb', line 142

def define_role(role, capabilities)
  CanDo::Role.define_role(role, capabilities)
end

#roles(user) ⇒ Object

Get user’s roles

returns an array of strings



161
162
163
164
165
166
# File 'lib/cando.rb', line 161

def roles(user)
  user = CanDo::User.first(:id => user)
  return [] unless user

  user.roles.map(&:id)
end