0.0
No commit activity in last 3 years
No release in over 3 years
The long awaited separation of groups and roles for Project Hydra.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

Runtime

 Project Readme

Hydra::Grouper

Gem Version Build Status Code Climate Test Coverage Documentation Status APACHE 2 License Contributing Guidelines

Details

A work in progress. See the example implementation for details. The big benefit of this refactor is we can say:

For a given user, what are all of my application abilities; That is to say what can I specifically do. It still requires reading the ruby code for the specific details of each ApplicationAbility that I have.

Glossary

  • User - A single person
  • Group - Users may be members of groups
  • FunctionalRole - For combining the application abilities that are all needed to perform a conceptual activity (think of this as a molecule). There is a relationship between a FunctionalRole and either a User or a Group. We are working on naming that concept (for now lets call it assignee).
  • Hyrax::ApplicationAbility - see below (think of this as an atom)

Example Implementation

class User < ActiveRecord::Base
  has_many :groups, through: :group_memberships
  has_many :group_memberships
  has_many :functional_roles, as: :assignee
end

class GroupMembership < ActiveRecord::Base
  belongs_to :user
  belongs_to :group
end

class Group < ActiveRecord::Base
  has_many :group_memberships
  has_many :users, through: :group_memberships
  has_many :functional_roles, as: :assignee
end

class FunctionalRole < ActiveRecord::Base
  belongs_to :assignee, polymorphic: true
  has_many :functional_abilities
end

class FunctionalAbility < ActiveRecord::Base
  belongs_to :functional_role

  def application_ability_class
    # We have a column :application_ability_class_name
    # with an example value of Hyrax::ApplicationAbility::AdminApplicationAbility
    application_ability_class_name.constantize
  end
end

module Hyrax # This should perhaps be pushed into the Hydra namespace.
  module ApplicationAbility
    # @api public
    #
    # Applies the functional abilities to the given ability based on the given ability's current_user.
    # This allows for us to plugin additional abilities in implementing applications without the explicit need
    # to re-open the Ability class. (more on that later).
    #
    # @param [Ability] ability - an object that implements the CanCan::Ability interface
    # @return [Ability]
    def self.append_abilities_to!(ability:)
      functionality_abilities_for(user: ability.current_user).each do |functional_ability|
        functional_ability.new(ability: ability).apply
      end
      ability
    end

    # @api public
    #
    # For the given user, return an enumerable of all of the ApplicationAbility objects
    # that apply, based on the user and their group memberships relation to their Functional Role
    # at the institution
    #
    # @param [User] user for which we are looking up their assigned functional abilities.
    # @return [Array<Hyrax::ApplicationAbility::BaseApplicationAbility]
    # @note This is the place for the new and improved user groups to be leveraged
    def self.functionality_abilities_for(user:)
      # TODO: Define an implementation of how this is looked up
    end

    # An abstract class that defines the interface for implementations of a ApplicationAbility.
    # A ApplicationAbility is a name-able atomic unit of permissions.
    class BaseApplicationAbility
      extend Forwardable
      def initialize(ability:)
        @ability = ability
      end
      def_delegators :@ability, :can, all # etc.

      def apply
        raise NotImplementedError, "Subclasses must implement #apply"
      end
    end

    # The set of specific cans and cannots that are applicable for an Admin.
    class AdminApplicationAbility < BaseApplicationAbility
      def apply
        # NOTE: We are removing the short-circuit tradition of a guard `return unless admin?`
        #       This ApplicationAbility will not be applied if it is not one of your functional roles at the institution.
        can :read, :admin_dashboard
      end
    end
  end

  module Ability
    extend ActiveSupport::Concern

    # @note assumes we are previously including Hydra::Ability
    def hydra_default_permissions
      super
      apply_functional_abilities
    end

    private

    def apply_functional_abilities
      Hyrax::ApplicationAbility.append_abilities_to!(ability: self)
    end
  end
end