Merge branch 'MDL-64702-master' of git://github.com/damyon/moodle

This commit is contained in:
Sara Arjona 2019-04-29 08:34:21 +02:00
commit bef6805656
5 changed files with 358 additions and 4 deletions

View File

@ -806,12 +806,25 @@ class backup_badges_structure_step extends backup_structure_step {
$badge = new backup_nested_element('badge', array('id'), array('name', 'description',
'timecreated', 'timemodified', 'usercreated', 'usermodified', 'issuername',
'issuerurl', 'issuercontact', 'expiredate', 'expireperiod', 'type', 'courseid',
'message', 'messagesubject', 'attachment', 'notification', 'status', 'nextcron'));
'message', 'messagesubject', 'attachment', 'notification', 'status', 'nextcron',
'version', 'language', 'imageauthorname', 'imageauthoremail', 'imageauthorurl',
'imagecaption'));
$criteria = new backup_nested_element('criteria');
$criterion = new backup_nested_element('criterion', array('id'), array('badgeid',
'criteriatype', 'method', 'description', 'descriptionformat'));
$endorsement = new backup_nested_element('endorsement', array('id'), array('badgeid',
'issuername', 'issuerurl', 'issueremail', 'claimid', 'claimcomment', 'dateissued'));
$alignments = new backup_nested_element('alignments');
$alignment = new backup_nested_element('alignment', array('id'), array('badgeid',
'targetname', 'targeturl', 'targetdescription', 'targetframework', 'targetcode'));
$relatedbadges = new backup_nested_element('relatedbadges');
$relatedbadge = new backup_nested_element('relatedbadge', array('id'), array('badgeid',
'relatedbadgeid'));
$parameters = new backup_nested_element('parameters');
$parameter = new backup_nested_element('parameter', array('id'), array('critid',
'name', 'value', 'criteriatype'));
@ -827,6 +840,11 @@ class backup_badges_structure_step extends backup_structure_step {
$criteria->add_child($criterion);
$criterion->add_child($parameters);
$parameters->add_child($parameter);
$badge->add_child($endorsement);
$badge->add_child($alignments);
$alignments->add_child($alignment);
$badge->add_child($relatedbadges);
$relatedbadges->add_child($relatedbadge);
$badge->add_child($manual_awards);
$manual_awards->add_child($manual_award);
@ -834,6 +852,10 @@ class backup_badges_structure_step extends backup_structure_step {
$badge->set_source_table('badge', array('courseid' => backup::VAR_COURSEID));
$criterion->set_source_table('badge_criteria', array('badgeid' => backup::VAR_PARENTID));
$endorsement->set_source_table('badge_endorsement', array('badgeid' => backup::VAR_PARENTID));
$alignment->set_source_table('badge_alignment', array('badgeid' => backup::VAR_PARENTID));
$relatedbadge->set_source_table('badge_related', array('badgeid' => backup::VAR_PARENTID));
$parametersql = 'SELECT cp.*, c.criteriatype
FROM {badge_criteria_param} cp JOIN {badge_criteria} c
@ -850,6 +872,10 @@ class backup_badges_structure_step extends backup_structure_step {
$badge->annotate_ids('user', 'usermodified');
$criterion->annotate_ids('badge', 'badgeid');
$parameter->annotate_ids('criterion', 'critid');
$endorsement->annotate_ids('badge', 'badgeid');
$alignment->annotate_ids('badge', 'badgeid');
$relatedbadge->annotate_ids('badge', 'badgeid');
$relatedbadge->annotate_ids('badge', 'relatedbadgeid');
$badge->annotate_files('badges', 'badgeimage', 'id');
$manual_award->annotate_ids('badge', 'badgeid');
$manual_award->annotate_ids('user', 'recipientid');

View File

@ -2517,6 +2517,9 @@ class restore_badges_structure_step extends restore_structure_step {
$paths[] = new restore_path_element('badge', '/badges/badge');
$paths[] = new restore_path_element('criterion', '/badges/badge/criteria/criterion');
$paths[] = new restore_path_element('parameter', '/badges/badge/criteria/criterion/parameters/parameter');
$paths[] = new restore_path_element('endorsement', '/badges/badge/endorsement');
$paths[] = new restore_path_element('alignment', '/badges/badge/alignments/alignment');
$paths[] = new restore_path_element('relatedbadge', '/badges/badge/relatedbadges/relatedbadge');
$paths[] = new restore_path_element('manual_award', '/badges/badge/manual_awards/manual_award');
return $paths;
@ -2561,13 +2564,87 @@ class restore_badges_structure_step extends restore_structure_step {
'attachment' => $data->attachment,
'notification' => $data->notification,
'status' => BADGE_STATUS_INACTIVE,
'nextcron' => $data->nextcron
'nextcron' => $data->nextcron,
'version' => $data->version,
'language' => $data->language,
'imageauthorname' => $data->imageauthorname,
'imageauthoremail' => $data->imageauthoremail,
'imageauthorurl' => $data->imageauthorurl,
'imagecaption' => $data->imagecaption
);
$newid = $DB->insert_record('badge', $params);
$this->set_mapping('badge', $data->id, $newid, $restorefiles);
}
/**
* Create an endorsement for a badge.
*
* @param mixed $data
* @return void
*/
public function process_endorsement($data) {
global $DB;
$data = (object)$data;
$params = [
'badgeid' => $this->get_new_parentid('badge'),
'issuername' => $data->issuername,
'issuerurl' => $data->issuerurl,
'issueremail' => $data->issueremail,
'claimid' => $data->claimid,
'claimcomment' => $data->claimcomment,
'dateissued' => $this->apply_date_offset($data->dateissued)
];
$newid = $DB->insert_record('badge_endorsement', $params);
$this->set_mapping('endorsement', $data->id, $newid);
}
/**
* Link to related badges for a badge. This relies on post processing in after_execute().
*
* @param mixed $data
* @return void
*/
public function process_relatedbadge($data) {
global $DB;
$data = (object)$data;
$relatedbadgeid = $data->relatedbadgeid;
if ($relatedbadgeid) {
// Only backup and restore related badges if they are contained in the backup file.
$params = array(
'badgeid' => $this->get_new_parentid('badge'),
'relatedbadgeid' => $relatedbadgeid
);
$newid = $DB->insert_record('badge_related', $params);
}
}
/**
* Link to an alignment for a badge.
*
* @param mixed $data
* @return void
*/
public function process_alignment($data) {
global $DB;
$data = (object)$data;
$params = array(
'badgeid' => $this->get_new_parentid('badge'),
'targetname' => $data->targetname,
'targeturl' => $data->targeturl,
'targetdescription' => $data->targetdescription,
'targetframework' => $data->targetframework,
'targetcode' => $data->targetcode
);
$newid = $DB->insert_record('badge_alignment', $params);
$this->set_mapping('alignment', $data->id, $newid);
}
public function process_criterion($data) {
global $DB;
@ -2580,6 +2657,7 @@ class restore_badges_structure_step extends restore_structure_step {
'description' => isset($data->description) ? $data->description : '',
'descriptionformat' => isset($data->descriptionformat) ? $data->descriptionformat : 0,
);
$newid = $DB->insert_record('badge_criteria', $params);
$this->set_mapping('criterion', $data->id, $newid);
}
@ -2613,6 +2691,14 @@ class restore_badges_structure_step extends restore_structure_step {
} else {
return;
}
} else if ($data->criteriatype == BADGE_CRITERIA_TYPE_COMPETENCY) {
$competencyid = $this->get_mappingid('competency', $data->value);
if (!empty($competencyid)) {
$params['name'] = 'competency_' . $competencyid;
$params['value'] = $competencyid;
} else {
return;
}
}
if (!$DB->record_exists('badge_criteria_param', $params)) {
@ -2645,8 +2731,38 @@ class restore_badges_structure_step extends restore_structure_step {
}
protected function after_execute() {
global $DB;
// Add related files.
$this->add_related_files('badges', 'badgeimage', 'badge');
$badgeid = $this->get_new_parentid('badge');
// Remap any related badges.
// We do this in the DB directly because this is backup/restore it is not valid to call into
// the component API.
$params = array('badgeid' => $badgeid);
$query = "SELECT DISTINCT br.id, br.badgeid, br.relatedbadgeid
FROM {badge_related} br
WHERE (br.badgeid = :badgeid)";
$relatedbadges = $DB->get_records_sql($query, $params);
$newrelatedids = [];
foreach ($relatedbadges as $relatedbadge) {
$relatedid = $this->get_mappingid('badge', $relatedbadge->relatedbadgeid);
$params['relatedbadgeid'] = $relatedbadge->relatedbadgeid;
$DB->delete_records_select('badge_related', '(badgeid = :badgeid AND relatedbadgeid = :relatedbadgeid)', $params);
if ($relatedid) {
$newrelatedids[] = $relatedid;
}
}
if (!empty($newrelatedids)) {
$relatedbadges = [];
foreach ($newrelatedids as $relatedid) {
$relatedbadge = new stdClass();
$relatedbadge->badgeid = $badgeid;
$relatedbadge->relatedbadgeid = $relatedid;
$relatedbadges[] = $relatedbadge;
}
$DB->insert_records('badge_related', $relatedbadges);
}
}
}

View File

@ -377,18 +377,40 @@ class provider implements
// Export the badges.
$uniqueid = $DB->sql_concat_join("'-'", ['b.id', 'COALESCE(bc.id, 0)', 'COALESCE(bi.id, 0)',
'COALESCE(bma.id, 0)', 'COALESCE(bcm.id, 0)']);
'COALESCE(bma.id, 0)', 'COALESCE(bcm.id, 0)', 'COALESCE(brb.id, 0)', 'COALESCE(ba.id, 0)']);
$sql = "
SELECT $uniqueid AS uniqueid, b.id,
bi.id AS biid, bi.dateissued, bi.dateexpire, bi.uniquehash,
bma.id AS bmaid, bma.datemet, bma.issuerid,
bcm.id AS bcmid,
c.fullname AS coursename,
be.id AS beid,
be.issuername AS beissuername,
be.issuerurl AS beissuerurl,
be.issueremail AS beissueremail,
be.claimid AS beclaimid,
be.claimcomment AS beclaimcomment,
be.dateissued AS bedateissued,
brb.id as rbid,
brb.badgeid as rbbadgeid,
brb.relatedbadgeid as rbrelatedbadgeid,
ba.id as baid,
ba.targetname as batargetname,
ba.targeturl as batargeturl,
ba.targetdescription as batargetdescription,
ba.targetframework as batargetframework,
ba.targetcode as batargetcode,
$ctxfields
FROM {badge} b
LEFT JOIN {badge_issued} bi
ON bi.badgeid = b.id
AND bi.userid = :userid1
LEFT JOIN {badge_related} brb
ON ( b.id = brb.badgeid OR b.id = brb.relatedbadgeid )
LEFT JOIN {badge_alignment} ba
ON ( b.id = ba.badgeid )
LEFT JOIN {badge_endorsement} be
ON be.badgeid = b.id
LEFT JOIN {badge_manual_award} bma
ON bma.badgeid = b.id
AND bma.recipientid = :userid2
@ -422,9 +444,16 @@ class provider implements
if ($carry === null) {
$carry = [
'name' => $badge->name,
'version' => $badge->version,
'language' => $badge->language,
'imageauthorname' => $badge->imageauthorname,
'imageauthoremail' => $badge->imageauthoremail,
'imageauthorurl' => $badge->imageauthorurl,
'imagecaption' => $badge->imagecaption,
'issued' => null,
'manual_award' => null,
'criteria_met' => []
'criteria_met' => [],
'endorsement' => null,
];
if ($badge->type == BADGE_TYPE_COURSE) {
@ -432,6 +461,17 @@ class provider implements
$carry['course'] = format_string($record->coursename, true, ['context' => $badge->get_context()]);
}
if (!empty($record->beid)) {
$carry['endorsement'] = [
'issuername' => $record->beissuername,
'issuerurl' => $record->beissuerurl,
'issueremail' => $record->beissueremail,
'claimid' => $record->beclaimid,
'claimcomment' => $record->beclaimcomment,
'dateissued' => $record->bedateissued ? transform::datetime($record->bedateissued) : null
];
}
if (!empty($record->biid)) {
$carry['issued'] = [
'issued_on' => transform::datetime($record->dateissued),
@ -447,6 +487,52 @@ class provider implements
];
}
}
if (!empty($record->rbid)) {
if (empty($carry['related_badge'])) {
$carry['related_badge'] = [];
}
$rbid = $record->rbbadgeid;
if ($rbid == $record->id) {
$rbid = $record->rbrelatedbadgeid;
}
$exists = false;
foreach ($carry['related_badge'] as $related) {
if ($related['badgeid'] == $rbid) {
$exists = true;
break;
}
}
if (!$exists) {
$relatedbadge = new badge($rbid);
$carry['related_badge'][] = [
'badgeid' => $rbid,
'badgename' => $relatedbadge->name
];
}
}
if (!empty($record->baid)) {
if (empty($carry['alignment'])) {
$carry['alignment'] = [];
}
$exists = false;
$newalignment = [
'targetname' => $record->batargetname,
'targeturl' => $record->batargeturl,
'targetdescription' => $record->batargetdescription,
'targetframework' => $record->batargetframework,
'targetcode' => $record->batargetcode,
];
foreach ($carry['alignment'] as $alignment) {
if ($alignment == $newalignment) {
$exists = true;
break;
}
}
if (!$exists) {
$carry['alignment'][] = $newalignment;
}
}
// Export the details of the criteria met.
// We only do that once, when we find that a least one criteria was met.

View File

@ -306,7 +306,11 @@ class core_badges_privacy_testcase extends provider_testcase {
$u2ctx = context_user::instance($u2->id);
$b1 = $this->create_badge(['usercreated' => $u3->id]);
$this->endorse_badge(['badgeid' => $b1->id]);
$this->align_badge(['badgeid' => $b1->id], ' (1)');
$this->align_badge(['badgeid' => $b1->id], ' (2)');
$b2 = $this->create_badge(['type' => BADGE_TYPE_COURSE, 'courseid' => $c1->id, 'usermodified' => $u3->id]);
$this->relate_badge($b1->id, $b2->id);
$b3 = $this->create_badge();
$b3crit = $this->create_criteria_manual($b3->id);
$b4 = $this->create_badge();
@ -333,6 +337,12 @@ class core_badges_privacy_testcase extends provider_testcase {
$path = [get_string('badges', 'core_badges'), "{$b1->name} ({$b1->id})"];
$data = writer::with_context($u1ctx)->get_data($path);
$this->assertEquals($b1->name, $data->name);
$this->assertEquals($b1->version, $data->version);
$this->assertEquals($b1->language, $data->language);
$this->assertEquals($b1->imageauthorname, $data->imageauthorname);
$this->assertEquals($b1->imageauthoremail, $data->imageauthoremail);
$this->assertEquals($b1->imageauthorurl, $data->imageauthorurl);
$this->assertEquals($b1->imagecaption, $data->imagecaption);
$this->assertNotEmpty($data->issued);
$this->assertEmpty($data->manual_award);
$this->assertEmpty($data->criteria_met);
@ -340,6 +350,33 @@ class core_badges_privacy_testcase extends provider_testcase {
$this->assertEquals('yoohoo', $data->issued['unique_hash']);
$this->assertNull($data->issued['expires_on']);
$this->assertNotEmpty($data->endorsement);
$this->assertNotEmpty($data->endorsement['issuername']);
$this->assertNotEmpty($data->endorsement['issuerurl']);
$this->assertNotEmpty($data->endorsement['issueremail']);
$this->assertNotEmpty($data->endorsement['claimid']);
$this->assertNotEmpty($data->endorsement['claimcomment']);
$this->assertNotEmpty($data->endorsement['dateissued']);
$this->assertNotEmpty($data->related_badge);
$this->assertNotEmpty($data->related_badge[0]);
$this->assertEquals($data->related_badge[0]['badgeid'], $b2->id);
$this->assertEquals($data->related_badge[0]['badgename'], $b2->name);
$this->assertNotEmpty($data->alignment);
$this->assertNotEmpty($data->alignment[0]);
$this->assertNotEmpty($data->alignment[0]['targetname']);
$this->assertNotEmpty($data->alignment[0]['targeturl']);
$this->assertNotEmpty($data->alignment[0]['targetdescription']);
$this->assertNotEmpty($data->alignment[0]['targetframework']);
$this->assertNotEmpty($data->alignment[0]['targetcode']);
$this->assertNotEmpty($data->alignment[1]);
$this->assertNotEmpty($data->alignment[1]['targetname']);
$this->assertNotEmpty($data->alignment[1]['targeturl']);
$this->assertNotEmpty($data->alignment[1]['targetdescription']);
$this->assertNotEmpty($data->alignment[1]['targetframework']);
$this->assertNotEmpty($data->alignment[1]['targetcode']);
$path = [get_string('badges', 'core_badges'), "{$b2->name} ({$b2->id})"];
$data = writer::with_context($u1ctx)->get_data($path);
$this->assertEquals($b2->name, $data->name);
@ -598,12 +635,79 @@ class core_badges_privacy_testcase extends provider_testcase {
'attachment' => 1,
'notification' => 0,
'status' => BADGE_STATUS_ACTIVE,
'version' => OPEN_BADGES_V2,
'language' => 'en',
'imageauthorname' => 'Image author',
'imageauthoremail' => 'author@example.com',
'imageauthorurl' => 'http://image.example.com/',
'imagecaption' => 'Image caption'
], $params);
$record->id = $DB->insert_record('badge', $record);
return $record;
}
/**
* Relate a badge.
*
* @param int $badgeid The badge ID.
* @param int $relatedbadgeid The related badge ID.
* @return object
*/
protected function relate_badge(int $badgeid, int $relatedbadgeid) {
global $DB;
$record = (object) [
'badgeid' => $badgeid,
'relatedbadgeid' => $relatedbadgeid
];
$record->id = $DB->insert_record('badge_related', $record);
return $record;
}
/**
* Align a badge.
*
* @param array $params Parameters.
* @return object
*/
protected function align_badge(array $params = [], $suffix = '') {
global $DB;
$record = (object) array_merge([
'badgeid' => null,
'targetname' => "Alignment name" . $suffix,
'targeturl' => "http://issuer-url.domain.co.nz",
'targetdescription' => "Description" . $suffix,
'targetframework' => "Framework" . $suffix,
'targetcode' => "Code . $suffix"
], $params);
$record->id = $DB->insert_record('badge_alignment', $record);
return $record;
}
/**
* Endorse a badge.
*
* @param array $params Parameters.
* @return object
*/
protected function endorse_badge(array $params = []) {
global $DB;
$record = (object) array_merge([
'badgeid' => null,
'issuername' => "External issuer name",
'issuerurl' => "http://issuer-url.domain.co.nz",
'issueremail' => "issuer@example.com",
'claimid' => "Claim ID",
'claimcomment' => "Claim comment",
'dateissued' => time()
], $params);
$record->id = $DB->insert_record('badge_endorsement', $record);
return $record;
}
/**
* Create a backpack.
*

View File

@ -324,6 +324,28 @@ class badge {
$crit->make_clone($new);
}
// Copy endorsement.
$endorsement = $this->get_endorsement();
if ($endorsement) {
unset($endorsement->id);
$endorsement->badgeid = $new;
$newbadge->save_endorsement($endorsement);
}
// Copy alignments.
$alignments = $this->get_alignments();
foreach ($alignments as $alignment) {
unset($alignment->id);
$alignment->badgeid = $new;
$newbadge->save_alignment($alignment);
}
// Copy related badges.
$related = $this->get_related_badges(true);
if (!empty($related)) {
$newbadge->add_related_badges(array_keys($related));
}
// Trigger event, badge duplicated.
$eventparams = array('objectid' => $new, 'context' => $PAGE->context);
$event = \core\event\badge_duplicated::create($eventparams);