diff --git a/classes/structure.php b/classes/structure.php index 4030a9e..4f671fc 100644 --- a/classes/structure.php +++ b/classes/structure.php @@ -962,107 +962,6 @@ class mod_attendance_structure { $sessions->close(); } - /** - * Remove a status variable from an attendance instance - * - * @param stdClass $status - */ - public function remove_status($status) { - global $DB; - - $DB->set_field('attendance_statuses', 'deleted', 1, array('id' => $status->id)); - $event = \mod_attendance\event\status_removed::create(array( - 'objectid' => $status->id, - 'context' => $this->context, - 'other' => array( - 'acronym' => $status->acronym, - 'description' => $status->description - ))); - $event->add_record_snapshot('course_modules', $this->cm); - $event->add_record_snapshot('attendance_statuses', $status); - $event->trigger(); - } - - /** - * Add an attendance status variable - * - * @param string $acronym - * @param string $description - * @param int $grade - */ - public function add_status($acronym, $description, $grade) { - global $DB; - - if ($acronym && $description) { - $rec = new stdClass(); - $rec->courseid = $this->course->id; - $rec->attendanceid = $this->id; - $rec->acronym = $acronym; - $rec->description = $description; - $rec->grade = $grade; - $rec->setnumber = $this->pageparams->statusset; // Save which set it is part of. - $rec->deleted = 0; - $rec->visible = 1; - $id = $DB->insert_record('attendance_statuses', $rec); - $rec->id = $id; - - $event = \mod_attendance\event\status_added::create(array( - 'objectid' => $this->id, - 'context' => $this->context, - 'other' => array('acronym' => $acronym, 'description' => $description, 'grade' => $grade))); - $event->add_record_snapshot('course_modules', $this->cm); - $event->add_record_snapshot('attendance_statuses', $rec); - $event->trigger(); - } else { - print_error('cantaddstatus', 'attendance', $this->url_preferences()); - } - } - - /** - * Update status variable for a particular Attendance module instance - * - * @param stdClass $status - * @param string $acronym - * @param string $description - * @param int $grade - * @param bool $visible - */ - public function update_status($status, $acronym, $description, $grade, $visible) { - global $DB; - - if (isset($visible)) { - $status->visible = $visible; - $updated[] = $visible ? get_string('show') : get_string('hide'); - } else if (empty($acronym) || empty($description)) { - return array('acronym' => $acronym, 'description' => $description); - } - - $updated = array(); - - if ($acronym) { - $status->acronym = $acronym; - $updated[] = $acronym; - } - if ($description) { - $status->description = $description; - $updated[] = $description; - } - if (isset($grade)) { - $status->grade = $grade; - $updated[] = $grade; - } - $DB->update_record('attendance_statuses', $status); - - $event = \mod_attendance\event\status_updated::create(array( - 'objectid' => $this->id, - 'context' => $this->context, - 'other' => array('acronym' => $acronym, 'description' => $description, 'grade' => $grade, - 'updated' => implode(' ', $updated)))); - $event->add_record_snapshot('course_modules', $this->cm); - $event->add_record_snapshot('attendance_statuses', $status); - $event->trigger(); - } - /** * Check if the email address is already in use by either another temporary user, * or a real user. diff --git a/defaultstatus.php b/defaultstatus.php new file mode 100644 index 0000000..65b3074 --- /dev/null +++ b/defaultstatus.php @@ -0,0 +1,113 @@ +. + +/** + * Allows default status set to be modified. + * + * @package mod_attendance + * @copyright 2017 Dan Marsden http://danmarsden.com + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + + +require_once(__DIR__.'/../../config.php'); +require_once($CFG->libdir.'/adminlib.php'); +require_once($CFG->dirroot.'/mod/attendance/lib.php'); +require_once($CFG->dirroot.'/mod/attendance/locallib.php'); + +$action = optional_param('action', null, PARAM_INT); +$statusid = optional_param('statusid', null, PARAM_INT); +admin_externalpage_setup('managemodules'); +$url = new moodle_url('/mod/attendance/defaultstatus.php', array('statusid' => $statusid, 'action' => $action)); + +// Check sesskey if we are performing an action. +if (!empty($action)) { + require_sesskey(); +} + +$output = $PAGE->get_renderer('mod_attendance'); +echo $OUTPUT->header(); +echo $OUTPUT->heading(get_string('defaultstatus', 'mod_attendance')); +$tabmenu = attendance_print_settings_tabs('defaultstatus'); +echo $tabmenu; + +// TODO: Would be good to combine this code block with the one in preferences to avoid duplication. +$errors = array(); +switch ($action) { + case mod_attendance_preferences_page_params::ACTION_ADD: + $newacronym = optional_param('newacronym', null, PARAM_TEXT); + $newdescription = optional_param('newdescription', null, PARAM_TEXT); + $newgrade = optional_param('newgrade', 0, PARAM_RAW); + $newgrade = unformat_float($newgrade); + + // Default value uses setnumber/attendanceid = 0. + attendance_add_status($newacronym, $newdescription, $newgrade, 0); + + break; + case mod_attendance_preferences_page_params::ACTION_DELETE: + $confirm = optional_param('confirm', null, PARAM_INT); + $statuses = attendance_get_statuses(0, false); + $status = $statuses[$statusid]; + + if (isset($confirm)) { + attendance_remove_status($status); + echo $OUTPUT->notification(get_string('statusdeleted', 'attendance'), 'success'); + break; + } + + $message = get_string('deletecheckfull', '', get_string('variable', 'attendance')); + $message .= str_repeat(html_writer::empty_tag('br'), 2); + $message .= $status->acronym.': '. + ($status->description ? $status->description : get_string('nodescription', 'attendance')); + $confirmurl = $url; + $confirmurl->param('confirm', 1); + + echo $OUTPUT->confirm($message, $confirmurl, $url); + echo $OUTPUT->footer(); + exit; + case mod_attendance_preferences_page_params::ACTION_HIDE: + $statuses = attendance_get_statuses(0, false); + $status = $statuses[$statusid]; + attendance_update_status($status, null, null, null, 0); + break; + case mod_attendance_preferences_page_params::ACTION_SHOW: + $statuses = attendance_get_statuses(0, false); + $status = $statuses[$statusid]; + attendance_update_status($status, null, null, null, 1); + break; + case mod_attendance_preferences_page_params::ACTION_SAVE: + $acronym = required_param_array('acronym', PARAM_TEXT); + $description = required_param_array('description', PARAM_TEXT); + $grade = required_param_array('grade', PARAM_RAW); + foreach ($grade as &$val) { + $val = unformat_float($val); + } + $statuses = attendance_get_statuses(0, false); + + foreach ($acronym as $id => $v) { + $status = $statuses[$id]; + $errors[$id] = attendance_update_status($status, $acronym[$id], $description[$id], $grade[$id], null); + } + echo $OUTPUT->notification(get_string('eventstatusupdated', 'attendance'), 'success'); + + break; +} + +$statuses = attendance_get_statuses(0, false); +$prefdata = new attendance_default_statusset($statuses, $errors); +echo $output->render($prefdata); + +echo $OUTPUT->footer(); \ No newline at end of file diff --git a/lang/en/attendance.php b/lang/en/attendance.php index 8530210..9e85f49 100644 --- a/lang/en/attendance.php +++ b/lang/en/attendance.php @@ -364,4 +364,5 @@ $string['requiresubnet'] = 'Students can only record own attendance from these c $string['subnetwrong'] = 'Attendance can only be recorded from certain locations, and this computer is not on the allowed list.'; $string['requiresubnet_help'] = 'Attendance recording may be restricted to particular subnets by specifying a comma-separated list of partial or full IP addresses.'; $string['defaultsettings'] = 'Default attendance settings'; -$string['defaultsettings_help'] = 'These settings define the defaults for all new attendances'; \ No newline at end of file +$string['defaultsettings_help'] = 'These settings define the defaults for all new attendances'; +$string['defaultstatus'] = 'Default status set'; \ No newline at end of file diff --git a/lib.php b/lib.php index c18ecc2..0f44ca2 100644 --- a/lib.php +++ b/lib.php @@ -385,3 +385,27 @@ function attendance_pluginfile($course, $cm, $context, $filearea, $args, $forced } send_stored_file($file, 0, 0, true); } + +/** + * Print tabs on attendance settings page. + * + * @param string $selected - current selected tab. + * + */ +function attendance_print_settings_tabs($selected = 'settings') { + global $CFG; + // Print tabs for different settings pages. + $tabs = array(); + $tabs[] = new tabobject('settings', $CFG->wwwroot.'/admin/settings.php?section=modsettingattendance', + get_string('settings', 'attendance'), get_string('settings'), false); + + $tabs[] = new tabobject('defaultstatus', $CFG->wwwroot.'/mod/attendance/defaultstatus.php', + get_string('defaultstatus', 'attendance'), get_string('defaultstatus', 'attendance'), false); + + ob_start(); + print_tabs(array($tabs), $selected); + $tabmenu = ob_get_contents(); + ob_end_clean(); + + return $tabmenu; +} \ No newline at end of file diff --git a/locallib.php b/locallib.php index 57467b9..5bf963d 100644 --- a/locallib.php +++ b/locallib.php @@ -240,3 +240,118 @@ function attendance_update_users_grade($attendance, $userids=array()) { return grade_update('mod/attendance', $course->id, 'mod', 'attendance', $attendance->id, 0, $grades); } + +/** + * Add an attendance status variable + * + * @param string $acronym + * @param string $description + * @param int $grade + */ +function attendance_add_status($acronym, $description, $grade, $attendanceid, $setnumber = 0, $context = null, $cm = null) { + global $DB; + if (empty($context)) { + $context = context_system::instance(); + } + if ($acronym && $description) { + $rec = new stdClass(); + $rec->attendanceid = $attendanceid; + $rec->acronym = $acronym; + $rec->description = $description; + $rec->grade = $grade; + $rec->setnumber = $setnumber; // Save which set it is part of. + $rec->deleted = 0; + $rec->visible = 1; + $id = $DB->insert_record('attendance_statuses', $rec); + $rec->id = $id; + + $event = \mod_attendance\event\status_added::create(array( + 'objectid' => $attendanceid, + 'context' => $context, + 'other' => array('acronym' => $acronym, 'description' => $description, 'grade' => $grade))); + if (!empty($cm)) { + $event->add_record_snapshot('course_modules', $cm); + } + $event->add_record_snapshot('attendance_statuses', $rec); + $event->trigger(); + return true; + } else { + return false; + } +} + +/** + * Remove a status variable from an attendance instance + * + * @param stdClass $status + */ +function attendance_remove_status($status, $context = null, $cm = null) { + global $DB; + if (empty($context)) { + $context = context_system::instance(); + } + $DB->set_field('attendance_statuses', 'deleted', 1, array('id' => $status->id)); + $event = \mod_attendance\event\status_removed::create(array( + 'objectid' => $status->id, + 'context' => $context, + 'other' => array( + 'acronym' => $status->acronym, + 'description' => $status->description + ))); + if (!empty($cm)) { + $event->add_record_snapshot('course_modules', $cm); + } + $event->add_record_snapshot('attendance_statuses', $status); + $event->trigger(); +} + +/** + * Update status variable for a particular Attendance module instance + * + * @param stdClass $status + * @param string $acronym + * @param string $description + * @param int $grade + * @param bool $visible + */ +function attendance_update_status($status, $acronym, $description, $grade, $visible, $context = null, $cm = null) { + global $DB; + + if (empty($context)) { + $context = context_system::instance(); + } + + if (isset($visible)) { + $status->visible = $visible; + $updated[] = $visible ? get_string('show') : get_string('hide'); + } else if (empty($acronym) || empty($description)) { + return array('acronym' => $acronym, 'description' => $description); + } + + $updated = array(); + + if ($acronym) { + $status->acronym = $acronym; + $updated[] = $acronym; + } + if ($description) { + $status->description = $description; + $updated[] = $description; + } + if (isset($grade)) { + $status->grade = $grade; + $updated[] = $grade; + } + $DB->update_record('attendance_statuses', $status); + + $event = \mod_attendance\event\status_updated::create(array( + 'objectid' => $status->attendanceid, + 'context' => $context, + 'other' => array('acronym' => $acronym, 'description' => $description, 'grade' => $grade, + 'updated' => implode(' ', $updated)))); + if (!empty($cm)) { + $event->add_record_snapshot('course_modules', $cm); + } + $event->add_record_snapshot('attendance_statuses', $status); + $event->trigger(); +} \ No newline at end of file diff --git a/preferences.php b/preferences.php index 1fd543d..eceb428 100644 --- a/preferences.php +++ b/preferences.php @@ -62,6 +62,7 @@ if (!empty($att->pageparams->action)) { require_sesskey(); } +// TODO: combine this with the stuff in defaultstatus.php to avoid code duplication. switch ($att->pageparams->action) { case mod_attendance_preferences_page_params::ACTION_ADD: $newacronym = optional_param('newacronym', null, PARAM_TEXT); @@ -69,7 +70,12 @@ switch ($att->pageparams->action) { $newgrade = optional_param('newgrade', 0, PARAM_RAW); $newgrade = unformat_float($newgrade); - $att->add_status($newacronym, $newdescription, $newgrade); + $status = attendance_add_status($newacronym, $newdescription, $newgrade, $att->id, + $att->pageparams->statusset, $att->context, $att->cm); + if (!$status) { + print_error('cantaddstatus', 'attendance', $this->url_preferences()); + } + if ($pageparams->statusset > $maxstatusset) { $maxstatusset = $pageparams->statusset; // Make sure the new maximum is shown without a page refresh. } @@ -84,7 +90,7 @@ switch ($att->pageparams->action) { $status = $statuses[$att->pageparams->statusid]; if (isset($confirm)) { - $att->remove_status($status); + attendance_remove_status($status); redirect($att->url_preferences(), get_string('statusdeleted', 'attendance')); } @@ -101,12 +107,12 @@ switch ($att->pageparams->action) { case mod_attendance_preferences_page_params::ACTION_HIDE: $statuses = $att->get_statuses(false); $status = $statuses[$att->pageparams->statusid]; - $att->update_status($status, null, null, null, 0); + attendance_update_status($status, null, null, null, 0, $att->context, $att->cm); break; case mod_attendance_preferences_page_params::ACTION_SHOW: $statuses = $att->get_statuses(false); $status = $statuses[$att->pageparams->statusid]; - $att->update_status($status, null, null, null, 1); + attendance_update_status($status, null, null, null, 1, $att->context, $att->cm); break; case mod_attendance_preferences_page_params::ACTION_SAVE: $acronym = required_param_array('acronym', PARAM_TEXT); @@ -119,7 +125,8 @@ switch ($att->pageparams->action) { foreach ($acronym as $id => $v) { $status = $statuses[$id]; - $errors[$id] = $att->update_status($status, $acronym[$id], $description[$id], $grade[$id], null); + $errors[$id] = attendance_update_status($status, $acronym[$id], $description[$id], $grade[$id], + null, $att->context, $att->cm); } attendance_update_users_grade($att); break; diff --git a/renderables.php b/renderables.php index 105630e..e9e22a6 100644 --- a/renderables.php +++ b/renderables.php @@ -506,6 +506,21 @@ class attendance_preferences_data implements renderable { } } +class attendance_default_statusset implements renderable { + public $statuses; + + public $errors; + + public function __construct($statuses, $errors) { + $this->statuses = $statuses; + $this->errors = $errors; + } + + public function url($params) { + return new moodle_url('/mod/attendance/defaultstatus.php', $params); + } +} + // Output a selector to change between status sets. class attendance_set_selector implements renderable { public $maxstatusset; diff --git a/renderer.php b/renderer.php index c78ed28..bf975ef 100644 --- a/renderer.php +++ b/renderer.php @@ -656,7 +656,7 @@ class mod_attendance_renderer extends plugin_renderer_base { if ($CFG->fullnamedisplay == 'lastname firstname') { $fullnamehead = "$lastname / $firstname"; } else { - $fullnamehead = "$firstname / $lastname"; + $fullnamehead = "$firstname / $lastname "; } return $fullnamehead; @@ -1479,6 +1479,62 @@ class mod_attendance_renderer extends plugin_renderer_base { return $o; } + protected function render_attendance_default_statusset(attendance_default_statusset $prefdata) { + $this->page->requires->js('/mod/attendance/module.js'); + + $table = new html_table(); + $table->width = '100%'; + $table->head = array('#', + get_string('acronym', 'attendance'), + get_string('description'), + get_string('points', 'attendance'), + get_string('action')); + $table->align = array('center', 'center', 'center', 'center', 'center', 'center'); + + $i = 1; + foreach ($prefdata->statuses as $st) { + $emptyacronym = ''; + $emptydescription = ''; + if (!empty(($prefdata->errors[$st->id]))) { + if (empty($prefdata->errors[$st->id]['acronym'])) { + $emptyacronym = $this->construct_notice(get_string('emptyacronym', 'mod_attendance'), 'notifyproblem'); + } + if (empty($prefdata->errors[$st->id]['description'])) { + $emptydescription = $this->construct_notice(get_string('emptydescription', 'mod_attendance') , 'notifyproblem'); + } + } + + $table->data[$i][] = $i; + $table->data[$i][] = $this->construct_text_input('acronym['.$st->id.']', 2, 2, $st->acronym) . $emptyacronym; + $table->data[$i][] = $this->construct_text_input('description['.$st->id.']', 30, 30, $st->description) . + $emptydescription; + $table->data[$i][] = $this->construct_text_input('grade['.$st->id.']', 4, 4, $st->grade); + $table->data[$i][] = $this->construct_preferences_actions_icons($st, $prefdata); + + $i++; + } + + $table->data[$i][] = '*'; + $table->data[$i][] = $this->construct_text_input('newacronym', 2, 2); + $table->data[$i][] = $this->construct_text_input('newdescription', 30, 30); + $table->data[$i][] = $this->construct_text_input('newgrade', 4, 4); + $table->data[$i][] = $this->construct_preferences_button(get_string('add', 'attendance'), + mod_attendance_preferences_page_params::ACTION_ADD); + + $o = html_writer::table($table); + $o .= html_writer::input_hidden_params($prefdata->url(array(), false)); + // We should probably rewrite this to use mforms but for now add sesskey. + $o .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey()))."\n"; + + $o .= $this->construct_preferences_button(get_string('update', 'attendance'), + mod_attendance_preferences_page_params::ACTION_SAVE); + $o = html_writer::tag('form', $o, array('id' => 'preferencesform', 'method' => 'post', + 'action' => $prefdata->url(array(), false)->out_omit_querystring())); + $o = $this->output->container($o, 'generalbox attwidth'); + + return $o; + } + private function construct_text_input($name, $size, $maxlength, $value='') { $attributes = array( 'type' => 'text', @@ -1504,7 +1560,7 @@ class mod_attendance_renderer extends plugin_renderer_base { $prefdata->url($params), new pix_icon("t/show", get_string('show'))); } - if (!$st->haslogs) { + if (empty($st->haslogs)) { $params['action'] = mod_attendance_preferences_page_params::ACTION_DELETE; $deleteicon = $OUTPUT->action_icon( $prefdata->url($params), diff --git a/settings.php b/settings.php index ffa3f99..25a1b8f 100644 --- a/settings.php +++ b/settings.php @@ -27,6 +27,9 @@ defined('MOODLE_INTERNAL') || die; if ($ADMIN->fulltree) { require_once(dirname(__FILE__).'/lib.php'); + $tabmenu = attendance_print_settings_tabs(); + $settings->add(new admin_setting_heading('attendance_header', '', $tabmenu)); + // Paging options. $options = array( 0 => get_string('donotusepaging', 'attendance'),