diff --git a/badges/backpack-add.php b/badges/backpack-add.php
index 1ff7795ae7c..7b4fc37ce6b 100644
--- a/badges/backpack-add.php
+++ b/badges/backpack-add.php
@@ -60,6 +60,7 @@ if (!empty($issuedbadge->recipient->id)) {
$assertionid = $assertion->get_assertion_hash();
$assertionentityid = $assertiondata['id'];
$badgeadded = false;
+ $issuerexists = false;
if (badges_open_badges_backpack_api() == OPEN_BADGES_V2) {
$sitebackpack = badges_get_site_primary_backpack();
$api = new \core_badges\backpack_api($sitebackpack);
@@ -71,62 +72,75 @@ if (!empty($issuedbadge->recipient->id)) {
$issuer = $assertion->get_issuer();
if (!($issuerentityid = badges_external_get_mapping($sitebackpack->id, OPEN_BADGES_V2_TYPE_ISSUER, $issuer['email']))) {
$response = $api->put_issuer($issuer);
- if (!$response) {
- throw new moodle_exception('invalidrequest', 'error');
+ if ($response) {
+ $issuerexists = true;
+ $issuerentityid = $response->id;
+ badges_external_create_mapping(
+ $sitebackpack->id,
+ OPEN_BADGES_V2_TYPE_ISSUER,
+ $issuer['email'],
+ $issuerentityid,
+ );
}
- $issuerentityid = $response->id;
- badges_external_create_mapping($sitebackpack->id, OPEN_BADGES_V2_TYPE_ISSUER, $issuer['email'],
- $issuerentityid);
}
- // Create badge.
- $badge = $assertion->get_badge_class(false);
- $badgeid = $assertion->get_badge_id();
- if (!($badgeentityid = badges_external_get_mapping($sitebackpack->id, OPEN_BADGES_V2_TYPE_BADGE, $badgeid))) {
- $response = $api->put_badgeclass($issuerentityid, $badge);
- if (!$response) {
- throw new moodle_exception('invalidrequest', 'error');
+ if ($issuerexists) {
+ // Create badge.
+ $badge = $assertion->get_badge_class(false);
+ $badgeid = $assertion->get_badge_id();
+ if (!($badgeentityid = badges_external_get_mapping($sitebackpack->id, OPEN_BADGES_V2_TYPE_BADGE, $badgeid))) {
+ $response = $api->put_badgeclass($issuerentityid, $badge);
+ if ($response) {
+ $badgeentityid = $response->id;
+ badges_external_create_mapping(
+ $sitebackpack->id,
+ OPEN_BADGES_V2_TYPE_BADGE,
+ $badgeid,
+ $badgeentityid,
+ );
+ }
}
- $badgeentityid = $response->id;
- badges_external_create_mapping($sitebackpack->id, OPEN_BADGES_V2_TYPE_BADGE, $badgeid,
- $badgeentityid);
- }
- // Create assertion (Award the badge!).
- $assertionentityid = badges_external_get_mapping(
- $sitebackpack->id,
- OPEN_BADGES_V2_TYPE_ASSERTION,
- $assertionid
- );
-
- if ($assertionentityid && strpos($sitebackpack->backpackapiurl, 'badgr')) {
- $assertionentityid = badges_generate_badgr_open_url(
- $sitebackpack,
- OPEN_BADGES_V2_TYPE_ASSERTION,
- $assertionentityid
- );
- }
-
- // Create an assertion for the recipient in the issuer's account.
- if (!$assertionentityid) {
- $response = $api->put_badgeclass_assertion($badgeentityid, $assertiondata);
- if (!$response) {
- throw new moodle_exception('invalidrequest', 'error');
- }
- $assertionentityid = badges_generate_badgr_open_url($sitebackpack, OPEN_BADGES_V2_TYPE_ASSERTION, $response->id);
- $badgeadded = true;
- badges_external_create_mapping($sitebackpack->id, OPEN_BADGES_V2_TYPE_ASSERTION, $assertionid,
- $response->id);
- } else {
- // An assertion already exists. Make sure it's up to date.
- $internalid = badges_external_get_mapping(
+ // Create assertion (Award the badge!).
+ $assertionentityid = badges_external_get_mapping(
$sitebackpack->id,
OPEN_BADGES_V2_TYPE_ASSERTION,
- $assertionid,
- 'externalid'
+ $assertionid
);
- $response = $api->update_assertion($internalid, $assertiondata);
- if (!$response) {
- throw new moodle_exception('invalidrequest', 'error');
+
+ if ($assertionentityid && strpos($sitebackpack->backpackapiurl, 'badgr')) {
+ $assertionentityid = badges_generate_badgr_open_url(
+ $sitebackpack,
+ OPEN_BADGES_V2_TYPE_ASSERTION,
+ $assertionentityid
+ );
+ }
+
+ // Create an assertion for the recipient in the issuer's account.
+ if (!$assertionentityid) {
+ $response = $api->put_badgeclass_assertion($badgeentityid, $assertiondata);
+ if ($response) {
+ $assertionentityid = badges_generate_badgr_open_url(
+ $sitebackpack,
+ OPEN_BADGES_V2_TYPE_ASSERTION,
+ $response->id,
+ );
+ $badgeadded = true;
+ badges_external_create_mapping(
+ $sitebackpack->id,
+ OPEN_BADGES_V2_TYPE_ASSERTION,
+ $assertionid,
+ $response->id,
+ );
+ }
+ } else {
+ // An assertion already exists. Make sure it's up to date.
+ $internalid = badges_external_get_mapping(
+ $sitebackpack->id,
+ OPEN_BADGES_V2_TYPE_ASSERTION,
+ $assertionid,
+ 'externalid'
+ );
+ $response = $api->update_assertion($internalid, $assertiondata);
}
}
}
@@ -136,21 +150,59 @@ if (!empty($issuedbadge->recipient->id)) {
// - If a user and site backpack have the same provider we can skip this as Badgr automatically maps recipients
// based on email address.
// - This is only needed when the backpacks are from different regions.
- if ($assertionentityid && !badges_external_get_mapping($userbackpack->id, OPEN_BADGES_V2_TYPE_ASSERTION, $assertionid)) {
+ if (
+ $assertionentityid
+ && (!$issuerexists || !badges_external_get_mapping($userbackpack->id, OPEN_BADGES_V2_TYPE_ASSERTION, $assertionid))
+ ) {
$userapi = new \core_badges\backpack_api($userbackpack, $backpack);
$userapi->authenticate();
$response = $userapi->import_badge_assertion($assertionentityid);
- if (!$response) {
- throw new moodle_exception('invalidrequest', 'error');
+ if ($response) {
+ $assertionentityid = $response->id;
+ $badgeadded = true;
+ badges_external_create_mapping(
+ $userbackpack->id,
+ OPEN_BADGES_V2_TYPE_ASSERTION,
+ $assertionid,
+ $assertionentityid,
+ );
}
- $assertionentityid = $response->id;
- $badgeadded = true;
- badges_external_create_mapping($userbackpack->id, OPEN_BADGES_V2_TYPE_ASSERTION, $assertionid,
- $assertionentityid);
}
- $response = $badgeadded ? ['success' => 'addedtobackpack'] : ['warning' => 'existsinbackpack'];
- redirect(new moodle_url('/badges/mybadges.php', $response));
+ $message = '';
+ $messagetype = \core\output\notification::NOTIFY_INFO;
+ if ($badgeadded) {
+ $message = get_string('addedtobackpack', 'badges');
+ $messagetype = \core\output\notification::NOTIFY_SUCCESS;
+ } else {
+ if (isset($userapi) && !empty($userapi->get_errors())) {
+ // If the api used to import the badge to the backpack has errors, show them to inform the user.
+ if (array_filter($userapi->get_errors(), fn($element) => str_contains($element, "DUPLICATE_BADGE"))) {
+ // Duplicated badges are displayed as a warning.
+ $message = get_string('existsinbackpack', 'badges');
+ $messagetype = \core\output\notification::NOTIFY_WARNING;
+ } else {
+ // If the userapi has any other errors, we will use those to inform the user.
+ $message = get_string(
+ 'error:cannotsendtobackpack',
+ 'badges',
+ implode($userapi->get_errors()),
+ );
+ $messagetype = \core\output\notification::NOTIFY_ERROR;
+ }
+ } else if (isset($api) && !empty($api->get_errors())) {
+ // If the api used to create/update the issuer has errors, show them to inform the user.
+ $errors = $api->get_errors() ?? [get_string('invalidrequest', 'error')];
+ $message = get_string(
+ 'error:cannotsendtobackpack',
+ 'badges',
+ implode($errors),
+ );
+ $messagetype = \core\output\notification::NOTIFY_ERROR;
+ }
+ }
+
+ redirect(new moodle_url('/badges/mybadges.php'), $message, null, $messagetype);
} else {
redirect(new moodle_url('/badges/mybadges.php'));
}
diff --git a/badges/classes/backpack_api.php b/badges/classes/backpack_api.php
index c7c49cec06e..4ea4b0f78cd 100644
--- a/badges/classes/backpack_api.php
+++ b/badges/classes/backpack_api.php
@@ -667,6 +667,20 @@ class backpack_api {
return backpack_api_mapping::get_authentication_error();
}
+ /**
+ * List all errors occurred during the requests to the backpack.
+ *
+ * @return array The list of errors.
+ */
+ public function get_errors(): array {
+ $errors = [];
+ foreach ($this->mappings as $mapping) {
+ $errors = array_merge($errors, $mapping->get_errors());
+ }
+
+ return $errors;
+ }
+
/**
* Get the list of badges in a collection.
*
diff --git a/badges/classes/backpack_api_mapping.php b/badges/classes/backpack_api_mapping.php
index 4c10f672a77..c8a81139a80 100644
--- a/badges/classes/backpack_api_mapping.php
+++ b/badges/classes/backpack_api_mapping.php
@@ -79,6 +79,9 @@ class backpack_api_mapping {
/** @var string Error string from authentication request. */
private static $authenticationerror = '';
+ /** @var array Errors encountered during the request. */
+ protected $errors = [];
+
/**
* Create a mapping.
*
@@ -144,6 +147,26 @@ class backpack_api_mapping {
return self::$authenticationerror;
}
+ /**
+ * Get the errors encountered during the request.
+ *
+ * @return array The list of errors.
+ */
+ public function get_errors() {
+ return $this->errors;
+ }
+
+ /**
+ * Add an error to the list of errors.
+ *
+ * @param string $error The error message.
+ * @return self This instance for method chaining.
+ */
+ public function add_error(string $error): self {
+ $this->errors[] = $error;
+ return $this;
+ }
+
/**
* Does the action match this mapping?
*
@@ -366,6 +389,23 @@ class backpack_api_mapping {
$response = $curl->put($url, $post, $options);
}
$response = json_decode($response);
+ if ($response === null) {
+ $this->add_error(get_string('invalidrequest', 'error'));
+ return null;
+ }
+ if (isset($response->status) && isset($response->status->success) && $response->status->success != true) {
+ // If the response wasn't successful, store the errors and return null.
+ if (isset($response->validationErrors)) {
+ $error = implode(', ', $response->validationErrors);
+ } else if (isset($response->status)) {
+ $error = $response->status->description;
+ } else {
+ $error = get_string('invalidrequest', 'error');
+ }
+ $this->add_error($error);
+ return null;
+ }
+
if (isset($response->result)) {
$response = $response->result;
}
diff --git a/lang/en/badges.php b/lang/en/badges.php
index b42b0484161..ebb109dd8e9 100644
--- a/lang/en/badges.php
+++ b/lang/en/badges.php
@@ -294,6 +294,9 @@ $string['error:cannotact'] = 'Cannot activate the badge. ';
$string['error:cannotawardbadge'] = 'Cannot award badge to a user.';
$string['error:cannotrevokebadge'] = 'Cannot revoke badge from a user.';
$string['error:cannotdeletecriterion'] = 'This criterion cannot be deleted. ';
+$string['error:cannotsendtobackpack'] = 'Can\'t add badge to backpack
+Your backpack provider is sending this message: \'{$a}\'.
+You can try downloading the badge and adding it manually to your backpack, or try again later.';
$string['error:connectionunknownreason'] = 'The connection was unsuccessful but no reason was given.';
$string['error:clone'] = 'Cannot clone the badge.';
$string['error:duplicatename'] = 'Badge with such name already exists in the system.';