Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 39 and 310] [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 and 403]

   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  /**
  18   * This file contains the core_userfeedback class
  19   *
  20   * @package    core
  21   * @copyright  2020 Shamim Rezaie <shamim@moodle.com>
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  defined('MOODLE_INTERNAL') || die();
  26  
  27  /**
  28   * This Class contains helper functions for user feedback functionality.
  29   *
  30   * @copyright  2020 Shamim Rezaie <shamim@moodle.com>
  31   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  32   */
  33  class core_userfeedback {
  34      /**
  35       * @var int Ask user to give feedback a few days after each major upgrade.
  36       */
  37      public const REMIND_AFTER_UPGRADE = 1;
  38  
  39      /**
  40       * @var int Ask user to give feedback periodically.
  41       */
  42      public const REMIND_PERIODICALLY = 2;
  43  
  44      /**
  45       * @var int Do not ask user to give feedback.
  46       */
  47      public const REMIND_NEVER = 3;
  48  
  49      /**
  50       * Displays the feedback reminder block.
  51       */
  52      public static function print_reminder_block(): void {
  53          global $PAGE;
  54  
  55          static $jscalled = false;
  56  
  57          $actions = [
  58              [
  59                  'title' => get_string('calltofeedback_give'),
  60                  'url' => static::make_link()->out(false),
  61                  'data' => [
  62                      'action' => 'give',
  63                      'record' => 1,
  64                      'hide' => 1,
  65                  ],
  66              ],
  67              [
  68                  'title' => get_string('calltofeedback_remind'),
  69                  'url' => '#',
  70                  'data' => [
  71                      'action' => 'remind',
  72                      'record' => 1,
  73                      'hide' => 1,
  74                  ],
  75              ],
  76          ];
  77          $icon = [
  78              'pix' => 'i/bullhorn',
  79              'component' => 'core'
  80          ];
  81  
  82          \core\notification::add_call_to_action($icon, get_string('calltofeedback'), $actions, 'core/userfeedback');
  83  
  84          if (!$jscalled) {
  85              $jscalled = true;
  86              // Calling the following more than once will register event listeners twice.
  87              $PAGE->requires->js_call_amd('core/userfeedback', 'registerEventListeners');
  88          }
  89      }
  90  
  91      /**
  92       * Indicates whether the feedback reminder block should be shown or not.
  93       *
  94       * @return bool
  95       */
  96      public static function should_display_reminder(): bool {
  97          global $CFG;
  98  
  99          if (static::can_give_feedback()) {
 100              $give = get_user_preferences('core_userfeedback_give');
 101              $remind = get_user_preferences('core_userfeedback_remind');
 102  
 103              $lastactiontime = max($give ?: 0, $remind ?: 0);
 104  
 105              switch ($CFG->userfeedback_nextreminder) {
 106                  case static::REMIND_AFTER_UPGRADE:
 107                      $lastupgrade = static::last_major_upgrade_time();
 108                      if ($lastupgrade >= $lastactiontime) {
 109                          return $lastupgrade + ($CFG->userfeedback_remindafter * DAYSECS) < time();
 110                      }
 111                      break;
 112                  case static::REMIND_PERIODICALLY:
 113                      return $lastactiontime + ($CFG->userfeedback_remindafter * DAYSECS) < time();
 114                      break;
 115              }
 116          }
 117          return false;
 118      }
 119  
 120      /**
 121       * Prepare and return the URL of the feedback site
 122       *
 123       * @return moodle_url
 124       */
 125      public static function make_link(): moodle_url {
 126          global $CFG, $PAGE;
 127  
 128          $baseurl = $CFG->userfeedback_url ?? 'https://feedback.moodle.org/lms';
 129          $lang = clean_param(current_language(), PARAM_LANG); // Avoid breaking WS because of incorrect package langs.
 130          $moodleurl = $CFG->wwwroot;
 131          $moodleversion = $CFG->release;
 132          $theme = $PAGE->theme->name;
 133          $themeversion = get_config('theme_'.$theme, 'version');
 134  
 135          $url = new moodle_url($baseurl, [
 136              'lang' => $lang,
 137              'moodle_url' => $moodleurl,
 138              'moodle_version' => $moodleversion,
 139              'theme' => $theme,
 140              'theme_version' => $themeversion,
 141              'newtest' => 'Y', // Respondents might be using the same device/browser to fill out the survey.
 142                                // The newtest param resets the session.
 143          ]);
 144  
 145          return $url;
 146      }
 147  
 148      /**
 149       * Whether the current can give feedback.
 150       *
 151       * @return bool
 152       */
 153      public static function can_give_feedback(): bool {
 154          global $CFG;
 155  
 156          return !empty($CFG->enableuserfeedback) && isloggedin() && !isguestuser();
 157      }
 158  
 159      /**
 160       * Returns the last major upgrade time
 161       *
 162       * @return int
 163       */
 164      private static function last_major_upgrade_time(): int {
 165          global $DB;
 166  
 167          $targetversioncast = $DB->sql_cast_char2real('targetversion');
 168          $versioncast = $DB->sql_cast_char2real('version');
 169  
 170          // A time difference more than 3 months has to be a core upgrade.
 171          // Also, passing IGNORE_MULTIPLE because we are only interested in the first field and LIMIT is not cross-DB.
 172          $time = $DB->get_field_sql("SELECT timemodified
 173                                       FROM {upgrade_log}
 174                                      WHERE plugin = 'core' AND $targetversioncast - $versioncast > 30000
 175                                   ORDER BY timemodified DESC", null, IGNORE_MULTIPLE);
 176  
 177          return (int)$time;
 178      }
 179  }