Merge branch 'MDL-83901-main-v02' of https://github.com/ferranrecio/moodle

This commit is contained in:
Sara Arjona
2025-03-12 08:09:16 +01:00
10 changed files with 1180 additions and 66 deletions
@@ -145,7 +145,7 @@ final class overviewfactory_test extends \advanced_testcase {
],
'workshop' => [
'resourcetype' => 'workshop',
'expected' => resourceoverview::class,
'expected' => \mod_workshop\courseformat\overview::class,
],
];
}
@@ -84,7 +84,7 @@ final class missingoverviewnotice_test extends \advanced_testcase {
'scorm' => ['modname' => 'scorm', 'expectempty' => false],
'url' => ['modname' => 'url', 'expectempty' => false],
'wiki' => ['modname' => 'wiki', 'expectempty' => false],
'workshop' => ['modname' => 'workshop', 'expectempty' => false],
'workshop' => ['modname' => 'workshop', 'expectempty' => true],
];
}
}
@@ -0,0 +1,236 @@
<?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/>.
namespace mod_workshop\courseformat;
use cm_info;
use core_courseformat\local\overview\overviewitem;
use core\output\action_link;
use core\output\local\properties\text_align;
use core\output\local\properties\button;
use core\url;
use stdClass;
use workshop;
/**
* Workshop overview integration.
*
* @package mod_workshop
* @copyright 2025 Ferran Recio <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class overview extends \core_courseformat\activityoverviewbase {
/** @var workshop $workshop the workshop instance. */
private workshop $workshop;
/** @var stdClass $activephase the active phase. */
private stdClass $activephase;
/**
* Constructor.
*
* @param cm_info $cm the course module instance.
*/
public function __construct(
cm_info $cm,
) {
global $CFG, $USER;
require_once($CFG->dirroot . '/mod/workshop/locallib.php');
parent::__construct($cm);
$this->workshop = new workshop(
$cm->get_instance_record(),
$cm,
$this->course,
$this->context,
);
$userplan = new \workshop_user_plan($this->workshop, $USER->id);
foreach ($userplan->phases as $phase) {
if ($phase->active) {
$this->activephase = $phase;
}
}
}
#[\Override]
protected function get_grade_item_names(array $items): array {
if (count($items) != 2) {
return parent::get_grade_item_names($items);
}
$names = [];
foreach ($items as $item) {
$stridentifier = ($item->itemnumber == 0) ? 'overview_submission_grade' : 'overview_assessment_grade';
$names[$item->id] = get_string($stridentifier, 'mod_workshop');
}
return $names;
}
#[\Override]
public function get_extra_overview_items(): array {
return [
'phase' => $this->get_extra_phase_overview(),
'deadline' => $this->get_extra_deadline_overview(),
'submissions' => $this->get_extra_submissions_overview(),
'assessments' => $this->get_extra_assessments_overview(),
];
}
/**
* Get the current phase overview item.
*
* @return overviewitem|null An overview item, or null if the user lacks the required capability.
*/
private function get_extra_phase_overview(): ?overviewitem {
$currentphasetitle = '-';
if ($this->activephase) {
$currentphasetitle = $this->activephase->title;
}
return new overviewitem(
name: get_string('phase', 'workshop'),
value: $this->workshop->phase,
content: $currentphasetitle,
);
}
/**
* Retrieves an overview of the deadline for the workshop.
*
* @return overviewitem|null An overview item, or null if the current phase does not have a deadline.
*/
private function get_extra_deadline_overview(): ?overviewitem {
$deadline = match ((int)$this->workshop->phase) {
workshop::PHASE_SUBMISSION => $this->workshop->submissionend ?? 0,
workshop::PHASE_ASSESSMENT => $this->workshop->assessmentend ?? 0,
default => 0,
};
if (empty($deadline)) {
return new overviewitem(
name: get_string('deadline', 'workshop'),
value: null,
content: '-',
);
}
return new overviewitem(
name: get_string('deadline', 'workshop'),
value: (int) $deadline,
content: userdate($deadline),
);
}
/**
* Retrieves an overview of submissions for the workshop.
*
* @return overviewitem|null An overview item, or null if the user lacks the required capability.
*/
private function get_extra_submissions_overview(): ?overviewitem {
if (!has_capability('mod/workshop:viewallsubmissions', $this->cm->context)) {
return null;
}
$submissions = $this->workshop->count_submissions();
$total = $this->workshop->count_participants();
if (!$total) {
return new overviewitem(
name: get_string('submissions', 'workshop'),
value: 0,
content: '-',
textalign: text_align::CENTER,
);
}
$content = get_string(
'count_of_total',
'core',
['count' => $submissions, 'total' => $total]
);
// If the current phase is submission, we can add a direct link.
if ($this->workshop->phase == workshop::PHASE_SUBMISSION) {
$content = new action_link(
url: new url(
'/mod/workshop/view.php',
['id' => $this->cm->id],
'workshop-viewlet-allsubmissions',
),
text: $content,
attributes: ['class' => button::SECONDARY_OUTLINE->classes()],
);
}
return new overviewitem(
name: get_string('submissions', 'workshop'),
value: $submissions,
content: $content,
textalign: text_align::CENTER,
);
}
/**
* Retrieves an overview of assessments for the workshop.
*
* @return overviewitem|null An overview item, or null if the user lacks the required capability.
*/
private function get_extra_assessments_overview(): ?overviewitem {
global $USER;
if (!has_capability('mod/workshop:viewallassessments', $this->cm->context)) {
return null;
}
$assessments = $this->workshop->count_assessments(true);
$total = $this->workshop->count_assessments(false);
if (!$total) {
return new overviewitem(
name: get_string('assessments', 'workshop'),
value: 0,
content: '-',
textalign: text_align::CENTER,
);
}
$content = get_string(
'count_of_total',
'core',
['count' => $assessments, 'total' => $total]
);
// If the current phase is assessment, we can add a direct link.
if ($this->workshop->phase == workshop::PHASE_ASSESSMENT) {
$content = new action_link(
url: new url(
'/mod/workshop/view.php',
['id' => $this->cm->id],
'workshop-viewlet-gradereport',
),
text: $content,
attributes: ['class' => button::SECONDARY_OUTLINE->classes()],
);
}
return new overviewitem(
name: get_string('assessments', 'workshop'),
value: $assessments,
content: $content,
textalign: text_align::CENTER,
);
}
}
+3 -63
View File
@@ -24,68 +24,8 @@
*/
require(__DIR__.'/../../config.php');
require_once(__DIR__.'/lib.php');
$id = required_param('id', PARAM_INT); // course
// For this type of page this is the course id.
$courseid = required_param('id', PARAM_INT);
$course = $DB->get_record('course', array('id' => $id), '*', MUST_EXIST);
require_course_login($course);
$PAGE->set_pagelayout('incourse');
$PAGE->set_url('/mod/workshop/index.php', array('id' => $course->id));
$PAGE->set_title($course->fullname);
$PAGE->set_heading($course->shortname);
$PAGE->navbar->add(get_string('modulenameplural', 'workshop'));
/// Output starts here
echo $OUTPUT->header();
$params = array('context' => context_course::instance($course->id));
$event = \mod_workshop\event\course_module_instance_list_viewed::create($params);
$event->add_record_snapshot('course', $course);
$event->trigger();
/// Get all the appropriate data
if (! $workshops = get_all_instances_in_course('workshop', $course)) {
echo $OUTPUT->heading(get_string('modulenameplural', 'workshop'));
notice(get_string('noworkshops', 'workshop'), new moodle_url('/course/view.php', array('id' => $course->id)));
echo $OUTPUT->footer();
die();
}
$usesections = course_format_uses_sections($course->format);
$timenow = time();
$strname = get_string('name');
$table = new html_table();
if ($usesections) {
$strsectionname = course_get_format($course)->get_generic_section_name();
$table->head = array ($strsectionname, $strname);
$table->align = array ('center', 'left');
} else {
$table->head = array ($strname);
$table->align = array ('left');
}
foreach ($workshops as $workshop) {
if (empty($workshop->visible)) {
$link = html_writer::link(new moodle_url('/mod/workshop/view.php', array('id' => $workshop->coursemodule)),
$workshop->name, array('class' => 'dimmed'));
} else {
$link = html_writer::link(new moodle_url('/mod/workshop/view.php', array('id' => $workshop->coursemodule)),
$workshop->name);
}
if ($usesections) {
$table->data[] = array(get_section_name($course, $workshop->section), $link);
} else {
$table->data[] = array($link);
}
}
echo $OUTPUT->heading(get_string('modulenameplural', 'workshop'), 3);
echo html_writer::table($table);
echo $OUTPUT->footer();
\core_courseformat\activityoverviewbase::redirect_to_overview_page($courseid, 'workshop');
+1
View File
@@ -0,0 +1 @@
noworkshops,mod_workshop
+8 -1
View File
@@ -108,6 +108,7 @@ $string['daysleft'] = '{$a} days left';
$string['daystoday'] = 'today';
$string['daystomorrow'] = 'tomorrow';
$string['daysyesterday'] = 'yesterday';
$string['deadline'] = 'Deadline';
$string['deadlinesignored'] = 'Time restrictions do not apply to you';
$string['deletesubmission'] = 'Delete submission';
$string['editassessmentform'] = 'Edit assessment form';
@@ -229,7 +230,6 @@ $string['nosubmissions'] = 'No submissions yet in this workshop';
$string['nothingtoreview'] = 'Nothing to review';
$string['notassessed'] = 'Not assessed yet';
$string['notoverridden'] = 'Not overridden';
$string['noworkshops'] = 'There are no workshops in this course';
$string['noyoursubmission'] = 'You have not submitted your work yet';
$string['nothingfound'] = 'Nothing to display';
$string['nullgrade'] = '-';
@@ -241,10 +241,13 @@ $string['overallfeedbackmode_0'] = 'Disabled';
$string['overallfeedbackmode_1'] = 'Enabled and optional';
$string['overallfeedbackmode_2'] = 'Enabled and required';
$string['overallfeedbackmode_help'] = 'If enabled, a text field is displayed at the bottom of the assessment form. Reviewers can put the overall assessment of the submission there, or provide additional explanation of their assessment.';
$string['overview_assessment_grade'] = 'Assessment grade';
$string['overview_submission_grade'] = 'Submission grade';
$string['page-mod-workshop-x'] = 'Any workshop module page';
$string['participant'] = 'Participant';
$string['participantrevierof'] = 'Participant is reviewer of';
$string['participantreviewedby'] = 'Participant is reviewed by';
$string['phase'] = 'Phase';
$string['phaseassessment'] = 'Assessment phase';
$string['phaseclosed'] = 'Closed';
$string['phaseevaluation'] = 'Grading evaluation phase';
@@ -345,6 +348,7 @@ $string['strategy_help'] = 'The grading strategy determines the assessment form
* Rubric - A level assessment is given regarding specified criteria';
$string['strategyhaschanged'] = 'The workshop grading strategy has changed since the form was opened for editing.';
$string['submission'] = 'Submission';
$string['submissions'] = 'Submissions';
$string['submissionattachment'] = 'Attachment';
$string['submissionby'] = 'Submission by {$a}';
$string['submissioncontent'] = 'Submission content';
@@ -455,3 +459,6 @@ $string['yourassessmentfor'] = 'Your assessment for {$a}';
$string['yourgrades'] = 'Your grades';
$string['yoursubmission'] = 'Your submission';
$string['yoursubmissionwithassessments'] = 'Your submission with assessments';
// Deprecated since Moodle 5.0.
$string['noworkshops'] = 'There are no workshops in this course';
+31
View File
@@ -774,6 +774,37 @@ class workshop {
return $DB->count_records_sql($sql, $params);
}
/**
* Returns the total number of assessments in the workshop.
*
* @param bool $onlygraded If true, count only graded assessments
* @param int|null $groupid If not null, return only assessments by reviewers in the specified group
* @return int Number of assessments
*/
public function count_assessments(bool $onlygraded = false, ?int $groupid = null): int {
global $DB;
$params = ['workshopid' => $this->id];
$sql = "SELECT COUNT(s.id)
FROM {workshop_assessments} s
JOIN {workshop_submissions} ws ON (s.submissionid = ws.id)
JOIN {user} u ON (ws.authorid = u.id)
JOIN {workshop} w ON (ws.workshopid = w.id)";
if ($groupid) {
$sql .= " JOIN {groups_members} gm ON (gm.userid = u.id AND gm.groupid = :groupid)";
$params['groupid'] = $groupid;
}
if ($onlygraded) {
$sql .= " WHERE s.grade IS NOT NULL AND w.id = :workshopid";
} else {
$sql .= " WHERE w.id = :workshopid";
}
return $DB->count_records_sql($sql, $params);
}
/**
* Returns submissions from this workshop
@@ -0,0 +1,166 @@
@mod @mod_workshop
Feature: Testing overview integration in mod_workshop
In order to summarize the workshops
As a user
I need to be able to see the workshop overview
Background:
Given the following "users" exist:
| username | firstname | lastname |
| student1 | Student | 1 |
| student2 | Student | 2 |
| student3 | Student | 3 |
| student4 | Student | 4 |
| student5 | Student | 5 |
| student6 | Student | 6 |
| student7 | Student | 7 |
| student8 | Student | 8 |
| teacher1 | Teacher | T |
And the following "courses" exist:
| fullname | shortname | groupmode |
| Course 1 | C1 | 1 |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
| student2 | C1 | student |
| student3 | C1 | student |
| student4 | C1 | student |
| student5 | C1 | student |
| student6 | C1 | student |
| student7 | C1 | student |
| student8 | C1 | student |
| teacher1 | C1 | editingteacher |
And the following "activities" exist:
| activity | name | course | idnumber | submissiontypetext | submissiontypefile | grade | gradinggrade | gradedecimals | overallfeedbackmethod |latesubmissions | submisstionstart | submissionend |
| workshop | Activity 1 | C1 | workshop1 | 2 | 1 | 100 | 5 | 1 | 2 |1 | ##1 Jan 2018 08:00## | ##1 Jan 2040 08:00## |
| workshop | Activity 2 | C1 | workshop1 | 2 | 1 | 100 | 5 | 1 | 2 |1 | ##1 Jan 2018 08:00## | ##1 Jan 2040 08:00## |
Scenario: The workshop overview report should generate log events
Given I am on the "Course 1" "course > activities > workshop" page logged in as "teacher1"
When I am on the "Course 1" "course" page logged in as "teacher1"
And I navigate to "Reports" in current page administration
And I click on "Logs" "link"
And I click on "Get these logs" "button"
Then I should see "Course activities overview page viewed"
And I should see "viewed the instance list for the module 'workshop'"
@javascript
Scenario: Students can see relevant columns in the workshop overview
# Workshop is not compatible with grade generators (hopefully someday).
Given I am on the "Course 1" "grades > Grader report > View" page logged in as "teacher1"
And I turn editing mode on
And I change window size to "large"
And I click on "Activity 1 (submission)" "core_grades > grade_actions" in the "Student 1" "table_row"
And I choose "Edit grade" in the open action menu
And I set the following fields to these values:
| Overridden | 1 |
| Final grade | 10 |
And I press "Save changes"
And I click on "Activity 2 (assessment)" "core_grades > grade_actions" in the "Student 1" "table_row"
And I choose "Edit grade" in the open action menu
And I set the following fields to these values:
| Overridden | 1 |
| Final grade | 20 |
And I press "Save changes"
And I change window size to "medium"
And I am on the "Activity 1" "workshop activity" page
And I change phase in workshop "Activity 1" to "Submission phase"
When I am on the "Course 1" "course > activities > workshop" page logged in as "student1"
# Check columns.
Then I should see "Name" in the "workshop_overview_collapsible" "region"
And I should see "Phase" in the "workshop_overview_collapsible" "region"
And I should see "Deadline" in the "workshop_overview_collapsible" "region"
And I should see "Assessment grade" in the "workshop_overview_collapsible" "region"
And I should see "Submission grade" in the "workshop_overview_collapsible" "region"
# Check phase.
And I should see "Submission phase" in the "Activity 1" "table_row"
And I should see "Setup phase" in the "Activity 2" "table_row"
# Cheack Deadline.
And I should see "1 January 2040" in the "Activity 1" "table_row"
And I should see "-" in the "Activity 2" "table_row"
# Check Grades.
And I should see "10.00" in the "Activity 1" "table_row"
And I should see "-" in the "Activity 1" "table_row"
And I should see "-" in the "Activity 2" "table_row"
# The worksup assessment grade is normalized to 5.00.
And I should see "5.00" in the "Activity 2" "table_row"
Scenario: Teachers can see relevant columns in the workshop overview
Given I log in as "teacher1"
And I am on the "C1" course page logged in as teacher1
And I edit assessment form in workshop "Activity 1" as:
| id_description__idx_0_editor | Aspect1 |
| id_description__idx_1_editor | |
| id_description__idx_2_editor | |
And I change phase in workshop "Activity 1" to "Submission phase"
# Change activity 2 to submission phase to see due date.
And I am on the "Activity 2" "workshop activity" page
And I change phase in workshop "Activity 2" to "Submission phase"
# student1 submits
And I am on the "Activity 1" "workshop activity" page logged in as student1
And I add a submission in workshop "Activity 1" as:
| Title | Submission1 |
| Submission content | Some content |
# teacher1 allocates reviewers and changes the phase to assessment
When I am on the "Activity 1" "workshop activity" page logged in as teacher1
And I allocate submissions in workshop "Activity 1" as:
| Participant | Reviewer |
| Student 1 | Student 2 |
| Student 1 | Student 3 |
| Student 1 | Student 4 |
And I am on the "Activity 1" "workshop activity" page
And I change phase in workshop "Activity 1" to "Assessment phase"
# student2 assesses work of student1
And I am on the "Activity 1" "workshop activity" page logged in as student2
And I assess submission "Student 1" in workshop "Activity 1" as:
| grade__idx_0 | 10 / 10 |
| peercomment__idx_0 | Amazing |
| Feedback for the author | Good work |
# student3 assesses work of student1
And I am on the "Activity 1" "workshop activity" page logged in as student3
And I assess submission "Student 1" in workshop "Activity 1" as:
| grade__idx_0 | 10 / 10 |
| peercomment__idx_0 | Amazing |
| Feedback for the author | Good work |
# student4 assesses work of student1
And I am on the "Activity 1" "workshop activity" page logged in as student4
And I assess submission "Student 1" in workshop "Activity 1" as:
| grade__idx_0 | 6 / 10 |
| peercomment__idx_0 | You can do better |
| Feedback for the author | Good work |
# teacher1 makes sure he can see all peer grades and changes to grading evaluation phase
And I am on the "Activity 1" "workshop activity" page logged in as teacher1
And I change phase in workshop "Activity 1" to "Grading evaluation phase"
And I press "Re-calculate grades"
# Now, the test itself.
When I am on the "Course 1" "course > activities > workshop" page logged in as "teacher1"
# Check columns.
Then I should see "Name" in the "workshop_overview_collapsible" "region"
And I should see "Phase" in the "workshop_overview_collapsible" "region"
And I should see "Deadline" in the "workshop_overview_collapsible" "region"
And I should see "Submissions" in the "workshop_overview_collapsible" "region"
And I should see "Assessments" in the "workshop_overview_collapsible" "region"
# Check phase.
And I should see "Grading evaluation phase" in the "Activity 1" "table_row"
And I should see "Submission phase" in the "Activity 2" "table_row"
# Cheack Deadline.
And I should see "-" in the "Activity 1" "table_row"
And I should see "1 January 2040" in the "Activity 2" "table_row"
# Check Submissions.
And I should see "1 of 8" in the "Activity 1" "table_row"
And I should see "0 of 8" in the "Activity 2" "table_row"
# Check Assessments.
And I should see "3 of 3" in the "Activity 1" "table_row"
And I should see "-" in the "Activity 2" "table_row"
@javascript
Scenario: The workshop index redirect to the activities overview
When I log in as "admin"
And I am on "Course 1" course homepage with editing mode on
And I add the "Activities" block
And I click on "Workshops" "link" in the "Activities" "block"
Then I should see "View all the activities in this course"
And I should see "Name" in the "workshop_overview_collapsible" "region"
And I should see "Phase" in the "workshop_overview_collapsible" "region"
And I should see "Submissions" in the "workshop_overview_collapsible" "region"
And I should see "Assessments" in the "workshop_overview_collapsible" "region"
@@ -0,0 +1,636 @@
<?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/>.
namespace mod_workshop\courseformat;
use core_courseformat\local\overview\overviewfactory;
/**
* Tests for Workshop overview integration.
*
* @covers \mod_workshop\course\overview
* @package mod_workshop
* @category test
* @copyright 2025 Ferran Recio <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
final class overview_test extends \advanced_testcase {
#[\Override]
public static function setUpBeforeClass(): void {
global $CFG;
require_once($CFG->dirroot . '/mod/workshop/locallib.php');
parent::setUpBeforeClass();
}
/**
* Test get_grade_item_names method.
*
* @dataProvider data_provider_get_grade_item_names
* @covers ::get_grade_item_names
* @param string $user
* @param bool $expectempty
* @param bool $hassubmission
* @param bool $hasassesment
*/
public function test_get_grade_item_names(
string $user,
bool $expectempty,
bool $hassubmission,
bool $hasassesment,
): void {
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
$student = $this->getDataGenerator()->create_and_enrol($course, 'student');
$activity = $this->getDataGenerator()->create_module(
'workshop',
['course' => $course->id],
);
$cm = get_fast_modinfo($course)->get_cm($activity->cmid);
// Set up a generator to create content.
/** @var \mod_workshop_generator $generator */
$generator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
// Add grading.
$workshopitems = array_values(
\grade_item::fetch_all([
'itemtype' => 'mod',
'itemmodule' => 'workshop',
'iteminstance' => (int) $activity->id,
'courseid' => $course->id,
['grade' => 100.0],
])
);
// Workshop stores in number 1 the assessment grade and in number 0 the submission grade.
$gradeitems = [];
foreach ($workshopitems as $workshopitem) {
if ($workshopitem->itemnumber == 0) {
$gradeitems['submission'] = $workshopitem;
} else {
$gradeitems['assessment'] = $workshopitem;
}
}
$expectedsubmissions = '-';
if ($hassubmission) {
$submissionid = $generator->create_submission(
$activity->id,
$student->id,
['title' => 'My custom title', 'grade' => 85.00000],
);
$gradegrade = new \grade_grade();
$gradegrade->itemid = $gradeitems['submission']->id;
$gradegrade->userid = (int) $student->id;
$gradegrade->rawgrade = 77;
$gradegrade->finalgrade = 77;
$gradegrade->insert();
$expectedsubmissions = '77.00000';
}
$expectedassessments = '-';
if ($hasassesment) {
$generator->create_assessment(
$submissionid,
$student->id,
['weight' => 3, 'grade' => 95.00000],
);
$gradegrade = new \grade_grade();
$gradegrade->itemid = $gradeitems['assessment']->id;
$gradegrade->userid = (int) $student->id;
$gradegrade->rawgrade = 88;
$gradegrade->finalgrade = 88;
$gradegrade->insert();
$expectedassessments = '88.00000';
}
$currentuser = ($user == 'teacher') ? $teacher : $student;
$this->setUser($currentuser);
$items = overviewfactory::create($cm)->get_grades_overviews();
// Students should not see item.
if ($expectempty) {
$this->assertEmpty($items);
return;
}
$this->assertEquals(get_string('overview_submission_grade', 'mod_workshop'), $items[0]->get_name());
$this->assertEquals($expectedsubmissions, $items[0]->get_value());
$this->assertEquals(get_string('overview_assessment_grade', 'mod_workshop'), $items[1]->get_name());
$this->assertEquals($expectedassessments, $items[1]->get_value());
}
/**
* Data provider for test_get_grade_item_names.
*
* @return array
*/
public static function data_provider_get_grade_item_names(): array {
return [
'student with submissions' => [
'user' => 'student',
'expectempty' => false,
'hassubmission' => true,
'hasassesment' => false,
],
'student with assessments' => [
'user' => 'student',
'expectempty' => false,
'hassubmission' => true,
'hasassesment' => true,
],
'teacher' => [
'user' => 'teacher',
'expectempty' => true,
'hassubmission' => false,
'hasassesment' => false,
],
];
}
/**
* Test get_extra_phase_overview method.
*
* @covers ::get_extra_phase_overview
* @dataProvider data_provider_get_extra_phase_overview
* @param string $user
* @param int $currentphase
*/
public function test_get_extra_phase_overview(string $user, int $currentphase): void {
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
$student = $this->getDataGenerator()->create_and_enrol($course, 'student');
$activity = $this->getDataGenerator()->create_module(
'workshop',
['course' => $course->id],
);
$cm = get_fast_modinfo($course)->get_cm($activity->cmid);
$manager = new \workshop($activity, $cm, $course, $cm->context);
$manager->switch_phase($currentphase);
$currentuser = ($user == 'teacher') ? $teacher : $student;
$this->setUser($currentuser);
$overview = overviewfactory::create($cm);
$reflection = new \ReflectionClass($overview);
$method = $reflection->getMethod('get_extra_phase_overview');
$method->setAccessible(true);
$item = $method->invoke($overview);
$this->assertEquals(get_string('phase', 'mod_workshop'), $item->get_name());
$this->assertEquals($currentphase, $item->get_value());
}
/**
* Data provider for test_get_extra_phase_overview.
*
* @return array
*/
public static function data_provider_get_extra_phase_overview(): array {
return [
'teacher setup phase' => [
'user' => 'teacher',
'currentphase' => \workshop::PHASE_SETUP,
],
'student setup phase' => [
'user' => 'student',
'currentphase' => \workshop::PHASE_SETUP,
],
'teacher submission phase' => [
'user' => 'teacher',
'currentphase' => \workshop::PHASE_SUBMISSION,
],
'student submission phase' => [
'user' => 'student',
'currentphase' => \workshop::PHASE_SUBMISSION,
],
'teacher assessment phase' => [
'user' => 'teacher',
'currentphase' => \workshop::PHASE_ASSESSMENT,
],
'student assessment phase' => [
'user' => 'student',
'currentphase' => \workshop::PHASE_ASSESSMENT,
],
'teacher evaluation phase' => [
'user' => 'teacher',
'currentphase' => \workshop::PHASE_EVALUATION,
],
'student evaluation phase' => [
'user' => 'student',
'currentphase' => \workshop::PHASE_EVALUATION,
],
'teacher closed phase' => [
'user' => 'teacher',
'currentphase' => \workshop::PHASE_CLOSED,
],
'student closed phase' => [
'user' => 'student',
'currentphase' => \workshop::PHASE_CLOSED,
],
];
}
/**
* Test get_extra_deadline_overview method.
*
* @covers ::get_extra_deadline_overview
* @dataProvider data_provider_get_extra_deadline_overview
* @param string $user
* @param int $currentphase
* @param int $submissionend
* @param int $assessmentend
* @param int|null $expectedincrement null if the item should be null.
*/
public function test_get_extra_deadline_overview(
string $user,
int $currentphase,
int $submissionend,
int $assessmentend,
?int $expectedincrement,
): void {
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
$student = $this->getDataGenerator()->create_and_enrol($course, 'student');
$current = $this->mock_clock_with_frozen()->time();
$activity = $this->getDataGenerator()->create_module(
'workshop',
[
'course' => $course->id,
'submissionend' => $current + $submissionend,
'assessmentend' => $current + $assessmentend,
],
);
$cm = get_fast_modinfo($course)->get_cm($activity->cmid);
$manager = new \workshop($activity, $cm, $course, $cm->context);
$manager->switch_phase($currentphase);
$currentuser = ($user == 'teacher') ? $teacher : $student;
$this->setUser($currentuser);
$overview = overviewfactory::create($cm);
$reflection = new \ReflectionClass($overview);
$method = $reflection->getMethod('get_extra_deadline_overview');
$method->setAccessible(true);
$item = $method->invoke($overview);
$this->assertEquals(get_string('deadline', 'mod_workshop'), $item->get_name());
if ($expectedincrement === null) {
$this->assertNull($item->get_value());
return;
}
$this->assertEquals($current + $expectedincrement, $item->get_value());
}
/**
* Data provider for test_get_extra_phase_overview.
*
* @return array
*/
public static function data_provider_get_extra_deadline_overview(): array {
$submissionend = 3600;
$assessmentend = 7200;
return [
'teacher setup phase' => [
'user' => 'teacher',
'currentphase' => \workshop::PHASE_SETUP,
'submissionend' => $submissionend,
'assessmentend' => $assessmentend,
'expectedincrement' => null,
],
'student setup phase' => [
'user' => 'student',
'currentphase' => \workshop::PHASE_SETUP,
'submissionend' => $submissionend,
'assessmentend' => $assessmentend,
'expectedincrement' => null,
],
'teacher submission phase' => [
'user' => 'teacher',
'currentphase' => \workshop::PHASE_SUBMISSION,
'submissionend' => $submissionend,
'assessmentend' => $assessmentend,
'expectedincrement' => $submissionend,
],
'student submission phase' => [
'user' => 'student',
'currentphase' => \workshop::PHASE_SUBMISSION,
'submissionend' => $submissionend,
'assessmentend' => $assessmentend,
'expectedincrement' => $submissionend,
],
'teacher assessment phase' => [
'user' => 'teacher',
'currentphase' => \workshop::PHASE_ASSESSMENT,
'submissionend' => $submissionend,
'assessmentend' => $assessmentend,
'expectedincrement' => $assessmentend,
],
'student assessment phase' => [
'user' => 'student',
'currentphase' => \workshop::PHASE_ASSESSMENT,
'submissionend' => $submissionend,
'assessmentend' => $assessmentend,
'expectedincrement' => $assessmentend,
],
'teacher evaluation phase' => [
'user' => 'teacher',
'currentphase' => \workshop::PHASE_EVALUATION,
'submissionend' => $submissionend,
'assessmentend' => $assessmentend,
'expectedincrement' => null,
],
'student evaluation phase' => [
'user' => 'student',
'currentphase' => \workshop::PHASE_EVALUATION,
'submissionend' => $submissionend,
'assessmentend' => $assessmentend,
'expectedincrement' => null,
],
'teacher closed phase' => [
'user' => 'teacher',
'currentphase' => \workshop::PHASE_CLOSED,
'submissionend' => $submissionend,
'assessmentend' => $assessmentend,
'expectedincrement' => null,
],
'student closed phase' => [
'user' => 'student',
'currentphase' => \workshop::PHASE_CLOSED,
'submissionend' => $submissionend,
'assessmentend' => $assessmentend,
'expectedincrement' => null,
],
];
}
/**
* Test get_extra_submissions_overview and get_extra_assessments_overview methods.
*
* @covers ::get_extra_submissions_overview
* @covers ::get_extra_assessments_overview
* @dataProvider data_provider_get_extra_submissions_overview
* @param string $user
* @param int $currentphase
* @param bool $hasstudentactivity
* @param bool $expectnull
*/
public function test_get_extra_submissions_overview(
string $user,
int $currentphase,
bool $hasstudentactivity,
bool $expectnull,
): void {
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
$student = $this->getDataGenerator()->create_and_enrol($course, 'student');
$student2 = $this->getDataGenerator()->create_and_enrol($course, 'student');
$activity = $this->getDataGenerator()->create_module(
'workshop',
['course' => $course->id],
);
$cm = get_fast_modinfo($course)->get_cm($activity->cmid);
// Set up a generator to create content.
/** @var \mod_workshop_generator $generator */
$generator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
// Add grading.
$workshopitems = array_values(
\grade_item::fetch_all([
'itemtype' => 'mod',
'itemmodule' => 'workshop',
'iteminstance' => (int) $activity->id,
'courseid' => $course->id,
['grade' => 100.0],
])
);
// Worksop stores un number 1 the assessment grade and in number 0 the submission grade.
foreach ($workshopitems as $workshopitem) {
if ($workshopitem->itemnumber == 0) {
$gradeitems['submission'] = $workshopitem;
} else {
$gradeitems['assessment'] = $workshopitem;
}
}
if ($hasstudentactivity) {
// Create some submissions.
$submissionid = $generator->create_submission(
$activity->id,
$student->id,
['title' => 'My custom title', 'grade' => 85.00000],
);
$generator->create_submission(
$activity->id,
$student2->id,
['title' => 'My custom title', 'grade' => 65.00000],
);
// Assess one submission.
$generator->create_assessment(
$submissionid,
$student->id,
['weight' => 3, 'grade' => 95.00000],
);
}
$manager = new \workshop($activity, $cm, $course, $cm->context);
$manager->switch_phase($currentphase);
$currentuser = ($user == 'teacher') ? $teacher : $student;
$this->setUser($currentuser);
$overview = overviewfactory::create($cm);
$reflection = new \ReflectionClass($overview);
$method = $reflection->getMethod('get_extra_submissions_overview');
$method->setAccessible(true);
$itemsubmissions = $method->invoke($overview);
$method = $reflection->getMethod('get_extra_assessments_overview');
$method->setAccessible(true);
$itemassessment = $method->invoke($overview);
if ($expectnull) {
$this->assertNull($itemsubmissions);
$this->assertNull($itemassessment);
return;
}
$this->assertEquals(get_string('submissions', 'mod_workshop'), $itemsubmissions->get_name());
$expected = ($hasstudentactivity) ? 2 : 0;
$this->assertEquals($expected, $itemsubmissions->get_value());
$this->assertEquals(get_string('assessments', 'mod_workshop'), $itemassessment->get_name());
$expected = ($hasstudentactivity) ? 1 : 0;
$this->assertEquals($expected, $itemassessment->get_value());
}
/**
* Data provider for test_get_extra_submissions_overview.
*
* @return array
*/
public static function data_provider_get_extra_submissions_overview(): array {
return [
'teacher setup phase without activity' => [
'user' => 'teacher',
'currentphase' => \workshop::PHASE_SETUP,
'hasstudentactivity' => false,
'expectnull' => false,
],
'student setup phase without activity' => [
'user' => 'student',
'currentphase' => \workshop::PHASE_SETUP,
'hasstudentactivity' => false,
'expectnull' => true,
],
'teacher submission phase without activity' => [
'user' => 'teacher',
'currentphase' => \workshop::PHASE_SUBMISSION,
'hasstudentactivity' => false,
'expectnull' => false,
],
'student submission phase without activity' => [
'user' => 'student',
'currentphase' => \workshop::PHASE_SUBMISSION,
'hasstudentactivity' => false,
'expectnull' => true,
],
'teacher assessment phase without activity' => [
'user' => 'teacher',
'currentphase' => \workshop::PHASE_ASSESSMENT,
'hasstudentactivity' => false,
'expectnull' => false,
],
'student assessment phase without activity' => [
'user' => 'student',
'currentphase' => \workshop::PHASE_ASSESSMENT,
'hasstudentactivity' => false,
'expectnull' => true,
],
'teacher evaluation phase without activity' => [
'user' => 'teacher',
'currentphase' => \workshop::PHASE_EVALUATION,
'hasstudentactivity' => false,
'expectnull' => false,
],
'student evaluation phase without activity' => [
'user' => 'student',
'currentphase' => \workshop::PHASE_EVALUATION,
'hasstudentactivity' => false,
'expectnull' => true,
],
'teacher closed phase without activity' => [
'user' => 'teacher',
'currentphase' => \workshop::PHASE_CLOSED,
'hasstudentactivity' => false,
'expectnull' => false,
],
'student closed phase without activity' => [
'user' => 'student',
'currentphase' => \workshop::PHASE_CLOSED,
'hasstudentactivity' => false,
'expectnull' => true,
],
// Tests with assessments.
'teacher setup phase with activity' => [
'user' => 'teacher',
'currentphase' => \workshop::PHASE_SETUP,
'hasstudentactivity' => true,
'expectnull' => false,
],
'student setup phase with activity' => [
'user' => 'student',
'currentphase' => \workshop::PHASE_SETUP,
'hasstudentactivity' => true,
'expectnull' => true,
],
'teacher submission phase with activity' => [
'user' => 'teacher',
'currentphase' => \workshop::PHASE_SUBMISSION,
'hasstudentactivity' => true,
'expectnull' => false,
],
'student submission phase with activity' => [
'user' => 'student',
'currentphase' => \workshop::PHASE_SUBMISSION,
'hasstudentactivity' => true,
'expectnull' => true,
],
'teacher assessment phase with activity' => [
'user' => 'teacher',
'currentphase' => \workshop::PHASE_ASSESSMENT,
'hasstudentactivity' => true,
'expectnull' => false,
],
'student assessment phase with activity' => [
'user' => 'student',
'currentphase' => \workshop::PHASE_ASSESSMENT,
'hasstudentactivity' => true,
'expectnull' => true,
],
'teacher evaluation phase with activity' => [
'user' => 'teacher',
'currentphase' => \workshop::PHASE_EVALUATION,
'hasstudentactivity' => true,
'expectnull' => false,
],
'student evaluation phase with activity' => [
'user' => 'student',
'currentphase' => \workshop::PHASE_EVALUATION,
'hasstudentactivity' => true,
'expectnull' => true,
],
'teacher closed phase with activity' => [
'user' => 'teacher',
'currentphase' => \workshop::PHASE_CLOSED,
'hasstudentactivity' => true,
'expectnull' => false,
],
'student closed phase with activity' => [
'user' => 'student',
'currentphase' => \workshop::PHASE_CLOSED,
'hasstudentactivity' => true,
'expectnull' => true,
],
];
}
}
+97
View File
@@ -867,4 +867,101 @@ final class locallib_test extends \advanced_testcase {
return $initialbarprefs;
}
/**
* Test count_submissions and count_assessments methods.
*
* @covers \workshop::count_submissions
* @covers \workshop::count_assessments
*/
public function test_count_submissions_count_assessments(): void {
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$group1 = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
$group2 = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
$student1 = $this->getDataGenerator()->create_and_enrol($course, 'student');
$student2 = $this->getDataGenerator()->create_and_enrol($course, 'student');
$student3 = $this->getDataGenerator()->create_and_enrol($course, 'student');
$student4 = $this->getDataGenerator()->create_and_enrol($course, 'student');
groups_add_member($group1, $student1);
groups_add_member($group1, $student3);
groups_add_member($group2, $student2);
$activity = $this->getDataGenerator()->create_module(
'workshop',
['course' => $course->id , 'groupmode' => SEPARATEGROUPS],
);
$cm = get_fast_modinfo($course)->get_cm($activity->cmid);
// Set up a generator to create content.
/** @var \mod_workshop_generator $generator */
$generator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
// Create some submissions.
$submission1id = $generator->create_submission(
$activity->id,
$student1->id,
['title' => 'My custom title', 'grade' => 85.00000],
);
$submission2id = $generator->create_submission(
$activity->id,
$student2->id,
['title' => 'My custom title', 'grade' => null],
);
$submission3id = $generator->create_submission(
$activity->id,
$student3->id,
['title' => 'My custom title', 'grade' => null],
);
$submission4id = $generator->create_submission(
$activity->id,
$student4->id,
['title' => 'My custom title', 'grade' => null],
);
// Assess one submission.
$generator->create_assessment(
$submission1id,
$student1->id,
['weight' => 3, 'grade' => 95.00000],
);
$generator->create_assessment(
$submission2id,
$student2->id,
['weight' => 3, 'grade' => null],
);
$generator->create_assessment(
$submission3id,
$student3->id,
['weight' => 3, 'grade' => null],
);
$generator->create_assessment(
$submission4id,
$student4->id,
['weight' => 3, 'grade' => 35.00000],
);
$manager = new workshop($activity, $cm, $course, $cm->context);
$this->assertEquals(4, $manager->count_submissions());
$this->assertEquals(4, $manager->count_submissions('all'));
$this->assertEquals(1, $manager->count_submissions($student1->id));
$this->assertEquals(1, $manager->count_submissions($student2->id));
$this->assertEquals(2, $manager->count_submissions('all', $group1->id));
$this->assertEquals(1, $manager->count_submissions('all', $group2->id));
$this->assertEquals(1, $manager->count_submissions($student1->id, $group1->id));
$this->assertEquals(0, $manager->count_submissions($student2->id, $group1->id));
$this->assertEquals(4, $manager->count_assessments());
$this->assertEquals(2, $manager->count_assessments(true));
$this->assertEquals(2, $manager->count_assessments(false, $group1->id));
$this->assertEquals(1, $manager->count_assessments(true, $group1->id));
$this->assertEquals(1, $manager->count_assessments(false, $group2->id));
$this->assertEquals(0, $manager->count_assessments(true, $group2->id));
}
}