Merge branch 'MDL-66297-master' of git://github.com/mickhawkins/moodle

This commit is contained in:
Andrew Nicols
2019-11-08 11:17:38 +08:00
14 changed files with 193 additions and 15 deletions
+12 -1
View File
@@ -54,8 +54,19 @@ class export_form extends \moodleform {
'multiple' => true,
'noselectionstring' => get_string('allusers', 'mod_forum'),
'courseid' => $forum->get_course_id(),
'valuehtmlcallback' => function($value) {
global $OUTPUT;
$allusernames = get_all_user_name_fields(true);
$fields = 'id, ' . $allusernames;
$user = \core_user::get_user($value, $fields);
$useroptiondata = [
'fullname' => fullname($user),
];
return $OUTPUT->render_from_template('mod_forum/form-user-selector-suggestion', $useroptiondata);
}
];
$mform->addElement('autocomplete', 'userids', get_string('users'), [], $options);
$mform->addElement('autocomplete', 'useridsselected', get_string('users'), [], $options);
// Get the discussions on this forum.
$vaultfactory = \mod_forum\local\container::get_vault_factory();
+29 -5
View File
@@ -26,8 +26,29 @@ define('NO_OUTPUT_BUFFERING', true);
require_once(__DIR__ . '/../../config.php');
require_once($CFG->libdir . '/adminlib.php');
require_once($CFG->libdir . '/dataformatlib.php');
require_once($CFG->dirroot . '/calendar/externallib.php');
$forumid = required_param('id', PARAM_INT);
$userids = optional_param_array('userids', [], PARAM_INT);
$discussionids = optional_param_array('discids', [], PARAM_INT);
$from = optional_param_array('from', [], PARAM_INT);
$to = optional_param_array('to', [], PARAM_INT);
$fromtimestamp = optional_param('timestampfrom', '', PARAM_INT);
$totimestamp = optional_param('timestampto', '', PARAM_INT);
if (!empty($from['enabled'])) {
unset($from['enabled']);
$from = core_calendar_external::get_timestamps([$from])['timestamps'][0]['timestamp'];
} else {
$from = $fromtimestamp;
}
if (!empty($to['enabled'])) {
unset($to['enabled']);
$to = core_calendar_external::get_timestamps([$to])['timestamps'][0]['timestamp'];
} else {
$to = $totimestamp;
}
$vaultfactory = mod_forum\local\container::get_vault_factory();
$managerfactory = mod_forum\local\container::get_manager_factory();
@@ -66,10 +87,9 @@ if ($form->is_cancelled()) {
$discussionvault = $vaultfactory->get_discussion_vault();
$postvault = $vaultfactory->get_post_vault();
$discussionids = [];
if ($data->discussionids) {
$discussionids = $data->discussionids;
} else {
} else if (empty($discussionids)) {
$discussions = $discussionvault->get_all_discussions_in_forum($forum);
$discussionids = array_map(function ($discussion) {
return $discussion->get_id();
@@ -77,8 +97,8 @@ if ($form->is_cancelled()) {
}
$filters = ['discussionids' => $discussionids];
if ($data->userids) {
$filters['userids'] = $data->userids;
if ($data->useridsselected) {
$filters['userids'] = $data->useridsselected;
}
if ($data->from) {
$filters['from'] = $data->from;
@@ -94,7 +114,8 @@ if ($form->is_cancelled()) {
$humandates = !empty($data->humandates);
$fields = ['id', 'discussion', 'parent', 'userid', 'created', 'modified', 'mailed', 'subject', 'message',
'messageformat', 'messagetrust', 'attachment', 'totalscore', 'mailnow', 'deleted', 'privatereplyto'];
'messageformat', 'messagetrust', 'attachment', 'totalscore', 'mailnow', 'deleted', 'privatereplyto',
'wordcount', 'charcount'];
$datamapper = $legacydatamapperfactory->get_post_data_mapper();
$exportdata = new ArrayObject($datamapper->to_legacy_objects($posts));
@@ -142,6 +163,9 @@ $PAGE->set_heading($pagetitle);
echo $OUTPUT->header();
echo $OUTPUT->heading($pagetitle);
// It is possible that the following fields have been provided in the URL.
$form->set_data(['useridsselected' => $userids, 'discussionids' => $discussionids, 'from' => $from, 'to' => $to]);
$form->display();
echo $OUTPUT->footer();
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,2 +1,2 @@
define ("forumreport_summary/selectors",["exports"],function(a){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;a.default={filters:{group:{checkbox:"[data-region=\"filter-groups\"] input[type=\"checkbox\"]",clear:"[data-region=\"filter-groups\"] .filter-clear",popover:"#filter-groups-popover",save:"[data-region=\"filter-groups\"] .filter-save",selectall:"[data-region=\"filter-groups\"] .select-all",trigger:"#filter-groups-button"},date:{calendar:"#dateselector-calendar-panel",calendariconfrom:"#id_filterdatefrompopover_calendar",calendariconto:"#id_filterdatetopopover_calendar",popover:"#filter-dates-popover",save:"[data-region=\"filter-dates\"] .filter-save",trigger:"#filter-dates-button"}}};return a.default});
define ("forumreport_summary/selectors",["exports"],function(a){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;a.default={filters:{group:{checkbox:"[data-region=\"filter-groups\"] input[type=\"checkbox\"]",clear:"[data-region=\"filter-groups\"] .filter-clear",popover:"#filter-groups-popover",save:"[data-region=\"filter-groups\"] .filter-save",selectall:"[data-region=\"filter-groups\"] .select-all",trigger:"#filter-groups-button"},date:{calendar:"#dateselector-calendar-panel",calendariconfrom:"#id_filterdatefrompopover_calendar",calendariconto:"#id_filterdatetopopover_calendar",popover:"#filter-dates-popover",save:"[data-region=\"filter-dates\"] .filter-save",trigger:"#filter-dates-button"},exportlink:{link:"#summaryreport #forumreport_summary_table button.export-link"}}};return a.default});
//# sourceMappingURL=selectors.min.js.map
@@ -1 +1 @@
{"version":3,"sources":["../src/selectors.js"],"names":["filters","group","checkbox","clear","popover","save","selectall","trigger","date","calendar","calendariconfrom","calendariconto"],"mappings":"yJAwBe,CACXA,OAAO,CAAE,CACLC,KAAK,CAAE,CACHC,QAAQ,CAAE,0DADP,CAEHC,KAAK,CAAE,+CAFJ,CAGHC,OAAO,CAAE,wBAHN,CAIHC,IAAI,CAAE,8CAJH,CAKHC,SAAS,CAAE,6CALR,CAMHC,OAAO,CAAE,uBANN,CADF,CASLC,IAAI,CAAE,CACFC,QAAQ,CAAE,8BADR,CAEFC,gBAAgB,CAAE,oCAFhB,CAGFC,cAAc,CAAE,kCAHd,CAIFP,OAAO,CAAE,uBAJP,CAKFC,IAAI,CAAE,6CALJ,CAMFE,OAAO,CAAE,sBANP,CATD,CADE,C","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Module containing the selectors for the forum summary report.\n *\n * @module forumreport_summary/selectors\n * @package forumreport_summary\n * @copyright 2019 Jun Pataleta\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nexport default {\n filters: {\n group: {\n checkbox: '[data-region=\"filter-groups\"] input[type=\"checkbox\"]',\n clear: '[data-region=\"filter-groups\"] .filter-clear',\n popover: '#filter-groups-popover',\n save: '[data-region=\"filter-groups\"] .filter-save',\n selectall: '[data-region=\"filter-groups\"] .select-all',\n trigger: '#filter-groups-button',\n },\n date: {\n calendar: '#dateselector-calendar-panel',\n calendariconfrom: '#id_filterdatefrompopover_calendar',\n calendariconto: '#id_filterdatetopopover_calendar',\n popover: '#filter-dates-popover',\n save: '[data-region=\"filter-dates\"] .filter-save',\n trigger: '#filter-dates-button',\n }\n }\n};\n"],"file":"selectors.min.js"}
{"version":3,"sources":["../src/selectors.js"],"names":["filters","group","checkbox","clear","popover","save","selectall","trigger","date","calendar","calendariconfrom","calendariconto","exportlink","link"],"mappings":"yJAwBe,CACXA,OAAO,CAAE,CACLC,KAAK,CAAE,CACHC,QAAQ,CAAE,0DADP,CAEHC,KAAK,CAAE,+CAFJ,CAGHC,OAAO,CAAE,wBAHN,CAIHC,IAAI,CAAE,8CAJH,CAKHC,SAAS,CAAE,6CALR,CAMHC,OAAO,CAAE,uBANN,CADF,CASLC,IAAI,CAAE,CACFC,QAAQ,CAAE,8BADR,CAEFC,gBAAgB,CAAE,oCAFhB,CAGFC,cAAc,CAAE,kCAHd,CAIFP,OAAO,CAAE,uBAJP,CAKFC,IAAI,CAAE,6CALJ,CAMFE,OAAO,CAAE,sBANP,CATD,CAiBLK,UAAU,CAAE,CACRC,IAAI,CAAE,8DADE,CAjBP,CADE,C","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Module containing the selectors for the forum summary report.\n *\n * @module forumreport_summary/selectors\n * @package forumreport_summary\n * @copyright 2019 Jun Pataleta\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nexport default {\n filters: {\n group: {\n checkbox: '[data-region=\"filter-groups\"] input[type=\"checkbox\"]',\n clear: '[data-region=\"filter-groups\"] .filter-clear',\n popover: '#filter-groups-popover',\n save: '[data-region=\"filter-groups\"] .filter-save',\n selectall: '[data-region=\"filter-groups\"] .select-all',\n trigger: '#filter-groups-button',\n },\n date: {\n calendar: '#dateselector-calendar-panel',\n calendariconfrom: '#id_filterdatefrompopover_calendar',\n calendariconto: '#id_filterdatetopopover_calendar',\n popover: '#filter-dates-popover',\n save: '[data-region=\"filter-dates\"] .filter-save',\n trigger: '#filter-dates-button',\n },\n exportlink: {\n link: '#summaryreport #forumreport_summary_table button.export-link'\n }\n }\n};\n"],"file":"selectors.min.js"}
@@ -240,6 +240,17 @@ export const init = (root) => {
submitWithFilter('#filter-groups-popover');
});
// Listeners for export buttons.
// These allow fetching of the relevant export URL, before submitting the request with
// any POST data that is common to all of the export links. This allows filters to be
// applied that contain potentially a lot of data (eg discussion IDs for groups filtering).
document.querySelectorAll(Selectors.filters.exportlink.link).forEach(function(exportbutton) {
exportbutton.addEventListener('click', function(event) {
document.forms.exportlinkform.action = event.target.dataset.url;
document.forms.exportlinkform.submit();
});
});
// Dates filter specific handlers.
// Event handler for showing dates filter popover.
@@ -39,6 +39,9 @@ export default {
popover: '#filter-dates-popover',
save: '[data-region="filter-dates"] .filter-save',
trigger: '#filter-dates-button',
},
exportlink: {
link: '#summaryreport #forumreport_summary_table button.export-link'
}
}
};
@@ -70,6 +70,17 @@ class filters implements renderable, templatable {
*/
protected $groupsselected = [];
/**
* IDs of discussions required for export links.
* If a subset of groups available are selected, this will include the discussion IDs
* within that group in the forum.
* If all groups are selected, or no groups mode is enabled, this will be empty as
* no discussion filtering is required in the export.
*
* @var array $discussionids
*/
protected $discussionids = [];
/**
* HTML for dates filter.
*
@@ -147,6 +158,23 @@ class filters implements renderable, templatable {
// Overwrite groups properties.
$this->groupsavailable = $groupsavailable;
$this->groupsselected = $groupsselected;
// If export links will require discussion filtering, find and set the discussion IDs.
$groupsselectedcount = count($groupsselected);
if ($groupsselectedcount > 0 && $groupsselectedcount < count($groupsavailable)) {
list($groupidin, $groupidparams) = $DB->get_in_or_equal($groupsselected, SQL_PARAMS_NAMED);
$dwhere = "course = :courseid AND forum = :forumid AND groupid {$groupidin}";
$dparams = [
'courseid' => $this->cm->course,
'forumid' => $this->cm->instance,
];
$dparams += $groupidparams;
$discussionids = $DB->get_fieldset_select('forum_discussions', 'DISTINCT id', $dwhere, $dparams);
foreach ($discussionids as $discussionid) {
$this->discussionids[] = ['discid' => $discussionid];
}
}
}
/**
@@ -263,6 +291,9 @@ class filters implements renderable, templatable {
$output->hasgroups = false;
}
// Set discussion IDs for use by export links (always included, as it will be empty if not required).
$output->discussionids = $this->discussionids;
// Set date button and generate dates popover mform.
$datesformdata = [];
@@ -94,6 +94,11 @@ class summary_table extends table_sql {
*/
protected $canseeprivatereplies;
/**
* @var array Validated filter data, for use in GET parameters by export links.
*/
protected $exportfilterdata = [];
/**
* Forum report table constructor.
*
@@ -102,9 +107,10 @@ class summary_table extends table_sql {
* @param bool $allowbulkoperations Is the user allowed to perform bulk operations?
* @param bool $canseeprivatereplies Whether the user can see all private replies or not.
* @param int $perpage The number of rows to display per page.
* @param bool $canexport Is the user allowed to export records?
*/
public function __construct(int $courseid, array $filters, bool $allowbulkoperations,
bool $canseeprivatereplies, int $perpage) {
bool $canseeprivatereplies, int $perpage, bool $canexport) {
global $USER, $OUTPUT;
$forumid = $filters['forums'][0];
@@ -156,6 +162,10 @@ class summary_table extends table_sql {
$columnheaders['earliestpost'] = get_string('earliestpost', 'forumreport_summary');
$columnheaders['latestpost'] = get_string('latestpost', 'forumreport_summary');
if ($canexport) {
$columnheaders['export'] = get_string('exportposts', 'forumreport_summary');
}
$this->define_columns(array_keys($columnheaders));
$this->define_headers(array_values($columnheaders));
@@ -277,6 +287,44 @@ class summary_table extends table_sql {
return empty($data->latestpost) ? '-' : userdate($data->latestpost, "", \core_date::get_user_timezone($USER));
}
/**
* Generate the export column.
*
* @param \stdClass $data The row data.
* @return string The link to export content belonging to the row.
*/
public function col_export(\stdClass $data): string {
global $OUTPUT;
// If no posts, nothing to export.
if (empty($data->earliestpost)) {
return '';
}
$params = [
'id' => $this->cm->instance, // Forum id.
'userids[]' => $data->userid, // User id.
];
// Add relevant filter params.
foreach ($this->exportfilterdata as $name => $data) {
if (is_array($data)) {
foreach ($data as $key => $value) {
$params["{$name}[{$key}]"] = $value;
}
} else {
$params[$name] = $data;
}
}
$buttoncontext = [
'url' => new \moodle_url('/mod/forum/export.php', $params),
'label' => get_string('exportpostslabel', 'forumreport_summary', fullname($data)),
];
return $OUTPUT->render_from_template('forumreport_summary/export_link_button', $buttoncontext);
}
/**
* Override the default implementation to set a decent heading level.
*
@@ -354,18 +402,17 @@ class summary_table extends table_sql {
// Skip adding filter if not applied, or all valid options are selected.
if (!empty($groups)) {
list($groupidin, $groupidparams) = $DB->get_in_or_equal($groups, SQL_PARAMS_NAMED);
// Posts within selected groups and/or not in any groups (group ID -1) are included.
// No user filtering as anyone enrolled can potentially post to unrestricted discussions.
if (array_search(-1, $groups) !== false) {
list($groupidin, $groupidparams) = $DB->get_in_or_equal($groups, SQL_PARAMS_NAMED);
$this->sql->filterwhere .= " AND d.groupid {$groupidin}";
$this->sql->params += $groupidparams;
} else {
// Only posts and users within selected groups are included.
list($groupusersin, $groupusersparams) = $DB->get_in_or_equal($groups, SQL_PARAMS_NAMED);
list($groupidin, $groupidparams) = $DB->get_in_or_equal($groups, SQL_PARAMS_NAMED);
// No joins required (handled by where to prevent data duplication).
$this->sql->filterwhere .= "
@@ -399,6 +446,7 @@ class summary_table extends table_sql {
$this->sql->params['fromdate'] = $values['from']['timestamp'];
$this->sql->filterbase['dateslog'] .= ' AND timecreated >= :fromdate';
$this->sql->filterbase['dateslogparams']['fromdate'] = $values['from']['timestamp'];
$this->exportfilterdata['timestampfrom'] = $values['from']['timestamp'];
}
// To date.
@@ -409,6 +457,7 @@ class summary_table extends table_sql {
$this->sql->params['todate'] = $values['to']['timestamp'];
$this->sql->filterbase['dateslog'] .= ' AND timecreated <= :todate';
$this->sql->filterbase['dateslogparams']['todate'] = $values['to']['timestamp'];
$this->exportfilterdata['timestampto'] = $values['to']['timestamp'];
}
}
@@ -435,6 +484,7 @@ class summary_table extends table_sql {
$this->pageable(true);
$this->is_downloadable(true);
$this->no_sorting('select');
$this->no_sorting('export');
$this->set_attribute('id', 'forumreport_summary_table');
$this->sql = new \stdClass();
$this->sql->params = [];
+3 -1
View File
@@ -80,8 +80,10 @@ $PAGE->navbar->add(get_string('nodetitle', "forumreport_summary"));
// Prepare and display the report.
$allowbulkoperations = !$download && !empty($CFG->messaging) && has_capability('moodle/course:bulkmessaging', $context);
$canseeprivatereplies = has_capability('mod/forum:readprivatereplies', $context);
$canexport = !$download && has_capability('mod/forum:exportforum', $context);
$table = new \forumreport_summary\summary_table($courseid, $filters, $allowbulkoperations, $canseeprivatereplies, $perpage);
$table = new \forumreport_summary\summary_table($courseid, $filters, $allowbulkoperations,
$canseeprivatereplies, $perpage, $canexport);
$table->baseurl = $url;
if ($download) {
@@ -37,6 +37,8 @@ $string['filter:groupsname'] = 'Groups';
$string['filter:groupscountall'] = 'Groups (all)';
$string['filter:groupscountnumber'] = 'Groups ({$a})';
$string['latestpost'] = 'Most recent post';
$string['exportposts'] = 'Export posts';
$string['exportpostslabel'] = 'Export posts for {$a}';
$string['nodetitle'] = 'Summary report';
$string['pluginname'] = 'Forum summary report';
$string['postcount'] = 'Number of discussions posted';
@@ -0,0 +1,31 @@
{{!
This file is part of Moodle - http://moodle.org/
Moodle is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Moodle is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
}}
{{!
@template forumreport_summary/export_link_button
Summary report filters.
Example context (json):
{
"url": "wwwroot/moodle/mod/forum/export.php?userids[]=12",
"label": "Export posts for Joey Jojo"
}
}}
<button class="btn btn-primary export-link" data-url="{{{url}}}" aria-label="{{label}}" title="{{label}}">
{{# str}}export, mod_forum{{/ str}}
</button>
@@ -49,6 +49,14 @@
"timestamp": "725673600",
"enabled": "1"
}
],
"discussionids": [
{
"discid": 123
},
{
"discid": 456
}
]
}
}}
@@ -62,6 +70,11 @@
{{> forumreport_summary/filter_groups}}
</div>
</form>
<form id="exportlinkform" name="exportlinkform" method="post" action="#">
{{#discussionids}}
<input type="hidden" name="discids[]" value="{{discid}}">
{{/discussionids}}
</form>
{{! Dates filter popover - mform must exist outside of the filtersform }}
{{> forumreport_summary/filter_dates_popover}}