denny/ShinyCMS-ruby

View on GitHub
plugins/ShinyCMS/app/models/concerns/shinycms/shiny_user_authorization.rb

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
# frozen_string_literal: true

# ShinyCMS ~ https://shinycms.org
#
# Copyright 2009-2024 Denny de la Haye ~ https://denny.me
#
# ShinyCMS is free software; you can redistribute it and/or modify it under the terms of the GPL (version 2 or later)

module ShinyCMS
  # Concern for user authorization - powered by Pundit
  module ShinyUserAuthorization
    extend ActiveSupport::Concern

    included do
      # Associations

      has_many :user_capabilities, dependent: :destroy
      has_many :capabilities, through: :user_capabilities, inverse_of: :users

      # Instance methods

      def admin?
        general = CapabilityCategory.find_by( name: 'general' )
        capabilities.exists? name: 'view_admin_area', category: general
      end

      def not_admin?
        !admin?
      end

      def can?( capability_name, category_name = :general )
        return cached_can?( capability_name, category_name ) if @cached_capabilities.present?

        cc = CapabilityCategory.find_by( name: category_name.to_s )
        return true if capabilities.exists? name: capability_name.to_s, category: cc

        false
      end

      def cached_can?( capability, category = :general )
        return false if cached_capabilities.blank?

        return true if cached_capabilities[ category.to_s ]&.include? capability.to_s

        false
      end

      def cached_capabilities
        return @cached_capabilities if @cached_capabilities.present?

        @cached_capabilities =
          capabilities.joins( :category )
                      .pluck( 'shinycms_capability_categories.name', :name )
                      .group_by( &:shift )
                      .each_value( &:flatten! )
      end

      def cache_capabilities
        cached_capabilities if @cached_capabilities.blank?
        self
      end

      def capabilities=( capability_set )
        old_capabilities = user_capabilities.pluck( :capability_id ).sort
        new_capabilities = capability_set.keys.collect( &:to_i ).sort

        remove = old_capabilities - new_capabilities
        add    = new_capabilities - old_capabilities

        add.each do |capability_id|
          user_capabilities.create!( capability_id: capability_id )
        end

        user_capabilities.where( capability_id: remove ).delete_all
      end
    end

    class_methods do
      # Return all users that have the specified capability
      def that_can( capability, category = nil )
        category ||= 'general'
        ShinyCMS::Capability
          .find_by( capability: capability.to_s, category: category.to_s )
          .user_capabilities.collect( &:user )
      end

      # Check whether we have at least one admin who can create more admins
      def super_admins_exist?
        that_can( :add, :admin_users ).present?
      end
    end
  end
end