Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.
   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  namespace core_question\local\bank;
  18  
  19  /**
  20   * Tracks all the contexts related to the one we are currently editing questions and provides helper methods to check permissions.
  21   *
  22   * @package   core_question
  23   * @copyright 2007 Jamie Pratt me@jamiep.org
  24   * @author    2021 Safat Shahin <safatshahin@catalyst-au.net>
  25   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  26   */
  27  class question_edit_contexts {
  28  
  29      /**
  30       * @var \string[][] array of the capabilities.
  31       */
  32      public static $caps = [
  33              'editq' => [
  34                      'moodle/question:add',
  35                      'moodle/question:editmine',
  36                      'moodle/question:editall',
  37                      'moodle/question:viewmine',
  38                      'moodle/question:viewall',
  39                      'moodle/question:usemine',
  40                      'moodle/question:useall',
  41                      'moodle/question:movemine',
  42                      'moodle/question:moveall'],
  43              'questions' => [
  44                      'moodle/question:add',
  45                      'moodle/question:editmine',
  46                      'moodle/question:editall',
  47                      'moodle/question:viewmine',
  48                      'moodle/question:viewall',
  49                      'moodle/question:movemine',
  50                      'moodle/question:moveall'],
  51              'categories' => [
  52                      'moodle/question:managecategory'],
  53              'import' => [
  54                      'moodle/question:add'],
  55              'export' => [
  56                      'moodle/question:viewall',
  57                      'moodle/question:viewmine']];
  58  
  59      /**
  60       * @var array of contexts.
  61       */
  62      protected $allcontexts;
  63  
  64      /**
  65       * Constructor
  66       * @param \context $thiscontext the current context.
  67       */
  68      public function __construct(\context $thiscontext) {
  69          $this->allcontexts = array_values($thiscontext->get_parent_contexts(true));
  70      }
  71  
  72      /**
  73       * Get all the contexts.
  74       *
  75       * @return \context[] all parent contexts
  76       */
  77      public function all() {
  78          return $this->allcontexts;
  79      }
  80  
  81      /**
  82       * Get the lowest context.
  83       *
  84       * @return \context lowest context which must be either the module or course context
  85       */
  86      public function lowest() {
  87          return $this->allcontexts[0];
  88      }
  89  
  90      /**
  91       * Get the contexts having cap.
  92       *
  93       * @param string $cap capability
  94       * @return \context[] parent contexts having capability, zero based index
  95       */
  96      public function having_cap($cap) {
  97          $contextswithcap = [];
  98          foreach ($this->allcontexts as $context) {
  99              if (has_capability($cap, $context)) {
 100                  $contextswithcap[] = $context;
 101              }
 102          }
 103          return $contextswithcap;
 104      }
 105  
 106      /**
 107       * Get the contexts having at least one cap.
 108       *
 109       * @param array $caps capabilities
 110       * @return \context[] parent contexts having at least one of $caps, zero based index
 111       */
 112      public function having_one_cap($caps) {
 113          $contextswithacap = [];
 114          foreach ($this->allcontexts as $context) {
 115              foreach ($caps as $cap) {
 116                  if (has_capability($cap, $context)) {
 117                      $contextswithacap[] = $context;
 118                      break; // Done with caps loop.
 119                  }
 120              }
 121          }
 122          return $contextswithacap;
 123      }
 124  
 125      /**
 126       * Context having at least one cap.
 127       *
 128       * @param string $tabname edit tab name
 129       * @return \context[] parent contexts having at least one of $caps, zero based index
 130       */
 131      public function having_one_edit_tab_cap($tabname) {
 132          return $this->having_one_cap(self::$caps[$tabname]);
 133      }
 134  
 135      /**
 136       * Contexts for adding question and also using it.
 137       *
 138       * @return \context[] those contexts where a user can add a question and then use it.
 139       */
 140      public function having_add_and_use() {
 141          $contextswithcap = [];
 142          foreach ($this->allcontexts as $context) {
 143              if (!has_capability('moodle/question:add', $context)) {
 144                  continue;
 145              }
 146              if (!has_any_capability(['moodle/question:useall', 'moodle/question:usemine'], $context)) {
 147                  continue;
 148              }
 149              $contextswithcap[] = $context;
 150          }
 151          return $contextswithcap;
 152      }
 153  
 154      /**
 155       * Has at least one parent context got the cap $cap?
 156       *
 157       * @param string $cap capability
 158       * @return boolean
 159       */
 160      public function have_cap($cap) {
 161          return (count($this->having_cap($cap)));
 162      }
 163  
 164      /**
 165       * Has at least one parent context got one of the caps $caps?
 166       *
 167       * @param array $caps capability
 168       * @return boolean
 169       */
 170      public function have_one_cap($caps) {
 171          foreach ($caps as $cap) {
 172              if ($this->have_cap($cap)) {
 173                  return true;
 174              }
 175          }
 176          return false;
 177      }
 178  
 179      /**
 180       * Has at least one parent context got one of the caps for actions on $tabname
 181       *
 182       * @param string $tabname edit tab name
 183       * @return boolean
 184       */
 185      public function have_one_edit_tab_cap($tabname) {
 186          return $this->have_one_cap(self::$caps[$tabname]);
 187      }
 188  
 189      /**
 190       * Throw error if at least one parent context hasn't got the cap $cap
 191       *
 192       * @param string $cap capability
 193       */
 194      public function require_cap($cap) {
 195          if (!$this->have_cap($cap)) {
 196              throw new \moodle_exception('nopermissions', '', '', $cap);
 197          }
 198      }
 199  
 200      /**
 201       * Throw error if at least one parent context hasn't got one of the caps $caps
 202       *
 203       * @param array $caps capabilities
 204       */
 205      public function require_one_cap($caps) {
 206          if (!$this->have_one_cap($caps)) {
 207              $capsstring = join(', ', $caps);
 208              throw new \moodle_exception('nopermissions', '', '', $capsstring);
 209          }
 210      }
 211  
 212      /**
 213       * Throw error if at least one parent context hasn't got one of the caps $caps
 214       *
 215       * @param string $tabname edit tab name
 216       */
 217      public function require_one_edit_tab_cap($tabname) {
 218          if (!$this->have_one_edit_tab_cap($tabname)) {
 219              throw new \moodle_exception('nopermissions', '', '', 'access question edit tab '.$tabname);
 220          }
 221      }
 222  }