diff --git a/classes/common.php b/classes/common.php
new file mode 100644
index 0000000..fe86e64
--- /dev/null
+++ b/classes/common.php
@@ -0,0 +1,51 @@
+get_record('availability_examus', $conditions);
+ if ($oldentry and $oldentry->status != 'Not inited') {
+ $entries = $DB->get_records('availability_examus', [
+ 'userid' => $oldentry->userid,
+ 'courseid' => $oldentry->courseid,
+ 'cmid' => $oldentry->cmid,
+ 'status' => 'Not inited']);
+ if (count($entries) == 0) {
+ $timenow = time();
+ $entry = new stdClass();
+ $entry->userid = $oldentry->userid;
+ $entry->courseid = $oldentry->courseid;
+ $entry->cmid = $oldentry->cmid;
+ $entry->accesscode = md5(uniqid(rand(), 1));
+ $entry->status = 'Not inited';
+ $entry->timecreated = $timenow;
+ $entry->timemodified = $timenow;
+ $DB->insert_record('availability_examus', $entry);
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ public static function delete_empty_entries($userid, $courseid, $cmid = null){
+ global $DB;
+
+ $condition = [
+ 'userid' => $userid,
+ 'courseid' => $courseid,
+ 'status' => 'Not inited'
+ ];
+
+ if(!empty($cmid)) {
+ $condition['cmid'] = $cmid;
+ }
+
+ $DB->delete_records('availability_examus', $condition);
+ }
+
+
+}
diff --git a/classes/condition.php b/classes/condition.php
index 11a3f6b..47349c4 100644
--- a/classes/condition.php
+++ b/classes/condition.php
@@ -56,15 +56,17 @@ class condition extends \core_availability\condition {
* @param stdClass $structure Structure
*/
public function __construct($structure) {
+ $manual_modes = ['normal', 'identification'];
+
if (!empty($structure->duration)) {
$this->duration = $structure->duration;
}
if (!empty($structure->mode)) {
$this->mode = $structure->mode;
}
- if (array_key_exists("scheduling_required", $structure)) {
- $this->scheduling_required = $structure->scheduling_required;
- }
+
+ $this->scheduling_required = in_array($this->mode, $manual_modes);
+
if (!empty($structure->rules)) {
$this->rules = $structure->rules;
}
@@ -78,11 +80,23 @@ public function __construct($structure) {
* @param int $cmid Cm id
*/
private static function delete_empty_entry($userid, $courseid, $cmid) {
- global $DB;
- $DB->delete_records('availability_examus', array(
- 'userid' => $userid, 'courseid' => $courseid, 'cmid' => $cmid, 'status' => 'Not inited'));
+ common::delete_empty_entries($userid, $courseid, $cmid);
+ }
+
+ /**
+ * delete empty entry for cm
+ *
+ * @param int $userid User id
+ * @param stdClass $cm Cm
+ * @return bool
+ */
+ public static function delete_empty_entry_for_cm($userid, $cm) {
+ $course = $cm->get_course();
+ $courseid = $course->id;
+ self::delete_empty_entry($userid, $courseid, $cm->id);
}
+
/**
* has examus condition
*
@@ -165,6 +179,7 @@ private static function get_examus_conditions($cm) {
*/
public function save() {
return (object) [
+ 'type' => 'examus',
'duration' => (int) $this->duration,
'mode' => (string) $this->mode,
'scheduling_required' => (bool) $this->scheduling_required,
@@ -233,17 +248,6 @@ protected function get_debug_string() {
return in_array('examus', $_SESSION) ? 'YES' : 'NO';
}
- /**
- * course mudule deleted handler
- *
- * @param \core\event\course_module_deleted $event Event
- */
- public static function course_module_deleted(\core\event\course_module_deleted $event) {
- global $DB;
- $cmid = $event->contextinstanceid;
- $DB->delete_records('availability_examus', array('cmid' => $cmid));
- }
-
/**
* create entry for cm
*
@@ -257,18 +261,6 @@ public static function create_entry_for_cm($userid, $cm) {
return self::create_entry_if_not_exist($userid, $courseid, $cm->id);
}
- /**
- * delete empty entry for cm
- *
- * @param int $userid User id
- * @param stdClass $cm Cm
- * @return bool
- */
- public static function delete_empty_entry_for_cm($userid, $cm) {
- $course = $cm->get_course();
- $courseid = $course->id;
- self::delete_empty_entry($userid, $courseid, $cm->id);
- }
public static function make_entry($courseid, $cmid, $userid=null) {
$timenow = time();
@@ -295,9 +287,10 @@ public static function make_entry($courseid, $cmid, $userid=null) {
private static function create_entry_if_not_exist($userid, $courseid, $cmid) {
// TODO: refactor this to get courseid and duration from cm.
global $DB;
+
$entries = $DB->get_records(
'availability_examus',
- array('userid' => $userid, 'courseid' => $courseid, 'cmid' => $cmid),
+ ['userid' => $userid, 'courseid' => $courseid, 'cmid' => $cmid],
$sort = 'id');
if (count($entries) == 0) {
@@ -314,21 +307,4 @@ private static function create_entry_if_not_exist($userid, $courseid, $cmid) {
return null;
}
- /**
- * user enrolment deleted handles
- *
- * @param \core\event\user_enrolment_deleted $event Event
- */
- public static function user_enrolment_deleted(\core\event\user_enrolment_deleted $event) {
- $cmid = $event->contextinstanceid;
- $course = get_course($event->courseid);
- $modinfo = get_fast_modinfo($course);
- $cm = $modinfo->get_cm($cmid);
- $userid = $event->relateduserid;
-
- if (self::has_examus_condition($cm)) {
- self::delete_empty_entry($userid, $event->courseid, $cmid);
- }
- }
-
-}
\ No newline at end of file
+}
diff --git a/classes/frontend.php b/classes/frontend.php
index d484ad5..d8588a1 100644
--- a/classes/frontend.php
+++ b/classes/frontend.php
@@ -39,12 +39,13 @@ class frontend extends \core_availability\frontend {
* @return array
*/
protected function get_javascript_strings() {
- return ['title', 'error_setduration', 'duration', 'link', 'mode', 'normal_mode',
- 'rules', 'olympics_mode', 'identification_mode', 'allow_to_use_websites',
- 'allow_to_use_books', 'allow_to_use_paper', 'allow_to_use_messengers',
- 'allow_to_use_calculator', 'allow_to_use_excel', 'allow_to_use_human_assistant',
- 'allow_absence_in_frame', 'allow_voices', 'allow_wrong_gaze_direction',
- 'scheduling_required'];
+ return [
+ 'title', 'error_setduration', 'duration', 'link', 'mode', 'normal_mode',
+ 'rules', 'olympics_mode', 'identification_mode', 'allow_to_use_websites',
+ 'allow_to_use_books', 'allow_to_use_paper', 'allow_to_use_messengers',
+ 'allow_to_use_calculator', 'allow_to_use_excel', 'allow_to_use_human_assistant',
+ 'allow_absence_in_frame', 'allow_voices', 'allow_wrong_gaze_direction'
+ ];
}
/**
diff --git a/classes/log.php b/classes/log.php
new file mode 100644
index 0000000..590a54a
--- /dev/null
+++ b/classes/log.php
@@ -0,0 +1,449 @@
+libdir . '/tablelib.php');
+
+class log {
+ protected $entries = [];
+ protected $entries_count = null;
+ protected $pages_count = null;
+ protected $per_page = 30;
+ protected $page = 0;
+
+ protected $table = null;
+ protected $url = null;
+ protected $filters = null;
+
+ public function __construct($filters, $page) {
+ global $PAGE;
+
+ $this->url = $PAGE->url;
+ $this->filters = $filters;
+ $this->page = $page;
+
+ $this->url->params($filters);
+
+ $this->setup_table();
+ $this->fetch_data();
+ }
+
+ protected function fetch_data(){
+ global $DB;
+ $select = [
+ 'e.id id',
+ 'e.timemodified timemodified',
+ 'timescheduled',
+ 'u.firstname u_firstname',
+ 'u.lastname u_lastname',
+ 'u.email u_email',
+ 'u.id userid',
+ 'e.status status',
+ 'review_link',
+ 'cmid',
+ 'courseid'
+ ];
+
+ $where = ['1'];
+ $params = $this->filters;
+
+ if(isset($params['from[day]']) && isset($params['from[month]']) && isset($params['from[year]'])){
+ $month = $params['from[month]'];
+ $day = $params['from[day]'];
+ $year = $params['from[year]'];
+ unset($params['from[month]'], $params['from[day]'], $params['from[year]']);
+
+ $params['from'] = mktime(0,0,0, $month, $day, $year);
+ };
+
+ if(isset($params['to[day]']) && isset($params['to[month]']) && isset($params['to[year]'])){
+ $month = $params['to[month]'];
+ $day = $params['to[day]'];
+ $year = $params['to[year]'];
+ unset($params['to[month]'], $params['to[day]'], $params['to[year]']);
+
+ $params['to'] = mktime(23,59,59, $month, $day, $year);
+ };
+
+
+ foreach($params as $key => $value){
+ if(empty($value)){
+ continue;
+ }
+ switch($key){
+ case 'from':
+ $where[]= 'e.timemodified > :'.$key;
+ break;
+
+ case 'to':
+ $where[]= 'e.timemodified <= :'.$key;
+ break;
+
+ case 'userquery':
+ $params[$key] = $value.'%';
+ $where[]= 'u.email LIKE :'.$key;
+ break;
+
+ default:
+ $where[]= $key.' = :'.$key;
+ }
+ }
+
+ $orderBy = $this->table->get_sql_sort();
+
+ $query = 'SELECT '.implode(', ', $select).' FROM {availability_examus} e '
+ . ' LEFT JOIN {user} u ON u.id=e.userid '
+ . ' WHERE '.implode(' AND ', $where)
+ . ($orderBy ? ' ORDER BY '. $orderBy : '')
+ . ' LIMIT '.($this->page * $this->per_page).','.$this->per_page
+ ;
+
+ $queryCount = 'SELECT count(e.id) as `count` FROM {availability_examus} e LEFT JOIN {user} u ON u.id=e.userid WHERE '.implode(' AND ', $where);
+
+ $this->entries = $DB->get_records_sql($query, $params);
+
+ $result = $DB->get_records_sql($queryCount, $params);
+ $this->entries_count = reset($result)->count;
+ $this->pages_count = ceil($this->entries_count / $this->per_page);
+
+ $this->table->pagesize($this->per_page, $this->pages_count);
+ }
+
+ protected function setup_table(){
+ $table = new \flexible_table('availability_examus_table');
+
+ $table->define_columns(['timemodified', 'timescheduled', 'u_email', 'courseid', 'cmid', 'status', 'review_link', 'create_entry']);
+
+ $table->define_headers([
+ get_string('date_modified', 'availability_examus'),
+ get_string('time_scheduled', 'availability_examus'),
+ get_string('user'),
+ get_string('course'),
+ get_string('module', 'availability_examus'),
+ get_string('status', 'availability_examus'),
+ get_string('review', 'availability_examus'),
+ ''
+ ]);
+
+ $table->define_baseurl($this->url);
+ $table->sortable(true, 'date_modified');
+ $table->no_sorting('courseid');
+ $table->no_sorting('cmid');
+ $table->set_attribute('id', 'entries');
+ $table->set_attribute('class', 'generaltable generalbox');
+ $table->setup();
+ $this->table = $table;
+ }
+
+ public function render_table() {
+ $entries = $this->entries;
+ $table = $this->table;
+
+ if (!empty($entries)) {
+ foreach ($entries as $entry) {
+ $row = [];
+
+ $date = usergetdate($entry->timemodified);
+ $row[] = '' . $date['year'] . '.' . $date['mon'] . '.' . $date['mday'] . ' ' .
+ $date['hours'] . ':' . $date['minutes'];
+
+ if ($entry->timescheduled) {
+ $timescheduled = usergetdate($entry->timescheduled);
+ $row[] = '' . $timescheduled['year'] . '.' . $timescheduled['mon'] . '.' . $timescheduled['mday'] . ' ' .
+ $timescheduled['hours'] . ':' . $timescheduled['minutes'];
+ } else {
+ $row[] = '';
+ }
+
+ $row[] = $entry->u_firstname . " " . $entry->u_lastname . "
" . $entry->u_email;
+
+ $course = get_course($entry->courseid);
+ $modinfo = get_fast_modinfo($course);
+ $cm = $modinfo->get_cm($entry->cmid);
+
+ $row[] = $course->fullname;
+ $row[] = $cm->get_formatted_name();
+ $row[] = $entry->status;
+ if ($entry->review_link !== null) {
+ $row[] = "" . get_string('link', 'availability_examus') . "";
+ } else {
+ $row[] = "-";
+ }
+
+ if ($entry->status != 'Not inited' and $entry->status != 'Scheduled') {
+ $row[] = "
";
+ } else {
+ $row[] = "-";
+ }
+ $table->add_data($row);
+ }
+ $table->print_html();
+ }
+
+ }
+
+ /**
+ * Return list of modules to show in selector.
+ *
+ * @return array list of courses.
+ */
+ public function get_module_list() {
+ global $DB, $SITE;
+
+ $courses = ['' => 'All modules'];
+
+ $sitecontext = \context_system::instance();
+ // First check to see if we can override showcourses and showusers.
+ $numcourses = $DB->count_records("course");
+
+ if ($courserecords = $DB->get_records("module", null, "fullname", "id,shortname,fullname,category")) {
+ foreach ($courserecords as $course) {
+ if ($course->id == SITEID) {
+ $courses[$course->id] = format_string($course->fullname) . ' (' . get_string('site') . ')';
+ } else {
+ $courses[$course->id] = format_string(get_course_display_name_for_list($course));
+ }
+ }
+ }
+ \core_collator::asort($courses);
+
+ return $courses;
+ }
+
+ /**
+ * Return list of courses to show in selector.
+ *
+ * @return array list of courses.
+ */
+ public function get_course_list() {
+ global $DB, $SITE;
+
+ $courses = [];
+
+ $sitecontext = \context_system::instance();
+ // First check to see if we can override showcourses and showusers.
+ $numcourses = $DB->count_records("course");
+
+ if ($courserecords = $DB->get_records("course", null, "fullname", "id,shortname,fullname,category")) {
+ foreach ($courserecords as $course) {
+ if ($course->id == SITEID) {
+ $courses[$course->id] = format_string($course->fullname) . ' (' . get_string('site') . ')';
+ } else {
+ $courses[$course->id] = format_string(get_course_display_name_for_list($course));
+ }
+ }
+ }
+ \core_collator::asort($courses);
+
+ return $courses;
+ }
+
+ /**
+ * Return list of courses to show in selector.
+ *
+ * @return array list of courses.
+ */
+ public function get_status_list() {
+ $statuses = [
+ 'Started' => 'Started',
+ 'Not inited' => 'Not inited',
+ 'Rules Violation' => 'Rules Violation',
+ 'Clean' => 'Clean',
+ 'Suspicious' => 'Suspicious',
+ ];
+
+
+ return $statuses;
+ }
+
+ /**
+ * Return list of users.
+ *
+ * @return array list of users.
+ */
+ public function get_user_list() {
+ global $CFG, $SITE;
+
+ $courseid = $SITE->id;
+ if (!empty($this->course)) {
+ $courseid = $this->course->id;
+ }
+ $context = \context_course::instance($courseid);
+ $limitfrom = 0;
+ $limitnum = 10000;
+ $courseusers = get_enrolled_users($context, '', null, 'u.id, ' . get_all_user_name_fields(true, 'u'),
+ null, $limitfrom, $limitnum);
+
+ $users = array();
+ if ($courseusers) {
+ foreach ($courseusers as $courseuser) {
+ $users[$courseuser->id] = fullname($courseuser, has_capability('moodle/site:viewfullnames', $context));
+ }
+ }
+ $users[$CFG->siteguest] = get_string('guestuser');
+
+ return $users;
+ }
+
+ /**
+ * Return list of date options.
+ *
+ * @return array date options.
+ */
+ public function get_date_options() {
+ global $SITE;
+
+ $strftimedate = get_string("strftimedate");
+ $strftimedaydate = get_string("strftimedaydate");
+
+ // Get all the possible dates.
+ // Note that we are keeping track of real (GMT) time and user time.
+ // User time is only used in displays - all calcs and passing is GMT.
+ $timenow = time(); // GMT.
+
+ // What day is it now for the user, and when is midnight that day (in GMT).
+ $timemidnight = usergetmidnight($timenow);
+
+ // Put today up the top of the list.
+ $dates = array("$timemidnight" => get_string("today").", ".userdate($timenow, $strftimedate) );
+
+ // If course is empty, get it from frontpage.
+ $course = $SITE;
+ if (!empty($this->course)) {
+ $course = $this->course;
+ }
+ if (!$course->startdate or ($course->startdate > $timenow)) {
+ $course->startdate = $course->timecreated;
+ }
+
+ $numdates = 1;
+ while ($timemidnight > $course->startdate and $numdates < 365) {
+ $timemidnight = $timemidnight - 86400;
+ $timenow = $timenow - 86400;
+ $dates["$timemidnight"] = userdate($timenow, $strftimedaydate);
+ $numdates++;
+ }
+ return $dates;
+ }
+
+ public function render_filter_form() {
+ global $OUTPUT;
+
+ $courseid = $this->filters['courseid'];
+
+ $userquery = $this->filters['userquery'];
+ $date = $this->filters['timemodified'];
+ $status = $this->filters['status'];
+
+ echo html_writer::start_tag('form', ['class' => 'examuslogselecform', 'action' => $this->url, 'method' => 'get']);
+ echo html_writer::start_div();
+
+ // Add course selector.
+ $sitecontext = \context_system::instance();
+ $courses = $this->get_course_list();
+ $users = $this->get_user_list();
+ $dates = $this->get_date_options();
+ $statuses = $this->get_status_list();
+
+ echo html_writer::start_div(null, ['class' => '', 'style' => 'padding: 0 0 0.8rem;']);
+ echo html_writer::label(get_string('selectacourse'), 'menuid', false, ['class' => 'accesshide']);
+ echo html_writer::select($courses, "courseid", $courseid, get_string('allcourses', 'availability_examus'), ['style'=>'height: 2.5rem;margin-right: 0.5rem']);
+
+
+ // Add user selector.
+ echo html_writer::label(get_string('selctauser'), 'menuuser', false, ['class' => 'accesshide']);
+ echo html_writer::empty_tag('input', [
+ 'name' => 'userquery',
+ 'value' => $userquery,
+ 'placeholder' => get_string("userquery", 'availability_examus'),
+ 'class' => 'form-control',
+ 'style' => 'width: auto;clear: none;display: inline-block;vertical-align: middle;font-size:inherit;height: 2.5rem;margin-right: 0.5rem'
+ ]);
+
+ // Add status selector.
+ //echo html_writer::label(get_string('selectstatus'), 'menuuser', false, array('class' => 'accesshide'));
+ echo html_writer::select($statuses, "status", $status, get_string('allstatuses', 'availability_examus'), ['style'=>'height: 2.5rem;margin-right: 0.5rem']);
+
+ /*
+ // Add date selector.
+ echo html_writer::label(get_string('date'), 'menudate', false, ['class' => 'accesshide']);
+ echo html_writer::select($dates, "timemodified", $date, get_string('alldays'));
+ */
+
+
+ // Get the calendar type used - see MDL-18375.
+ $calendartype = \core_calendar\type_factory::get_calendar_instance();
+ $dateformat = $calendartype->get_date_order(2000, date('Y'));
+ // Reverse date element (Day, Month, Year), in RTL mode.
+ if (right_to_left()) {
+ $dateformat = array_reverse($dateformat);
+ }
+
+ echo html_writer::end_div();
+
+ // From date
+ echo html_writer::start_div(null, ['class' => 'fdate_selector', 'style' => 'padding: 0 0 0.8rem;']);
+
+ echo html_writer::label(get_string('fromdate', 'availability_examus'), '', false, ['style' => 'width: 12%;']);
+
+ foreach ($dateformat as $key => $value) {
+ $name = 'from['.$key.']';
+ echo html_writer::select($value, $name, $this->filters[$name], null, ['style'=>'height: 2.5rem;margin-right: 0.5rem']);
+ }
+ // The YUI2 calendar only supports the gregorian calendar type so only display the calendar image if this is being used.
+ if ($calendartype->get_name() === 'gregorian') {
+ form_init_date_js();
+ echo html_writer::start_tag('a', [
+ 'href' => '#',
+ 'title' => get_string('calendar', 'calendar'),
+ 'class' => 'visibleifjs',
+ 'name' => 'from[calendar]'
+ ]);
+ echo $OUTPUT->pix_icon('i/calendar', get_string('calendar', 'calendar') , 'moodle');
+ echo html_writer::end_tag('a');
+ }
+ echo html_writer::end_div();
+
+ // To date
+ echo html_writer::start_div(null, ['class' => 'fdate_selector', 'style' => 'padding: 0 0 0.8rem;']);
+
+ echo html_writer::label(get_string('todate', 'availability_examus'), '', false, ['style' => 'width: 12%;']);
+
+ foreach ($dateformat as $key => $value) {
+ $name = 'to['.$key.']';
+ echo html_writer::select($value, $name, $this->filters[$name], null, ['style'=>'height: 2.5rem;margin-right: 0.5rem']);
+ }
+ // The YUI2 calendar only supports the gregorian calendar type so only display the calendar image if this is being used.
+ if ($calendartype->get_name() === 'gregorian') {
+ form_init_date_js();
+ echo html_writer::start_tag('a', [
+ 'href' => '#',
+ 'title' => get_string('calendar', 'calendar'),
+ 'class' => 'visibleifjs',
+ 'name' => 'to[calendar]'
+ ]);
+ echo $OUTPUT->pix_icon('i/calendar', get_string('calendar', 'calendar') , 'moodle');
+ echo html_writer::end_tag('a');
+ }
+ echo html_writer::end_div();
+
+
+ echo html_writer::empty_tag('input', [
+ 'type' => 'submit',
+ 'value' => get_string('apply_filter', 'availability_examus'),
+ 'class' => 'btn btn-secondary'
+ ]);
+
+ echo html_writer::end_div();
+ echo html_writer::end_tag('form');
+
+
+
+ }
+}
\ No newline at end of file
diff --git a/db/access.php b/db/access.php
new file mode 100644
index 0000000..bc5aef7
--- /dev/null
+++ b/db/access.php
@@ -0,0 +1,12 @@
+ [
+ 'riskbitmask' => RISK_PERSONAL | RISK_CONFIG,
+ 'captype' => 'write',
+ 'contextlevel' => CONTEXT_SYSTEM,
+ 'archetypes' => []
+ ],
+];
diff --git a/db/events.php b/db/events.php
index f7a3f70..e7ff222 100644
--- a/db/events.php
+++ b/db/events.php
@@ -25,18 +25,33 @@
defined('MOODLE_INTERNAL') || die();
$observers = [
- [
- 'eventname' => '\core\event\course_module_deleted',
- 'callback' => '\availability_examus\condition::course_module_deleted'
- ],
- [
- 'eventname' => '\core\event\user_enrolment_deleted',
- 'callback' => '\availability_examus\condition::user_enrolment_deleted'
- ],
- [
- 'eventname' => '\mod_quiz\event\attempt_submitted',
- 'callback' => 'examus_attempt_submitted_handler',
- 'includefile' => '/availability/condition/examus/locallib.php',
- 'internal' => false
- ]
+ [
+ 'eventname' => '\core\event\course_module_deleted',
+ 'includefile' => '/availability/condition/examus/locallib.php',
+ 'callback' => 'examus_course_module_deleted',
+ ],
+ [
+ 'eventname' => '\core\event\user_enrolment_deleted',
+ 'callback' => 'examus_user_enrolment_deleted',
+ 'includefile' => '/availability/condition/examus/locallib.php',
+
+ ],
+ [
+ 'eventname' => '\mod_quiz\event\attempt_submitted',
+ 'callback' => 'examus_attempt_submitted_handler',
+ 'includefile' => '/availability/condition/examus/locallib.php',
+ 'internal' => false,
+ ],
+ [
+ 'eventname' => '\mod_quiz\event\attempt_started',
+ 'callback' => 'examus_attempt_started_handler',
+ 'includefile' => '/availability/condition/examus/locallib.php',
+ 'internal' => false,
+ ],
+ [
+ 'eventname' => '\mod_quiz\event\attempt_deleted',
+ 'callback' => 'examus_attempt_deleted_handler',
+ 'includefile' => '/availability/condition/examus/locallib.php',
+ 'internal' => false,
+ ],
];
diff --git a/db/install.xml b/db/install.xml
index babb8db..2859821 100644
--- a/db/install.xml
+++ b/db/install.xml
@@ -9,9 +9,10 @@
+
-
+
@@ -28,4 +29,4 @@
-
\ No newline at end of file
+
diff --git a/db/services.php b/db/services.php
index 0f854ab..27fcc3e 100644
--- a/db/services.php
+++ b/db/services.php
@@ -25,30 +25,41 @@
defined('MOODLE_INTERNAL') || die();
// We defined the web service functions to install.
-$functions = array(
- 'availability_examus_user_proctored_modules' => array(
- 'classname' => 'availability_examus_external',
- 'methodname' => 'user_proctored_modules',
- 'classpath' => 'availability/condition/examus/externallib.php',
- 'description' => 'Returns modules exams for user',
- 'type' => 'write',
- 'services' => 'Examus',
- ),
- 'availability_examus_submit_proctoring_review' => array(
- 'classname' => 'availability_examus_external',
- 'methodname' => 'submit_proctoring_review',
- 'classpath' => 'availability/condition/examus/externallib.php',
- 'description' => 'Accepts review for proctoring session',
- 'type' => 'write',
- 'services' => 'Examus',
- )
-);
+$functions = [
+ 'availability_examus_user_proctored_modules' => [
+ 'classname' => 'availability_examus_external',
+ 'methodname' => 'user_proctored_modules',
+ 'classpath' => 'availability/condition/examus/externallib.php',
+ 'description' => 'Returns modules exams for user',
+ 'type' => 'write',
+ 'services' => 'Examus',
+ ],
+
+ 'availability_examus_submit_proctoring_review' => [
+ 'classname' => 'availability_examus_external',
+ 'methodname' => 'submit_proctoring_review',
+ 'classpath' => 'availability/condition/examus/externallib.php',
+ 'description' => 'Accepts review for proctoring session',
+ 'type' => 'write',
+ 'services' => 'Examus',
+ ],
+
+ 'availability_examus_reset_entry' => [
+ 'classname' => 'availability_examus_external',
+ 'methodname' => 'reset_entry',
+ 'classpath' => 'availability/condition/examus/externallib.php',
+ 'description' => 'Resets entry for a user',
+ 'type' => 'write',
+ 'services' => 'Examus',
+ ],
+
+];
// We define the services to install as pre-build services. A pre-build service is not editable by administrator.
-$services = array(
- 'Examus' => array(
- 'functions' => array('availability_examus_user_proctored_modules', 'availability_examus_submit_proctoring_review'),
- 'restrictedusers' => 0,
- 'enabled' => 1,
- )
-);
+$services = [
+ 'Examus' => [
+ 'functions' => array_keys($functions),
+ 'restrictedusers' => 0,
+ 'enabled' => 1,
+ ]
+];
diff --git a/db/upgrade.php b/db/upgrade.php
index f243abb..08ffe44 100644
--- a/db/upgrade.php
+++ b/db/upgrade.php
@@ -54,5 +54,17 @@ function xmldb_availability_examus_upgrade($oldversion) {
}
+ if ($oldversion < 2019031502) {
+ $table = new xmldb_table('availability_examus');
+
+ $field = new xmldb_field('attemptid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
+
+ // Conditionally launch add field timescheduled.
+ if (!$dbman->field_exists($table, $field)) {
+ $dbman->add_field($table, $field);
+ }
+
+ }
+
return true;
}
\ No newline at end of file
diff --git a/externallib.php b/externallib.php
index 6500d51..6a4770b 100644
--- a/externallib.php
+++ b/externallib.php
@@ -26,6 +26,8 @@
global $CFG;
require_once($CFG->libdir . "/externallib.php");
+use core_availability\info_module;
+
/**
* Availability examus class
* @copyright 2017 Max Pomazuev
@@ -129,6 +131,12 @@ public static function user_proctored_modules($useremail, $accesscode) {
$instancesbytypes = $modinfo->get_instances();
foreach ($instancesbytypes as $instances) {
foreach ($instances as $cm) {
+ $availibility_info = new info_module($cm);
+ $reason = '';
+ if($availibility_info && !$availibility_info->is_available($reason)){
+ continue;
+ }
+
if (\availability_examus\condition::has_examus_condition($cm) and $cm->uservisible) {
$entry = \availability_examus\condition::create_entry_for_cm($user->id, $cm);
if ($entry == null) {
@@ -233,14 +241,15 @@ public static function submit_proctoring_review_parameters() {
public static function submit_proctoring_review($accesscode, $status, $reviewlink, $timescheduled) {
global $DB;
- self::validate_parameters(self::submit_proctoring_review_parameters(), array(
+ self::validate_parameters(self::submit_proctoring_review_parameters(), [
'accesscode' => $accesscode,
'review_link' => $reviewlink,
'status' => $status,
- 'timescheduled' => $timescheduled));
+ 'timescheduled' => $timescheduled
+ ]);
$timenow = time();
- $entry = $DB->get_record('availability_examus', array('accesscode' => $accesscode));
+ $entry = $DB->get_record('availability_examus', ['accesscode' => $accesscode]);
if ($entry) {
if ($reviewlink) {
@@ -257,23 +266,74 @@ public static function submit_proctoring_review($accesscode, $status, $reviewlin
$entry->timemodified = $timenow;
$DB->update_record('availability_examus', $entry);
- return array('success' => true, 'error' => null);
+
+ if (!$entry->attemptid) {
+ \availability_examus\common::reset_entry(['accesscode' => $entry->accesscode]);
+ }
+
+ return ['success' => true, 'error' => null];
}
- return array('success' => false, 'error' => 'Entry was not found');
+ return ['success' => false, 'error' => 'Entry was not found'];
}
+
/**
* Returns description of method result value
*
* @return external_description
*/
public static function submit_proctoring_review_returns() {
- return new external_single_structure(
- array(
- 'success' => new external_value(PARAM_BOOL, 'request success status'),
- 'error' => new external_value(PARAM_TEXT, 'error message')
- )
- );
+ return new external_single_structure([
+ 'success' => new external_value(PARAM_BOOL, 'request success status'),
+ 'error' => new external_value(PARAM_TEXT, 'error message')
+ ]);
+ }
+
+
+ /**
+ * Returns success flag and error message for reset operation
+ *
+ * @param string $accesscode accesscode
+ * @return array
+ */
+ public static function reset_entry($accesscode) {
+ global $DB;
+
+ self::validate_parameters(self::reset_entry_parameters(), [
+ 'accesscode' => $accesscode,
+ ]);
+
+ $result = \availability_examus\common::reset_entry(['accesscode' => $accesscode]);
+
+ if ($result) {
+ return ['success' => true, 'error' => null];
+ }else{
+ return ['success' => false, 'error' => 'Entry was not found'];
+ }
+
+ }
+
+ /**
+ * Returns description of method parameters
+ *
+ * @return external_function_parameters
+ */
+ public static function reset_entry_parameters() {
+ return new external_function_parameters([
+ 'accesscode' => new external_value(PARAM_TEXT, 'Access Code'),
+ ]);
+ }
+
+ /**
+ * Returns description of method result value
+ *
+ * @return external_description
+ */
+ public static function reset_entry_returns() {
+ return new external_single_structure([
+ 'success' => new external_value(PARAM_BOOL, 'request success status'),
+ 'error' => new external_value(PARAM_TEXT, 'error message')
+ ]);
}
}
diff --git a/index.php b/index.php
index b153e53..fdddc62 100644
--- a/index.php
+++ b/index.php
@@ -23,45 +23,26 @@
*/
require_once('../../../config.php');
-require_once("{$CFG->libdir}/formslib.php");
+require_once($CFG->libdir . "/formslib.php");
require_once($CFG->libdir . '/adminlib.php');
-require_once($CFG->libdir.'/tablelib.php');
require_login();
-
-admin_externalpage_setup('availability_examus_settings');
+require_capability('availability/examus:logaccess', context_system::instance());
$action = optional_param('action', '', PARAM_ALPHA);
switch ($action) {
case 'renew':
$id = required_param('id', PARAM_TEXT);
- $oldentry = $DB->get_record('availability_examus', array('id' => $id));
- if ($oldentry and $oldentry->status != 'Not inited') {
- $entries = $DB->get_records('availability_examus', array(
- 'userid' => $oldentry->userid,
- 'courseid' => $oldentry->courseid,
- 'cmid' => $oldentry->cmid,
- 'status' => 'Not inited'));
- if (count($entries) == 0) {
- $timenow = time();
- $entry = new stdClass();
- $entry->userid = $oldentry->userid;
- $entry->courseid = $oldentry->courseid;
- $entry->cmid = $oldentry->cmid;
- $entry->accesscode = md5(uniqid(rand(), 1));
- $entry->status = 'Not inited';
- $entry->timecreated = $timenow;
- $entry->timemodified = $timenow;
- $DB->insert_record('availability_examus', $entry);
- redirect('index.php', get_string('new_entry_created', 'availability_examus'),
- null, \core\output\notification::NOTIFY_SUCCESS);
- } else {
- redirect('index.php', get_string('entry_exist', 'availability_examus'),
+ if(\availability_examus\common::reset_entry(['id' => $id])){
+ redirect('index.php', get_string('new_entry_created', 'availability_examus'),
+ null, \core\output\notification::NOTIFY_SUCCESS);
+ } else {
+ redirect('index.php', get_string('entry_exist', 'availability_examus'),
null, \core\output\notification::NOTIFY_ERROR);
- }
}
+
break;
default:
break;
@@ -71,71 +52,28 @@
echo $OUTPUT->header();
echo $OUTPUT->heading(get_string('pluginname', 'availability_examus'));
-
-$entries = $DB->get_records('availability_examus', array(), '-id');
-
-if (!empty($entries)) {
- $table = new flexible_table('availability_examus_table');
-
- $table->define_columns(array('date', 'time_scheduled', 'user', 'course', 'module', 'status', 'review_link', 'create_entry'));
- $table->define_headers(array(
- get_string('date_modified', 'availability_examus'),
- get_string('time_scheduled', 'availability_examus'),
- get_string('user'),
- get_string('course'),
- get_string('module', 'availability_examus'),
- get_string('status', 'availability_examus'),
- get_string('review', 'availability_examus'),
- ''));
-
- $table->define_baseurl($PAGE->url);
- $table->set_attribute('id', 'entries');
- $table->set_attribute('class', 'generaltable generalbox');
- $table->setup();
-
- foreach ($entries as $entry) {
- $row = array();
-
- $date = usergetdate($entry->timemodified);
- $row[] = '' . $date['year'] . '.' . $date['mon'] . '.' . $date['mday'] . ' ' .
- $date['hours'] . ':' . $date['minutes'];
-
- if ($entry->timescheduled) {
- $timescheduled = usergetdate($entry->timescheduled);
- $row[] = '' . $timescheduled['year'] . '.' . $timescheduled['mon'] . '.' . $timescheduled['mday'] . ' ' .
- $timescheduled['hours'] . ':' . $timescheduled['minutes'];
- } else {
- $row[] = '';
- }
-
- $user = $DB->get_record('user', array('id' => $entry->userid));
- $row[] = $user->firstname . " " . $user->lastname . "
" . $user->email;
-
- $course = get_course($entry->courseid);
- $modinfo = get_fast_modinfo($course);
- $cm = $modinfo->get_cm($entry->cmid);
-
- $row[] = $course->fullname;
- $row[] = $cm->get_formatted_name();
- $row[] = $entry->status;
- if ($entry->review_link !== null) {
- $row[] = "" . get_string('link', 'availability_examus') . "";
- } else {
- $row[] = "-";
- }
-
- if ($entry->status != 'Not inited' and $entry->status != 'Scheduled') {
- $row[] = "";
- } else {
- $row[] = "-";
- }
- $table->add_data($row);
- }
- $table->print_html();
-}
+global $PAGE;
+
+$from = isset($_GET['from']) ? $_GET['from'] : ['day' => null, 'month' => null, 'year' => null];
+$to = isset($_GET['to']) ? $_GET['to'] : ['day' => date('j'), 'month' => date('n'), 'year' => date('Y')];;
+
+$filters = [
+ 'courseid' => optional_param('courseid', null, PARAM_INT),
+ 'timemodified' => optional_param('timemodified', null, PARAM_INT),
+ 'moduleid' => optional_param('moduleid', null, PARAM_INT),
+ 'userquery' => optional_param('userquery', null, PARAM_TEXT),
+ 'status' => optional_param('status', null, PARAM_TEXT),
+ 'from[day]' => $from['day'],
+ 'from[month]' => $from['month'],
+ 'from[year]' => $from['year'],
+ 'to[day]' => $to['day'],
+ 'to[month]' => $to['month'],
+ 'to[year]' => $to['year'],
+];
+
+$log = new \availability_examus\log($filters, optional_param('page', 0, PARAM_INT));
+$log->render_filter_form();
+$log->render_table();
echo $OUTPUT->footer();
diff --git a/lang/en/availability_examus.php b/lang/en/availability_examus.php
index 0375c21..f83f6bf 100644
--- a/lang/en/availability_examus.php
+++ b/lang/en/availability_examus.php
@@ -24,12 +24,14 @@
defined('MOODLE_INTERNAL') || die();
+$string['examus:logaccess'] = 'Examus log access';
$string['description'] = 'Allows students to use Examus proctoring service';
$string['pluginname'] = 'Proctoring by Examus';
$string['title'] = 'Examus';
$string['use_examus'] = 'Use examus app to view this module';
$string['settings'] = 'Examus settings';
+$string['log_section'] = 'Examus log';
$string['status'] = 'Status';
$string['review'] = 'Review';
$string['module'] = 'Module';
@@ -63,3 +65,9 @@
$string['allow_wrong_gaze_direction'] = 'Allow wrong gaze direction';
$string['scheduling_required'] = 'A calendar entry is required';
+$string['apply_filter'] = 'Apply filter';
+$string['allcourses'] = 'All courses';
+$string['allstatuses'] = 'All statuses';
+$string['userquery'] = 'User Email starts with';
+$string['fromdate'] = 'From date:';
+$string['todate'] = 'To date:';
diff --git a/lang/ru/availability_examus.php b/lang/ru/availability_examus.php
index c92d91e..f484bdb 100644
--- a/lang/ru/availability_examus.php
+++ b/lang/ru/availability_examus.php
@@ -24,12 +24,14 @@
defined('MOODLE_INTERNAL') || die();
+$string['examus:logaccess'] = 'Доступ к отчету Экзамус';
$string['description'] = 'Позволяет студентам использовать сервис прокторинга "Экзамус"';
$string['pluginname'] = 'Прокторинг "Экзамус"';
$string['title'] = 'Экзамус';
$string['use_examus'] = 'Используйте приложение "Экзамус", чтобы получить доступ к модулю';
$string['settings'] = 'Настройки прокторинга "Экзамус"';
+$string['log_section'] = 'Журнал прокторинга "Экзамус"';
$string['status'] = 'Статус';
$string['review'] = 'Результат';
$string['module'] = 'Модуль';
@@ -63,3 +65,9 @@
$string['allow_wrong_gaze_direction'] = 'Разрешить взгляд в сторону';
$string['scheduling_required'] = 'Обязательна запись в календаре';
+$string['apply_filter'] = 'Применить фильтры';
+$string['allcourses'] = 'Все курсы';
+$string['allstatuses'] = 'Все статусы';
+$string['userquery'] = 'Email пользователя начинается с';
+$string['fromdate'] = 'С:';
+$string['todate'] = 'По:';
diff --git a/locallib.php b/locallib.php
index aa93b74..7d77bf7 100644
--- a/locallib.php
+++ b/locallib.php
@@ -44,4 +44,62 @@ function examus_attempt_submitted_handler($event) {
$entry->status = "Finished";
$DB->update_record('availability_examus', $entry);
}
-}
\ No newline at end of file
+}
+
+/**
+ * When attempt is started, update entry accordingly
+ *
+ * @param stdClass $event Event
+ */
+function examus_attempt_started_handler($event) {
+ global $DB;
+ if(isset($_SESSION['examus'])){
+ $accesscode = $_SESSION['examus'];
+
+ $attempt = $event->get_record_snapshot('quiz_attempts', $event->objectid);
+
+ $entry = $DB->get_record('availability_examus', ['status' => 'Started', 'accesscode' => $accesscode]);
+
+ $entry->attemptid = $attempt->id;
+ $DB->update_record('availability_examus', $entry);
+ }
+}
+
+
+/**
+ * Remove entries on attempt deletion
+ *
+ * @param stdClass $event Event
+ */
+function examus_attempt_deleted_handler($event) {
+ global $DB;
+
+ $course = $DB->get_record('course', array('id' => $event->courseid));
+ $attempt = $event->get_record_snapshot('quiz_attempts', $event->objectid);
+ $quiz = $event->get_record_snapshot('quiz', $attempt->quiz);
+ $cm = get_coursemodule_from_id('quiz', $event->get_context()->instanceid, $event->courseid);
+ $result = \availability_examus\common::reset_entry(['cmid' => $cm->id, 'attemptid' => $attempt->id]);
+}
+
+/**
+ * user enrolment deleted handles
+ *
+ * @param \core\event\user_enrolment_deleted $event Event
+ */
+function examus_user_enrolment_deleted(\core\event\user_enrolment_deleted $event) {
+ $course = get_course($event->courseid);
+ $userid = $event->relateduserid;
+
+ \availability_examus\common::delete_empty_entries($userid, $event->courseid);
+}
+
+/**
+ * course mudule deleted handler
+ *
+ * @param \core\event\course_module_deleted $event Event
+ */
+function examus_course_module_deleted(\core\event\course_module_deleted $event) {
+ global $DB;
+ $cmid = $event->contextinstanceid;
+ $DB->delete_records('availability_examus', ['cmid' => $cmid]);
+}
diff --git a/settings.php b/settings.php
index 9c283e5..0ee4d5c 100644
--- a/settings.php
+++ b/settings.php
@@ -24,8 +24,12 @@
defined('MOODLE_INTERNAL') || die();
-if ($hassiteconfig) {
- $ADMIN->add('reports', new admin_externalpage('availability_examus_settings', get_string('settings', 'availability_examus'),
- $CFG->wwwroot . '/availability/condition/examus/index.php'));
-}
-
+$ADMIN->add(
+ 'reports',
+ new admin_externalpage(
+ 'availability_examus_settings',
+ get_string('log_section', 'availability_examus'),
+ $CFG->wwwroot . '/availability/condition/examus/index.php',
+ 'availability/examus:logaccess'
+ )
+);
diff --git a/version.php b/version.php
index 3af0d74..5f1cb4a 100644
--- a/version.php
+++ b/version.php
@@ -25,7 +25,7 @@
defined('MOODLE_INTERNAL') || die();
$plugin->component = 'availability_examus';
-$plugin->version = 2018042401;
-$plugin->release = 'v3.1-r1';
+$plugin->version = 2019110701;
+$plugin->release = 'v3.1-r4';
$plugin->requires = 2016052300;
$plugin->maturity = MATURITY_STABLE;
diff --git a/yui/build/moodle-availability_examus-form/moodle-availability_examus-form-coverage.js b/yui/build/moodle-availability_examus-form/moodle-availability_examus-form-coverage.js
deleted file mode 100644
index ce8992b..0000000
--- a/yui/build/moodle-availability_examus-form/moodle-availability_examus-form-coverage.js
+++ /dev/null
@@ -1,6 +0,0 @@
-if (typeof __coverage__ === 'undefined') { __coverage__ = {}; }
-if (!__coverage__['build/moodle-availability_examus-form/moodle-availability_examus-form.js']) {
- __coverage__['build/moodle-availability_examus-form/moodle-availability_examus-form.js'] = {"path":"build/moodle-availability_examus-form/moodle-availability_examus-form.js","s":{"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0,"50":0,"51":0,"52":0,"53":0,"54":0,"55":0,"56":0,"57":0,"58":0,"59":0,"60":0,"61":0,"62":0,"63":0,"64":0,"65":0,"66":0,"67":0,"68":0,"69":0,"70":0,"71":0,"72":0,"73":0,"74":0,"75":0,"76":0,"77":0,"78":0},"b":{"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0],"8":[0,0],"9":[0,0],"10":[0,0],"11":[0,0],"12":[0,0,0]},"f":{"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0},"fnMap":{"1":{"name":"(anonymous_1)","line":1,"loc":{"start":{"line":1,"column":43},"end":{"line":1,"column":62}}},"2":{"name":"(anonymous_2)","line":16,"loc":{"start":{"line":16,"column":39},"end":{"line":17,"column":0}}},"3":{"name":"(anonymous_3)","line":23,"loc":{"start":{"line":23,"column":37},"end":{"line":23,"column":52}}},"4":{"name":"getString","line":27,"loc":{"start":{"line":27,"column":4},"end":{"line":27,"column":35}}},"5":{"name":"(anonymous_5)","line":91,"loc":{"start":{"line":91,"column":37},"end":{"line":91,"column":48}}},"6":{"name":"(anonymous_6)","line":94,"loc":{"start":{"line":94,"column":31},"end":{"line":94,"column":42}}},"7":{"name":"(anonymous_7)","line":97,"loc":{"start":{"line":97,"column":37},"end":{"line":97,"column":48}}},"8":{"name":"(anonymous_8)","line":100,"loc":{"start":{"line":100,"column":31},"end":{"line":100,"column":42}}},"9":{"name":"(anonymous_9)","line":108,"loc":{"start":{"line":108,"column":39},"end":{"line":108,"column":61}}},"10":{"name":"(anonymous_10)","line":121,"loc":{"start":{"line":121,"column":24},"end":{"line":121,"column":45}}},"11":{"name":"(anonymous_11)","line":132,"loc":{"start":{"line":132,"column":40},"end":{"line":132,"column":63}}}},"statementMap":{"1":{"start":{"line":1,"column":0},"end":{"line":140,"column":90}},"2":{"start":{"line":10,"column":0},"end":{"line":10,"column":52}},"3":{"start":{"line":12,"column":0},"end":{"line":12,"column":66}},"4":{"start":{"line":14,"column":0},"end":{"line":14,"column":40}},"5":{"start":{"line":16,"column":0},"end":{"line":19,"column":2}},"6":{"start":{"line":18,"column":4},"end":{"line":18,"column":23}},"7":{"start":{"line":21,"column":0},"end":{"line":21,"column":38}},"8":{"start":{"line":23,"column":0},"end":{"line":106,"column":2}},"9":{"start":{"line":24,"column":4},"end":{"line":24,"column":70}},"10":{"start":{"line":27,"column":4},"end":{"line":29,"column":5}},"11":{"start":{"line":28,"column":8},"end":{"line":28,"column":68}},"12":{"start":{"line":31,"column":4},"end":{"line":31,"column":43}},"13":{"start":{"line":33,"column":4},"end":{"line":33,"column":54}},"14":{"start":{"line":35,"column":4},"end":{"line":35,"column":61}},"15":{"start":{"line":37,"column":4},"end":{"line":37,"column":34}},"16":{"start":{"line":38,"column":4},"end":{"line":38,"column":85}},"17":{"start":{"line":39,"column":4},"end":{"line":39,"column":74}},"18":{"start":{"line":41,"column":4},"end":{"line":41,"column":38}},"19":{"start":{"line":42,"column":4},"end":{"line":42,"column":95}},"20":{"start":{"line":43,"column":4},"end":{"line":43,"column":98}},"21":{"start":{"line":45,"column":4},"end":{"line":45,"column":26}},"22":{"start":{"line":46,"column":4},"end":{"line":46,"column":81}},"23":{"start":{"line":47,"column":4},"end":{"line":47,"column":55}},"24":{"start":{"line":48,"column":4},"end":{"line":48,"column":81}},"25":{"start":{"line":49,"column":4},"end":{"line":49,"column":97}},"26":{"start":{"line":50,"column":4},"end":{"line":50,"column":85}},"27":{"start":{"line":51,"column":4},"end":{"line":51,"column":24}},"28":{"start":{"line":53,"column":4},"end":{"line":53,"column":34}},"29":{"start":{"line":54,"column":4},"end":{"line":54,"column":57}},"30":{"start":{"line":55,"column":4},"end":{"line":59,"column":5}},"31":{"start":{"line":56,"column":8},"end":{"line":56,"column":31}},"32":{"start":{"line":57,"column":8},"end":{"line":57,"column":107}},"33":{"start":{"line":58,"column":8},"end":{"line":58,"column":78}},"34":{"start":{"line":60,"column":4},"end":{"line":60,"column":21}},"35":{"start":{"line":63,"column":4},"end":{"line":63,"column":56}},"36":{"start":{"line":64,"column":4},"end":{"line":66,"column":5}},"37":{"start":{"line":65,"column":8},"end":{"line":65,"column":69}},"38":{"start":{"line":68,"column":4},"end":{"line":70,"column":5}},"39":{"start":{"line":69,"column":8},"end":{"line":69,"column":98}},"40":{"start":{"line":72,"column":4},"end":{"line":76,"column":5}},"41":{"start":{"line":73,"column":8},"end":{"line":75,"column":9}},"42":{"start":{"line":74,"column":12},"end":{"line":74,"column":82}},"43":{"start":{"line":78,"column":4},"end":{"line":80,"column":5}},"44":{"start":{"line":79,"column":8},"end":{"line":80,"column":4}},"45":{"start":{"line":82,"column":4},"end":{"line":86,"column":5}},"46":{"start":{"line":83,"column":8},"end":{"line":85,"column":9}},"47":{"start":{"line":84,"column":12},"end":{"line":84,"column":81}},"48":{"start":{"line":88,"column":4},"end":{"line":103,"column":5}},"49":{"start":{"line":89,"column":8},"end":{"line":89,"column":54}},"50":{"start":{"line":90,"column":8},"end":{"line":90,"column":44}},"51":{"start":{"line":91,"column":8},"end":{"line":93,"column":56}},"52":{"start":{"line":92,"column":12},"end":{"line":92,"column":46}},"53":{"start":{"line":94,"column":8},"end":{"line":96,"column":67}},"54":{"start":{"line":95,"column":12},"end":{"line":95,"column":46}},"55":{"start":{"line":97,"column":8},"end":{"line":99,"column":53}},"56":{"start":{"line":98,"column":12},"end":{"line":98,"column":46}},"57":{"start":{"line":100,"column":8},"end":{"line":102,"column":48}},"58":{"start":{"line":101,"column":12},"end":{"line":101,"column":46}},"59":{"start":{"line":105,"column":4},"end":{"line":105,"column":16}},"60":{"start":{"line":108,"column":0},"end":{"line":130,"column":2}},"61":{"start":{"line":109,"column":4},"end":{"line":109,"column":25}},"62":{"start":{"line":110,"column":4},"end":{"line":110,"column":74}},"63":{"start":{"line":111,"column":4},"end":{"line":111,"column":67}},"64":{"start":{"line":113,"column":4},"end":{"line":117,"column":5}},"65":{"start":{"line":114,"column":8},"end":{"line":114,"column":41}},"66":{"start":{"line":116,"column":8},"end":{"line":116,"column":42}},"67":{"start":{"line":119,"column":4},"end":{"line":119,"column":21}},"68":{"start":{"line":120,"column":4},"end":{"line":120,"column":43}},"69":{"start":{"line":121,"column":4},"end":{"line":129,"column":7}},"70":{"start":{"line":122,"column":8},"end":{"line":122,"column":37}},"71":{"start":{"line":123,"column":8},"end":{"line":127,"column":9}},"72":{"start":{"line":124,"column":12},"end":{"line":124,"column":36}},"73":{"start":{"line":126,"column":12},"end":{"line":126,"column":37}},"74":{"start":{"line":132,"column":0},"end":{"line":138,"column":2}},"75":{"start":{"line":133,"column":4},"end":{"line":133,"column":19}},"76":{"start":{"line":134,"column":4},"end":{"line":134,"column":32}},"77":{"start":{"line":135,"column":4},"end":{"line":137,"column":5}},"78":{"start":{"line":136,"column":8},"end":{"line":136,"column":61}}},"branchMap":{"1":{"line":10,"type":"binary-expr","locations":[{"start":{"line":10,"column":24},"end":{"line":10,"column":45}},{"start":{"line":10,"column":49},"end":{"line":10,"column":51}}]},"2":{"line":64,"type":"if","locations":[{"start":{"line":64,"column":4},"end":{"line":64,"column":4}},{"start":{"line":64,"column":4},"end":{"line":64,"column":4}}]},"3":{"line":68,"type":"if","locations":[{"start":{"line":68,"column":4},"end":{"line":68,"column":4}},{"start":{"line":68,"column":4},"end":{"line":68,"column":4}}]},"4":{"line":72,"type":"if","locations":[{"start":{"line":72,"column":4},"end":{"line":72,"column":4}},{"start":{"line":72,"column":4},"end":{"line":72,"column":4}}]},"5":{"line":73,"type":"if","locations":[{"start":{"line":73,"column":8},"end":{"line":73,"column":8}},{"start":{"line":73,"column":8},"end":{"line":73,"column":8}}]},"6":{"line":78,"type":"if","locations":[{"start":{"line":78,"column":4},"end":{"line":78,"column":4}},{"start":{"line":78,"column":4},"end":{"line":78,"column":4}}]},"7":{"line":83,"type":"if","locations":[{"start":{"line":83,"column":8},"end":{"line":83,"column":8}},{"start":{"line":83,"column":8},"end":{"line":83,"column":8}}]},"8":{"line":88,"type":"if","locations":[{"start":{"line":88,"column":4},"end":{"line":88,"column":4}},{"start":{"line":88,"column":4},"end":{"line":88,"column":4}}]},"9":{"line":113,"type":"if","locations":[{"start":{"line":113,"column":4},"end":{"line":113,"column":4}},{"start":{"line":113,"column":4},"end":{"line":113,"column":4}}]},"10":{"line":123,"type":"if","locations":[{"start":{"line":123,"column":8},"end":{"line":123,"column":8}},{"start":{"line":123,"column":8},"end":{"line":123,"column":8}}]},"11":{"line":135,"type":"if","locations":[{"start":{"line":135,"column":4},"end":{"line":135,"column":4}},{"start":{"line":135,"column":4},"end":{"line":135,"column":4}}]},"12":{"line":135,"type":"binary-expr","locations":[{"start":{"line":135,"column":8},"end":{"line":135,"column":36}},{"start":{"line":135,"column":40},"end":{"line":135,"column":84}},{"start":{"line":135,"column":88},"end":{"line":135,"column":113}}]}},"code":["(function () { YUI.add('moodle-availability_examus-form', function (Y, NAME) {","","/* global M */","/**"," * JavaScript for form editing profile conditions."," *"," * @module moodle-availability_examus-form"," */","/** @suppress checkVars */","M.availability_examus = M.availability_examus || {};","","M.availability_examus.form = Y.Object(M.core_availability.plugin);","","M.availability_examus.form.rules = null;","","M.availability_examus.form.initInner = function(rules)","{"," this.rules = rules;","};","","M.availability_examus.form.instId = 0;","","M.availability_examus.form.getNode = function(json) {"," var html, node, root, id, modeId, durationId, schedulingId, keyId;",""," /** Returns string from translations. */"," function getString(identifier) {"," return M.util.get_string(identifier, 'availability_examus');"," }",""," M.availability_examus.form.instId += 1;",""," id = 'examus' + M.availability_examus.form.instId;",""," html = '
';",""," durationId = id + '_duration';"," html += ' ';"," html += '';",""," schedulingId = id + '_scheduling';"," html += '
';"," html += ' ';",""," modeId = id + '_mode';"," html += '
';"," html += '';",""," html += '';"," html += ' ';"," for (var key in this.rules) {"," keyId = id + '_' + key;"," html += '
';"," html += ' ';"," }"," html += '
';","",""," node = Y.Node.create(' ' + html + ' ');"," if (json.duration !== undefined) {"," node.one('input[name=duration]').set('value', json.duration);"," }",""," if (json.mode !== undefined) {"," node.one('select[name=mode] option[value=' + json.mode + ']').set('selected', 'selected');"," }",""," if (json.scheduling_required !== undefined) {"," if (json.scheduling_required) {"," node.one('input[name=scheduling_required]').set('checked', 'checked');"," }"," }",""," if (json.rules === undefined) {"," json.rules = this.rules"," }",""," for (key in json.rules) {"," if (json.rules[key]) {"," node.one('.rules input[name=' + key + ']').set('checked', 'checked');"," }"," }",""," if (!M.availability_examus.form.addedEvents) {"," M.availability_examus.form.addedEvents = true;"," root = Y.one(\".availability-field\");"," root.delegate('valuechange', function() {"," M.core_availability.form.update();"," }, '.availability_examus input[name=duration]');"," root.delegate('click', function() {"," M.core_availability.form.update();"," }, '.availability_examus input[name=scheduling_required]');"," root.delegate('valuechange', function() {"," M.core_availability.form.update();"," }, '.availability_examus select[name=mode]');"," root.delegate('click', function() {"," M.core_availability.form.update();"," }, '.availability_examus .rules input');"," }",""," return node;","};","","M.availability_examus.form.fillValue = function(value, node) {"," var rulesInputs, key;"," value.duration = node.one('input[name=duration]').get('value').trim();"," value.mode = node.one('select[name=mode]').get('value').trim();",""," if (node.one('input[name=scheduling_required]').get('checked') === true) {"," value.scheduling_required = true;"," } else {"," value.scheduling_required = false;"," }",""," value.rules = {};"," rulesInputs = node.all('.rules input');"," Y.each(rulesInputs, function (ruleInput) {"," key = ruleInput.get('value');"," if (ruleInput.get('checked') === true) {"," value.rules[key] = true;"," } else {"," value.rules[key] = false;"," }",""," });","};","","M.availability_examus.form.fillErrors = function(errors, node) {"," var value = {};"," this.fillValue(value, node);"," if (value.duration === undefined || !(new RegExp('^\\\\d+$')).test(value.duration) || value.duration % 30 !== 0) {"," errors.push('availability_examus:error_setduration');"," }","};","","}, '@VERSION@', {\"requires\": [\"base\", \"node\", \"event\", \"moodle-core_availability-form\"]});","","}());"]};
-}
-var __cov_VkxrC3bnPgMAADDnSvyZqQ = __coverage__['build/moodle-availability_examus-form/moodle-availability_examus-form.js'];
-__cov_VkxrC3bnPgMAADDnSvyZqQ.s['1']++;YUI.add('moodle-availability_examus-form',function(Y,NAME){__cov_VkxrC3bnPgMAADDnSvyZqQ.f['1']++;__cov_VkxrC3bnPgMAADDnSvyZqQ.s['2']++;M.availability_examus=(__cov_VkxrC3bnPgMAADDnSvyZqQ.b['1'][0]++,M.availability_examus)||(__cov_VkxrC3bnPgMAADDnSvyZqQ.b['1'][1]++,{});__cov_VkxrC3bnPgMAADDnSvyZqQ.s['3']++;M.availability_examus.form=Y.Object(M.core_availability.plugin);__cov_VkxrC3bnPgMAADDnSvyZqQ.s['4']++;M.availability_examus.form.rules=null;__cov_VkxrC3bnPgMAADDnSvyZqQ.s['5']++;M.availability_examus.form.initInner=function(rules){__cov_VkxrC3bnPgMAADDnSvyZqQ.f['2']++;__cov_VkxrC3bnPgMAADDnSvyZqQ.s['6']++;this.rules=rules;};__cov_VkxrC3bnPgMAADDnSvyZqQ.s['7']++;M.availability_examus.form.instId=0;__cov_VkxrC3bnPgMAADDnSvyZqQ.s['8']++;M.availability_examus.form.getNode=function(json){__cov_VkxrC3bnPgMAADDnSvyZqQ.f['3']++;__cov_VkxrC3bnPgMAADDnSvyZqQ.s['9']++;var html,node,root,id,modeId,durationId,schedulingId,keyId;__cov_VkxrC3bnPgMAADDnSvyZqQ.s['10']++;function getString(identifier){__cov_VkxrC3bnPgMAADDnSvyZqQ.f['4']++;__cov_VkxrC3bnPgMAADDnSvyZqQ.s['11']++;return M.util.get_string(identifier,'availability_examus');}__cov_VkxrC3bnPgMAADDnSvyZqQ.s['12']++;M.availability_examus.form.instId+=1;__cov_VkxrC3bnPgMAADDnSvyZqQ.s['13']++;id='examus'+M.availability_examus.form.instId;__cov_VkxrC3bnPgMAADDnSvyZqQ.s['14']++;html='
';__cov_VkxrC3bnPgMAADDnSvyZqQ.s['15']++;durationId=id+'_duration';__cov_VkxrC3bnPgMAADDnSvyZqQ.s['16']++;html+=' ';__cov_VkxrC3bnPgMAADDnSvyZqQ.s['17']++;html+='';__cov_VkxrC3bnPgMAADDnSvyZqQ.s['18']++;schedulingId=id+'_scheduling';__cov_VkxrC3bnPgMAADDnSvyZqQ.s['19']++;html+='
';__cov_VkxrC3bnPgMAADDnSvyZqQ.s['20']++;html+=' ';__cov_VkxrC3bnPgMAADDnSvyZqQ.s['21']++;modeId=id+'_mode';__cov_VkxrC3bnPgMAADDnSvyZqQ.s['22']++;html+='
';__cov_VkxrC3bnPgMAADDnSvyZqQ.s['23']++;html+='';__cov_VkxrC3bnPgMAADDnSvyZqQ.s['28']++;html+='';__cov_VkxrC3bnPgMAADDnSvyZqQ.s['29']++;html+=' ';__cov_VkxrC3bnPgMAADDnSvyZqQ.s['30']++;for(var key in this.rules){__cov_VkxrC3bnPgMAADDnSvyZqQ.s['31']++;keyId=id+'_'+key;__cov_VkxrC3bnPgMAADDnSvyZqQ.s['32']++;html+='
';__cov_VkxrC3bnPgMAADDnSvyZqQ.s['33']++;html+=' ';}__cov_VkxrC3bnPgMAADDnSvyZqQ.s['34']++;html+='
';__cov_VkxrC3bnPgMAADDnSvyZqQ.s['35']++;node=Y.Node.create(' '+html+' ');__cov_VkxrC3bnPgMAADDnSvyZqQ.s['36']++;if(json.duration!==undefined){__cov_VkxrC3bnPgMAADDnSvyZqQ.b['2'][0]++;__cov_VkxrC3bnPgMAADDnSvyZqQ.s['37']++;node.one('input[name=duration]').set('value',json.duration);}else{__cov_VkxrC3bnPgMAADDnSvyZqQ.b['2'][1]++;}__cov_VkxrC3bnPgMAADDnSvyZqQ.s['38']++;if(json.mode!==undefined){__cov_VkxrC3bnPgMAADDnSvyZqQ.b['3'][0]++;__cov_VkxrC3bnPgMAADDnSvyZqQ.s['39']++;node.one('select[name=mode] option[value='+json.mode+']').set('selected','selected');}else{__cov_VkxrC3bnPgMAADDnSvyZqQ.b['3'][1]++;}__cov_VkxrC3bnPgMAADDnSvyZqQ.s['40']++;if(json.scheduling_required!==undefined){__cov_VkxrC3bnPgMAADDnSvyZqQ.b['4'][0]++;__cov_VkxrC3bnPgMAADDnSvyZqQ.s['41']++;if(json.scheduling_required){__cov_VkxrC3bnPgMAADDnSvyZqQ.b['5'][0]++;__cov_VkxrC3bnPgMAADDnSvyZqQ.s['42']++;node.one('input[name=scheduling_required]').set('checked','checked');}else{__cov_VkxrC3bnPgMAADDnSvyZqQ.b['5'][1]++;}}else{__cov_VkxrC3bnPgMAADDnSvyZqQ.b['4'][1]++;}__cov_VkxrC3bnPgMAADDnSvyZqQ.s['43']++;if(json.rules===undefined){__cov_VkxrC3bnPgMAADDnSvyZqQ.b['6'][0]++;__cov_VkxrC3bnPgMAADDnSvyZqQ.s['44']++;json.rules=this.rules;}else{__cov_VkxrC3bnPgMAADDnSvyZqQ.b['6'][1]++;}__cov_VkxrC3bnPgMAADDnSvyZqQ.s['45']++;for(key in json.rules){__cov_VkxrC3bnPgMAADDnSvyZqQ.s['46']++;if(json.rules[key]){__cov_VkxrC3bnPgMAADDnSvyZqQ.b['7'][0]++;__cov_VkxrC3bnPgMAADDnSvyZqQ.s['47']++;node.one('.rules input[name='+key+']').set('checked','checked');}else{__cov_VkxrC3bnPgMAADDnSvyZqQ.b['7'][1]++;}}__cov_VkxrC3bnPgMAADDnSvyZqQ.s['48']++;if(!M.availability_examus.form.addedEvents){__cov_VkxrC3bnPgMAADDnSvyZqQ.b['8'][0]++;__cov_VkxrC3bnPgMAADDnSvyZqQ.s['49']++;M.availability_examus.form.addedEvents=true;__cov_VkxrC3bnPgMAADDnSvyZqQ.s['50']++;root=Y.one('.availability-field');__cov_VkxrC3bnPgMAADDnSvyZqQ.s['51']++;root.delegate('valuechange',function(){__cov_VkxrC3bnPgMAADDnSvyZqQ.f['5']++;__cov_VkxrC3bnPgMAADDnSvyZqQ.s['52']++;M.core_availability.form.update();},'.availability_examus input[name=duration]');__cov_VkxrC3bnPgMAADDnSvyZqQ.s['53']++;root.delegate('click',function(){__cov_VkxrC3bnPgMAADDnSvyZqQ.f['6']++;__cov_VkxrC3bnPgMAADDnSvyZqQ.s['54']++;M.core_availability.form.update();},'.availability_examus input[name=scheduling_required]');__cov_VkxrC3bnPgMAADDnSvyZqQ.s['55']++;root.delegate('valuechange',function(){__cov_VkxrC3bnPgMAADDnSvyZqQ.f['7']++;__cov_VkxrC3bnPgMAADDnSvyZqQ.s['56']++;M.core_availability.form.update();},'.availability_examus select[name=mode]');__cov_VkxrC3bnPgMAADDnSvyZqQ.s['57']++;root.delegate('click',function(){__cov_VkxrC3bnPgMAADDnSvyZqQ.f['8']++;__cov_VkxrC3bnPgMAADDnSvyZqQ.s['58']++;M.core_availability.form.update();},'.availability_examus .rules input');}else{__cov_VkxrC3bnPgMAADDnSvyZqQ.b['8'][1]++;}__cov_VkxrC3bnPgMAADDnSvyZqQ.s['59']++;return node;};__cov_VkxrC3bnPgMAADDnSvyZqQ.s['60']++;M.availability_examus.form.fillValue=function(value,node){__cov_VkxrC3bnPgMAADDnSvyZqQ.f['9']++;__cov_VkxrC3bnPgMAADDnSvyZqQ.s['61']++;var rulesInputs,key;__cov_VkxrC3bnPgMAADDnSvyZqQ.s['62']++;value.duration=node.one('input[name=duration]').get('value').trim();__cov_VkxrC3bnPgMAADDnSvyZqQ.s['63']++;value.mode=node.one('select[name=mode]').get('value').trim();__cov_VkxrC3bnPgMAADDnSvyZqQ.s['64']++;if(node.one('input[name=scheduling_required]').get('checked')===true){__cov_VkxrC3bnPgMAADDnSvyZqQ.b['9'][0]++;__cov_VkxrC3bnPgMAADDnSvyZqQ.s['65']++;value.scheduling_required=true;}else{__cov_VkxrC3bnPgMAADDnSvyZqQ.b['9'][1]++;__cov_VkxrC3bnPgMAADDnSvyZqQ.s['66']++;value.scheduling_required=false;}__cov_VkxrC3bnPgMAADDnSvyZqQ.s['67']++;value.rules={};__cov_VkxrC3bnPgMAADDnSvyZqQ.s['68']++;rulesInputs=node.all('.rules input');__cov_VkxrC3bnPgMAADDnSvyZqQ.s['69']++;Y.each(rulesInputs,function(ruleInput){__cov_VkxrC3bnPgMAADDnSvyZqQ.f['10']++;__cov_VkxrC3bnPgMAADDnSvyZqQ.s['70']++;key=ruleInput.get('value');__cov_VkxrC3bnPgMAADDnSvyZqQ.s['71']++;if(ruleInput.get('checked')===true){__cov_VkxrC3bnPgMAADDnSvyZqQ.b['10'][0]++;__cov_VkxrC3bnPgMAADDnSvyZqQ.s['72']++;value.rules[key]=true;}else{__cov_VkxrC3bnPgMAADDnSvyZqQ.b['10'][1]++;__cov_VkxrC3bnPgMAADDnSvyZqQ.s['73']++;value.rules[key]=false;}});};__cov_VkxrC3bnPgMAADDnSvyZqQ.s['74']++;M.availability_examus.form.fillErrors=function(errors,node){__cov_VkxrC3bnPgMAADDnSvyZqQ.f['11']++;__cov_VkxrC3bnPgMAADDnSvyZqQ.s['75']++;var value={};__cov_VkxrC3bnPgMAADDnSvyZqQ.s['76']++;this.fillValue(value,node);__cov_VkxrC3bnPgMAADDnSvyZqQ.s['77']++;if((__cov_VkxrC3bnPgMAADDnSvyZqQ.b['12'][0]++,value.duration===undefined)||(__cov_VkxrC3bnPgMAADDnSvyZqQ.b['12'][1]++,!new RegExp('^\\d+$').test(value.duration))||(__cov_VkxrC3bnPgMAADDnSvyZqQ.b['12'][2]++,value.duration%30!==0)){__cov_VkxrC3bnPgMAADDnSvyZqQ.b['11'][0]++;__cov_VkxrC3bnPgMAADDnSvyZqQ.s['78']++;errors.push('availability_examus:error_setduration');}else{__cov_VkxrC3bnPgMAADDnSvyZqQ.b['11'][1]++;}};},'@VERSION@',{'requires':['base','node','event','moodle-core_availability-form']});
diff --git a/yui/build/moodle-availability_examus-form/moodle-availability_examus-form-debug.js b/yui/build/moodle-availability_examus-form/moodle-availability_examus-form-debug.js
index 33b56d2..b01b54e 100644
--- a/yui/build/moodle-availability_examus-form/moodle-availability_examus-form-debug.js
+++ b/yui/build/moodle-availability_examus-form/moodle-availability_examus-form-debug.js
@@ -21,7 +21,7 @@ M.availability_examus.form.initInner = function(rules)
M.availability_examus.form.instId = 0;
M.availability_examus.form.getNode = function(json) {
- var html, node, root, id, modeId, durationId, schedulingId, keyId;
+ var html, node, root, id, modeId, durationId, keyId;
/** Returns string from translations. */
function getString(identifier) {
@@ -38,10 +38,6 @@ M.availability_examus.form.getNode = function(json) {
html += ' ';
html += '';
- schedulingId = id + '_scheduling';
- html += '
';
- html += ' ';
-
modeId = id + '_mode';
html += '
';
html += '