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 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   * Page to export forum discussions.
  19   *
  20   * @package    mod_forum
  21   * @copyright  2019 Simey Lameze <simey@moodle.com>
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  define('NO_OUTPUT_BUFFERING', true);
  25  
  26  require_once(__DIR__ . '/../../config.php');
  27  require_once($CFG->libdir . '/adminlib.php');
  28  require_once($CFG->dirroot . '/calendar/externallib.php');
  29  
  30  $forumid = required_param('id', PARAM_INT);
  31  $userids = optional_param_array('userids', [], PARAM_INT);
  32  $discussionids = optional_param_array('discids', [], PARAM_INT);
  33  $from = optional_param_array('from', [], PARAM_INT);
  34  $to = optional_param_array('to', [], PARAM_INT);
  35  $fromtimestamp = optional_param('timestampfrom', '', PARAM_INT);
  36  $totimestamp = optional_param('timestampto', '', PARAM_INT);
  37  
  38  if (!empty($from['enabled'])) {
  39      unset($from['enabled']);
  40      $from = core_calendar_external::get_timestamps([$from])['timestamps'][0]['timestamp'];
  41  } else {
  42      $from = $fromtimestamp;
  43  }
  44  
  45  if (!empty($to['enabled'])) {
  46      unset($to['enabled']);
  47      $to = core_calendar_external::get_timestamps([$to])['timestamps'][0]['timestamp'];
  48  } else {
  49      $to = $totimestamp;
  50  }
  51  
  52  $vaultfactory = mod_forum\local\container::get_vault_factory();
  53  $managerfactory = mod_forum\local\container::get_manager_factory();
  54  $legacydatamapperfactory = mod_forum\local\container::get_legacy_data_mapper_factory();
  55  
  56  $forumvault = $vaultfactory->get_forum_vault();
  57  
  58  $forum = $forumvault->get_from_id($forumid);
  59  if (empty($forum)) {
  60      throw new moodle_exception('Unable to find forum with id ' . $forumid);
  61  }
  62  
  63  $capabilitymanager = $managerfactory->get_capability_manager($forum);
  64  if (!$capabilitymanager->can_export_forum($USER)) {
  65      throw new moodle_exception('cannotexportforum', 'forum');
  66  }
  67  
  68  $course = $forum->get_course_record();
  69  $coursemodule = $forum->get_course_module_record();
  70  $cm = cm_info::create($coursemodule);
  71  
  72  require_course_login($course, true, $cm);
  73  
  74  $url = new moodle_url('/mod/forum/export.php');
  75  $pagetitle = get_string('export', 'mod_forum');
  76  $context = $forum->get_context();
  77  
  78  $form = new mod_forum\form\export_form($url->out(false), [
  79      'forum' => $forum
  80  ]);
  81  
  82  if ($form->is_cancelled()) {
  83      redirect(new moodle_url('/mod/forum/view.php', ['id' => $cm->id]));
  84  } else if ($data = $form->get_data()) {
  85      $dataformat = $data->format;
  86  
  87      // This may take a very long time and extra memory.
  88      \core_php_time_limit::raise();
  89      raise_memory_limit(MEMORY_HUGE);
  90  
  91      $discussionvault = $vaultfactory->get_discussion_vault();
  92      if ($data->discussionids) {
  93          $discussionids = $data->discussionids;
  94      } else if (empty($discussionids)) {
  95          $discussions = $discussionvault->get_all_discussions_in_forum($forum);
  96          $discussionids = array_map(function ($discussion) {
  97              return $discussion->get_id();
  98          }, $discussions);
  99      }
 100  
 101      $filters = ['discussionids' => $discussionids];
 102      if ($data->useridsselected) {
 103          $filters['userids'] = $data->useridsselected;
 104      }
 105      if ($data->from) {
 106          $filters['from'] = $data->from;
 107      }
 108      if ($data->to) {
 109          $filters['to'] = $data->to;
 110      }
 111  
 112      // Retrieve posts based on the selected filters, note if forum has no discussions then there is nothing to export.
 113      if (!empty($filters['discussionids'])) {
 114          $postvault = $vaultfactory->get_post_vault();
 115          $posts = $postvault->get_from_filters($USER, $filters, $capabilitymanager->can_view_any_private_reply($USER));
 116      } else {
 117          $posts = [];
 118      }
 119  
 120      $striphtml = !empty($data->striphtml);
 121      $humandates = !empty($data->humandates);
 122  
 123      $fields = ['id', 'discussion', 'parent', 'userid', 'userfullname', 'created', 'modified', 'mailed', 'subject', 'message',
 124                  'messageformat', 'messagetrust', 'attachment', 'totalscore', 'mailnow', 'deleted', 'privatereplyto',
 125                  'privatereplytofullname', 'wordcount', 'charcount'];
 126  
 127      $canviewfullname = has_capability('moodle/site:viewfullnames', $context);
 128  
 129      $datamapper = $legacydatamapperfactory->get_post_data_mapper();
 130      $exportdata = new ArrayObject($datamapper->to_legacy_objects($posts));
 131      $iterator = $exportdata->getIterator();
 132  
 133      $filename = clean_filename('discussion');
 134      \core\dataformat::download_data(
 135          $filename,
 136          $dataformat,
 137          $fields,
 138          $iterator,
 139          function($exportdata) use ($fields, $striphtml, $humandates, $canviewfullname, $context) {
 140              $data = new stdClass();
 141  
 142              foreach ($fields as $field) {
 143                  // Set data field's value from the export data's equivalent field by default.
 144                  $data->$field = $exportdata->$field ?? null;
 145  
 146                  if ($field == 'userfullname') {
 147                      $user = \core_user::get_user($data->userid);
 148                      $data->userfullname = fullname($user, $canviewfullname);
 149                  }
 150  
 151                  if ($field == 'privatereplytofullname' && !empty($data->privatereplyto)) {
 152                      $user = \core_user::get_user($data->privatereplyto);
 153                      $data->privatereplytofullname = fullname($user, $canviewfullname);
 154                  }
 155  
 156                  if ($field == 'message') {
 157                      $data->message = file_rewrite_pluginfile_urls($data->message, 'pluginfile.php', $context->id, 'mod_forum',
 158                          'post', $data->id);
 159                  }
 160  
 161                  // Convert any boolean fields to their integer equivalent for output.
 162                  if (is_bool($data->$field)) {
 163                      $data->$field = (int) $data->$field;
 164                  }
 165              }
 166  
 167              if ($striphtml) {
 168                  $data->message = html_to_text(format_text($data->message, $data->messageformat), 0, false);
 169                  $data->messageformat = FORMAT_PLAIN;
 170              }
 171              if ($humandates) {
 172                  $data->created = userdate($data->created);
 173                  $data->modified = userdate($data->modified);
 174              }
 175              return $data;
 176          });
 177      die;
 178  }
 179  
 180  $PAGE->set_context($context);
 181  $PAGE->set_url($url);
 182  $PAGE->set_title($pagetitle);
 183  $PAGE->set_pagelayout('admin');
 184  $PAGE->set_heading($pagetitle);
 185  
 186  echo $OUTPUT->header();
 187  echo $OUTPUT->heading($pagetitle);
 188  
 189  // It is possible that the following fields have been provided in the URL.
 190  $userids = array_filter($userids, static function(int $userid) use ($course, $cm): bool {
 191      $user = core_user::get_user($userid, '*', MUST_EXIST);
 192      return $cm->effectivegroupmode != SEPARATEGROUPS || user_can_view_profile($user, $course);
 193  });
 194  $form->set_data(['useridsselected' => $userids, 'discussionids' => $discussionids, 'from' => $from, 'to' => $to]);
 195  
 196  $form->display();
 197  
 198  echo $OUTPUT->footer();