diff --git a/mod/data/classes/external.php b/mod/data/classes/external.php index c68f639a53c..2639c4d1826 100644 --- a/mod/data/classes/external.php +++ b/mod/data/classes/external.php @@ -150,6 +150,27 @@ class mod_data_external extends external_api { ); } + /** + * Utility function for validating a database. + * + * @param int $databaseid database instance id + * @return array array containing the database object, course, context and course module objects + * @since Moodle 3.3 + */ + protected static function validate_database($databaseid) { + global $DB; + + // Request and permission validation. + $database = $DB->get_record('data', array('id' => $databaseid), '*', MUST_EXIST); + list($course, $cm) = get_course_and_cm_from_instance($database, 'data'); + + $context = context_module::instance($cm->id); + self::validate_context($context); + require_capability('mod/data:viewentry', $context); + + return array($database, $course, $cm, $context); + } + /** * Returns description of method parameters * @@ -173,22 +194,14 @@ class mod_data_external extends external_api { * @throws moodle_exception */ public static function view_database($databaseid) { - global $DB; $params = self::validate_parameters(self::view_database_parameters(), array('databaseid' => $databaseid)); $warnings = array(); - // Request and permission validation. - $data = $DB->get_record('data', array('id' => $params['databaseid']), '*', MUST_EXIST); - list($course, $cm) = get_course_and_cm_from_instance($data, 'data'); - - $context = context_module::instance($cm->id); - self::validate_context($context); - - require_capability('mod/data:viewentry', $context); + list($database, $course, $cm, $context) = self::validate_database($params['databaseid']); // Call the data/lib API. - data_view($data, $course, $cm, $context); + data_view($database, $course, $cm, $context); $result = array(); $result['status'] = true; @@ -211,4 +224,102 @@ class mod_data_external extends external_api { ); } + /** + * Returns description of method parameters. + * + * @return external_function_parameters + * @since Moodle 3.3 + */ + public static function get_data_access_information_parameters() { + return new external_function_parameters( + array( + 'databaseid' => new external_value(PARAM_INT, 'Database instance id.'), + 'groupid' => new external_value(PARAM_INT, 'Group id, 0 means that the function will determine the user group.', + VALUE_DEFAULT, 0), + ) + ); + } + + /** + * Return access information for a given database. + * + * @param int $databaseid the database instance id + * @param int $groupid (optional) group id, 0 means that the function will determine the user group + * @return array of warnings and access information + * @since Moodle 3.3 + * @throws moodle_exception + */ + public static function get_data_access_information($databaseid, $groupid = 0) { + + $params = array('databaseid' => $databaseid, 'groupid' => $groupid); + $params = self::validate_parameters(self::get_data_access_information_parameters(), $params); + $warnings = array(); + + list($database, $course, $cm, $context) = self::validate_database($params['databaseid']); + + $result = array( + 'warnings' => $warnings + ); + + $groupmode = groups_get_activity_groupmode($cm); + if (!empty($params['groupid'])) { + $groupid = $params['groupid']; + // Determine is the group is visible to user. + if (!groups_group_visible($groupid, $course, $cm)) { + throw new moodle_exception('notingroup'); + } + } else { + // Check to see if groups are being used here. + if ($groupmode) { + $groupid = groups_get_activity_group($cm); + // Determine is the group is visible to user (this is particullary for the group 0 -> all groups). + if (!groups_group_visible($groupid, $course, $cm)) { + throw new moodle_exception('notingroup'); + } + } else { + $groupid = 0; + } + } + // Group related information. + $result['groupid'] = $groupid; + $result['canaddentry'] = data_user_can_add_entry($database, $groupid, $groupmode, $context); + + // Now capabilities. + $result['canmanageentries'] = has_capability('mod/data:manageentries', $context); + $result['canapprove'] = has_capability('mod/data:approve', $context); + + // Now time access restrictions. + list($result['timeavailable'], $warnings) = data_get_time_availability_status($database, $result['canmanageentries']); + + // Other information. + $result['numentries'] = data_numentries($database); + $result['entrieslefttoadd'] = data_get_entries_left_to_add($database, $result['numentries'], $result['canmanageentries']); + $result['entrieslefttoview'] = data_get_entries_left_to_view($database, $result['numentries'], $result['canmanageentries']); + $result['inreadonlyperiod'] = data_in_readonly_period($database); + + return $result; + } + + /** + * Returns description of method result value. + * + * @return external_description + * @since Moodle 3.3 + */ + public static function get_data_access_information_returns() { + return new external_single_structure( + array( + 'groupid' => new external_value(PARAM_INT, 'User current group id (calculated)'), + 'canaddentry' => new external_value(PARAM_BOOL, 'Whether the user can add entries or not.'), + 'canmanageentries' => new external_value(PARAM_BOOL, 'Whether the user can manage entries or not.'), + 'canapprove' => new external_value(PARAM_BOOL, 'Whether the user can approve entries or not.'), + 'timeavailable' => new external_value(PARAM_BOOL, 'Whether the database is available or not by time restrictions.'), + 'inreadonlyperiod' => new external_value(PARAM_BOOL, 'Whether the database is in read mode only.'), + 'numentries' => new external_value(PARAM_INT, 'The number of entries the current user added.'), + 'entrieslefttoadd' => new external_value(PARAM_INT, 'The number of entries left to complete the activity.'), + 'entrieslefttoview' => new external_value(PARAM_INT, 'The number of entries left to view other users entries.'), + 'warnings' => new external_warnings() + ) + ); + } } diff --git a/mod/data/db/services.php b/mod/data/db/services.php index 213474fba74..a1ae7174b6d 100644 --- a/mod/data/db/services.php +++ b/mod/data/db/services.php @@ -43,4 +43,12 @@ $functions = array( 'capabilities' => 'mod/data:viewentry', 'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE) ), + 'mod_data_get_data_access_information' => array( + 'classname' => 'mod_data_external', + 'methodname' => 'get_data_access_information', + 'description' => 'Return access information for a given database.', + 'type' => 'read', + 'capabilities' => 'mod/data:viewentry', + 'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE) + ), ); diff --git a/mod/data/lib.php b/mod/data/lib.php index 566790eb353..81cfb9102cb 100644 --- a/mod/data/lib.php +++ b/mod/data/lib.php @@ -3244,6 +3244,7 @@ function data_pluginfile($course, $cm, $context, $filearea, $args, $forcedownloa function data_extend_navigation($navigation, $course, $module, $cm) { global $CFG, $OUTPUT, $USER, $DB; + require_once($CFG->dirroot . '/mod/data/locallib.php'); $rid = optional_param('rid', 0, PARAM_INT); @@ -3251,10 +3252,10 @@ function data_extend_navigation($navigation, $course, $module, $cm) { $currentgroup = groups_get_activity_group($cm); $groupmode = groups_get_activity_groupmode($cm); - $numentries = data_numentries($data); - /// Check the number of entries required against the number of entries already made (doesn't apply to teachers) - if ($data->requiredentries > 0 && $numentries < $data->requiredentries && !has_capability('mod/data:manageentries', context_module::instance($cm->id))) { - $data->entriesleft = $data->requiredentries - $numentries; + $numentries = data_numentries($data); + $canmanageentries = has_capability('mod/data:manageentries', context_module::instance($cm->id)); + + if ($data->entriesleft = data_get_entries_left_to_add($data, $numentries, $canmanageentries)) { $entriesnode = $navigation->add(get_string('entrieslefttoadd', 'data', $data)); $entriesnode->add_class('note'); } diff --git a/mod/data/locallib.php b/mod/data/locallib.php index 015d578f434..276efac61a8 100644 --- a/mod/data/locallib.php +++ b/mod/data/locallib.php @@ -670,3 +670,97 @@ function data_set_events($data) { } } } + +/** + * Check if a database is available for the current user. + * + * @param stdClass $data database record + * @param boolean $canmanageentries optional, if the user can manage entries + * @param stdClass $context Module context, required if $canmanageentries is not set + * @return array status (available or not and possible warnings) + * @since Moodle 3.3 + */ +function data_get_time_availability_status($data, $canmanageentries = null, $context = null) { + $open = true; + $closed = false; + $warnings = array(); + + if ($canmanageentries === null) { + $canmanageentries = has_capability('mod/data:manageentries', $context); + } + + if (!$canmanageentries) { + $timenow = time(); + + if (!empty($data->timeavailablefrom) and $data->timeavailablefrom > $timenow) { + $open = false; + } + if (!empty($data->timeavailableto) and $timenow > $data->timeavailableto) { + $closed = true; + } + + if (!$open or $closed) { + if (!$open) { + $warnings['notopenyet'] = userdate($data->timeavailablefrom); + } + if ($closed) { + $warnings['expired'] = userdate($data->timeavailableto); + } + return array(false, $warnings); + } + } + + // Database is available. + return array(true, $warnings); +} + +/** + * Requires a database to be available for the current user. + * + * @param stdClass $data database record + * @param boolean $canmanageentries optional, if the user can manage entries + * @param stdClass $context Module context, required if $canmanageentries is not set + * @throws moodle_exception + * @since Moodle 3.3 + */ +function data_require_time_available($data, $canmanageentries = null, $context = null) { + + list($available, $warnings) = data_get_time_availability_status($data, $canmanageentries, $context); + + if (!$available) { + $reason = current(array_keys($warnings)); + throw new moodle_exception($reason, 'data', '', $warnings[$reason]); + } +} + +/** + * Return the number of entries left to add to complete the activity. + * + * @param stdClass $data database object + * @param int $numentries the number of entries the current user has created + * @param bool $canmanageentries whether the user can manage entries (teachers, managers) + * @return int the number of entries left, 0 if no entries left or if is not required + * @since Moodle 3.3 + */ +function data_get_entries_left_to_add($data, $numentries, $canmanageentries) { + if ($data->requiredentries > 0 && $numentries < $data->requiredentries && !$canmanageentries) { + return $data->requiredentries - $numentries; + } + return 0; +} + +/** + * Return the number of entires left to add to view other users entries.. + * + * @param stdClass $data database object + * @param int $numentries the number of entries the current user has created + * @param bool $canmanageentries whether the user can manage entries (teachers, managers) + * @return int the number of entries left, 0 if no entries left or if is not required + * @since Moodle 3.3 + */ +function data_get_entries_left_to_view($data, $numentries, $canmanageentries) { + if ($data->requiredentriestoview > 0 && $numentries < $data->requiredentriestoview && !$canmanageentries) { + return $data->requiredentriestoview - $numentries; + } + return 0; +} diff --git a/mod/data/tests/externallib_test.php b/mod/data/tests/externallib_test.php index 46bd139e0df..e2c841afa16 100644 --- a/mod/data/tests/externallib_test.php +++ b/mod/data/tests/externallib_test.php @@ -257,4 +257,62 @@ class mod_data_external_testcase extends externallib_advanced_testcase { $this->assertEventContextNotUsed($event); $this->assertNotEmpty($event->get_name()); } + + /** + * Test get_data_access_information for student. + */ + public function test_get_data_access_information_student() { + global $DB; + // Modify the database to add access restrictions. + $this->data->timeavailablefrom = time() + DAYSECS; + $this->data->requiredentries = 2; + $this->data->requiredentriestoview = 2; + $DB->update_record('data', $this->data); + + // Test user with full capabilities. + $this->setUser($this->student1); + + $result = mod_data_external::get_data_access_information($this->data->id); + $result = external_api::clean_returnvalue(mod_data_external::get_data_access_information_returns(), $result); + + $this->assertEquals(0, $result['groupid']); + + $this->assertFalse($result['canmanageentries']); + $this->assertFalse($result['canapprove']); + $this->assertTrue($result['canaddentry']); // It return true because it doen't check time restrictions. + $this->assertFalse($result['timeavailable']); + $this->assertFalse($result['inreadonlyperiod']); + $this->assertEquals(0, $result['numentries']); + $this->assertEquals($this->data->requiredentries, $result['entrieslefttoadd']); + $this->assertEquals($this->data->requiredentriestoview, $result['entrieslefttoview']); + } + + /** + * Test get_data_access_information for teacher. + */ + public function test_get_data_access_information_teacher() { + global $DB; + // Modify the database to add access restrictions. + $this->data->timeavailablefrom = time() + DAYSECS; + $this->data->requiredentries = 2; + $this->data->requiredentriestoview = 2; + $DB->update_record('data', $this->data); + + // Test user with full capabilities. + $this->setUser($this->teacher); + + $result = mod_data_external::get_data_access_information($this->data->id); + $result = external_api::clean_returnvalue(mod_data_external::get_data_access_information_returns(), $result); + + $this->assertEquals(0, $result['groupid']); + + $this->assertTrue($result['canmanageentries']); + $this->assertTrue($result['canapprove']); + $this->assertTrue($result['canaddentry']); // It return true because it doen't check time restrictions. + $this->assertTrue($result['timeavailable']); + $this->assertFalse($result['inreadonlyperiod']); + $this->assertEquals(0, $result['numentries']); + $this->assertEquals(0, $result['entrieslefttoadd']); + $this->assertEquals(0, $result['entrieslefttoview']); + } } diff --git a/mod/data/version.php b/mod/data/version.php index 0e463c70107..43d1f0e0586 100644 --- a/mod/data/version.php +++ b/mod/data/version.php @@ -24,7 +24,7 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2016120502; // The current module version (Date: YYYYMMDDXX) +$plugin->version = 2016120503; // The current module version (Date: YYYYMMDDXX) $plugin->requires = 2016112900; // Requires this Moodle version $plugin->component = 'mod_data'; // Full name of the plugin (used for diagnostics) $plugin->cron = 0; diff --git a/mod/data/view.php b/mod/data/view.php index d9063df1db1..49b6db5d085 100644 --- a/mod/data/view.php +++ b/mod/data/view.php @@ -432,19 +432,13 @@ } } + // If data activity closed dont let students in. + list($showactivity, $warnings) = data_get_time_availability_status($data, $canmanageentries); -//if data activity closed dont let students in -$showactivity = true; -if (!$canmanageentries) { - $timenow = time(); - if (!empty($data->timeavailablefrom) && $data->timeavailablefrom > $timenow) { - echo $OUTPUT->notification(get_string('notopenyet', 'data', userdate($data->timeavailablefrom))); - $showactivity = false; - } else if (!empty($data->timeavailableto) && $timenow > $data->timeavailableto) { - echo $OUTPUT->notification(get_string('expired', 'data', userdate($data->timeavailableto))); - $showactivity = false; + if (!$showactivity) { + $reason = current(array_keys($warnings)); + echo $OUTPUT->notification(get_string($reason, 'data', $warnings[$reason])); } -} if ($showactivity) { // Print the tabs @@ -483,18 +477,16 @@ if ($showactivity) { } } - $numentries = data_numentries($data); + $numentries = data_numentries($data); /// Check the number of entries required against the number of entries already made (doesn't apply to teachers) - if ($data->requiredentries > 0 && $numentries < $data->requiredentries && !$canmanageentries) { - $data->entriesleft = $data->requiredentries - $numentries; + if ($data->entriesleft = data_get_entries_left_to_add($data, $numentries, $canmanageentries)) { $strentrieslefttoadd = get_string('entrieslefttoadd', 'data', $data); echo $OUTPUT->notification($strentrieslefttoadd); } /// Check the number of entries required before to view other participant's entries against the number of entries already made (doesn't apply to teachers) $requiredentries_allowed = true; - if ($data->requiredentriestoview > 0 && $numentries < $data->requiredentriestoview && !$canmanageentries) { - $data->entrieslefttoview = $data->requiredentriestoview - $numentries; + if ($data->entrieslefttoview = data_get_entries_left_to_view($data, $numentries, $canmanageentries)) { $strentrieslefttoaddtoview = get_string('entrieslefttoaddtoview', 'data', $data); echo $OUTPUT->notification($strentrieslefttoaddtoview); $requiredentries_allowed = false;