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.

Differences Between: [Versions 400 and 401]

   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 mod_bigbluebuttonbn\completion;
  18  
  19  use core_completion\activity_custom_completion;
  20  use mod_bigbluebuttonbn\instance;
  21  use mod_bigbluebuttonbn\logger;
  22  use moodle_exception;
  23  use stdClass;
  24  
  25  /**
  26   * Class custom_completion
  27   *
  28   * @package   mod_bigbluebuttonbn
  29   * @copyright 2010 onwards, Blindside Networks Inc
  30   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  31   * @author    Laurent David (laurent@call-learning.fr)
  32   */
  33  class custom_completion extends activity_custom_completion {
  34  
  35      /**
  36       * Filters for logs
  37       */
  38      const FILTERS = [
  39          'completionattendance' => [logger::EVENT_SUMMARY],
  40          'completionengagementchats' => [logger::EVENT_SUMMARY],
  41          'completionengagementtalks' => [logger::EVENT_SUMMARY],
  42          'completionengagementraisehand' => [logger::EVENT_SUMMARY],
  43          'completionengagementpollvotes' => [logger::EVENT_SUMMARY],
  44          'completionengagementemojis' => [logger::EVENT_SUMMARY],
  45      ];
  46  
  47      /**
  48       * Get current state
  49       *
  50       * @param string $rule
  51       * @return int
  52       */
  53      public function get_state(string $rule): int {
  54          // Get instance details.
  55          $instance = instance::get_from_cmid($this->cm->id);
  56  
  57          if (empty($instance)) {
  58              throw new moodle_exception("Can't find bigbluebuttonbn instance {$this->cm->instance}");
  59          }
  60  
  61          // Default return value.
  62          $returnedvalue = COMPLETION_INCOMPLETE;
  63          $filters = self::FILTERS[$rule] ?? [logger::EVENT_SUMMARY];
  64          $logs = logger::get_user_completion_logs($instance, $this->userid, $filters);
  65  
  66          if (method_exists($this, "get_{$rule}_value")) {
  67              $completionvalue = $this->aggregate_values($logs, self::class . "::get_{$rule}_value");
  68              if ($completionvalue) {
  69                  // So in this case we check the value set in the module setting. If we go over the threshold, then
  70                  // this is complete.
  71                  $rulevalue = $instance->get_instance_var($rule);
  72                  if (!is_null($rulevalue)) {
  73                      if ($rulevalue <= $completionvalue) {
  74                          $returnedvalue = COMPLETION_COMPLETE;
  75                      }
  76                  } else {
  77                      // If there is at least a hit, we consider it as complete.
  78                      $returnedvalue = $completionvalue ? COMPLETION_COMPLETE : COMPLETION_INCOMPLETE;
  79                  }
  80              }
  81          }
  82          return $returnedvalue;
  83      }
  84  
  85      /**
  86       * Compute current state from logs.
  87       *
  88       * @param array $logs
  89       * @param callable $logvaluegetter
  90       * @return int the sum of all values for this particular event (it can be a duration or a number of hits)
  91       */
  92      protected function aggregate_values(array $logs, callable $logvaluegetter): int {
  93          if (empty($logs)) {
  94              // As completion by engagement with $rulename hand was required, the activity hasn't been completed.
  95              return 0;
  96          }
  97  
  98          $value = 0;
  99          foreach ($logs as $log) {
 100              $value += $logvaluegetter($log);
 101          }
 102  
 103          return $value;
 104      }
 105  
 106      /**
 107       * Fetch the list of custom completion rules that this module defines.
 108       *
 109       * @return array
 110       */
 111      public static function get_defined_custom_rules(): array {
 112          return [
 113              'completionattendance',
 114              'completionengagementchats',
 115              'completionengagementtalks',
 116              'completionengagementraisehand',
 117              'completionengagementpollvotes',
 118              'completionengagementemojis',
 119          ];
 120      }
 121  
 122      /**
 123       * Returns an associative array of the descriptions of custom completion rules.
 124       *
 125       * @return array
 126       */
 127      public function get_custom_rule_descriptions(): array {
 128          $completionengagementchats = $this->cm->customdata['customcompletionrules']['completionengagementchats'] ?? 1;
 129          $completionengagementtalks = $this->cm->customdata['customcompletionrules']['completionengagementtalks'] ?? 1;
 130          $completionengagementraisehand = $this->cm->customdata['customcompletionrules']['completionengagementraisehand'] ?? 1;
 131          $completionengagementpollvotes = $this->cm->customdata['customcompletionrules']['completionengagementpollvotes'] ?? 1;
 132          $completionengagementemojis = $this->cm->customdata['customcompletionrules']['completionengagementemojis'] ?? 1;
 133          $completionattendance = $this->cm->customdata['customcompletionrules']['completionattendance'] ?? 1;
 134          return [
 135              'completionengagementchats' => get_string('completionengagementchats_desc', 'mod_bigbluebuttonbn',
 136                  $completionengagementchats),
 137              'completionengagementtalks' => get_string('completionengagementtalks_desc', 'mod_bigbluebuttonbn',
 138                  $completionengagementtalks),
 139              'completionengagementraisehand' => get_string('completionengagementraisehand_desc', 'mod_bigbluebuttonbn',
 140                  $completionengagementraisehand),
 141              'completionengagementpollvotes' => get_string('completionengagementpollvotes_desc', 'mod_bigbluebuttonbn',
 142                  $completionengagementpollvotes),
 143              'completionengagementemojis' => get_string('completionengagementemojis_desc', 'mod_bigbluebuttonbn',
 144                  $completionengagementemojis),
 145              'completionattendance' => get_string('completionattendance_desc', 'mod_bigbluebuttonbn',
 146                  $completionattendance),
 147          ];
 148      }
 149  
 150      /**
 151       * Returns an array of all completion rules, in the order they should be displayed to users.
 152       *
 153       * @return array
 154       */
 155      public function get_sort_order(): array {
 156          return [
 157              'completionview',
 158              'completionengagementchats',
 159              'completionengagementtalks',
 160              'completionengagementraisehand',
 161              'completionengagementpollvotes',
 162              'completionengagementemojis',
 163              'completionattendance',
 164          ];
 165      }
 166  
 167      /**
 168       * Get current states of completion in a human-friendly version
 169       *
 170       * @return string[]
 171       */
 172      public function get_printable_states(): array {
 173          $result = [];
 174          foreach ($this->get_available_custom_rules() as $rule) {
 175              $result[] = $this->get_printable_state($rule);
 176          }
 177          return $result;
 178      }
 179  
 180      /**
 181       * Get current states of completion for a rule in a human-friendly version
 182       *
 183       * @param string $rule
 184       * @return string
 185       */
 186      private function get_printable_state(string $rule): string {
 187          // Get instance details.
 188          $instance = instance::get_from_cmid($this->cm->id);
 189  
 190          if (empty($instance)) {
 191              throw new moodle_exception("Can't find bigbluebuttonbn instance {$this->cm->instance}");
 192          }
 193          $summary = "";
 194          $filters = self::FILTERS[$rule] ?? [logger::EVENT_SUMMARY];
 195          $logs = logger::get_user_completion_logs($instance, $this->userid, $filters);
 196  
 197          if (method_exists($this, "get_{$rule}_value")) {
 198              $summary = get_string(
 199                  $rule . '_event_desc',
 200                  'mod_bigbluebuttonbn',
 201                  $this->aggregate_values($logs, self::class . "::get_{$rule}_value")
 202              );
 203          }
 204          return $summary;
 205      }
 206  
 207      /**
 208       * Get current state in a friendly version
 209       *
 210       * @param string $rule
 211       * @return string
 212       */
 213      public function get_last_log_timestamp(string $rule): string {
 214          // Get instance details.
 215          $instance = instance::get_from_cmid($this->cm->id);
 216  
 217          if (empty($instance)) {
 218              throw new moodle_exception("Can't find bigbluebuttonbn instance {$this->cm->instance}");
 219          }
 220          $filters = self::FILTERS[$rule] ?? [logger::EVENT_SUMMARY];
 221          return logger::get_user_completion_logs_max_timestamp($instance, $this->userid, $filters);
 222      }
 223  
 224      /**
 225       * Get attendance summary value
 226       *
 227       * @param stdClass $log
 228       * @return int
 229       */
 230      protected static function get_completionattendance_value(stdClass $log): int {
 231          $summary = json_decode($log->meta);
 232          return empty($summary->data->duration) ? 0 : (int)($summary->data->duration / 60);
 233      }
 234  
 235      /**
 236       * Get general completion engagement value
 237       *
 238       * @param stdClass $log
 239       * @return int
 240       */
 241      protected static function get_completionengagementchats_value(stdClass $log): int {
 242          return self::get_completionengagement_value($log, 'chats');
 243      }
 244  
 245      /**
 246       * Get general completion engagement value
 247       *
 248       * @param stdClass $log
 249       * @return int
 250       */
 251      protected static function get_completionengagementtalks_value(stdClass $log): int {
 252          return self::get_completionengagement_value($log, 'talks');
 253      }
 254  
 255      /**
 256       * Get general completion engagement value
 257       *
 258       * @param stdClass $log
 259       * @return int
 260       */
 261      protected static function get_completionengagementraisehand_value(stdClass $log): int {
 262          return self::get_completionengagement_value($log, 'raisehand');
 263      }
 264  
 265      /**
 266       * Get general completion engagement value
 267       *
 268       * @param stdClass $log
 269       * @return int
 270       */
 271      protected static function get_completionengagementpollvotes_value(stdClass $log): int {
 272          return self::get_completionengagement_value($log, 'poll_votes');
 273      }
 274  
 275      /**
 276       * Get general completion engagement value
 277       *
 278       * @param stdClass $log
 279       * @return int
 280       */
 281      protected static function get_completionengagementemojis_value(stdClass $log): int {
 282          return self::get_completionengagement_value($log, 'emojis');
 283      }
 284  
 285      /**
 286       * Get general completion engagement value
 287       *
 288       * @param stdClass $log
 289       * @param string $type
 290       * @return int
 291       */
 292      protected static function get_completionengagement_value(stdClass $log, string $type): int {
 293          $summary = json_decode($log->meta);
 294          return intval($summary->data->engagement->$type ?? 0);
 295      }
 296  }