Abilities

 view release on metacpan or  search on metacpan

lib/Abilities.pm  view on Meta::CPAN

		
		# it is constrained (or at least it should be, let's make
		# sure we have an array-ref of constraints)
		if (ref $self->abilities->{$action} eq 'ARRAY') {
			return 1 if $constraint eq '_any_';	# caller wants to know if
								# user/role has any constraint,
								# which we now know is true
			foreach (@{$self->abilities->{$action}}) {
				return 1 if $_ eq $constraint;
			}
			return; # constraint not met
		} else {
			carp "Expected an array-ref of constraints for action $action, received ".ref($self->abilities->{$action}).", returning false.";
			return;
		}
	} else {
		# no constraint, make sure user/role's ability is indeed
		# not constrained
		return if ref $self->abilities->{$action}; # implied: ref == 'ARRAY', thus constrained
		return 1; # not constrained
	}
}

=head2 assigned_role( $role_name )

This method receives a role name and returns a true value if the user/role
is a direct member of the provided role. Only direct membership is checked,
so the user/role must be specifically assigned to the provided role, and
not to a role that inherits from that role (see L</"does_role( $role )">
instead).

=cut

sub assigned_role {
	my ($self, $role) = @_;

	return unless $role;

	foreach ($self->roles) {
		return 1 if $_ eq $role;
	}

	return;
}

=head2 does_role( $role_name )

Receives the name of a role, and returns a true value if the user/role
inherits the abilities of the provided role. This method takes inheritance
into account, so if a user was directly assigned to the 'admins' role,
and the 'admins' role inherits from the 'devs' role, then C<does_role('devs')>
will return true for that user (while C<assigned_role('devs')> returns false).

=cut

sub does_role {
	my ($self, $role) = @_;

	return unless $role;

	foreach (map([$_, $self->get_role($_)], $self->roles)) {
		return 1 if $_->[0] eq $role || $_->[1]->does_role($role);
	}

	return;
}

=head2 abilities()

Returns a hash reference of all the abilities a user/role object can
perform, after consolidating abilities inherited from roles (including
recursively) and directly granted. Keys in the hash-ref will be names
of actions, values will be 1 (for yes/no actions) or a single-item array-ref
with the name of a constraint (for constrained actions).

=cut

sub abilities {
	my $self = shift;

	my $abilities = {};

	# load direct actions granted to this user/role
	foreach ($self->actions) {
		# is this action constrained/scoped?
		unless (ref $_) {
			$abilities->{$_} = 1;
		} elsif (ref $_ eq 'ARRAY' && scalar @$_ == 2) {
			$abilities->{$_->[0]} = [$_->[1]];
		} else {
			carp "Can't handle action of reference ".ref($_);
		}
	}

	# load actions from roles this user/role consumes
	my @hashes = map { $self->get_role($_)->abilities } $self->roles;

	# merge all abilities
	while (scalar @hashes) {
		$abilities = merge($abilities, shift @hashes);
	}

	return $abilities;
}

=head1 UPGRADING FROM v0.2

Up to version 0.2, C<Abilities> required the C<roles> and C<actions>
attributes to return objects. While this made it easier to calculate
abilities, it made this system a bit less flexible.

In version 0.3, C<Abilities> changed the requirement such that both these
attributes need to return strings (the names of the roles/actions). If your implementation
has granted roles and actions stored in a database by names, this made life a bit easier
for you. On other implementations, however, this has the potential of
requiring you to write a bit more code. If that is the case, I apologize,
but keep in mind that you can still store granted roles and actions
any way you want in a database (either by names or by references), just
as long as you correctly provide C<roles> and C<actions>.

Unfortunately, in both versions 0.3 and 0.4, I made a bit of a mess
that rendered both versions unusable. While I documented the C<roles>
attribute as requiring role names instead of role objects, the actual
implementation still required role objects. This has now been fixed,
but it also meant I had to add a new requirement: consuming classes
now have to provide a method called C<get_role()> that takes the name
of a role and returns its object. This will probably means loading the
role from a database and blessing it into your role class that also consumes
this module.

I apologize for any inconvenience this might have caused.

=head1 AUTHOR

Ido Perlmuter, C<< <ido at ido50 dot net> >>

=head1 BUGS

Please report any bugs or feature requests to C<bug-abilities at rt.cpan.org>, or through
the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Abilities>. I will be notified, and then you'll
automatically be notified of progress on your bug as I make changes.

=head1 SUPPORT

You can find documentation for this module with the perldoc command.

	perldoc Abilities

You can also look for information at:

=over 4

=item * RT: CPAN's request tracker

L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Abilities>



( run in 2.038 seconds using v1.01-cache-2.11-cpan-140bd7fdf52 )