SproutCMS

This is the code documentation for the SproutCMS project

source of /sprout/Helpers/PerRecordPerms.php

  1. <?php
  2. /*
  3.  * Copyright (C) 2017 Karmabunny Pty Ltd.
  4.  *
  5.  * This file is a part of SproutCMS.
  6.  *
  7.  * SproutCMS is free software: you can redistribute it and/or modify it under the terms
  8.  * of the GNU General Public License as published by the Free Software Foundation, either
  9.  * version 2 of the License, or (at your option) any later version.
  10.  *
  11.  * For more information, visit <http://getsproutcms.com>.
  12.  */
  13.  
  14. namespace Sprout\Helpers;
  15.  
  16. use Sprout\Controllers\Admin\ManagedAdminController;
  17. use karmabunny\pdb\Exceptions\RowMissingException;
  18.  
  19.  
  20. /**
  21.  * Helper for implementing per-record permissions
  22.  */
  23. class PerRecordPerms
  24. {
  25. /**
  26.   * Checks to see if per-record permissions apply to a particular controller
  27.   *
  28.   * @param ManagedAdminController $ctlr The controller to check
  29.   * @return bool True if per-record permissions apply
  30.   */
  31. public static function controllerRestricted(ManagedAdminController $ctlr)
  32. {
  33. $controller_name = $ctlr->getControllerName();
  34.  
  35. $q = "SELECT 1 FROM ~per_record_controllers WHERE name = ? AND active = 1";
  36. return (bool) Pdb::query($q, [$controller_name], 'count');
  37. }
  38.  
  39.  
  40. /**
  41.   * Checks if a given controller has at least one permission rule in place
  42.   *
  43.   * @param ManagedAdminController $ctlr The controller to check
  44.   * @return bool True if at least one permission rule exists
  45.   */
  46. public static function hasRecordPerms(ManagedAdminController $ctlr)
  47. {
  48. $controller_name = $ctlr->getControllerName();
  49.  
  50. $q = "SELECT id FROM ~per_record_permissions WHERE controller = ? LIMIT 1";
  51. return (bool) Pdb::query($q, [$controller_name], 'count');
  52. }
  53.  
  54.  
  55. /**
  56.   * Gets a clause to restrict a query to the set of categories the current admin belongs to
  57.   *
  58.   * @return string Example: "(operator_categories = '*' OR operator_categories LIKE '%,123,%')"
  59.   */
  60. public static function getCategoryClause()
  61. {
  62. $operator_cats = AdminAuth::getOperatorCategories();
  63.  
  64. $clauses = [];
  65. $clauses[] = "operator_categories = '*'";
  66. foreach ($operator_cats as $cat_id) {
  67. $cat_id = (int) $cat_id;
  68. $clauses[] = "operator_categories LIKE CONCAT('%,{$cat_id},%')";
  69. }
  70.  
  71. return '(' . implode(' OR ', $clauses) . ')';
  72. }
  73.  
  74.  
  75. /**
  76.   * Gets the permission details from the database
  77.   *
  78.   * @param ManagedAdminController $ctlr Admin controller for the record in question
  79.   * @param int $item_id ID of the record
  80.   * @return array Contains the following elements:
  81.   * int id
  82.   * array[int]|string categories (ids as int, or the string '*' for all)
  83.   * @throws RowMissingException if a row containing the permission data wasn't found
  84.   */
  85. public static function fetchDetails(ManagedAdminController $ctlr, $item_id)
  86. {
  87. $q = "SELECT id, operator_categories AS categories
  88. FROM ~per_record_permissions
  89. WHERE controller = ? AND item_id = ?";
  90. $row = Pdb::q($q, [$ctlr->getControllerName(), $item_id], 'row');
  91.  
  92. if ($row['categories'] != '*') {
  93. $row['categories'] = explode(',', trim($row['categories'], ','));
  94. }
  95.  
  96. return $row;
  97. }
  98.  
  99.  
  100. /**
  101.   * Save the permissions for a particular record
  102.   *
  103.   * @post array[int] _prm_categories IDs of operator categories which can edit the record
  104.   * @post bool _prm_all_cats If true, override _prm_categories; allow all operator categories to edit the record
  105.   * @param ManagedAdminController $ctlr Admin controller for the record in question
  106.   * @param int $item_id ID of the record
  107.   * @return void
  108.   */
  109. public static function save(ManagedAdminController $ctlr, $item_id)
  110. {
  111. if (!PerRecordPerms::controllerRestricted($ctlr)) {
  112. return;
  113. }
  114.  
  115. $perms = [
  116. 'controller' => $ctlr->getControllerName(),
  117. 'item_id' => $item_id,
  118. 'operator_categories' => '*',
  119. ];
  120. if (AdminPerms::canAccess('access_operators')) {
  121. $all_cat_ids = array_keys(AdminAuth::getAllCategories());
  122. } else {
  123. $all_cat_ids = AdminAuth::getOperatorCategories();
  124. }
  125.  
  126. $cat_ids = @$_POST['_prm_categories'];
  127. if (!is_array($cat_ids)) $cat_ids = [];
  128.  
  129. $cat_ids = array_intersect($cat_ids, $all_cat_ids);
  130.  
  131. // Always include primary administrators
  132. try {
  133. $cat_ids[] = AdminAuth::getPrimaryCategoryId();
  134. } catch (RowMissingException $ex) {
  135. }
  136.  
  137. $perms['operator_categories'] = ',' . implode(',', $cat_ids) . ',';
  138.  
  139. if (AdminPerms::canAccess('access_operators') and !empty($_POST['_prm_all_cats'])) {
  140. $perms['operator_categories'] = '*';
  141. }
  142.  
  143. $params = [];
  144. $conds = [
  145. 'controller' => $perms['controller'],
  146. 'item_id' => $item_id,
  147. ];
  148. $where = Pdb::buildClause($conds, $params);
  149. $q = "SELECT id FROM ~per_record_permissions WHERE {$where}";
  150. try {
  151. $perm_id = Pdb::q($q, $params, 'val');
  152. Pdb::update('per_record_permissions', $perms, ['id' => $perm_id]);
  153. } catch (RowMissingException $ex) {
  154. Pdb::insert('per_record_permissions', $perms);
  155. }
  156. }
  157. }
  158.