MDL-50664 mod_data: add 'manageapproved' setting.
authorJohannes Burk <me@jojoob.de>
Thu, 25 Jun 2015 15:10:34 +0000 (17:10 +0200)
committerRyan Wyllie <ryan@moodle.com>
Tue, 15 Sep 2015 07:16:40 +0000 (07:16 +0000)
New function data_user_can_manage_entry checks whether a user is allowed to manage an entry.
Considering manageentries capability, data_in_readonly_period() result,
ownership (determined by data_isowner()), approval and manageapproved setting.

mod/data/backup/moodle2/backup_data_stepslib.php
mod/data/classes/external.php
mod/data/db/install.xml
mod/data/db/upgrade.php
mod/data/edit.php
mod/data/lang/en/data.php
mod/data/lib.php
mod/data/mod_form.php
mod/data/version.php
mod/data/view.php

index 385e66b..a190eb5 100644 (file)
@@ -43,7 +43,7 @@ class backup_data_activity_structure_step extends backup_activity_structure_step
             'requiredentries', 'requiredentriestoview', 'maxentries', 'rssarticles',
             'singletemplate', 'listtemplate', 'listtemplateheader', 'listtemplatefooter',
             'addtemplate', 'rsstemplate', 'rsstitletemplate', 'csstemplate',
-            'jstemplate', 'asearchtemplate', 'approval', 'scale',
+            'jstemplate', 'asearchtemplate', 'approval', 'manageapproved', 'scale',
             'assessed', 'assesstimestart', 'assesstimefinish', 'defaultsort',
             'defaultsortdir', 'editany', 'notification'));
 
index d45977d..eb0b2ad 100644 (file)
@@ -152,7 +152,7 @@ class mod_data_external extends external_api {
 
                     $additionalfields = array('maxentries', 'rssarticles', 'singletemplate', 'listtemplate',
                         'listtemplateheader', 'listtemplatefooter', 'addtemplate', 'rsstemplate', 'rsstitletemplate',
-                        'csstemplate', 'jstemplate', 'asearchtemplate', 'approval', 'scale', 'assessed', 'assesstimestart',
+                        'csstemplate', 'jstemplate', 'asearchtemplate', 'approval', 'manageapproved', 'scale', 'assessed', 'assesstimestart',
                         'assesstimefinish', 'defaultsort', 'defaultsortdir', 'editany', 'notification');
 
                     // This is for avoid a long repetitive list.
@@ -212,6 +212,7 @@ class mod_data_external extends external_api {
                             'jstemplate' => new external_value(PARAM_RAW, 'jstemplate field', VALUE_OPTIONAL),
                             'asearchtemplate' => new external_value(PARAM_RAW, 'asearchtemplate field', VALUE_OPTIONAL),
                             'approval' => new external_value(PARAM_BOOL, 'approval field', VALUE_OPTIONAL),
+                            'manageapproved' => new external_value(PARAM_BOOL, 'manageapproved field', VALUE_OPTIONAL),
                             'scale' => new external_value(PARAM_INT, 'scale field', VALUE_OPTIONAL),
                             'assessed' => new external_value(PARAM_INT, 'assessed field', VALUE_OPTIONAL),
                             'assesstimestart' => new external_value(PARAM_INT, 'assesstimestart field', VALUE_OPTIONAL),
index c4a5c2c..3eea246 100644 (file)
@@ -31,6 +31,7 @@
         <FIELD NAME="jstemplate" TYPE="text" NOTNULL="false" SEQUENCE="false"/>
         <FIELD NAME="asearchtemplate" TYPE="text" NOTNULL="false" SEQUENCE="false"/>
         <FIELD NAME="approval" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
+        <FIELD NAME="manageapproved" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="1" SEQUENCE="false"/>
         <FIELD NAME="scale" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
         <FIELD NAME="assessed" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
         <FIELD NAME="assesstimestart" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
index 602552a..b02948f 100644 (file)
@@ -153,5 +153,20 @@ function xmldb_data_upgrade($oldversion) {
     // Moodle v2.9.0 release upgrade line.
     // Put any upgrade step following this.
 
+    if ($oldversion < 2015070300) {
+
+        // Define field manageapproved to be added to data.
+        $table = new xmldb_table('data');
+        $field = new xmldb_field('manageapproved', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, '1', 'approval');
+
+        // Conditionally launch add field manageapproved.
+        if (!$dbman->field_exists($table, $field)) {
+            $dbman->add_field($table, $field);
+        }
+
+        // Data savepoint reached.
+        upgrade_mod_savepoint(true, 2015070300, 'data');
+    }
+
     return true;
 }
index 7350cca..df09006 100644 (file)
@@ -112,7 +112,7 @@ $groupmode = groups_get_activity_groupmode($cm);
 if (!has_capability('mod/data:manageentries', $context)) {
     if ($rid) {
         // User is editing an existing record
-        if (!data_isowner($rid) || data_in_readonly_period($data)) {
+        if (!data_user_can_manage_entry($record, $data, $context)) {
             print_error('noaccess','data');
         }
     } else if (!data_user_can_add_entry($data, $currentgroup, $groupmode, $context)) {
index cf3f7dc..8d2e0e4 100644 (file)
@@ -215,6 +215,8 @@ $string['latlongotherfields'] = 'Other fields';
 $string['list'] = 'View list';
 $string['listtemplate'] = 'List template';
 $string['longitude'] = 'Longitude';
+$string['manageapproved'] = 'Allow editing of approved entries';
+$string['manageapproved_help'] = 'If disabled, approved entries are not editable and deletable by its owner. This setting only takes effect if approval required is set to yes. Default is yes.';
 $string['mapexistingfield'] = 'Map to {$a}';
 $string['mapnewfield'] = 'Create a new field';
 $string['mappingwarning'] = 'All old fields not mapped to a new field will be lost and all data in that field will be removed.';
index d664107..d1075a9 100644 (file)
@@ -1230,9 +1230,6 @@ function data_print_template($template, $records, $data, $search='', $page=0, $r
     }
     $jumpurl = new moodle_url($jumpurl, array('page' => $page, 'sesskey' => sesskey()));
 
-    // Check whether this activity is read-only at present
-    $readonly = data_in_readonly_period($data);
-
     foreach ($records as $record) {   // Might be just one for the single template
 
     // Replacing tags
@@ -1250,7 +1247,7 @@ function data_print_template($template, $records, $data, $search='', $page=0, $r
     // Replacing special tags (##Edit##, ##Delete##, ##More##)
         $patterns[]='##edit##';
         $patterns[]='##delete##';
-        if ($canmanageentries || (!$readonly && data_isowner($record->id))) {
+        if (data_user_can_manage_entry($record, $data, $context)) {
             $replacement[] = '<a href="'.$CFG->wwwroot.'/mod/data/edit.php?d='
                              .$data->id.'&amp;rid='.$record->id.'&amp;sesskey='.sesskey().'"><img src="'.$OUTPUT->pix_url('t/edit') . '" class="iconsmall" alt="'.get_string('edit').'" title="'.get_string('edit').'" /></a>';
             $replacement[] = '<a href="'.$CFG->wwwroot.'/mod/data/view.php?d='
@@ -2173,6 +2170,44 @@ function data_user_can_add_entry($data, $currentgroup, $groupmode, $context = nu
     }
 }
 
+/**
+ * Check whether the current user is allowed to manage the given record considering manageentries capability,
+ * data_in_readonly_period() result, ownership (determined by data_isowner()) and manageapproved setting.
+ * @param mixed $record record object or id
+ * @param object $data data object
+ * @param object $context context object
+ * @return bool returns true if the user is allowd to edit the entry, false otherwise
+ */
+function data_user_can_manage_entry($record, $data, $context) {
+    global $DB;
+
+    if (has_capability('mod/data:manageentries', $context)) {
+        return true;
+    }
+
+    // Check whether this activity is read-only at present.
+    $readonly = data_in_readonly_period($data);
+
+    if (!$readonly) {
+        // Get record object from db if just id given like in data_isowner.
+        // ...done before calling data_isowner() to avoid querying db twice.
+        if (!is_object($record)) {
+            if (!$record = $DB->get_record('data_records', array('id' => $record))) {
+                return false;
+            }
+        }
+        if (data_isowner($record)) {
+            if ($data->approval && $record->approved) {
+                return $data->manageapproved == 1;
+            } else {
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
+
 /**
  * Check whether the specified database activity is currently in a read-only period
  *
@@ -3314,6 +3349,7 @@ function data_presets_generate_xml($course, $cm, $data) {
         'maxentries',
         'rssarticles',
         'approval',
+        'manageapproved',
         'defaultsortdir'
     );
 
index 6a25ea3..fb6fc19 100644 (file)
@@ -32,6 +32,11 @@ class mod_data_mod_form extends moodleform_mod {
         $mform->addElement('selectyesno', 'approval', get_string('requireapproval', 'data'));
         $mform->addHelpButton('approval', 'requireapproval', 'data');
 
+        $mform->addElement('selectyesno', 'manageapproved', get_string('manageapproved', 'data'));
+        $mform->addHelpButton('manageapproved', 'manageapproved', 'data');
+        $mform->setDefault('manageapproved', 1);
+        $mform->disabledIf('manageapproved', 'approval', 'eq', 0);
+
         $mform->addElement('selectyesno', 'comments', get_string('allowcomments', 'data'));
 
         $countoptions = array(0=>get_string('none'))+
index 27eeca5..11903fe 100644 (file)
@@ -24,7 +24,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2015051100;       // The current module version (Date: YYYYMMDDXX)
+$plugin->version   = 2015070300;       // The current module version (Date: YYYYMMDDXX)
 $plugin->requires  = 2015050500;       // Requires this Moodle version
 $plugin->component = 'mod_data';       // Full name of the plugin (used for diagnostics)
 $plugin->cron      = 0;
index 6ff22b7..b0c5077 100644 (file)
 
 /// Delete any requested records
 
-    if ($delete && confirm_sesskey() && ($canmanageentries or data_isowner($delete))) {
+    if ($delete && confirm_sesskey() && (data_user_can_manage_entry($delete, $data, $context))) {
         if ($confirm = optional_param('confirm',0,PARAM_INT)) {
             if (data_delete_record($delete, $data, $course->id, $cm->id)) {
                 echo $OUTPUT->notification(get_string('recorddeleted','data'), 'notifysuccess');