Skip to content

Commit 435e98d

Browse files
committed
MDL-83905 core_badges: Merge backpack-add and backpack-export
1 parent 23ed2c1 commit 435e98d

File tree

9 files changed

+229
-135
lines changed

9 files changed

+229
-135
lines changed

badges/backpack-add.php

+25-119
Original file line numberDiff line numberDiff line change
@@ -25,134 +25,40 @@
2525
require_once(__DIR__ . '/../config.php');
2626
require_once($CFG->libdir . '/badgeslib.php');
2727

28+
use core_badges\backpack;
2829
use core_badges\local\backpack\ob\api_base;
2930

3031
require_login();
3132

32-
$userbackpack = badges_get_user_backpack();
33-
if (badges_open_badges_backpack_api($userbackpack->id) != OPEN_BADGES_V2) {
34-
throw new coding_exception('No backpacks support Open Badges V2.');
33+
// Check if badges and the external backpack are enabled.
34+
if (empty($CFG->badges_allowexternalbackpack) || empty($CFG->enablebadges)) {
35+
redirect($CFG->wwwroot);
3536
}
3637

37-
$id = required_param('hash', PARAM_ALPHANUM);
38-
39-
$PAGE->set_url('/badges/backpack-add.php', array('hash' => $id));
40-
$PAGE->set_context(context_system::instance());
41-
$output = $PAGE->get_renderer('core', 'badges');
42-
43-
$issuedbadge = new \core_badges\output\issued_badge($id);
44-
if (!empty($issuedbadge->recipient->id)) {
45-
// The flow for issuing a badge is:
46-
// * Create issuer
47-
// * Create badge
48-
// * Create assertion (Award the badge!)
49-
50-
// With the introduction OBv2.1 and MDL-65959 to allow cross region Badgr imports the above (old) procedure will
51-
// only be completely performed if both the site and user backpacks conform to the same apiversion.
52-
// Else we will attempt at pushing the assertion to the user's backpack. In this case, the id set against the assertion
53-
// has to be a publicly accessible resource.
54-
55-
// Get the backpack.
56-
$badgeid = $issuedbadge->badgeid;
57-
$badge = new badge($badgeid);
58-
$backpack = $DB->get_record('badge_backpack', array('userid' => $USER->id));
59-
$userbackpack = badges_get_site_backpack($backpack->externalbackpackid, $USER->id);
60-
$assertion = new core_badges_assertion($id, OPEN_BADGES_V2);
61-
$assertiondata = $assertion->get_badge_assertion(false, false);
62-
$assertionid = $assertion->get_assertion_hash();
63-
$assertionentityid = $assertiondata['id'];
64-
$badgeadded = false;
65-
if (badges_open_badges_backpack_api() == OPEN_BADGES_V2) {
66-
$sitebackpack = badges_get_site_primary_backpack();
67-
$api = api_base::create_from_externalbackpack($userbackpack);
68-
$response = $api->authenticate();
69-
70-
// A numeric response indicates a valid successful authentication. Else an error object will be returned.
71-
if (is_numeric($response)) {
72-
// Create issuer.
73-
$issuer = $assertion->get_issuer();
74-
if (!($issuerentityid = badges_external_get_mapping($sitebackpack->id, OPEN_BADGES_V2_TYPE_ISSUER, $issuer['email']))) {
75-
$response = $api->put_issuer($issuer);
76-
if (!$response) {
77-
throw new moodle_exception('invalidrequest', 'error');
78-
}
79-
$issuerentityid = $response->id;
80-
badges_external_create_mapping($sitebackpack->id, OPEN_BADGES_V2_TYPE_ISSUER, $issuer['email'],
81-
$issuerentityid);
82-
}
83-
// Create badge.
84-
$badge = $assertion->get_badge_class(false);
85-
$badgeid = $assertion->get_badge_id();
86-
if (!($badgeentityid = badges_external_get_mapping($sitebackpack->id, OPEN_BADGES_V2_TYPE_BADGE, $badgeid))) {
87-
$response = $api->put_badgeclass($issuerentityid, $badge);
88-
if (!$response) {
89-
throw new moodle_exception('invalidrequest', 'error');
90-
}
91-
$badgeentityid = $response->id;
92-
badges_external_create_mapping($sitebackpack->id, OPEN_BADGES_V2_TYPE_BADGE, $badgeid,
93-
$badgeentityid);
94-
}
38+
// Check the user has a backpack.
39+
$backpack = backpack::get_user_backpack();
40+
if (empty($backpack)) {
41+
throw new coding_exception('This user has no backpack associated with their account.');
42+
}
9543

96-
// Create assertion (Award the badge!).
97-
$assertionentityid = badges_external_get_mapping(
98-
$sitebackpack->id,
99-
OPEN_BADGES_V2_TYPE_ASSERTION,
100-
$assertionid
101-
);
44+
$hash = required_param('hash', PARAM_ALPHANUM);
10245

103-
if ($assertionentityid && strpos($sitebackpack->backpackapiurl, 'badgr')) {
104-
$assertionentityid = badges_generate_badgr_open_url(
105-
$sitebackpack,
106-
OPEN_BADGES_V2_TYPE_ASSERTION,
107-
$assertionentityid
108-
);
109-
}
46+
$PAGE->set_url('/badges/backpack-add.php', ['hash' => $hash]);
47+
$PAGE->set_context(context_user::instance($USER->id));
48+
$output = $PAGE->get_renderer('core', 'badges');
11049

111-
// Create an assertion for the recipient in the issuer's account.
112-
if (!$assertionentityid) {
113-
$response = $api->put_badgeclass_assertion($badgeentityid, $assertiondata);
114-
if (!$response) {
115-
throw new moodle_exception('invalidrequest', 'error');
116-
}
117-
$assertionentityid = badges_generate_badgr_open_url($sitebackpack, OPEN_BADGES_V2_TYPE_ASSERTION, $response->id);
118-
$badgeadded = true;
119-
badges_external_create_mapping($sitebackpack->id, OPEN_BADGES_V2_TYPE_ASSERTION, $assertionid,
120-
$response->id);
121-
} else {
122-
// An assertion already exists. Make sure it's up to date.
123-
$internalid = badges_external_get_mapping(
124-
$sitebackpack->id,
125-
OPEN_BADGES_V2_TYPE_ASSERTION,
126-
$assertionid,
127-
'externalid'
128-
);
129-
$response = $api->update_assertion($internalid, $assertiondata);
130-
if (!$response) {
131-
throw new moodle_exception('invalidrequest', 'error');
132-
}
133-
}
134-
}
135-
}
50+
// Check the assertion belongs to the current user.
51+
$assertion = new core_badges_assertion($hash, $backpack->apiversion);
52+
if ($assertion->get_userid() != $USER->id) {
53+
throw new coding_exception('This assertion does not belong to the current user.');
54+
}
13655

137-
// Now award/upload the badge to the user's account.
138-
// - If a user and site backpack have the same provider we can skip this as Badgr automatically maps recipients
139-
// based on email address.
140-
// - This is only needed when the backpacks are from different regions.
141-
if ($assertionentityid && !badges_external_get_mapping($userbackpack->id, OPEN_BADGES_V2_TYPE_ASSERTION, $assertionid)) {
142-
$userapi = api_base::create_from_externalbackpack($userbackpack);
143-
$userapi->authenticate();
144-
$response = $userapi->import_badge_assertion($assertionentityid);
145-
if (!$response) {
146-
throw new moodle_exception('invalidrequest', 'error');
147-
}
148-
$assertionentityid = $response->id;
149-
$badgeadded = true;
150-
badges_external_create_mapping($userbackpack->id, OPEN_BADGES_V2_TYPE_ASSERTION, $assertionid,
151-
$assertionentityid);
152-
}
56+
// Send the assertion to the backpack.
57+
$api = api_base::create_from_externalbackpack($backpack);
58+
$notify = $api->put_assertions($hash);
15359

154-
$response = $badgeadded ? ['success' => 'addedtobackpack'] : ['warning' => 'existsinbackpack'];
155-
redirect(new moodle_url('/badges/mybadges.php', $response));
156-
} else {
157-
redirect(new moodle_url('/badges/mybadges.php'));
60+
$redirecturl = new moodle_url('/badges/mybadges.php');
61+
if (!empty($notify['status'])) {
62+
redirect($redirecturl, $notify['message'], null, $notify['status']);
15863
}
64+
redirect($redirecturl);

badges/backpack-export.php

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
/**
1818
* Export badges to the backpack site.
19+
* TODO: Deprecate or delete this file.
1920
*
2021
* @package core_badges
2122
* @copyright 2020 Tung Thai

badges/classes/assertion.php

+7-2
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ public function __construct($hash, $obversion = OPEN_BADGES_V2) {
6060
bi.dateexpire,
6161
bi.uniquehash,
6262
u.email,
63+
u.id as userid,
6364
b.*,
6465
bb.email as backpackemail
6566
FROM
@@ -119,7 +120,7 @@ public function get_badge_assertion($issued = true, $usesalt = true) {
119120
$this->_data->uniquehash,
120121
exporter_base::convert_apiversion(OPEN_BADGES_V2),
121122
);
122-
return $assertionexporter->export();
123+
return $assertionexporter->export($issued, $usesalt);
123124
}
124125

125126
/**
@@ -135,7 +136,7 @@ public function get_badge_class($issued = true) {
135136
$this->get_badge_id(),
136137
exporter_base::convert_apiversion(OPEN_BADGES_V2),
137138
);
138-
return $badgeexporter->export();
139+
return $badgeexporter->export($issued);
139140
}
140141

141142
/**
@@ -295,4 +296,8 @@ protected function embed_data_badge_version2(&$json, $type = OPEN_BADGES_V2_TYPE
295296
public function get_tags(): array {
296297
return array_values(\core_tag_tag::get_item_tags_array('core_badges', 'badge', $this->get_badge_id()));
297298
}
299+
300+
public function get_userid(): int {
301+
return $this->_data->userid;
302+
}
298303
}

badges/classes/backpack.php

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
// This file is part of Moodle - http://moodle.org/
3+
//
4+
// Moodle is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// Moodle is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU General Public License
15+
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
16+
17+
namespace core_badges;
18+
19+
/**
20+
* Class that represents a backpack.
21+
* TODO: Review/improve this class because it's not clear how to create backpacks (id's, hash...) and what represents.
22+
*
23+
* @package core_badges
24+
* @copyright 2025 Sara Arjona <sara@moodle.com>
25+
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26+
*/
27+
class backpack {
28+
29+
/**
30+
* Constructs with badge details.
31+
*
32+
* @param int $badgeid badge ID.
33+
*/
34+
public function __construct(string $hash) {
35+
}
36+
37+
38+
/**
39+
* Get the user backpack for the currently logged in user OR the provided user
40+
*
41+
* @param int|null $userid The user whose backpack you're requesting for. If null, get the logged in user's backpack
42+
* @return mixed The user's backpack or none.
43+
*/
44+
public static function get_user_backpack(?int $userid = 0) {
45+
global $DB;
46+
47+
if (!$userid) {
48+
global $USER;
49+
$userid = $USER->id;
50+
}
51+
52+
$sql = "SELECT beb.*, bb.id AS badgebackpack, bb.password, bb.email AS backpackemail
53+
FROM {badge_external_backpack} beb
54+
JOIN {badge_backpack} bb ON bb.externalbackpackid = beb.id AND bb.userid=:userid";
55+
56+
return $DB->get_record_sql($sql, ['userid' => $userid]);
57+
}
58+
59+
}

badges/classes/local/backpack/ob/api_base.php

+8
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,14 @@ abstract protected function get_mappings(): array;
8686
*/
8787
abstract public function disconnect_backpack(): bool;
8888

89+
/**
90+
* Send an assertion to the backpack.
91+
*
92+
* @param string $hash The assertion hash
93+
* @return array
94+
*/
95+
abstract public function put_assertions(string $hash): array;
96+
8997
/**
9098
* Create a new backpackapi instance from an external backpack record.
9199
*

0 commit comments

Comments
 (0)