0.0
The project is in a healthy, maintained state
Continuing professional development and audits rails engine
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
 Project Readme

Effective CPD

Continuing professional development.

An admin creates a set of categories, activites and rules. User enters number of hours or work done to have a scored statement. Audits.

Works with action_text for content bodies, and active_storage for file uploads.

Getting Started

This requires Rails 6+ and Twitter Bootstrap 4 and just works with Devise.

Please first install the effective_datatables gem.

Please download and install the Twitter Bootstrap4

Add to your Gemfile:

gem 'haml-rails' # or try using gem 'hamlit-rails'
gem 'effective_cpd'

Run the bundle command to install it:

bundle install

Then run the generator:

rails generate effective_cpd:install

The generator will install an initializer which describes all configuration options and creates a database migration.

If you want to tweak the table names, manually adjust both the configuration file and the migration now.

Then migrate the database:

rake db:migrate

Please add the following to your User model:

has_many :cpd_statements, -> { Effective::CpdStatement.sorted }, class_name: 'Effective::CpdStatement'

Use the following datatables to display to your user their statements and audits and audit reviews:

%h2 Continuing Professional Development

- # Auditee datatables (4)
- auditing = EffectiveCpdAvailableAuditsDatatable.new(self)
- if auditing.present?
  .mt-4
    %p You have been selected for audit:
    = render_datatable(auditing, simple: true)

- audited = EffectiveCpdCompletedAuditsDatatable.new(self)
- if audited.present?
  .mt-4
    %p You have completed these past audits:
    = render_datatable(audited, simple: true)

- available = EffectiveCpdAvailableCyclesDatatable.new(self)
- if available.present?
  .mt-4
    %p Please submit a CPD statement for the following available #{cpd_cycles_label}:
    = render_datatable(available, simple: true)

- completed = EffectiveCpdCompletedStatementsDatatable.new(self)
- if completed.present?
  .mt-4
    %p You have completed these past statements:
    = render_datatable(completed, simple: true)

- # Auditor / Audit reviewer datatables (2)
- reviewing = EffectiveCpdAvailableAuditReviewsDatatable.new(self)
- if reviewing.present?
  .mt-4
    %p You have been selected to review the following audits:
    = render_datatable(reviewing, simple: true)

- reviewed = EffectiveCpdCompletedAuditReviewsDatatable.new(self)
- if reviewed.present?
  .mt-4
    %p You have completed these past audit reviews:
    = render_datatable(reviewed, simple: true)

On the Admin::Users#edit, you can use the following datatables as well:

%h2 CPD Statements
- datatable = Admin::EffectiveCpdStatementsDatatable.new(user_id: user.id, user_type: user.class.name)
= render_datatable(datatable, inline: true)

%h2 CPD Audits
- datatable = Admin::EffectiveCpdAuditsDatatable.new(user_id: user.id, user_type: user.class.name)
= render_datatable(datatable)

Add a link to the admin menu:

- if can? :admin, :effective_cpd
  - if can? :index, Effective::CpdCategory
    = nav_link_to 'CPD Categories', effective_cpd.admin_cpd_categories_path

  - if can? :index, Effective::CpdCycle
    = nav_link_to 'CPD Cycles', effective_cpd.admin_cpd_cycles_path

  - if can? :index, Effective::CpdAuditLevel
    = nav_link_to 'CPD Audit Levels', effective_cpd.admin_cpd_audit_levels_path

  = nav_divider

  - if can? :index, Effective::CpdStatement
    = nav_link_to 'CPD Statements', effective_cpd.admin_cpd_statements_path

  - if can? :index, Effective::CpdAudit
    = nav_link_to 'CPD Audits', effective_cpd.admin_cpd_audits_path

Configuration

As an admin, visit the CPD Categories, then CPD Cycles, and CPD Audit levels.

Once all these 3 areas have been configured, users can submit statements and audits can be performed.

Required Score

You can specify the required score in the CPD Cycle.

You can also programatically do it. Add the following to your user class.

# This is an ActiveRecord concern to add the has_many :cpd_statements
effective_cpd_user

# We require 100 points in the last 3 years.
def cpd_statement_required_score(cpd_statement)
  # We always consider the 3 year window, of the passed cpd_statement and the last two statements
  last_two_statements = cpd_statements.select do |statement|
    statement.completed? && statement.cpd_cycle_id < cpd_statement.cpd_cycle_id
  end.last(2)

  # They can submit 0 0 100
  return 0 if last_two_statements.length < 2

  # 100 points in the last 3 years.
  required_score = 100

  # Score so far
  existing_score = last_two_statements.sum { |statement| statement.score }
  raise('expected existing_score to be >= 0') if existing_score < 0

  # Required score minus previous
  return 0 if existing_score >= required_score
  (required_score - existing_score)
end

Authorization

All authorization checks are handled via the effective_resources gem found in the config/initializers/effective_resources.rb file.

Permissions

The permissions you actually want to define are as follows (using CanCan):

# Regular signed up user. Guest users not supported.
if user.persisted?
  can :new, Effective::CpdStatement
  can [:index, :show, :update], Effective::CpdStatement, user_id: user.id
  can [:index, :show], Effective::CpdCycle
  can([:create, :update, :destroy], Effective::CpdStatementActivity) { |sa| sa.cpd_statement.user_id == user.id }
  can [:index, :show, :update], Effective::CpdAudit, user_id: user.id
end

if user.reviewer?
  can [:index], Effective::CpdAudit
  can [:index, :show, :update], Effective::CpdAuditReview, user_id: user.id
end

if user.admin?
  can :admin, :effective_cpd
  can :manage, Effective::CpdActivity
  can :manage, Effective::CpdCategory
  can :manage, Effective::CpdCycle
  can :manage, Effective::CpdRule

  can([:index, :show], Effective::CpdStatement)
  can(:unsubmit, Effective::CpdStatement) { |statement| statement.completed? }

  can :manage, Effective::CpdAuditLevel
  can :manage, Effective::CpdAuditLevelSection
  can :manage, Effective::CpdAuditLevelQuestion

  can :manage, Effective::CpdAudit
  can :manage, Effective::CpdAuditReview
end

License

MIT License. Copyright Code and Effect Inc.

Testing

Run tests by:

rails test

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Bonus points for test coverage
  6. Create new Pull Request