Merge branch 'MDL-68163-master' of https://github.com/syxton/moodle

This commit is contained in:
Jake Dallimore
2020-06-03 12:06:06 +08:00
7 changed files with 219 additions and 0 deletions
+11
View File
@@ -86,6 +86,17 @@ if ($action == 'moveselect') {
$grade_edit_tree = new grade_edit_tree($gtree, $movingeid, $gpr);
switch ($action) {
case 'duplicate':
if ($eid and confirm_sesskey()) {
if (!$el = $gtree->locate_element($eid)) {
print_error('invalidelementid', '', $returnurl);
}
$object->duplicate();
redirect($returnurl);
}
break;
case 'delete':
if ($eid && confirm_sesskey()) {
if (!$grade_edit_tree->element_deletable($element)) {
+30
View File
@@ -149,6 +149,18 @@ class grade_edit_tree {
$actionsmenu->add($icon);
}
if ($this->element_duplicatable($element)) {
$duplicateparams = array();
$duplicateparams['id'] = $COURSE->id;
$duplicateparams['action'] = 'duplicate';
$duplicateparams['eid'] = $eid;
$duplicateparams['sesskey'] = sesskey();
$aurl = new moodle_url('index.php', $duplicateparams);
$duplicateicon = new pix_icon('t/copy', get_string('duplicate'));
$icon = new action_menu_link_secondary($aurl, $duplicateicon, get_string('duplicate'));
$actionsmenu->add($icon);
}
$aurl = new moodle_url('index.php', array('id' => $COURSE->id, 'action' => 'moveselect', 'eid' => $eid, 'sesskey' => sesskey()));
$moveaction .= $OUTPUT->action_icon($aurl, new pix_icon('t/move', get_string('move')));
}
@@ -460,6 +472,24 @@ class grade_edit_tree {
return false;
}
/**
* Given an element of the grade tree, returns whether it is duplicatable or not (only manual grade items are duplicatable)
*
* @param array $element
* @return bool
*/
public function element_duplicatable($element) {
if ($element['type'] != 'item') {
return false;
}
$gradeitem = $element['object'];
if ($gradeitem->itemtype != 'mod') {
return true;
}
return false;
}
/**
* Given the grade tree and an array of element ids (e.g. c15, i42), and expecting the 'moveafter' URL param,
* moves the selected items to the requested location. Then redirects the user to the given $returnurl
+23
View File
@@ -117,6 +117,29 @@ class behat_grade extends behat_base {
"//tr[descendant::*[text() = " . $this->escape($gradeitem) . "]]", 'xpath_element'));
}
/**
* Duplicates a grade item or category.
*
* Teacher must be on the grade setup page.
*
* @Given /^I duplicate the grade item "(?P<grade_item_string>(?:[^"]|\\")*)"$/
* @param string $gradeitem
*/
public function i_duplicate_the_grade_item($gradeitem) {
$gradeitem = behat_context_helper::escape($gradeitem);
if ($this->running_javascript()) {
$xpath = "//tr[contains(.,$gradeitem)]//*[contains(@class,'moodle-actionmenu')]//a[contains(@class,'toggle-display')]";
if ($this->getSession()->getPage()->findAll('xpath', $xpath)) {
$this->execute("behat_general::i_click_on", array($this->escape($xpath), "xpath_element"));
}
}
$this->execute("behat_general::i_click_on_in_the", array(get_string('duplicate'), 'link',
"//tr[descendant::*[text() = " . $this->escape($gradeitem) . "]]", 'xpath_element'));
}
/**
* Sets a calculated manual grade item. Needs a table with item name - idnumber relation.
* The step requires you to be in the 'Gradebook setup' page.
@@ -0,0 +1,45 @@
@core @core_grades
Feature: We can duplicate grade items that already exist.
In order to quickly create grade items that have similar settings.
As a teacher
I need to duplicate an existing grade item and check that its values are properly duplicated.
Background:
Given the following "courses" exist:
| fullname | shortname | format |
| Course 1 | C1 | topics |
And the following "grade categories" exist:
| fullname | course |
| Category1 | C1 |
And the following "activities" exist:
| activity | course | idnumber | name | gradecategory |
| assign | C1 | a1 | Assignment1 | Category1 |
And the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
And the following "grade items" exist:
| itemname | course | category | idnumber | gradetype | grademax | grademin | gradepass | display | decimals | hidden | weightoverride |
| Item1 | C1 | Category1 | 001 | Value | 80.00 | 5.00 | 40.00 | 1 | 1 | 0 | 1 |
Scenario: Ensure the duplicated grade item settings match the original grade item
Given I log in as "teacher1"
And I am on "Course 1" course homepage
And I navigate to "Setup > Gradebook setup" in the course gradebook
And I should not see "Duplicate Category1"
And I should not see "Duplicate Assignment1"
When I duplicate the grade item "Item1"
Then I should see "Item1 (copy)"
And I follow "Edit Item1 (copy)"
And the field "Item name" matches value "Item1 (copy)"
And the field "ID number" matches value ""
And the field "Grade type" matches value "Value"
And the field "Maximum grade" matches value "80.00"
And the field "Minimum grade" matches value "5.00"
And the field "Grade to pass" matches value "40.00"
And the field "Grade display type" matches value "Real"
And the field "Overall decimal places" matches value "1"
And the field "Hidden" matches value "0"
And the field "Weight adjusted" matches value "1"
+1
View File
@@ -163,6 +163,7 @@ $string['dropped'] = 'Dropped';
$string['droplowestvalues'] = 'Drop {$a} lowest values';
$string['dropxlowest'] = 'Drop X lowest';
$string['dropxlowestwarning'] = 'Note: If you use drop x lowest the grading assumes that all items in the category have the same point value. If point values differ results will be unpredictable';
$string['duplicatedgradeitem'] = '{$a} (copy)';
$string['duplicatescale'] = 'Duplicate scale';
$string['edit'] = 'Edit';
$string['editcalculation'] = 'Edit calculation';
+35
View File
@@ -449,6 +449,41 @@ class grade_item extends grade_object {
return true;
}
/**
* Duplicate grade item.
*
* @return grade_item The duplicate grade item
*/
public function duplicate() {
// Convert current object to array.
$copy = (array) $this;
if (empty($copy["id"])) {
throw new moodle_exception('invalidgradeitemid');
}
// Remove fields that will be either unique or automatically filled.
$removekeys = array();
$removekeys[] = 'id';
$removekeys[] = 'idnumber';
$removekeys[] = 'timecreated';
$removekeys[] = 'sortorder';
foreach ($removekeys as $key) {
unset($copy[$key]);
}
// Addendum to name.
$copy["itemname"] = get_string('duplicatedgradeitem', 'grades', $copy["itemname"]);
// Create new grade item.
$gradeitem = new grade_item($copy);
// Insert grade item into database.
$gradeitem->insert();
return $gradeitem;
}
/**
* In addition to perform parent::insert(), calls force_regrading() method too.
*
+74
View File
@@ -1050,4 +1050,78 @@ class core_grade_item_testcase extends grade_base_testcase {
$this->assertEquals($gradeitem->itemmodule, $event->other['itemmodule']);
$this->assertEquals('updatedname', $event->other['itemname']);
}
/**
* Test grade item duplication expecting success.
*/
public function test_grade_duplicate_grade_item_success() {
$cat = new grade_category();
$cat->courseid = $this->courseid;
$cat->fullname = 'Grade category';
$cat->insert();
// Method exists.
$gi = new grade_item();
$this->assertTrue(method_exists($gi, 'duplicate'));
// Grade item is inserted and valid for duplication.
$gi->courseid = $this->courseid;
$gi->categoryid = $cat->id;
$gi->itemtype = 'manual';
$gi->itemname = 'Grade Item 1';
$gi->idnumber = '1000';
$gi->insert();
$gi2 = $gi->duplicate();
$this->assertEquals($gi->courseid, $gi2->courseid);
$this->assertEquals($gi->categoryid, $gi2->categoryid);
$this->assertEquals($gi->itemtype, $gi2->itemtype);
$this->assertEquals($gi->gradetype, $gi2->gradetype);
$this->assertEquals($gi->grademax, $gi2->grademax);
$this->assertEquals($gi->grademin, $gi2->grademin);
$this->assertEquals($gi->gradepass, $gi2->gradepass);
$this->assertEquals($gi->display, $gi2->display);
$this->assertEquals($gi->decimals, $gi2->decimals);
$this->assertEquals($gi->hidden, $gi2->hidden);
$this->assertEquals($gi->weightoverride, $gi2->weightoverride);
$this->assertNotEquals($gi->id, $gi2->id);
$this->assertNotEquals($gi->idnumber, $gi2->idnumber);
$this->assertNotEquals($gi->sortorder, $gi2->sortorder);
$this->assertNotEquals($gi->itemname, $gi2->itemname);
}
/**
* Test grade item duplication exception expected with incomplete grade item.
*/
public function test_grade_duplicate_grade_item_incomplete() {
// Grade item is not valid because it is empty.
$gi = new grade_item();
$gi->courseid = $this->courseid;
$this->expectException("moodle_exception");
$gi2 = $gi->duplicate();
}
/**
* Test grade item duplication exception expected because item must be in db.
*/
public function test_grade_duplicate_grade_item_not_in_db() {
$cat = new grade_category();
$cat->courseid = $this->courseid;
$cat->fullname = 'Grade category';
$cat->insert();
// Grade item is valid for insertion but is not inserted into db.
// Duplicate method throws an exception.
$gi = new grade_item();
$gi->courseid = $this->courseid;
$gi->categoryid = $cat->id;
$gi->itemtype = 'manual';
$gi->itemname = 'Grade Item 1';
$gi->idnumber = '1000';
$this->expectException("moodle_exception");
$gi2 = $gi->duplicate();
}
}