first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-09-30 18:11:26 -04:00
commit e592ca6823
27270 changed files with 5002257 additions and 0 deletions
+59
View File
@@ -0,0 +1,59 @@
<?php
// 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/>.
/**
* Process ajax requests
*
* @copyright Andreas Grabs
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package mod_feedback
*/
if (!defined('AJAX_SCRIPT')) {
define('AJAX_SCRIPT', true);
}
require(__DIR__.'/../../config.php');
require_once('lib.php');
$id = required_param('id', PARAM_INT);
$action = optional_param('action', '', PARAM_ALPHA);
$sesskey = optional_param('sesskey', false, PARAM_TEXT);
$itemorder = optional_param('itemorder', false, PARAM_SEQUENCE);
$cm = get_coursemodule_from_id('feedback', $id, 0, false, MUST_EXIST);
$course = $DB->get_record('course', array('id'=>$cm->course), '*', MUST_EXIST);
$feedback = $DB->get_record('feedback', array('id'=>$cm->instance), '*', MUST_EXIST);
require_sesskey();
$context = context_module::instance($cm->id);
require_login($course, true, $cm);
require_capability('mod/feedback:edititems', $context);
$return = false;
switch ($action) {
case 'saveitemorder':
$itemlist = explode(',', trim($itemorder, ','));
if (count($itemlist) > 0) {
$return = feedback_ajax_saveitemorder($itemlist, $feedback);
}
break;
}
echo json_encode($return);
die;
+10
View File
@@ -0,0 +1,10 @@
define("mod_feedback/createtemplate",["exports","core_form/modalform","core/notification","core/str","core/toast"],(function(_exports,_modalform,_notification,_str,_toast){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}
/**
* Javascript module for saving a new template.
*
* @module mod_feedback/createtemplate
* @copyright 2021 Peter Dias
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_modalform=_interopRequireDefault(_modalform),_notification=_interopRequireDefault(_notification);const selectors_modaltrigger='[data-action="createtemplate"]';_exports.init=()=>{document.querySelector(selectors_modaltrigger).addEventListener("click",(event=>{event.preventDefault();const ele=event.currentTarget,modalForm=new _modalform.default({modalConfig:{title:(0,_str.getString)("save_as_new_template","mod_feedback")},formClass:"mod_feedback\\form\\create_template_form",args:{id:ele.dataset.dataid},saveButtonText:(0,_str.getString)("save","core")});modalForm.addEventListener(modalForm.events.FORM_SUBMITTED,(event=>{event.detail.result?(0,_str.getString)("template_saved","feedback").then(_toast.add).catch():(0,_str.getString)("saving_failed","feedback").then((string=>_notification.default.addNotification({type:"error",message:string}))).catch()})),modalForm.show()}))}}));
//# sourceMappingURL=createtemplate.min.js.map
@@ -0,0 +1 @@
{"version":3,"file":"createtemplate.min.js","sources":["../src/createtemplate.js"],"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 * Javascript module for saving a new template.\n *\n * @module mod_feedback/createtemplate\n * @copyright 2021 Peter Dias\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport ModalForm from 'core_form/modalform';\nimport Notification from 'core/notification';\nimport {getString} from 'core/str';\nimport {add as addToast} from 'core/toast';\n\nconst selectors = {\n modaltrigger: '[data-action=\"createtemplate\"]',\n};\n\n/**\n * Initialize module\n */\nexport const init = () => {\n const trigger = document.querySelector(selectors.modaltrigger);\n\n trigger.addEventListener('click', event => {\n event.preventDefault();\n const ele = event.currentTarget;\n\n const modalForm = new ModalForm({\n modalConfig: {\n title: getString('save_as_new_template', 'mod_feedback'),\n },\n formClass: 'mod_feedback\\\\form\\\\create_template_form',\n args: {\n id: ele.dataset.dataid\n },\n saveButtonText: getString('save', 'core')\n });\n\n // Show a toast notification when the form is submitted.\n modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, event => {\n if (event.detail.result) {\n getString('template_saved', 'feedback').then(addToast).catch();\n } else {\n getString('saving_failed', 'feedback').then(string => {\n return Notification.addNotification({\n type: 'error',\n message: string\n });\n }).catch();\n }\n });\n\n modalForm.show();\n });\n};\n"],"names":["selectors","document","querySelector","addEventListener","event","preventDefault","ele","currentTarget","modalForm","ModalForm","modalConfig","title","formClass","args","id","dataset","dataid","saveButtonText","events","FORM_SUBMITTED","detail","result","then","addToast","catch","string","Notification","addNotification","type","message","show"],"mappings":";;;;;;;0LA4BMA,uBACY,+CAME,KACAC,SAASC,cAAcF,wBAE/BG,iBAAiB,SAASC,QAC9BA,MAAMC,uBACAC,IAAMF,MAAMG,cAEZC,UAAY,IAAIC,mBAAU,CAC5BC,YAAa,CACTC,OAAO,kBAAU,uBAAwB,iBAE7CC,UAAW,2CACXC,KAAM,CACFC,GAAIR,IAAIS,QAAQC,QAEpBC,gBAAgB,kBAAU,OAAQ,UAItCT,UAAUL,iBAAiBK,UAAUU,OAAOC,gBAAgBf,QACpDA,MAAMgB,OAAOC,0BACH,iBAAkB,YAAYC,KAAKC,YAAUC,2BAE7C,gBAAiB,YAAYF,MAAKG,QACjCC,sBAAaC,gBAAgB,CAChCC,KAAM,QACNC,QAASJ,WAEdD,WAIXhB,UAAUsB"}
+3
View File
@@ -0,0 +1,3 @@
define("mod_feedback/edit",["jquery","core/ajax","core/str","core/notification"],(function($,ajax,str,notification){var manager={deleteItem:function(e){e.preventDefault();var targetUrl=$(e.currentTarget).attr("href");str.get_strings([{key:"confirmation",component:"admin"},{key:"confirmdeleteitem",component:"mod_feedback"},{key:"yes",component:"moodle"},{key:"no",component:"moodle"}]).then((function(s){notification.confirm(s[0],s[1],s[2],s[3],(function(){window.location=targetUrl}))})).catch()},setup:function(){$("body").delegate('[data-action="delete"]',"click",manager.deleteItem)}};return{setup:manager.setup}}));
//# sourceMappingURL=edit.min.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"edit.min.js","sources":["../src/edit.js"],"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 * Edit items in feedback module\n *\n * @module mod_feedback/edit\n * @copyright 2016 Marina Glancy\n */\ndefine(['jquery', 'core/ajax', 'core/str', 'core/notification'],\nfunction($, ajax, str, notification) {\n var manager = {\n deleteItem: function(e) {\n e.preventDefault();\n var targetUrl = $(e.currentTarget).attr('href');\n\n str.get_strings([\n {\n key: 'confirmation',\n component: 'admin'\n },\n {\n key: 'confirmdeleteitem',\n component: 'mod_feedback'\n },\n {\n key: 'yes',\n component: 'moodle'\n },\n {\n key: 'no',\n component: 'moodle'\n }\n ])\n .then(function(s) {\n notification.confirm(s[0], s[1], s[2], s[3], function() {\n window.location = targetUrl;\n });\n\n return;\n })\n .catch();\n },\n\n setup: function() {\n $('body').delegate('[data-action=\"delete\"]', 'click', manager.deleteItem);\n }\n };\n\n return {\n setup: manager.setup\n };\n});\n"],"names":["define","$","ajax","str","notification","manager","deleteItem","e","preventDefault","targetUrl","currentTarget","attr","get_strings","key","component","then","s","confirm","window","location","catch","setup","delegate"],"mappings":"AAqBAA,2BAAO,CAAC,SAAU,YAAa,WAAY,sBAC3C,SAASC,EAAGC,KAAMC,IAAKC,kBACfC,QAAU,CACVC,WAAY,SAASC,GACjBA,EAAEC,qBACEC,UAAYR,EAAEM,EAAEG,eAAeC,KAAK,QAExCR,IAAIS,YAAY,CACZ,CACIC,IAAY,eACZC,UAAY,SAEhB,CACID,IAAY,oBACZC,UAAY,gBAEhB,CACID,IAAY,MACZC,UAAY,UAEhB,CACID,IAAY,KACZC,UAAY,YAGnBC,MAAK,SAASC,GACXZ,aAAaa,QAAQD,EAAE,GAAIA,EAAE,GAAIA,EAAE,GAAIA,EAAE,IAAI,WACzCE,OAAOC,SAAWV,gBAKzBW,SAGLC,MAAO,WACHpB,EAAE,QAAQqB,SAAS,yBAA0B,QAASjB,QAAQC,oBAI/D,CACHe,MAAOhB,QAAQgB"}
+10
View File
@@ -0,0 +1,10 @@
define("mod_feedback/usetemplate",["exports","core_form/modalform","core/notification","core/str"],(function(_exports,_modalform,_notification,_str){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}
/**
* Javascript module for using an existing template
*
* @module mod_feedback/usetemplate
* @copyright 2021 Peter Dias
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_modalform=_interopRequireDefault(_modalform),_notification=_interopRequireDefault(_notification);const selectors_modaltrigger='[data-action="usetemplate"]';_exports.init=()=>{const trigger=document.querySelector(selectors_modaltrigger);trigger.addEventListener("click",(event=>{event.preventDefault();const modalForm=new _modalform.default({modalConfig:{title:(0,_str.getString)("use_this_template","mod_feedback")},formClass:"mod_feedback\\form\\use_template_form",args:{id:trigger.getAttribute("data-dataid"),templateid:trigger.getAttribute("data-templateid")},saveButtonText:(0,_str.getString)("save","core")});modalForm.addEventListener(modalForm.events.FORM_SUBMITTED,(event=>{event.detail.result?window.location.assign(event.detail.url):_notification.default.addNotification({type:"error",message:(0,_str.getString)("saving_failed","mod_feedback")})})),modalForm.show()}))}}));
//# sourceMappingURL=usetemplate.min.js.map
@@ -0,0 +1 @@
{"version":3,"file":"usetemplate.min.js","sources":["../src/usetemplate.js"],"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 * Javascript module for using an existing template\n *\n * @module mod_feedback/usetemplate\n * @copyright 2021 Peter Dias\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport ModalForm from 'core_form/modalform';\nimport Notification from 'core/notification';\nimport {getString} from 'core/str';\n\nconst selectors = {\n modaltrigger: '[data-action=\"usetemplate\"]',\n};\n\n/**\n * Initialize module\n */\nexport const init = () => {\n const trigger = document.querySelector(selectors.modaltrigger);\n\n trigger.addEventListener('click', event => {\n event.preventDefault();\n\n const modalForm = new ModalForm({\n modalConfig: {\n title: getString('use_this_template', 'mod_feedback'),\n },\n formClass: 'mod_feedback\\\\form\\\\use_template_form',\n args: {\n id: trigger.getAttribute('data-dataid'),\n templateid: trigger.getAttribute('data-templateid')\n },\n saveButtonText: getString('save', 'core')\n });\n\n // Show a toast notification when the form is submitted.\n modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, event => {\n if (event.detail.result) {\n window.location.assign(event.detail.url);\n } else {\n Notification.addNotification({\n type: 'error',\n message: getString('saving_failed', 'mod_feedback')\n });\n }\n });\n\n modalForm.show();\n });\n};\n"],"names":["selectors","trigger","document","querySelector","addEventListener","event","preventDefault","modalForm","ModalForm","modalConfig","title","formClass","args","id","getAttribute","templateid","saveButtonText","events","FORM_SUBMITTED","detail","result","window","location","assign","url","addNotification","type","message","show"],"mappings":";;;;;;;0LA2BMA,uBACY,4CAME,WACVC,QAAUC,SAASC,cAAcH,wBAEvCC,QAAQG,iBAAiB,SAASC,QAC9BA,MAAMC,uBAEAC,UAAY,IAAIC,mBAAU,CAC5BC,YAAa,CACTC,OAAO,kBAAU,oBAAqB,iBAE1CC,UAAW,wCACXC,KAAM,CACFC,GAAIZ,QAAQa,aAAa,eACzBC,WAAYd,QAAQa,aAAa,oBAErCE,gBAAgB,kBAAU,OAAQ,UAItCT,UAAUH,iBAAiBG,UAAUU,OAAOC,gBAAgBb,QACpDA,MAAMc,OAAOC,OACbC,OAAOC,SAASC,OAAOlB,MAAMc,OAAOK,2BAEvBC,gBAAgB,CACzBC,KAAM,QACNC,SAAU,kBAAU,gBAAiB,qBAKjDpB,UAAUqB"}
+70
View File
@@ -0,0 +1,70 @@
// 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/>.
/**
* Javascript module for saving a new template.
*
* @module mod_feedback/createtemplate
* @copyright 2021 Peter Dias
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
import ModalForm from 'core_form/modalform';
import Notification from 'core/notification';
import {getString} from 'core/str';
import {add as addToast} from 'core/toast';
const selectors = {
modaltrigger: '[data-action="createtemplate"]',
};
/**
* Initialize module
*/
export const init = () => {
const trigger = document.querySelector(selectors.modaltrigger);
trigger.addEventListener('click', event => {
event.preventDefault();
const ele = event.currentTarget;
const modalForm = new ModalForm({
modalConfig: {
title: getString('save_as_new_template', 'mod_feedback'),
},
formClass: 'mod_feedback\\form\\create_template_form',
args: {
id: ele.dataset.dataid
},
saveButtonText: getString('save', 'core')
});
// Show a toast notification when the form is submitted.
modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, event => {
if (event.detail.result) {
getString('template_saved', 'feedback').then(addToast).catch();
} else {
getString('saving_failed', 'feedback').then(string => {
return Notification.addNotification({
type: 'error',
message: string
});
}).catch();
}
});
modalForm.show();
});
};
+65
View File
@@ -0,0 +1,65 @@
// 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/>.
/**
* Edit items in feedback module
*
* @module mod_feedback/edit
* @copyright 2016 Marina Glancy
*/
define(['jquery', 'core/ajax', 'core/str', 'core/notification'],
function($, ajax, str, notification) {
var manager = {
deleteItem: function(e) {
e.preventDefault();
var targetUrl = $(e.currentTarget).attr('href');
str.get_strings([
{
key: 'confirmation',
component: 'admin'
},
{
key: 'confirmdeleteitem',
component: 'mod_feedback'
},
{
key: 'yes',
component: 'moodle'
},
{
key: 'no',
component: 'moodle'
}
])
.then(function(s) {
notification.confirm(s[0], s[1], s[2], s[3], function() {
window.location = targetUrl;
});
return;
})
.catch();
},
setup: function() {
$('body').delegate('[data-action="delete"]', 'click', manager.deleteItem);
}
};
return {
setup: manager.setup
};
});
+67
View File
@@ -0,0 +1,67 @@
// 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/>.
/**
* Javascript module for using an existing template
*
* @module mod_feedback/usetemplate
* @copyright 2021 Peter Dias
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
import ModalForm from 'core_form/modalform';
import Notification from 'core/notification';
import {getString} from 'core/str';
const selectors = {
modaltrigger: '[data-action="usetemplate"]',
};
/**
* Initialize module
*/
export const init = () => {
const trigger = document.querySelector(selectors.modaltrigger);
trigger.addEventListener('click', event => {
event.preventDefault();
const modalForm = new ModalForm({
modalConfig: {
title: getString('use_this_template', 'mod_feedback'),
},
formClass: 'mod_feedback\\form\\use_template_form',
args: {
id: trigger.getAttribute('data-dataid'),
templateid: trigger.getAttribute('data-templateid')
},
saveButtonText: getString('save', 'core')
});
// Show a toast notification when the form is submitted.
modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, event => {
if (event.detail.result) {
window.location.assign(event.detail.url);
} else {
Notification.addNotification({
type: 'error',
message: getString('saving_failed', 'mod_feedback')
});
}
});
modalForm.show();
});
};
+101
View File
@@ -0,0 +1,101 @@
<?php
// 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/>.
/**
* shows an analysed view of feedback
*
* @copyright Andreas Grabs
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package mod_feedback
*/
require_once("../../config.php");
require_once("lib.php");
$current_tab = 'analysis';
$id = required_param('id', PARAM_INT); // Course module id.
$url = new moodle_url('/mod/feedback/analysis.php', array('id'=>$id));
$PAGE->set_url($url);
list($course, $cm) = get_course_and_cm_from_cmid($id, 'feedback');
require_course_login($course, true, $cm);
$feedback = $PAGE->activityrecord;
$feedbackstructure = new mod_feedback_structure($feedback, $cm);
$context = context_module::instance($cm->id);
if (!$feedbackstructure->can_view_analysis()) {
throw new \moodle_exception('error');
}
/// Print the page header
$PAGE->set_heading($course->fullname);
$PAGE->set_title($feedback->name);
$PAGE->activityheader->set_attrs([
'hidecompletion' => true,
'description' => ''
]);
$PAGE->add_body_class('limitedwidth');
echo $OUTPUT->header();
echo $OUTPUT->heading(get_string('analysis', 'mod_feedback'), 3);
//get the groupid
$mygroupid = groups_get_activity_group($cm, true);
groups_print_activity_menu($cm, $url);
// Button "Export to excel".
if (has_capability('mod/feedback:viewreports', $context) && $feedbackstructure->get_items()) {
echo $OUTPUT->container_start('form-buttons');
$aurl = new moodle_url('/mod/feedback/analysis_to_excel.php', ['sesskey' => sesskey(), 'id' => $id]);
echo $OUTPUT->single_button($aurl, get_string('export_to_excel', 'feedback'));
echo $OUTPUT->container_end();
}
// Show the summary.
$summary = new mod_feedback\output\summary($feedbackstructure, $mygroupid);
echo $OUTPUT->render_from_template('mod_feedback/summary', $summary->export_for_template($OUTPUT));
// Get the items of the feedback.
$items = $feedbackstructure->get_items(true);
$check_anonymously = true;
if ($mygroupid > 0 AND $feedback->anonymous == FEEDBACK_ANONYMOUS_YES) {
$completedcount = $feedbackstructure->count_completed_responses($mygroupid);
if ($completedcount < FEEDBACK_MIN_ANONYMOUS_COUNT_IN_GROUP) {
$check_anonymously = false;
}
}
echo '<div>';
if ($check_anonymously) {
// Print the items in an analysed form.
foreach ($items as $item) {
$itemobj = feedback_get_item_class($item->typ);
$printnr = ($feedback->autonumbering && $item->itemnr) ? ($item->itemnr . '.') : '';
$itemobj->print_analysed($item, $printnr, $mygroupid);
}
} else {
echo $OUTPUT->heading_with_help(get_string('insufficient_responses_for_this_group', 'feedback'),
'insufficient_responses',
'feedback', '', '', 3);
}
echo '</div>';
echo $OUTPUT->footer();
+153
View File
@@ -0,0 +1,153 @@
<?php
// 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/>.
/**
* shows an analysed view of a feedback on the mainsite
*
* @author Andreas Grabs
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package mod_feedback
*/
require_once("../../config.php");
require_once("lib.php");
$current_tab = 'analysis';
$id = required_param('id', PARAM_INT); //the POST dominated the GET
$courseitemfilter = optional_param('courseitemfilter', '0', PARAM_INT);
$courseitemfiltertyp = optional_param('courseitemfiltertyp', '0', PARAM_ALPHANUM);
$courseid = optional_param('courseid', false, PARAM_INT);
$url = new moodle_url('/mod/feedback/analysis_course.php', array('id'=>$id));
navigation_node::override_active_url($url);
if ($courseid !== false) {
$url->param('courseid', $courseid);
}
if ($courseitemfilter !== '0') {
$url->param('courseitemfilter', $courseitemfilter);
}
if ($courseitemfiltertyp !== '0') {
$url->param('courseitemfiltertyp', $courseitemfiltertyp);
}
$PAGE->set_url($url);
list($course, $cm) = get_course_and_cm_from_cmid($id, 'feedback');
$context = context_module::instance($cm->id);
require_course_login($course, true, $cm);
$feedback = $PAGE->activityrecord;
if (!($feedback->publish_stats OR has_capability('mod/feedback:viewreports', $context))) {
throw new \moodle_exception('error');
}
$feedbackstructure = new mod_feedback_structure($feedback, $PAGE->cm, $courseid);
// Process course select form.
$courseselectform = new mod_feedback_course_select_form($url, $feedbackstructure);
if ($data = $courseselectform->get_data()) {
redirect(new moodle_url($url, ['courseid' => $data->courseid]));
}
/// Print the page header
$strfeedbacks = get_string("modulenameplural", "feedback");
$strfeedback = get_string("modulename", "feedback");
$PAGE->set_heading($course->fullname);
$PAGE->set_title($feedback->name);
echo $OUTPUT->header();
if (!$PAGE->has_secondary_navigation()) {
echo $OUTPUT->heading(format_string($feedback->name));
}
//get the groupid
//lstgroupid is the choosen id
$mygroupid = false;
$courseselectform->display();
// Button "Export to excel".
if (has_capability('mod/feedback:viewreports', $context) && $feedbackstructure->get_items()) {
echo $OUTPUT->container_start('form-buttons');
$aurl = new moodle_url('/mod/feedback/analysis_to_excel.php',
['sesskey' => sesskey(), 'id' => $id, 'courseid' => (int)$courseid]);
echo $OUTPUT->single_button($aurl, get_string('export_to_excel', 'feedback'));
echo $OUTPUT->container_end();
}
// Show the summary.
$summary = new mod_feedback\output\summary($feedbackstructure);
echo $OUTPUT->render_from_template('mod_feedback/summary', $summary->export_for_template($OUTPUT));
// Get the items of the feedback.
$items = $feedbackstructure->get_items(true);
if ($courseitemfilter > 0) {
$sumvalue = 'SUM(' . $DB->sql_cast_char2real('value', true) . ')';
$sql = "SELECT fv.course_id, c.shortname, $sumvalue AS sumvalue, COUNT(value) as countvalue
FROM {feedback_value} fv, {course} c, {feedback_item} fi
WHERE fv.course_id = c.id AND fi.id = fv.item AND fi.typ = ? AND fv.item = ?
GROUP BY course_id, shortname
ORDER BY sumvalue desc";
if ($courses = $DB->get_records_sql($sql, array($courseitemfiltertyp, $courseitemfilter))) {
$item = $DB->get_record('feedback_item', array('id'=>$courseitemfilter));
echo '<h4>'.$item->name.'</h4>';
echo '<div class="clearfix">';
echo '<table>';
echo '<tr><th>Course</th><th>Average</th></tr>';
foreach ($courses as $c) {
$coursecontext = context_course::instance($c->course_id);
$shortname = format_string($c->shortname, true, array('context' => $coursecontext));
echo '<tr>';
echo '<td>'.$shortname.'</td>';
echo '<td class="text-right">';
echo format_float(($c->sumvalue / $c->countvalue), 2);
echo '</td>';
echo '</tr>';
}
echo '</table>';
} else {
echo '<p>'.get_string('noresults').'</p>';
}
echo '<p><a href="analysis_course.php?id=' . $id . '">';
echo get_string('back');
echo '</a></p>';
} else {
// Print the items in an analysed form.
foreach ($items as $item) {
echo '<table class="analysis">';
$itemobj = feedback_get_item_class($item->typ);
$printnr = ($feedback->autonumbering && $item->itemnr) ? ($item->itemnr . '.') : '';
$itemobj->print_analysed($item, $printnr, $mygroupid, $feedbackstructure->get_courseid());
if (preg_match('/rated$/i', $item->typ)) {
$url = new moodle_url('/mod/feedback/analysis_course.php', array('id' => $id,
'courseitemfilter' => $item->id, 'courseitemfiltertyp' => $item->typ));
$anker = html_writer::link($url, get_string('sort_by_course', 'feedback'));
echo '<tr><td colspan="2">'.$anker.'</td></tr>';
}
echo '</table>';
}
}
echo $OUTPUT->footer();
+115
View File
@@ -0,0 +1,115 @@
<?php
// 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/>.
/**
* prints an analysed excel-spreadsheet of the feedback
*
* @copyright Andreas Grabs
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package mod_feedback
*/
require_once("../../config.php");
require_once("lib.php");
require_once("$CFG->libdir/excellib.class.php");
$id = required_param('id', PARAM_INT); // Course module id.
$courseid = optional_param('courseid', '0', PARAM_INT);
$url = new moodle_url('/mod/feedback/analysis_to_excel.php', array('id' => $id));
if ($courseid) {
$url->param('courseid', $courseid);
}
$PAGE->set_url($url);
list($course, $cm) = get_course_and_cm_from_cmid($id, 'feedback');
require_login($course, false, $cm);
$context = context_module::instance($cm->id);
require_capability('mod/feedback:viewreports', $context);
$feedback = $PAGE->activityrecord;
// Buffering any output. This prevents some output before the excel-header will be send.
ob_start();
ob_end_clean();
// Get the questions (item-names).
$feedbackstructure = new mod_feedback_structure($feedback, $cm, $course->id);
if (!$items = $feedbackstructure->get_items(true)) {
throw new \moodle_exception('no_items_available_yet', 'feedback', $cm->url);
}
$mygroupid = groups_get_activity_group($cm);
// Creating a workbook.
$filename = "feedback_" . clean_filename($cm->get_formatted_name()) . ".xls";
$workbook = new MoodleExcelWorkbook($filename);
// Creating the worksheet.
error_reporting(0);
$worksheet1 = $workbook->add_worksheet();
error_reporting($CFG->debug);
$worksheet1->hide_gridlines();
$worksheet1->set_column(0, 0, 10);
$worksheet1->set_column(1, 1, 30);
$worksheet1->set_column(2, 20, 15);
// Creating the needed formats.
$xlsformats = new stdClass();
$xlsformats->head1 = $workbook->add_format(['bold' => 1, 'size' => 12]);
$xlsformats->head2 = $workbook->add_format(['align' => 'left', 'bold' => 1, 'bottum' => 2]);
$xlsformats->default = $workbook->add_format(['align' => 'left', 'v_align' => 'top']);
$xlsformats->value_bold = $workbook->add_format(['align' => 'left', 'bold' => 1, 'v_align' => 'top']);
$xlsformats->procent = $workbook->add_format(['align' => 'left', 'bold' => 1, 'v_align' => 'top', 'num_format' => '#,##0.00']);
// Writing the table header.
$rowoffset1 = 0;
$worksheet1->write_string($rowoffset1, 0, userdate(time()), $xlsformats->head1);
// Get the completeds.
$completedscount = $feedbackstructure->count_completed_responses($mygroupid);
// Write the count of completeds.
// Keep consistency and write count of completeds even when they are 0.
$rowoffset1++;
$worksheet1->write_string($rowoffset1,
0,
get_string('completed_feedbacks', 'feedback').': '.strval($completedscount),
$xlsformats->head1);
$rowoffset1++;
$worksheet1->write_string($rowoffset1,
0,
get_string('questions', 'feedback').': '. strval(count($items)),
$xlsformats->head1);
$rowoffset1 += 2;
$worksheet1->write_string($rowoffset1, 0, get_string('item_label', 'feedback'), $xlsformats->head1);
$worksheet1->write_string($rowoffset1, 1, get_string('question', 'feedback'), $xlsformats->head1);
$worksheet1->write_string($rowoffset1, 2, get_string('responses', 'feedback'), $xlsformats->head1);
$rowoffset1++;
foreach ($items as $item) {
// Get the class of item-typ.
$itemobj = feedback_get_item_class($item->typ);
$rowoffset1 = $itemobj->excelprint_item($worksheet1,
$rowoffset1,
$xlsformats,
$item,
$mygroupid,
$courseid);
}
$workbook->close();
+158
View File
@@ -0,0 +1,158 @@
<?php
// 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/>.
/**
* Provides support for the conversion of moodle1 backup to the moodle2 format
*
* @package mod_feedback
* @copyright 2011 Rossiani Wijaya <rwijaya@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Feedback module conversion handler
*/
class moodle1_mod_feedback_handler extends moodle1_mod_handler {
/** @var moodle1_file_manager */
protected $fileman = null;
/** @var int cmid */
protected $moduleid = null;
/**
* Declare the paths in moodle.xml we are able to convert
*
* The method returns list of {@link convert_path} instances.
* For each path returned, the corresponding conversion method must be
* defined.
*
* Note that the path /MOODLE_BACKUP/COURSE/MODULES/MOD/FEEDBACK does not
* actually exist in the file. The last element with the module name was
* appended by the moodle1_converter class.
*
* @return array of {@link convert_path} instances
*/
public function get_paths() {
return array(
new convert_path(
'feedback', '/MOODLE_BACKUP/COURSE/MODULES/MOD/FEEDBACK',
array(
'renamefields' => array(
'summary' => 'intro',
'pageaftersub' => 'page_after_submit',
),
'newfields' => array(
'autonumbering' => 1,
'site_after_submit' => '',
'introformat' => 0,
'page_after_submitformat' => 0,
'completionsubmit' => 0,
),
)
),
new convert_path(
'feedback_item', '/MOODLE_BACKUP/COURSE/MODULES/MOD/FEEDBACK/ITEMS/ITEM',
array (
'newfields' => array(
'label' => '',
'options' => '',
'dependitem' => 0,
'dependvalue' => '',
),
)
),
);
}
/**
* This is executed every time we have one /MOODLE_BACKUP/COURSE/MODULES/MOD/FEEDBACK
* data available
*/
public function process_feedback($data) {
global $CFG;
// get the course module id and context id
$instanceid = $data['id'];
$cminfo = $this->get_cminfo($instanceid);
$this->moduleid = $cminfo['id'];
$contextid = $this->converter->get_contextid(CONTEXT_MODULE, $this->moduleid);
// get a fresh new file manager for this instance
$this->fileman = $this->converter->get_file_manager($contextid, 'mod_feedback');
// convert course files embedded into the intro
$this->fileman->filearea = 'intro';
$this->fileman->itemid = 0;
$data['intro'] = moodle1_converter::migrate_referenced_files($data['intro'], $this->fileman);
// Convert the introformat if necessary.
if ($CFG->texteditors !== 'textarea') {
$data['intro'] = text_to_html($data['intro'], false, false, true);
$data['introformat'] = FORMAT_HTML;
}
// start writing feedback.xml
$this->open_xml_writer("activities/feedback_{$this->moduleid}/feedback.xml");
$this->xmlwriter->begin_tag('activity', array('id' => $instanceid, 'moduleid' => $this->moduleid,
'modulename' => 'feedback', 'contextid' => $contextid));
$this->xmlwriter->begin_tag('feedback', array('id' => $instanceid));
foreach ($data as $field => $value) {
if ($field <> 'id') {
$this->xmlwriter->full_tag($field, $value);
}
}
$this->xmlwriter->begin_tag('items');
return $data;
}
/**
* This is executed every time we have one /MOODLE_BACKUP/COURSE/MODULES/MOD/FEEDBACK/ITEMS/ITEM
* data available
*/
public function process_feedback_item($data) {
$this->write_xml('item', $data, array('/item/id'));
}
/**
* This is executed when we reach the closing </MOD> tag of our 'feedback' path
*/
public function on_feedback_end() {
// finish writing feedback.xml
$this->xmlwriter->end_tag('items');
$this->xmlwriter->end_tag('feedback');
$this->xmlwriter->end_tag('activity');
$this->close_xml_writer();
// write inforef.xml
$this->open_xml_writer("activities/feedback_{$this->moduleid}/inforef.xml");
$this->xmlwriter->begin_tag('inforef');
$this->xmlwriter->begin_tag('fileref');
foreach ($this->fileman->get_fileids() as $fileid) {
$this->write_xml('file', array('id' => $fileid));
}
$this->xmlwriter->end_tag('fileref');
$this->xmlwriter->end_tag('inforef');
$this->close_xml_writer();
}
}
@@ -0,0 +1,80 @@
<?php
// 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/>.
/**
* Defines backup_feedback_activity_task class
*
* @package mod_feedback
* @category backup
* @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once($CFG->dirroot . '/mod/feedback/backup/moodle2/backup_feedback_stepslib.php');
require_once($CFG->dirroot . '/mod/feedback/backup/moodle2/backup_feedback_settingslib.php');
/**
* Provides the steps to perform one complete backup of the Feedback instance
*/
class backup_feedback_activity_task extends backup_activity_task {
/**
* No specific settings for this activity
*/
protected function define_my_settings() {
}
/**
* Defines a backup step to store the instance data in the feedback.xml file
*/
protected function define_my_steps() {
// feedback only has one structure step
$this->add_step(new backup_feedback_activity_structure_step('feedback structure', 'feedback.xml'));
}
/**
* Encodes URLs to the index.php and view.php scripts
*
* @param string $content some HTML text that eventually contains URLs to the activity instance scripts
* @return string the content with the URLs encoded
*/
public static function encode_content_links($content) {
global $CFG;
$base = preg_quote($CFG->wwwroot, "/");
// Link to the list of feedbacks
$search="/(".$base."\/mod\/feedback\/index.php\?id\=)([0-9]+)/";
$content= preg_replace($search, '$@FEEDBACKINDEX*$2@$', $content);
// Link to feedback view by moduleid
$search="/(".$base."\/mod\/feedback\/view.php\?id\=)([0-9]+)/";
$content= preg_replace($search, '$@FEEDBACKVIEWBYID*$2@$', $content);
// Link to feedback analyis by moduleid
$search="/(".$base."\/mod\/feedback\/analysis.php\?id\=)([0-9]+)/";
$content= preg_replace($search, '$@FEEDBACKANALYSISBYID*$2@$', $content);
// Link to feedback entries by moduleid
$search="/(".$base."\/mod\/feedback\/show_entries.php\?id\=)([0-9]+)/";
$content= preg_replace($search, '$@FEEDBACKSHOWENTRIESBYID*$2@$', $content);
return $content;
}
}
@@ -0,0 +1,26 @@
<?php
// 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/>.
/**
* @package mod_feedback
* @subpackage backup-moodle2
* @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
// This activity has not particular settings but the inherited from the generic
// backup_activity_task so here there isn't any class definition, like the ones
// existing in /backup/moodle2/backup_settingslib.php (activities section)
@@ -0,0 +1,130 @@
<?php
// 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/>.
/**
* @package mod_feedback
* @subpackage backup-moodle2
* @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Define all the backup steps that will be used by the backup_feedback_activity_task
*/
/**
* Define the complete feedback structure for backup, with file and id annotations
*/
class backup_feedback_activity_structure_step extends backup_activity_structure_step {
protected function define_structure() {
// To know if we are including userinfo
$userinfo = $this->get_setting_value('userinfo');
// Define each element separated
$feedback = new backup_nested_element('feedback', array('id'), array(
'name',
'intro',
'introformat',
'anonymous',
'email_notification',
'multiple_submit',
'autonumbering',
'site_after_submit',
'page_after_submit',
'page_after_submitformat',
'publish_stats',
'timeopen',
'timeclose',
'timemodified',
'completionsubmit'));
$completeds = new backup_nested_element('completeds');
$completed = new backup_nested_element('completed', array('id'), array(
'userid',
'timemodified',
'random_response',
'anonymous_response',
'courseid'));
$items = new backup_nested_element('items');
$item = new backup_nested_element('item', array('id'), array(
'template',
'name',
'label',
'presentation',
'typ',
'hasvalue',
'position',
'required',
'dependitem',
'dependvalue',
'options'));
$values = new backup_nested_element('values');
$value = new backup_nested_element('value', array('id'), array(
'item',
'template',
'completed',
'value',
'course_id'));
// Build the tree
$feedback->add_child($items);
$items->add_child($item);
$feedback->add_child($completeds);
$completeds->add_child($completed);
$completed->add_child($values);
$values->add_child($value);
// Define sources
$feedback->set_source_table('feedback', array('id' => backup::VAR_ACTIVITYID));
$item->set_source_table('feedback_item', array('feedback' => backup::VAR_PARENTID));
// All these source definitions only happen if we are including user info
if ($userinfo) {
$completed->set_source_sql('
SELECT *
FROM {feedback_completed}
WHERE feedback = ?',
array(backup::VAR_PARENTID));
$value->set_source_table('feedback_value', array('completed' => backup::VAR_PARENTID));
}
// Define id annotations
$completed->annotate_ids('user', 'userid');
// Define file annotations
$feedback->annotate_files('mod_feedback', 'intro', null); // This file area hasn't itemid
$feedback->annotate_files('mod_feedback', 'page_after_submit', null); // This file area hasn't itemid
$item->annotate_files('mod_feedback', 'item', 'id');
// Return the root element (feedback), wrapped into standard activity structure
return $this->prepare_activity_structure($feedback);
}
}
@@ -0,0 +1,114 @@
<?php
// 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/>.
/**
* @package mod_feedback
* @subpackage backup-moodle2
* @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once($CFG->dirroot . '/mod/feedback/backup/moodle2/restore_feedback_stepslib.php'); // Because it exists (must)
/**
* feedback restore task that provides all the settings and steps to perform one
* complete restore of the activity
*/
class restore_feedback_activity_task extends restore_activity_task {
/**
* Define (add) particular settings this activity can have
*/
protected function define_my_settings() {
// No particular settings for this activity
}
/**
* Define (add) particular steps this activity can have
*/
protected function define_my_steps() {
// feedback only has one structure step
$this->add_step(new restore_feedback_activity_structure_step('feedback_structure', 'feedback.xml'));
}
/**
* Define the contents in the activity that must be
* processed by the link decoder
*/
public static function define_decode_contents() {
$contents = array();
$contents[] = new restore_decode_content('feedback', array('intro', 'site_after_submit', 'page_after_submit'), 'feedback');
$contents[] = new restore_decode_content('feedback_item', array('presentation'), 'feedback_item');
$contents[] = new restore_decode_content('feedback_value', array('value'), 'feedback_value');
return $contents;
}
/**
* Define the decoding rules for links belonging
* to the activity to be executed by the link decoder
*/
public static function define_decode_rules() {
$rules = array();
$rules[] = new restore_decode_rule('FEEDBACKINDEX', '/mod/feedback/index.php?id=$1', 'course');
$rules[] = new restore_decode_rule('FEEDBACKVIEWBYID', '/mod/feedback/view.php?id=$1', 'course_module');
$rules[] = new restore_decode_rule('FEEDBACKANALYSISBYID', '/mod/feedback/analysis.php?id=$1', 'course_module');
$rules[] = new restore_decode_rule('FEEDBACKSHOWENTRIESBYID', '/mod/feedback/show_entries.php?id=$1', 'course_module');
return $rules;
}
/**
* Define the restore log rules that will be applied
* by the {@link restore_logs_processor} when restoring
* feedback logs. It must return one array
* of {@link restore_log_rule} objects
*/
public static function define_restore_log_rules() {
$rules = array();
$rules[] = new restore_log_rule('feedback', 'add', 'view.php?id={course_module}', '{feedback}');
$rules[] = new restore_log_rule('feedback', 'update', 'view.php?id={course_module}', '{feedback}');
$rules[] = new restore_log_rule('feedback', 'view', 'view.php?id={course_module}', '{feedback}');
$rules[] = new restore_log_rule('feedback', 'submit', 'view.php?id={course_module}', '{feedback}');
$rules[] = new restore_log_rule('feedback', 'startcomplete', 'view.php?id={course_module}', '{feedback}');
return $rules;
}
/**
* Define the restore log rules that will be applied
* by the {@link restore_logs_processor} when restoring
* course logs. It must return one array
* of {@link restore_log_rule} objects
*
* Note this rules are applied when restoring course logs
* by the restore final task, but are defined here at
* activity level. All them are rules not linked to any module instance (cmid = 0)
*/
public static function define_restore_log_rules_for_course() {
$rules = array();
$rules[] = new restore_log_rule('feedback', 'view all', 'index.php?id={course}', null);
return $rules;
}
}
@@ -0,0 +1,133 @@
<?php
// 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/>.
/**
* @package mod_feedback
* @subpackage backup-moodle2
* @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Define all the restore steps that will be used by the restore_feedback_activity_task
*/
/**
* Structure step to restore one feedback activity
*/
class restore_feedback_activity_structure_step extends restore_activity_structure_step {
protected function define_structure() {
$paths = array();
$userinfo = $this->get_setting_value('userinfo');
$paths[] = new restore_path_element('feedback', '/activity/feedback');
$paths[] = new restore_path_element('feedback_item', '/activity/feedback/items/item');
if ($userinfo) {
$paths[] = new restore_path_element('feedback_completed', '/activity/feedback/completeds/completed');
$paths[] = new restore_path_element('feedback_value', '/activity/feedback/completeds/completed/values/value');
}
// Return the paths wrapped into standard activity structure
return $this->prepare_activity_structure($paths);
}
protected function process_feedback($data) {
global $DB;
$data = (object)$data;
$oldid = $data->id;
$data->course = $this->get_courseid();
// Any changes to the list of dates that needs to be rolled should be same during course restore and course reset.
// See MDL-9367.
$data->timeopen = $this->apply_date_offset($data->timeopen);
$data->timeclose = $this->apply_date_offset($data->timeclose);
// insert the feedback record
$newitemid = $DB->insert_record('feedback', $data);
// immediately after inserting "activity" record, call this
$this->apply_activity_instance($newitemid);
}
protected function process_feedback_item($data) {
global $DB;
$data = (object)$data;
$oldid = $data->id;
$data->feedback = $this->get_new_parentid('feedback');
$data->typ = clean_param($data->typ, PARAM_ALPHA);
$newitemid = $DB->insert_record('feedback_item', $data);
$this->set_mapping('feedback_item', $oldid, $newitemid, true); // Can have files
}
protected function process_feedback_completed($data) {
global $DB;
$data = (object)$data;
$oldid = $data->id;
$data->feedback = $this->get_new_parentid('feedback');
$data->userid = $this->get_mappingid('user', $data->userid);
if ($this->task->is_samesite() && !empty($data->courseid)) {
$data->courseid = $data->courseid;
} else if ($this->get_courseid() == SITEID) {
$data->courseid = SITEID;
} else {
$data->courseid = 0;
}
$newitemid = $DB->insert_record('feedback_completed', $data);
$this->set_mapping('feedback_completed', $oldid, $newitemid);
}
protected function process_feedback_value($data) {
global $DB;
$data = (object)$data;
$oldid = $data->id;
$data->completed = $this->get_new_parentid('feedback_completed');
$data->item = $this->get_mappingid('feedback_item', $data->item);
if ($this->task->is_samesite() && !empty($data->course_id)) {
$data->course_id = $data->course_id;
} else if ($this->get_courseid() == SITEID) {
$data->course_id = SITEID;
} else {
$data->course_id = 0;
}
$newitemid = $DB->insert_record('feedback_value', $data);
$this->set_mapping('feedback_value', $oldid, $newitemid);
}
protected function after_execute() {
global $DB;
// Add feedback related files, no need to match by itemname (just internally handled context)
$this->add_related_files('mod_feedback', 'intro', null);
$this->add_related_files('mod_feedback', 'page_after_submit', null);
$this->add_related_files('mod_feedback', 'item', 'feedback_item');
// Once all items are restored we can set their dependency.
if ($records = $DB->get_records('feedback_item', array('feedback' => $this->task->get_activityid()))) {
foreach ($records as $record) {
// Get new id for dependitem if present. This will also reset dependitem if not found.
$record->dependitem = $this->get_mappingid('feedback_item', $record->dependitem);
$DB->update_record('feedback_item', $record);
}
}
}
}
+25
View File
@@ -0,0 +1,25 @@
<?php
// 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/>.
/**
* prints the form to choose the group you want to analyse
*
* @author Andreas Grabs
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package mod_feedback
*/
//This file can be deleted
@@ -0,0 +1,65 @@
<?php
// 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/>.
/**
* Activity base class.
*
* @package mod_feedback
* @copyright 2017 onwards Ankit Agarwal <ankit.agrr@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_feedback\analytics\indicator;
defined('MOODLE_INTERNAL') || die();
/**
* Activity base class.
*
* @package mod_feedback
* @copyright 2017 onwards Ankit Agarwal <ankit.agrr@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
abstract class activity_base extends \core_analytics\local\indicator\community_of_inquiry_activity {
/**
* Overwritten to mark as viewed if stats are published.
*
* @param \cm_info $cm
* @param int $contextid
* @param int $userid
* @param int $after
* @return bool
*/
protected function feedback_viewed(\cm_info $cm, $contextid, $userid, $after = null) {
// If stats are published any write action counts as viewed feedback.
if (!empty($this->instancedata[$cm->instance]->publish_stats)) {
$user = (object)['id' => $userid];
return $this->any_write_log($contextid, $user);
}
return parent::feedback_viewed($cm, $contextid, $userid, $after);
}
/**
* Returns the name of the field that controls activity availability.
*
* @return null|string
*/
protected function get_timeclose_field() {
return 'timeclose';
}
}
@@ -0,0 +1,62 @@
<?php
// 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/>.
/**
* Cognitive depth indicator - feedback.
*
* @package mod_feedback
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_feedback\analytics\indicator;
defined('MOODLE_INTERNAL') || die();
/**
* Cognitive depth indicator - feedback.
*
* @package mod_feedback
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class cognitive_depth extends activity_base {
/**
* Returns the name.
*
* If there is a corresponding '_help' string this will be shown as well.
*
* @return \lang_string
*/
public static function get_name(): \lang_string {
return new \lang_string('indicator:cognitivedepth', 'mod_feedback');
}
public function get_indicator_type() {
return self::INDICATOR_COGNITIVE;
}
public function get_cognitive_depth_level(\cm_info $cm) {
$this->fill_instance_data($cm);
if (!empty($this->instancedata[$cm->instance]->publish_stats)) {
// If stats are published we count that the user viewed feedback.
return self::COGNITIVE_LEVEL_3;
}
return self::COGNITIVE_LEVEL_2;
}
}
@@ -0,0 +1,58 @@
<?php
// 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/>.
/**
* Social breadth indicator - feedback.
*
* @package mod_feedback
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_feedback\analytics\indicator;
defined('MOODLE_INTERNAL') || die();
/**
* Social breadth indicator - feedback.
*
* @package mod_feedback
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class social_breadth extends activity_base {
/**
* Returns the name.
*
* If there is a corresponding '_help' string this will be shown as well.
*
* @return \lang_string
*/
public static function get_name(): \lang_string {
return new \lang_string('indicator:socialbreadth', 'mod_feedback');
}
public function get_indicator_type() {
return self::INDICATOR_SOCIAL;
}
public function get_social_breadth_level(\cm_info $cm) {
$this->fill_instance_data($cm);
return self::SOCIAL_LEVEL_2;
}
}
+574
View File
@@ -0,0 +1,574 @@
<?php
// 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/>.
/**
* Contains class mod_feedback_complete_form
*
* @package mod_feedback
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Class mod_feedback_complete_form
*
* @package mod_feedback
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class mod_feedback_complete_form extends moodleform {
/** @var int */
const MODE_COMPLETE = 1;
/** @var int */
const MODE_PRINT = 2;
/** @var int */
const MODE_EDIT = 3;
/** @var int */
const MODE_VIEW_RESPONSE = 4;
/** @var int */
const MODE_VIEW_TEMPLATE = 5;
/** @var int */
protected $mode;
/** @var mod_feedback_structure|mod_feedback_completion */
protected $structure;
/** @var mod_feedback_completion */
protected $completion;
/** @var int */
protected $gopage;
/** @var bool */
protected $hasrequired = false;
/**
* Constructor
*
* @param int $mode
* @param mod_feedback_structure $structure
* @param string $formid CSS id attribute of the form
* @param array $customdata
*/
public function __construct($mode, mod_feedback_structure $structure, $formid, $customdata = null) {
$this->mode = $mode;
$this->structure = $structure;
$this->gopage = isset($customdata['gopage']) ? $customdata['gopage'] : 0;
$isanonymous = $this->structure->is_anonymous() ? ' ianonymous' : '';
parent::__construct(null, $customdata, 'POST', '',
array('id' => $formid, 'class' => 'feedback_form' . $isanonymous), true);
$this->set_display_vertical();
}
/**
* Form definition
*/
public function definition() {
$mform = $this->_form;
$mform->addElement('hidden', 'id', $this->get_cm()->id);
$mform->setType('id', PARAM_INT);
$mform->addElement('hidden', 'courseid', $this->get_current_course_id());
$mform->setType('courseid', PARAM_INT);
$mform->addElement('hidden', 'gopage');
$mform->setType('gopage', PARAM_INT);
$mform->addElement('hidden', 'lastpage');
$mform->setType('lastpage', PARAM_INT);
$mform->addElement('hidden', 'startitempos');
$mform->setType('startitempos', PARAM_INT);
$mform->addElement('hidden', 'lastitempos');
$mform->setType('lastitempos', PARAM_INT);
if (isloggedin() && !isguestuser() && $this->mode != self::MODE_EDIT && $this->mode != self::MODE_VIEW_TEMPLATE &&
$this->mode != self::MODE_VIEW_RESPONSE) {
// Output information about the current mode (anonymous or not) in some modes.
if ($this->structure->is_anonymous()) {
$anonymousmodeinfo = get_string('anonymous', 'feedback');
} else {
$anonymousmodeinfo = get_string('non_anonymous', 'feedback');
}
$element = $mform->addElement('static', 'anonymousmode', '',
get_string('mode', 'feedback') . ': ' . $anonymousmodeinfo);
$element->setAttributes($element->getAttributes() + ['class' => 'feedback_mode']);
}
// Add buttons to go to previous/next pages and submit the feedback.
if ($this->mode == self::MODE_COMPLETE) {
$buttonarray = array();
$buttonarray[] = &$mform->createElement('submit', 'gopreviouspage', get_string('previous_page', 'feedback'));
$buttonarray[] = &$mform->createElement('submit', 'gonextpage', get_string('next_page', 'feedback'),
array('class' => 'form-submit'));
$buttonarray[] = &$mform->createElement('submit', 'savevalues', get_string('save_entries', 'feedback'),
array('class' => 'form-submit'));
$buttonarray[] = &$mform->createElement('cancel');
$mform->addGroup($buttonarray, 'buttonar', '', array(' '), false);
$mform->closeHeaderBefore('buttonar');
}
if ($this->mode == self::MODE_COMPLETE) {
$this->definition_complete();
} else {
$this->definition_preview();
}
// Set data.
$this->set_data(array('gopage' => $this->gopage));
}
/**
* Called from definition_after_data() in the completion mode
*
* This will add only items from a current page to the feedback and adjust the buttons
*/
protected function definition_complete() {
if (!$this->structure instanceof mod_feedback_completion) {
// We should not really be here but just in case.
return;
}
$pages = $this->structure->get_pages();
$gopage = $this->gopage;
$pageitems = $pages[$gopage];
$hasnextpage = $gopage < count($pages) - 1; // Until we complete this page we can not trust get_next_page().
$hasprevpage = $gopage && ($this->structure->get_previous_page($gopage, false) !== null);
// Add elements.
foreach ($pageitems as $item) {
$itemobj = feedback_get_item_class($item->typ);
$itemobj->complete_form_element($item, $this);
}
// Remove invalid buttons (for example, no "previous page" if we are on the first page).
if (!$hasprevpage) {
$this->remove_button('gopreviouspage');
}
if (!$hasnextpage) {
$this->remove_button('gonextpage');
}
if ($hasnextpage) {
$this->remove_button('savevalues');
}
}
/**
* Called from definition_after_data() in all modes except for completion
*
* This will add all items to the form, including pagebreaks as horizontal rules.
*/
protected function definition_preview() {
foreach ($this->structure->get_items() as $feedbackitem) {
$itemobj = feedback_get_item_class($feedbackitem->typ);
$itemobj->complete_form_element($feedbackitem, $this);
}
}
/**
* Removes the button that is not applicable for the current page
*
* @param string $buttonname
*/
private function remove_button($buttonname) {
$el = $this->_form->getElement('buttonar');
foreach ($el->_elements as $idx => $button) {
if ($button instanceof MoodleQuickForm_submit && $button->getName() === $buttonname) {
unset($el->_elements[$idx]);
return;
}
}
}
/**
* Returns value for this element that is already stored in temporary or permanent table,
* usually only available when user clicked "Previous page". Null means no value is stored.
*
* @param stdClass $item
* @return string
*/
public function get_item_value($item) {
if ($this->structure instanceof mod_feedback_completion) {
return $this->structure->get_item_value($item);
}
return null;
}
/**
* Can be used by the items to get the course id for which feedback is taken
*
* This function returns 0 for feedbacks that are located inside the courses.
* $this->get_feedback()->course will return the course where feedback is located.
* $this->get_current_course_id() will return the course where user was before taking the feedback
*
* @return int
*/
public function get_course_id() {
return $this->structure->get_courseid();
}
/**
* Record from 'feedback' table corresponding to the current feedback
* @return stdClass
*/
public function get_feedback() {
return $this->structure->get_feedback();
}
/**
* Current feedback mode, see constants on the top of this class
* @return int
*/
public function get_mode() {
return $this->mode;
}
/**
* Returns whether the form is frozen, some items may prefer to change the element
* type in case of frozen form. For example, text or textarea element does not look
* nice when frozen
*
* @return bool
*/
public function is_frozen() {
return $this->mode == self::MODE_VIEW_RESPONSE;
}
/**
* Returns the current course module
* @return cm_info
*/
public function get_cm() {
return $this->structure->get_cm();
}
/**
* Returns the course where user was before taking the feedback.
*
* For feedbacks inside the course it will be the same as $this->get_feedback()->course.
* For feedbacks on the frontpage it will be the same as $this->get_course_id()
*
* @return int
*/
public function get_current_course_id() {
return $this->structure->get_courseid() ?: $this->get_feedback()->course;
}
/**
* CSS class for the item
* @param stdClass $item
* @return string
*/
protected function get_suggested_class($item) {
$class = "feedback_itemlist feedback-item-{$item->typ}";
if ($item->dependitem) {
$class .= " feedback_is_dependent";
}
if ($item->typ !== 'pagebreak') {
$itemobj = feedback_get_item_class($item->typ);
if ($itemobj->get_hasvalue()) {
$class .= " feedback_hasvalue";
}
}
return $class;
}
/**
* Adds an element to this form - to be used by items in their complete_form_element() method
*
* @param stdClass $item
* @param HTML_QuickForm_element|array $element either completed form element or an array that
* can be passed as arguments to $this->_form->createElement() function
* @param bool $addrequiredrule automatically add 'required' rule
* @param bool $setdefaultvalue automatically set default value for element
* @return HTML_QuickForm_element
*/
public function add_form_element($item, $element, $addrequiredrule = true, $setdefaultvalue = true) {
global $OUTPUT;
if (is_array($element) && $element[0] == 'group') {
// For groups, use the mforms addGroup API.
// $element looks like: ['group', $groupinputname, $name, $objects, $separator, $appendname],
$element = $this->_form->addGroup($element[3], $element[1], $element[2], $element[4], $element[5]);
} else {
// Add non-group element to the form.
if (is_array($element)) {
$element = call_user_func_array(array($this->_form, 'createElement'), $element);
}
$element = $this->_form->addElement($element);
}
// Prepend standard CSS classes to the element classes.
$attributes = $element->getAttributes();
$class = !empty($attributes['class']) ? ' ' . $attributes['class'] : '';
$attributes['class'] = $this->get_suggested_class($item) . $class;
$element->setAttributes($attributes);
// Add required rule.
if ($item->required && $addrequiredrule) {
$this->_form->addRule($element->getName(), get_string('required'), 'required', null, 'client');
}
// Set default value.
if ($setdefaultvalue && ($tmpvalue = $this->get_item_value($item))) {
$this->_form->setDefault($element->getName(), htmlspecialchars_decode($tmpvalue, ENT_QUOTES));
}
// Freeze if needed.
if ($this->is_frozen()) {
$element->freeze();
}
// Add red asterisks on required fields.
if ($item->required) {
$required = $OUTPUT->pix_icon('req', get_string('requiredelement', 'form'));
$element->setLabel($element->getLabel() . $required);
$this->hasrequired = true;
}
// Add different useful stuff to the question name.
$this->add_item_label($item, $element);
$this->add_item_dependencies($item, $element);
$this->add_item_number($item, $element);
if ($this->mode == self::MODE_EDIT) {
$this->enhance_name_for_edit($item, $element);
}
return $element;
}
/**
* Adds a group element to this form - to be used by items in their complete_form_element() method
*
* @param stdClass $item
* @param string $groupinputname name for the form element
* @param string $name question text
* @param array $elements array of arrays that can be passed to $this->_form->createElement()
* @param string $separator separator between group elements
* @param string $class additional CSS classes for the form element
* @return HTML_QuickForm_element
*/
public function add_form_group_element($item, $groupinputname, $name, $elements, $separator,
$class = '') {
$objects = array();
foreach ($elements as $element) {
$object = call_user_func_array(array($this->_form, 'createElement'), $element);
$objects[] = $object;
}
$element = $this->add_form_element($item,
['group', $groupinputname, $name, $objects, $separator, false],
false,
false);
if ($class !== '') {
$attributes = $element->getAttributes();
$attributes['class'] .= ' ' . $class;
$element->setAttributes($attributes);
}
return $element;
}
/**
* Adds an item number to the question name (if feedback autonumbering is on)
* @param stdClass $item
* @param HTML_QuickForm_element $element
*/
protected function add_item_number($item, $element) {
if ($this->get_feedback()->autonumbering && !empty($item->itemnr)) {
$name = $element->getLabel();
$element->setLabel(html_writer::span($item->itemnr. '.', 'itemnr') . ' ' . $name);
}
}
/**
* Adds an item label to the question name
* @param stdClass $item
* @param HTML_QuickForm_element $element
*/
protected function add_item_label($item, $element) {
if (strlen($item->label) && ($this->mode == self::MODE_EDIT || $this->mode == self::MODE_VIEW_TEMPLATE)) {
$name = get_string('nameandlabelformat', 'mod_feedback',
(object)['label' => format_string($item->label), 'name' => $element->getLabel()]);
$element->setLabel($name);
}
}
/**
* Adds a dependency description to the question name
* @param stdClass $item
* @param HTML_QuickForm_element $element
*/
protected function add_item_dependencies($item, $element) {
$allitems = $this->structure->get_items();
if ($item->dependitem && ($this->mode == self::MODE_EDIT || $this->mode == self::MODE_VIEW_TEMPLATE)) {
if (isset($allitems[$item->dependitem])) {
$dependitem = $allitems[$item->dependitem];
$name = $element->getLabel();
$name .= html_writer::span(' ('.format_string($dependitem->label).'-&gt;'.$item->dependvalue.')',
'feedback_depend');
$element->setLabel($name);
}
}
}
/**
* Returns the CSS id attribute that will be assigned by moodleform later to this element
* @param stdClass $item
* @param HTML_QuickForm_element $element
*/
protected function guess_element_id($item, $element) {
if (!$id = $element->getAttribute('id')) {
$attributes = $element->getAttributes();
$id = $attributes['id'] = 'feedback_item_' . $item->id;
$element->setAttributes($attributes);
}
if ($element->getType() === 'group') {
return 'fgroup_' . $id;
}
return 'fitem_' . $id;
}
/**
* Adds editing actions to the question name in the edit mode
* @param stdClass $item
* @param HTML_QuickForm_element $element
*/
protected function enhance_name_for_edit($item, $element) {
global $OUTPUT;
$menu = new action_menu();
$menu->set_owner_selector('#' . $this->guess_element_id($item, $element));
$menu->set_menu_trigger(get_string('edit'));
$menu->prioritise = true;
$itemobj = feedback_get_item_class($item->typ);
$actions = $itemobj->edit_actions($item, $this->get_feedback(), $this->get_cm());
foreach ($actions as $action) {
$menu->add($action);
}
$editmenu = $OUTPUT->render($menu);
$name = $element->getLabel();
$name = html_writer::span('', 'itemdd', array('id' => 'feedback_item_box_' . $item->id)) .
html_writer::span($name, 'itemname') .
html_writer::span($editmenu, 'itemactions');
$element->setLabel(html_writer::span($name, 'itemtitle'));
}
/**
* Sets the default value for form element - alias to $this->_form->setDefault()
* @param HTML_QuickForm_element|string $element
* @param mixed $defaultvalue
*/
public function set_element_default($element, $defaultvalue) {
if ($element instanceof HTML_QuickForm_element) {
$element = $element->getName();
}
$this->_form->setDefault($element, $defaultvalue);
}
/**
* Sets the default value for form element - wrapper to $this->_form->setType()
* @param HTML_QuickForm_element|string $element
* @param int $type
*/
public function set_element_type($element, $type) {
if ($element instanceof HTML_QuickForm_element) {
$element = $element->getName();
}
$this->_form->setType($element, $type);
}
/**
* Adds a validation rule for the given field - wrapper for $this->_form->addRule()
*
* Do not use for 'required' rule!
* Required * will be added automatically, if additional validation is needed
* use method {@link self::add_validation_rule()}
*
* @param string $element Form element name
* @param string $message Message to display for invalid data
* @param string $type Rule type, use getRegisteredRules() to get types
* @param string $format (optional)Required for extra rule data
* @param string $validation (optional)Where to perform validation: "server", "client"
* @param bool $reset Client-side validation: reset the form element to its original value if there is an error?
* @param bool $force Force the rule to be applied, even if the target form element does not exist
*/
public function add_element_rule($element, $message, $type, $format = null, $validation = 'server',
$reset = false, $force = false) {
if ($element instanceof HTML_QuickForm_element) {
$element = $element->getName();
}
$this->_form->addRule($element, $message, $type, $format, $validation, $reset, $force);
}
/**
* Adds a validation rule to the form
*
* @param callable $callback with arguments ($values, $files)
*/
public function add_validation_rule(callable $callback) {
if ($this->mode == self::MODE_COMPLETE) {
$this->_form->addFormRule($callback);
}
}
/**
* Returns a reference to the element - wrapper for function $this->_form->getElement()
*
* @param string $elementname Element name
* @return HTML_QuickForm_element reference to element
*/
public function get_form_element($elementname) {
return $this->_form->getElement($elementname);
}
/**
* Displays the form
*/
public function display() {
global $OUTPUT, $PAGE;
// Finalize the form definition if not yet done.
if (!$this->_definition_finalized) {
$this->_definition_finalized = true;
$this->definition_after_data();
}
$mform = $this->_form;
// Add "This form has required fields" text in the bottom of the form.
if (($mform->_required || $this->hasrequired) &&
($this->mode == self::MODE_COMPLETE || $this->mode == self::MODE_PRINT || $this->mode == self::MODE_VIEW_TEMPLATE)) {
$element = $mform->addElement('static', 'requiredfields', '',
get_string('somefieldsrequired', 'form',
$OUTPUT->pix_icon('req', get_string('requiredelement', 'form'))));
$element->setAttributes($element->getAttributes() + ['class' => 'requirednote']);
}
// Reset _required array so the default red * are not displayed.
$mform->_required = array();
// Move buttons to the end of the form.
if ($this->mode == self::MODE_COMPLETE) {
$mform->addElement('hidden', '__dummyelement');
$buttons = $mform->removeElement('buttonar', false);
$mform->insertElementBefore($buttons, '__dummyelement');
$mform->removeElement('__dummyelement');
}
$this->_form->display();
if ($this->mode == self::MODE_EDIT) {
$PAGE->requires->js_call_amd('mod_feedback/edit', 'setup');
}
}
}
+764
View File
@@ -0,0 +1,764 @@
<?php
// 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/>.
/**
* Contains class mod_feedback_completion
*
* @package mod_feedback
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Collects information and methods about feedback completion (either complete.php or show_entries.php)
*
* @package mod_feedback
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class mod_feedback_completion extends mod_feedback_structure {
/** @var stdClass */
protected $completed;
/** @var stdClass */
protected $completedtmp = null;
/** @var stdClass[] */
protected $valuestmp = null;
/** @var stdClass[] */
protected $values = null;
/** @var bool */
protected $iscompleted = false;
/** @var mod_feedback_complete_form the form used for completing the feedback */
protected $form = null;
/** @var bool true when the feedback has been completed during the request */
protected $justcompleted = false;
/** @var int the next page the user should jump after processing the form */
protected $jumpto = null;
/**
* Constructor
*
* @param stdClass $feedback feedback object
* @param cm_info $cm course module object corresponding to the $feedback
* (at least one of $feedback or $cm is required)
* @param int $courseid current course (for site feedbacks only)
* @param bool $iscompleted has feedback been already completed? If yes either completedid or userid must be specified.
* @param int $completedid id in the table feedback_completed, may be omitted if userid is specified
* but it is highly recommended because the same user may have multiple responses to the same feedback
* for different courses
* @param int $nonanonymouseuserid - Return only anonymous results or specified user's results.
* If null only anonymous replies will be returned and the $completedid is mandatory.
* If specified only non-anonymous replies of $nonanonymouseuserid will be returned.
* @param int $userid User id to use for all capability checks, etc. Set to 0 for current user (default).
*/
public function __construct($feedback, $cm, $courseid, $iscompleted = false, $completedid = null,
$nonanonymouseuserid = null, $userid = 0) {
global $DB;
parent::__construct($feedback, $cm, $courseid, 0, $userid);
// Make sure courseid is always set for site feedback.
if ($this->feedback->course == SITEID && !$this->courseid) {
$this->courseid = SITEID;
}
if ($iscompleted) {
// Retrieve information about the completion.
$this->iscompleted = true;
$params = array('feedback' => $this->feedback->id);
if (!$nonanonymouseuserid && !$completedid) {
throw new coding_exception('Either $completedid or $nonanonymouseuserid must be specified for completed feedbacks');
}
if ($completedid) {
$params['id'] = $completedid;
}
if ($nonanonymouseuserid) {
// We must respect the anonymousity of the reply that the user saw when they were completing the feedback,
// not the current state that may have been changed later by the teacher.
$params['anonymous_response'] = FEEDBACK_ANONYMOUS_NO;
$params['userid'] = $nonanonymouseuserid;
}
$this->completed = $DB->get_record('feedback_completed', $params, '*', MUST_EXIST);
$this->courseid = $this->completed->courseid;
}
}
/**
* Returns a record from 'feedback_completed' table
* @return stdClass
*/
public function get_completed() {
return $this->completed;
}
/**
* Check if the feedback was just completed.
*
* @return bool true if the feedback was just completed.
* @since Moodle 3.3
*/
public function just_completed() {
return $this->justcompleted;
}
/**
* Return the jumpto property.
*
* @return int the next page to jump.
* @since Moodle 3.3
*/
public function get_jumpto() {
return $this->jumpto;
}
/**
* Returns the temporary completion record for the current user or guest session
*
* @return stdClass|false record from feedback_completedtmp or false if not found
*/
public function get_current_completed_tmp() {
global $DB, $USER;
if ($this->completedtmp === null) {
$params = array('feedback' => $this->get_feedback()->id);
if ($courseid = $this->get_courseid()) {
$params['courseid'] = $courseid;
}
if ((isloggedin() || $USER->id != $this->userid) && !isguestuser($this->userid)) {
$params['userid'] = $this->userid;
} else {
$params['guestid'] = sesskey();
}
$this->completedtmp = $DB->get_record('feedback_completedtmp', $params);
}
return $this->completedtmp;
}
/**
* Can the current user see the item, if dependency is met?
*
* @param stdClass $item
* @return bool whether user can see item or not,
* true if there is no dependency or dependency is met,
* false if dependent question is visible or broken
* and further it is either not answered or the dependency is not met,
* null if dependency is broken.
*/
protected function can_see_item($item) {
if (empty($item->dependitem)) {
return true;
}
if ($this->dependency_has_error($item)) {
return null;
}
$allitems = $this->get_items();
$ditem = $allitems[$item->dependitem];
$itemobj = feedback_get_item_class($ditem->typ);
if ($this->iscompleted) {
$value = $this->get_values($ditem);
} else {
$value = $this->get_values_tmp($ditem);
}
if ($value === null) {
// Cyclic dependencies are no problem here, since they will throw an dependency error above.
if ($this->can_see_item($ditem) === false) {
return false;
}
return null;
}
$check = $itemobj->compare_value($ditem, $value, $item->dependvalue) ? true : false;
if ($check) {
return $this->can_see_item($ditem);
}
return false;
}
/**
* Dependency condition has an error
* @param stdClass $item
* @return bool
*/
protected function dependency_has_error($item) {
if (empty($item->dependitem)) {
// No dependency - no error.
return false;
}
$allitems = $this->get_items();
if (!array_key_exists($item->dependitem, $allitems)) {
// Looks like dependent item has been removed.
return true;
}
$itemids = array_keys($allitems);
$index1 = array_search($item->dependitem, $itemids);
$index2 = array_search($item->id, $itemids);
if ($index1 >= $index2) {
// Dependent item is after the current item in the feedback.
return true;
}
for ($i = $index1 + 1; $i < $index2; $i++) {
if ($allitems[$itemids[$i]]->typ === 'pagebreak') {
return false;
}
}
// There are no page breaks between dependent items.
return true;
}
/**
* Returns a value stored for this item in the feedback (temporary or not, depending on the mode)
* @param stdClass $item
* @return string
*/
public function get_item_value($item) {
if ($this->iscompleted) {
return $this->get_values($item);
} else {
return $this->get_values_tmp($item);
}
}
/**
* Retrieves responses from an unfinished attempt.
*
* @return array the responses (from the feedback_valuetmp table)
* @since Moodle 3.3
*/
public function get_unfinished_responses() {
global $DB;
$responses = array();
$completedtmp = $this->get_current_completed_tmp();
if ($completedtmp) {
$responses = $DB->get_records('feedback_valuetmp', ['completed' => $completedtmp->id]);
}
return $responses;
}
/**
* Returns all temporary values for this feedback or just a value for an item
* @param stdClass $item
* @return array
*/
protected function get_values_tmp($item = null) {
global $DB;
if ($this->valuestmp === null) {
$this->valuestmp = array();
$responses = $this->get_unfinished_responses();
foreach ($responses as $r) {
$this->valuestmp[$r->item] = $r->value;
}
}
if ($item) {
return array_key_exists($item->id, $this->valuestmp) ? $this->valuestmp[$item->id] : null;
}
return $this->valuestmp;
}
/**
* Retrieves responses from an finished attempt.
*
* @return array the responses (from the feedback_value table)
* @since Moodle 3.3
*/
public function get_finished_responses() {
global $DB;
$responses = array();
if ($this->completed) {
$responses = $DB->get_records('feedback_value', ['completed' => $this->completed->id]);
}
return $responses;
}
/**
* Returns all completed values for this feedback or just a value for an item
* @param stdClass $item
* @return array
*/
protected function get_values($item = null) {
global $DB;
if ($this->values === null) {
$this->values = array();
$responses = $this->get_finished_responses();
foreach ($responses as $r) {
$this->values[$r->item] = $r->value;
}
}
if ($item) {
return array_key_exists($item->id, $this->values) ? $this->values[$item->id] : null;
}
return $this->values;
}
/**
* Splits the feedback items into pages
*
* Items that we definitely know at this stage as not applicable are excluded.
* Items that are dependent on something that has not yet been answered are
* still present, as well as items with broken dependencies.
*
* @return array array of arrays of items
*/
public function get_pages() {
$pages = [[]]; // The first page always exists.
$items = $this->get_items();
foreach ($items as $item) {
if ($item->typ === 'pagebreak') {
$pages[] = [];
} else if ($this->can_see_item($item) !== false) {
$pages[count($pages) - 1][] = $item;
}
}
return $pages;
}
/**
* Returns the last page that has items with the value (i.e. not label) which have been answered
* as well as the first page that has items with the values that have not been answered.
*
* Either of the two return values may be null if there are no answered page or there are no
* unanswered pages left respectively.
*
* Two pages may not be directly following each other because there may be empty pages
* or pages with information texts only between them
*
* @return array array of two elements [$lastcompleted, $firstincompleted]
*/
protected function get_last_completed_page() {
$completed = [];
$incompleted = [];
$pages = $this->get_pages();
foreach ($pages as $pageidx => $pageitems) {
foreach ($pageitems as $item) {
if ($item->hasvalue) {
if ($this->get_values_tmp($item) !== null) {
$completed[$pageidx] = true;
} else {
$incompleted[$pageidx] = true;
}
}
}
}
$completed = array_keys($completed);
$incompleted = array_keys($incompleted);
// If some page has both completed and incompleted items it is considered incompleted.
$completed = array_diff($completed, $incompleted);
// If the completed page follows an incompleted page, it does not count.
$firstincompleted = $incompleted ? min($incompleted) : null;
if ($firstincompleted !== null) {
$completed = array_filter($completed, function($a) use ($firstincompleted) {
return $a < $firstincompleted;
});
}
$lastcompleted = $completed ? max($completed) : null;
return [$lastcompleted, $firstincompleted];
}
/**
* Get the next page for the feedback
*
* This is normally $gopage+1 but may be bigger if there are empty pages or
* pages without visible questions.
*
* This method can only be called when questions on the current page are
* already answered, otherwise it may be inaccurate.
*
* @param int $gopage current page
* @param bool $strictcheck when gopage is the user-input value, make sure we do not jump over unanswered questions
* @return int|null the index of the next page or null if this is the last page
*/
public function get_next_page($gopage, $strictcheck = true) {
if ($strictcheck) {
list($lastcompleted, $firstincompleted) = $this->get_last_completed_page();
if ($firstincompleted !== null && $firstincompleted <= $gopage) {
return $firstincompleted;
}
}
$pages = $this->get_pages();
for ($pageidx = $gopage + 1; $pageidx < count($pages); $pageidx++) {
if (!empty($pages[$pageidx])) {
return $pageidx;
}
}
// No further pages in the feedback have any visible items.
return null;
}
/**
* Get the previous page for the feedback
*
* This is normally $gopage-1 but may be smaller if there are empty pages or
* pages without visible questions.
*
* @param int $gopage current page
* @param bool $strictcheck when gopage is the user-input value, make sure we do not jump over unanswered questions
* @return int|null the index of the next page or null if this is the first page with items
*/
public function get_previous_page($gopage, $strictcheck = true) {
if (!$gopage) {
// If we are already on the first (0) page, there is definitely no previous page.
return null;
}
$pages = $this->get_pages();
$rv = null;
// Iterate through previous pages and find the closest one that has any items on it.
for ($pageidx = $gopage - 1; $pageidx >= 0; $pageidx--) {
if (!empty($pages[$pageidx])) {
$rv = $pageidx;
break;
}
}
if ($rv === null) {
// We are on the very first page that has items.
return null;
}
if ($rv > 0 && $strictcheck) {
// Check if this page is actually not past than first incompleted page.
list($lastcompleted, $firstincompleted) = $this->get_last_completed_page();
if ($firstincompleted !== null && $firstincompleted < $rv) {
return $firstincompleted;
}
}
return $rv;
}
/**
* Page index to resume the feedback
*
* When user abandones answering feedback and then comes back to it we should send him
* to the first page after the last page he fully completed.
* @return int
*/
public function get_resume_page() {
list($lastcompleted, $firstincompleted) = $this->get_last_completed_page();
return $lastcompleted === null ? 0 : $this->get_next_page($lastcompleted, false);
}
/**
* Creates a new record in the 'feedback_completedtmp' table for the current user/guest session
*
* @return stdClass record from feedback_completedtmp or false if not found
*/
protected function create_current_completed_tmp() {
global $DB, $USER;
$record = (object)['feedback' => $this->feedback->id];
if ($this->get_courseid()) {
$record->courseid = $this->get_courseid();
}
if ((isloggedin() || $USER->id != $this->userid) && !isguestuser($this->userid)) {
$record->userid = $this->userid;
} else {
$record->guestid = sesskey();
}
$record->timemodified = time();
$record->anonymous_response = $this->feedback->anonymous;
$id = $DB->insert_record('feedback_completedtmp', $record);
$this->completedtmp = $DB->get_record('feedback_completedtmp', ['id' => $id]);
$this->valuestmp = null;
return $this->completedtmp;
}
/**
* If user has already completed the feedback, create the temproray values from last completed attempt
*
* @return stdClass record from feedback_completedtmp or false if not found
*/
public function create_completed_tmp_from_last_completed() {
if (!$this->get_current_completed_tmp()) {
$lastcompleted = $this->find_last_completed();
if ($lastcompleted) {
$this->completedtmp = feedback_set_tmp_values($lastcompleted);
}
}
return $this->completedtmp;
}
/**
* Saves unfinished response to the temporary table
*
* This is called when user proceeds to the next/previous page in the complete form
* and also right after the form submit.
* After the form submit the {@link save_response()} is called to
* move response from temporary table to completion table.
*
* @param stdClass $data data from the form mod_feedback_complete_form
*/
public function save_response_tmp($data) {
global $DB;
if (!$completedtmp = $this->get_current_completed_tmp()) {
$completedtmp = $this->create_current_completed_tmp();
} else {
$currentime = time();
$DB->update_record('feedback_completedtmp',
['id' => $completedtmp->id, 'timemodified' => $currentime]);
$completedtmp->timemodified = $currentime;
}
// Find all existing values.
$existingvalues = $DB->get_records_menu('feedback_valuetmp',
['completed' => $completedtmp->id], '', 'item, id');
// Loop through all feedback items and save the ones that are present in $data.
$allitems = $this->get_items();
foreach ($allitems as $item) {
if (!$item->hasvalue) {
continue;
}
$keyname = $item->typ . '_' . $item->id;
if (!isset($data->$keyname)) {
// This item is either on another page or dependency was not met - nothing to save.
continue;
}
$newvalue = ['item' => $item->id, 'completed' => $completedtmp->id, 'course_id' => $completedtmp->courseid];
// Convert the value to string that can be stored in 'feedback_valuetmp' or 'feedback_value'.
$itemobj = feedback_get_item_class($item->typ);
$newvalue['value'] = $itemobj->create_value($data->$keyname);
// Update or insert the value in the 'feedback_valuetmp' table.
if (array_key_exists($item->id, $existingvalues)) {
$newvalue['id'] = $existingvalues[$item->id];
$DB->update_record('feedback_valuetmp', $newvalue);
} else {
$DB->insert_record('feedback_valuetmp', $newvalue);
}
}
// Reset valuestmp cache.
$this->valuestmp = null;
}
/**
* Saves the response
*
* The form data has already been stored in the temporary table in
* {@link save_response_tmp()}. This function copies the values
* from the temporary table to the completion table.
* It is also responsible for sending email notifications when applicable.
*/
public function save_response() {
global $SESSION, $DB, $USER;
$feedbackcompleted = $this->find_last_completed();
// If no record is found, change false to null for safe use in feedback_save_tmp_values.
$feedbackcompleted = !$feedbackcompleted ? null : $feedbackcompleted;
$feedbackcompletedtmp = $this->get_current_completed_tmp();
if (feedback_check_is_switchrole()) {
// We do not actually save anything if the role is switched, just delete temporary values.
$this->delete_completedtmp();
return;
}
// Save values.
$completedid = feedback_save_tmp_values($feedbackcompletedtmp, $feedbackcompleted);
$this->completed = $DB->get_record('feedback_completed', array('id' => $completedid));
// Send email.
if ($this->feedback->anonymous == FEEDBACK_ANONYMOUS_NO) {
feedback_send_email($this->cm, $this->feedback, $this->cm->get_course(), $this->userid, $this->completed);
} else {
feedback_send_email_anonym($this->cm, $this->feedback, $this->cm->get_course());
}
unset($SESSION->feedback->is_started);
// Update completion state.
$completion = new completion_info($this->cm->get_course());
if ((isloggedin() || $USER->id != $this->userid) && $completion->is_enabled($this->cm) &&
$this->cm->completion == COMPLETION_TRACKING_AUTOMATIC && $this->feedback->completionsubmit) {
$completion->update_state($this->cm, COMPLETION_COMPLETE, $this->userid);
}
}
/**
* Deletes the temporary completed and all related temporary values
*/
protected function delete_completedtmp() {
global $DB;
if ($completedtmp = $this->get_current_completed_tmp()) {
$DB->delete_records('feedback_valuetmp', ['completed' => $completedtmp->id]);
$DB->delete_records('feedback_completedtmp', ['id' => $completedtmp->id]);
$this->completedtmp = null;
}
}
/**
* Retrieves the last completion record for the current user
*
* @return stdClass record from feedback_completed or false if not found
*/
public function find_last_completed() {
global $DB, $USER;
if ((!isloggedin() && $USER->id == $this->userid) || isguestuser($this->userid)) {
// Not possible to retrieve completed feedback for guests.
return false;
}
if ($this->is_anonymous()) {
// Not possible to retrieve completed anonymous feedback.
return false;
}
$params = array('feedback' => $this->feedback->id,
'userid' => $this->userid,
'anonymous_response' => FEEDBACK_ANONYMOUS_NO
);
if ($this->get_courseid()) {
$params['courseid'] = $this->get_courseid();
}
$this->completed = $DB->get_record('feedback_completed', $params);
return $this->completed;
}
/**
* Checks if user has capability to submit the feedback
*
* There is an exception for fully anonymous feedbacks when guests can complete
* feedback without the proper capability.
*
* This should be followed by checking {@link can_submit()} because even if
* user has capablity to complete, they may have already submitted feedback
* and can not re-submit
*
* @return bool
*/
public function can_complete() {
global $CFG, $USER;
$context = context_module::instance($this->cm->id);
if (has_capability('mod/feedback:complete', $context, $this->userid)) {
return true;
}
if (!empty($CFG->feedback_allowfullanonymous)
AND $this->feedback->course == SITEID
AND $this->feedback->anonymous == FEEDBACK_ANONYMOUS_YES
AND ((!isloggedin() && $USER->id == $this->userid) || isguestuser($this->userid))) {
// Guests are allowed to complete fully anonymous feedback without having 'mod/feedback:complete' capability.
return true;
}
return false;
}
/**
* Checks if user is prevented from re-submission.
*
* This must be called after {@link can_complete()}
*
* @return bool
*/
public function can_submit() {
if ($this->get_feedback()->multiple_submit == 0 ) {
if ($this->is_already_submitted()) {
return false;
}
}
return true;
}
/**
* Trigger module viewed event.
*
* @since Moodle 3.3
*/
public function trigger_module_viewed() {
$event = \mod_feedback\event\course_module_viewed::create_from_record($this->feedback, $this->cm, $this->cm->get_course());
$event->trigger();
}
/**
* Mark activity viewed for completion-tracking.
*
* @since Moodle 3.3
*/
public function set_module_viewed() {
global $CFG;
require_once($CFG->libdir . '/completionlib.php');
$completion = new completion_info($this->cm->get_course());
$completion->set_module_viewed($this->cm, $this->userid);
}
/**
* Process a page jump via the mod_feedback_complete_form.
*
* This function initializes the form and process the submission.
*
* @param int $gopage the current page
* @param int $gopreviouspage if the user chose to go to the previous page
* @return string the url to redirect the user (if any)
* @since Moodle 3.3
*/
public function process_page($gopage, $gopreviouspage = false) {
global $CFG, $PAGE, $SESSION;
$urltogo = null;
// Save the form for later during the request.
$this->create_completed_tmp_from_last_completed();
$this->form = new mod_feedback_complete_form(mod_feedback_complete_form::MODE_COMPLETE,
$this, 'feedback_complete_form', array('gopage' => $gopage));
if ($this->form->is_cancelled()) {
// Form was cancelled - return to the course page.
$urltogo = new moodle_url('/mod/feedback/view.php', ['id' => $this->get_cm()->id]);
} else if ($this->form->is_submitted() &&
($this->form->is_validated() || $gopreviouspage)) {
// Form was submitted (skip validation for "Previous page" button).
$data = $this->form->get_submitted_data();
if (!isset($SESSION->feedback->is_started) OR !$SESSION->feedback->is_started == true) {
throw new \moodle_exception('error', '', $CFG->wwwroot.'/course/view.php?id='.$this->courseid);
}
$this->save_response_tmp($data);
if (!empty($data->savevalues) || !empty($data->gonextpage)) {
if (($nextpage = $this->get_next_page($gopage)) !== null) {
if ($PAGE->has_set_url()) {
$urltogo = new moodle_url($PAGE->url, array('gopage' => $nextpage));
}
$this->jumpto = $nextpage;
} else {
$this->save_response();
if (!$this->get_feedback()->page_after_submit) {
\core\notification::success(get_string('entries_saved', 'feedback'));
}
$this->justcompleted = true;
}
} else if (!empty($gopreviouspage)) {
$prevpage = intval($this->get_previous_page($gopage));
if ($PAGE->has_set_url()) {
$urltogo = new moodle_url($PAGE->url, array('gopage' => $prevpage));
}
$this->jumpto = $prevpage;
}
}
return $urltogo;
}
/**
* Render the form with the questions.
*
* @return string the form rendered
* @since Moodle 3.3
*/
public function render_items() {
global $SESSION;
// Print the items.
$SESSION->feedback->is_started = true;
return $this->form->render();
}
}
@@ -0,0 +1,82 @@
<?php
// 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/>.
declare(strict_types=1);
namespace mod_feedback\completion;
use core_completion\activity_custom_completion;
/**
* Activity custom completion subclass for the feedback activity.
*
* Class for defining mod_feedback's custom completion rules and fetching the completion statuses
* of the custom completion rules for a given feedback instance and a user.
*
* @package mod_feedback
* @copyright Simey Lameze <simey@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class custom_completion extends activity_custom_completion {
/**
* Fetches the completion state for a given completion rule.
*
* @param string $rule The completion rule.
* @return int The completion state.
*/
public function get_state(string $rule): int {
global $DB;
$this->validate_rule($rule);
// Feedback only supports completionsubmit as a custom rule.
$status = $DB->record_exists('feedback_completed', ['feedback' => $this->cm->instance, 'userid' => $this->userid]);
return $status ? COMPLETION_COMPLETE : COMPLETION_INCOMPLETE;
}
/**
* Fetch the list of custom completion rules that this module defines.
*
* @return array
*/
public static function get_defined_custom_rules(): array {
return ['completionsubmit'];
}
/**
* Returns an associative array of the descriptions of custom completion rules.
*
* @return array
*/
public function get_custom_rule_descriptions(): array {
return [
'completionsubmit' => get_string('completiondetail:submit', 'feedback')
];
}
/**
* Returns an array of all completion rules, in the order they should be displayed to users.
*
* @return array
*/
public function get_sort_order(): array {
return [
'completionview',
'completionsubmit',
];
}
}
+48
View File
@@ -0,0 +1,48 @@
<?php
// 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/>.
/**
* Contains class mod_feedback_course_map_form
*
* @package mod_feedback
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Form for mapping courses to the feedback
*
* @package mod_feedback
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class mod_feedback_course_map_form extends moodleform {
/**
* Definition of the form
*/
public function definition() {
$mform = $this->_form;
$mform->addElement('hidden', 'id');
$mform->setType('id', PARAM_INT);
$options = array('multiple' => true, 'includefrontpage' => true);
$mform->addElement('course', 'mappedcourses', get_string('courses'), $options);
$this->add_action_buttons();
}
}
@@ -0,0 +1,83 @@
<?php
// 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/>.
/**
* Contains class mod_feedback_course_map_form
*
* @package mod_feedback
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Form for mapping courses to the feedback
*
* @package mod_feedback
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class mod_feedback_course_select_form extends moodleform {
/** @var moodle_url */
protected $action;
/** @var mod_feedback_structure $feedbackstructure */
protected $feedbackstructure;
/**
* Constructor
*
* @param string|moodle_url $action the action attribute for the form
* @param mod_feedback_structure $feedbackstructure
* @param bool $editable
*/
public function __construct($action, mod_feedback_structure $feedbackstructure, $editable = true) {
$this->action = new moodle_url($action, ['courseid' => null]);
$this->feedbackstructure = $feedbackstructure;
parent::__construct($action, null, 'post', '', ['id' => 'feedback_course_filter'], $editable);
}
/**
* Definition of the form
*/
public function definition() {
$mform = $this->_form;
$feedbackstructure = $this->feedbackstructure;
$mform->addElement('hidden', 'id');
$mform->setType('id', PARAM_INT);
if (!$this->_form->_freezeAll && ($courses = $feedbackstructure->get_completed_courses()) && count($courses) > 1) {
$elements = [];
$elements[] = $mform->createElement('autocomplete', 'courseid', get_string('filter_by_course', 'feedback'),
['' => get_string('fulllistofcourses')] + $courses);
$elements[] = $mform->createElement('submit', 'submitbutton', get_string('filter'));
if ($feedbackstructure->get_courseid()) {
$elements[] = $mform->createElement('static', 'showall', '',
html_writer::link($this->action, get_string('show_all', 'feedback')));
}
if (defined('BEHAT_SITE_RUNNING')) {
// TODO MDL-53734 remove this - behat does not recognise autocomplete element inside a group.
foreach ($elements as $element) {
$mform->addElement($element);
}
} else {
$mform->addGroup($elements, 'coursefilter', get_string('filter_by_course', 'feedback'), array(' '), false);
}
}
$this->set_data(['courseid' => $feedbackstructure->get_courseid(), 'id' => $feedbackstructure->get_cm()->id]);
}
}
+70
View File
@@ -0,0 +1,70 @@
<?php
// 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/>.
/**
* Contains the class for fetching the important dates in mod_feedback for a given module instance and a user.
*
* @package mod_feedback
* @copyright 2021 Shamim Rezaie <shamim@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
declare(strict_types=1);
namespace mod_feedback;
use core\activity_dates;
/**
* Class for fetching the important dates in mod_feedback for a given module instance and a user.
*
* @copyright 2021 Shamim Rezaie <shamim@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class dates extends activity_dates {
/**
* Returns a list of important dates in mod_feedback
*
* @return array
*/
protected function get_dates(): array {
$timeopen = $this->cm->customdata['timeopen'] ?? null;
$timeclose = $this->cm->customdata['timeclose'] ?? null;
$now = time();
$dates = [];
if ($timeopen) {
$openlabelid = $timeopen > $now ? 'activitydate:opens' : 'activitydate:opened';
$dates[] = [
'dataid' => 'timeopen',
'label' => get_string($openlabelid, 'course'),
'timestamp' => (int) $timeopen,
];
}
if ($timeclose) {
$closelabelid = $timeclose > $now ? 'activitydate:closes' : 'activitydate:closed';
$dates[] = [
'dataid' => 'timeclose',
'label' => get_string($closelabelid, 'course'),
'timestamp' => (int) $timeclose,
];
}
return $dates;
}
}
@@ -0,0 +1,38 @@
<?php
// 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/>.
/**
* The mod_feedback instance list viewed event.
*
* @package mod_feedback
* @copyright 2013 Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_feedback\event;
defined('MOODLE_INTERNAL') || die();
/**
* The mod_feedback instance list viewed event class.
*
* @package mod_feedback
* @since Moodle 2.7
* @copyright 2013 onwards Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class course_module_instance_list_viewed extends \core\event\course_module_instance_list_viewed {
}
@@ -0,0 +1,120 @@
<?php
// 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/>.
/**
* The mod_feedback course module viewed event.
*
* @package mod_feedback
* @copyright 2013 Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_feedback\event;
defined('MOODLE_INTERNAL') || die();
/**
* The mod_feedback course module viewed event class.
*
* @property-read array $other {
* Extra information about event.
*
* - int anonymous if feedback is anonymous.
* }
*
* @package mod_feedback
* @since Moodle 2.6
* @copyright 2013 Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class course_module_viewed extends \core\event\course_module_viewed {
/**
* Init method.
*/
protected function init() {
$this->data['crud'] = 'r';
$this->data['edulevel'] = self::LEVEL_PARTICIPATING;
$this->data['objecttable'] = 'feedback';
}
/**
* Creates an instance from feedback record
*
* @param stdClass $feedback
* @param cm_info|stdClass $cm
* @param stdClass $course
* @return course_module_viewed
*/
public static function create_from_record($feedback, $cm, $course) {
$event = self::create(array(
'objectid' => $feedback->id,
'context' => \context_module::instance($cm->id),
'anonymous' => ($feedback->anonymous == FEEDBACK_ANONYMOUS_YES),
'other' => array(
'anonymous' => $feedback->anonymous // Deprecated.
)
));
$event->add_record_snapshot('course_modules', $cm);
$event->add_record_snapshot('course', $course);
$event->add_record_snapshot('feedback', $feedback);
return $event;
}
/**
* Define whether a user can view the event or not. Make sure no one except admin can see details of an anonymous response.
*
* @deprecated since 2.7
*
* @param int|\stdClass $userorid ID of the user.
* @return bool True if the user can view the event, false otherwise.
*/
public function can_view($userorid = null) {
global $USER;
debugging('can_view() method is deprecated, use anonymous flag instead if necessary.', DEBUG_DEVELOPER);
if (empty($userorid)) {
$userorid = $USER;
}
if ($this->anonymous) {
return is_siteadmin($userorid);
} else {
return has_capability('mod/feedback:viewreports', $this->context, $userorid);
}
}
/**
* Custom validations.
*
* @throws \coding_exception in case of any problems.
*/
protected function validate_data() {
parent::validate_data();
if (!isset($this->other['anonymous'])) {
throw new \coding_exception('The \'anonymous\' value must be set in other.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'feedback', 'restore' => 'feedback');
}
public static function get_other_mapping() {
// No need to map the 'anonymous' flag.
return false;
}
}
@@ -0,0 +1,158 @@
<?php
// 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/>.
/**
* The mod_feedback response deleted event.
*
* @package mod_feedback
* @copyright 2013 Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
*/
namespace mod_feedback\event;
defined('MOODLE_INTERNAL') || die();
/**
* The mod_feedback response deleted event class.
*
* This event is triggered when a feedback response is deleted.
*
* @property-read array $other {
* Extra information about event.
*
* - int anonymous: if feedback is anonymous.
* - int cmid: course module id.
* - int instanceid: id of instance.
* }
*
* @package mod_feedback
* @since Moodle 2.6
* @copyright 2013 Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
*/
class response_deleted extends \core\event\base {
/**
* Set basic properties for the event.
*/
protected function init() {
$this->data['objecttable'] = 'feedback_completed';
$this->data['crud'] = 'd';
$this->data['edulevel'] = self::LEVEL_PARTICIPATING;
}
/**
* Creates an instance from the record from db table feedback_completed
*
* @param stdClass $completed
* @param stdClass|cm_info $cm
* @param stdClass $feedback
* @return self
*/
public static function create_from_record($completed, $cm, $feedback) {
$event = self::create(array(
'relateduserid' => $completed->userid,
'objectid' => $completed->id,
'courseid' => $cm->course,
'context' => \context_module::instance($cm->id),
'anonymous' => ($completed->anonymous_response == FEEDBACK_ANONYMOUS_YES),
'other' => array(
'cmid' => $cm->id,
'instanceid' => $feedback->id,
'anonymous' => $completed->anonymous_response) // Deprecated.
));
$event->add_record_snapshot('feedback_completed', $completed);
$event->add_record_snapshot('feedback', $feedback);
return $event;
}
/**
* Returns localised general event name.
*
* @return string
*/
public static function get_name() {
return get_string('eventresponsedeleted', 'mod_feedback');
}
/**
* Returns non-localised event description with id's for admin use only.
*
* @return string
*/
public function get_description() {
return "The user with id '$this->userid' deleted the feedback for the user with id '$this->relateduserid' " .
"for the feedback activity with course module id '$this->contextinstanceid'.";
}
/**
* Define whether a user can view the event or not. Make sure no one except admin can see details of an anonymous response.
*
* @deprecated since 2.7
*
* @param int|\stdClass $userorid ID of the user.
* @return bool True if the user can view the event, false otherwise.
*/
public function can_view($userorid = null) {
global $USER;
debugging('can_view() method is deprecated, use anonymous flag instead if necessary.', DEBUG_DEVELOPER);
if (empty($userorid)) {
$userorid = $USER;
}
if ($this->anonymous) {
return is_siteadmin($userorid);
} else {
return has_capability('mod/feedback:viewreports', $this->context, $userorid);
}
}
/**
* Custom validations
*
* @throws \coding_exception in case of any problems.
*/
protected function validate_data() {
parent::validate_data();
if (!isset($this->relateduserid)) {
throw new \coding_exception('The \'relateduserid\' must be set.');
}
if (!isset($this->other['anonymous'])) {
throw new \coding_exception('The \'anonymous\' value must be set in other.');
}
if (!isset($this->other['cmid'])) {
throw new \coding_exception('The \'cmid\' value must be set in other.');
}
if (!isset($this->other['instanceid'])) {
throw new \coding_exception('The \'instanceid\' value must be set in other.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'feedback_completed', 'restore' => 'feedback_completed');
}
public static function get_other_mapping() {
$othermapped = array();
$othermapped['cmid'] = array('db' => 'course_modules', 'restore' => 'course_module');
$othermapped['instanceid'] = array('db' => 'feedback', 'restore' => 'feedback');
return $othermapped;
}
}
@@ -0,0 +1,172 @@
<?php
// 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/>.
/**
* The mod_feedback response submitted event.
*
* @package mod_feedback
* @copyright 2013 Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
*/
namespace mod_feedback\event;
defined('MOODLE_INTERNAL') || die();
/**
* The mod_feedback response submitted event class.
*
* This event is triggered when a feedback response is submitted.
*
* @property-read array $other {
* Extra information about event.
*
* - int anonymous: if feedback is anonymous.
* - int cmid: course module id.
* - int instanceid: id of instance.
* }
*
* @package mod_feedback
* @since Moodle 2.6
* @copyright 2013 Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
*/
class response_submitted extends \core\event\base {
/**
* Set basic properties for the event.
*/
protected function init() {
global $CFG;
require_once($CFG->dirroot.'/mod/feedback/lib.php');
$this->data['objecttable'] = 'feedback_completed';
$this->data['crud'] = 'c';
$this->data['edulevel'] = self::LEVEL_PARTICIPATING;
}
/**
* Creates an instance from the record from db table feedback_completed
*
* @param stdClass $completed
* @param stdClass|cm_info $cm
* @return self
*/
public static function create_from_record($completed, $cm) {
$event = self::create(array(
'relateduserid' => $completed->userid,
'objectid' => $completed->id,
'context' => \context_module::instance($cm->id),
'anonymous' => ($completed->anonymous_response == FEEDBACK_ANONYMOUS_YES),
'other' => array(
'cmid' => $cm->id,
'instanceid' => $completed->feedback,
'anonymous' => $completed->anonymous_response // Deprecated.
)
));
$event->add_record_snapshot('feedback_completed', $completed);
return $event;
}
/**
* Returns localised general event name.
*
* @return string
*/
public static function get_name() {
return get_string('eventresponsesubmitted', 'mod_feedback');
}
/**
* Returns non-localised event description with id's for admin use only.
*
* @return string
*/
public function get_description() {
return "The user with id '$this->userid' submitted response for 'feedback' activity with "
. "course module id '$this->contextinstanceid'.";
}
/**
* Returns relevant URL based on the anonymous mode of the response.
* @return \moodle_url
*/
public function get_url() {
if ($this->anonymous) {
return new \moodle_url('/mod/feedback/show_entries.php', array('id' => $this->other['cmid'],
'showcompleted' => $this->objectid));
} else {
return new \moodle_url('/mod/feedback/show_entries.php' , array('id' => $this->other['cmid'],
'userid' => $this->userid, 'showcompleted' => $this->objectid));
}
}
/**
* Define whether a user can view the event or not. Make sure no one except admin can see details of an anonymous response.
*
* @deprecated since 2.7
*
* @param int|\stdClass $userorid ID of the user.
* @return bool True if the user can view the event, false otherwise.
*/
public function can_view($userorid = null) {
global $USER;
debugging('can_view() method is deprecated, use anonymous flag instead if necessary.', DEBUG_DEVELOPER);
if (empty($userorid)) {
$userorid = $USER;
}
if ($this->anonymous) {
return is_siteadmin($userorid);
} else {
return has_capability('mod/feedback:viewreports', $this->context, $userorid);
}
}
/**
* Custom validations.
*
* @throws \coding_exception in case of any problems.
*/
protected function validate_data() {
parent::validate_data();
if (!isset($this->relateduserid)) {
throw new \coding_exception('The \'relateduserid\' must be set.');
}
if (!isset($this->other['anonymous'])) {
throw new \coding_exception('The \'anonymous\' value must be set in other.');
}
if (!isset($this->other['cmid'])) {
throw new \coding_exception('The \'cmid\' value must be set in other.');
}
if (!isset($this->other['instanceid'])) {
throw new \coding_exception('The \'instanceid\' value must be set in other.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'feedback_completed', 'restore' => 'feedback_completed');
}
public static function get_other_mapping() {
$othermapped = array();
$othermapped['cmid'] = array('db' => 'course_modules', 'restore' => 'course_module');
$othermapped['instanceid'] = array('db' => 'feedback', 'restore' => 'feedback');
return $othermapped;
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,74 @@
<?php
// 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/>.
/**
* Class for exporting a feedback completion record.
*
* @package mod_feedback
* @copyright 2017 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_feedback\external;
defined('MOODLE_INTERNAL') || die();
use core\external\exporter;
/**
* Class for exporting a feedback completion record.
*
* @copyright 2017 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class feedback_completed_exporter extends exporter {
/**
* Return the list of properties.
*
* @return array list of properties
*/
protected static function define_properties() {
return array(
'id' => array(
'type' => PARAM_INT,
'description' => 'The record id.',
),
'feedback' => array(
'type' => PARAM_INT,
'description' => 'The feedback instance id this records belongs to.',
),
'userid' => array(
'type' => PARAM_INT,
'description' => 'The user who completed the feedback (0 for anonymous).',
),
'timemodified' => array(
'type' => PARAM_INT,
'description' => 'The last time the feedback was completed.',
),
'random_response' => array(
'type' => PARAM_INT,
'description' => 'The response number (used when shuffling anonymous responses).',
),
'anonymous_response' => array(
'type' => PARAM_INT,
'description' => 'Whether is an anonymous response.',
),
'courseid' => array(
'type' => PARAM_INT,
'description' => 'The course id where the feedback was completed.',
),
);
}
}
@@ -0,0 +1,78 @@
<?php
// 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/>.
/**
* Class for exporting a feedback temporary completion record.
*
* @package mod_feedback
* @copyright 2017 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_feedback\external;
defined('MOODLE_INTERNAL') || die();
use core\external\exporter;
/**
* Class for exporting a feedback temporary completion record.
*
* @copyright 2017 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class feedback_completedtmp_exporter extends exporter {
/**
* Return the list of properties.
*
* @return array list of properties
*/
protected static function define_properties() {
return array(
'id' => array(
'type' => PARAM_INT,
'description' => 'The record id.',
),
'feedback' => array(
'type' => PARAM_INT,
'description' => 'The feedback instance id this records belongs to.',
),
'userid' => array(
'type' => PARAM_INT,
'description' => 'The user who completed the feedback (0 for anonymous).',
),
'guestid' => array(
'type' => PARAM_RAW,
'description' => 'For guests, this is the session key.',
),
'timemodified' => array(
'type' => PARAM_INT,
'description' => 'The last time the feedback was completed.',
),
'random_response' => array(
'type' => PARAM_INT,
'description' => 'The response number (used when shuffling anonymous responses).',
),
'anonymous_response' => array(
'type' => PARAM_INT,
'description' => 'Whether is an anonymous response.',
),
'courseid' => array(
'type' => PARAM_INT,
'description' => 'The course id where the feedback was completed.',
),
);
}
}
+177
View File
@@ -0,0 +1,177 @@
<?php
// 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/>.
/**
* Class for exporting a feedback item (question).
*
* @package mod_feedback
* @copyright 2017 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_feedback\external;
defined('MOODLE_INTERNAL') || die();
use core\external\exporter;
use renderer_base;
use core_files\external\stored_file_exporter;
/**
* Class for exporting a feedback item (question).
*
* @copyright 2017 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class feedback_item_exporter extends exporter {
protected static function define_properties() {
return array(
'id' => array(
'type' => PARAM_INT,
'description' => 'The record id.',
),
'feedback' => array(
'type' => PARAM_INT,
'description' => 'The feedback instance id this records belongs to.',
'default' => 0,
),
'template' => array(
'type' => PARAM_INT,
'description' => 'If it belogns to a template, the template id.',
'default' => 0,
),
'name' => array(
'type' => PARAM_RAW,
'description' => 'The item name.',
),
'label' => array(
'type' => PARAM_NOTAGS,
'description' => 'The item label.',
),
'presentation' => array(
'type' => PARAM_RAW,
'description' => 'The text describing the item or the available possible answers.',
),
'typ' => array(
'type' => PARAM_ALPHA,
'description' => 'The type of the item.',
),
'hasvalue' => array(
'type' => PARAM_INT,
'description' => 'Whether it has a value or not.',
'default' => 0,
),
'position' => array(
'type' => PARAM_INT,
'description' => 'The position in the list of questions.',
'default' => 0,
),
'required' => array(
'type' => PARAM_BOOL,
'description' => 'Whether is a item (question) required or not.',
'default' => 0,
),
'dependitem' => array(
'type' => PARAM_INT,
'description' => 'The item id this item depend on.',
'default' => 0,
),
'dependvalue' => array(
'type' => PARAM_RAW,
'description' => 'The depend value.',
),
'options' => array(
'type' => PARAM_ALPHA,
'description' => 'Different additional settings for the item (question).',
),
);
}
protected static function define_related() {
return array(
'context' => 'context',
'itemnumber' => 'int?'
);
}
protected static function define_other_properties() {
return array(
'itemfiles' => array(
'type' => stored_file_exporter::read_properties_definition(),
'multiple' => true
),
'itemnumber' => array(
'type' => PARAM_INT,
'description' => 'The item position number',
'null' => NULL_ALLOWED
),
'otherdata' => array(
'type' => PARAM_RAW,
'description' => 'Additional data that may be required by external functions',
'null' => NULL_ALLOWED
),
);
}
protected function get_other_values(renderer_base $output) {
$context = $this->related['context'];
$itemobj = feedback_get_item_class($this->data->typ);
$values = array(
'itemfiles' => array(),
'itemnumber' => $this->related['itemnumber'],
'otherdata' => $itemobj->get_data_for_external($this->data),
);
$fs = get_file_storage();
$files = array();
$itemfiles = $fs->get_area_files($context->id, 'mod_feedback', 'item', $this->data->id, 'filename', false);
if (!empty($itemfiles)) {
foreach ($itemfiles as $storedfile) {
$fileexporter = new stored_file_exporter($storedfile, array('context' => $context));
$files[] = $fileexporter->export($output);
}
$values['itemfiles'] = $files;
}
return $values;
}
/**
* Get the formatting parameters for the name.
*
* @return array
*/
protected function get_format_parameters_for_name() {
return [
'component' => 'mod_feedback',
'filearea' => 'item',
'itemid' => $this->data->id
];
}
/**
* Get the formatting parameters for the presentation.
*
* @return array
*/
protected function get_format_parameters_for_presentation() {
return [
'component' => 'mod_feedback',
'filearea' => 'item',
'itemid' => $this->data->id
];
}
}
@@ -0,0 +1,190 @@
<?php
// 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/>.
namespace mod_feedback\external;
use core\external\exporter;
use renderer_base;
use core_external\util as external_util;
use core_external\external_files;
/**
* Class for exporting partial feedback data (some fields are only viewable by admins).
*
* @copyright 2017 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @package mod_feedback
*/
class feedback_summary_exporter extends exporter {
protected static function define_properties() {
return array(
'id' => array(
'type' => PARAM_INT,
'description' => 'The primary key of the record.',
),
'course' => array(
'type' => PARAM_INT,
'description' => 'Course id this feedback is part of.',
),
'name' => array(
'type' => PARAM_TEXT,
'description' => 'Feedback name.',
),
'intro' => array(
'default' => '',
'type' => PARAM_RAW,
'description' => 'Feedback introduction text.',
),
'introformat' => array(
'choices' => array(FORMAT_HTML, FORMAT_MOODLE, FORMAT_PLAIN, FORMAT_MARKDOWN),
'type' => PARAM_INT,
'default' => FORMAT_MOODLE,
'description' => 'Feedback intro text format.',
),
'lang' => array(
'type' => PARAM_LANG,
'description' => 'Forced activity language',
'null' => NULL_ALLOWED,
),
'anonymous' => array(
'type' => PARAM_INT,
'description' => 'Whether the feedback is anonymous.',
),
'email_notification' => array(
'type' => PARAM_BOOL,
'optional' => true,
'description' => 'Whether email notifications will be sent to teachers.',
),
'multiple_submit' => array(
'default' => 1,
'type' => PARAM_BOOL,
'description' => 'Whether multiple submissions are allowed.',
),
'autonumbering' => array(
'default' => 1,
'type' => PARAM_BOOL,
'description' => 'Whether questions should be auto-numbered.',
),
'site_after_submit' => array(
'type' => PARAM_TEXT,
'optional' => true,
'description' => 'Link to next page after submission.',
),
'page_after_submit' => array(
'type' => PARAM_RAW,
'optional' => true,
'description' => 'Text to display after submission.',
),
'page_after_submitformat' => array(
'choices' => array(FORMAT_HTML, FORMAT_MOODLE, FORMAT_PLAIN, FORMAT_MARKDOWN),
'type' => PARAM_INT,
'default' => FORMAT_MOODLE,
'description' => 'Text to display after submission format.',
),
'publish_stats' => array(
'default' => 0,
'type' => PARAM_BOOL,
'description' => 'Whether stats should be published.',
),
'timeopen' => array(
'type' => PARAM_INT,
'optional' => true,
'description' => 'Allow answers from this time.',
),
'timeclose' => array(
'type' => PARAM_INT,
'optional' => true,
'description' => 'Allow answers until this time.',
),
'timemodified' => array(
'type' => PARAM_INT,
'optional' => true,
'description' => 'The time this record was modified.',
),
'completionsubmit' => array(
'default' => 0,
'type' => PARAM_BOOL,
'description' => 'If this field is set to 1, then the activity will be automatically marked as complete on submission.',
),
);
}
protected static function define_related() {
return array(
'context' => 'context'
);
}
protected static function define_other_properties() {
return array(
'coursemodule' => array(
'type' => PARAM_INT
),
'introfiles' => array(
'type' => external_files::get_properties_for_exporter(),
'multiple' => true
),
'pageaftersubmitfiles' => array(
'type' => external_files::get_properties_for_exporter(),
'multiple' => true,
'optional' => true
),
);
}
protected function get_other_values(renderer_base $output) {
$context = $this->related['context'];
$values = array(
'coursemodule' => $context->instanceid,
);
$values['introfiles'] = external_util::get_area_files($context->id, 'mod_feedback', 'intro', false, false);
if (!empty($this->data->page_after_submit)) {
$values['pageaftersubmitfiles'] = external_util::get_area_files($context->id, 'mod_feedback', 'page_after_submit');
}
return $values;
}
/**
* Get the formatting parameters for the intro.
*
* @return array
*/
protected function get_format_parameters_for_intro() {
return [
'component' => 'mod_feedback',
'filearea' => 'intro',
'options' => array('noclean' => true),
];
}
/**
* Get the formatting parameters for the page_after_submit.
*
* @return array
*/
protected function get_format_parameters_for_page_after_submit() {
return [
'component' => 'mod_feedback',
'filearea' => 'page_after_submit',
'itemid' => 0
];
}
}
@@ -0,0 +1,70 @@
<?php
// 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/>.
/**
* Class for exporting a feedback response.
*
* @package mod_feedback
* @copyright 2017 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_feedback\external;
defined('MOODLE_INTERNAL') || die();
use core\external\exporter;
/**
* Class for exporting a feedback response.
*
* @copyright 2017 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class feedback_value_exporter extends exporter {
/**
* Return the list of properties.
*
* @return array list of properties
*/
protected static function define_properties() {
return array(
'id' => array(
'type' => PARAM_INT,
'description' => 'The record id.',
),
'course_id' => array(
'type' => PARAM_INT,
'description' => 'The course id this record belongs to.',
),
'item' => array(
'type' => PARAM_INT,
'description' => 'The item id that was responded.',
),
'completed' => array(
'type' => PARAM_INT,
'description' => 'Reference to the feedback_completed table.',
),
'tmp_completed' => array(
'type' => PARAM_INT,
'description' => 'Old field - not used anymore.',
),
'value' => array(
'type' => PARAM_RAW,
'description' => 'The response value.',
),
);
}
}
@@ -0,0 +1,70 @@
<?php
// 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/>.
/**
* Class for exporting a feedback tmp response.
*
* @package mod_feedback
* @copyright 2017 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_feedback\external;
defined('MOODLE_INTERNAL') || die();
use core\external\exporter;
/**
* Class for exporting a feedback tmp response.
*
* @copyright 2017 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class feedback_valuetmp_exporter extends exporter {
/**
* Return the list of properties.
*
* @return array list of properties
*/
protected static function define_properties() {
return array(
'id' => array(
'type' => PARAM_INT,
'description' => 'The record id.',
),
'course_id' => array(
'type' => PARAM_INT,
'description' => 'The course id this record belongs to.',
),
'item' => array(
'type' => PARAM_INT,
'description' => 'The item id that was responded.',
),
'completed' => array(
'type' => PARAM_INT,
'description' => 'Reference to the feedback_completedtmp table.',
),
'tmp_completed' => array(
'type' => PARAM_INT,
'description' => 'Old field - not used anymore.',
),
'value' => array(
'type' => PARAM_RAW,
'description' => 'The response value.',
),
);
}
}
@@ -0,0 +1,115 @@
<?php
// 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/>.
namespace mod_feedback\form;
use core_form\dynamic_form;
use moodle_url;
use context;
use context_module;
use context_system;
/**
* Prints the create new template form
*
* @copyright 2021 Peter Dias
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package mod_feedback
*/
class create_template_form extends dynamic_form {
/**
* Define the form
*/
public function definition() {
$mform =& $this->_form;
$mform->addElement('hidden', 'id');
$mform->setType('id', PARAM_INT);
$mform->addElement('text',
'templatename',
get_string('name', 'feedback'),
['maxlength' => '200', 'size' => '50']);
$mform->setType('templatename', PARAM_TEXT);
if (has_capability('mod/feedback:createpublictemplate', context_system::instance())) {
$mform->addElement('checkbox',
'ispublic', '',
get_string('public', 'feedback'));
}
}
/**
* Returns context where this form is used
*
* @return context
*/
protected function get_context_for_dynamic_submission(): context {
$id = $this->optional_param('id', null, PARAM_INT);
list($course, $cm) = get_course_and_cm_from_cmid($id, 'feedback');
return context_module::instance($cm->id);
}
/**
* Checks if current user has access to this form, otherwise throws exception
*
* @throws \moodle_exception User does not have capability to access the form
*/
protected function check_access_for_dynamic_submission(): void {
$context = $this->get_context_for_dynamic_submission();
if (!has_capability('mod/feedback:edititems', $context) ||
!(has_capability('mod/feedback:createprivatetemplate', $context) ||
has_capability('mod/feedback:createpublictemplate', $context))) {
throw new \moodle_exception('nocapabilitytousethisservice');
}
}
/**
* Process the form submission, used if form was submitted via AJAX
*
* @return array Returns whether a new template was created.
*/
public function process_dynamic_submission(): array {
global $PAGE;
$formdata = $this->get_data();
$ispublic = !empty($formdata->ispublic) ? 1 : 0;
$result = feedback_save_as_template($PAGE->activityrecord, $formdata->templatename, $ispublic);
return [
'result' => $result,
];
}
/**
* Load in existing data as form defaults
*/
public function set_data_for_dynamic_submission(): void {
$this->set_data((object)[
'id' => $this->optional_param('id', null, PARAM_INT),
]);
}
/**
* Returns url to set in $PAGE->set_url() when form is being rendered or submitted via AJAX
*
* @return moodle_url
*/
protected function get_page_url_for_dynamic_submission(): moodle_url {
$params = [
'id' => $this->optional_param('id', null, PARAM_INT),
];
return new moodle_url('/mod/feedback/edit.php', $params);
}
}
@@ -0,0 +1,120 @@
<?php
// 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/>.
namespace mod_feedback\form;
use core_form\dynamic_form;
use moodle_url;
use context;
use context_module;
/**
* Prints the confirm use template form
*
* @copyright 2021 Peter Dias
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package mod_feedback
*/
class use_template_form extends dynamic_form {
/**
* Define the form
*/
public function definition() {
$mform =& $this->_form;
$mform->addElement('static', 'generalheader', '', get_string("whatfor", 'feedback'));
$mform->addElement('radio', 'deleteolditems', '', get_string('delete_old_items', 'feedback'), 1);
$mform->addElement('radio', 'deleteolditems', '', get_string('append_new_items', 'feedback'), 0);
$mform->setType('deleteolditems', PARAM_INT);
$mform->setDefault('deleteolditems', 1);
$mform->addElement('hidden', 'id');
$mform->setType('id', PARAM_INT);
$mform->addElement('hidden', 'templateid');
$mform->setType('templateid', PARAM_INT);
}
/**
* Returns context where this form is used
*
* @return context
*/
protected function get_context_for_dynamic_submission(): context {
$id = $this->optional_param('id', null, PARAM_INT);
list($course, $cm) = get_course_and_cm_from_cmid($id, 'feedback');
return context_module::instance($cm->id);
}
/**
* Checks if current user has access to this form, otherwise throws exception
*
* @throws \moodle_exception User does not have capability to access the form
*/
protected function check_access_for_dynamic_submission(): void {
if (!has_capability('mod/feedback:edititems', $this->get_context_for_dynamic_submission())) {
throw new \moodle_exception('nocapabilitytousethisservice');
}
}
/**
* Process the form submission, used if form was submitted via AJAX
*
* @return array Returns the following information
* - the template was successfully created/updated from the provided template
* - the redirect url.
*/
public function process_dynamic_submission(): array {
global $PAGE;
$formdata = $this->get_data();
$templateid = $this->optional_param('templateid', null, PARAM_INT);
$id = $this->optional_param('id', null, PARAM_INT);
$response = feedback_items_from_template($PAGE->activityrecord, $templateid, $formdata->deleteolditems);
$url = new moodle_url('/mod/feedback/edit.php', ['id' => $id]);
if ($response !== false) {
// Provide a notification on success as the user will be redirected.
\core\notification::add(get_string('feedbackupdated', 'feedback'), \core\notification::SUCCESS);
}
return [
'result' => $response !== false,
'url' => $url->out()
];
}
/**
* Load in existing data as form defaults
*/
public function set_data_for_dynamic_submission(): void {
$this->set_data((object)[
'id' => $this->optional_param('id', null, PARAM_INT),
'templateid' => $this->optional_param('templateid', null, PARAM_INT)
]);
}
/**
* Returns url to set in $PAGE->set_url() when form is being rendered or submitted via AJAX
*
* @return moodle_url
*/
protected function get_page_url_for_dynamic_submission(): moodle_url {
$params = [
'id' => $this->optional_param('id', null, PARAM_INT),
'templateid' => $this->optional_param('templateid', null, PARAM_INT)
];
return new moodle_url('/mod/feedback/use_templ.php', $params);
}
}
@@ -0,0 +1,83 @@
<?php
// 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/>.
namespace mod_feedback\navigation\views;
use core\navigation\views\secondary as core_secondary;
use settings_navigation;
use navigation_node;
/**
* Custom secondary navigation class
*
* A custom construct of secondary nav for feedback. This rearranges the nodes for the secondary
*
* @package mod_feedback
* @category navigation
* @copyright 2021 onwards Peter Dias
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class secondary extends core_secondary {
protected function get_default_module_mapping(): array {
$basenodes = parent::get_default_module_mapping();
$basenodes[self::TYPE_CUSTOM] += [
'templatenode' => 12,
'mapcourse' => 13,
'feedbackanalysis' => 14,
'responses' => 15,
'nonrespondents' => 15.1
];
return $basenodes;
}
/**
* Custom module construct for feedback
*
* @param settings_navigation $settingsnav The settings navigation object related to the module page
* @param navigation_node|null $rootnode The node where the module navigation nodes should be added into as children.
* If not explicitly defined, the nodes will be added to the secondary root
* node by default.
*/
protected function load_module_navigation(settings_navigation $settingsnav, ?navigation_node $rootnode = null): void {
$rootnode = $rootnode ?? $this;
$mainnode = $settingsnav->find('modulesettings', self::TYPE_SETTING);
$nodes = $this->get_default_module_mapping();
if ($mainnode) {
$url = new \moodle_url('/mod/' . $this->page->activityname . '/view.php', ['id' => $this->page->cm->id]);
$setactive = $url->compare($this->page->url, URL_MATCH_BASE);
$node = $rootnode->add(get_string('modulename', 'feedback'), $url, null, null, 'modulepage');
if ($setactive) {
$node->make_active();
}
// Add the initial nodes.
$nodesordered = $this->get_leaf_nodes($mainnode, $nodes);
$this->add_ordered_nodes($nodesordered, $rootnode);
// Reorder the existing nodes in settings so the active node scan can pick it up.
$existingnode = $settingsnav->find('questionnode', self::TYPE_CUSTOM);
if ($existingnode) {
$node->add_node($existingnode);
$nodes[self::TYPE_CUSTOM] += ['questionnode' => 3];
}
// We have finished inserting the initial structure.
// Populate the menu with the rest of the nodes available.
$this->load_remaining_nodes($mainnode, $nodes, $rootnode);
}
}
}
+46
View File
@@ -0,0 +1,46 @@
<?php
// 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/>.
/**
* Event observers supported by this module
*
* @package mod_feedback
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Event observers supported by this module
*
* @package mod_feedback
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class mod_feedback_observer {
/**
* Observer for the even course_content_deleted - delete all course templates.
*
* @param \core\event\course_content_deleted $event
*/
public static function course_content_deleted(\core\event\course_content_deleted $event) {
global $DB;
// Delete all templates of given course.
$DB->delete_records('feedback_template', array('course' => $event->objectid));
}
}
@@ -0,0 +1,101 @@
<?php
// 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/>.
namespace mod_feedback\output;
use context_module;
use renderable;
use renderer_base;
use templatable;
/**
* Class base_action_bar
*
* Base class to be inherited by any other feedback action bar
*
* @package mod_feedback
* @copyright 2021 onwards Peter Dias
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
abstract class base_action_bar implements renderable, templatable {
/** @var int $cmid The module id */
protected $cmid;
/** @var object $context The context we are in */
protected $context;
/** @var object $course The course we are in */
protected $course;
/** @var array $urlparams The default params to be used when creating urls */
protected $urlparams;
/** @var object $feedback The activity record that is being viewed */
protected $feedback;
/**
* base_action_bar constructor.
*
* @param int $cmid
*/
public function __construct(int $cmid) {
global $PAGE;
$this->cmid = $cmid;
$this->context = context_module::instance($cmid);
[$course, $cm] = get_course_and_cm_from_cmid($cmid);
$this->course = $course;
$this->urlparams = [
'id' => $cmid
];
$this->feedback = $PAGE->activityrecord;
}
/**
* Recursively iterates through to array of renderables and exports
*
* @param array $items Collection of renderables
* @param renderer_base $output
* @return array $items Data to be used in the mustache template
*/
private function export_items_for_template(array $items, renderer_base $output): array {
$items = array_map(function($item) use ($output) {
if (is_array($item)) {
return $this->export_items_for_template($item, $output);
}
if (is_object($item) && method_exists($item, 'export_for_template')) {
return $item->export_for_template($output);
}
return $item;
}, $items);
return $items;
}
/**
* Export the data so it can be used as the context for a mustache template.
*
* @param renderer_base $output
* @return array
*/
public function export_for_template(renderer_base $output): array {
$items = $this->export_items_for_template($this->get_items(), $output);
return $items;
}
/**
* Function to generate a list of renderables to be displayed
* @return array
*/
abstract protected function get_items(): array;
}
@@ -0,0 +1,100 @@
<?php
// 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/>.
namespace mod_feedback\output;
use moodle_url;
use action_link;
use single_select;
use url_select;
/**
* Class actionbar - Display the action bar
*
* @package mod_feedback
* @copyright 2021 Peter Dias
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class edit_action_bar extends base_action_bar {
/** @var moodle_url $currenturl The current page url */
private $currenturl;
/** @var int|null $lastposition The index of the last question type in the feedback module */
private $lastposition;
/**
* edit_action_bar constructor.
*
* @param int $cmid The course module id
* @param moodle_url $pageurl The current page url
* @param int|null $lastposition Index of the last question in the feedback
*/
public function __construct(int $cmid, moodle_url $pageurl, ?int $lastposition = null) {
parent::__construct($cmid);
$this->currenturl = $pageurl;
$this->lastposition = $lastposition;
}
/**
* Return the items to be used for the tertiary nav
*
* @return array
*/
public function get_items(): array {
global $DB;
$url = new moodle_url('/mod/feedback/view.php', ['id' => $this->cmid]);
$items['left'][]['actionlink'] = new action_link($url, get_string('back'), null, ['class' => 'btn btn-secondary']);
if (has_capability('mod/feedback:edititems', $this->context)) {
$editurl = new moodle_url('/mod/feedback/edit.php', $this->urlparams);
$templateurl = new moodle_url('/mod/feedback/manage_templates.php', $this->urlparams);
$importurl = new moodle_url('/mod/feedback/import.php', $this->urlparams);
$options = [
$editurl->out(false) => get_string('add_item', 'feedback'),
$templateurl->out(false) => get_string('using_templates', 'feedback'),
$importurl->out(false) => get_string('import_questions', 'feedback')
];
$selected = $this->currenturl;
// Template pages can have sub pages, so match these.
if ($this->currenturl->compare(new moodle_url('/mod/feedback/use_templ.php'), URL_MATCH_BASE)) {
$selected = $templateurl;
}
$items['left'][]['urlselect'] = new url_select($options, $selected->out(false), null);
$viewquestions = $editurl->compare($this->currenturl);
if ($viewquestions) {
$select = new single_select(new moodle_url('/mod/feedback/edit_item.php',
['cmid' => $this->cmid, 'position' => $this->lastposition, 'sesskey' => sesskey()]),
'typ', feedback_load_feedback_items_options());
$items['left'][]['singleselect'] = $select;
if ($DB->record_exists('feedback_item', ['feedback' => $this->feedback->id])) {
$items['export'] = new action_link(
new moodle_url('/mod/feedback/export.php', $this->urlparams + ['action' => 'exportfile']),
get_string('export_questions', 'feedback'),
null,
['class' => 'btn btn-secondary'],
);
}
}
}
return $items;
}
}
@@ -0,0 +1,86 @@
<?php
// 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/>.
namespace mod_feedback\output;
use confirm_action;
use context_system;
use moodle_url;
use action_link;
/**
* Class actionbar - Display the action bar
*
* @package mod_feedback
* @copyright 2021 Peter Dias
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class edit_template_action_bar extends base_action_bar {
/** @var int $templateid The template that is being edited/used */
private $templateid;
/** @var string $mode The type of view we are dealing with */
private $mode;
/**
* edit_template_action_bar constructor.
* @param int $cmid
* @param int $templateid
* @param string $mode
*/
public function __construct(int $cmid, int $templateid, string $mode) {
parent::__construct($cmid);
$this->templateid = $templateid;
$this->mode = $mode;
}
/**
* Return the items to be used in the tertiary nav
*
* @return array
*/
public function get_items(): array {
global $DB;
$additionalparams = ($this->mode ? ['mode' => $this->mode] : []);
$templateurl = new moodle_url('/mod/feedback/manage_templates.php', $this->urlparams + $additionalparams);
$items['left'][]['actionlink'] = new action_link($templateurl, get_string('back'), null, ['class' => 'btn btn-secondary']);
if (has_capability('mod/feedback:edititems', $this->context)) {
$items['usetemplate'] = $this->urlparams + [
'templateid' => $this->templateid
];
}
$template = $DB->get_record('feedback_template', array('id' => $this->templateid), '*', MUST_EXIST);
$systemcontext = context_system::instance();
$showdelete = has_capability('mod/feedback:deletetemplate', $this->context);
if ($template->ispublic) {
$showdelete = has_capability('mod/feedback:createpublictemplate', $systemcontext) &&
has_capability('mod/feedback:deletetemplate', $systemcontext);
}
if ($showdelete) {
$params = $this->urlparams + $additionalparams + [
'deletetemplate' => $this->templateid,
'sesskey' => sesskey()
];
$deleteurl = new moodle_url('/mod/feedback/manage_templates.php', $params);
$deleteaction = new confirm_action(get_string('confirmdeletetemplate', 'feedback'));
$items['export'] = new action_link($deleteurl, get_string('delete'), $deleteaction, ['class' => 'btn btn-secondary']);
}
return $items;
}
}
+50
View File
@@ -0,0 +1,50 @@
<?php
// 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/>.
namespace mod_feedback\output;
use plugin_renderer_base;
/**
* Class renderer
*
* @package mod_feedback
* @copyright 2021 Peter Dias
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class renderer extends plugin_renderer_base {
/**
* Generate the tertiary nav
*
* @param base_action_bar $actionmenu
* @return bool|string
*/
public function main_action_bar(base_action_bar $actionmenu) {
$context = $actionmenu->export_for_template($this);
return $this->render_from_template('mod_feedback/main_action_menu', $context);
}
/**
* Render the create template form
*
* @param int $id
* @return bool|string
*/
public function create_template_form(int $id) {
return $this->render_from_template('mod_feedback/create_template', ['id' => $id]);
}
}
@@ -0,0 +1,72 @@
<?php
// 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/>.
namespace mod_feedback\output;
use moodle_url;
use url_select;
/**
* Class responses_action_bar. The tertiary nav for the responses page
*
* @copyright 2021 Peter Dias
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package mod_feedback
*/
class responses_action_bar extends base_action_bar {
/** @var moodle_url $currenturl The current page url */
private $currenturl;
/**
* responses_action_bar constructor.
*
* @param int $cmid The cmid for the module we are operating on
* @param moodle_url $pageurl The current page url
*/
public function __construct(int $cmid, moodle_url $pageurl) {
parent::__construct($cmid);
$this->currenturl = $pageurl;
$this->urlparams['courseid'] = $this->course->id;
}
/**
* Return the items to be used in the tertiary nav
*
* @return array
*/
public function get_items(): array {
$items = [];
if (has_capability('mod/feedback:viewreports', $this->context)) {
$reporturl = new moodle_url('/mod/feedback/show_entries.php', $this->urlparams);
$options[$reporturl->out(false)] = get_string('show_entries', 'feedback');
$selected = $this->currenturl->compare($reporturl, URL_MATCH_BASE) ? $reporturl : $this->currenturl;
if ($this->feedback->anonymous == FEEDBACK_ANONYMOUS_NO && $this->course->id != SITEID) {
$nonrespondenturl = new moodle_url('/mod/feedback/show_nonrespondents.php', $this->urlparams);
$options[$nonrespondenturl->out(false)] = get_string('show_nonrespondents', 'feedback');
$selected = $this->currenturl->compare($nonrespondenturl, URL_MATCH_BASE) ? $nonrespondenturl : $this->currenturl;;
}
// Don't show the dropdown if it's only a single item.
if (count($options) != 1) {
$items['left'][]['urlselect'] = new url_select($options,
$selected->out(false),
null);
}
}
return $items;
}
}
@@ -0,0 +1,100 @@
<?php
// 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/>.
namespace mod_feedback\output;
use action_link;
use moodle_url;
/**
* Class standard_action_bar
*
* The default tertiary nav on the module landing page
*
* @copyright 2021 Peter Dias
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package mod_feedback
*/
class standard_action_bar extends base_action_bar {
/** @var int $startpage The page to resume with. */
private $startpage;
/** @var int $viewcompletion Whether or not the user can finish the feedback */
private $viewcompletion;
/**
* standard_action_bar constructor.
*
* @param int $cmid
* @param bool $viewcompletion Whether or not the user can finish the feedback
* @param int|null $startpage The page to resume with.
* @param int|null $courseid The course that the feedback is being accessed from. If null, courseid will be
* set via the $cmid relationship
*/
public function __construct(int $cmid, bool $viewcompletion, ?int $startpage = null, ?int $courseid = null) {
parent::__construct($cmid);
$this->startpage = $startpage;
$this->viewcompletion = $viewcompletion;
if ($courseid && $courseid != $this->course->id) {
$this->course = get_course($courseid);
}
$this->urlparams['courseid'] = $this->course->id;
}
/**
* Return the items to be used in the tertiary nav
*
* @return array
*/
public function get_items(): array {
$items = [];
if (has_capability('mod/feedback:edititems', $this->context)) {
$editurl = new moodle_url('/mod/feedback/edit.php', $this->urlparams);
$items['left'][]['actionlink'] = new action_link($editurl, get_string('edit_items', 'feedback'),
null, ['class' => 'btn btn-secondary']);
}
// The preview icon should be displayed only to users with capability to edit or view reports (to include
// non-editing teachers too).
$capabilities = [
'mod/feedback:edititems',
'mod/feedback:viewreports',
];
if (has_any_capability($capabilities, $this->context)) {
$previewlnk = new moodle_url('/mod/feedback/print.php', array('id' => $this->cmid));
if ($this->course->id) {
$previewlnk->param('courseid', $this->course->id);
}
$items['left'][]['actionlink'] = new action_link($previewlnk, get_string('previewquestions', 'feedback'),
null, ['class' => 'btn btn-secondary']);
}
if ($this->viewcompletion) {
// Display a link to complete feedback or resume.
$completeurl = new moodle_url('/mod/feedback/complete.php',
['id' => $this->cmid, 'courseid' => $this->course->id]);
if ($this->startpage) {
$completeurl->param('gopage', $this->startpage);
$label = get_string('continue_the_form', 'feedback');
} else {
$label = get_string('complete_the_form', 'feedback');
}
$items['left'][]['actionlink'] = new action_link($completeurl, $label, null, ['class' => 'btn btn-primary']);
}
return $items;
}
}
+73
View File
@@ -0,0 +1,73 @@
<?php
// 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/>.
/**
* Contains class mod_feedback\output\summary
*
* @package mod_feedback
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_feedback\output;
use renderable;
use templatable;
use renderer_base;
use stdClass;
use moodle_url;
use mod_feedback_structure;
/**
* Class to help display feedback summary
*
* @package mod_feedback
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class summary implements renderable, templatable {
/** @var mod_feedback_structure */
protected $feedbackstructure;
/** @var int */
protected $mygroupid;
/**
* Constructor.
*
* @param mod_feedback_structure $feedbackstructure
* @param int $mygroupid currently selected group
*/
public function __construct($feedbackstructure, $mygroupid = false) {
$this->feedbackstructure = $feedbackstructure;
$this->mygroupid = $mygroupid;
}
/**
* Export this data so it can be used as the context for a mustache template.
*
* @param renderer_base $output
* @return stdClass
*/
public function export_for_template(renderer_base $output) {
$r = new stdClass();
$r->completedcount = $this->feedbackstructure->count_completed_responses($this->mygroupid);
$r->itemscount = count($this->feedbackstructure->get_items(true));
return $r;
}
}
+488
View File
@@ -0,0 +1,488 @@
<?php
// 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/>.
/**
* Data provider.
*
* @package mod_feedback
* @copyright 2018 Frédéric Massart
* @author Frédéric Massart <fred@branchup.tech>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_feedback\privacy;
defined('MOODLE_INTERNAL') || die();
use context;
use context_helper;
use stdClass;
use core_privacy\local\metadata\collection;
use core_privacy\local\request\approved_contextlist;
use core_privacy\local\request\approved_userlist;
use core_privacy\local\request\contextlist;
use core_privacy\local\request\helper;
use core_privacy\local\request\transform;
use core_privacy\local\request\userlist;
use core_privacy\local\request\writer;
require_once($CFG->dirroot . '/mod/feedback/lib.php');
/**
* Data provider class.
*
* @package mod_feedback
* @copyright 2018 Frédéric Massart
* @author Frédéric Massart <fred@branchup.tech>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements
\core_privacy\local\metadata\provider,
\core_privacy\local\request\core_userlist_provider,
\core_privacy\local\request\plugin\provider {
/**
* Returns metadata.
*
* @param collection $collection The initialised collection to add items to.
* @return collection A listing of user data stored through this system.
*/
public static function get_metadata(collection $collection): collection {
$completedfields = [
'userid' => 'privacy:metadata:completed:userid',
'timemodified' => 'privacy:metadata:completed:timemodified',
'anonymous_response' => 'privacy:metadata:completed:anonymousresponse',
];
$collection->add_database_table('feedback_completed', $completedfields, 'privacy:metadata:completed');
$collection->add_database_table('feedback_completedtmp', $completedfields, 'privacy:metadata:completedtmp');
$valuefields = [
'value' => 'privacy:metadata:value:value'
];
$collection->add_database_table('feedback_value', $valuefields, 'privacy:metadata:value');
$collection->add_database_table('feedback_valuetmp', $valuefields, 'privacy:metadata:valuetmp');
return $collection;
}
/**
* Get the list of contexts that contain user information for the specified user.
*
* @param int $userid The user to search.
* @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
*/
public static function get_contexts_for_userid(int $userid): contextlist {
$sql = "
SELECT DISTINCT ctx.id
FROM {%s} fc
JOIN {modules} m
ON m.name = :feedback
JOIN {course_modules} cm
ON cm.instance = fc.feedback
AND cm.module = m.id
JOIN {context} ctx
ON ctx.instanceid = cm.id
AND ctx.contextlevel = :modlevel
WHERE fc.userid = :userid";
$params = ['feedback' => 'feedback', 'modlevel' => CONTEXT_MODULE, 'userid' => $userid];
$contextlist = new contextlist();
$contextlist->add_from_sql(sprintf($sql, 'feedback_completed'), $params);
$contextlist->add_from_sql(sprintf($sql, 'feedback_completedtmp'), $params);
return $contextlist;
}
/**
* Get the list of users who have data within a context.
*
* @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination.
*
*/
public static function get_users_in_context(userlist $userlist) {
$context = $userlist->get_context();
if (!is_a($context, \context_module::class)) {
return;
}
// Find users with feedback entries.
$sql = "
SELECT fc.userid
FROM {%s} fc
JOIN {modules} m
ON m.name = :feedback
JOIN {course_modules} cm
ON cm.instance = fc.feedback
AND cm.module = m.id
JOIN {context} ctx
ON ctx.instanceid = cm.id
AND ctx.contextlevel = :modlevel
WHERE ctx.id = :contextid";
$params = ['feedback' => 'feedback', 'modlevel' => CONTEXT_MODULE, 'contextid' => $context->id];
$userlist->add_from_sql('userid', sprintf($sql, 'feedback_completed'), $params);
$userlist->add_from_sql('userid', sprintf($sql, 'feedback_completedtmp'), $params);
}
/**
* Export all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist The approved contexts to export information for.
*/
public static function export_user_data(approved_contextlist $contextlist) {
global $DB;
$user = $contextlist->get_user();
$userid = $user->id;
$contextids = array_map(function($context) {
return $context->id;
}, array_filter($contextlist->get_contexts(), function($context) {
return $context->contextlevel == CONTEXT_MODULE;
}));
if (empty($contextids)) {
return;
}
$flushdata = function($context, $data) use ($user) {
$contextdata = helper::get_context_data($context, $user);
helper::export_context_files($context, $user);
$mergeddata = array_merge((array) $contextdata, (array) $data);
// Drop the temporary keys.
if (array_key_exists('submissions', $mergeddata)) {
$mergeddata['submissions'] = array_values($mergeddata['submissions']);
}
writer::with_context($context)->export_data([], (object) $mergeddata);
};
$lastctxid = null;
$data = (object) [];
list($sql, $params) = static::prepare_export_query($contextids, $userid);
$recordset = $DB->get_recordset_sql($sql, $params);
foreach ($recordset as $record) {
if ($lastctxid && $lastctxid != $record->contextid) {
$flushdata(context::instance_by_id($lastctxid), $data);
$data = (object) [];
}
context_helper::preload_from_record($record);
$id = ($record->istmp ? 'tmp' : 'notmp') . $record->submissionid;
if (!isset($data->submissions)) {
$data->submissions = [];
}
if (!isset($data->submissions[$id])) {
$data->submissions[$id] = [
'inprogress' => transform::yesno($record->istmp),
'anonymousresponse' => transform::yesno($record->anonymousresponse == FEEDBACK_ANONYMOUS_YES),
'timemodified' => transform::datetime($record->timemodified),
'answers' => []
];
}
$item = static::extract_item_record_from_record($record);
$value = static::extract_value_record_from_record($record);
$itemobj = feedback_get_item_class($record->itemtyp);
$data->submissions[$id]['answers'][] = [
'question' => format_text($record->itemname, FORMAT_HTML, [
'context' => context::instance_by_id($record->contextid),
'para' => false,
'noclean' => true,
]),
'answer' => $itemobj->get_printval($item, $value)
];
$lastctxid = $record->contextid;
}
if (!empty($lastctxid)) {
$flushdata(context::instance_by_id($lastctxid), $data);
}
$recordset->close();
}
/**
* Delete all data for all users in the specified context.
*
* @param context $context The specific context to delete data for.
*/
public static function delete_data_for_all_users_in_context(\context $context) {
global $DB;
// This should not happen, but just in case.
if ($context->contextlevel != CONTEXT_MODULE) {
return;
}
// Prepare SQL to gather all completed IDs.
$completedsql = "
SELECT fc.id
FROM {%s} fc
JOIN {modules} m
ON m.name = :feedback
JOIN {course_modules} cm
ON cm.instance = fc.feedback
AND cm.module = m.id
WHERE cm.id = :cmid";
$completedparams = ['cmid' => $context->instanceid, 'feedback' => 'feedback'];
// Delete temp answers and submissions.
$completedtmpids = $DB->get_fieldset_sql(sprintf($completedsql, 'feedback_completedtmp'), $completedparams);
if (!empty($completedtmpids)) {
list($insql, $inparams) = $DB->get_in_or_equal($completedtmpids, SQL_PARAMS_NAMED);
$DB->delete_records_select('feedback_valuetmp', "completed $insql", $inparams);
$DB->delete_records_select('feedback_completedtmp', "id $insql", $inparams);
}
// Delete answers and submissions.
$completedids = $DB->get_fieldset_sql(sprintf($completedsql, 'feedback_completed'), $completedparams);
if (!empty($completedids)) {
list($insql, $inparams) = $DB->get_in_or_equal($completedids, SQL_PARAMS_NAMED);
$DB->delete_records_select('feedback_value', "completed $insql", $inparams);
$DB->delete_records_select('feedback_completed', "id $insql", $inparams);
}
}
/**
* Delete all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
*/
public static function delete_data_for_user(approved_contextlist $contextlist) {
global $DB;
$userid = $contextlist->get_user()->id;
// Ensure that we only act on module contexts.
$contextids = array_map(function($context) {
return $context->instanceid;
}, array_filter($contextlist->get_contexts(), function($context) {
return $context->contextlevel == CONTEXT_MODULE;
}));
// Prepare SQL to gather all completed IDs.
list($insql, $inparams) = $DB->get_in_or_equal($contextids, SQL_PARAMS_NAMED);
$completedsql = "
SELECT fc.id
FROM {%s} fc
JOIN {modules} m
ON m.name = :feedback
JOIN {course_modules} cm
ON cm.instance = fc.feedback
AND cm.module = m.id
WHERE fc.userid = :userid
AND cm.id $insql";
$completedparams = array_merge($inparams, ['userid' => $userid, 'feedback' => 'feedback']);
// Delete all submissions in progress.
$completedtmpids = $DB->get_fieldset_sql(sprintf($completedsql, 'feedback_completedtmp'), $completedparams);
if (!empty($completedtmpids)) {
list($insql, $inparams) = $DB->get_in_or_equal($completedtmpids, SQL_PARAMS_NAMED);
$DB->delete_records_select('feedback_valuetmp', "completed $insql", $inparams);
$DB->delete_records_select('feedback_completedtmp', "id $insql", $inparams);
}
// Delete all final submissions.
$completedids = $DB->get_fieldset_sql(sprintf($completedsql, 'feedback_completed'), $completedparams);
if (!empty($completedids)) {
list($insql, $inparams) = $DB->get_in_or_equal($completedids, SQL_PARAMS_NAMED);
$DB->delete_records_select('feedback_value', "completed $insql", $inparams);
$DB->delete_records_select('feedback_completed', "id $insql", $inparams);
}
}
/**
* Delete multiple users within a single context.
*
* @param approved_userlist $userlist The approved context and user information to delete information for.
*/
public static function delete_data_for_users(approved_userlist $userlist) {
global $DB;
$context = $userlist->get_context();
$userids = $userlist->get_userids();
// Prepare SQL to gather all completed IDs.
list($insql, $inparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
$completedsql = "
SELECT fc.id
FROM {%s} fc
JOIN {modules} m
ON m.name = :feedback
JOIN {course_modules} cm
ON cm.instance = fc.feedback
AND cm.module = m.id
WHERE cm.id = :instanceid
AND fc.userid $insql";
$completedparams = array_merge($inparams, ['instanceid' => $context->instanceid, 'feedback' => 'feedback']);
// Delete all submissions in progress.
$completedtmpids = $DB->get_fieldset_sql(sprintf($completedsql, 'feedback_completedtmp'), $completedparams);
if (!empty($completedtmpids)) {
list($insql, $inparams) = $DB->get_in_or_equal($completedtmpids, SQL_PARAMS_NAMED);
$DB->delete_records_select('feedback_valuetmp', "completed $insql", $inparams);
$DB->delete_records_select('feedback_completedtmp', "id $insql", $inparams);
}
// Delete all final submissions.
$completedids = $DB->get_fieldset_sql(sprintf($completedsql, 'feedback_completed'), $completedparams);
if (!empty($completedids)) {
list($insql, $inparams) = $DB->get_in_or_equal($completedids, SQL_PARAMS_NAMED);
$DB->delete_records_select('feedback_value', "completed $insql", $inparams);
$DB->delete_records_select('feedback_completed', "id $insql", $inparams);
}
}
/**
* Extract an item record from a database record.
*
* @param stdClass $record The record.
* @return The item record.
*/
protected static function extract_item_record_from_record(stdClass $record) {
$newrec = new stdClass();
foreach ($record as $key => $value) {
if (strpos($key, 'item') !== 0) {
continue;
}
$key = substr($key, 4);
$newrec->{$key} = $value;
}
return $newrec;
}
/**
* Extract a value record from a database record.
*
* @param stdClass $record The record.
* @return The value record.
*/
protected static function extract_value_record_from_record(stdClass $record) {
$newrec = new stdClass();
foreach ($record as $key => $value) {
if (strpos($key, 'value') !== 0) {
continue;
}
$key = substr($key, 5);
$newrec->{$key} = $value;
}
return $newrec;
}
/**
* Prepare the query to export all data.
*
* Doing it this way allows for merging all records from both the temporary and final tables
* as most of their columns are shared. It is a lot easier to deal with the records when
* exporting as we do not need to try to manually group the two types of submissions in the
* same reported dataset.
*
* The ordering may affect performance on large datasets.
*
* @param array $contextids The context IDs.
* @param int $userid The user ID.
* @return array With SQL and params.
*/
protected static function prepare_export_query(array $contextids, $userid) {
global $DB;
$makefetchsql = function($istmp) use ($DB, $contextids, $userid) {
$ctxfields = context_helper::get_preload_record_columns_sql('ctx');
list($insql, $inparams) = $DB->get_in_or_equal($contextids, SQL_PARAMS_NAMED);
$i = $istmp ? 0 : 1;
$istmpsqlval = $istmp ? 1 : 0;
$prefix = $istmp ? 'idtmp' : 'id';
$uniqid = $DB->sql_concat("'$prefix'", 'fc.id');
$sql = "
SELECT $uniqid AS uniqid,
f.id AS feedbackid,
ctx.id AS contextid,
$istmpsqlval AS istmp,
fc.id AS submissionid,
fc.anonymous_response AS anonymousresponse,
fc.timemodified AS timemodified,
fv.id AS valueid,
fv.course_id AS valuecourse_id,
fv.item AS valueitem,
fv.completed AS valuecompleted,
fv.tmp_completed AS valuetmp_completed,
$ctxfields
FROM {context} ctx
JOIN {course_modules} cm
ON cm.id = ctx.instanceid
JOIN {feedback} f
ON f.id = cm.instance
JOIN {%s} fc
ON fc.feedback = f.id
JOIN {%s} fv
ON fv.completed = fc.id
WHERE ctx.id $insql
AND fc.userid = :userid{$i}";
$params = array_merge($inparams, [
'userid' . $i => $userid,
]);
$completedtbl = $istmp ? 'feedback_completedtmp' : 'feedback_completed';
$valuetbl = $istmp ? 'feedback_valuetmp' : 'feedback_value';
return [sprintf($sql, $completedtbl, $valuetbl), $params];
};
list($nontmpsql, $nontmpparams) = $makefetchsql(false);
list($tmpsql, $tmpparams) = $makefetchsql(true);
// Oracle does not support UNION on text fields, therefore we must get the itemdescription
// and valuevalue after doing the union by joining on the result.
$sql = "
SELECT q.*,
COALESCE(fv.value, fvt.value) AS valuevalue,
fi.id AS itemid,
fi.feedback AS itemfeedback,
fi.template AS itemtemplate,
fi.name AS itemname,
fi.label AS itemlabel,
fi.presentation AS itempresentation,
fi.typ AS itemtyp,
fi.hasvalue AS itemhasvalue,
fi.position AS itemposition,
fi.required AS itemrequired,
fi.dependitem AS itemdependitem,
fi.dependvalue AS itemdependvalue,
fi.options AS itemoptions
FROM ($nontmpsql UNION $tmpsql) q
LEFT JOIN {feedback_value} fv
ON fv.id = q.valueid AND q.istmp = 0
LEFT JOIN {feedback_valuetmp} fvt
ON fvt.id = q.valueid AND q.istmp = 1
JOIN {feedback_item} fi
ON (fi.id = fv.item OR fi.id = fvt.item)
ORDER BY q.contextid, q.istmp, q.submissionid, q.valueid";
$params = array_merge($nontmpparams, $tmpparams);
return [$sql, $params];
}
}
@@ -0,0 +1,129 @@
<?php
// 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/>.
/**
* Contains class mod_feedback_responses_anon_table
*
* @package mod_feedback
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Class mod_feedback_responses_anon_table
*
* @package mod_feedback
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class mod_feedback_responses_anon_table extends mod_feedback_responses_table {
/** @var string */
protected $showallparamname = 'ashowall';
/** @var string */
protected $downloadparamname = 'adownload';
/**
* Initialises table
* @param int $group retrieve only users from this group (optional)
*/
public function init($group = 0) {
$cm = $this->feedbackstructure->get_cm();
$this->uniqueid = 'feedback-showentry-anon-list-' . $cm->instance;
// There potentially can be both tables with anonymouns and non-anonymous responses on
// the same page (for example when feedback anonymity was changed after some people
// already responded). In this case we need to distinguish tables' pagination parameters.
$this->request[TABLE_VAR_PAGE] = 'apage';
$tablecolumns = ['random_response'];
$tableheaders = [get_string('response_nr', 'feedback')];
if ($this->feedbackstructure->get_feedback()->course == SITEID && !$this->feedbackstructure->get_courseid()) {
$tablecolumns[] = 'courseid';
$tableheaders[] = get_string('course');
}
$this->define_columns($tablecolumns);
$this->define_headers($tableheaders);
$this->sortable(true, 'random_response');
$this->collapsible(true);
$this->set_attribute('id', 'showentryanontable');
$params = ['instance' => $cm->instance,
'anon' => FEEDBACK_ANONYMOUS_YES,
'courseid' => $this->feedbackstructure->get_courseid()];
$fields = 'c.id, c.random_response, c.courseid';
$from = '{feedback_completed} c';
$where = 'c.anonymous_response = :anon AND c.feedback = :instance';
if ($this->feedbackstructure->get_courseid()) {
$where .= ' AND c.courseid = :courseid';
}
$group = (empty($group)) ? groups_get_activity_group($this->feedbackstructure->get_cm(), true) : $group;
if ($group) {
$where .= ' AND c.userid IN (SELECT g.userid FROM {groups_members} g WHERE g.groupid = :group)';
$params['group'] = $group;
}
$this->set_sql($fields, $from, $where, $params);
$this->set_count_sql("SELECT COUNT(c.id) FROM $from WHERE $where", $params);
}
/**
* Returns a link for viewing a single response
* @param stdClass $row
* @return \moodle_url
*/
protected function get_link_single_entry($row) {
return new moodle_url($this->baseurl, ['showcompleted' => $row->id]);
}
/**
* Prepares column reponse for display
* @param stdClass $row
* @return string
*/
public function col_random_response($row) {
if ($this->is_downloading()) {
return $row->random_response;
} else {
return html_writer::link($this->get_link_single_entry($row),
get_string('response_nr', 'feedback').': '. $row->random_response);
}
}
/**
* Add data for the external structure that will be returned.
*
* @param stdClass $row a database query record row
* @since Moodle 3.3
*/
protected function add_data_for_external($row) {
$this->dataforexternal[] = [
'id' => $row->id,
'courseid' => $row->courseid,
'number' => $row->random_response,
'responses' => $this->get_responses_for_external($row)
];
}
}
+675
View File
@@ -0,0 +1,675 @@
<?php
// 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/>.
/**
* Contains class mod_feedback_responses_table
*
* @package mod_feedback
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->libdir . '/tablelib.php');
/**
* Class mod_feedback_responses_table
*
* @package mod_feedback
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class mod_feedback_responses_table extends table_sql {
/**
* Maximum number of feedback questions to display in the "Show responses" table
*/
const PREVIEWCOLUMNSLIMIT = 10;
/**
* Maximum number of feedback questions answers to retrieve in one SQL query.
* Mysql has a limit of 60, we leave 1 for joining with users table.
*/
const TABLEJOINLIMIT = 59;
/**
* When additional queries are needed to retrieve more than TABLEJOINLIMIT questions answers, do it in chunks every x rows.
* Value too small will mean too many DB queries, value too big may cause memory overflow.
*/
const ROWCHUNKSIZE = 100;
/** @var mod_feedback_structure */
protected $feedbackstructure;
/** @var int */
protected $grandtotal = null;
/** @var bool */
protected $showall = false;
/** @var string */
protected $showallparamname = 'showall';
/** @var string */
protected $downloadparamname = 'download';
/** @var int number of columns that were not retrieved in the main SQL query
* (no more than TABLEJOINLIMIT tables with values can be joined). */
protected $hasmorecolumns = 0;
/** @var bool whether we are building this table for a external function */
protected $buildforexternal = false;
/** @var array the data structure containing the table data for the external function */
protected $dataforexternal = [];
/** @var bool true if elements per page > 0, otherwise false. */
protected $pageable;
/**
* Constructor
*
* @param mod_feedback_structure $feedbackstructure
* @param int $group retrieve only users from this group (optional)
*/
public function __construct(mod_feedback_structure $feedbackstructure, $group = 0) {
$this->feedbackstructure = $feedbackstructure;
parent::__construct('feedback-showentry-list-' . $feedbackstructure->get_cm()->instance);
$this->showall = optional_param($this->showallparamname, 0, PARAM_BOOL);
$this->define_baseurl(new moodle_url('/mod/feedback/show_entries.php',
['id' => $this->feedbackstructure->get_cm()->id]));
if ($courseid = $this->feedbackstructure->get_courseid()) {
$this->baseurl->param('courseid', $courseid);
}
if ($this->showall) {
$this->baseurl->param($this->showallparamname, $this->showall);
}
$name = format_string($feedbackstructure->get_feedback()->name);
$this->is_downloadable(true);
$this->is_downloading(optional_param($this->downloadparamname, 0, PARAM_ALPHA),
$name, get_string('responses', 'feedback'));
$this->useridfield = 'userid';
$this->init($group);
}
/**
* Initialises table
* @param int $group retrieve only users from this group (optional)
*/
protected function init($group = 0) {
$tablecolumns = array('userpic', 'fullname', 'groups');
$tableheaders = array(
get_string('userpic'),
get_string('fullnameuser'),
get_string('groups')
);
// TODO Does not support custom user profile fields (MDL-70456).
$userfieldsapi = \core_user\fields::for_identity($this->get_context(), false)->with_userpic();
$ufields = $userfieldsapi->get_sql('u', false, '', $this->useridfield, false)->selects;
$extrafields = $userfieldsapi->get_required_fields([\core_user\fields::PURPOSE_IDENTITY]);
$fields = 'c.id, c.timemodified as completed_timemodified, c.courseid, '.$ufields;
$from = '{feedback_completed} c '
. 'JOIN {user} u ON u.id = c.userid AND u.deleted = :notdeleted';
$where = 'c.anonymous_response = :anon
AND c.feedback = :instance';
if ($this->feedbackstructure->get_courseid()) {
$where .= ' AND c.courseid = :courseid';
}
if ($this->is_downloading()) {
// When downloading data:
// Remove 'userpic' from downloaded data.
array_shift($tablecolumns);
array_shift($tableheaders);
// Add all identity fields as separate columns.
foreach ($extrafields as $field) {
$fields .= ", u.{$field}";
$tablecolumns[] = $field;
$tableheaders[] = \core_user\fields::get_display_name($field);
}
}
if ($this->feedbackstructure->get_feedback()->course == SITEID && !$this->feedbackstructure->get_courseid()) {
$tablecolumns[] = 'courseid';
$tableheaders[] = get_string('course');
}
$tablecolumns[] = 'completed_timemodified';
$tableheaders[] = get_string('date');
$this->define_columns($tablecolumns);
$this->define_headers($tableheaders);
$this->sortable(true, 'lastname', SORT_ASC);
$this->no_sorting('groups');
$this->collapsible(true);
$this->set_attribute('id', 'showentrytable');
$params = array();
$params['anon'] = FEEDBACK_ANONYMOUS_NO;
$params['instance'] = $this->feedbackstructure->get_feedback()->id;
$params['notdeleted'] = 0;
$params['courseid'] = $this->feedbackstructure->get_courseid();
$group = (empty($group)) ? groups_get_activity_group($this->feedbackstructure->get_cm(), true) : $group;
if ($group) {
$where .= ' AND c.userid IN (SELECT g.userid FROM {groups_members} g WHERE g.groupid = :group)';
$params['group'] = $group;
}
$this->set_sql($fields, $from, $where, $params);
$this->set_count_sql("SELECT COUNT(c.id) FROM $from WHERE $where", $params);
}
/**
* Current context
* @return context_module
*/
public function get_context(): context {
return context_module::instance($this->feedbackstructure->get_cm()->id);
}
/**
* Allows to set the display column value for all columns without "col_xxxxx" method.
* @param string $column column name
* @param stdClass $row current record result of SQL query
*/
public function other_cols($column, $row) {
if (preg_match('/^val(\d+)$/', $column, $matches)) {
$items = $this->feedbackstructure->get_items();
$itemobj = feedback_get_item_class($items[$matches[1]]->typ);
$printval = $itemobj->get_printval($items[$matches[1]], (object) ['value' => $row->$column]);
if ($this->is_downloading()) {
$printval = s($printval);
}
return trim($printval);
}
return parent::other_cols($column, $row);
}
/**
* Prepares column userpic for display
* @param stdClass $row
* @return string
*/
public function col_userpic($row) {
global $OUTPUT;
$user = user_picture::unalias($row, [], $this->useridfield);
return $OUTPUT->user_picture($user, array('courseid' => $this->feedbackstructure->get_cm()->course));
}
/**
* Prepares column deleteentry for display
* @param stdClass $row
* @return string
*/
public function col_deleteentry($row) {
global $OUTPUT;
$deleteentryurl = new moodle_url($this->baseurl, ['delete' => $row->id, 'sesskey' => sesskey()]);
$deleteaction = new confirm_action(get_string('confirmdeleteentry', 'feedback'));
return $OUTPUT->action_icon($deleteentryurl,
new pix_icon('t/delete', get_string('delete_entry', 'feedback')), $deleteaction);
}
/**
* Returns a link for viewing a single response
* @param stdClass $row
* @return \moodle_url
*/
protected function get_link_single_entry($row) {
return new moodle_url($this->baseurl, ['userid' => $row->{$this->useridfield}, 'showcompleted' => $row->id]);
}
/**
* Prepares column completed_timemodified for display
* @param stdClass $student
* @return string
*/
public function col_completed_timemodified($student) {
if ($this->is_downloading()) {
return userdate($student->completed_timemodified);
} else {
return html_writer::link($this->get_link_single_entry($student),
userdate($student->completed_timemodified));
}
}
/**
* Prepares column courseid for display
* @param array $row
* @return string
*/
public function col_courseid($row) {
$courses = $this->feedbackstructure->get_completed_courses();
$name = '';
if (isset($courses[$row->courseid])) {
$name = $courses[$row->courseid];
if (!$this->is_downloading()) {
$name = html_writer::link(course_get_url($row->courseid), $name);
}
}
return $name;
}
/**
* Prepares column groups for display
* @param array $row
* @return string
*/
public function col_groups($row) {
$groups = '';
if ($usergrps = groups_get_all_groups($this->feedbackstructure->get_cm()->course, $row->userid, 0, 'name')) {
foreach ($usergrps as $group) {
$groups .= format_string($group->name). ' ';
}
}
return trim($groups);
}
/**
* Adds common values to the table that do not change the number or order of entries and
* are only needed when outputting or downloading data.
*/
protected function add_all_values_to_output() {
global $DB;
$tablecolumns = array_keys($this->columns);
$tableheaders = $this->headers;
$items = $this->feedbackstructure->get_items(true);
if (!$this->is_downloading() && !$this->buildforexternal) {
// In preview mode do not show all columns or the page becomes unreadable.
// The information message will be displayed to the teacher that the rest of the data can be viewed when downloading.
$items = array_slice($items, 0, self::PREVIEWCOLUMNSLIMIT, true);
}
$columnscount = 0;
$this->hasmorecolumns = max(0, count($items) - self::TABLEJOINLIMIT);
$headernamepostfix = !$this->is_downloading();
// Add feedback response values.
foreach ($items as $nr => $item) {
if ($columnscount++ < self::TABLEJOINLIMIT) {
// Mysql has a limit on the number of tables in the join, so we only add limited number of columns here,
// the rest will be added in {@link self::build_table()} and {@link self::build_table_chunk()} functions.
$this->sql->fields .= ", " . $DB->sql_cast_to_char("v{$nr}.value") . " AS val{$nr}";
$this->sql->from .= " LEFT OUTER JOIN {feedback_value} v{$nr} " .
"ON v{$nr}.completed = c.id AND v{$nr}.item = :itemid{$nr}";
$this->sql->params["itemid{$nr}"] = $item->id;
}
$tablecolumns[] = "val{$nr}";
$itemobj = feedback_get_item_class($item->typ);
$columnheader = $itemobj->get_display_name($item, $headernamepostfix);
if (!$this->is_downloading()) {
$columnheader = shorten_text($columnheader);
}
if (strval($item->label) !== '') {
$columnheader = get_string('nameandlabelformat', 'mod_feedback',
(object)['label' => format_string($item->label), 'name' => $columnheader]);
}
$tableheaders[] = $columnheader;
}
// Add 'Delete entry' column.
if (!$this->is_downloading() && has_capability('mod/feedback:deletesubmissions', $this->get_context())) {
$tablecolumns[] = 'deleteentry';
$tableheaders[] = '';
}
$this->define_columns($tablecolumns);
$this->define_headers($tableheaders);
}
/**
* Query the db. Store results in the table object for use by build_table.
*
* @param int $pagesize size of page for paginated displayed table.
* @param bool $useinitialsbar do you want to use the initials bar. Bar
* will only be used if there is a fullname column defined for the table.
*/
public function query_db($pagesize, $useinitialsbar=true) {
global $DB;
$this->totalrows = $grandtotal = $this->get_total_responses_count();
if (!$this->is_downloading()) {
$this->initialbars($useinitialsbar);
list($wsql, $wparams) = $this->get_sql_where();
if ($wsql) {
$this->countsql .= ' AND '.$wsql;
$this->countparams = array_merge($this->countparams, $wparams);
$this->sql->where .= ' AND '.$wsql;
$this->sql->params = array_merge($this->sql->params, $wparams);
$this->totalrows = $DB->count_records_sql($this->countsql, $this->countparams);
}
if ($this->totalrows > $pagesize) {
$this->pagesize($pagesize, $this->totalrows);
}
}
if ($sort = $this->get_sql_sort()) {
$sort = "ORDER BY $sort";
}
$sql = "SELECT
{$this->sql->fields}
FROM {$this->sql->from}
WHERE {$this->sql->where}
{$sort}";
if (!$this->is_downloading()) {
$this->rawdata = $DB->get_recordset_sql($sql, $this->sql->params, $this->get_page_start(), $this->get_page_size());
} else {
$this->rawdata = $DB->get_recordset_sql($sql, $this->sql->params);
}
}
/**
* Returns total number of reponses (without any filters applied)
* @return int
*/
public function get_total_responses_count() {
global $DB;
if ($this->grandtotal === null) {
$this->grandtotal = $DB->count_records_sql($this->countsql, $this->countparams);
}
return $this->grandtotal;
}
/**
* Defines columns
* @param array $columns an array of identifying names for columns. If
* columns are sorted then column names must correspond to a field in sql.
*/
public function define_columns($columns) {
parent::define_columns($columns);
foreach ($this->columns as $column => $column) {
// Automatically assign classes to columns.
$this->column_class[$column] = ' ' . $column;
}
}
/**
* Convenience method to call a number of methods for you to display the
* table.
* @param int $pagesize
* @param bool $useinitialsbar
* @param string $downloadhelpbutton
*/
public function out($pagesize, $useinitialsbar, $downloadhelpbutton='') {
$this->add_all_values_to_output();
parent::out($pagesize, $useinitialsbar, $downloadhelpbutton);
}
/**
* Displays the table
*/
public function display() {
global $OUTPUT;
groups_print_activity_menu($this->feedbackstructure->get_cm(), $this->baseurl->out());
$grandtotal = $this->get_total_responses_count();
if (!$grandtotal) {
echo $OUTPUT->notification(get_string('nothingtodisplay'), 'info', false);
return;
}
if (count($this->feedbackstructure->get_items(true)) > self::PREVIEWCOLUMNSLIMIT) {
echo $OUTPUT->notification(get_string('questionslimited', 'feedback', self::PREVIEWCOLUMNSLIMIT), 'info');
}
$this->out($this->showall ? $grandtotal : FEEDBACK_DEFAULT_PAGE_COUNT,
$grandtotal > FEEDBACK_DEFAULT_PAGE_COUNT);
// Toggle 'Show all' link.
if ($this->totalrows > FEEDBACK_DEFAULT_PAGE_COUNT) {
if (!$this->use_pages) {
echo html_writer::div(html_writer::link(new moodle_url($this->baseurl, [$this->showallparamname => 0]),
get_string('showperpage', '', FEEDBACK_DEFAULT_PAGE_COUNT)), 'showall');
} else {
echo html_writer::div(html_writer::link(new moodle_url($this->baseurl, [$this->showallparamname => 1]),
get_string('showall', '', $this->totalrows)), 'showall');
}
}
}
/**
* Returns links to previous/next responses in the list
* @param stdClass $record
* @return array array of three elements [$prevresponseurl, $returnurl, $nextresponseurl]
*/
public function get_reponse_navigation_links($record) {
$this->setup();
$grandtotal = $this->get_total_responses_count();
$this->query_db($grandtotal);
$lastrow = $thisrow = $nextrow = null;
$counter = 0;
$page = 0;
while ($this->rawdata->valid()) {
$row = $this->rawdata->current();
if ($row->id == $record->id) {
$page = $this->showall ? 0 : floor($counter / FEEDBACK_DEFAULT_PAGE_COUNT);
$thisrow = $row;
$this->rawdata->next();
$nextrow = $this->rawdata->valid() ? $this->rawdata->current() : null;
break;
}
$lastrow = $row;
$this->rawdata->next();
$counter++;
}
$this->rawdata->close();
if (!$thisrow) {
$lastrow = null;
}
return [
$lastrow ? $this->get_link_single_entry($lastrow) : null,
new moodle_url($this->baseurl, [$this->request[TABLE_VAR_PAGE] => $page]),
$nextrow ? $this->get_link_single_entry($nextrow) : null,
];
}
/**
* Download the data.
*/
public function download() {
\core\session\manager::write_close();
$this->out($this->get_total_responses_count(), false);
exit;
}
/**
* Take the data returned from the db_query and go through all the rows
* processing each col using either col_{columnname} method or other_cols
* method or if other_cols returns NULL then put the data straight into the
* table.
*
* This overwrites the parent method because full SQL query may fail on Mysql
* because of the limit in the number of tables in the join. Therefore we only
* join 59 tables in the main query and add the rest here.
*
* @return void
*/
public function build_table() {
if ($this->rawdata instanceof \Traversable && !$this->rawdata->valid()) {
return;
}
if (!$this->rawdata) {
return;
}
$columnsgroups = [];
if ($this->hasmorecolumns) {
$items = $this->feedbackstructure->get_items(true);
$notretrieveditems = array_slice($items, self::TABLEJOINLIMIT, $this->hasmorecolumns, true);
$columnsgroups = array_chunk($notretrieveditems, self::TABLEJOINLIMIT, true);
}
$chunk = [];
foreach ($this->rawdata as $row) {
if ($this->hasmorecolumns) {
$chunk[$row->id] = $row;
if (count($chunk) >= self::ROWCHUNKSIZE) {
$this->build_table_chunk($chunk, $columnsgroups);
$chunk = [];
}
} else {
if ($this->buildforexternal) {
$this->add_data_for_external($row);
} else {
$this->add_data_keyed($this->format_row($row), $this->get_row_class($row));
}
}
}
$this->build_table_chunk($chunk, $columnsgroups);
}
/**
* Retrieve additional columns. Database engine may have a limit on number of joins.
*
* @param array $rows Array of rows with already retrieved data, new values will be added to this array
* @param array $columnsgroups array of arrays of columns. Each element has up to self::TABLEJOINLIMIT items. This
* is easy to calculate but because we can call this method many times we calculate it once and pass by
* reference for performance reasons
*/
protected function build_table_chunk(&$rows, &$columnsgroups) {
global $DB;
if (!$rows) {
return;
}
foreach ($columnsgroups as $columnsgroup) {
$fields = 'c.id';
$from = '{feedback_completed} c';
$params = [];
foreach ($columnsgroup as $nr => $item) {
$fields .= ", " . $DB->sql_cast_to_char("v{$nr}.value") . " AS val{$nr}";
$from .= " LEFT OUTER JOIN {feedback_value} v{$nr} " .
"ON v{$nr}.completed = c.id AND v{$nr}.item = :itemid{$nr}";
$params["itemid{$nr}"] = $item->id;
}
list($idsql, $idparams) = $DB->get_in_or_equal(array_keys($rows), SQL_PARAMS_NAMED);
$sql = "SELECT $fields FROM $from WHERE c.id ".$idsql;
$results = $DB->get_records_sql($sql, $params + $idparams);
foreach ($results as $result) {
foreach ($result as $key => $value) {
$rows[$result->id]->{$key} = $value;
}
}
}
foreach ($rows as $row) {
if ($this->buildforexternal) {
$this->add_data_for_external($row);
} else {
$this->add_data_keyed($this->format_row($row), $this->get_row_class($row));
}
}
}
/**
* Returns html code for displaying "Download" button if applicable.
*/
public function download_buttons() {
global $OUTPUT;
if ($this->is_downloadable() && !$this->is_downloading()) {
return $OUTPUT->download_dataformat_selector(get_string('downloadas', 'table'),
$this->baseurl->out_omit_querystring(), $this->downloadparamname, $this->baseurl->params());
} else {
return '';
}
}
/**
* Return user responses data ready for the external function.
*
* @param stdClass $row the table row containing the responses
* @return array returns the responses ready to be used by an external function
* @since Moodle 3.3
*/
protected function get_responses_for_external($row) {
$responses = [];
foreach ($row as $el => $val) {
// Get id from column name.
if (preg_match('/^val(\d+)$/', $el, $matches)) {
$id = $matches[1];
$responses[] = [
'id' => $id,
'name' => $this->headers[$this->columns[$el]],
'printval' => $this->other_cols($el, $row),
'rawval' => $val,
];
}
}
return $responses;
}
/**
* Add data for the external structure that will be returned.
*
* @param stdClass $row a database query record row
* @since Moodle 3.3
*/
protected function add_data_for_external($row) {
$this->dataforexternal[] = [
'id' => $row->id,
'courseid' => $row->courseid,
'userid' => $row->userid,
'fullname' => fullname($row),
'timemodified' => $row->completed_timemodified,
'responses' => $this->get_responses_for_external($row),
];
}
/**
* Exports the table as an external structure handling pagination.
*
* @param int $page page number (for pagination)
* @param int $perpage elements per page
* @since Moodle 3.3
* @return array returns the table ready to be used by an external function
*/
public function export_external_structure($page = 0, $perpage = 0) {
$this->buildforexternal = true;
$this->add_all_values_to_output();
// Set-up.
$this->setup();
// Override values, if needed.
if ($perpage > 0) {
$this->pageable = true;
$this->currpage = $page;
$this->pagesize = $perpage;
} else {
$this->pagesize = $this->get_total_responses_count();
}
$this->query_db($this->pagesize, false);
$this->build_table();
$this->close_recordset();
return $this->dataforexternal;
}
}
+46
View File
@@ -0,0 +1,46 @@
<?php
// 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/>.
/**
* Search area for mod_feedback activities.
*
* @package mod_feedback
* @copyright 2015 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_feedback\search;
defined('MOODLE_INTERNAL') || die();
/**
* Search area for mod_feedback activities.
*
* @package mod_feedback
* @copyright 2015 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class activity extends \core_search\base_activity {
/**
* Returns true if this area uses file indexing.
*
* @return bool
*/
public function uses_file_indexing() {
return true;
}
}
+367
View File
@@ -0,0 +1,367 @@
<?php
// 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/>.
/**
* Contains class mod_feedback_structure
*
* @package mod_feedback
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Stores and manipulates the structure of the feedback or template (items, pages, etc.)
*
* @package mod_feedback
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class mod_feedback_structure {
/** @var stdClass record from 'feedback' table.
* Reliably has fields: id, course, timeopen, timeclose, anonymous, completionsubmit.
* For full object or to access any other field use $this->get_feedback()
*/
protected $feedback;
/** @var cm_info */
protected $cm;
/** @var int course where the feedback is filled. For feedbacks that are NOT on the front page this is 0 */
protected $courseid = 0;
/** @var int */
protected $templateid;
/** @var array */
protected $allitems;
/** @var array */
protected $allcourses;
/** @var int */
protected $userid;
/**
* Constructor
*
* @param stdClass $feedback feedback object, in case of the template
* this is the current feedback the template is accessed from
* @param stdClass|cm_info $cm course module object corresponding to the $feedback
* (at least one of $feedback or $cm is required)
* @param int $courseid current course (for site feedbacks only)
* @param int $templateid template id if this class represents the template structure
* @param int $userid User id to use for all capability checks, etc. Set to 0 for current user (default).
*/
public function __construct($feedback, $cm, $courseid = 0, $templateid = null, $userid = 0) {
global $USER;
if ((empty($feedback->id) || empty($feedback->course)) && (empty($cm->instance) || empty($cm->course))) {
throw new coding_exception('Either $feedback or $cm must be passed to constructor');
}
$this->feedback = $feedback ?: (object)['id' => $cm->instance, 'course' => $cm->course];
$this->cm = ($cm && $cm instanceof cm_info) ? $cm :
get_fast_modinfo($this->feedback->course)->instances['feedback'][$this->feedback->id];
$this->templateid = $templateid;
$this->courseid = ($this->feedback->course == SITEID) ? $courseid : 0;
if (empty($userid)) {
$this->userid = $USER->id;
} else {
$this->userid = $userid;
}
if (!$feedback) {
// If feedback object was not specified, populate object with fields required for the most of methods.
// These fields were added to course module cache in feedback_get_coursemodule_info().
// Full instance record can be retrieved by calling mod_feedback_structure::get_feedback().
$customdata = ($this->cm->customdata ?: []) + ['timeopen' => 0, 'timeclose' => 0, 'anonymous' => 0];
$this->feedback->timeopen = $customdata['timeopen'];
$this->feedback->timeclose = $customdata['timeclose'];
$this->feedback->anonymous = $customdata['anonymous'];
$this->feedback->completionsubmit = empty($this->cm->customdata['customcompletionrules']['completionsubmit']) ? 0 : 1;
}
}
/**
* Current feedback
* @return stdClass
*/
public function get_feedback() {
global $DB;
if (!isset($this->feedback->publish_stats) || !isset($this->feedback->name)) {
// Make sure the full object is retrieved.
$this->feedback = $DB->get_record('feedback', ['id' => $this->feedback->id], '*', MUST_EXIST);
}
return $this->feedback;
}
/**
* Current course module
* @return stdClass
*/
public function get_cm() {
return $this->cm;
}
/**
* Id of the current course (for site feedbacks only)
* @return stdClass
*/
public function get_courseid() {
return $this->courseid;
}
/**
* Template id
* @return int
*/
public function get_templateid() {
return $this->templateid;
}
/**
* Is this feedback open (check timeopen and timeclose)
* @return bool
*/
public function is_open() {
$checktime = time();
return (!$this->feedback->timeopen || $this->feedback->timeopen <= $checktime) &&
(!$this->feedback->timeclose || $this->feedback->timeclose >= $checktime);
}
/**
* Get all items in this feedback or this template
* @param bool $hasvalueonly only count items with a value.
* @return array of objects from feedback_item with an additional attribute 'itemnr'
*/
public function get_items($hasvalueonly = false) {
global $DB;
if ($this->allitems === null) {
if ($this->templateid) {
$this->allitems = $DB->get_records('feedback_item', ['template' => $this->templateid], 'position');
} else {
$this->allitems = $DB->get_records('feedback_item', ['feedback' => $this->feedback->id], 'position');
}
$idx = 1;
foreach ($this->allitems as $id => $item) {
$this->allitems[$id]->itemnr = $item->hasvalue ? ($idx++) : null;
}
}
if ($hasvalueonly && $this->allitems) {
return array_filter($this->allitems, function($item) {
return $item->hasvalue;
});
}
return $this->allitems;
}
/**
* Is the items list empty?
* @return bool
*/
public function is_empty() {
$items = $this->get_items();
$displayeditems = array_filter($items, function($item) {
return $item->typ !== 'pagebreak';
});
return !$displayeditems;
}
/**
* Is this feedback anonymous?
* @return bool
*/
public function is_anonymous() {
return $this->feedback->anonymous == FEEDBACK_ANONYMOUS_YES;
}
/**
* Returns the formatted text of the page after submit or null if it is not set
*
* @return string|null
*/
public function page_after_submit() {
global $CFG;
require_once($CFG->libdir . '/filelib.php');
$pageaftersubmit = $this->get_feedback()->page_after_submit;
if (empty($pageaftersubmit)) {
return null;
}
$pageaftersubmitformat = $this->get_feedback()->page_after_submitformat;
$context = context_module::instance($this->get_cm()->id);
$output = file_rewrite_pluginfile_urls($pageaftersubmit,
'pluginfile.php', $context->id, 'mod_feedback', 'page_after_submit', 0);
return format_text($output, $pageaftersubmitformat, array('overflowdiv' => true));
}
/**
* Checks if current user is able to view feedback on this course.
*
* @return bool
*/
public function can_view_analysis() {
global $USER;
$context = context_module::instance($this->cm->id);
if (has_capability('mod/feedback:viewreports', $context, $this->userid)) {
return true;
}
if (intval($this->get_feedback()->publish_stats) != 1 ||
!has_capability('mod/feedback:viewanalysepage', $context, $this->userid)) {
return false;
}
if ((!isloggedin() && $USER->id == $this->userid) || isguestuser($this->userid)) {
// There is no tracking for the guests, assume that they can view analysis if condition above is satisfied.
return $this->feedback->course == SITEID;
}
return $this->is_already_submitted(true);
}
/**
* check for multiple_submit = false.
* if the feedback is global so the courseid must be given
*
* @param bool $anycourseid if true checks if this feedback was submitted in any course, otherwise checks $this->courseid .
* Applicable to frontpage feedbacks only
* @return bool true if the feedback already is submitted otherwise false
*/
public function is_already_submitted($anycourseid = false) {
global $DB, $USER;
if ((!isloggedin() && $USER->id == $this->userid) || isguestuser($this->userid)) {
return false;
}
$params = array('userid' => $this->userid, 'feedback' => $this->feedback->id);
if (!$anycourseid && $this->courseid) {
$params['courseid'] = $this->courseid;
}
return $DB->record_exists('feedback_completed', $params);
}
/**
* Check whether the feedback is mapped to the given courseid.
*/
public function check_course_is_mapped() {
global $DB;
if ($this->feedback->course != SITEID) {
return true;
}
if ($DB->get_records('feedback_sitecourse_map', array('feedbackid' => $this->feedback->id))) {
$params = array('feedbackid' => $this->feedback->id, 'courseid' => $this->courseid);
if (!$DB->get_record('feedback_sitecourse_map', $params)) {
return false;
}
}
// No mapping means any course is mapped.
return true;
}
/**
* If there are any new responses to the anonymous feedback, re-shuffle all
* responses and assign response number to each of them.
*/
public function shuffle_anonym_responses() {
global $DB;
$params = array('feedback' => $this->feedback->id,
'random_response' => 0,
'anonymous_response' => FEEDBACK_ANONYMOUS_YES);
if ($DB->count_records('feedback_completed', $params, 'random_response')) {
// Get all of the anonymous records, go through them and assign a response id.
unset($params['random_response']);
$feedbackcompleteds = $DB->get_records('feedback_completed', $params, 'id');
shuffle($feedbackcompleteds);
$num = 1;
foreach ($feedbackcompleteds as $compl) {
$compl->random_response = $num++;
$DB->update_record('feedback_completed', $compl);
}
}
}
/**
* Counts records from {feedback_completed} table for a given feedback
*
* If $groupid or $this->courseid is set, the records are filtered by the group/course
*
* @param int $groupid
* @return mixed array of found completeds otherwise false
*/
public function count_completed_responses($groupid = 0) {
global $DB;
if (intval($groupid) > 0) {
$query = "SELECT COUNT(DISTINCT fbc.id)
FROM {feedback_completed} fbc, {groups_members} gm
WHERE fbc.feedback = :feedback
AND gm.groupid = :groupid
AND fbc.userid = gm.userid";
} else if ($this->courseid) {
$query = "SELECT COUNT(fbc.id)
FROM {feedback_completed} fbc
WHERE fbc.feedback = :feedback
AND fbc.courseid = :courseid";
} else {
$query = "SELECT COUNT(fbc.id) FROM {feedback_completed} fbc WHERE fbc.feedback = :feedback";
}
$params = ['feedback' => $this->feedback->id, 'groupid' => $groupid, 'courseid' => $this->courseid];
return $DB->get_field_sql($query, $params);
}
/**
* For the frontpage feedback returns the list of courses with at least one completed feedback
*
* @return array id=>name pairs of courses
*/
public function get_completed_courses() {
global $DB;
if ($this->get_feedback()->course != SITEID) {
return [];
}
if ($this->allcourses !== null) {
return $this->allcourses;
}
$courseselect = "SELECT fbc.courseid
FROM {feedback_completed} fbc
WHERE fbc.feedback = :feedbackid";
$ctxselect = context_helper::get_preload_record_columns_sql('ctx');
$sql = 'SELECT c.id, c.shortname, c.fullname, c.idnumber, c.visible, '. $ctxselect. '
FROM {course} c
JOIN {context} ctx ON c.id = ctx.instanceid AND ctx.contextlevel = :contextcourse
WHERE c.id IN ('. $courseselect.') ORDER BY c.sortorder';
$list = $DB->get_records_sql($sql, ['contextcourse' => CONTEXT_COURSE, 'feedbackid' => $this->get_feedback()->id]);
$this->allcourses = array();
foreach ($list as $course) {
context_helper::preload_from_record($course);
if (!$course->visible &&
!has_capability('moodle/course:viewhiddencourses', context_course::instance($course->id), $this->userid)) {
// Do not return courses that current user can not see.
continue;
}
$label = get_course_display_name_for_list($course);
$this->allcourses[$course->id] = $label;
}
return $this->allcourses;
}
}
+108
View File
@@ -0,0 +1,108 @@
<?php
// 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/>.
/**
* Contains class mod_feedback_templates_table
*
* @package mod_feedback
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->libdir . '/tablelib.php');
/**
* Class mod_feedback_templates_table
*
* @package mod_feedback
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class mod_feedback_templates_table extends flexible_table {
/** @var string|null Indicate whether we are managing template or not. */
private $mode;
/**
* Constructor
* @param int $uniqueid all tables have to have a unique id, this is used
* as a key when storing table properties like sort order in the session.
* @param moodle_url $baseurl
* @param string $mode Indicate whether we are managing templates
*/
public function __construct($uniqueid, $baseurl, ?string $mode = null) {
parent::__construct($uniqueid);
$this->mode = $mode;
$tablecolumns = array('template');
if ($this->mode) {
$tablecolumns[] = 'actions';
}
$tableheaders = array(get_string('template', 'feedback'), '');
$this->set_attribute('class', 'templateslist');
$this->define_columns($tablecolumns);
$this->define_headers($tableheaders);
$this->define_baseurl($baseurl);
$this->column_class('template', 'template');
$this->column_class('actions', 'text-right');
$this->sortable(false);
}
/**
* Displays the table with the given set of templates
* @param array $templates
*/
public function display($templates) {
global $OUTPUT;
if (empty($templates)) {
echo $OUTPUT->box(get_string('no_templates_available_yet', 'feedback'),
'generalbox boxaligncenter');
return;
}
$this->setup();
$strdeletefeedback = get_string('delete_template', 'feedback');
foreach ($templates as $template) {
$data = [];
$url = new moodle_url($this->baseurl, array('templateid' => $template->id, 'sesskey' => sesskey()));
$data[] = $OUTPUT->action_link($url, format_string($template->name));
// Only show the actions if we are managing templates.
if ($this->mode && has_capability('mod/feedback:deletetemplate', $this->get_context())) {
$deleteurl = new moodle_url('/mod/feedback/manage_templates.php',
$url->params() + ['deletetemplate' => $template->id]);
$deleteaction = new confirm_action(get_string('confirmdeletetemplate', 'feedback'));
$deleteicon = $OUTPUT->action_icon($deleteurl, new pix_icon('t/delete', $strdeletefeedback), $deleteaction);
if ($template->ispublic) {
$systemcontext = context_system::instance();
if (!(has_capability('mod/feedback:createpublictemplate', $systemcontext) &&
has_capability('mod/feedback:deletetemplate', $systemcontext))) {
$deleteicon = false;
}
}
$data[] = $deleteicon;
}
$this->add_data($data);
}
$this->finish_output();
}
}
+142
View File
@@ -0,0 +1,142 @@
<?php
// 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/>.
/**
* prints the form so the user can fill out the feedback
*
* @author Andreas Grabs
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package mod_feedback
*/
require_once("../../config.php");
require_once("lib.php");
feedback_init_feedback_session();
$id = required_param('id', PARAM_INT);
$courseid = optional_param('courseid', null, PARAM_INT);
$gopage = optional_param('gopage', 0, PARAM_INT);
$gopreviouspage = optional_param('gopreviouspage', null, PARAM_RAW);
list($course, $cm) = get_course_and_cm_from_cmid($id, 'feedback');
$feedback = $DB->get_record("feedback", array("id" => $cm->instance), '*', MUST_EXIST);
$urlparams = array('id' => $cm->id, 'gopage' => $gopage, 'courseid' => $courseid);
$PAGE->set_url('/mod/feedback/complete.php', $urlparams);
require_course_login($course, true, $cm);
$PAGE->set_activity_record($feedback);
$context = context_module::instance($cm->id);
$feedbackcompletion = new mod_feedback_completion($feedback, $cm, $courseid);
$courseid = $feedbackcompletion->get_courseid();
// Check whether the feedback is mapped to the given courseid.
if (!has_capability('mod/feedback:edititems', $context) &&
!$feedbackcompletion->check_course_is_mapped()) {
echo $OUTPUT->header();
echo $OUTPUT->notification(get_string('cannotaccess', 'mod_feedback'));
echo $OUTPUT->footer();
exit;
}
//check whether the given courseid exists
if ($courseid AND $courseid != SITEID) {
require_course_login(get_course($courseid)); // This overwrites the object $COURSE .
}
if (!$feedbackcompletion->can_complete()) {
throw new \moodle_exception('error');
}
$PAGE->navbar->add(get_string('feedback:complete', 'feedback'));
$PAGE->set_heading($course->fullname);
$PAGE->set_title($feedback->name);
$PAGE->set_pagelayout('incourse');
$PAGE->set_secondary_active_tab('modulepage');
$PAGE->add_body_class('limitedwidth');
// Check if the feedback is open (timeopen, timeclose).
if (!$feedbackcompletion->is_open()) {
echo $OUTPUT->header();
echo $OUTPUT->box_start('generalbox boxaligncenter');
echo $OUTPUT->notification(get_string('feedback_is_not_open', 'feedback'));
echo $OUTPUT->continue_button(course_get_url($courseid ?: $feedback->course));
echo $OUTPUT->box_end();
echo $OUTPUT->footer();
exit;
}
// Mark activity viewed for completion-tracking.
if (isloggedin() && !isguestuser()) {
$feedbackcompletion->set_module_viewed();
}
// Check if user is prevented from re-submission.
$cansubmit = $feedbackcompletion->can_submit();
// Initialise the form processing feedback completion.
if (!$feedbackcompletion->is_empty() && $cansubmit) {
// Process the page via the form.
$urltogo = $feedbackcompletion->process_page($gopage, $gopreviouspage);
if ($urltogo !== null) {
redirect($urltogo);
}
}
// Print the page header.
$strfeedbacks = get_string("modulenameplural", "feedback");
$strfeedback = get_string("modulename", "feedback");
echo $OUTPUT->header();
if ($feedbackcompletion->is_empty()) {
\core\notification::error(get_string('no_items_available_yet', 'feedback'));
} else if ($cansubmit) {
if ($feedbackcompletion->just_completed()) {
// Display information after the submit.
if ($feedback->page_after_submit) {
echo $OUTPUT->box($feedbackcompletion->page_after_submit(),
'generalbox boxaligncenter');
}
if (!$PAGE->has_secondary_navigation() && $feedbackcompletion->can_view_analysis()) {
echo '<p class="text-center">';
$analysisurl = new moodle_url('/mod/feedback/analysis.php', array('id' => $cm->id, 'courseid' => $courseid));
echo html_writer::link($analysisurl, get_string('completed_feedbacks', 'feedback'));
echo '</p>';
}
if ($feedback->site_after_submit) {
$url = feedback_encode_target_url($feedback->site_after_submit);
} else {
$url = course_get_url($courseid ?: $course->id);
}
echo $OUTPUT->continue_button($url);
} else {
// Display the form with the questions.
echo $feedbackcompletion->render_items();
}
} else {
echo $OUTPUT->box_start('generalbox boxaligncenter');
echo $OUTPUT->notification(get_string('this_feedback_is_already_submitted', 'feedback'));
echo $OUTPUT->continue_button(course_get_url($courseid ?: $course->id));
echo $OUTPUT->box_end();
}
echo $OUTPUT->footer();
+32
View File
@@ -0,0 +1,32 @@
<?php
// 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/>.
/**
* prints the form so an anonymous user can fill out the feedback on the mainsite
*
* @author Andreas Grabs
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package mod_feedback
*/
require_once("../../config.php");
// This file is no longer used, however it will remain here to redirect existing links to complete.php.
$url = new moodle_url('/mod/feedback/complete.php');
foreach ($_GET as $key => $value) {
$url->param($key, $value);
}
redirect($url);
+172
View File
@@ -0,0 +1,172 @@
<?php
// 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/>.
/**
* Plugin capabilities
*
* @package mod_feedback
* @copyright Andreas Grabs
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$capabilities = array(
'mod/feedback:addinstance' => array(
'riskbitmask' => RISK_XSS,
'captype' => 'write',
'contextlevel' => CONTEXT_COURSE,
'archetypes' => array(
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
),
'clonepermissionsfrom' => 'moodle/course:manageactivities'
),
'mod/feedback:view' => array(
'captype' => 'read',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'guest' => CAP_ALLOW,
'frontpage' => CAP_ALLOW,
'student' => CAP_ALLOW,
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
)
),
'mod/feedback:complete' => array(
'riskbitmask' => RISK_SPAM,
'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'frontpage' => CAP_ALLOW,
'student' => CAP_ALLOW
)
),
'mod/feedback:viewanalysepage' => array(
'riskbitmask' => RISK_PERSONAL,
'captype' => 'read',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'student' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
)
),
'mod/feedback:deletesubmissions' => array(
'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
)
),
'mod/feedback:mapcourse' => array(
'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'manager' => CAP_ALLOW
)
),
'mod/feedback:edititems' => array(
'riskbitmask' => RISK_SPAM | RISK_XSS,
'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
)
),
'mod/feedback:createprivatetemplate' => array(
'riskbitmask' => RISK_SPAM,
'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
)
),
'mod/feedback:createpublictemplate' => array(
'riskbitmask' => RISK_SPAM,
'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
)
),
'mod/feedback:deletetemplate' => array(
'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
)
),
'mod/feedback:viewreports' => array(
'riskbitmask' => RISK_PERSONAL,
'captype' => 'read',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
)
),
'mod/feedback:receivemail' => array(
'riskbitmask' => RISK_PERSONAL,
'captype' => 'read',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW
)
),
);
+34
View File
@@ -0,0 +1,34 @@
<?php
// 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/>.
/**
* Feedback event handler definition.
*
* @package mod_feedback
* @category event
* @copyright 2016 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
// List of observers.
$observers = array(
array(
'eventname' => '\core\event\course_content_deleted',
'callback' => 'mod_feedback_observer::course_content_deleted',
),
);
+20
View File
@@ -0,0 +1,20 @@
<?php
// 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/>.
function xmldb_feedback_install() {
global $DB;
}
+159
View File
@@ -0,0 +1,159 @@
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="mod/feedback/db" VERSION="20220530" COMMENT="XMLDB file for Moodle mod/feedback"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
>
<TABLES>
<TABLE NAME="feedback" COMMENT="all feedbacks">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="course" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="intro" TYPE="text" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="introformat" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="anonymous" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="1" SEQUENCE="false"/>
<FIELD NAME="email_notification" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="1" SEQUENCE="false"/>
<FIELD NAME="multiple_submit" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="1" SEQUENCE="false"/>
<FIELD NAME="autonumbering" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="1" SEQUENCE="false"/>
<FIELD NAME="site_after_submit" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="page_after_submit" TYPE="text" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="page_after_submitformat" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="publish_stats" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="timeopen" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="timeclose" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="completionsubmit" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="If this field is set to 1, then the activity will be automatically marked as 'complete' once the user submits their choice."/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id" COMMENT="Primary key for feedback"/>
</KEYS>
<INDEXES>
<INDEX NAME="course" UNIQUE="false" FIELDS="course"/>
</INDEXES>
</TABLE>
<TABLE NAME="feedback_template" COMMENT="templates of feedbackstructures">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="course" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="ispublic" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id" COMMENT="Primary key for feedback_template"/>
</KEYS>
<INDEXES>
<INDEX NAME="course" UNIQUE="false" FIELDS="course"/>
</INDEXES>
</TABLE>
<TABLE NAME="feedback_item" COMMENT="feedback_items">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="feedback" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="template" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="label" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="presentation" TYPE="text" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="typ" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="hasvalue" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="position" TYPE="int" LENGTH="3" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="required" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="dependitem" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="dependvalue" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="options" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id" COMMENT="Primary key for feedback_item"/>
<KEY NAME="feedback" TYPE="foreign" FIELDS="feedback" REFTABLE="feedback" REFFIELDS="id"/>
<KEY NAME="template" TYPE="foreign" FIELDS="template" REFTABLE="feedback_template" REFFIELDS="id"/>
</KEYS>
</TABLE>
<TABLE NAME="feedback_completed" COMMENT="filled out feedback">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="feedback" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="random_response" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="anonymous_response" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id" COMMENT="Primary key for feedback_completed"/>
<KEY NAME="feedback" TYPE="foreign" FIELDS="feedback" REFTABLE="feedback" REFFIELDS="id"/>
<KEY NAME="courseid" TYPE="foreign" FIELDS="courseid" REFTABLE="course" REFFIELDS="id"/>
</KEYS>
<INDEXES>
<INDEX NAME="userid" UNIQUE="false" FIELDS="userid"/>
</INDEXES>
</TABLE>
<TABLE NAME="feedback_completedtmp" COMMENT="filled out feedback">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="feedback" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="guestid" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="random_response" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="anonymous_response" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id" COMMENT="Primary key for feedback_completedtmp"/>
<KEY NAME="feedback" TYPE="foreign" FIELDS="feedback" REFTABLE="feedback" REFFIELDS="id"/>
</KEYS>
<INDEXES>
<INDEX NAME="userid" UNIQUE="false" FIELDS="userid"/>
</INDEXES>
</TABLE>
<TABLE NAME="feedback_value" COMMENT="values of the completeds">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="course_id" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="item" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="completed" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="tmp_completed" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="value" TYPE="text" NOTNULL="true" SEQUENCE="false"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id" COMMENT="Primary key for feedback_value"/>
<KEY NAME="item" TYPE="foreign" FIELDS="item" REFTABLE="feedback_item" REFFIELDS="id"/>
</KEYS>
<INDEXES>
<INDEX NAME="course_id" UNIQUE="false" FIELDS="course_id"/>
<INDEX NAME="completed_item" UNIQUE="true" FIELDS="completed, item, course_id"/>
</INDEXES>
</TABLE>
<TABLE NAME="feedback_valuetmp" COMMENT="values of the completedstmp">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="course_id" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="item" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="completed" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="tmp_completed" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="value" TYPE="text" NOTNULL="true" SEQUENCE="false"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id" COMMENT="Primary key for feedback_valuetmp"/>
<KEY NAME="item" TYPE="foreign" FIELDS="item" REFTABLE="feedback_item" REFFIELDS="id"/>
</KEYS>
<INDEXES>
<INDEX NAME="course_id" UNIQUE="false" FIELDS="course_id"/>
<INDEX NAME="completed_item" UNIQUE="true" FIELDS="completed, item, course_id"/>
</INDEXES>
</TABLE>
<TABLE NAME="feedback_sitecourse_map" COMMENT="feedback sitecourse map">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="feedbackid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id" COMMENT="Primary key for feedback_sitecourse_map"/>
<KEY NAME="feedbackid" TYPE="foreign" FIELDS="feedbackid" REFTABLE="feedback" REFFIELDS="id"/>
</KEYS>
<INDEXES>
<INDEX NAME="courseid" UNIQUE="false" FIELDS="courseid"/>
</INDEXES>
</TABLE>
</TABLES>
</XMLDB>
+34
View File
@@ -0,0 +1,34 @@
<?php
// 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/>.
/**
* Definition of log events
*
* @package mod_feedback
* @category log
* @copyright 2010 Petr Skoda (http://skodak.org)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$logs = array(
array('module'=>'feedback', 'action'=>'startcomplete', 'mtable'=>'feedback', 'field'=>'name'),
array('module'=>'feedback', 'action'=>'submit', 'mtable'=>'feedback', 'field'=>'name'),
array('module'=>'feedback', 'action'=>'delete', 'mtable'=>'feedback', 'field'=>'name'),
array('module'=>'feedback', 'action'=>'view', 'mtable'=>'feedback', 'field'=>'name'),
array('module'=>'feedback', 'action'=>'view all', 'mtable'=>'course', 'field'=>'shortname'),
);
+42
View File
@@ -0,0 +1,42 @@
<?php
// 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/>.
/**
* Defines message providers (types of messages being sent)
*
* @package mod_feedback
* @copyright 2010 onwards Aparup Banerjee http://moodle.com
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$messageproviders = array (
// Submitting a feedback.
'submission' => [
'defaults' => [
'popup' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
'email' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
],
],
// Message to nonrespondents.
'message' => [
'defaults' => [
'popup' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
'email' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
],
],
);
+144
View File
@@ -0,0 +1,144 @@
<?php
// 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/>.
/**
* Feedback external functions and service definitions.
*
* @package mod_feedback
* @category external
* @copyright 2017 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since Moodle 3.3
*/
defined('MOODLE_INTERNAL') || die;
$functions = array(
'mod_feedback_get_feedbacks_by_courses' => array(
'classname' => 'mod_feedback_external',
'methodname' => 'get_feedbacks_by_courses',
'description' => 'Returns a list of feedbacks in a provided list of courses, if no list is provided all feedbacks that
the user can view will be returned.',
'type' => 'read',
'capabilities' => 'mod/feedback:view',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
),
'mod_feedback_get_feedback_access_information' => array(
'classname' => 'mod_feedback_external',
'methodname' => 'get_feedback_access_information',
'description' => 'Return access information for a given feedback.',
'type' => 'read',
'capabilities' => 'mod/feedback:view',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
),
'mod_feedback_view_feedback' => array(
'classname' => 'mod_feedback_external',
'methodname' => 'view_feedback',
'description' => 'Trigger the course module viewed event and update the module completion status.',
'type' => 'write',
'capabilities' => 'mod/feedback:view',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
'mod_feedback_get_current_completed_tmp' => array(
'classname' => 'mod_feedback_external',
'methodname' => 'get_current_completed_tmp',
'description' => 'Returns the temporary completion record for the current user.',
'type' => 'read',
'capabilities' => 'mod/feedback:view',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
'mod_feedback_get_items' => array(
'classname' => 'mod_feedback_external',
'methodname' => 'get_items',
'description' => 'Returns the items (questions) in the given feedback.',
'type' => 'read',
'capabilities' => 'mod/feedback:view',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
'mod_feedback_launch_feedback' => array(
'classname' => 'mod_feedback_external',
'methodname' => 'launch_feedback',
'description' => 'Starts or continues a feedback submission.',
'type' => 'write',
'capabilities' => 'mod/feedback:complete',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
'mod_feedback_get_page_items' => array(
'classname' => 'mod_feedback_external',
'methodname' => 'get_page_items',
'description' => 'Get a single feedback page items.',
'type' => 'read',
'capabilities' => 'mod/feedback:complete',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
'mod_feedback_process_page' => array(
'classname' => 'mod_feedback_external',
'methodname' => 'process_page',
'description' => 'Process a jump between pages.',
'type' => 'write',
'capabilities' => 'mod/feedback:complete',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
'mod_feedback_get_analysis' => array(
'classname' => 'mod_feedback_external',
'methodname' => 'get_analysis',
'description' => 'Retrieves the feedback analysis.',
'type' => 'read',
'capabilities' => 'mod/feedback:viewanalysepage',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
'mod_feedback_get_unfinished_responses' => array(
'classname' => 'mod_feedback_external',
'methodname' => 'get_unfinished_responses',
'description' => 'Retrieves responses from the current unfinished attempt.',
'type' => 'read',
'capabilities' => 'mod/feedback:view',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
'mod_feedback_get_finished_responses' => array(
'classname' => 'mod_feedback_external',
'methodname' => 'get_finished_responses',
'description' => 'Retrieves responses from the last finished attempt.',
'type' => 'read',
'capabilities' => 'mod/feedback:view',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
'mod_feedback_get_non_respondents' => array(
'classname' => 'mod_feedback_external',
'methodname' => 'get_non_respondents',
'description' => 'Retrieves a list of students who didn\'t submit the feedback.',
'type' => 'read',
'capabilities' => 'mod/feedback:viewreports',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
'mod_feedback_get_responses_analysis' => array(
'classname' => 'mod_feedback_external',
'methodname' => 'get_responses_analysis',
'description' => 'Return the feedback user responses analysis.',
'type' => 'read',
'capabilities' => 'mod/feedback:viewreports',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
'mod_feedback_get_last_completed' => array(
'classname' => 'mod_feedback_external',
'methodname' => 'get_last_completed',
'description' => 'Retrieves the last completion record for the current user.',
'type' => 'read',
'capabilities' => 'mod/feedback:view',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
);
+56
View File
@@ -0,0 +1,56 @@
<?php
// 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/>.
/**
* This file keeps track of upgrades to the feedback module.
*
* Sometimes, changes between versions involve
* alterations to database structures and other
* major things that may break installations.
*
* The upgrade function in this file will attempt
* to perform all the necessary actions to upgrade
* your older installation to the current version.
*
* If there's something it cannot do itself, it
* will tell you what you need to do.
*
* The commands in here will all be database-neutral,
* using the methods of database_manager class
*
* Please do not forget to use upgrade_set_timeout()
* before any action that may take longer time to finish.
*
* @package mod_feedback
* @copyright Andreas Grabs
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
function xmldb_feedback_upgrade($oldversion) {
// Automatically generated Moodle v4.1.0 release upgrade line.
// Put any upgrade step following this.
// Automatically generated Moodle v4.2.0 release upgrade line.
// Put any upgrade step following this.
// Automatically generated Moodle v4.3.0 release upgrade line.
// Put any upgrade step following this.
// Automatically generated Moodle v4.4.0 release upgrade line.
// Put any upgrade step following this.
return true;
}
+31
View File
@@ -0,0 +1,31 @@
<?php
// 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/>.
/**
* List of deprecated mod_feedback functions.
*
* @package mod_feedback
* @copyright 2021 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* @deprecated since Moodle 3.11
*/
function feedback_get_completion_state() {
$completionclass = \mod_feedback\completion\custom_completion::class;
throw new coding_exception(__FUNCTION__ . "() has been removed, please use the '{$completionclass}' class instead");
}
+119
View File
@@ -0,0 +1,119 @@
<?php
// 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/>.
/**
* prints the form to edit the feedback items such moving, deleting and so on
*
* @author Andreas Grabs
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package mod_feedback
*/
require_once('../../config.php');
require_once('lib.php');
feedback_init_feedback_session();
$id = required_param('id', PARAM_INT);
if (($formdata = data_submitted()) AND !confirm_sesskey()) {
throw new \moodle_exception('invalidsesskey');
}
$switchitemrequired = optional_param('switchitemrequired', false, PARAM_INT);
$deleteitem = optional_param('deleteitem', false, PARAM_INT);
list($course, $cm) = get_course_and_cm_from_cmid($id, 'feedback');
$context = context_module::instance($cm->id);
require_login($course, false, $cm);
require_capability('mod/feedback:edititems', $context);
$feedback = $PAGE->activityrecord;
$feedbackstructure = new mod_feedback_structure($feedback, $cm);
$url = new moodle_url('/mod/feedback/edit.php', ['id' => $cm->id]);
if ($switchitemrequired) {
require_sesskey();
$items = $feedbackstructure->get_items();
if (isset($items[$switchitemrequired])) {
feedback_switch_item_required($items[$switchitemrequired]);
}
redirect($url);
}
if ($deleteitem) {
require_sesskey();
$items = $feedbackstructure->get_items();
if (isset($items[$deleteitem])) {
feedback_delete_item($deleteitem);
}
redirect($url);
}
// Process the create template form.
$cancreatetemplates = has_capability('mod/feedback:createprivatetemplate', $context) ||
has_capability('mod/feedback:createpublictemplate', $context);
//Get the feedbackitems
$lastposition = 0;
$feedbackitems = $DB->get_records('feedback_item', array('feedback'=>$feedback->id), 'position');
if (is_array($feedbackitems)) {
$feedbackitems = array_values($feedbackitems);
if (count($feedbackitems) > 0) {
$lastitem = $feedbackitems[count($feedbackitems)-1];
$lastposition = $lastitem->position;
} else {
$lastposition = 0;
}
}
$lastposition++;
$PAGE->set_url($url);
$PAGE->set_heading($course->fullname);
$PAGE->set_title($feedback->name);
$actionbar = new \mod_feedback\output\edit_action_bar($cm->id, $url, $lastposition);
$PAGE->activityheader->set_attrs([
'hidecompletion' => true,
'description' => ''
]);
$PAGE->add_body_class('limitedwidth');
//Adding the javascript module for the items dragdrop.
if (count($feedbackitems) > 1) {
$PAGE->requires->strings_for_js(array(
'pluginname',
'move_item',
'position',
), 'feedback');
$PAGE->requires->yui_module('moodle-mod_feedback-dragdrop', 'M.mod_feedback.init_dragdrop',
array(array('cmid' => $cm->id)));
}
echo $OUTPUT->header();
/** @var \mod_feedback\output\renderer $renderer */
$renderer = $PAGE->get_renderer('mod_feedback');
echo $renderer->main_action_bar($actionbar);
$form = new mod_feedback_complete_form(mod_feedback_complete_form::MODE_EDIT,
$feedbackstructure, 'feedback_edit_form');
echo '<div id="feedback_dragarea">'; // The container for the dragging area.
$form->display();
echo '</div>';
if ($cancreatetemplates) {
echo $renderer->create_template_form($id);
}
echo $OUTPUT->footer();
+288
View File
@@ -0,0 +1,288 @@
<?php
// 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/>.
/**
* prints the forms to choose an item-typ to create items and to choose a template to use
*
* @author Andreas Grabs
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package mod_feedback
*/
//It must be included from a Moodle page
if (!defined('MOODLE_INTERNAL')) {
die('Direct access to this script is forbidden.');
}
require_once($CFG->libdir.'/formslib.php');
/**
* The feedback_edit_use_template_form
*
* @deprecated since 4.0 new dynamic forms created
*/
class feedback_edit_use_template_form extends moodleform {
public function __construct($action = null, $customdata = null, $method = 'post', $target = '',
$attributes = null, $editable = true, $ajaxformdata = null) {
debugging('Class feedback_edit_use_template_form is deprecated. Replaced with dynamic forms.', DEBUG_DEVELOPER);
parent::__construct($action, $customdata, $method, $target, $attributes, $editable, $ajaxformdata);
}
/**
* Overrides parent static method for deprecation purposes.
*
* @deprecated since 4.0
* @return array
*/
public static function get_js_module() {
debugging('Class feedback_edit_use_template_form is deprecated. Replaced with dynamic forms.', DEBUG_DEVELOPER);
return parent::get_js_module();
}
/**
* Overrides parent static method for deprecation purposes.
*
* @deprecated since 4.0
* @param array $simulatedsubmitteddata
* @param array $simulatedsubmittedfiles
* @param string $method
* @param null $formidentifier
* @return array
*/
public static function mock_ajax_submit($simulatedsubmitteddata, $simulatedsubmittedfiles = array(),
$method = 'post', $formidentifier = null) {
debugging('Class feedback_edit_use_template_form is deprecated. Replaced with dynamic forms.', DEBUG_DEVELOPER);
return parent::mock_ajax_submit($simulatedsubmitteddata, $simulatedsubmittedfiles, $method, $formidentifier);
}
/**
* Overrides parent static method for deprecation purposes.
*
* @deprecated since 4.0
* @param array $data
* @return array
*/
public static function mock_generate_submit_keys($data = []) {
debugging('Class feedback_edit_use_template_form is deprecated. Replaced with dynamic forms.', DEBUG_DEVELOPER);
return parent::mock_generate_submit_keys($data);
}
/**
* Overrides parent static method for deprecation purposes.
*
* @deprecated since 4.0
* @param array $simulatedsubmitteddata
* @param array $simulatedsubmittedfiles
* @param string $method
* @param null $formidentifier
*/
public static function mock_submit($simulatedsubmitteddata, $simulatedsubmittedfiles = array(),
$method = 'post', $formidentifier = null) {
debugging('Class feedback_edit_use_template_form is deprecated. Replaced with dynamic forms.', DEBUG_DEVELOPER);
parent::mock_submit($simulatedsubmitteddata, $simulatedsubmittedfiles, $method, $formidentifier);
}
/**
* Form definition
*/
public function definition() {
$mform =& $this->_form;
$course = $this->_customdata['course'];
$elementgroup = array();
//headline
$mform->addElement('header', 'using_templates', get_string('using_templates', 'feedback'));
// hidden elements
$mform->addElement('hidden', 'id');
$mform->setType('id', PARAM_INT);
// visible elements
$templates_options = array();
$owntemplates = feedback_get_template_list($course, 'own');
$publictemplates = feedback_get_template_list($course, 'public');
$options = array();
if ($owntemplates or $publictemplates) {
$options[''] = array('' => get_string('choosedots'));
if ($owntemplates) {
$courseoptions = array();
foreach ($owntemplates as $template) {
$courseoptions[$template->id] = format_string($template->name);
}
$options[get_string('course')] = $courseoptions;
}
if ($publictemplates) {
$publicoptions = array();
foreach ($publictemplates as $template) {
$publicoptions[$template->id] = format_string($template->name);
}
$options[get_string('public', 'feedback')] = $publicoptions;
}
$attributes = [
'onChange="this.form.submit()"',
'data-form-change-checker-override="1"',
];
$elementgroup[] = $mform->createElement(
'selectgroups',
'templateid',
get_string('using_templates', 'feedback'),
$options,
implode(' ', $attributes)
);
$elementgroup[] = $mform->createElement('submit',
'use_template',
get_string('use_this_template', 'feedback'),
array('class' => 'hiddenifjs'));
$mform->addGroup($elementgroup, 'elementgroup', '', array(' '), false);
} else {
$mform->addElement('static', 'info', get_string('no_templates_available_yet', 'feedback'));
}
$this->set_data(array('id' => $this->_customdata['id']));
}
}
/**
* The feedback_edit_create_template_form
*
* @deprecated since 4.0, new dynamic forms have been created instead.
*/
class feedback_edit_create_template_form extends moodleform {
public function __construct($action = null, $customdata = null, $method = 'post',
$target = '', $attributes = null, $editable = true, $ajaxformdata = null) {
debugging('Class feedback_edit_create_template_form is deprecated. Replaced with dynamic forms.', DEBUG_DEVELOPER);
parent::__construct($action, $customdata, $method, $target, $attributes, $editable, $ajaxformdata);
}
/**
* Overrides parent static method for deprecation purposes.
*
* @deprecated since 4.0
* @return array
*/
public static function get_js_module() {
debugging('Class feedback_edit_create_template_form is deprecated. Replaced with dynamic forms.', DEBUG_DEVELOPER);
return parent::get_js_module();
}
/**
* Overrides parent static method for deprecation purposes.
*
* @deprecated since 4.0
* @param array $simulatedsubmitteddata
* @param array $simulatedsubmittedfiles
* @param string $method
* @param null $formidentifier
* @return array
*/
public static function mock_ajax_submit($simulatedsubmitteddata, $simulatedsubmittedfiles = array(),
$method = 'post', $formidentifier = null) {
debugging('Class feedback_edit_create_template_form is deprecated. Replaced with dynamic forms.', DEBUG_DEVELOPER);
return parent::mock_ajax_submit($simulatedsubmitteddata, $simulatedsubmittedfiles, $method, $formidentifier);
}
/**
* Overrides parent static method for deprecation purposes.
*
* @deprecated since 4.0
* @param array $data
* @return array
*/
public static function mock_generate_submit_keys($data = []) {
debugging('Class feedback_edit_create_template_form is deprecated. Replaced with dynamic forms.', DEBUG_DEVELOPER);
return parent::mock_generate_submit_keys($data);
}
/**
* Overrides parent static method for deprecation purposes.
*
* @deprecated since 4.0
* @param array $simulatedsubmitteddata
* @param array $simulatedsubmittedfiles
* @param string $method
* @param null $formidentifier
*/
public static function mock_submit($simulatedsubmitteddata, $simulatedsubmittedfiles = array(),
$method = 'post', $formidentifier = null) {
debugging('Class feedback_edit_create_template_form is deprecated. Replaced with dynamic forms.', DEBUG_DEVELOPER);
parent::mock_submit($simulatedsubmitteddata, $simulatedsubmittedfiles, $method, $formidentifier);
}
/**
* Form definition
*/
public function definition() {
$mform =& $this->_form;
// hidden elements
$mform->addElement('hidden', 'id');
$mform->setType('id', PARAM_INT);
$mform->addElement('hidden', 'do_show');
$mform->setType('do_show', PARAM_ALPHANUMEXT);
$mform->setConstant('do_show', 'edit');
// visible elements
$elementgroup = array();
$elementgroup[] = $mform->createElement('text',
'templatename',
get_string('name', 'feedback'),
['maxlength' => '200']);
if (has_capability('mod/feedback:createpublictemplate', context_system::instance())) {
$elementgroup[] = $mform->createElement('checkbox',
'ispublic', '',
get_string('public', 'feedback'));
}
$mform->addGroup($elementgroup,
'elementgroup',
get_string('name', 'feedback'),
array(' '),
false);
// Buttons.
$mform->addElement('submit', 'create_template', get_string('save_as_new_template', 'feedback'));
$mform->setType('templatename', PARAM_TEXT);
$this->set_data(array('id' => $this->_customdata['id']));
}
/**
* Form validation
*
* @param array $data array of ("fieldname"=>value) of submitted data
* @param array $files array of uploaded files "element_name"=>tmp_file_path
* @return array of "element_name"=>"error_description" if there are errors,
* or an empty array if everything is OK (true allowed for backwards compatibility too).
*/
public function validation($data, $files) {
$errors = parent::validation($data, $files);
if (!isset($data['templatename']) || trim(strval($data['templatename'])) === '') {
$errors['elementgroup'] = get_string('name_required', 'feedback');
}
return $errors;
}
}
+123
View File
@@ -0,0 +1,123 @@
<?php
// 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/>.
/**
* prints the form to edit a dedicated item
*
* @author Andreas Grabs
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package mod_feedback
*/
require_once("../../config.php");
require_once("lib.php");
feedback_init_feedback_session();
$itemid = optional_param('id', false, PARAM_INT);
if (!$itemid) {
$cmid = required_param('cmid', PARAM_INT);
$typ = required_param('typ', PARAM_ALPHA);
}
if ($itemid) {
$item = $DB->get_record('feedback_item', array('id' => $itemid), '*', MUST_EXIST);
list($course, $cm) = get_course_and_cm_from_instance($item->feedback, 'feedback');
$url = new moodle_url('/mod/feedback/edit_item.php', array('id' => $itemid));
$typ = $item->typ;
} else {
$item = null;
list($course, $cm) = get_course_and_cm_from_cmid($cmid, 'feedback');
$url = new moodle_url('/mod/feedback/edit_item.php', array('cmid' => $cm->id, 'typ' => $typ));
$item = (object)['id' => null, 'position' => -1, 'typ' => $typ, 'options' => ''];
}
require_login($course, true, $cm);
$context = context_module::instance($cm->id);
require_capability('mod/feedback:edititems', $context);
$feedback = $PAGE->activityrecord;
$editurl = new moodle_url('/mod/feedback/edit.php', array('id' => $cm->id));
$PAGE->set_url($url);
// If the typ is pagebreak so the item will be saved directly.
if (!$item->id && $typ === 'pagebreak') {
require_sesskey();
$redirectmessage = '';
if (!feedback_create_pagebreak($feedback->id)) {
$redirectmessage = get_string('cannotcreatepagebreak', 'mod_feedback');
}
redirect($editurl, $redirectmessage, null, \core\output\notification::NOTIFY_WARNING);
}
//get the existing item or create it
if (!$typ) {
throw new \moodle_exception('typemissing', 'feedback', $editurl->out(false));
}
$itemobj = feedback_get_item_class($typ);
$itemobj->build_editform($item, $feedback, $cm);
if ($itemobj->is_cancelled()) {
redirect($editurl);
exit;
}
if ($itemobj->get_data()) {
if ($item = $itemobj->save_item()) {
feedback_move_item($item, $item->position);
redirect($editurl);
}
}
////////////////////////////////////////////////////////////////////////////////////
/// Print the page header
$strfeedbacks = get_string("modulenameplural", "feedback");
$strfeedback = get_string("modulename", "feedback");
navigation_node::override_active_url(new moodle_url('/mod/feedback/edit.php',
array('id' => $cm->id, 'do_show' => 'edit')));
if ($item->id) {
$PAGE->navbar->add(get_string('edit_item', 'feedback'));
} else {
$PAGE->navbar->add(get_string('add_item', 'feedback'));
}
$PAGE->set_heading($course->fullname);
$PAGE->set_title($feedback->name);
$PAGE->activityheader->set_attrs([
"hidecompletion" => true,
"description" => ''
]);
echo $OUTPUT->header();
/// print the tabs
$current_tab = 'edit';
$id = $cm->id;
//print errormsg
if (isset($error)) {
echo $error;
}
$itemobj->show_editform();
/// Finish the page
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
echo $OUTPUT->footer();
+171
View File
@@ -0,0 +1,171 @@
<?php
// 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/>.
/**
* prints the form to export the items as xml-file
*
* @author Andreas Grabs
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package mod_feedback
*/
require_once("../../config.php");
require_once("lib.php");
// get parameters
$id = required_param('id', PARAM_INT);
$action = optional_param('action', false, PARAM_ALPHA);
$url = new moodle_url('/mod/feedback/export.php', array('id'=>$id));
if ($action !== false) {
$url->param('action', $action);
}
$PAGE->set_url($url);
if (! $cm = get_coursemodule_from_id('feedback', $id)) {
throw new \moodle_exception('invalidcoursemodule');
}
if (! $course = $DB->get_record("course", array("id"=>$cm->course))) {
throw new \moodle_exception('coursemisconf');
}
if (! $feedback = $DB->get_record("feedback", array("id"=>$cm->instance))) {
throw new \moodle_exception('invalidcoursemodule');
}
$context = context_module::instance($cm->id);
require_login($course, true, $cm);
require_capability('mod/feedback:edititems', $context);
if ($action == 'exportfile') {
if (!$exportdata = feedback_get_xml_data($feedback->id)) {
throw new \moodle_exception('nodata');
}
@feedback_send_xml_data($exportdata, 'feedback_'.$feedback->id.'.xml');
exit;
}
redirect('view.php?id='.$id);
exit;
function feedback_get_xml_data($feedbackid) {
global $DB;
$space = ' ';
//get all items of the feedback
if (!$items = $DB->get_records('feedback_item', array('feedback'=>$feedbackid), 'position')) {
return false;
}
//writing the header of the xml file including the charset of the currrent used language
$data = '<?xml version="1.0" encoding="UTF-8" ?>'."\n";
$data .= '<FEEDBACK VERSION="200701" COMMENT="XML-Importfile for mod/feedback">'."\n";
$data .= $space.'<ITEMS>'."\n";
//writing all the items
foreach ($items as $item) {
//start of item
$data .= $space.$space.'<ITEM TYPE="'.$item->typ.'" REQUIRED="'.$item->required.'">'."\n";
//start of itemid
$data .= $space.$space.$space.'<ITEMID>'."\n";
//start of CDATA
$data .= $space.$space.$space.$space.'<![CDATA[';
$data .= $item->id;
//end of CDATA
$data .= ']]>'."\n";
//end of itemid
$data .= $space.$space.$space.'</ITEMID>'."\n";
//start of itemtext
$data .= $space.$space.$space.'<ITEMTEXT>'."\n";
//start of CDATA
$data .= $space.$space.$space.$space.'<![CDATA[';
$data .= $item->name;
//end of CDATA
$data .= ']]>'."\n";
//end of itemtext
$data .= $space.$space.$space.'</ITEMTEXT>'."\n";
//start of itemtext
$data .= $space.$space.$space.'<ITEMLABEL>'."\n";
//start of CDATA
$data .= $space.$space.$space.$space.'<![CDATA[';
$data .= $item->label;
//end of CDATA
$data .= ']]>'."\n";
//end of itemtext
$data .= $space.$space.$space.'</ITEMLABEL>'."\n";
//start of presentation
$data .= $space.$space.$space.'<PRESENTATION>'."\n";
//start of CDATA
$data .= $space.$space.$space.$space.'<![CDATA[';
$data .= $item->presentation;
//end of CDATA
$data .= ']]>'."\n";
//end of presentation
$data .= $space.$space.$space.'</PRESENTATION>'."\n";
//start of options
$data .= $space.$space.$space.'<OPTIONS>'."\n";
//start of CDATA
$data .= $space.$space.$space.$space.'<![CDATA[';
$data .= $item->options;
//end of CDATA
$data .= ']]>'."\n";
//end of options
$data .= $space.$space.$space.'</OPTIONS>'."\n";
//start of dependitem
$data .= $space.$space.$space.'<DEPENDITEM>'."\n";
//start of CDATA
$data .= $space.$space.$space.$space.'<![CDATA[';
$data .= $item->dependitem;
//end of CDATA
$data .= ']]>'."\n";
//end of dependitem
$data .= $space.$space.$space.'</DEPENDITEM>'."\n";
//start of dependvalue
$data .= $space.$space.$space.'<DEPENDVALUE>'."\n";
//start of CDATA
$data .= $space.$space.$space.$space.'<![CDATA[';
$data .= $item->dependvalue;
//end of CDATA
$data .= ']]>'."\n";
//end of dependvalue
$data .= $space.$space.$space.'</DEPENDVALUE>'."\n";
//end of item
$data .= $space.$space.'</ITEM>'."\n";
}
//writing the footer of the xml file
$data .= $space.'</ITEMS>'."\n";
$data .= '</FEEDBACK>'."\n";
return $data;
}
function feedback_send_xml_data($data, $filename) {
@header('Content-Type: application/xml; charset=UTF-8');
@header('Content-Disposition: attachment; filename="'.$filename.'"');
print($data);
}
+300
View File
@@ -0,0 +1,300 @@
<?php
// 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/>.
/**
* prints the form to import items from xml-file
*
* @author Andreas Grabs
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package mod_feedback
*/
require_once("../../config.php");
require_once("lib.php");
require_once('import_form.php');
// get parameters
$id = required_param('id', PARAM_INT);
$choosefile = optional_param('choosefile', false, PARAM_PATH);
$action = optional_param('action', false, PARAM_ALPHA);
$url = new moodle_url('/mod/feedback/import.php', array('id'=>$id));
if ($choosefile !== false) {
$url->param('choosefile', $choosefile);
}
if ($action !== false) {
$url->param('action', $action);
}
$PAGE->set_url($url);
if (! $cm = get_coursemodule_from_id('feedback', $id)) {
throw new \moodle_exception('invalidcoursemodule');
}
if (! $course = $DB->get_record("course", array("id"=>$cm->course))) {
throw new \moodle_exception('coursemisconf');
}
if (! $feedback = $DB->get_record("feedback", array("id"=>$cm->instance))) {
throw new \moodle_exception('invalidcoursemodule');
}
$context = context_module::instance($cm->id);
require_login($course, true, $cm);
require_capability('mod/feedback:edititems', $context);
$actionbar = new \mod_feedback\output\edit_action_bar($cm->id, $url);
$mform = new feedback_import_form();
$newformdata = array('id'=>$id,
'deleteolditems'=>'1',
'action'=>'choosefile',
'confirmadd'=>'1',
'do_show'=>'templates');
$mform->set_data($newformdata);
$formdata = $mform->get_data();
if ($mform->is_cancelled()) {
redirect('edit.php?id='.$id.'&do_show=templates');
}
// process if we are happy file is ok
if ($choosefile) {
$xmlcontent = $mform->get_file_content('choosefile');
if (!$xmldata = feedback_load_xml_data($xmlcontent)) {
throw new \moodle_exception('cannotloadxml', 'feedback', 'edit.php?id='.$id);
}
$importerror = feedback_import_loaded_data($xmldata, $feedback->id);
if ($importerror->stat == true) {
$url = 'edit.php?id='.$id.'&do_show=templates';
redirect($url, get_string('import_successfully', 'feedback'), 3);
exit;
}
}
/// Print the page header
$strfeedbacks = get_string("modulenameplural", "feedback");
$strfeedback = get_string("modulename", "feedback");
$PAGE->set_heading($course->fullname);
$PAGE->set_title($feedback->name);
$PAGE->activityheader->set_attrs([
"hidecompletion" => true,
"description" => ''
]);
echo $OUTPUT->header();
/** @var \mod_feedback\output\renderer $renderer */
$renderer = $PAGE->get_renderer('mod_feedback');
echo $renderer->main_action_bar($actionbar);
/// Print the main part of the page
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
if (!$PAGE->has_secondary_navigation()) {
echo $OUTPUT->heading(get_string('import_questions', 'feedback'), 3);
}
if (isset($importerror->msg) AND is_array($importerror->msg)) {
echo $OUTPUT->box_start('generalbox errorboxcontent boxaligncenter');
foreach ($importerror->msg as $msg) {
echo $msg.'<br />';
}
echo $OUTPUT->box_end();
}
$mform->display();
echo $OUTPUT->footer();
function feedback_load_xml_data($xmlcontent) {
global $CFG;
require_once($CFG->dirroot.'/lib/xmlize.php');
if (!$xmlcontent = feedback_check_xml_utf8($xmlcontent)) {
return false;
}
$data = xmlize($xmlcontent, 1, 'UTF-8');
if (intval($data['FEEDBACK']['@']['VERSION']) != 200701) {
return false;
}
$data = $data['FEEDBACK']['#']['ITEMS'][0]['#']['ITEM'];
return $data;
}
function feedback_import_loaded_data(&$data, $feedbackid) {
global $CFG, $DB;
feedback_load_feedback_items();
$deleteolditems = optional_param('deleteolditems', 0, PARAM_INT);
$error = new stdClass();
$error->stat = true;
$error->msg = array();
if (!is_array($data)) {
$error->msg[] = get_string('data_is_not_an_array', 'feedback');
$error->stat = false;
return $error;
}
if ($deleteolditems) {
feedback_delete_all_items($feedbackid);
$position = 0;
} else {
//items will be add to the end of the existing items
$position = $DB->count_records('feedback_item', array('feedback'=>$feedbackid));
}
//depend items we are storing temporary in an mapping list array(new id => dependitem)
//we also store a mapping of all items array(oldid => newid)
$dependitemsmap = array();
$itembackup = array();
foreach ($data as $item) {
$position++;
//check the typ
$typ = $item['@']['TYPE'];
//check oldtypes first
switch($typ) {
case 'radio':
$typ = 'multichoice';
$oldtyp = 'radio';
break;
case 'dropdown':
$typ = 'multichoice';
$oldtyp = 'dropdown';
break;
case 'check':
$typ = 'multichoice';
$oldtyp = 'check';
break;
case 'radiorated':
$typ = 'multichoicerated';
$oldtyp = 'radiorated';
break;
case 'dropdownrated':
$typ = 'multichoicerated';
$oldtyp = 'dropdownrated';
break;
default:
$oldtyp = $typ;
}
$itemclass = 'feedback_item_'.$typ;
if ($typ != 'pagebreak' AND !class_exists($itemclass)) {
$error->stat = false;
$error->msg[] = 'type ('.$typ.') not found';
continue;
}
$itemobj = new $itemclass();
$newitem = new stdClass();
$newitem->feedback = $feedbackid;
$newitem->template = 0;
$newitem->typ = $typ;
$newitem->name = trim($item['#']['ITEMTEXT'][0]['#']);
$newitem->label = trim($item['#']['ITEMLABEL'][0]['#']);
if ($typ === 'captcha' || $typ === 'label') {
$newitem->label = '';
$newitem->name = '';
}
$newitem->options = trim($item['#']['OPTIONS'][0]['#']);
$newitem->presentation = trim($item['#']['PRESENTATION'][0]['#']);
//check old types of radio, check, and so on
switch($oldtyp) {
case 'radio':
$newitem->presentation = 'r>>>>>'.$newitem->presentation;
break;
case 'dropdown':
$newitem->presentation = 'd>>>>>'.$newitem->presentation;
break;
case 'check':
$newitem->presentation = 'c>>>>>'.$newitem->presentation;
break;
case 'radiorated':
$newitem->presentation = 'r>>>>>'.$newitem->presentation;
break;
case 'dropdownrated':
$newitem->presentation = 'd>>>>>'.$newitem->presentation;
break;
}
if (isset($item['#']['DEPENDITEM'][0]['#'])) {
$newitem->dependitem = intval($item['#']['DEPENDITEM'][0]['#']);
} else {
$newitem->dependitem = 0;
}
if (isset($item['#']['DEPENDVALUE'][0]['#'])) {
$newitem->dependvalue = trim($item['#']['DEPENDVALUE'][0]['#']);
} else {
$newitem->dependvalue = '';
}
$olditemid = intval($item['#']['ITEMID'][0]['#']);
if ($typ != 'pagebreak') {
$newitem->hasvalue = $itemobj->get_hasvalue();
} else {
$newitem->hasvalue = 0;
}
$newitem->required = intval($item['@']['REQUIRED']);
$newitem->position = $position;
$newid = $DB->insert_record('feedback_item', $newitem);
$itembackup[$olditemid] = $newid;
if ($newitem->dependitem) {
$dependitemsmap[$newid] = $newitem->dependitem;
}
}
//remapping the dependency
foreach ($dependitemsmap as $key => $dependitem) {
$newitem = $DB->get_record('feedback_item', array('id'=>$key));
$newitem->dependitem = $itembackup[$newitem->dependitem];
$DB->update_record('feedback_item', $newitem);
}
return $error;
}
function feedback_check_xml_utf8($text) {
//find the encoding
$searchpattern = '/^\<\?xml.+(encoding=\"([a-z0-9-]*)\").+\?\>/is';
if (!preg_match($searchpattern, $text, $match)) {
return false; //no xml-file
}
//$match[0] = \<\? xml ... \?\> (without \)
//$match[1] = encoding="...."
//$match[2] = ISO-8859-1 or so on
if (isset($match[0]) AND !isset($match[1])) { //no encoding given. we assume utf-8
return $text;
}
//encoding is given in $match[2]
if (isset($match[0]) AND isset($match[1]) AND isset($match[2])) {
$enc = $match[2];
return core_text::convert($text, $enc);
}
}
+59
View File
@@ -0,0 +1,59 @@
<?php
// 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/>.
/**
* prints the forms to choose an xml-template file to import items
*
* @author Andreas Grabs
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package mod_feedback
*/
//It must be included from a Moodle page
if (!defined('MOODLE_INTERNAL')) {
die('Direct access to this script is forbidden.');
}
require_once($CFG->libdir.'/formslib.php');
class feedback_import_form extends moodleform {
public function definition() {
global $CFG;
$mform =& $this->_form;
$strdeleteolditmes = get_string('delete_old_items', 'feedback').
' ('.get_string('oldvalueswillbedeleted', 'feedback').')';
$strnodeleteolditmes = get_string('append_new_items', 'feedback').
' ('.get_string('oldvaluespreserved', 'feedback').')';
// hidden elements
$mform->addElement('hidden', 'id');
$mform->setType('id', PARAM_INT);
$mform->addElement('filepicker',
'choosefile',
get_string('file'),
null,
array('maxbytes' => $CFG->maxbytes, 'filetypes' => '*'));
$mform->addElement('radio', 'deleteolditems', '', $strdeleteolditmes, true);
$mform->addElement('radio', 'deleteolditems', '', $strnodeleteolditmes);
// buttons
$this->add_action_buttons(false, get_string('save'));
}
}
+129
View File
@@ -0,0 +1,129 @@
<?php
// 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/>.
/**
* prints the overview of all feedbacks included into the current course
*
* @author Andreas Grabs
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package mod_feedback
*/
require_once("../../config.php");
require_once("lib.php");
$id = required_param('id', PARAM_INT);
$url = new moodle_url('/mod/feedback/index.php', array('id'=>$id));
$PAGE->set_url($url);
if (!$course = $DB->get_record('course', array('id'=>$id))) {
throw new \moodle_exception('invalidcourseid');
}
$context = context_course::instance($course->id);
require_login($course);
$PAGE->set_pagelayout('incourse');
$PAGE->add_body_class('limitedwidth');
// Trigger instances list viewed event.
$event = \mod_feedback\event\course_module_instance_list_viewed::create(array('context' => $context));
$event->add_record_snapshot('course', $course);
$event->trigger();
/// Print the page header
$strfeedbacks = get_string("modulenameplural", "feedback");
$strfeedback = get_string("modulename", "feedback");
$PAGE->navbar->add($strfeedbacks);
$PAGE->set_heading($course->fullname);
$PAGE->set_title(get_string('modulename', 'feedback').' '.get_string('activities'));
echo $OUTPUT->header();
if (!$PAGE->has_secondary_navigation()) {
echo $OUTPUT->heading($strfeedbacks);
}
/// Get all the appropriate data
if (! $feedbacks = get_all_instances_in_course("feedback", $course)) {
$url = new moodle_url('/course/view.php', array('id'=>$course->id));
notice(get_string('thereareno', 'moodle', $strfeedbacks), $url);
die;
}
$usesections = course_format_uses_sections($course->format);
/// Print the list of instances (your module will probably extend this)
$timenow = time();
$strname = get_string("name");
$strresponses = get_string('responses', 'feedback');
$table = new html_table();
if ($usesections) {
$strsectionname = get_string('sectionname', 'format_'.$course->format);
if (has_capability('mod/feedback:viewreports', $context)) {
$table->head = array ($strsectionname, $strname, $strresponses);
$table->align = array ("center", "left", 'center');
} else {
$table->head = array ($strsectionname, $strname);
$table->align = array ("center", "left");
}
} else {
if (has_capability('mod/feedback:viewreports', $context)) {
$table->head = array ($strname, $strresponses);
$table->align = array ("left", "center");
} else {
$table->head = array ($strname);
$table->align = array ("left");
}
}
foreach ($feedbacks as $feedback) {
//get the responses of each feedback
$viewurl = new moodle_url('/mod/feedback/view.php', array('id'=>$feedback->coursemodule));
if (has_capability('mod/feedback:viewreports', $context)) {
$completed_feedback_count = intval(feedback_get_completeds_group_count($feedback));
}
$dimmedclass = $feedback->visible ? '' : 'class="dimmed"';
$link = '<a '.$dimmedclass.' href="'.$viewurl->out().'">'.$feedback->name.'</a>';
if ($usesections) {
$tabledata = array (get_section_name($course, $feedback->section), $link);
} else {
$tabledata = array ($link);
}
if (has_capability('mod/feedback:viewreports', $context)) {
$tabledata[] = $completed_feedback_count;
}
$table->data[] = $tabledata;
}
echo "<br />";
echo html_writer::table($table);
/// Finish the page
echo $OUTPUT->footer();
@@ -0,0 +1,52 @@
<?php
// 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/>.
require_once($CFG->dirroot.'/mod/feedback/item/feedback_item_form_class.php');
class feedback_captcha_form extends feedback_item_form {
protected $type = "captcha";
public function definition() {
$item = $this->_customdata['item'];
$common = $this->_customdata['common'];
$positionlist = $this->_customdata['positionlist'];
$position = $this->_customdata['position'];
$mform =& $this->_form;
$mform->addElement('header', 'general', get_string($this->type, 'feedback'));
$mform->addElement('advcheckbox', 'required', get_string('required', 'feedback'), '' , null , array(0, 1));
$mform->addElement('text',
'name',
get_string('item_name', 'feedback'),
array('size'=>FEEDBACK_ITEM_NAME_TEXTBOX_SIZE, 'maxlength'=>255));
$mform->addElement('text',
'label',
get_string('item_label', 'feedback'),
array('size'=>FEEDBACK_ITEM_LABEL_TEXTBOX_SIZE, 'maxlength'=>255));
$mform->addElement('select',
'presentation',
get_string('count_of_nums', 'feedback').'&nbsp;',
array_slice(range(0, 10), 3, 10, true));
parent::definition();
$this->set_data($item);
}
}
+213
View File
@@ -0,0 +1,213 @@
<?php
// 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/>.
defined('MOODLE_INTERNAL') OR die('not allowed');
require_once($CFG->dirroot.'/mod/feedback/item/feedback_item_class.php');
class feedback_item_captcha extends feedback_item_base {
protected $type = "captcha";
public function build_editform($item, $feedback, $cm) {
global $DB;
$editurl = new moodle_url('/mod/feedback/edit.php', array('id'=>$cm->id));
// There are no settings for recaptcha.
if (isset($item->id) AND $item->id > 0) {
notice(get_string('there_are_no_settings_for_recaptcha', 'feedback'), $editurl->out());
exit;
}
// Only one recaptcha can be in a feedback.
$params = array('feedback' => $feedback->id, 'typ' => $this->type);
if ($DB->record_exists('feedback_item', $params)) {
notice(get_string('only_one_captcha_allowed', 'feedback'), $editurl->out());
exit;
}
$this->item = $item;
$this->item_form = true; // Dummy.
$lastposition = $DB->count_records('feedback_item', array('feedback'=>$feedback->id));
$this->item->feedback = $feedback->id;
$this->item->template = 0;
$this->item->name = get_string('captcha', 'feedback');
$this->item->label = '';
$this->item->presentation = '';
$this->item->typ = $this->type;
$this->item->hasvalue = $this->get_hasvalue();
$this->item->position = $lastposition + 1;
$this->item->required = 1;
$this->item->dependitem = 0;
$this->item->dependvalue = '';
$this->item->options = '';
}
public function show_editform() {
}
public function is_cancelled() {
return false;
}
public function get_data() {
return true;
}
public function save_item() {
global $DB;
if (!$this->item) {
return false;
}
if (empty($this->item->id)) {
$this->item->id = $DB->insert_record('feedback_item', $this->item);
} else {
$DB->update_record('feedback_item', $this->item);
}
return $DB->get_record('feedback_item', array('id'=>$this->item->id));
}
public function get_printval($item, $value) {
return '';
}
public function print_analysed($item, $itemnr = '', $groupid = false, $courseid = false) {
return $itemnr;
}
public function excelprint_item(&$worksheet, $row_offset,
$xls_formats, $item,
$groupid, $courseid = false) {
return $row_offset;
}
/**
* Returns the formatted name of the item for the complete form or response view
*
* @param stdClass $item
* @param bool $withpostfix
* @return string
*/
public function get_display_name($item, $withpostfix = true) {
return get_string('captcha', 'feedback');
}
/**
* Adds an input element to the complete form
*
* @param stdClass $item
* @param mod_feedback_complete_form $form
*/
public function complete_form_element($item, $form) {
$name = $this->get_display_name($item);
$inputname = $item->typ . '_' . $item->id;
if ($form->get_mode() != mod_feedback_complete_form::MODE_COMPLETE) {
// Span to hold the element id. The id is used for drag and drop reordering.
$form->add_form_element($item,
['static', $inputname, $name, html_writer::span('', '', ['id' => 'feedback_item_' . $item->id])],
false,
false);
} else {
// Add recaptcha element that is used during the form validation.
$form->add_form_element($item,
['recaptcha', $inputname . 'recaptcha', $name],
false,
false);
// Add hidden element with value "1" that will be saved in the values table after completion.
$form->add_form_element($item, ['hidden', $inputname, 1], false);
$form->set_element_type($inputname, PARAM_INT);
}
// Add recaptcha validation to the form.
$form->add_validation_rule(function($values, $files) use ($item, $form) {
$elementname = $item->typ . '_' . $item->id . 'recaptcha';
$recaptchaelement = $form->get_form_element($elementname);
if (empty($values['g-recaptcha-response'])) {
return array($elementname => get_string('required'));
} else {
$response = $values['g-recaptcha-response'];
if (true !== ($result = $recaptchaelement->verify($response))) {
return array($elementname => $result);
}
}
return true;
});
}
public function create_value($data) {
global $USER;
return $USER->sesskey;
}
public function get_hasvalue() {
global $CFG;
// Is recaptcha configured in moodle?
if (empty($CFG->recaptchaprivatekey) OR empty($CFG->recaptchapublickey)) {
return 0;
}
return 1;
}
public function can_switch_require() {
return false;
}
/**
* Returns the list of actions allowed on this item in the edit mode
*
* @param stdClass $item
* @param stdClass $feedback
* @param cm_info $cm
* @return action_menu_link[]
*/
public function edit_actions($item, $feedback, $cm) {
$actions = parent::edit_actions($item, $feedback, $cm);
unset($actions['update']);
return $actions;
}
public function get_data_for_external($item) {
global $CFG;
if (empty($CFG->recaptchaprivatekey) || empty($CFG->recaptchapublickey)) {
return null;
}
// With reCAPTCHA v2 the captcha will be rendered by the mobile client using just the publickey.
$data[] = $CFG->recaptchapublickey;
return json_encode($data);
}
/**
* Return the analysis data ready for external functions.
*
* @param stdClass $item the item (question) information
* @param int $groupid the group id to filter data (optional)
* @param int $courseid the course id (optional)
* @return array an array of data with non scalar types json encoded
* @since Moodle 3.3
*/
public function get_analysed_for_external($item, $groupid = false, $courseid = false) {
return [];
}
}
+124
View File
@@ -0,0 +1,124 @@
<?php
// 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/>.
require_once('../../../../config.php');
$id = required_param('id', PARAM_INT);
$PAGE->set_url('/mod/feedback/item/captcha/print_captcha.php', array('id'=>$id));
if ($id) {
if (! $cm = get_coursemodule_from_id('feedback', $id)) {
throw new \moodle_exception('invalidcoursemodule');
}
if (! $course = $DB->get_record("course", array("id"=>$cm->course))) {
throw new \moodle_exception('coursemisconf');
}
if (! $feedback = $DB->get_record("feedback", array("id"=>$cm->instance))) {
throw new \moodle_exception('invalidcoursemodule');
}
}
if (!isset($SESSION->feedback->item->captcha)) {
throw new \moodle_exception('captchanotset', 'feedback');
}
$height = 40;
$charcount = $SESSION->feedback->item->captcha->charcount;
$fontfile = $CFG->libdir.'/default.ttf';
$ttfbox = imagettfbbox ( 30, 0, $fontfile, 'H' );//the text to measure
$charwidth = $ttfbox[2];
$width = $charcount * $charwidth;
$scale = 0.3;
$elipsesize = intval((($width + $height)/2) / 5);
$factor_x = intval($width * $scale);
$factor_y = intval($height * $scale);
//I split the colors in three ranges
//given are the max-min-values
$colors = array(array(0, 40), array(50, 200), array(210, 255));
list($col_text1, $col_el, $col_text2) = $colors;
//if the text is in color_1 so the elipses can be in color_2 or color_3
//if the text is in color_2 so the elipses can be in color_1 or color_3
//and so on.
$textcolnum = rand(1, 3);
//create the numbers to print out
$nums = array();
for ($i = 0; $i < $charcount; $i++) {
$nums[] = rand(0, 9); //Ziffern von 0-
}
//to draw enough elipses so I draw 0.2 * width and 0.2 * height
//we need th colors for that
$properties = array();
for ($x = 0; $x < $factor_x; $x++) {
for ($y = 0; $y < $factor_y; $y++) {
$propobj = new stdClass();
$propobj->x = intval($x / $scale);
$propobj->y = intval($y / $scale);
$propobj->red = get_random_color($col_el[0], $col_el[1]);
$propobj->green = get_random_color($col_el[0], $col_el[1]);
$propobj->blue = get_random_color($col_el[0], $col_el[1]);
$properties[] = $propobj;
}
}
shuffle($properties);
// create a blank image
$image = imagecreatetruecolor($width, $height);
$bg = imagecolorallocate($image, 0, 0, 0);
for ($i = 0; $i < ($factor_x * $factor_y); $i++) {
$propobj = $properties[$i];
// choose a color for the ellipse
$col_ellipse = imagecolorallocate($image, $propobj->red, $propobj->green, $propobj->blue);
// draw the white ellipse
imagefilledellipse($image, $propobj->x, $propobj->y, $elipsesize, $elipsesize, $col_ellipse);
}
$checkchar = '';
for ($i = 0; $i < $charcount; $i++) {
$colnum = rand(1, 2);
$textcol = new stdClass();
$textcol->red = get_random_color(${'col_text'.$colnum}[0], ${'col_text'.$colnum}[1]);
$textcol->green = get_random_color(${'col_text'.$colnum}[0], ${'col_text'.$colnum}[1]);
$textcol->blue = get_random_color(${'col_text'.$colnum}[0], ${'col_text'.$colnum}[1]);
$color_text = imagecolorallocate($image, $textcol->red, $textcol->green, $textcol->blue);
$angle_text = rand(-20, 20);
$left_text = $i * $charwidth;
$text = $nums[$i];
$checkchar .= $text;
imagettftext($image, 30, $angle_text, $left_text, 35, $color_text, $fontfile, $text);
}
$SESSION->feedback->item->captcha->checkchar = $checkchar;
// output the picture
header("Content-type: image/png");
imagepng($image);
function get_random_color($val1 = 0, $val2 = 255) {
$min = $val1 < $val2 ? $val1 : $val2;
$max = $val1 > $val2 ? $val1 : $val2;
return rand($min, $max);
}
+374
View File
@@ -0,0 +1,374 @@
<?php
// 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/>.
abstract class feedback_item_base {
/** @var string type of the element, should be overridden by each item type */
protected $type;
/** @var feedback_item_form */
protected $item_form;
/** @var stdClass */
protected $item;
/**
* constructor
*/
public function __construct() {
}
/**
* Displays the form for editing an item
*
* this function only can used after the call of build_editform()
*/
public function show_editform() {
$this->item_form->display();
}
/**
* Checks if the editing form was cancelled
*
* @return bool
*/
public function is_cancelled() {
return $this->item_form->is_cancelled();
}
/**
* Gets submitted data from the edit form and saves it in $this->item
*
* @return bool
*/
public function get_data() {
if ($this->item !== null) {
return true;
}
if ($this->item = $this->item_form->get_data()) {
return true;
}
return false;
}
/**
* Set the item data (to be used by data generators).
*
* @param stdClass $itemdata the item data to set
* @since Moodle 3.3
*/
public function set_data($itemdata) {
$this->item = $itemdata;
}
/**
* Creates and returns an instance of the form for editing the item
*
* @param stdClass $item
* @param stdClass $feedback
* @param cm_info|stdClass $cm
*/
abstract public function build_editform($item, $feedback, $cm);
/**
* Saves the item after it has been edited (or created)
*/
abstract public function save_item();
/**
* Converts the value from complete_form data to the string value that is stored in the db.
* @param mixed $value element from mod_feedback_complete_form::get_data() with the name $item->typ.'_'.$item->id
* @return string
*/
public function create_value($value) {
return strval($value);
}
/**
* Compares the dbvalue with the dependvalue
*
* @param stdClass $item
* @param string $dbvalue is the value input by user in the format as it is stored in the db
* @param string $dependvalue is the value that it needs to be compared against
*/
public function compare_value($item, $dbvalue, $dependvalue) {
return strval($dbvalue) === strval($dependvalue);
}
/**
* Wether this item type has a value that is expected from the user and saved in the stored values.
* @return int
*/
public function get_hasvalue() {
return 1;
}
/**
* Wether this item can be set as both required and not
* @return bool
*/
public function can_switch_require() {
return true;
}
/**
* Adds summary information about an item to the Excel export file
*
* @param object $worksheet a reference to the pear_spreadsheet-object
* @param integer $row_offset
* @param stdClass $xls_formats see analysis_to_excel.php
* @param object $item the db-object from feedback_item
* @param integer $groupid
* @param integer $courseid
* @return integer the new row_offset
*/
abstract public function excelprint_item(&$worksheet, $row_offset,
$xls_formats, $item,
$groupid, $courseid = false);
/**
* Prints analysis for the current item
*
* @param $item the db-object from feedback_item
* @param string $itemnr
* @param integer $groupid
* @param integer $courseid
* @return integer the new itemnr
*/
abstract public function print_analysed($item, $itemnr = '', $groupid = false, $courseid = false);
/**
* Prepares the value for exporting to Excel
*
* @param object $item the db-object from feedback_item
* @param object $value object with item-related value from feedback_values in the 'value' property
* @return string
*/
abstract public function get_printval($item, $value);
/**
* Returns the formatted name of the item for the complete form or response view
*
* @param stdClass $item
* @param bool $withpostfix
* @return string
*/
public function get_display_name($item, $withpostfix = true) {
return format_text($item->name, FORMAT_HTML, array('noclean' => true, 'para' => false)) .
($withpostfix ? $this->get_display_name_postfix($item) : '');
}
/**
* Returns the postfix to be appended to the display name that is based on other settings
*
* @param stdClass $item
* @return string
*/
public function get_display_name_postfix($item) {
return '';
}
/**
* Adds an input element to the complete form
*
* This method is called:
* - to display the form when user completes feedback
* - to display existing elements when teacher edits the feedback items
* - to display the feedback preview (print.php)
* - to display the completed response
* - to preview a feedback template
*
* If it is important which mode the form is in, use $form->get_mode()
*
* Each item type must add a single form element with the name $item->typ.'_'.$item->id
* This element must always be present in form data even if nothing is selected (i.e. use advcheckbox and not checkbox).
* To add an element use either:
* $form->add_form_element() - adds a single element to the form
* $form->add_form_group_element() - adds a group element to the form
*
* Other useful methods:
* $form->get_item_value()
* $form->set_element_default()
* $form->add_validation_rule()
* $form->set_element_type()
*
* The element must support freezing so it can be used for viewing the response as well.
* If the desired form element does not support freezing, check $form->is_frozen()
* and create a static element instead.
*
* @param stdClass $item
* @param mod_feedback_complete_form $form
*/
abstract public function complete_form_element($item, $form);
/**
* Returns the list of actions allowed on this item in the edit mode
*
* @param stdClass $item
* @param stdClass $feedback
* @param cm_info $cm
* @return action_menu_link[]
*/
public function edit_actions($item, $feedback, $cm) {
$actions = array();
$strupdate = get_string('edit_item', 'feedback');
$actions['update'] = new action_menu_link_secondary(
new moodle_url('/mod/feedback/edit_item.php', array('id' => $item->id)),
new pix_icon('t/edit', $strupdate, 'moodle', array('class' => 'iconsmall', 'title' => '')),
$strupdate,
array('class' => 'editing_update', 'data-action' => 'update')
);
if ($this->can_switch_require()) {
if ($item->required == 1) {
$buttontitle = get_string('switch_item_to_not_required', 'feedback');
$buttonimg = 'required';
} else {
$buttontitle = get_string('switch_item_to_required', 'feedback');
$buttonimg = 'notrequired';
}
$actions['required'] = new action_menu_link_secondary(
new moodle_url('/mod/feedback/edit.php', array('id' => $cm->id,
'switchitemrequired' => $item->id, 'sesskey' => sesskey())),
new pix_icon($buttonimg, $buttontitle, 'feedback', array('class' => 'iconsmall', 'title' => '')),
$buttontitle,
array('class' => 'editing_togglerequired', 'data-action' => 'togglerequired')
);
}
$strdelete = get_string('delete_item', 'feedback');
$actions['delete'] = new action_menu_link_secondary(
new moodle_url('/mod/feedback/edit.php', array('id' => $cm->id, 'deleteitem' => $item->id, 'sesskey' => sesskey())),
new pix_icon('t/delete', $strdelete, 'moodle', array('class' => 'iconsmall', 'title' => '')),
$strdelete,
array('class' => 'editing_delete', 'data-action' => 'delete')
);
return $actions;
}
/**
* Return extra data for external functions.
*
* Some items may have additional configuration data or default values that should be returned for external functions:
* - Info elements: The default value information (course or category name)
* - Captcha: The recaptcha challenge hash key
*
* @param stdClass $item the item object
* @return str the data, may be json_encoded for large structures
*/
public function get_data_for_external($item) {
return null;
}
/**
* Return the analysis data ready for external functions.
*
* @param stdClass $item the item (question) information
* @param int $groupid the group id to filter data (optional)
* @param int $courseid the course id (optional)
* @return array an array of data with non scalar types json encoded
* @since Moodle 3.3
*/
abstract public function get_analysed_for_external($item, $groupid = false, $courseid = false);
}
//a dummy class to realize pagebreaks
class feedback_item_pagebreak extends feedback_item_base {
protected $type = "pagebreak";
public function show_editform() {
}
/**
* Checks if the editing form was cancelled
* @return bool
*/
public function is_cancelled() {
}
public function get_data() {
}
public function build_editform($item, $feedback, $cm) {
}
public function save_item() {
}
public function create_value($data) {
}
public function get_hasvalue() {
return 0;
}
public function excelprint_item(&$worksheet, $row_offset,
$xls_formats, $item,
$groupid, $courseid = false) {
}
public function print_analysed($item, $itemnr = '', $groupid = false, $courseid = false) {
}
public function get_printval($item, $value) {
}
public function can_switch_require() {
return false;
}
/**
* Adds an input element to the complete form
*
* @param stdClass $item
* @param mod_feedback_complete_form $form
*/
public function complete_form_element($item, $form) {
$form->add_form_element($item,
['static',
$item->typ.'_'.$item->id,
'',
html_writer::empty_tag('hr', ['class' => 'feedback_pagebreak', 'id' => 'feedback_item_' . $item->id])
]);
}
/**
* Returns the list of actions allowed on this item in the edit mode
*
* @param stdClass $item
* @param stdClass $feedback
* @param cm_info $cm
* @return action_menu_link[]
*/
public function edit_actions($item, $feedback, $cm) {
$actions = array();
$strdelete = get_string('delete_pagebreak', 'feedback');
$actions['delete'] = new action_menu_link_secondary(
new moodle_url('/mod/feedback/edit.php', array('id' => $cm->id, 'deleteitem' => $item->id, 'sesskey' => sesskey())),
new pix_icon('t/delete', $strdelete, 'moodle', array('class' => 'iconsmall', 'title' => '')),
$strdelete,
array('class' => 'editing_delete', 'data-action' => 'delete')
);
return $actions;
}
/**
* Return the analysis data ready for external functions.
*
* @param stdClass $item the item (question) information
* @param int $groupid the group id to filter data (optional)
* @param int $courseid the course id (optional)
* @return array an array of data with non scalar types json encoded
* @since Moodle 3.3
*/
public function get_analysed_for_external($item, $groupid = false, $courseid = false) {
return;
}
}
@@ -0,0 +1,131 @@
<?php
// 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/>.
require_once($CFG->libdir.'/formslib.php');
define('FEEDBACK_ITEM_NAME_TEXTBOX_SIZE', 80);
define('FEEDBACK_ITEM_LABEL_TEXTBOX_SIZE', 20);
abstract class feedback_item_form extends moodleform {
/** @var string type value in the hidden element. */
protected $type;
public function definition() {
$item = $this->_customdata['item']; //the item object
//common is an array like:
// array('cmid'=>$cm->id,
// 'id'=>isset($item->id) ? $item->id : NULL,
// 'typ'=>$item->typ,
// 'items'=>$feedbackitems,
// 'feedback'=>$feedback->id);
$common = $this->_customdata['common'];
//positionlist is an array with possible positions for the item location
$positionlist = $this->_customdata['positionlist'];
//the current position of the item
$position = $this->_customdata['position'];
$mform =& $this->_form;
if (array_filter(array_keys($common['items']))) {
$mform->addElement('select',
'dependitem',
get_string('dependitem', 'feedback').'&nbsp;',
$common['items']
);
$mform->addHelpButton('dependitem', 'depending', 'feedback');
$mform->addElement('text',
'dependvalue',
get_string('dependvalue', 'feedback'),
array('size'=>FEEDBACK_ITEM_LABEL_TEXTBOX_SIZE, 'maxlength'=>255));
$mform->hideIf('dependvalue', 'dependitem', 'eq', '0');
} else {
$mform->addElement('hidden', 'dependitem', 0);
$mform->addElement('hidden', 'dependvalue', '');
}
$mform->setType('dependitem', PARAM_INT);
$mform->setType('dependvalue', PARAM_RAW);
$position_select = $mform->addElement('select',
'position',
get_string('position', 'feedback').'&nbsp;',
$positionlist);
$position_select->setValue($position);
$mform->addElement('hidden', 'cmid', $common['cmid']);
$mform->setType('cmid', PARAM_INT);
$mform->addElement('hidden', 'id', $common['id']);
$mform->setType('id', PARAM_INT);
$mform->addElement('hidden', 'feedback', $common['feedback']);
$mform->setType('feedback', PARAM_INT);
$mform->addElement('hidden', 'template', 0);
$mform->setType('template', PARAM_INT);
$mform->setType('name', PARAM_RAW);
$mform->setType('label', PARAM_NOTAGS);
$mform->addElement('hidden', 'typ', $this->type);
$mform->setType('typ', PARAM_ALPHA);
$mform->addElement('hidden', 'hasvalue', 0);
$mform->setType('hasvalue', PARAM_INT);
$mform->addElement('hidden', 'options', '');
$mform->setType('options', PARAM_ALPHA);
$buttonarray = array();
if (!empty($item->id)) {
$buttonarray[] = &$mform->createElement('submit',
'update_item',
get_string('update_item', 'feedback'));
$buttonarray[] = &$mform->createElement('submit',
'clone_item',
get_string('save_as_new_item', 'feedback'));
} else {
$mform->addElement('hidden', 'clone_item', 0);
$mform->setType('clone_item', PARAM_INT);
$buttonarray[] = &$mform->createElement('submit',
'save_item',
get_string('savechanges'));
}
$buttonarray[] = &$mform->createElement('cancel');
$mform->addGroup($buttonarray, 'buttonar', '&nbsp;', array(' '), false);
}
/**
* Return submitted data if properly submitted or returns NULL if validation fails or
* if there is no submitted data.
*
* @return object submitted data; NULL if not valid or not submitted or cancelled
*/
public function get_data() {
if ($item = parent::get_data()) {
if (!isset($item->dependvalue)) {
$item->dependvalue = '';
}
}
return $item;
}
}
+58
View File
@@ -0,0 +1,58 @@
<?php
// 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/>.
require_once($CFG->dirroot.'/mod/feedback/item/feedback_item_form_class.php');
class feedback_info_form extends feedback_item_form {
protected $type = "info";
/** @var object Form element. */
protected $infotype;
public function definition() {
$item = $this->_customdata['item'];
$common = $this->_customdata['common'];
$positionlist = $this->_customdata['positionlist'];
$position = $this->_customdata['position'];
$presentationoptions = $this->_customdata['presentationoptions'];
$mform =& $this->_form;
$mform->addElement('header', 'general', get_string($this->type, 'feedback'));
$mform->addElement('hidden', 'required', 0);
$mform->setType('required', PARAM_INT);
$mform->addElement('text',
'name',
get_string('item_name', 'feedback'),
array('size'=>FEEDBACK_ITEM_NAME_TEXTBOX_SIZE, 'maxlength'=>255));
$mform->addElement('text',
'label',
get_string('item_label', 'feedback'),
array('size'=>FEEDBACK_ITEM_LABEL_TEXTBOX_SIZE, 'maxlength'=>255));
$this->infotype = &$mform->addElement('select',
'presentation',
get_string('infotype', 'feedback'),
$presentationoptions);
parent::definition();
$this->set_data($item);
}
}
+322
View File
@@ -0,0 +1,322 @@
<?php
// 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/>.
defined('MOODLE_INTERNAL') OR die('not allowed');
require_once($CFG->dirroot.'/mod/feedback/item/feedback_item_class.php');
class feedback_item_info extends feedback_item_base {
protected $type = "info";
/** Mode recording response time (for non-anonymous feedbacks only) */
const MODE_RESPONSETIME = 1;
/** Mode recording current course */
const MODE_COURSE = 2;
/** Mode recording current course category */
const MODE_CATEGORY = 3;
/** Special constant to keep the current timestamp as value for the form element */
const CURRENTTIMESTAMP = '__CURRENT__TIMESTAMP__';
public function build_editform($item, $feedback, $cm) {
global $DB, $CFG;
require_once('info_form.php');
//get the lastposition number of the feedback_items
$position = $item->position;
$lastposition = $DB->count_records('feedback_item', array('feedback'=>$feedback->id));
if ($position == -1) {
$i_formselect_last = $lastposition + 1;
$i_formselect_value = $lastposition + 1;
$item->position = $lastposition + 1;
} else {
$i_formselect_last = $lastposition;
$i_formselect_value = $item->position;
}
//the elements for position dropdownlist
$positionlist = array_slice(range(0, $i_formselect_last), 1, $i_formselect_last, true);
$item->presentation = empty($item->presentation) ? self::MODE_COURSE : $item->presentation;
$item->required = 0;
//all items for dependitem
$feedbackitems = feedback_get_depend_candidates_for_item($feedback, $item);
$commonparams = array('cmid'=>$cm->id,
'id'=>isset($item->id) ? $item->id : null,
'typ'=>$item->typ,
'items'=>$feedbackitems,
'feedback'=>$feedback->id);
// Options for the 'presentation' select element.
$presentationoptions = array();
if ($feedback->anonymous == FEEDBACK_ANONYMOUS_NO || $item->presentation == self::MODE_RESPONSETIME) {
// "Response time" is hidden anyway in case of anonymous feedback, no reason to offer this option.
// However if it was already selected leave it in the dropdown.
$presentationoptions[self::MODE_RESPONSETIME] = get_string('responsetime', 'feedback');
}
$presentationoptions[self::MODE_COURSE] = get_string('course');
$presentationoptions[self::MODE_CATEGORY] = get_string('coursecategory');
//build the form
$this->item_form = new feedback_info_form('edit_item.php',
array('item'=>$item,
'common'=>$commonparams,
'positionlist'=>$positionlist,
'position' => $position,
'presentationoptions' => $presentationoptions));
}
public function save_item() {
global $DB;
if (!$this->get_data()) {
return false;
}
$item = $this->item;
if (isset($item->clone_item) AND $item->clone_item) {
$item->id = ''; //to clone this item
$item->position++;
}
$item->hasvalue = $this->get_hasvalue();
if (!$item->id) {
$item->id = $DB->insert_record('feedback_item', $item);
} else {
$DB->update_record('feedback_item', $item);
}
return $DB->get_record('feedback_item', array('id'=>$item->id));
}
/**
* Helper function for collected data, both for analysis page and export to excel
*
* @param stdClass $item the db-object from feedback_item
* @param int|false $groupid
* @param int $courseid
* @return stdClass
*/
protected function get_analysed($item, $groupid = false, $courseid = false) {
$presentation = $item->presentation;
$analysed_val = new stdClass();
$analysed_val->data = null;
$analysed_val->name = $item->name;
$values = feedback_get_group_values($item, $groupid, $courseid);
if ($values) {
$data = array();
foreach ($values as $value) {
$datavalue = new stdClass();
switch($presentation) {
case self::MODE_RESPONSETIME:
$datavalue->value = $value->value;
$datavalue->show = $value->value ? userdate($datavalue->value) : '';
break;
case self::MODE_COURSE:
$datavalue->value = $value->value;
$datavalue->show = $datavalue->value;
break;
case self::MODE_CATEGORY:
$datavalue->value = $value->value;
$datavalue->show = $datavalue->value;
break;
}
$data[] = $datavalue;
}
$analysed_val->data = $data;
}
return $analysed_val;
}
public function get_printval($item, $value) {
if (strval($value->value) === '') {
return '';
}
return $item->presentation == self::MODE_RESPONSETIME ?
userdate($value->value) : $value->value;
}
public function print_analysed($item, $itemnr = '', $groupid = false, $courseid = false) {
echo "<table class=\"analysis itemtype_{$item->typ}\">";
$analysed_item = $this->get_analysed($item, $groupid, $courseid);
$data = $analysed_item->data;
if (is_array($data)) {
echo '<tr><th class="text-left">';
echo $itemnr . ' ';
if (strval($item->label) !== '') {
echo '('. format_string($item->label).') ';
}
echo format_text($item->name, FORMAT_HTML, array('noclean' => true, 'para' => false));
echo '</th></tr>';
$sizeofdata = count($data);
for ($i = 0; $i < $sizeofdata; $i++) {
$class = strlen(trim($data[$i]->show)) ? '' : ' class="isempty"';
echo '<tr'.$class.'><td class="singlevalue">';
echo str_replace("\n", '<br />', $data[$i]->show);
echo '</td></tr>';
}
}
echo '</table>';
}
public function excelprint_item(&$worksheet, $row_offset,
$xls_formats, $item,
$groupid, $courseid = false) {
$analysed_item = $this->get_analysed($item, $groupid, $courseid);
$worksheet->write_string($row_offset, 0, $item->label, $xls_formats->head2);
$worksheet->write_string($row_offset, 1, $item->name, $xls_formats->head2);
$data = $analysed_item->data;
if (is_array($data)) {
$worksheet->write_string($row_offset, 2, $data[0]->show, $xls_formats->value_bold);
$row_offset++;
$sizeofdata = count($data);
for ($i = 1; $i < $sizeofdata; $i++) {
$worksheet->write_string($row_offset, 2, $data[$i]->show, $xls_formats->default);
$row_offset++;
}
}
$row_offset++;
return $row_offset;
}
/**
* Calculates the value of the item (time, course, course category)
*
* @param stdClass $item
* @param stdClass $feedback
* @param int $courseid
* @return string
*/
protected function get_current_value($item, $feedback, $courseid) {
global $DB;
switch ($item->presentation) {
case self::MODE_RESPONSETIME:
if ($feedback->anonymous != FEEDBACK_ANONYMOUS_YES) {
// Response time is not allowed in anonymous feedbacks.
return time();
}
break;
case self::MODE_COURSE:
$course = get_course($courseid);
return format_string($course->shortname, true,
array('context' => context_course::instance($course->id)));
break;
case self::MODE_CATEGORY:
if ($courseid !== SITEID) {
$coursecategory = $DB->get_record_sql('SELECT cc.id, cc.name FROM {course_categories} cc, {course} c '
. 'WHERE c.category = cc.id AND c.id = ?', array($courseid));
return format_string($coursecategory->name, true,
array('context' => context_coursecat::instance($coursecategory->id)));
}
break;
}
return '';
}
/**
* Adds an input element to the complete form
*
* @param stdClass $item
* @param mod_feedback_complete_form $form
*/
public function complete_form_element($item, $form) {
if ($form->get_mode() == mod_feedback_complete_form::MODE_VIEW_RESPONSE) {
$value = strval($form->get_item_value($item));
} else {
$value = $this->get_current_value($item,
$form->get_feedback(), $form->get_current_course_id());
}
$printval = $this->get_printval($item, (object)['value' => $value]);
$class = '';
switch ($item->presentation) {
case self::MODE_RESPONSETIME:
$class = 'info-responsetime';
$value = $value ? self::CURRENTTIMESTAMP : '';
break;
case self::MODE_COURSE:
$class = 'info-course';
break;
case self::MODE_CATEGORY:
$class = 'info-category';
break;
}
$name = $this->get_display_name($item);
$inputname = $item->typ . '_' . $item->id;
$element = $form->add_form_element($item,
['select', $inputname, $name,
array($value => $printval),
array('class' => $class)],
false,
false);
$form->set_element_default($inputname, $value);
$element->freeze();
if ($form->get_mode() == mod_feedback_complete_form::MODE_COMPLETE) {
$element->setPersistantFreeze(true);
}
}
/**
* Converts the value from complete_form data to the string value that is stored in the db.
* @param mixed $value element from mod_feedback_complete_form::get_data() with the name $item->typ.'_'.$item->id
* @return string
*/
public function create_value($value) {
if ($value === self::CURRENTTIMESTAMP) {
return strval(time());
}
return parent::create_value($value);
}
public function can_switch_require() {
return false;
}
public function get_data_for_external($item) {
global $DB;
$feedback = $DB->get_record('feedback', array('id' => $item->feedback), '*', MUST_EXIST);
// Return the default value (course name, category name or timestamp).
return $this->get_current_value($item, $feedback, $feedback->course);
}
/**
* Return the analysis data ready for external functions.
*
* @param stdClass $item the item (question) information
* @param int $groupid the group id to filter data (optional)
* @param int $courseid the course id (optional)
* @return array an array of data with non scalar types json encoded
* @since Moodle 3.3
*/
public function get_analysed_for_external($item, $groupid = false, $courseid = false) {
$externaldata = array();
$data = $this->get_analysed($item, $groupid, $courseid);
if (is_array($data->data)) {
foreach ($data->data as $d) {
$externaldata[] = json_encode($d);
}
}
return $externaldata;
}
}
+51
View File
@@ -0,0 +1,51 @@
<?php
// 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/>.
require_once($CFG->dirroot.'/mod/feedback/item/feedback_item_form_class.php');
class feedback_label_form extends feedback_item_form {
protected $type = "label";
private $area;
public function definition() {
global $CFG;
$item = $this->_customdata['item'];
$common = $this->_customdata['common'];
$presentationoptions = $this->_customdata['presentationoptions'];
$positionlist = $this->_customdata['positionlist'];
$position = $this->_customdata['position'];
$mform =& $this->_form;
$mform->addElement('hidden', 'required', 0);
$mform->setType('required', PARAM_INT);
$mform->addElement('hidden', 'name', 'label');
$mform->setType('template', PARAM_ALPHA);
$mform->addElement('hidden', 'label', '');
$mform->setType('label', PARAM_ALPHA);
$mform->addElement('header', 'general', get_string($this->type, 'feedback'));
$mform->addElement('editor', 'presentation_editor', get_string('labelcontents', 'feedback'), null, $presentationoptions);
$mform->setType('presentation_editor', PARAM_RAW);
parent::definition();
$this->set_data($item);
}
}
+259
View File
@@ -0,0 +1,259 @@
<?php
// 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/>.
defined('MOODLE_INTERNAL') OR die('not allowed');
require_once($CFG->dirroot.'/mod/feedback/item/feedback_item_class.php');
require_once($CFG->libdir.'/formslib.php');
class feedback_item_label extends feedback_item_base {
protected $type = "label";
private $presentationoptions = null;
private $context;
/**
* Constructor
*/
public function __construct() {
$this->presentationoptions = array('maxfiles' => EDITOR_UNLIMITED_FILES,
'trusttext'=>true);
}
public function build_editform($item, $feedback, $cm) {
global $DB, $CFG;
require_once('label_form.php');
//get the lastposition number of the feedback_items
$position = $item->position;
$lastposition = $DB->count_records('feedback_item', array('feedback'=>$feedback->id));
if ($position == -1) {
$i_formselect_last = $lastposition + 1;
$i_formselect_value = $lastposition + 1;
$item->position = $lastposition + 1;
} else {
$i_formselect_last = $lastposition;
$i_formselect_value = $item->position;
}
//the elements for position dropdownlist
$positionlist = array_slice(range(0, $i_formselect_last), 1, $i_formselect_last, true);
//all items for dependitem
$feedbackitems = feedback_get_depend_candidates_for_item($feedback, $item);
$commonparams = array('cmid'=>$cm->id,
'id'=>isset($item->id) ? $item->id : null,
'typ'=>$item->typ,
'items'=>$feedbackitems,
'feedback'=>$feedback->id);
$this->context = context_module::instance($cm->id);
//preparing the editor for new file-api
$item->presentationformat = FORMAT_HTML;
$item->presentationtrust = 1;
// Append editor context to presentation options, giving preference to existing context.
$this->presentationoptions = array_merge(array('context' => $this->context),
$this->presentationoptions);
$item = file_prepare_standard_editor($item,
'presentation', //name of the form element
$this->presentationoptions,
$this->context,
'mod_feedback',
'item', //the filearea
$item->id);
//build the form
$customdata = array('item' => $item,
'common' => $commonparams,
'positionlist' => $positionlist,
'position' => $position,
'presentationoptions' => $this->presentationoptions);
$this->item_form = new feedback_label_form('edit_item.php', $customdata);
}
public function save_item() {
global $DB;
if (!$this->get_data()) {
return false;
}
$item = $this->item;
if (isset($item->clone_item) AND $item->clone_item) {
$item->id = ''; //to clone this item
$item->position++;
}
$item->presentation = '';
$item->hasvalue = $this->get_hasvalue();
if (!$item->id) {
$item->id = $DB->insert_record('feedback_item', $item);
} else {
$DB->update_record('feedback_item', $item);
}
$item = file_postupdate_standard_editor($item,
'presentation',
$this->presentationoptions,
$this->context,
'mod_feedback',
'item',
$item->id);
$DB->update_record('feedback_item', $item);
return $DB->get_record('feedback_item', array('id'=>$item->id));
}
/**
* prepares the item for output or export to file
* @param stdClass $item
* @return string
*/
private function print_item($item) {
global $DB, $CFG;
require_once($CFG->libdir . '/filelib.php');
//is the item a template?
if (!$item->feedback AND $item->template) {
$template = $DB->get_record('feedback_template', array('id'=>$item->template));
if ($template->ispublic) {
$context = context_system::instance();
} else {
$context = context_course::instance($template->course);
}
$filearea = 'template';
} else {
$cm = get_coursemodule_from_instance('feedback', $item->feedback);
$context = context_module::instance($cm->id);
$filearea = 'item';
}
$item->presentationformat = FORMAT_HTML;
$item->presentationtrust = 1;
$output = file_rewrite_pluginfile_urls($item->presentation,
'pluginfile.php',
$context->id,
'mod_feedback',
$filearea,
$item->id);
$formatoptions = array('overflowdiv'=>true, 'trusted'=>$CFG->enabletrusttext);
echo format_text($output, FORMAT_HTML, $formatoptions);
}
/**
* @param stdClass $item
* @param bool|true $withpostfix
* @return string
*/
public function get_display_name($item, $withpostfix = true) {
return '';
}
/**
* Adds an input element to the complete form
*
* @param stdClass $item
* @param mod_feedback_complete_form $form
*/
public function complete_form_element($item, $form) {
global $DB;
if (!$item->feedback AND $item->template) {
// This is a template.
$template = $DB->get_record('feedback_template', array('id' => $item->template));
if ($template->ispublic) {
$context = context_system::instance();
} else {
$context = context_course::instance($template->course);
}
$filearea = 'template';
} else {
// This is a question in the current feedback.
$context = $form->get_cm()->context;
$filearea = 'item';
}
$output = file_rewrite_pluginfile_urls($item->presentation, 'pluginfile.php',
$context->id, 'mod_feedback', $filearea, $item->id);
$formatoptions = array('overflowdiv' => true, 'noclean' => true);
$output = format_text($output, FORMAT_HTML, $formatoptions);
$output = html_writer::div($output, '', ['id' => 'feedback_item_' . $item->id]);
$inputname = $item->typ . '_' . $item->id;
$name = $this->get_display_name($item);
$form->add_form_element($item, ['static', $inputname, $name, $output], false, false);
}
public function compare_value($item, $dbvalue, $dependvalue) {
return false;
}
public function postupdate($item) {
global $DB;
$context = context_module::instance($item->cmid);
$item = file_postupdate_standard_editor($item,
'presentation',
$this->presentationoptions,
$context,
'mod_feedback',
'item',
$item->id);
$DB->update_record('feedback_item', $item);
return $item->id;
}
public function get_hasvalue() {
return 0;
}
public function can_switch_require() {
return false;
}
public function excelprint_item(&$worksheet,
$row_offset,
$xls_formats,
$item,
$groupid,
$courseid = false) {
}
public function print_analysed($item, $itemnr = '', $groupid = false, $courseid = false) {
}
public function get_printval($item, $value) {
}
/**
* Return the analysis data ready for external functions.
*
* @param stdClass $item the item (question) information
* @param int $groupid the group id to filter data (optional)
* @param int $courseid the course id (optional)
* @return array an array of data with non scalar types json encoded
* @since Moodle 3.3
*/
public function get_analysed_for_external($item, $groupid = false, $courseid = false) {
return [];
}
}
+516
View File
@@ -0,0 +1,516 @@
<?php
// 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/>.
defined('MOODLE_INTERNAL') OR die('not allowed');
require_once($CFG->dirroot.'/mod/feedback/item/feedback_item_class.php');
define('FEEDBACK_MULTICHOICE_TYPE_SEP', '>>>>>');
define('FEEDBACK_MULTICHOICE_LINE_SEP', '|');
define('FEEDBACK_MULTICHOICE_ADJUST_SEP', '<<<<<');
define('FEEDBACK_MULTICHOICE_IGNOREEMPTY', 'i');
define('FEEDBACK_MULTICHOICE_HIDENOSELECT', 'h');
class feedback_item_multichoice extends feedback_item_base {
protected $type = "multichoice";
public function build_editform($item, $feedback, $cm) {
global $DB, $CFG;
require_once('multichoice_form.php');
//get the lastposition number of the feedback_items
$position = $item->position;
$lastposition = $DB->count_records('feedback_item', array('feedback'=>$feedback->id));
if ($position == -1) {
$i_formselect_last = $lastposition + 1;
$i_formselect_value = $lastposition + 1;
$item->position = $lastposition + 1;
} else {
$i_formselect_last = $lastposition;
$i_formselect_value = $item->position;
}
//the elements for position dropdownlist
$positionlist = array_slice(range(0, $i_formselect_last), 1, $i_formselect_last, true);
$item->presentation = empty($item->presentation) ? '' : $item->presentation;
$info = $this->get_info($item);
$item->ignoreempty = $this->ignoreempty($item);
$item->hidenoselect = $this->hidenoselect($item);
//all items for dependitem
$feedbackitems = feedback_get_depend_candidates_for_item($feedback, $item);
$commonparams = array('cmid'=>$cm->id,
'id'=>isset($item->id) ? $item->id : null,
'typ'=>$item->typ,
'items'=>$feedbackitems,
'feedback'=>$feedback->id);
//build the form
$customdata = array('item' => $item,
'common' => $commonparams,
'positionlist' => $positionlist,
'position' => $position,
'info' => $info);
$this->item_form = new feedback_multichoice_form('edit_item.php', $customdata);
}
public function save_item() {
global $DB;
if (!$this->get_data()) {
return false;
}
$item = $this->item;
if (isset($item->clone_item) AND $item->clone_item) {
$item->id = ''; //to clone this item
$item->position++;
}
$this->set_ignoreempty($item, $item->ignoreempty);
$this->set_hidenoselect($item, $item->hidenoselect);
$item->hasvalue = $this->get_hasvalue();
if (!$item->id) {
$item->id = $DB->insert_record('feedback_item', $item);
} else {
$DB->update_record('feedback_item', $item);
}
return $DB->get_record('feedback_item', array('id'=>$item->id));
}
//gets an array with three values(typ, name, XXX)
//XXX is an object with answertext, answercount and quotient
/**
* Helper function for collected data, both for analysis page and export to excel
*
* @param stdClass $item the db-object from feedback_item
* @param int $groupid
* @param int $courseid
* @return array|null
*/
protected function get_analysed($item, $groupid = false, $courseid = false) {
$info = $this->get_info($item);
$analysed_item = array();
$analysed_item[] = $item->typ;
$analysed_item[] = format_string($item->name);
//get the possible answers
$answers = null;
$answers = explode (FEEDBACK_MULTICHOICE_LINE_SEP, $info->presentation);
if (!is_array($answers)) {
return null;
}
//get the values
$values = feedback_get_group_values($item, $groupid, $courseid, $this->ignoreempty($item));
if (!$values) {
return null;
}
//get answertext, answercount and quotient for each answer
$analysed_answer = array();
if ($info->subtype == 'c') {
$sizeofanswers = count($answers);
for ($i = 1; $i <= $sizeofanswers; $i++) {
$ans = new stdClass();
$ans->answertext = $answers[$i-1];
$ans->answercount = 0;
foreach ($values as $value) {
//ist die Antwort gleich dem index der Antworten + 1?
$vallist = explode(FEEDBACK_MULTICHOICE_LINE_SEP, $value->value);
foreach ($vallist as $val) {
if ($val == $i) {
$ans->answercount++;
}
}
}
$ans->quotient = $ans->answercount / count($values);
$analysed_answer[] = $ans;
}
} else {
$sizeofanswers = count($answers);
for ($i = 1; $i <= $sizeofanswers; $i++) {
$ans = new stdClass();
$ans->answertext = $answers[$i-1];
$ans->answercount = 0;
foreach ($values as $value) {
//ist die Antwort gleich dem index der Antworten + 1?
if ($value->value == $i) {
$ans->answercount++;
}
}
$ans->quotient = $ans->answercount / count($values);
$analysed_answer[] = $ans;
}
}
$analysed_item[] = $analysed_answer;
return $analysed_item;
}
public function get_printval($item, $value) {
$info = $this->get_info($item);
$printval = '';
if (!isset($value->value)) {
return $printval;
}
$presentation = explode (FEEDBACK_MULTICHOICE_LINE_SEP, $info->presentation);
if ($info->subtype == 'c') {
$vallist = array_values(explode (FEEDBACK_MULTICHOICE_LINE_SEP, $value->value));
$sizeofvallist = count($vallist);
$sizeofpresentation = count($presentation);
for ($i = 0; $i < $sizeofvallist; $i++) {
for ($k = 0; $k < $sizeofpresentation; $k++) {
if ($vallist[$i] == ($k + 1)) {//Die Werte beginnen bei 1, das Array aber mit 0
$printval .= trim(format_string($presentation[$k])) . chr(10);
break;
}
}
}
} else {
$index = 1;
foreach ($presentation as $pres) {
if ($value->value == $index) {
$printval = format_string($pres);
break;
}
$index++;
}
}
return $printval;
}
public function print_analysed($item, $itemnr = '', $groupid = false, $courseid = false) {
global $OUTPUT;
$analysed_item = $this->get_analysed($item, $groupid, $courseid);
if ($analysed_item) {
$itemname = $analysed_item[1];
echo "<table class=\"analysis itemtype_{$item->typ}\">";
echo '<tr><th class="text-left">';
echo $itemnr . ' ';
if (strval($item->label) !== '') {
echo '('. format_string($item->label).') ';
}
echo format_string($itemname);
echo '</th></tr>';
$analysed_vals = $analysed_item[2];
$count = 0;
$data = [];
foreach ($analysed_vals as $val) {
$quotient = format_float($val->quotient * 100, 2);
$strquotient = '';
if ($val->quotient > 0) {
$strquotient = ' ('. $quotient . ' %)';
}
$answertext = format_text(trim($val->answertext), FORMAT_HTML,
array('noclean' => true, 'para' => false));
$data['labels'][$count] = $answertext;
$data['series'][$count] = $val->answercount;
$data['series_labels'][$count] = $val->answercount . $strquotient;
$count++;
}
$chart = new \core\chart_bar();
$chart->set_horizontal(true);
$series = new \core\chart_series(format_string(get_string("responses", "feedback")), $data['series']);
$series->set_labels($data['series_labels']);
$chart->add_series($series);
$chart->set_labels($data['labels']);
echo '<tr><td>'. $OUTPUT->render($chart) . '</td></tr>';
echo "</table>";
}
}
public function excelprint_item(&$worksheet, $row_offset,
$xls_formats, $item,
$groupid, $courseid = false) {
$analysed_item = $this->get_analysed($item, $groupid, $courseid);
if (!$analysed_item) {
return $row_offset;
}
$data = $analysed_item[2];
//frage schreiben
$worksheet->write_string($row_offset, 0, $item->label, $xls_formats->head2);
$worksheet->write_string($row_offset, 1, $analysed_item[1], $xls_formats->head2);
if (is_array($data)) {
$sizeofdata = count($data);
for ($i = 0; $i < $sizeofdata; $i++) {
$analysed_data = $data[$i];
$worksheet->write_string($row_offset,
$i + 2,
trim($analysed_data->answertext),
$xls_formats->head2);
$worksheet->write_number($row_offset + 1,
$i + 2,
$analysed_data->answercount,
$xls_formats->default);
$worksheet->write_number($row_offset + 2,
$i + 2,
$analysed_data->quotient,
$xls_formats->procent);
}
}
$row_offset += 3;
return $row_offset;
}
/**
* Options for the multichoice element
* @param stdClass $item
* @return array
*/
protected function get_options($item) {
$info = $this->get_info($item);
$presentation = explode (FEEDBACK_MULTICHOICE_LINE_SEP, $info->presentation);
$options = array();
foreach ($presentation as $idx => $optiontext) {
$options[$idx + 1] = format_text($optiontext, FORMAT_HTML, array('noclean' => true, 'para' => false));
}
if ($info->subtype === 'r' && !$this->hidenoselect($item)) {
$options = array(0 => get_string('not_selected', 'feedback')) + $options;
}
return $options;
}
/**
* Adds an input element to the complete form
*
* This element has many options - it can be displayed as group or radio elements,
* group of checkboxes or a dropdown list.
*
* @param stdClass $item
* @param mod_feedback_complete_form $form
*/
public function complete_form_element($item, $form) {
$info = $this->get_info($item);
$name = $this->get_display_name($item);
$class = 'multichoice-' . $info->subtype;
$inputname = $item->typ . '_' . $item->id;
$options = $this->get_options($item);
$separator = !empty($info->horizontal) ? ' ' : '<br>';
$tmpvalue = $form->get_item_value($item) ?? 0; // Used for element defaults, so must be a valid value (not null).
// Subtypes:
// r = radio
// c = checkbox
// d = dropdown.
if ($info->subtype === 'd' || ($info->subtype === 'r' && $form->is_frozen())) {
// Display as a dropdown in the complete form or a single value in the response view.
$element = $form->add_form_element($item,
['select', $inputname, $name, array(0 => '') + $options, array('class' => $class)],
false, false);
$form->set_element_default($inputname, $tmpvalue);
$form->set_element_type($inputname, PARAM_INT);
} else if ($info->subtype === 'c' && $form->is_frozen()) {
// Display list of checkbox values in the response view.
$objs = [];
foreach (explode(FEEDBACK_MULTICHOICE_LINE_SEP, $form->get_item_value($item)) as $v) {
$objs[] = ['static', $inputname."[$v]", '', isset($options[$v]) ? $options[$v] : ''];
}
$element = $form->add_form_group_element($item, 'group_'.$inputname, $name, $objs, $separator, $class);
} else {
// Display group or radio or checkbox elements.
$class .= ' multichoice-' . ($info->horizontal ? 'horizontal' : 'vertical');
$objs = [];
if ($info->subtype === 'c') {
// Checkboxes.
$objs[] = ['hidden', $inputname.'[0]', 0];
$form->set_element_type($inputname.'[0]', PARAM_INT);
foreach ($options as $idx => $label) {
$objs[] = ['advcheckbox', $inputname.'['.$idx.']', '', $label, null, array(0, $idx)];
$form->set_element_type($inputname.'['.$idx.']', PARAM_INT);
}
// Span to hold the element id. The id is used for drag and drop reordering.
$objs[] = ['static', '', '', html_writer::span('', '', ['id' => 'feedback_item_' . $item->id])];
$element = $form->add_form_group_element($item, 'group_'.$inputname, $name, $objs, $separator, $class);
if ($tmpvalue) {
foreach (explode(FEEDBACK_MULTICHOICE_LINE_SEP, $tmpvalue) as $v) {
$form->set_element_default($inputname.'['.$v.']', $v);
}
}
} else {
// Radio.
if (!array_key_exists(0, $options)) {
// Always add a hidden element to the group to guarantee we get a value in the submit data.
$objs[] = ['hidden', $inputname, 0];
}
foreach ($options as $idx => $label) {
$objs[] = ['radio', $inputname, '', $label, $idx];
}
// Span to hold the element id. The id is used for drag and drop reordering.
$objs[] = ['static', '', '', html_writer::span('', '', ['id' => 'feedback_item_' . $item->id])];
$element = $form->add_form_group_element($item, 'group_'.$inputname, $name, $objs, $separator, $class);
$form->set_element_default($inputname, $tmpvalue);
$form->set_element_type($inputname, PARAM_INT);
}
}
// Process 'required' rule.
if ($item->required) {
$elementname = $element->getName();
$form->add_validation_rule(function($values) use ($elementname, $item) {
$inputname = $item->typ . '_' . $item->id;
return empty($values[$inputname]) || (is_array($values[$inputname]) && !array_filter($values[$inputname])) ?
array($elementname => get_string('required')) : true;
});
}
}
/**
* Prepares value that user put in the form for storing in DB
* @param array $value
* @return string
*/
public function create_value($value) {
// Could be an array (multichoice checkbox) or single value (multichoice radio or dropdown).
$value = is_array($value) ? $value : [$value];
$value = array_unique(array_filter($value));
return join(FEEDBACK_MULTICHOICE_LINE_SEP, $value);
}
/**
* Compares the dbvalue with the dependvalue
*
* @param stdClass $item
* @param string $dbvalue is the value input by user in the format as it is stored in the db
* @param string $dependvalue is the value that it needs to be compared against
*/
public function compare_value($item, $dbvalue, $dependvalue) {
if (is_array($dbvalue)) {
$dbvalues = $dbvalue;
} else {
$dbvalues = explode(FEEDBACK_MULTICHOICE_LINE_SEP, $dbvalue);
}
$info = $this->get_info($item);
$presentation = explode (FEEDBACK_MULTICHOICE_LINE_SEP, $info->presentation);
$index = 1;
foreach ($presentation as $pres) {
foreach ($dbvalues as $dbval) {
if ($dbval == $index AND trim($pres) == $dependvalue) {
return true;
}
}
$index++;
}
return false;
}
public function get_info($item) {
$presentation = empty($item->presentation) ? '' : $item->presentation;
$info = new stdClass();
//check the subtype of the multichoice
//it can be check(c), radio(r) or dropdown(d)
$info->subtype = '';
$info->presentation = '';
$info->horizontal = false;
$parts = explode(FEEDBACK_MULTICHOICE_TYPE_SEP, $item->presentation);
$info->subtype = $parts[0];
if (count($parts) > 1) {
$info->presentation = $parts[1];
}
if (!isset($info->subtype)) {
$info->subtype = 'r';
}
if ($info->subtype != 'd') {
$parts = explode(FEEDBACK_MULTICHOICE_ADJUST_SEP, $info->presentation);
$info->presentation = $parts[0];
if (count($parts) > 1) {
$info->horizontal = $parts[1];
}
if (isset($info->horizontal) AND $info->horizontal == 1) {
$info->horizontal = true;
} else {
$info->horizontal = false;
}
}
return $info;
}
public function set_ignoreempty($item, $ignoreempty=true) {
$item->options = str_replace(FEEDBACK_MULTICHOICE_IGNOREEMPTY, '', $item->options);
if ($ignoreempty) {
$item->options .= FEEDBACK_MULTICHOICE_IGNOREEMPTY;
}
}
public function ignoreempty($item) {
if (strstr($item->options, FEEDBACK_MULTICHOICE_IGNOREEMPTY)) {
return true;
}
return false;
}
public function set_hidenoselect($item, $hidenoselect=true) {
$item->options = str_replace(FEEDBACK_MULTICHOICE_HIDENOSELECT, '', $item->options);
if ($hidenoselect) {
$item->options .= FEEDBACK_MULTICHOICE_HIDENOSELECT;
}
}
public function hidenoselect($item) {
if (strstr($item->options, FEEDBACK_MULTICHOICE_HIDENOSELECT)) {
return true;
}
return false;
}
/**
* Return the analysis data ready for external functions.
*
* @param stdClass $item the item (question) information
* @param int $groupid the group id to filter data (optional)
* @param int $courseid the course id (optional)
* @return array an array of data with non scalar types json encoded
* @since Moodle 3.3
*/
public function get_analysed_for_external($item, $groupid = false, $courseid = false) {
$externaldata = array();
$data = $this->get_analysed($item, $groupid, $courseid);
if ($data && !empty($data[2]) && is_array($data[2])) {
foreach ($data[2] as $d) {
$externaldata[] = json_encode($d);
}
}
return $externaldata;
}
}
@@ -0,0 +1,117 @@
<?php
// 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/>.
require_once($CFG->dirroot.'/mod/feedback/item/feedback_item_form_class.php');
class feedback_multichoice_form extends feedback_item_form {
protected $type = "multichoice";
public function definition() {
$item = $this->_customdata['item'];
$common = $this->_customdata['common'];
$positionlist = $this->_customdata['positionlist'];
$position = $this->_customdata['position'];
$mform =& $this->_form;
$mform->addElement('header', 'general', get_string($this->type, 'feedback'));
$mform->addElement('advcheckbox', 'required', get_string('required', 'feedback'), '' , null , array(0, 1));
$mform->addElement('text',
'name',
get_string('item_name', 'feedback'),
array('size' => FEEDBACK_ITEM_NAME_TEXTBOX_SIZE,
'maxlength' => 255));
$mform->addElement('text',
'label',
get_string('item_label', 'feedback'),
array('size' => FEEDBACK_ITEM_LABEL_TEXTBOX_SIZE,
'maxlength' => 255));
$mform->addElement('select',
'subtype',
get_string('multichoicetype', 'feedback').'&nbsp;',
array('r'=>get_string('radio', 'feedback'),
'c'=>get_string('check', 'feedback'),
'd'=>get_string('dropdown', 'feedback')));
$mform->addElement('select',
'horizontal',
get_string('adjustment', 'feedback').'&nbsp;',
array(0 => get_string('vertical', 'feedback'),
1 => get_string('horizontal', 'feedback')));
$mform->hideIf('horizontal', 'subtype', 'eq', 'd');
$mform->addElement('selectyesno',
'hidenoselect',
get_string('hide_no_select_option', 'feedback'));
$mform->hideIf('hidenoselect', 'subtype', 'ne', 'r');
$mform->addElement('selectyesno',
'ignoreempty',
get_string('do_not_analyse_empty_submits', 'feedback'));
$mform->addElement('textarea', 'values', get_string('multichoice_values', 'feedback'),
'wrap="virtual" rows="10" cols="65"');
$mform->addElement('static', 'hint', '', get_string('use_one_line_for_each_value', 'feedback'));
parent::definition();
$this->set_data($item);
}
public function set_data($item) {
$info = $this->_customdata['info'];
$item->horizontal = $info->horizontal;
$item->subtype = $info->subtype;
$itemvalues = str_replace(FEEDBACK_MULTICHOICE_LINE_SEP, "\n", $info->presentation);
$itemvalues = str_replace("\n\n", "\n", $itemvalues);
$item->values = $itemvalues;
return parent::set_data($item);
}
public function get_data() {
if (!$item = parent::get_data()) {
return false;
}
$presentation = str_replace("\n", FEEDBACK_MULTICHOICE_LINE_SEP, trim($item->values));
if (!isset($item->subtype)) {
$subtype = 'r';
} else {
$subtype = substr($item->subtype, 0, 1);
}
if (isset($item->horizontal) AND $item->horizontal == 1 AND $subtype != 'd') {
$presentation .= FEEDBACK_MULTICHOICE_ADJUST_SEP.'1';
}
if (!isset($item->hidenoselect)) {
$item->hidenoselect = 1;
}
if (!isset($item->ignoreempty)) {
$item->ignoreempty = 0;
}
$item->presentation = $subtype.FEEDBACK_MULTICHOICE_TYPE_SEP.$presentation;
return $item;
}
}
+509
View File
@@ -0,0 +1,509 @@
<?php
// 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/>.
defined('MOODLE_INTERNAL') OR die('not allowed');
require_once($CFG->dirroot.'/mod/feedback/item/feedback_item_class.php');
define('FEEDBACK_RADIORATED_ADJUST_SEP', '<<<<<');
define('FEEDBACK_MULTICHOICERATED_MAXCOUNT', 10); //count of possible items
define('FEEDBACK_MULTICHOICERATED_VALUE_SEP', '####');
define('FEEDBACK_MULTICHOICERATED_VALUE_SEP2', '/');
define('FEEDBACK_MULTICHOICERATED_TYPE_SEP', '>>>>>');
define('FEEDBACK_MULTICHOICERATED_LINE_SEP', '|');
define('FEEDBACK_MULTICHOICERATED_ADJUST_SEP', '<<<<<');
define('FEEDBACK_MULTICHOICERATED_IGNOREEMPTY', 'i');
define('FEEDBACK_MULTICHOICERATED_HIDENOSELECT', 'h');
class feedback_item_multichoicerated extends feedback_item_base {
protected $type = "multichoicerated";
public function build_editform($item, $feedback, $cm) {
global $DB, $CFG;
require_once('multichoicerated_form.php');
//get the lastposition number of the feedback_items
$position = $item->position;
$lastposition = $DB->count_records('feedback_item', array('feedback'=>$feedback->id));
if ($position == -1) {
$i_formselect_last = $lastposition + 1;
$i_formselect_value = $lastposition + 1;
$item->position = $lastposition + 1;
} else {
$i_formselect_last = $lastposition;
$i_formselect_value = $item->position;
}
//the elements for position dropdownlist
$positionlist = array_slice(range(0, $i_formselect_last), 1, $i_formselect_last, true);
$item->presentation = empty($item->presentation) ? '' : $item->presentation;
$info = $this->get_info($item);
$item->ignoreempty = $this->ignoreempty($item);
$item->hidenoselect = $this->hidenoselect($item);
//all items for dependitem
$feedbackitems = feedback_get_depend_candidates_for_item($feedback, $item);
$commonparams = array('cmid'=>$cm->id,
'id'=>isset($item->id) ? $item->id : null,
'typ'=>$item->typ,
'items'=>$feedbackitems,
'feedback'=>$feedback->id);
//build the form
$customdata = array('item' => $item,
'common' => $commonparams,
'positionlist' => $positionlist,
'position' => $position,
'info' => $info);
$this->item_form = new feedback_multichoicerated_form('edit_item.php', $customdata);
}
/**
* Saves item
*
* @return stdClass
*/
public function save_item() {
global $DB;
if (!$this->get_data()) {
return false;
}
$item = $this->item;
if (isset($item->clone_item) AND $item->clone_item) {
$item->id = ''; //to clone this item
$item->position++;
}
$this->set_ignoreempty($item, $item->ignoreempty);
$this->set_hidenoselect($item, $item->hidenoselect);
$item->hasvalue = $this->get_hasvalue();
if (!$item->id) {
$item->id = $DB->insert_record('feedback_item', $item);
} else {
$DB->update_record('feedback_item', $item);
}
return $DB->get_record('feedback_item', array('id'=>$item->id));
}
/**
* Helper function for collected data, both for analysis page and export to excel
*
* @param stdClass $item the db-object from feedback_item
* @param int $groupid
* @param int $courseid
* @return array|null
*/
protected function get_analysed($item, $groupid = false, $courseid = false) {
$analysed_item = array();
$analysed_item[] = $item->typ;
$analysed_item[] = $item->name;
//die moeglichen Antworten extrahieren
$info = $this->get_info($item);
$lines = null;
$lines = explode (FEEDBACK_MULTICHOICERATED_LINE_SEP, $info->presentation);
if (!is_array($lines)) {
return null;
}
//die Werte holen
$values = feedback_get_group_values($item, $groupid, $courseid, $this->ignoreempty($item));
if (!$values) {
return null;
}
//schleife ueber den Werten und ueber die Antwortmoeglichkeiten
$analysed_answer = array();
$sizeoflines = count($lines);
for ($i = 1; $i <= $sizeoflines; $i++) {
$item_values = explode(FEEDBACK_MULTICHOICERATED_VALUE_SEP, $lines[$i-1]);
$ans = new stdClass();
$ans->answertext = $item_values[1];
$avg = 0.0;
$anscount = 0;
foreach ($values as $value) {
//ist die Antwort gleich dem index der Antworten + 1?
if ($value->value == $i) {
$avg += $item_values[0]; //erst alle Werte aufsummieren
$anscount++;
}
}
$ans->answercount = $anscount;
$ans->avg = doubleval($avg) / doubleval(count($values));
$ans->value = $item_values[0];
$ans->quotient = $ans->answercount / count($values);
$analysed_answer[] = $ans;
}
$analysed_item[] = $analysed_answer;
return $analysed_item;
}
public function get_printval($item, $value) {
$printval = '';
if (!isset($value->value)) {
return $printval;
}
$info = $this->get_info($item);
$presentation = explode (FEEDBACK_MULTICHOICERATED_LINE_SEP, $info->presentation);
$index = 1;
foreach ($presentation as $pres) {
if ($value->value == $index) {
$item_label = explode(FEEDBACK_MULTICHOICERATED_VALUE_SEP, $pres);
$printval = format_string($item_label[1]);
break;
}
$index++;
}
return $printval;
}
public function print_analysed($item, $itemnr = '', $groupid = false, $courseid = false) {
global $OUTPUT;
$analysed_item = $this->get_analysed($item, $groupid, $courseid);
if ($analysed_item) {
echo "<table class=\"analysis itemtype_{$item->typ}\">";
echo '<tr><th class="text-left">';
echo $itemnr . ' ';
if (strval($item->label) !== '') {
echo '('. format_string($item->label).') ';
}
echo format_string($analysed_item[1]);
echo '</th></tr>';
$analysed_vals = $analysed_item[2];
$avg = 0.0;
$count = 0;
$data = [];
foreach ($analysed_vals as $val) {
$avg += $val->avg;
$quotient = format_float($val->quotient * 100, 2);
$answertext = '('.$val->value.') ' . format_text(trim($val->answertext), FORMAT_HTML,
array('noclean' => true, 'para' => false));
if ($val->quotient > 0) {
$strquotient = ' ('.$quotient.' %)';
} else {
$strquotient = '';
}
$data['labels'][$count] = $answertext;
$data['series'][$count] = $val->answercount;
$data['series_labels'][$count] = $val->answercount . $strquotient;
$count++;
}
$chart = new \core\chart_bar();
$chart->set_horizontal(true);
$series = new \core\chart_series(format_string(get_string("responses", "feedback")), $data['series']);
$series->set_labels($data['series_labels']);
$chart->add_series($series);
$chart->set_labels($data['labels']);
echo '<tr><td>'. $OUTPUT->render($chart) . '</td></tr>';
$avg = format_float($avg, 2);
echo '<tr><td class="text-left"><b>';
echo get_string('average', 'feedback').': '.$avg.'</b>';
echo '</td></tr>';
echo '</table>';
}
}
public function excelprint_item(&$worksheet, $row_offset,
$xls_formats, $item,
$groupid, $courseid = false) {
$analysed_item = $this->get_analysed($item, $groupid, $courseid);
if (!$analysed_item) {
return $row_offset;
}
$data = $analysed_item[2];
//write the item
$worksheet->write_string($row_offset, 0, $item->label, $xls_formats->head2);
$worksheet->write_string($row_offset, 1, $analysed_item[1], $xls_formats->head2);
if (is_array($data)) {
$avg = 0.0;
$sizeofdata = count($data);
for ($i = 0; $i < $sizeofdata; $i++) {
$analysed_data = $data[$i];
$worksheet->write_string($row_offset,
$i + 2,
trim($analysed_data->answertext).' ('.$analysed_data->value.')',
$xls_formats->value_bold);
$worksheet->write_number($row_offset + 1,
$i + 2,
$analysed_data->answercount,
$xls_formats->default);
$avg += $analysed_data->avg;
}
//mittelwert anzeigen
$worksheet->write_string($row_offset,
count($data) + 2,
get_string('average', 'feedback'),
$xls_formats->value_bold);
$worksheet->write_number($row_offset + 1,
count($data) + 2,
$avg,
$xls_formats->value_bold);
}
$row_offset +=2;
return $row_offset;
}
/**
* Options for the multichoice element
* @param stdClass $item
* @return array
*/
protected function get_options($item) {
$info = $this->get_info($item);
$lines = explode(FEEDBACK_MULTICHOICERATED_LINE_SEP, $info->presentation);
$options = array();
foreach ($lines as $idx => $line) {
list($weight, $optiontext) = explode(FEEDBACK_MULTICHOICERATED_VALUE_SEP, $line);
$a = new stdclass();
$a->weight = $weight;
$a->name = format_text($optiontext, FORMAT_HTML, array('noclean' => true, 'para' => false));
$options[$idx + 1] = get_string('multichoiceoption', 'feedback', $a);
}
if ($info->subtype === 'r' && !$this->hidenoselect($item)) {
$options = array(0 => get_string('not_selected', 'feedback')) + $options;
}
return $options;
}
/**
* Adds an input element to the complete form
*
* @param stdClass $item
* @param mod_feedback_complete_form $form
*/
public function complete_form_element($item, $form) {
$info = $this->get_info($item);
$name = $this->get_display_name($item);
$class = 'multichoicerated-' . $info->subtype;
$inputname = $item->typ . '_' . $item->id;
$options = $this->get_options($item);
if ($info->subtype === 'd' || $form->is_frozen()) {
$el = $form->add_form_element($item,
['select', $inputname, $name, array('' => '') + $options, array('class' => $class)]);
} else {
$objs = array();
if (!array_key_exists(0, $options)) {
// Always add '0' as hidden element, otherwise form submit data may not have this element.
$objs[] = ['hidden', $inputname];
}
foreach ($options as $idx => $label) {
$objs[] = ['radio', $inputname, '', $label, $idx];
}
// Span to hold the element id. The id is used for drag and drop reordering.
$objs[] = ['static', '', '', html_writer::span('', '', ['id' => 'feedback_item_' . $item->id])];
$separator = $info->horizontal ? ' ' : '<br>';
$class .= ' multichoicerated-' . ($info->horizontal ? 'horizontal' : 'vertical');
$el = $form->add_form_group_element($item, 'group_'.$inputname, $name, $objs, $separator, $class);
$form->set_element_type($inputname, PARAM_INT);
// Set previously input values.
$form->set_element_default($inputname, $form->get_item_value($item));
// Process "required" rule.
if ($item->required) {
$form->add_validation_rule(function($values, $files) use ($item) {
$inputname = $item->typ . '_' . $item->id;
return empty($values[$inputname]) ? array('group_' . $inputname => get_string('required')) : true;
});
}
}
}
/**
* Compares the dbvalue with the dependvalue
*
* @param stdClass $item
* @param string $dbvalue is the value input by user in the format as it is stored in the db
* @param string $dependvalue is the value that it needs to be compared against
*/
public function compare_value($item, $dbvalue, $dependvalue) {
if (is_array($dbvalue)) {
$dbvalues = $dbvalue;
} else {
$dbvalues = explode(FEEDBACK_MULTICHOICERATED_LINE_SEP, $dbvalue);
}
$info = $this->get_info($item);
$presentation = explode (FEEDBACK_MULTICHOICERATED_LINE_SEP, $info->presentation);
$index = 1;
foreach ($presentation as $pres) {
$presvalues = explode(FEEDBACK_MULTICHOICERATED_VALUE_SEP, $pres);
foreach ($dbvalues as $dbval) {
if ($dbval == $index AND trim($presvalues[1]) == $dependvalue) {
return true;
}
}
$index++;
}
return false;
}
public function get_info($item) {
$presentation = empty($item->presentation) ? '' : $item->presentation;
$info = new stdClass();
//check the subtype of the multichoice
//it can be check(c), radio(r) or dropdown(d)
$info->subtype = '';
$info->presentation = '';
$info->horizontal = false;
$parts = explode(FEEDBACK_MULTICHOICERATED_TYPE_SEP, $item->presentation);
$info->subtype = $parts[0];
if (count($parts) > 1) {
$info->presentation = $parts[1];
}
if (!isset($info->subtype)) {
$info->subtype = 'r';
}
if ($info->subtype != 'd') {
$parts = explode(FEEDBACK_MULTICHOICERATED_ADJUST_SEP, $info->presentation);
$info->presentation = $parts[0];
if (count($parts) > 1) {
$info->horizontal = $parts[1];
}
if (isset($info->horizontal) AND $info->horizontal == 1) {
$info->horizontal = true;
} else {
$info->horizontal = false;
}
}
$info->values = $this->prepare_presentation_values_print($info->presentation,
FEEDBACK_MULTICHOICERATED_VALUE_SEP,
FEEDBACK_MULTICHOICERATED_VALUE_SEP2);
return $info;
}
public function prepare_presentation_values($linesep1,
$linesep2,
$valuestring,
$valuesep1,
$valuesep2) {
$lines = explode($linesep1, $valuestring);
$newlines = array();
foreach ($lines as $line) {
$value = '';
$text = '';
if (strpos($line, $valuesep1) === false) {
$value = 0;
$text = $line;
} else {
@list($value, $text) = explode($valuesep1, $line, 2);
}
$value = intval($value);
$newlines[] = $value.$valuesep2.$text;
}
$newlines = implode($linesep2, $newlines);
return $newlines;
}
public function prepare_presentation_values_print($valuestring, $valuesep1, $valuesep2) {
$valuestring = str_replace(array("\n","\r"), "", $valuestring);
return $this->prepare_presentation_values(FEEDBACK_MULTICHOICERATED_LINE_SEP,
"\n",
$valuestring,
$valuesep1,
$valuesep2);
}
public function prepare_presentation_values_save($valuestring, $valuesep1, $valuesep2) {
$valuestring = str_replace("\r", "\n", $valuestring);
$valuestring = str_replace("\n\n", "\n", $valuestring);
return $this->prepare_presentation_values("\n",
FEEDBACK_MULTICHOICERATED_LINE_SEP,
$valuestring,
$valuesep1,
$valuesep2);
}
public function set_ignoreempty($item, $ignoreempty=true) {
$item->options = str_replace(FEEDBACK_MULTICHOICERATED_IGNOREEMPTY, '', $item->options);
if ($ignoreempty) {
$item->options .= FEEDBACK_MULTICHOICERATED_IGNOREEMPTY;
}
}
public function ignoreempty($item) {
if (strstr($item->options, FEEDBACK_MULTICHOICERATED_IGNOREEMPTY)) {
return true;
}
return false;
}
public function set_hidenoselect($item, $hidenoselect=true) {
$item->options = str_replace(FEEDBACK_MULTICHOICERATED_HIDENOSELECT, '', $item->options);
if ($hidenoselect) {
$item->options .= FEEDBACK_MULTICHOICERATED_HIDENOSELECT;
}
}
public function hidenoselect($item) {
if (strstr($item->options, FEEDBACK_MULTICHOICERATED_HIDENOSELECT)) {
return true;
}
return false;
}
/**
* Return the analysis data ready for external functions.
*
* @param stdClass $item the item (question) information
* @param int $groupid the group id to filter data (optional)
* @param int $courseid the course id (optional)
* @return array an array of data with non scalar types json encoded
* @since Moodle 3.3
*/
public function get_analysed_for_external($item, $groupid = false, $courseid = false) {
$externaldata = array();
$data = $this->get_analysed($item, $groupid, $courseid);
if ($data && !empty($data[2]) && is_array($data[2])) {
foreach ($data[2] as $d) {
$externaldata[] = json_encode($d);
}
}
return $externaldata;
}
}
@@ -0,0 +1,126 @@
<?php
// 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/>.
require_once($CFG->dirroot.'/mod/feedback/item/feedback_item_form_class.php');
class feedback_multichoicerated_form extends feedback_item_form {
protected $type = "multichoicerated";
/** @var object Form element */
protected $values;
public function definition() {
$item = $this->_customdata['item'];
$common = $this->_customdata['common'];
$positionlist = $this->_customdata['positionlist'];
$position = $this->_customdata['position'];
$mform =& $this->_form;
$mform->addElement('header', 'general', get_string($this->type, 'feedback'));
$mform->addElement('advcheckbox', 'required', get_string('required', 'feedback'), '' , null , array(0, 1));
$mform->addElement('text',
'name',
get_string('item_name', 'feedback'),
array('size'=>FEEDBACK_ITEM_NAME_TEXTBOX_SIZE,
'maxlength'=>255));
$mform->addElement('text',
'label',
get_string('item_label', 'feedback'),
array('size'=>FEEDBACK_ITEM_LABEL_TEXTBOX_SIZE,
'maxlength'=>255));
$mform->addElement('select',
'subtype',
get_string('multichoicetype', 'feedback').'&nbsp;',
array('r'=>get_string('radio', 'feedback'),
'd'=>get_string('dropdown', 'feedback')));
$mform->addElement('select',
'horizontal',
get_string('adjustment', 'feedback').'&nbsp;',
array(0 => get_string('vertical', 'feedback'),
1 => get_string('horizontal', 'feedback')));
$mform->hideIf('horizontal', 'subtype', 'eq', 'd');
$mform->addElement('selectyesno',
'hidenoselect',
get_string('hide_no_select_option', 'feedback'));
$mform->hideIf('hidenoselect', 'subtype', 'eq', 'd');
$mform->addElement('selectyesno',
'ignoreempty',
get_string('do_not_analyse_empty_submits', 'feedback'));
$mform->disabledIf('ignoreempty', 'required', 'eq', '1');
$this->values = $mform->addElement('textarea',
'values',
get_string('multichoice_values', 'feedback'),
'wrap="virtual" rows="10" cols="65"');
$mform->addElement('static',
'hint',
'',
get_string('use_one_line_for_each_value', 'feedback'));
parent::definition();
$this->set_data($item);
}
public function set_data($item) {
$info = $this->_customdata['info'];
$item->horizontal = $info->horizontal;
$item->subtype = $info->subtype;
$item->values = $info->values;
return parent::set_data($item);
}
public function get_data() {
if (!$item = parent::get_data()) {
return false;
}
$itemobj = new feedback_item_multichoicerated();
$presentation = $itemobj->prepare_presentation_values_save(trim($item->values),
FEEDBACK_MULTICHOICERATED_VALUE_SEP2,
FEEDBACK_MULTICHOICERATED_VALUE_SEP);
if (!isset($item->subtype)) {
$subtype = 'r';
} else {
$subtype = substr($item->subtype, 0, 1);
}
if (isset($item->horizontal) AND $item->horizontal == 1 AND $subtype != 'd') {
$presentation .= FEEDBACK_MULTICHOICERATED_ADJUST_SEP.'1';
}
$item->presentation = $subtype.FEEDBACK_MULTICHOICERATED_TYPE_SEP.$presentation;
if (!isset($item->hidenoselect)) {
$item->hidenoselect = 1;
}
if (!isset($item->ignoreempty)) {
$item->ignoreempty = 0;
}
return $item;
}
}
+329
View File
@@ -0,0 +1,329 @@
<?php
// 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/>.
defined('MOODLE_INTERNAL') OR die('not allowed');
require_once($CFG->dirroot.'/mod/feedback/item/feedback_item_class.php');
class feedback_item_numeric extends feedback_item_base {
protected $type = "numeric";
public function build_editform($item, $feedback, $cm) {
global $DB, $CFG;
require_once('numeric_form.php');
//get the lastposition number of the feedback_items
$position = $item->position;
$lastposition = $DB->count_records('feedback_item', array('feedback'=>$feedback->id));
if ($position == -1) {
$i_formselect_last = $lastposition + 1;
$i_formselect_value = $lastposition + 1;
$item->position = $lastposition + 1;
} else {
$i_formselect_last = $lastposition;
$i_formselect_value = $item->position;
}
//the elements for position dropdownlist
$positionlist = array_slice(range(0, $i_formselect_last), 1, $i_formselect_last, true);
$item->presentation = empty($item->presentation) ? '' : $item->presentation;
$range_from_to = explode('|', $item->presentation);
if (isset($range_from_to[0]) AND is_numeric($range_from_to[0])) {
$range_from = $this->format_float($range_from_to[0]);
} else {
$range_from = '-';
}
if (isset($range_from_to[1]) AND is_numeric($range_from_to[1])) {
$range_to = $this->format_float($range_from_to[1]);
} else {
$range_to = '-';
}
$item->rangefrom = $range_from;
$item->rangeto = $range_to;
//all items for dependitem
$feedbackitems = feedback_get_depend_candidates_for_item($feedback, $item);
$commonparams = array('cmid'=>$cm->id,
'id'=>isset($item->id) ? $item->id : null,
'typ'=>$item->typ,
'items'=>$feedbackitems,
'feedback'=>$feedback->id);
//build the form
$customdata = array('item' => $item,
'common' => $commonparams,
'positionlist' => $positionlist,
'position' => $position);
$this->item_form = new feedback_numeric_form('edit_item.php', $customdata);
}
public function save_item() {
global $DB;
if (!$this->get_data()) {
return false;
}
$item = $this->item;
if (isset($item->clone_item) AND $item->clone_item) {
$item->id = ''; //to clone this item
$item->position++;
}
$item->hasvalue = $this->get_hasvalue();
if (!$item->id) {
$item->id = $DB->insert_record('feedback_item', $item);
} else {
$DB->update_record('feedback_item', $item);
}
return $DB->get_record('feedback_item', array('id'=>$item->id));
}
/**
* Helper function for collected data, both for analysis page and export to excel
*
* @param stdClass $item the db-object from feedback_item
* @param int $groupid
* @param int $courseid
* @return stdClass
*/
protected function get_analysed($item, $groupid = false, $courseid = false) {
global $DB;
$analysed = new stdClass();
$analysed->data = array();
$analysed->name = $item->name;
$values = feedback_get_group_values($item, $groupid, $courseid);
$avg = 0.0;
$counter = 0;
if ($values) {
$data = array();
foreach ($values as $value) {
if (is_numeric($value->value)) {
$data[] = $value->value;
$avg += $value->value;
$counter++;
}
}
$avg = $counter > 0 ? $avg / $counter : null;
$analysed->data = $data;
$analysed->avg = $avg;
}
return $analysed;
}
public function get_printval($item, $value) {
if (!isset($value->value)) {
return '';
}
return $value->value;
}
public function print_analysed($item, $itemnr = '', $groupid = false, $courseid = false) {
$values = $this->get_analysed($item, $groupid, $courseid);
if (isset($values->data) AND is_array($values->data)) {
echo "<table class=\"analysis itemtype_{$item->typ}\">";
echo '<tr><th class="text-left">';
echo $itemnr . ' ';
if (strval($item->label) !== '') {
echo '('. format_string($item->label).') ';
}
echo format_text($item->name, FORMAT_HTML, array('noclean' => true, 'para' => false));
echo '</th></tr>';
foreach ($values->data as $value) {
echo '<tr><td class="singlevalue">';
echo $this->format_float($value);
echo '</td></tr>';
}
if (isset($values->avg)) {
$avg = format_float($values->avg, 2);
} else {
$avg = '-';
}
echo '<tr><td><b>';
echo get_string('average', 'feedback').': '.$avg;
echo '</b></td></tr>';
echo '</table>';
}
}
public function excelprint_item(&$worksheet, $row_offset,
$xls_formats, $item,
$groupid, $courseid = false) {
$analysed_item = $this->get_analysed($item, $groupid, $courseid);
$worksheet->write_string($row_offset, 0, $item->label, $xls_formats->head2);
$worksheet->write_string($row_offset, 1, $item->name, $xls_formats->head2);
$data = $analysed_item->data;
if (is_array($data)) {
// Export average.
$worksheet->write_string($row_offset,
2,
get_string('average', 'feedback'),
$xls_formats->value_bold);
if (isset($analysed_item->avg)) {
$worksheet->write_number($row_offset + 1,
2,
$analysed_item->avg,
$xls_formats->value_bold);
} else {
$worksheet->write_string($row_offset + 1,
2,
'',
$xls_formats->value_bold);
}
$row_offset++;
}
$row_offset++;
return $row_offset;
}
/**
* Prints the float nicely in the localized format
*
* Similar to format_float() but automatically calculates the number of decimal places
*
* @param float $value The float to print
* @return string
*/
protected function format_float($value) {
if (!is_numeric($value)) {
return null;
}
$decimal = is_int($value) ? 0 : strlen(substr(strrchr($value, '.'), 1));
return format_float($value, $decimal);
}
/**
* Returns human-readable boundaries (min - max)
* @param stdClass $item
* @return string
*/
protected function get_boundaries_for_display($item) {
list($rangefrom, $rangeto) = explode('|', $item->presentation);
if (!isset($rangefrom) || !is_numeric($rangefrom)) {
$rangefrom = null;
}
if (!isset($rangeto) || !is_numeric($rangeto)) {
$rangeto = null;
}
if (is_null($rangefrom) && is_numeric($rangeto)) {
return ' (' . get_string('maximal', 'feedback') .
': ' . $this->format_float($rangeto) . ')';
}
if (is_numeric($rangefrom) && is_null($rangeto)) {
return ' (' . get_string('minimal', 'feedback') .
': ' . $this->format_float($rangefrom) . ')';
}
if (is_null($rangefrom) && is_null($rangeto)) {
return '';
}
return ' (' . $this->format_float($rangefrom) .
' - ' . $this->format_float($rangeto) . ')';
}
/**
* Returns the postfix to be appended to the display name that is based on other settings
*
* @param stdClass $item
* @return string
*/
public function get_display_name_postfix($item) {
return html_writer::span($this->get_boundaries_for_display($item), 'boundaries');
}
/**
* Adds an input element to the complete form
*
* @param stdClass $item
* @param mod_feedback_complete_form $form
*/
public function complete_form_element($item, $form) {
$name = $this->get_display_name($item);
$inputname = $item->typ . '_' . $item->id;
$form->add_form_element($item,
['text', $inputname, $name],
true,
false
);
$form->set_element_type($inputname, PARAM_NOTAGS);
$tmpvalue = $this->format_float($form->get_item_value($item));
$form->set_element_default($inputname, $tmpvalue);
// Add form validation rule to check for boundaries.
$form->add_validation_rule(function($values, $files) use ($item) {
$inputname = $item->typ . '_' . $item->id;
list($rangefrom, $rangeto) = explode('|', $item->presentation);
if (!isset($values[$inputname]) || trim($values[$inputname]) === '') {
return $item->required ? array($inputname => get_string('required')) : true;
}
$value = unformat_float($values[$inputname], true);
if ($value === false) {
return array($inputname => get_string('invalidnum', 'error'));
}
if ((is_numeric($rangefrom) && $value < floatval($rangefrom)) ||
(is_numeric($rangeto) && $value > floatval($rangeto))) {
return array($inputname => get_string('numberoutofrange', 'feedback'));
}
return true;
});
}
public function create_value($data) {
$data = unformat_float($data, true);
if (is_numeric($data)) {
$data = floatval($data);
} else {
$data = '';
}
return $data;
}
/**
* Return the analysis data ready for external functions.
*
* @param stdClass $item the item (question) information
* @param int $groupid the group id to filter data (optional)
* @param int $courseid the course id (optional)
* @return array an array of data with non scalar types json encoded
* @since Moodle 3.3
*/
public function get_analysed_for_external($item, $groupid = false, $courseid = false) {
$externaldata = array();
$data = $this->get_analysed($item, $groupid, $courseid);
if (is_array($data->data)) {
return $data->data; // No need to json, scalar type.
}
return $externaldata;
}
}
@@ -0,0 +1,88 @@
<?php
// 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/>.
require_once($CFG->dirroot.'/mod/feedback/item/feedback_item_form_class.php');
class feedback_numeric_form extends feedback_item_form {
protected $type = "numeric";
public function definition() {
$item = $this->_customdata['item'];
$common = $this->_customdata['common'];
$positionlist = $this->_customdata['positionlist'];
$position = $this->_customdata['position'];
$mform =& $this->_form;
$mform->addElement('header', 'general', get_string($this->type, 'feedback'));
$mform->addElement('advcheckbox', 'required', get_string('required', 'feedback'), '' , null , array(0, 1));
$mform->addElement('text',
'name',
get_string('item_name', 'feedback'),
array('size'=>FEEDBACK_ITEM_NAME_TEXTBOX_SIZE, 'maxlength'=>255));
$mform->addElement('text',
'label',
get_string('item_label', 'feedback'),
array('size'=>FEEDBACK_ITEM_LABEL_TEXTBOX_SIZE, 'maxlength'=>255));
$mform->addElement('text',
'rangefrom',
get_string('numeric_range_from', 'feedback'),
array('size'=>10, 'maxlength'=>10));
$mform->setType('rangefrom', PARAM_RAW);
$mform->addElement('text',
'rangeto',
get_string('numeric_range_to', 'feedback'),
array('size'=>10, 'maxlength'=>10));
$mform->setType('rangeto', PARAM_RAW);
parent::definition();
$this->set_data($item);
}
public function get_data() {
if (!$item = parent::get_data()) {
return false;
}
$num1 = unformat_float($item->rangefrom, true);
if ($num1 === false || $num1 === null) {
$num1 = '-';
}
$num2 = unformat_float($item->rangeto, true);
if ($num2 === false || $num2 === null) {
$num2 = '-';
}
if ($num1 === '-' OR $num2 === '-') {
$item->presentation = $num1 . '|'. $num2;
return $item;
}
if ($num1 > $num2) {
$item->presentation = $num2 . '|'. $num1;
} else {
$item->presentation = $num1 . '|'. $num2;
}
return $item;
}
}
+221
View File
@@ -0,0 +1,221 @@
<?php
// 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/>.
defined('MOODLE_INTERNAL') OR die('not allowed');
require_once($CFG->dirroot.'/mod/feedback/item/feedback_item_class.php');
class feedback_item_textarea extends feedback_item_base {
protected $type = "textarea";
public function build_editform($item, $feedback, $cm) {
global $DB, $CFG;
require_once('textarea_form.php');
//get the lastposition number of the feedback_items
$position = $item->position;
$lastposition = $DB->count_records('feedback_item', array('feedback'=>$feedback->id));
if ($position == -1) {
$i_formselect_last = $lastposition + 1;
$i_formselect_value = $lastposition + 1;
$item->position = $lastposition + 1;
} else {
$i_formselect_last = $lastposition;
$i_formselect_value = $item->position;
}
//the elements for position dropdownlist
$positionlist = array_slice(range(0, $i_formselect_last), 1, $i_formselect_last, true);
$item->presentation = empty($item->presentation) ? '' : $item->presentation;
$width_and_height = explode('|', $item->presentation);
if (isset($width_and_height[0]) AND $width_and_height[0] >= 5) {
$itemwidth = $width_and_height[0];
} else {
$itemwidth = 30;
}
if (isset($width_and_height[1])) {
$itemheight = $width_and_height[1];
} else {
$itemheight = 5;
}
$item->itemwidth = $itemwidth;
$item->itemheight = $itemheight;
//all items for dependitem
$feedbackitems = feedback_get_depend_candidates_for_item($feedback, $item);
$commonparams = array('cmid'=>$cm->id,
'id'=>isset($item->id) ? $item->id : null,
'typ'=>$item->typ,
'items'=>$feedbackitems,
'feedback'=>$feedback->id);
//build the form
$customdata = array('item' => $item,
'common' => $commonparams,
'positionlist' => $positionlist,
'position' => $position);
$this->item_form = new feedback_textarea_form('edit_item.php', $customdata);
}
public function save_item() {
global $DB;
if (!$this->get_data()) {
return false;
}
$item = $this->item;
if (isset($item->clone_item) AND $item->clone_item) {
$item->id = ''; //to clone this item
$item->position++;
}
$item->hasvalue = $this->get_hasvalue();
if (!$item->id) {
$item->id = $DB->insert_record('feedback_item', $item);
} else {
$DB->update_record('feedback_item', $item);
}
return $DB->get_record('feedback_item', array('id'=>$item->id));
}
/**
* Helper function for collected data for exporting to excel
*
* @param stdClass $item the db-object from feedback_item
* @param int $groupid
* @param int $courseid
* @param bool $excel Indicate if being used for Excel
* @return stdClass
*/
protected function get_analysed($item, $groupid = false, $courseid = false, bool $excel = false) {
global $DB;
$analysed_val = new stdClass();
$analysed_val->data = array();
$analysed_val->name = $item->name;
$values = feedback_get_group_values($item, $groupid, $courseid);
if ($values) {
$data = array();
foreach ($values as $value) {
// Convert line breaks except for Excel.
$data[] = $excel ? $value->value : str_replace("\n", '<br />', $value->value);
}
$analysed_val->data = $data;
}
return $analysed_val;
}
public function get_printval($item, $value) {
if (!isset($value->value)) {
return '';
}
return $value->value;
}
public function print_analysed($item, $itemnr = '', $groupid = false, $courseid = false) {
$values = feedback_get_group_values($item, $groupid, $courseid);
if ($values) {
echo "<table class=\"analysis itemtype_{$item->typ}\">";
echo '<tr><th class="text-left">';
echo $itemnr . ' ';
if (strval($item->label) !== '') {
echo '('. format_string($item->label).') ';
}
echo format_text($item->name, FORMAT_HTML, array('noclean' => true, 'para' => false));
echo '</th></tr>';
foreach ($values as $value) {
$class = strlen(trim($value->value)) ? '' : ' class="isempty"';
echo '<tr'.$class.'>';
echo '<td class="singlevalue">';
echo str_replace("\n", '<br />', $value->value);
echo '</td>';
echo '</tr>';
}
echo '</table>';
}
}
public function excelprint_item(&$worksheet, $row_offset,
$xls_formats, $item,
$groupid, $courseid = false) {
$analyseditem = $this->get_analysed($item, $groupid, $courseid, true);
$worksheet->write_string($row_offset, 0, $item->label, $xls_formats->head2);
$worksheet->write_string($row_offset, 1, $item->name, $xls_formats->head2);
$data = $analyseditem->data;
if (is_array($data)) {
if (isset($data[0])) {
$worksheet->write_string($row_offset, 2, htmlspecialchars_decode($data[0], ENT_QUOTES), $xls_formats->value_bold);
}
$row_offset++;
$sizeofdata = count($data);
for ($i = 1; $i < $sizeofdata; $i++) {
$worksheet->write_string($row_offset, 2, htmlspecialchars_decode($data[$i], ENT_QUOTES), $xls_formats->default);
$row_offset++;
}
}
$row_offset++;
return $row_offset;
}
/**
* Adds an input element to the complete form
*
* @param stdClass $item
* @param mod_feedback_complete_form $form
*/
public function complete_form_element($item, $form) {
$name = $this->get_display_name($item);
$inputname = $item->typ . '_' . $item->id;
list($cols, $rows) = explode ("|", $item->presentation);
$form->add_form_element($item,
['textarea', $inputname, $name, array('rows' => $rows, 'cols' => $cols)]);
$form->set_element_type($inputname, PARAM_NOTAGS);
}
public function create_value($data) {
return s($data);
}
/**
* Return the analysis data ready for external functions.
*
* @param stdClass $item the item (question) information
* @param int $groupid the group id to filter data (optional)
* @param int $courseid the course id (optional)
* @return array an array of data with non scalar types json encoded
* @since Moodle 3.3
*/
public function get_analysed_for_external($item, $groupid = false, $courseid = false) {
$externaldata = array();
$data = $this->get_analysed($item, $groupid, $courseid);
if (is_array($data->data)) {
return $data->data; // No need to json, scalar type.
}
return $externaldata;
}
}
@@ -0,0 +1,66 @@
<?php
// 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/>.
require_once($CFG->dirroot.'/mod/feedback/item/feedback_item_form_class.php');
class feedback_textarea_form extends feedback_item_form {
protected $type = "textarea";
public function definition() {
$item = $this->_customdata['item'];
$common = $this->_customdata['common'];
$positionlist = $this->_customdata['positionlist'];
$position = $this->_customdata['position'];
$mform =& $this->_form;
$mform->addElement('header', 'general', get_string($this->type, 'feedback'));
$mform->addElement('advcheckbox', 'required', get_string('required', 'feedback'), '' , null , array(0, 1));
$mform->addElement('text',
'name',
get_string('item_name', 'feedback'),
array('size'=>FEEDBACK_ITEM_NAME_TEXTBOX_SIZE, 'maxlength'=>255));
$mform->addElement('text',
'label',
get_string('item_label', 'feedback'),
array('size'=>FEEDBACK_ITEM_LABEL_TEXTBOX_SIZE, 'maxlength'=>255));
$mform->addElement('select',
'itemwidth',
get_string('textarea_width', 'feedback').'&nbsp;',
array_slice(range(0, 80), 5, 80, true));
$mform->addElement('select',
'itemheight',
get_string('textarea_height', 'feedback').'&nbsp;',
array_slice(range(0, 40), 5, 40, true));
parent::definition();
$this->set_data($item);
}
public function get_data() {
if (!$item = parent::get_data()) {
return false;
}
$item->presentation = $item->itemwidth . '|'. $item->itemheight;
return $item;
}
}
+218
View File
@@ -0,0 +1,218 @@
<?php
// 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/>.
defined('MOODLE_INTERNAL') OR die('not allowed');
require_once($CFG->dirroot.'/mod/feedback/item/feedback_item_class.php');
class feedback_item_textfield extends feedback_item_base {
protected $type = "textfield";
public function build_editform($item, $feedback, $cm) {
global $DB, $CFG;
require_once('textfield_form.php');
//get the lastposition number of the feedback_items
$position = $item->position;
$lastposition = $DB->count_records('feedback_item', array('feedback'=>$feedback->id));
if ($position == -1) {
$i_formselect_last = $lastposition + 1;
$i_formselect_value = $lastposition + 1;
$item->position = $lastposition + 1;
} else {
$i_formselect_last = $lastposition;
$i_formselect_value = $item->position;
}
//the elements for position dropdownlist
$positionlist = array_slice(range(0, $i_formselect_last), 1, $i_formselect_last, true);
$item->presentation = empty($item->presentation) ? '' : $item->presentation;
$size_and_length = explode('|', $item->presentation);
if (isset($size_and_length[0]) AND $size_and_length[0] >= 5) {
$itemsize = $size_and_length[0];
} else {
$itemsize = 30;
}
$itemlength = isset($size_and_length[1]) ? $size_and_length[1] : 255;
$item->itemsize = $itemsize;
$item->itemmaxlength = $itemlength;
//all items for dependitem
$feedbackitems = feedback_get_depend_candidates_for_item($feedback, $item);
$commonparams = array('cmid' => $cm->id,
'id' => isset($item->id) ? $item->id : null,
'typ' => $item->typ,
'items' => $feedbackitems,
'feedback' => $feedback->id);
//build the form
$customdata = array('item' => $item,
'common' => $commonparams,
'positionlist' => $positionlist,
'position' => $position);
$this->item_form = new feedback_textfield_form('edit_item.php', $customdata);
}
public function save_item() {
global $DB;
if (!$this->get_data()) {
return false;
}
$item = $this->item;
if (isset($item->clone_item) AND $item->clone_item) {
$item->id = ''; //to clone this item
$item->position++;
}
$item->hasvalue = $this->get_hasvalue();
if (!$item->id) {
$item->id = $DB->insert_record('feedback_item', $item);
} else {
$DB->update_record('feedback_item', $item);
}
return $DB->get_record('feedback_item', array('id'=>$item->id));
}
/**
* Helper function for collected data for exporting to excel
*
* @param stdClass $item the db-object from feedback_item
* @param int $groupid
* @param int $courseid
* @return stdClass
*/
protected function get_analysed($item, $groupid = false, $courseid = false) {
$analysed_val = new stdClass();
$analysed_val->data = null;
$analysed_val->name = $item->name;
$values = feedback_get_group_values($item, $groupid, $courseid);
if ($values) {
$data = array();
foreach ($values as $value) {
$data[] = str_replace("\n", '<br />', $value->value);
}
$analysed_val->data = $data;
}
return $analysed_val;
}
public function get_printval($item, $value) {
if (!isset($value->value)) {
return '';
}
return $value->value;
}
public function print_analysed($item, $itemnr = '', $groupid = false, $courseid = false) {
$values = feedback_get_group_values($item, $groupid, $courseid);
if ($values) {
echo "<table class=\"analysis itemtype_{$item->typ}\">";
echo '<tr><th class="text-left">';
echo $itemnr . ' ';
if (strval($item->label) !== '') {
echo '('. format_string($item->label).') ';
}
echo $this->get_display_name($item);
echo '</th></tr>';
foreach ($values as $value) {
$class = strlen(trim($value->value)) ? '' : ' class="isempty"';
echo '<tr'.$class.'><td class="singlevalue">';
echo str_replace("\n", '<br />', $value->value);
echo '</td></tr>';
}
echo '</table>';
}
}
public function excelprint_item(&$worksheet, $row_offset,
$xls_formats, $item,
$groupid, $courseid = false) {
$analysed_item = $this->get_analysed($item, $groupid, $courseid);
$worksheet->write_string($row_offset, 0, $item->label, $xls_formats->head2);
$worksheet->write_string($row_offset, 1, $item->name, $xls_formats->head2);
$data = $analysed_item->data;
if (is_array($data)) {
$worksheet->write_string($row_offset, 2, htmlspecialchars_decode($data[0], ENT_QUOTES), $xls_formats->value_bold);
$row_offset++;
$sizeofdata = count($data);
for ($i = 1; $i < $sizeofdata; $i++) {
$worksheet->write_string($row_offset, 2, htmlspecialchars_decode($data[$i], ENT_QUOTES), $xls_formats->default);
$row_offset++;
}
}
$row_offset++;
return $row_offset;
}
/**
* Adds an input element to the complete form
*
* @param stdClass $item
* @param mod_feedback_complete_form $form
*/
public function complete_form_element($item, $form) {
$name = $this->get_display_name($item);
$inputname = $item->typ . '_' . $item->id;
list($size, $maxlength) = explode ("|", $item->presentation);
$form->add_form_element($item,
['text', $inputname, $name, ['maxlength' => $maxlength, 'size' => $size]]);
$form->set_element_type($inputname, PARAM_NOTAGS);
$form->add_element_rule($inputname, get_string('maximumchars', '', $maxlength), 'maxlength', $maxlength, 'client');
}
/**
* Converts the value from complete_form data to the string value that is stored in the db.
* @param mixed $value element from mod_feedback_complete_form::get_data() with the name $item->typ.'_'.$item->id
* @return string
*/
public function create_value($value) {
return s($value);
}
/**
* Return the analysis data ready for external functions.
*
* @param stdClass $item the item (question) information
* @param int $groupid the group id to filter data (optional)
* @param int $courseid the course id (optional)
* @return array an array of data with non scalar types json encoded
* @since Moodle 3.3
*/
public function get_analysed_for_external($item, $groupid = false, $courseid = false) {
$externaldata = array();
$data = $this->get_analysed($item, $groupid, $courseid);
if (is_array($data->data)) {
return $data->data; // No need to json, scalar type.
}
return $externaldata;
}
}
@@ -0,0 +1,67 @@
<?php
// 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/>.
require_once($CFG->dirroot.'/mod/feedback/item/feedback_item_form_class.php');
class feedback_textfield_form extends feedback_item_form {
protected $type = "textfield";
public function definition() {
$item = $this->_customdata['item'];
$common = $this->_customdata['common'];
$positionlist = $this->_customdata['positionlist'];
$position = $this->_customdata['position'];
$mform =& $this->_form;
$mform->addElement('header', 'general', get_string($this->type, 'feedback'));
$mform->addElement('advcheckbox', 'required', get_string('required', 'feedback'), '' , null , array(0, 1));
$mform->addElement('text',
'name',
get_string('item_name', 'feedback'),
array('size'=>FEEDBACK_ITEM_NAME_TEXTBOX_SIZE, 'maxlength'=>255));
$mform->addElement('text',
'label',
get_string('item_label', 'feedback'),
array('size'=>FEEDBACK_ITEM_LABEL_TEXTBOX_SIZE, 'maxlength'=>255));
$mform->addElement('select',
'itemsize',
get_string('textfield_size', 'feedback').'&nbsp;',
array_slice(range(0, 255), 5, 255, true));
$mform->addElement('text',
'itemmaxlength',
get_string('textfield_maxlength', 'feedback'));
$mform->setType('itemmaxlength', PARAM_INT);
$mform->addRule('itemmaxlength', null, 'numeric', null, 'client');
parent::definition();
$this->set_data($item);
}
public function get_data() {
if (!$item = parent::get_data()) {
return false;
}
$item->presentation = $item->itemsize . '|'. $item->itemmaxlength;
return $item;
}
}
View File
+302
View File
@@ -0,0 +1,302 @@
<?php
// 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/>.
/**
* Strings for component 'feedback', language 'en', branch 'MOODLE_20_STABLE'
*
* @package mod_feedback
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['add_item'] = 'Add question';
$string['add_pagebreak'] = 'Add a page break';
$string['adjustment'] = 'Adjustment';
$string['after_submit'] = 'After submission';
$string['allowfullanonymous'] = 'Allow full anonymous';
$string['analysis'] = 'Analysis';
$string['anonymous'] = 'Anonymous';
$string['anonymous_edit'] = 'Record user names';
$string['anonymous_entries'] = 'Anonymous entries ({$a})';
$string['anonymous_user'] = 'Anonymous user';
$string['answerquestions'] = 'Answer the questions';
$string['append_new_items'] = 'Append new items';
$string['autonumbering'] = 'Auto number questions';
$string['autonumbering_help'] = 'Enables or disables automated numbers for each question';
$string['average'] = 'Average';
$string['bold'] = 'Bold';
$string['calendarend'] = '{$a} closes';
$string['calendarstart'] = '{$a} opens';
$string['cannotaccess'] = 'You can only access this feedback from a course';
$string['cannotcreatepagebreak'] = 'Page breaks cannot be added at the beginning of a feedback, and only one page break can be added at the end';
$string['cannotsavetempl'] = 'Saving templates is not allowed';
$string['captcha'] = 'Captcha';
$string['captchanotset'] = 'Captcha hasn\'t been set.';
$string['closebeforeopen'] = 'You have specified an end date before the start date.';
$string['completed_feedbacks'] = 'Submitted answers';
$string['complete_the_form'] = 'Answer the questions';
$string['completed'] = 'Completed';
$string['completedon'] = 'Completed on {$a}';
$string['completiondetail:submit'] = 'Submit feedback';
$string['completionsubmit'] = 'Submit feedback';
$string['configallowfullanonymous'] = 'If set to \'yes\', users can complete a feedback activity on the site home without being required to log in.';
$string['confirmdeleteentry'] = 'Are you sure you want to delete this entry?';
$string['confirmdeleteitem'] = 'Are you sure you want to delete this element?';
$string['confirmdeletetemplate'] = 'Are you sure you want to delete this template?';
$string['confirmusetemplate'] = 'Are you sure you want to use this template?';
$string['continue_the_form'] = 'Continue answering the questions';
$string['count_of_nums'] = 'Count of numbers';
$string['courseid'] = 'Course ID';
$string['creating_templates'] = 'Save these questions as a new template';
$string['delete_entry'] = 'Delete entry';
$string['delete_item'] = 'Delete question';
$string['delete_old_items'] = 'Delete old items';
$string['delete_pagebreak'] = 'Delete page break';
$string['delete_template'] = 'Delete template';
$string['delete_templates'] = 'Delete template...';
$string['depending'] = 'Dependencies';
$string['depending_help'] = 'It is possible to show an item depending on the value of another item.<br />
<strong>Here is an example.</strong><br />
<ul>
<li>First, create an item on which another item will depend on.</li>
<li>Next, add a pagebreak.</li>
<li>Then add the items dependant on the value of the item created before. Choose the item from the list labelled "Dependence item" and write the required value in the textbox labelled "Dependence value".</li>
</ul>
<strong>The item structure should look like this.</strong>
<ol>
<li>Item Q: Do you have a car? A: yes/no</li>
<li>Pagebreak</li>
<li>Item Q: What colour is your car?<br />
(this item depends on item 1 with value = yes)</li>
<li>Item Q: Why don\'t you have a car?<br />
(this item depends on item 1 with value = no)</li>
<li> ... other items</li>
</ol>';
$string['dependitem'] = 'Dependence item';
$string['dependvalue'] = 'Dependence value';
$string['description'] = 'Description';
$string['do_not_analyse_empty_submits'] = 'Omit empty submits in analysis';
$string['dropdown'] = 'Multiple choice - single answer allowed (drop-down menu)';
$string['dropdownlist'] = 'Multiple choice - single answer (drop-down menu)';
$string['dropdownrated'] = 'Drop-down menu (rated)';
$string['dropdown_values'] = 'Answers';
$string['drop_feedback'] = 'Remove from this course';
$string['edit_item'] = 'Edit question';
$string['edit_items'] = 'Edit questions';
$string['email_notification'] = 'Enable notification of submissions';
$string['email_notification_help'] = 'If enabled, teachers will receive notification of feedback submissions.';
$string['emailteachermail'] = '{$a->username} has completed feedback activity : \'{$a->feedback}\'
You can view it here:
{$a->url}';
$string['emailteachermailhtml'] = '<p>{$a->username} has completed feedback activity : <i>\'{$a->feedback}\'</i>.</p>
<p>It is <a href="{$a->url}">available on the site</a>.</p>';
$string['entries_saved'] = 'Your answers have been saved. Thank you.';
$string['export_questions'] = 'Export questions';
$string['export_to_excel'] = 'Export to Excel';
$string['eventresponsedeleted'] = 'Response deleted';
$string['eventresponsesubmitted'] = 'Response submitted';
$string['feedbackcompleted'] = '{$a->username} completed {$a->feedbackname}';
$string['feedback:addinstance'] = 'Add a new feedback';
$string['feedbackclose'] = 'Allow answers to';
$string['feedback:complete'] = 'Complete a feedback';
$string['feedback:createprivatetemplate'] = 'Create private template';
$string['feedback:createpublictemplate'] = 'Create public template';
$string['feedback:deletesubmissions'] = 'Delete completed submissions';
$string['feedback:deletetemplate'] = 'Delete template';
$string['feedback:edititems'] = 'Edit items';
$string['feedback_is_not_for_anonymous'] = 'Feedback is not for anonymous';
$string['feedback_is_not_open'] = 'The feedback is not open';
$string['feedback:mapcourse'] = 'Map courses to global feedbacks';
$string['feedbackopen'] = 'Allow answers from';
$string['feedback:receivemail'] = 'Receive email notification';
$string['feedback:view'] = 'View a feedback';
$string['feedback:viewanalysepage'] = 'View the analysis page after submit';
$string['feedback:viewreports'] = 'View reports';
$string['feedbackupdated'] = 'Feedback updated.';
$string['file'] = 'File';
$string['filter_by_course'] = 'Filter by course';
$string['handling_error'] = 'Error occurred in feedback module action handling';
$string['hide_no_select_option'] = 'Hide the "Not selected" option';
$string['horizontal'] = 'Horizontal';
$string['check'] = 'Multiple choice - multiple answers';
$string['checkbox'] = 'Multiple choice - multiple answers allowed (check boxes)';
$string['check_values'] = 'Possible responses';
$string['choosefile'] = 'Choose a file';
$string['chosen_feedback_response'] = 'Chosen feedback response';
$string['downloadresponseas'] = 'Download all responses as:';
$string['importfromthisfile'] = 'Import from this file';
$string['import_questions'] = 'Import questions';
$string['import_successfully'] = 'Import successfully';
$string['includeuserinrecipientslist'] = 'Include {$a} in the list of recipients';
$string['indicator:cognitivedepth'] = 'Feedback cognitive';
$string['indicator:cognitivedepth_help'] = 'This indicator is based on the cognitive depth reached by the student in a Feedback activity.';
$string['indicator:cognitivedepthdef'] = 'Feedback cognitive';
$string['indicator:cognitivedepthdef_help'] = 'The participant has reached this percentage of the cognitive engagement offered by the Feedback activities during this analysis interval (Levels = No view, View, Submit)';
$string['indicator:cognitivedepthdef_link'] = 'Learning_analytics_indicators#Cognitive_depth';
$string['indicator:socialbreadth'] = 'Feedback social';
$string['indicator:socialbreadth_help'] = 'This indicator is based on the social breadth reached by the student in a Feedback activity.';
$string['indicator:socialbreadthdef'] = 'Feedback social';
$string['indicator:socialbreadthdef_help'] = 'The participant has reached this percentage of the social engagement offered by the Feedback activities during this analysis interval (Levels = No participation, Participant alone, Participant with others)';
$string['indicator:socialbreadthdef_link'] = 'Learning_analytics_indicators#Social_breadth';
$string['info'] = 'Information';
$string['infotype'] = 'Information type';
$string['insufficient_responses_for_this_group'] = 'There are insufficient responses for this group';
$string['insufficient_responses'] = 'insufficient responses';
$string['insufficient_responses_help'] = 'For the feedback to be anonymous, there must be at least 2 responses.';
$string['item_label'] = 'Label';
$string['item_name'] = 'Question';
$string['label'] = 'Text and media area';
$string['labelcontents'] = 'Contents';
$string['mapcourseinfo'] = 'This is a site-wide feedback that is available to all courses using the feedback block. You can however limit the courses to which it will appear by mapping them. Search the course and map it to this feedback.';
$string['mapcoursenone'] = 'No courses mapped. Feedback available to all courses';
$string['mapcourse'] = 'Map feedback to courses';
$string['mapcourse_help'] = 'By default, feedback forms created on your homepage are available site-wide
and will appear in all courses using the feedback block. You can force the feedback form to appear by making it a sticky block or limit the courses in which a feedback form will appear by mapping it to specific courses.';
$string['mapcourses'] = 'Map feedback to courses';
$string['mappedcourses'] = 'Mapped courses';
$string['mappingchanged'] = 'Course mapping has been changed';
$string['minimal'] = 'Minimum';
$string['maximal'] = 'Maximum';
$string['messageprovider:message'] = 'Feedback reminder';
$string['messageprovider:submission'] = 'Feedback notifications';
$string['mode'] = 'Mode';
$string['modulename'] = 'Feedback';
$string['modulename_help'] = 'The feedback activity enables a teacher to create a custom survey for collecting feedback from participants using a variety of question types including multiple choice, yes/no or text input.
Feedback responses may be anonymous if desired, and results may be shown to all participants or restricted to teachers only. Any feedback activities on the site home may also be completed by non-logged-in users.
Feedback activities may be used
* For course evaluations, helping improve the content for later participants
* To enable participants to sign up for course modules, events etc.
* For guest surveys of course choices, school policies etc.
* For anti-bullying surveys in which students can report incidents anonymously';
$string['modulename_link'] = 'mod/feedback/view';
$string['modulenameplural'] = 'Feedback';
$string['move_item'] = 'Move this question';
$string['multichoice'] = 'Multiple choice';
$string['multichoiceoption'] = '<span class="weight">({$a->weight}) </span>{$a->name}';
$string['multichoicerated'] = 'Multiple choice (rated)';
$string['multichoicetype'] = 'Multiple choice type';
$string['multichoice_values'] = 'Multiple choice values';
$string['multiplesubmit'] = 'Allow multiple submissions';
$string['multiplesubmit_help'] = 'If set to Yes:
* For anonymous surveys: participants can submit unlimited responses, and all responses will be recorded.
* For non-anonymous surveys: participants can submit unlimited responses, but only their latest response will be recorded.';
$string['name'] = 'Name';
$string['name_required'] = 'Name required';
$string['nameandlabelformat'] = '({$a->label}) {$a->name}';
$string['next_page'] = 'Next page';
$string['no_handler'] = 'No action handler exists for';
$string['no_itemlabel'] = 'No label';
$string['no_itemname'] = 'No itemname';
$string['no_items_available_yet'] = 'No questions have been set up yet';
$string['non_anonymous'] = 'User\'s name will be logged and shown with answers';
$string['non_anonymous_entries'] = 'Non anonymous entries ({$a})';
$string['non_respondents_students'] = 'Non-respondent students ({$a})';
$string['not_completed_yet'] = 'Not completed yet';
$string['not_started'] = 'Not started';
$string['no_templates_available_yet'] = 'No templates available yet';
$string['not_selected'] = 'Not selected';
$string['numberoutofrange'] = 'Number out of range';
$string['numeric'] = 'Numeric answer';
$string['numeric_range_from'] = 'Range from';
$string['numeric_range_to'] = 'Range to';
$string['of'] = 'of';
$string['oldvaluespreserved'] = 'All old questions and the assigned values will be preserved';
$string['oldvalueswillbedeleted'] = 'Current questions and all responses will be deleted.';
$string['only_one_captcha_allowed'] = 'Only one captcha is allowed in a feedback';
$string['openafterclose'] = 'You have specified an open date after the close date';
$string['overview'] = 'Overview';
$string['page'] = 'Page';
$string['page-mod-feedback-x'] = 'Any feedback module page';
$string['page_after_submit'] = 'Completion message';
$string['pagebreak'] = 'Page break';
$string['pluginadministration'] = 'Feedback administration';
$string['pluginname'] = 'Feedback';
$string['position'] = 'Position';
$string['previous_page'] = 'Previous page';
$string['previewquestions'] = 'Preview questions';
$string['privacy:metadata:completed'] = 'A record of the submissions to the feedback';
$string['privacy:metadata:completed:anonymousresponse'] = 'Whether the submission is to be used anonymously.';
$string['privacy:metadata:completed:timemodified'] = 'The time when the submission was last modified.';
$string['privacy:metadata:completed:userid'] = 'The ID of the user who completed the feedback activity.';
$string['privacy:metadata:completedtmp'] = 'A record of the submissions which are still in progress.';
$string['privacy:metadata:value'] = 'A record of the answer to a question.';
$string['privacy:metadata:value:value'] = 'The chosen answer.';
$string['privacy:metadata:valuetmp'] = 'A record of the answer to a question in a submission in progress.';
$string['public'] = 'Public';
$string['question'] = 'Question';
$string['questionandsubmission'] = 'Question and submission settings';
$string['questions'] = 'Questions';
$string['questionslimited'] = 'Showing only {$a} first questions, view individual answers or download table data to view all.';
$string['radio'] = 'Multiple choice - single answer';
$string['radio_values'] = 'Responses';
$string['ready_feedbacks'] = 'Ready feedbacks';
$string['required'] = 'Required';
$string['resetting_data'] = 'Reset feedback responses';
$string['resetting_feedbacks'] = 'Resetting feedbacks';
$string['response_nr'] = 'Response number';
$string['responses'] = 'Responses';
$string['responsetime'] = 'Responses time';
$string['save_as_new_item'] = 'Save as new question';
$string['save_as_new_template'] = 'Save as new template';
$string['save_entries'] = 'Submit your answers';
$string['save_item'] = 'Save question';
$string['saving_failed'] = 'Saving failed';
$string['search:activity'] = 'Feedback - activity information';
$string['search_course'] = 'Search course';
$string['searchcourses'] = 'Search courses';
$string['searchcourses_help'] = 'Search for the code or name of the course(s) that you wish to associate with this feedback.';
$string['selected_dump'] = 'Selected indexes of $SESSION variable are dumped below:';
$string['send'] = 'Send';
$string['send_message'] = 'Send notification';
$string['show_all'] = 'Show all';
$string['show_analysepage_after_submit'] = 'Show analysis page';
$string['show_entries'] = 'Show responses';
$string['show_entry'] = 'Show response';
$string['show_nonrespondents'] = 'Show non-respondents';
$string['site_after_submit'] = 'Site after submit';
$string['sort_by_course'] = 'Sort by course';
$string['started'] = 'Started';
$string['startedon'] = 'Started on {$a}';
$string['subject'] = 'Subject';
$string['switch_item_to_not_required'] = 'Set as not required';
$string['switch_item_to_required'] = 'Set as required';
$string['template'] = 'Template';
$string['templates'] = 'Templates';
$string['template_deleted'] = 'Template deleted';
$string['template_saved'] = 'Template saved';
$string['textarea'] = 'Longer text answer';
$string['textarea_height'] = 'Number of lines';
$string['textarea_width'] = 'Width';
$string['textfield'] = 'Short text answer';
$string['textfield_maxlength'] = 'Maximum characters accepted';
$string['textfield_size'] = 'Textfield width';
$string['there_are_no_settings_for_recaptcha'] = 'There are no settings for captcha';
$string['this_feedback_is_already_submitted'] = 'You\'ve already completed this activity.';
$string['typemissing'] = 'Missing value "type"';
$string['update_item'] = 'Save changes to question';
$string['url_for_continue'] = 'Link to next activity';
$string['url_for_continue_help'] = 'After submitting the feedback, a continue button is displayed, which links to the course page. Alternatively, it may link to the next activity if the URL of the activity is entered here.';
$string['use_one_line_for_each_value'] = 'Use one line for each answer!';
$string['use_this_template'] = 'Use this template';
$string['using_templates'] = 'Use a template';
$string['vertical'] = 'Vertical';
$string['whatfor'] = 'What do you want to do?';
+3280
View File
File diff suppressed because it is too large Load Diff
+102
View File
@@ -0,0 +1,102 @@
<?php
// 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/>.
/**
* Manage the various templates available
*
* @author Peter Dias
* @copyright 2021 Peter Dias
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package mod_feedback
*/
require_once("../../config.php");
require_once("lib.php");
$id = required_param('id', PARAM_INT);
$mode = optional_param('mode', '', PARAM_ALPHA);
$templateid = optional_param('deletetemplate', 0, PARAM_INT);
list($course, $cm) = get_course_and_cm_from_cmid($id, 'feedback');
$context = context_module::instance($cm->id);
require_login($course, true, $cm);
require_capability('mod/feedback:edititems', $context);
$feedback = $PAGE->activityrecord;
$systemcontext = context_system::instance();
$params = ['id' => $id];
if ($mode) {
$params += ['mode' => $mode];
}
$url = new moodle_url('/mod/feedback/manage_templates.php', $params);
if ($mode == 'manage') {
navigation_node::override_active_url($url);
} else {
navigation_node::override_active_url(new moodle_url('/mod/feedback/view.php', $params));
}
$PAGE->set_url($url);
$actionbar = new \mod_feedback\output\edit_action_bar($cm->id, $url);
$PAGE->set_heading($course->fullname);
$PAGE->set_title($feedback->name);
// Process template deletion.
if ($templateid) {
require_sesskey();
require_capability('mod/feedback:deletetemplate', $context);
$template = $DB->get_record('feedback_template', ['id' => $templateid], '*', MUST_EXIST);
if ($template->ispublic) {
require_capability('mod/feedback:createpublictemplate', $systemcontext);
require_capability('mod/feedback:deletetemplate', $systemcontext);
}
feedback_delete_template($template);
$successurl = new moodle_url('/mod/feedback/manage_templates.php', ['id' => $id]);
redirect($url, get_string('template_deleted', 'feedback'), null, \core\output\notification::NOTIFY_SUCCESS);
}
$PAGE->activityheader->set_attrs([
"hidecompletion" => true,
"description" => ''
]);
echo $OUTPUT->header();
/** @var \mod_feedback\output\renderer $renderer */
$renderer = $PAGE->get_renderer('mod_feedback');
if (!$mode) {
echo $renderer->main_action_bar($actionbar);
}
echo $OUTPUT->heading(get_string('templates', 'mod_feedback'), 3);
// First we get the course templates.
$templates = feedback_get_template_list($course, 'own');
echo $OUTPUT->box_start('coursetemplates');
echo $OUTPUT->heading(get_string('course'), 4);
$baseurl = new moodle_url('/mod/feedback/use_templ.php', $params);
$tablecourse = new mod_feedback_templates_table('feedback_template_course_table', $baseurl, $mode);
$tablecourse->display($templates);
echo $OUTPUT->box_end();
$templates = feedback_get_template_list($course, 'public');
echo $OUTPUT->box_start('publictemplates');
echo $OUTPUT->heading(get_string('public', 'feedback'), 4);
$tablepublic = new mod_feedback_templates_table('feedback_template_public_table', $baseurl, $mode);
$tablepublic->display($templates);
echo $OUTPUT->box_end();
echo $OUTPUT->footer();
+66
View File
@@ -0,0 +1,66 @@
<?php
// 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/>.
/**
* print the form to map courses for global feedbacks
*
* @author Andreas Grabs
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package mod_feedback
*/
require_once(__DIR__ . "/../../config.php");
require_once($CFG->dirroot . "/mod/feedback/lib.php");
require_once("$CFG->libdir/tablelib.php");
$id = required_param('id', PARAM_INT); // Course Module ID.
$url = new moodle_url('/mod/feedback/mapcourse.php', array('id'=>$id));
$PAGE->set_url($url);
$current_tab = 'mapcourse';
list($course, $cm) = get_course_and_cm_from_cmid($id, 'feedback');
require_login($course, true, $cm);
$feedback = $PAGE->activityrecord;
$context = context_module::instance($cm->id);
require_capability('mod/feedback:mapcourse', $context);
$coursemap = array_keys(feedback_get_courses_from_sitecourse_map($feedback->id));
$form = new mod_feedback_course_map_form();
$form->set_data(array('id' => $cm->id, 'mappedcourses' => $coursemap));
$mainurl = new moodle_url('/mod/feedback/view.php', ['id' => $id]);
if ($form->is_cancelled()) {
redirect($mainurl);
} else if ($data = $form->get_data()) {
feedback_update_sitecourse_map($feedback, $data->mappedcourses);
redirect($mainurl, get_string('mappingchanged', 'feedback'), null, \core\output\notification::NOTIFY_SUCCESS);
}
// Print the page header.
$strfeedbacks = get_string("modulenameplural", "feedback");
$strfeedback = get_string("modulename", "feedback");
$PAGE->set_heading($course->fullname);
$PAGE->set_title($feedback->name);
echo $OUTPUT->header();
echo $OUTPUT->box(get_string('mapcourseinfo', 'feedback'));
$form->display();
echo $OUTPUT->footer();
+226
View File
@@ -0,0 +1,226 @@
<?php
// 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/>.
/**
* print the form to add or edit a feedback-instance
*
* @author Andreas Grabs
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package mod_feedback
*/
//It must be included from a Moodle page
if (!defined('MOODLE_INTERNAL')) {
die('Direct access to this script is forbidden.');
}
require_once($CFG->dirroot.'/course/moodleform_mod.php');
class mod_feedback_mod_form extends moodleform_mod {
public function definition() {
global $CFG, $DB;
$editoroptions = feedback_get_editor_options();
$mform =& $this->_form;
//-------------------------------------------------------------------------------
$mform->addElement('header', 'general', get_string('general', 'form'));
$mform->addElement('text', 'name', get_string('name', 'feedback'), array('size'=>'64'));
$mform->setType('name', PARAM_TEXT);
$mform->addRule('name', null, 'required', null, 'client');
$mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
$this->standard_intro_elements(get_string('description', 'feedback'));
//-------------------------------------------------------------------------------
$mform->addElement('header', 'timinghdr', get_string('availability'));
$mform->addElement('date_time_selector', 'timeopen', get_string('feedbackopen', 'feedback'),
array('optional' => true));
$mform->addElement('date_time_selector', 'timeclose', get_string('feedbackclose', 'feedback'),
array('optional' => true));
//-------------------------------------------------------------------------------
$mform->addElement('header', 'feedbackhdr', get_string('questionandsubmission', 'feedback'));
$options=array();
$options[1] = get_string('anonymous', 'feedback');
$options[2] = get_string('non_anonymous', 'feedback');
$mform->addElement('select',
'anonymous',
get_string('anonymous_edit', 'feedback'),
$options);
// check if there is existing responses to this feedback
if (is_numeric($this->_instance) AND
$this->_instance AND
$feedback = $DB->get_record("feedback", array("id"=>$this->_instance))) {
$completed_feedback_count = feedback_get_completeds_group_count($feedback);
} else {
$completed_feedback_count = false;
}
if ($completed_feedback_count) {
$multiple_submit_value = $feedback->multiple_submit ? get_string('yes') : get_string('no');
$mform->addElement('text',
'multiple_submit_static',
get_string('multiplesubmit', 'feedback'),
array('size'=>'4',
'disabled'=>'disabled',
'value'=>$multiple_submit_value));
$mform->setType('multiple_submit_static', PARAM_RAW);
$mform->addElement('hidden', 'multiple_submit', '');
$mform->setType('multiple_submit', PARAM_INT);
$mform->addHelpButton('multiple_submit_static', 'multiplesubmit', 'feedback');
} else {
$mform->addElement('selectyesno',
'multiple_submit',
get_string('multiplesubmit', 'feedback'));
$mform->addHelpButton('multiple_submit', 'multiplesubmit', 'feedback');
}
$mform->addElement('selectyesno', 'email_notification', get_string('email_notification', 'feedback'));
$mform->addHelpButton('email_notification', 'email_notification', 'feedback');
$mform->addElement('selectyesno', 'autonumbering', get_string('autonumbering', 'feedback'));
$mform->addHelpButton('autonumbering', 'autonumbering', 'feedback');
//-------------------------------------------------------------------------------
$mform->addElement('header', 'aftersubmithdr', get_string('after_submit', 'feedback'));
$mform->addElement('selectyesno', 'publish_stats', get_string('show_analysepage_after_submit', 'feedback'));
$mform->addElement('editor',
'page_after_submit_editor',
get_string("page_after_submit", "feedback"),
null,
$editoroptions);
$mform->setType('page_after_submit_editor', PARAM_RAW);
$mform->addElement('text',
'site_after_submit',
get_string('url_for_continue', 'feedback'),
array('size'=>'64', 'maxlength'=>'255'));
$mform->setType('site_after_submit', PARAM_TEXT);
$mform->addHelpButton('site_after_submit', 'url_for_continue', 'feedback');
//-------------------------------------------------------------------------------
$this->standard_coursemodule_elements();
//-------------------------------------------------------------------------------
// buttons
$this->add_action_buttons();
}
public function data_preprocessing(&$default_values) {
$editoroptions = feedback_get_editor_options();
if ($this->current->instance) {
// editing an existing feedback - let us prepare the added editor elements (intro done automatically)
$draftitemid = file_get_submitted_draft_itemid('page_after_submit');
$default_values['page_after_submit_editor']['text'] =
file_prepare_draft_area($draftitemid, $this->context->id,
'mod_feedback', 'page_after_submit', false,
$editoroptions,
$default_values['page_after_submit']);
$default_values['page_after_submit_editor']['format'] = $default_values['page_after_submitformat'];
$default_values['page_after_submit_editor']['itemid'] = $draftitemid;
} else {
// adding a new feedback instance
$draftitemid = file_get_submitted_draft_itemid('page_after_submit_editor');
// no context yet, itemid not used
file_prepare_draft_area($draftitemid, null, 'mod_feedback', 'page_after_submit', false);
$default_values['page_after_submit_editor']['text'] = '';
$default_values['page_after_submit_editor']['format'] = editors_get_preferred_format();
$default_values['page_after_submit_editor']['itemid'] = $draftitemid;
}
}
/**
* Allows module to modify the data returned by form get_data().
* This method is also called in the bulk activity completion form.
*
* Only available on moodleform_mod.
*
* @param stdClass $data the form data to be modified.
*/
public function data_postprocessing($data) {
parent::data_postprocessing($data);
if (isset($data->page_after_submit_editor)) {
$data->page_after_submitformat = $data->page_after_submit_editor['format'];
$data->page_after_submit = $data->page_after_submit_editor['text'];
if (!empty($data->completionunlocked)) {
// Turn off completion settings if the checkboxes aren't ticked.
$suffix = $this->get_suffix();
$completion = $data->{'completion' . $suffix};
$autocompletion = !empty($completion) && $completion == COMPLETION_TRACKING_AUTOMATIC;
if (!$autocompletion || empty($data->{'completionsubmit' . $suffix})) {
$data->{'completionsubmit' . $suffix} = 0;
}
}
}
}
/**
* Enforce validation rules here
*
* @param array $data array of ("fieldname"=>value) of submitted data
* @param array $files array of uploaded files "element_name"=>tmp_file_path
* @return array
**/
public function validation($data, $files) {
$errors = parent::validation($data, $files);
// Check open and close times are consistent.
if ($data['timeopen'] && $data['timeclose'] &&
$data['timeclose'] < $data['timeopen']) {
$errors['timeclose'] = get_string('closebeforeopen', 'feedback');
}
return $errors;
}
public function add_completion_rules() {
$mform =& $this->_form;
$suffix = $this->get_suffix();
$completionsubmitel = 'completionsubmit' . $suffix;
$mform->addElement('checkbox',
$completionsubmitel,
'',
get_string('completionsubmit', 'feedback')
);
// Enable this completion rule by default.
$mform->setDefault($completionsubmitel, 1);
return [$completionsubmitel];
}
public function completion_rule_enabled($data) {
$suffix = $this->get_suffix();
return !empty($data['completionsubmit' . $suffix]);
}
}

Some files were not shown because too many files have changed in this diff Show More