diff --git a/mod/workshop/lang/en/workshop.php b/mod/workshop/lang/en/workshop.php index c7bea5ef07a..c6a2624f6e7 100644 --- a/mod/workshop/lang/en/workshop.php +++ b/mod/workshop/lang/en/workshop.php @@ -334,6 +334,7 @@ $string['userplanaccessibilitytitle'] = 'Workshop timeline with {$a} phases'; $string['useselfassessment'] = 'Use self-assessment'; $string['useselfassessment_help'] = 'If enabled, a user may be allocated their own submission to assess and will receive a grade for assessment in addition to a grade for their submission.'; $string['useselfassessment_desc'] = 'Students may assess their own work'; +$string['viewworkshopsummary'] = 'View workshop summary'; $string['weightinfo'] = 'Weight: {$a}'; $string['withoutsubmission'] = 'Reviewer without own submission'; $string['workshop:addinstance'] = 'Add a new workshop'; diff --git a/mod/workshop/lib.php b/mod/workshop/lib.php index b5d8b18f1c7..273675b57cd 100644 --- a/mod/workshop/lib.php +++ b/mod/workshop/lib.php @@ -30,6 +30,11 @@ defined('MOODLE_INTERNAL') || die(); require_once($CFG->dirroot . '/calendar/lib.php'); +define('WORKSHOP_EVENT_TYPE_SUBMISSION_OPEN', 'opensubmission'); +define('WORKSHOP_EVENT_TYPE_SUBMISSION_CLOSE', 'closesubmission'); +define('WORKSHOP_EVENT_TYPE_ASSESSMENT_OPEN', 'openassessment'); +define('WORKSHOP_EVENT_TYPE_ASSESSMENT_CLOSE', 'closeassessment'); + //////////////////////////////////////////////////////////////////////////////// // Moodle core API // //////////////////////////////////////////////////////////////////////////////// @@ -1698,7 +1703,6 @@ function workshop_calendar_update(stdClass $workshop, $cmid) { $base->groupid = 0; $base->userid = 0; $base->modulename = 'workshop'; - $base->eventtype = 'pluginname'; $base->instance = $workshop->id; $base->visible = instance_is_visible('workshop', $workshop); $base->timeduration = 0; @@ -1706,7 +1710,10 @@ function workshop_calendar_update(stdClass $workshop, $cmid) { if ($workshop->submissionstart) { $event = clone($base); $event->name = get_string('submissionstartevent', 'mod_workshop', $workshop->name); + $event->eventtype = WORKSHOP_EVENT_TYPE_SUBMISSION_OPEN; + $event->type = empty($workshop->submissionend) ? CALENDAR_EVENT_TYPE_ACTION : CALENDAR_EVENT_TYPE_STANDARD; $event->timestart = $workshop->submissionstart; + $event->timesort = $workshop->submissionstart; if ($reusedevent = array_shift($currentevents)) { $event->id = $reusedevent->id; } else { @@ -1721,7 +1728,10 @@ function workshop_calendar_update(stdClass $workshop, $cmid) { if ($workshop->submissionend) { $event = clone($base); $event->name = get_string('submissionendevent', 'mod_workshop', $workshop->name); + $event->eventtype = WORKSHOP_EVENT_TYPE_SUBMISSION_CLOSE; + $event->type = CALENDAR_EVENT_TYPE_ACTION; $event->timestart = $workshop->submissionend; + $event->timesort = $workshop->submissionend; if ($reusedevent = array_shift($currentevents)) { $event->id = $reusedevent->id; } else { @@ -1736,7 +1746,10 @@ function workshop_calendar_update(stdClass $workshop, $cmid) { if ($workshop->assessmentstart) { $event = clone($base); $event->name = get_string('assessmentstartevent', 'mod_workshop', $workshop->name); + $event->eventtype = WORKSHOP_EVENT_TYPE_ASSESSMENT_OPEN; + $event->type = empty($workshop->assessmentend) ? CALENDAR_EVENT_TYPE_ACTION : CALENDAR_EVENT_TYPE_STANDARD; $event->timestart = $workshop->assessmentstart; + $event->timesort = $workshop->assessmentstart; if ($reusedevent = array_shift($currentevents)) { $event->id = $reusedevent->id; } else { @@ -1751,7 +1764,10 @@ function workshop_calendar_update(stdClass $workshop, $cmid) { if ($workshop->assessmentend) { $event = clone($base); $event->name = get_string('assessmentendevent', 'mod_workshop', $workshop->name); + $event->eventtype = WORKSHOP_EVENT_TYPE_ASSESSMENT_CLOSE; + $event->type = CALENDAR_EVENT_TYPE_ACTION; $event->timestart = $workshop->assessmentend; + $event->timesort = $workshop->assessmentend; if ($reusedevent = array_shift($currentevents)) { $event->id = $reusedevent->id; } else { @@ -1770,6 +1786,38 @@ function workshop_calendar_update(stdClass $workshop, $cmid) { } } +/** + * Is the event visible? + * + * @param \core_calendar\event $event + * @return bool Returns true if the event is visible to the current user, false otherwise. + */ +function mod_workshop_core_calendar_is_event_visible(\core_calendar\event $event) { + $cm = get_fast_modinfo($event->courseid)->instances['workshop'][$event->instance]; + $context = context_module::instance($cm->id); + return has_capability('mod/workshop:view', $context); +} + +/** + * Handles creating actions for events. + * + * @param \core_calendar\event $event + * @param \core_calendar\action_factory $factory + * @return \core_calendar\local\event\value_objects\action|\core_calendar\local\interfaces\action_interface|null + */ +function mod_workshop_core_calendar_provide_event_action(\core_calendar\event $event, + \core_calendar\action_factory $factory) { + + $cm = get_fast_modinfo($event->courseid)->instances['workshop'][$event->instance]; + + return $factory->create_instance( + get_string('viewworkshopsummary', 'workshop'), + new \moodle_url('/mod/workshop/view.php', array('id' => $cm->id)), + 1, + true + ); +} + //////////////////////////////////////////////////////////////////////////////// // Course reset API // //////////////////////////////////////////////////////////////////////////////// diff --git a/mod/workshop/tests/lib_test.php b/mod/workshop/tests/lib_test.php new file mode 100644 index 00000000000..ddb7eb4933a --- /dev/null +++ b/mod/workshop/tests/lib_test.php @@ -0,0 +1,189 @@ +. +/** + * Unit tests for mod/workshop/lib.php. + * + * @package mod_workshop + * @copyright 2017 Simey Lameze + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +defined('MOODLE_INTERNAL') || die(); + +global $CFG; +require_once($CFG->dirroot . '/mod/workshop/lib.php'); + +/** + * Unit tests for mod/workshop/lib.php. + * + * @copyright 2017 Simey Lameze + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class mod_workshop_lib_testcase extends advanced_testcase +{ + + /** + * Test calendar event visibility. + */ + public function test_workshop_core_calendar_is_event_visible() + { + $this->resetAfterTest(); + $this->setAdminUser(); + + $course = $this->getDataGenerator()->create_course(); + $workshop = $this->getDataGenerator()->create_module('workshop', ['course' => $course->id]); + $event = $this->create_action_event($course->id, $workshop->id, WORKSHOP_EVENT_TYPE_SUBMISSION_OPEN); + + $this->assertTrue(mod_workshop_core_calendar_is_event_visible($event)); + } + + /** + * Test calendar event visibility to a non-user. + */ + public function test_workshop_core_calendar_is_event_visible_as_non_user() + { + global $CFG; + $this->resetAfterTest(); + $this->setAdminUser(); + + $course = $this->getDataGenerator()->create_course(); + $workshop = $this->getDataGenerator()->create_module('workshop', array('course' => $course->id)); + $event = $this->create_action_event($course->id, $workshop->id, WORKSHOP_EVENT_TYPE_SUBMISSION_OPEN); + + // Log out the user and set force login to true. + \core\session\manager::init_empty_session(); + $CFG->forcelogin = true; + + $this->assertFalse(mod_workshop_core_calendar_is_event_visible($event)); + } + + /** + * Test calendar event provide action open. + */ + public function test_workshop_core_calendar_provide_event_action_open() + { + $this->resetAfterTest(); + $this->setAdminUser(); + + $now = time(); + $course = $this->getDataGenerator()->create_course(); + $workshop = $this->getDataGenerator()->create_module('workshop', ['course' => $course->id, + 'submissionstart' => $now - DAYSECS, 'submissionend' => $now + DAYSECS]); + $event = $this->create_action_event($course->id, $workshop->id, WORKSHOP_EVENT_TYPE_SUBMISSION_OPEN); + + $factory = new \core_calendar\action_factory(); + $actionevent = mod_workshop_core_calendar_provide_event_action($event, $factory); + + $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent); + $this->assertEquals(get_string('viewworkshopsummary', 'workshop'), $actionevent->get_name()); + $this->assertInstanceOf('moodle_url', $actionevent->get_url()); + $this->assertEquals(1, $actionevent->get_item_count()); + $this->assertTrue($actionevent->is_actionable()); + } + + /** + * Test calendar event provide action closed. + */ + public function test_workshop_core_calendar_provide_event_action_closed() + { + $this->resetAfterTest(); + $this->setAdminUser(); + + $course = $this->getDataGenerator()->create_course(); + $workshop = $this->getDataGenerator()->create_module('workshop', array('course' => $course->id, + 'submissionend' => time() - DAYSECS)); + $event = $this->create_action_event($course->id, $workshop->id, WORKSHOP_EVENT_TYPE_SUBMISSION_OPEN); + + $factory = new \core_calendar\action_factory(); + $actionevent = mod_workshop_core_calendar_provide_event_action($event, $factory); + + $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent); + $this->assertEquals(get_string('viewworkshopsummary', 'workshop'), $actionevent->get_name()); + $this->assertInstanceOf('moodle_url', $actionevent->get_url()); + $this->assertEquals(1, $actionevent->get_item_count()); + $this->assertTrue($actionevent->is_actionable()); + } + + /** + * Test calendar event action open in future. + * + * @throws coding_exception + */ + public function test_workshop_core_calendar_provide_event_action_open_in_future() + { + $this->resetAfterTest(); + $this->setAdminUser(); + + $course = $this->getDataGenerator()->create_course(); + $workshop = $this->getDataGenerator()->create_module('workshop', ['course' => $course->id, + 'submissionstart' => time() + DAYSECS]); + $event = $this->create_action_event($course->id, $workshop->id, WORKSHOP_EVENT_TYPE_SUBMISSION_OPEN); + + $factory = new \core_calendar\action_factory(); + $actionevent = mod_workshop_core_calendar_provide_event_action($event, $factory); + + $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent); + $this->assertEquals(get_string('viewworkshopsummary', 'workshop'), $actionevent->get_name()); + $this->assertInstanceOf('moodle_url', $actionevent->get_url()); + $this->assertEquals(1, $actionevent->get_item_count()); + $this->assertTrue($actionevent->is_actionable()); + } + + /** + * Test calendar event with no time specified. + * + * @throws coding_exception + */ + public function test_workshop_core_calendar_provide_event_action_no_time_specified() + { + $this->resetAfterTest(); + $this->setAdminUser(); + + $course = $this->getDataGenerator()->create_course(); + $workshop = $this->getDataGenerator()->create_module('workshop', ['course' => $course->id]); + $event = $this->create_action_event($course->id, $workshop->id, WORKSHOP_EVENT_TYPE_SUBMISSION_OPEN); + + $factory = new \core_calendar\action_factory(); + $actionevent = mod_workshop_core_calendar_provide_event_action($event, $factory); + + $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent); + $this->assertEquals(get_string('viewworkshopsummary', 'workshop'), $actionevent->get_name()); + $this->assertInstanceOf('moodle_url', $actionevent->get_url()); + $this->assertEquals(1, $actionevent->get_item_count()); + $this->assertTrue($actionevent->is_actionable()); + } + + /** + * Creates an action event. + * + * @param int $courseid The course id. + * @param int $instanceid The workshop id. + * @param string $eventtype The event type. eg. WORKSHOP_EVENT_TYPE_OPEN. + * @return bool|\core_calendar\event + */ + private function create_action_event($courseid, $instanceid, $eventtype) + { + $event = new stdClass(); + $event->name = 'Calendar event'; + $event->modulename = 'workshop'; + $event->courseid = $courseid; + $event->instance = $instanceid; + $event->type = CALENDAR_EVENT_TYPE_ACTION; + $event->eventtype = $eventtype; + $event->timestart = time(); + + return \core_calendar\event::create($event); + } +}