The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Abilities::Features - Extends Abilities with plan management for subscription-based web services.

VERSION

version 0.5

SYNOPSIS

        package Customer;
        
        use Moose; # or Moo
        with 'Abilities::Features';
        
        # ... define required methods ...
        
        # somewhere else in your code:

        # get a customer object that consumed the Abilities::Features role
        my $customer = MyApp->get_customer('some_company');
                
        # check if the customer has a certain feature
        if ($customer->has_feature('ssl_encryption')) {
                &initiate_https_connection();
        } else {
                &initiate_http_connection();
        }

DESCRIPTION

This Moo role extends the ability-based authorization system defined by the Abilities module with customer and plan management for subscription-based web services. This includes paid services, where customers subscribe to a plan from a list of available plans, each plan with a different set of features. Examples of such a service are GitHub (a Git revision control hosting service, where customers purchase a plan that provides them with different amounts of storage, SSH support, etc.) and MailChimp (email marketing service where customers purchase plans that provide them with different amounts of monthly emails to send and other features).

The Abilities role defined three entities: users, roles and actions. This role defines three more entities: customers, plans and features. Customers are organizations, companies or individuals that subscribe to your web service. They can subscribe to any number of plans, and thus be provided with the features of these plans. The users from the Abilities module will now be children of the customers. They still go on being members of roles and performing actions they are granted with, but now possibly only within the scope of their parent customer, and to the limits defined in the customer's plan. Plans can inherit features from other plans, allowing for defining plans faster and easier.

Customer and plan objects are meant to consume the Abilities::Features role. Entities is a reference implementation of both the Abilities and Abilities::Features roles. It is meant to be used as-is by web applications, or just as an example of how a user management and authorization system that consumes these roles might look like. Entities::Customer and Entities::Plan are customer and plan classes that consume this role.

Just like in Abilities, features can be constrained. For more info, see "CONSTRAINTS" in Abilities.

More information about how these roles work can be found in the Entities documentation.

REQUIRED METHODS

Customer and plan classes that consume this role are required to provide the following methods:

plans()

This method returns a list of all plan names that a customer has subscribed to, or that a plan inherits from.

Example return structure:

        ( 'starter', 'diamond' )

NOTE: In previous versions, this method was required to return an array of plan objects, not a list of plan names. This has been changed in version 0.3.

features()

This method returns a list of all feature names that a customer has explicitely been given, or that a plan has. If a certain feature is constrained, then it should be added to the list as an array reference with two items, the first being the name of the feature, the second being the name of the constraint.

Example return structure:

        ( 'ssh_access', [ 'multiple_users', 5 ] )

NOTE: In previous versions, this method was required to return an array of feature objects, not a list of feature names. This has been changed in version 0.3.

get_plan( $name )

Returns the object of the plan named $plan.

METHODS

Classes that consume this role will have the following methods provided to them:

has_feature( $feature_name, [ $constraint ] )

Receives the name of a feature, and possibly a constraint, and returns a true value if the customer/plan has that feature, false value otherwise.

in_plan( $plan_name )

Receives the name of plan and returns a true value if the user/customer is a direct member of the provided plan(s). Only direct association is checked, so the user/customer must be specifically assigned to that plan, and not to a plan that inherits from that plan (see "inherits_plan( $plan_name )" instead).

inherits_plan( $plan_name )

Returns a true value if the customer/plan inherits the features of the provided plan(s). If a customer belongs to the 'premium' plan, and the 'premium' plan inherits from the 'basic' plan, then inherits_plan('basic') will be true for that customer, while in_plan('basic') will be false.

available_features

Returns a hash-ref of all features available to a customer/plan object, after consolidating features from inherited plans (recursively) and directly granted. Keys of this hash-ref will be the names of the features, values will either be 1 (for yes/no features), or a single-item array-ref with a name of a constraint (for constrained features).

UPGRADING FROM v0.2

Up to version 0.2, Abilities::Features required the plans and features attributes to return objects. While this made it easier to calculate available features, it made this system a bit less flexible.

In version 0.3, Abilities::Features changed the requirement such that both these attributes need to return strings (the names of the plans/features). If your implementation has granted plans and features 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 plans and features any way you want in a database (either by names or by references), just as long as you correctly provide plans and features.

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 plans attribute as requiring plan names instead of plan objects, the actual implementation still required plan 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 get_plan() that takes the name of a plan and returns its object. This will probably means loading the plan from a database and blessing it into your plan class that also consumes this module.

I apologize for any inconvenience this might have caused.

AUTHOR

Ido Perlmuter, <ido at ido50 dot net>

BUGS

Please report any bugs or feature requests to bug-abilities at rt.cpan.org, or through the web interface at 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.

SUPPORT

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

        perldoc Abilities::Features

You can also look for information at:

LICENSE AND COPYRIGHT

Copyright 2010-2013 Ido Perlmuter.

This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License.

See http://dev.perl.org/licenses/ for more information.