Fix #187 allow default status set to be editable.
authorDan Marsden <dan@danmarsden.com>
Wed, 8 Mar 2017 22:37:30 +0000 (11:37 +1300)
committerDan Marsden <dan@danmarsden.com>
Wed, 8 Mar 2017 22:37:59 +0000 (11:37 +1300)
classes/structure.php
defaultstatus.php [new file with mode: 0644]
lang/en/attendance.php
lib.php
locallib.php
preferences.php
renderables.php
renderer.php
settings.php

index 4030a9e..4f671fc 100644 (file)
@@ -963,107 +963,6 @@ class mod_attendance_structure {
     }
 
     /**
-     * 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 (file)
index 0000000..65b3074
--- /dev/null
@@ -0,0 +1,113 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * 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
index 8530210..9e85f49 100644 (file)
@@ -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 (file)
--- 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
index 57467b9..5bf963d 100644 (file)
@@ -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
index 1fd543d..eceb428 100644 (file)
@@ -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;
index 105630e..e9e22a6 100644 (file)
@@ -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;
index c78ed28..bf975ef 100644 (file)
@@ -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),
index ffa3f99..25a1b8f 100644 (file)
@@ -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'),