Commit a7728b18 authored by Camille Tardy's avatar Camille Tardy
Browse files

Initial commit -v1

parents
Group Quiz
=======
_@author: 2017, Camille Tardy, University of Geneva_
Sub-plugin of Moodle Quiz to enable the group notion for the quiz.
Must be install under `.../mod/quiz/report/group`.
Available in French and English.
Works on moodle 3.1 -> 3.5
### How it works
##### Set up and usage
Creates a menu entry under Quiz > Report > Group quiz.
The plugin is then set up from there, by selecting the grouping to be used.
Students are grouped using the course grouping and group tools.
The teacher must select a grouping when creating the quiz to define which group to use for the group quiz.
If a grouping is selected, only one student per group can fill up the quiz.
If the `"no grouping"` choice is selected, the quiz behaves normally without taking the groups into account.
##### Copy the grades to the group's members
Once the students are done answering, the teacher can copy the grade registered for each participant to the rest of their respective group members in the Gradebook.
The grades copy can be done at any time.
So every time a teacher edit an attempt in the result view of the quiz, or a student is moved from a group to another, the copy will take into account the changes and overwrite the previous grade.
##### Notes
* If a teacher deletes an attempt, the Gradebook is not cleared of the copied grades. It must be done manually by the teacher.
* If a student is in more than one group in the same grouping, the system will only consider his first affiliation.
* Do not change the grouping if some attempts exist for a given quiz.
### TODO in the next update
* Do not allow grouping changing if an attempt already exist in the DB.
\ No newline at end of file
<?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') || die();
require_once($CFG->dirroot . '/mod/quiz/classes/event/attempt_started.php');
require_once($CFG->dirroot . '/mod/quiz/report/group/locallib.php');
/**
* This file defines the function triggered by the event observer.
*
* @package quiz_group
* @copyright 2017 Camille Tardy, University of Geneva
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
**/
class quiz_group_observer{
/**
* Event processor - attempt started
* Create new attempt record in group quiz table
*
* @param \mod_quiz\event\attempt_started $event
* @return bool
*/
public static function attempt_started(core\event\base $event) {
global $DB, $PAGE;
$attempt = $event->get_data();
$cm = $PAGE->cm;
$quiz_id = $cm->instance;
$groupingid = get_groupquiz_groupingid($quiz_id);
if($groupingid == null || $groupingid ==0){
// if grp_quiz is not enabled do nothing
}else{
//check if a user from the same group is trying to attempt quiz when we already have an attempt for this group.
$user_grp = get_user_group_for_groupquiz($attempt['userid'], $quiz_id, $attempt['courseid']);
$attempt_grp_inDB = $DB->get_records('quiz_group_attempts', array('quizid'=>$quiz_id, 'groupid'=>$user_grp, 'groupingid'=>$groupingid));
if (!empty($attempt_grp_inDB)){
// An attempt already exist for this group block current user attempt
$grp_attemptID = 0;
$grp_name = $DB->get_field('groups', 'name', array('id'=>$user_grp));
//return to view quiz page with message : warning(yellow) --> NOTIFY_WARNING // error(red) --> NOTIFY_ERROR
redirect(new moodle_url('/mod/quiz/view.php', array('id' => $cm->id)), get_string('group_attempt_already_created', 'quiz_group', $grp_name), null, \core\output\notification::NOTIFY_ERROR);
}else{
// no attempt yet for this group : proceed with current user
$group_attempt = quiz_group_attempt_to_groupattempt_dbobject($attempt, $quiz_id, $user_grp, $groupingid);
//save in DB
$grp_attemptID = $DB->insert_record('quiz_group_attempts', $group_attempt, true);
}
return $grp_attemptID;
}
}
/**
* Event processor - attempt submited
* edit the group attemp object actual attempt id
*
* @param \mod_quiz\event\attempt_submitted $event
* @return bool
*/
public static function attempt_submitted(core\event\base $event){
global $DB;
$attempt = $event->get_data();
$quiz_id = $attempt['other']['quizid'];
$user_id = $attempt['userid'];
$attempt_id = $attempt['objectid'];
$course_id = $attempt['courseid'];
$groupingid = get_groupquiz_groupingid($quiz_id);
if($groupingid == null || $groupingid ==0){
// of grp_quiz is not enabled do nothing
}else{
$gid = get_user_group_for_groupquiz($user_id, $quiz_id, $course_id);
//retrieve grp attempt object
$grp_attempt = $DB->get_record('quiz_group_attempts', array('groupid'=>$gid, 'quizid'=>$quiz_id));
if(!empty($grp_attempt)){
//edit grp attempt
$grp_attempt->attemptid = $attempt_id;
//save in DB
$DB->update_record('quiz_group_attempts', $grp_attempt, false);
}else {
//ERROR : Grp attempt not in DB
//create grp_attempt if not in DB
create_grpattempt_from_attempt($attempt,$course_id);
}
}
return true;
}
/**
* Event processor - attempt deleted
* delete the group attempt record in group quiz table
*
* @param \mod_quiz\event\attempt_started $event
* @return bool
*/
public static function attempt_deleted(core\event\base $event) {
global $DB;
$attempt = $event->get_data();
$quiz_id = $attempt['other']['quizid'];
// $attempt_id = $attempt['objectid'];
$user_id = $attempt['relateduserid'];
//attempt can be null in grp_attempt if attempt never submitted by user
//better to retreive attempt via quizid and userid
//delete record in DB
$DB->delete_records('quiz_group_attempts', array('quizid'=>$quiz_id, 'userid'=>$user_id));
return true ;
}
/**
* Event processor - attempt abandoned
* delete the group attempt record in group quiz table
*
* @param \mod_quiz\event\attempt_abandoned $event
* @return bool
*/
public static function attempt_abandoned(core\event\base $event) {
global $DB;
$attempt = $event->get_data();
$quizid = $attempt['other']['quizid'];
$userid = $attempt['other']['userid'];
// $courseid = $attempt['other']['courseid'];
/* $attemptid = $attempt['other']['$attemptid'];
if($attemptid !== null){
//if we know the attempt id and if it exist in DB use
$DB->delete_records('quiz_group_attempts', array('quizid'=>$quiz_id, 'attemptid'=>$attempt_id));
}else{}*/
// $groupid = get_user_group_for_groupquiz($userid, $quizid, $courseid);
//delete record in DB for group in quiz
$DB->delete_records('quiz_group_attempts', array('quizid'=>$quizid, 'userid'=>$userid));
return true ;
}
/**
* Flag whether a course reset is in progress or not.
*
* @var int The course ID.
*/
protected static $resetinprogress = false;
/**
* A course reset has started.
*
* @param \core\event\base $event The event.
* @return void
*/
public static function course_reset_started($event) {
self::$resetinprogress = $event->courseid;
}
/**
* A course reset has ended.
*
* @param \core\event\base $event The event.
* @return void
*/
public static function course_reset_ended($event) {
if (!empty(self::$resetinprogress)) {
if (!empty($event->other['reset_options']['reset_groups_remove'])) {
quiz_process_grp_deleted_in_course($event->courseid);
}
}
self::$resetinprogress = null;
}
/**
* A group was deleted.
*
* @param \core\event\base $event The event.
* @return void
*/
public static function group_deleted($event) {
if (!empty(self::$resetinprogress)) {
// We will take care of that once the course reset ends.
return;
}
quiz_process_grp_deleted_in_course($event->courseid);
}
}
\ No newline at end of file
<?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 defines the observers for the quiz group.
*
* @package quiz_group
* @copyright 2017 Camille Tardy, University of Geneva
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
// catch attempt started
$observers = array(
array(
'eventname' => '\mod_quiz\event\attempt_started',
'callback' => 'quiz_group_observer::attempt_started',
),
// catch attempt submitted
array(
'eventname' => '\mod_quiz\event\attempt_submitted',
'callback' => 'quiz_group_observer::attempt_submitted',
),
//catch attempt abandoned
array(
'eventname' => '\mod_quiz\event\attempt_abandoned',
'callback' => 'quiz_group_observer::attempt_abandoned',
),
// catch attempt deleted
array(
'eventname' => '\mod_quiz\event\attempt_deleted',
'callback' => 'quiz_group_observer::attempt_deleted',
),
// group event and course reset
array(
'eventname' => '\core\event\course_reset_started',
'callback' => 'quiz_group_observer::course_reset_started',
),
array(
'eventname' => '\core\event\course_reset_ended',
'callback' => 'quiz_group_observer::course_reset_ended',
),
array(
'eventname' => '\core\event\group_deleted',
'callback' => 'quiz_group_observer::group_deleted'
)
);
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="mod/quiz/report/group/db" VERSION="" COMMENT="XMLDB file for Moodle mod/quiz/report/report"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../../../lib/xmldb/xmldb.xsd"
>
<TABLES>
<TABLE NAME="quiz_group_attempts" COMMENT="This table records the group quiz attempts.">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="attemptid" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="Foreign key"/>
<FIELD NAME="quizid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Foreign key"/>
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Foreign key"/>
<FIELD NAME="groupid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Foreign key"/>
<FIELD NAME="groupingid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Foreign key"/>
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Timestamp of when this row was last modified."/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
</KEYS>
</TABLE>
<TABLE NAME="quiz_group" COMMENT="This table records the group quiz pairing.">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="groupingid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Foreign key"/>
<FIELD NAME="quizid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Foreign key"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
</KEYS>
</TABLE>
</TABLES>
</XMLDB>
<?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 defines the setting form for the quiz group.
*
* @package quiz_group
* @copyright 2017 Camille Tardy, University of Geneva
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once($CFG->libdir . '/formslib.php');
/**
* Quiz group report settings form.
*
* @copyright 2017 Camille Tardy, University of Geneva
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class quiz_group_dispatchgrade_form extends moodleform {
protected function definition() {
//todo: disable if no attempt
$mform_dispatch = $this->_form;
$mform_dispatch->addElement('html', "<p>".get_string('dispatchgrade_info', 'quiz_group')."</p>");
$mform_dispatch->addElement('hidden', 'groupingid');
//submit button
$mform_dispatch->addElement('submit', 'dispatch', get_string('dispatchgrades', 'quiz_group'));
}
function validation($data, $files) {
//No form validation needed.
}
}
<?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 defines the setting form for the quiz group.
*
* @package quiz_group
* @copyright 2017 Camille Tardy, University of Geneva
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once($CFG->libdir . '/formslib.php');
/**
* Quiz group report settings form.
*
* @copyright 2017 Camille Tardy, University of Geneva
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class quiz_group_settings_form extends moodleform {
protected function definition() {
global $COURSE;
$mform = $this->_form;
$mform->addElement('header', 'quizgroupsubmission', get_string('quizgroup', 'quiz_group'));
//todo : fix hasattempt --> kills action button return url (bad quiz id)
// if attempt block edit.
/* $mform->addElement('hidden', 'hasattempts');
$mform->setType('hasattempts',PARAM_RAW);
$mform->setDefault('hasattempts', false);
if($this->_customdata['hasattempts']===true){
$mform->addElement('html', "<p style='color: red; background-color: #FFFECE; padding: 1px 10px;'>".get_string('quiz_has_attempts', 'quiz_group')."</p> <br/>");
// $mform->setDefault('hasattempts', true);
}*/
$mform->addElement('html', "<p>".get_string('info_bygroup', 'quiz_group')."</p>");
$mform->addElement('html', "<p><em>".get_string('warning_group', 'quiz_group')."</em></p></br></br>");
$mform->addElement('html', "<h4>".get_string('title_groupingselect', 'quiz_group')."</h4>");
//get grouping list from course
$groupings = groups_get_all_groupings($COURSE->id);
$options = array();
$options[0] = get_string('no_grouping', 'quiz_group');
foreach ($groupings as $grouping) {
$options[$grouping->id] = $grouping->name;
}
// create select element and pre-select current value
$mform->addElement('select', 'sel_groupingid', get_string('teamsubmissiongroupingid', 'assign'), $options);
//submit button
$this->add_action_buttons(true, get_string('savechanges', 'quiz_group'), false);
//$mform->disabledIf('submitbutton', 'hasattempts', 'eq',true);
//$mform->disabledIf('sel_groupingid', 'hasattempts', 'eq',true);
}
function validation($data, $files) {
//No form validation needed yet.
}
}
<?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 'quiz_group', language 'en'
*
* @package quiz_group
* @copyright 2017 Camille Tardy, University of Geneva
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['pluginname'] = 'Group quiz';
$string['group'] = 'Group quiz';
$string['quizgroup'] = 'Group quiz';
$string['activatebygroup'] = 'Do quiz for group of student?';
$string['no_grouping'] = 'Standard Quiz (no grouping)';
$string['info_bygroup'] = 'Only one student per group answers the quiz questions. The grade is copied to all the members of the group using the second form below. <br/> If you need to change any grade in the test, you must use the Responses view and not the Gradebook. Then you can apply again the group grade to all the members of the group.';
$string['warning_group'] = "Careful: <ul> <li>The group quiz uses a specific grouping. Make sure to give the appropriate access rule in the 'Restrict access' section of the quiz main settings page. </li><li/>If a student is in more than one groupe in the same grouping, the system will only consider his first affiliation.</li><li>Do not change the grouping if attempts exist for this quiz!</li></ul>";
$string['error_groupingquizsetting'] = 'The selected grouping for access and quiz must be the same.';
$string['savechanges'] = 'Save';
$string['settings_edited'] = 'The quiz has been edited with the following grouping: {$a}';
$string['title_groupingselect'] = 'Choose the grouping for the quiz';
$string['no_group_string'] = 'No grouping';
$string['quiz_has_attempts'] = 'This quiz already has attempts. You can no longer update the group setting.';
$string['canceledit'] ='You have canceled the edition of group setting.';
$string['group_attempt_already_created'] = 'An attempt for this Group quiz for your group : {$a}, already exist.';
$string['titleapply'] = 'Transfer group grades';
$string['apply'] = 'Apply grades';
$string['info_dispatchgrades'] = 'Apply the group grades to all the group members in the Gradebook. You can repeat this operation every time you edit a grade. ';
$string['dispatchgrade_done'] = 'The group grades have been dispatch to the other groups member.';
$string['user_notin_grouping'] = 'You do not belong to the selected grouping for this Group Quiz. Please contact the manager of the quiz.';
\ No newline at end of file
<?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 'quiz_group', language 'fr'
*
* @package quiz_group
* @copyright 2017 Camille Tardy, University of Geneva
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['pluginname'] = 'Test en groupe';
$string['group'] = 'Test en groupe';
$string['quizgroup'] = 'Test en groupe';
$string['activatebygroup'] = 'Faire passer le test par groupe ?';
$string['no_grouping'] = 'Test standard (pas de groupes)';
$string['info_bygroup'] = 'Seul un étudiant répond au test. La même note est distribuée à tous les membres du groupe en utilisant le formulaire ci dessous.<br/> Pour changer une note, il faut utiliser la vue des Réponses et non pas le Carnet de note. Vous pourrez alors copier la note à tous les membres du groupe.';
$string['warning_group'] = 'Attention : <ul> <li>Le test en groupe utilise un groupement spécifique. Assurez vous de donner les accès appropriés dans la section "Restreindre l\'acces" dans les paramètres du quiz.</li><li/>Si un étudiant est dans plusieurs groupes d\'un même groupement, le système ne considèrerea que sa première affiliation.</li><li>Ne pas changer le groupement si des tentatives sont déjà enregistrées pour ce test!</li></ul>';
$string['error_groupingquizsetting'] = 'Le groupement sélectionné pour l\'accès et le test doivent être identiques.';
$string['savechanges'] = 'Enregistrer';
$string['settings_edited'] = 'Le test a bien été modifié avec le groupement : {$a}';
$string['title_groupingselect'] = 'Choisissez le groupement pour le test';
$string['no_group_string'] = 'Pas de groupement';
$string['quiz_has_attempts'] = 'Ce test a des participations. Vous ne pouvez plus modifier les paramètres de groupe.';
$string['canceledit'] ='Edition du paramettre de groupe annulé.';
$string['group_attempt_already_created'] = 'Une participation à ce test en groupe pour votre groupe : {$a}, existe déjà.';
$string['titleapply'] = 'Transmettre les notes de groupe';
$string['apply'] = 'Appliquer les notes';
$string['info_dispatchgrades'] = 'Appliquer la note de groupe à tous les membres du groupe dans le Gradebook. Vous pouvez répeter cette opération à chaque fois que vous changez une note.';
$string['dispatchgrade_done'] = 'Les notes de groupe ont été copiées à tous les autres membres du groupe.';
$string['user_notin_grouping'] = 'Vous n\'appartenez pas au groupement pour ce test en groupe. Veuillez contacter le responsable du test.';
\ No newline at end of file
<?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/>.
/**
* Library of functions used by the quiz module.
*
* This contains functions that are called from within the quiz group sub_module only
*
* @package quiz_group
* @copyright 2017 Camille Tardy, University of Geneva
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();