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 += '',a=s+"_scheduling",n+='
',n+=' ",o=s+"_mode",n+='
",n+='",n+='
',n+=" ";for(var c in this.rules)f=s+"_"+c,n+='
',n+=' ";n+="
",r=e.Node.create(" "+n+" "),t.duration!==undefined&&r.one("input[name=duration]").set("value",t.duration),t.mode!==undefined&&r.one("select[name=mode] option[value="+t.mode+"]").set("selected","selected"),t.scheduling_required!==undefined&&t.scheduling_required&&r.one("input[name=scheduling_required]").set("checked","checked"),t.rules===undefined&&(t.rules=this.rules);for(c in t.rules)t.rules[c]&&r.one(".rules input[name="+c+"]").set("checked","checked");return M.availability_examus.form.addedEvents||(M.availability_examus.form.addedEvents=!0,i=e.one(".availability-field"),i.delegate("valuechange",function(){M.core_availability.form.update()},".availability_examus input[name=duration]"),i.delegate("click",function(){M.core_availability.form.update()},".availability_examus input[name=scheduling_required]"),i.delegate("valuechange",function(){M.core_availability.form.update()},".availability_examus select[name=mode]"),i.delegate("click",function(){M.core_availability.form.update()},".availability_examus .rules input")),r},M.availability_examus.form.fillValue=function(t,n){var r,i;t.duration=n.one("input[name=duration]").get("value").trim(),t.mode=n.one("select[name=mode]").get("value").trim(),n.one("input[name=scheduling_required]").get("checked")===!0?t.scheduling_required=!0:t.scheduling_required=!1,t.rules={},r=n.all(".rules input"),e.each(r,function(e){i=e.get("value"),e.get("checked")===!0?t.rules[i]=!0:t.rules[i]=!1})},M.availability_examus.form.fillErrors=function(e,t){var n={};this.fillValue(n,t),(n.duration===undefined||!(new RegExp("^\\d+$")).test(n.duration)||n.duration%30!==0)&&e.push("availability_examus:error_setduration")}},"@VERSION@",{requires:["base","node","event","moodle-core_availability-form"]}); +YUI.add("moodle-availability_examus-form",function(e,t){M.availability_examus=M.availability_examus||{},M.availability_examus.form=e.Object(M.core_availability.plugin),M.availability_examus.form.rules=null,M.availability_examus.form.initInner=function(e){this.rules=e},M.availability_examus.form.instId=0,M.availability_examus.form.getNode=function(t){function f(e){return M.util.get_string(e,"availability_examus")}var n,r,i,s,o,u,a;M.availability_examus.form.instId+=1,s="examus"+M.availability_examus.form.instId,n="
",u=s+"_duration",n+=' ",n+='',o=s+"_mode",n+='
",n+='",n+='
',n+=" ";for(var l in this.rules)a=s+"_"+l,n+='
',n+=' ";n+="
",r=e.Node.create(" "+n+" "),t.duration!==undefined&&r.one("input[name=duration]").set("value",t.duration),t.mode!==undefined&&r.one("select[name=mode] option[value="+t.mode+"]").set("selected","selected"),t.rules===undefined&&(t.rules=this.rules);for(l in t.rules)t.rules[l]&&r.one(".rules input[name="+l+"]").set("checked","checked");return M.availability_examus.form.addedEvents||(M.availability_examus.form.addedEvents=!0,i=e.one(".availability-field"),i.delegate("valuechange",function(){M.core_availability.form.update()},".availability_examus input[name=duration]"),i.delegate("valuechange",function(){M.core_availability.form.update()},".availability_examus select[name=mode]"),i.delegate("click",function(){M.core_availability.form.update()},".availability_examus .rules input")),r},M.availability_examus.form.fillValue=function(t,n){var r,i;t.duration=n.one("input[name=duration]").get("value").trim(),t.mode=n.one("select[name=mode]").get("value").trim(),t.rules={},r=n.all(".rules input"),e.each(r,function(e){i=e.get("value"),e.get("checked")===!0?t.rules[i]=!0:t.rules[i]=!1})},M.availability_examus.form.fillErrors=function(e,t){var n={};this.fillValue(n,t),(n.duration===undefined||!(new RegExp("^\\d+$")).test(n.duration)||n.duration%30!==0)&&e.push("availability_examus:error_setduration")}},"@VERSION@",{requires:["base","node","event","moodle-core_availability-form"]}); diff --git a/yui/build/moodle-availability_examus-form/moodle-availability_examus-form.js b/yui/build/moodle-availability_examus-form/moodle-availability_examus-form.js index 33b56d2..b01b54e 100644 --- a/yui/build/moodle-availability_examus-form/moodle-availability_examus-form.js +++ b/yui/build/moodle-availability_examus-form/moodle-availability_examus-form.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 += ''; - schedulingId = id + '_scheduling'; - html += '
'; - html += ' '; - modeId = id + '_mode'; html += '
'; html += '