Skip to content

Commit

Permalink
MDL-65959 badges: Update the implementation to use admin set backpack
Browse files Browse the repository at this point in the history
  • Loading branch information
Peter Dias committed Oct 26, 2020
1 parent b6435e0 commit 3cae942
Show file tree
Hide file tree
Showing 9 changed files with 125 additions and 64 deletions.
8 changes: 2 additions & 6 deletions badges/classes/backpack_api.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,10 @@ public function __construct($sitebackpack, $userbackpack = false) {
$this->backpackapiurl = $sitebackpack->backpackapiurl;
$this->backpackapiversion = $sitebackpack->apiversion;
$this->password = $sitebackpack->password;
$this->email = !empty($CFG->badges_defaultissuercontact) ? $CFG->badges_defaultissuercontact : '';
$this->email = $sitebackpack->backpackemail;
$this->isuserbackpack = false;
$this->backpackid = $sitebackpack->id;
if (!empty($userbackpack)) {
if ($userbackpack->externalbackpackid != $sitebackpack->id) {
throw new coding_exception('Incorrect backpack');
}
$this->isuserbackpack = true;
$this->password = $userbackpack->password;
$this->email = $userbackpack->email;
Expand Down Expand Up @@ -602,7 +599,7 @@ public function get_collection_record($collectionid) {
* @param integer $backpackid The backpack to disconnect
* @return boolean
*/
public function disconnect_backpack($userid, $backpackid, $externalbackupid) {
public function disconnect_backpack($userid, $backpackid) {
global $DB, $USER;

if (\core\session\manager::is_loggedinas() || $userid != $USER->id) {
Expand All @@ -614,7 +611,6 @@ public function disconnect_backpack($userid, $backpackid, $externalbackupid) {

$DB->delete_records('badge_external', array('backpackid' => $backpackid));
$DB->delete_records('badge_backpack', array('userid' => $userid));
$DB->delete_records('badge_external_backpack', array('id' => $externalbackupid));
$badgescache->delete($userid);
return true;
}
Expand Down
63 changes: 33 additions & 30 deletions badges/classes/form/backpack.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,31 +47,55 @@ class backpack extends external_backpack {
public function definition() {
global $USER, $PAGE, $OUTPUT, $CFG;
$mform = $this->_form;
$this->_customdata['userbackpack'] = 1;

$mform->addElement('html', html_writer::tag('span', '', array('class' => 'notconnected', 'id' => 'connection-error')));
$mform->addElement('header', 'backpackheader', get_string('backpackconnection', 'badges'));
$mform->addHelpButton('backpackheader', 'backpackconnection', 'badges');
$mform->addElement('hidden', 'userid', $USER->id);
$mform->setType('userid', PARAM_INT);
$mform->addElement('hidden', 'externalbackpackid');
$mform->setType('externalbackpackid', PARAM_INT);
$freeze = [];
if (isset($this->_customdata['email'])) {
// Email will be passed in when we're in the process of verifying the user's email address,
// so set the connection status, lock the email field, and provide options to resend the verification
// email or cancel the verification process entirely and start over.
$mform->hardFreeze();
$freeze = ['backpackemail'];
$mform->addElement('hidden', 'password', $this->_customdata['backpackpassword']);
$mform->setType('password', PARAM_RAW);
$mform->addElement('hidden', 'externalbackpackid', $this->_customdata['backpackid']);
$mform->setType('externalbackpackid', PARAM_INT);
$status = html_writer::tag('span', get_string('backpackemailverificationpending', 'badges'),
array('class' => 'notconnected', 'id' => 'connection-status'));
} else {
$sitebackpacks = badges_get_site_backpacks();
$choices = [];
$restrictedoptions = [];
foreach ($sitebackpacks as $backpack) {
$choices[$backpack->id] = $backpack->backpackweburl;
if ($backpack->apiversion == OPEN_BADGES_V2P1) {
$restrictedoptions[] = $backpack->id;
}
}
$mform->addElement('select', 'externalbackpackid', get_string('backpackprovider', 'badges'), $choices);
$mform->setType('externalbackpackid', PARAM_INT);
$mform->setDefault('externalbackpackid', $CFG->badges_site_backpack);
$mform->hideIf('password', 'externalbackpackid', 'in', $restrictedoptions);
$mform->hideIf('backpackemail', 'externalbackpackid', 'in', $restrictedoptions);

$status = html_writer::tag('span', get_string('notconnected', 'badges'),
array('class' => 'notconnected', 'id' => 'connection-status'));
}
$mform->addElement('static', 'status', get_string('status'), $status);

parent::definition();
$this->add_auth_fields($this->_customdata['email'] ?? $USER->email, !isset($this->_customdata['email']));

$mform->setDefault('backpackemail', $USER->email);
$mform->setDisableShortforms(false);

// Freeze any elemnts after definition.
if ($freeze) {
$mform->freeze($freeze);
}
$this->add_action_buttons();
}

/**
Expand All @@ -81,8 +105,8 @@ public function definition() {
* @param null|text $submitlabel
*/
public function add_action_buttons($cancel = true, $submitlabel = null) {
if ($this->_customdata['email']) {
$mform = $this->_form;
$mform = $this->_form;
if (isset($this->_customdata['email'])) {
$buttonarray = [];
$buttonarray[] = &$mform->createElement('submit', 'submitbutton',
get_string('backpackconnectionresendemail', 'badges'));
Expand All @@ -92,27 +116,6 @@ public function add_action_buttons($cancel = true, $submitlabel = null) {
$mform->closeHeaderBefore('buttonar');
} else {
// Email isn't present, so provide an input element to get it and a button to start the verification process.

$mform->addElement('static', 'info', get_string('backpackweburl', 'badges'), $sitebackpack->backpackweburl);
$mform->addElement('hidden', 'backpackid', $sitebackpack->id);
$mform->setType('backpackid', PARAM_INT);

$status = html_writer::tag('span', get_string('notconnected', 'badges'),
array('class' => 'notconnected', 'id' => 'connection-status'));
$mform->addElement('static', 'status', get_string('status'), $status);
if (badges_open_badges_backpack_api() != OPEN_BADGES_V2P1) {
$mform->addElement('text', 'email', get_string('email'), 'maxlength="100" size="30"');
$mform->addHelpButton('email', 'backpackemail', 'badges');
$mform->addRule('email', get_string('required'), 'required', null, 'client');
$mform->setType('email', PARAM_EMAIL);
if (badges_open_badges_backpack_api() == OPEN_BADGES_V2) {
$mform->addElement('passwordunmask', 'backpackpassword', get_string('password'));
$mform->setType('backpackpassword', PARAM_RAW);
} else {
$mform->addElement('hidden', 'backpackpassword', '');
$mform->setType('backpackpassword', PARAM_RAW);
}
}
parent::add_action_buttons(false, get_string('backpackconnectionconnect', 'badges'));
}
}
Expand All @@ -132,9 +135,9 @@ public function validation($data, $files) {
$check = new stdClass();
$check->email = $data['backpackemail'];
$check->password = $data['password'];
$check->externalbackpackid = $data['externalbackpackid'];
$sitebackpack = badges_get_site_backpack($data['externalbackpackid']);
$bp = new \core_badges\backpack_api($sitebackpack, $check);

$bp = new \core_badges\backpack_api((object) $data, $check);
$result = $bp->authenticate();
if ($result === false || !empty($result->error)) {
$errors['backpackemail'] = get_string('backpackconnectionunexpectedresult', 'badges');
Expand Down
48 changes: 37 additions & 11 deletions badges/classes/form/external_backpack.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,26 +72,19 @@ public function definition() {
$mform->addElement('hidden', 'id', ($backpack->id ?? null));
$mform->setType('id', PARAM_INT);
$mform->addElement('hidden', 'badgebackpack', 0);
$mform->setType('badgebackpack', PARAM_INTEGER);
$mform->setType('badgebackpack', PARAM_INT);
$mform->addElement('hidden', 'userid', 0);
$mform->setType('userid', PARAM_INTEGER);
$mform->setType('userid', PARAM_INT);
$mform->addElement('hidden', 'backpackuid', 0);
$mform->setType('backpackuid', PARAM_INTEGER);
$mform->setType('backpackuid', PARAM_INT);

$mform->addElement('advcheckbox', 'includeauthdetails', null, get_string('includeauthdetails', 'core_badges'));
if (!empty($backpack->backpackemail) || !empty($backpack->password)) {
$mform->setDefault('includeauthdetails', 1);
}

$issuercontact = $CFG->badges_defaultissuercontact;
$mform->addElement('text', 'backpackemail', get_string('defaultissuercontact', 'core_badges'));
$mform->setType('backpackemail', PARAM_EMAIL);
$mform->setDefault('backpackemail', $issuercontact);

$mform->addElement('passwordunmask', 'password', get_string('defaultissuerpassword', 'core_badges'));
$mform->setType('password', PARAM_RAW);
$mform->addHelpButton('password', 'defaultissuerpassword', 'badges');
$mform->hideIf('password', 'apiversion', 'neq', 2);
$this->add_auth_fields($issuercontact);

$oauth2options = badges_get_oauth2_service_options();
$mform->addElement('select', 'oauth2_issuerid', get_string('oauth2issuer', 'core_badges'), $oauth2options);
Expand All @@ -102,6 +95,12 @@ public function definition() {
$this->set_data($backpack);
}

$mform->hideIf('includeauthdetails', 'apiversion', 'in', [OPEN_BADGES_V2P1]);
$mform->hideIf('backpackemail', 'includeauthdetails');
$mform->hideIf('backpackemail', 'apiversion', 'in', [OPEN_BADGES_V2P1]);
$mform->hideIf('password', 'includeauthdetails');
$mform->hideIf('password', 'apiversion', 'in', [1, OPEN_BADGES_V2P1]);

// Disable short forms.
$mform->setDisableShortforms();

Expand Down Expand Up @@ -151,4 +150,31 @@ public function get_data() {

return $data;
}

/**
* Add backpack specific auth details.
*
* @param string|null $email The email addressed provided or null if it's new.
* @param boolean|true $includepassword Include the password field.
* @throws \coding_exception
*/
protected function add_auth_fields(?string $email, bool $includepassword = true) {
$mform = $this->_form;
$emailstring = get_string('email');
$passwordstring = get_string('password');
if (!isset($this->_customdata['userbackpack'])) {
$emailstring = get_string('defaultissuercontact', 'core_badges');
$passwordstring = get_string('defaultissuerpassword', 'core_badges');
}

$mform->addElement('text', 'backpackemail', $emailstring);
$mform->setType('backpackemail', PARAM_EMAIL);
$mform->setDefault('backpackemail', $email);

if ($includepassword) {
$mform->addElement('passwordunmask', 'password', $passwordstring);
$mform->setType('password', PARAM_RAW);
$mform->addHelpButton('password', 'defaultissuerpassword', 'badges');
}
}
}
5 changes: 2 additions & 3 deletions badges/mybackpack.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
} else {
// If backpack is connected, need to select collections.
$bp = new \core_badges\backpack_api($sitebackpack, $backpack);
$bp->disconnect_backpack($USER->id, $backpack->id, $sitebackpack->id);
$bp->disconnect_backpack($USER->id, $backpack->id);
redirect(new moodle_url('/badges/mybackpack.php'));
}
}
Expand Down Expand Up @@ -142,8 +142,7 @@
badges_disconnect_user_backpack($USER->id);
redirect(new moodle_url('/badges/mybackpack.php'));
} else if (isset($data->backpackemail)) {
$newid = badges_create_site_backpack($data, true);
if (badges_send_verification_email($data->backpackemail, $newid, $data->password)) {
if (badges_send_verification_email($data->backpackemail, $data->externalbackpackid, $data->password)) {
$a = get_user_preferences('badges_email_verify_backpackid');
redirect(new moodle_url('/badges/mybackpack.php'),
get_string('backpackemailverifypending', 'badges', $data->backpackemail),
Expand Down
6 changes: 5 additions & 1 deletion lang/en/badges.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@
$string['backpackavailability'] = 'External badge verification';
$string['backpackconnectionok'] = 'Backpack connection successfully established';
$string['backpackconnectionnottested'] = 'The connection cannot be tested for this backpack because only Open Badges v2.0 backpacks support it.';
$string['backpackneedsupdate'] = 'The backpack connected to this profile does not match the backpack for the site. You need to disconnect and reconnect the backpack.';
$string['backpackavailability_help'] = 'For badge recipients to be able to prove they earned their badges from you, an external backpack service should be able to access your site and verify badges issued from it. Your site does not currently appear to be accessible, which means that badges you have already issued or will issue in the future cannot be verified.
**Why am I seeing this message?**
Expand Down Expand Up @@ -137,6 +136,7 @@
$string['backpacksettings'] = 'Backpack settings';
$string['backpackapiurl'] = 'Backpack API URL';
$string['backpackweburl'] = 'Backpack URL';
$string['backpackprovider'] = 'Backpack Provider';
$string['badges'] = 'Badges';
$string['badgedetails'] = 'Badge details';
$string['badgeimage'] = 'Image';
Expand Down Expand Up @@ -571,7 +571,11 @@
$string['version_help'] = 'The version field may be used to keep track of the badge\'s development. If specified, the version is displayed on the badge page.';
$string['warnexpired'] = ' (This badge has expired!)';
$string['year'] = 'Year(s)';
$string['includeauthdetails'] = "Include authentication details with the backpack";

// Deprecated since Moodle 3.9.
$string['editsettings'] = 'Edit settings';
$string['sitebackpackverify'] = 'Backpack connection';

// Deprecated since Moodle 3.10.
$string['backpackneedsupdate'] = 'The backpack connected to this profile does not match the backpack for the site. You need to disconnect and reconnect the backpack.';
1 change: 1 addition & 0 deletions lang/en/deprecated.txt
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,4 @@ userfilterplaceholder,core
sitebackpackverify,core_badges
filetypesnotwhitelisted,core_form
modeloutputdirinfo,core_analytics
backpackneedsupdate,core_badges
18 changes: 10 additions & 8 deletions lib/badgeslib.php
Original file line number Diff line number Diff line change
Expand Up @@ -851,9 +851,7 @@ function badges_save_external_backpack(stdClass $data) {
$backpack->apiversion = $data->apiversion;
$backpack->backpackweburl = $data->backpackweburl;
$backpack->backpackapiurl = $data->backpackapiurl;
$backpack->backpackemail = $data->backpackemail;
$backpack->password = !empty($data->password) ? $data->password : '';
$backpack->oauth2_issuerid = !empty($data->oauth2_issuerid) ? $data->oauth2_issuerid : '';
$backpack->oauth2_issuerid = $data->oauth2_issuerid ?? '';
if (isset($data->sortorder)) {
$backpack->sortorder = $data->sortorder;
}
Expand All @@ -868,7 +866,6 @@ function badges_save_external_backpack(stdClass $data) {

unset($data->id);
badges_save_backpack_credentials($data);

return $data->externalbackpackid;
}

Expand Down Expand Up @@ -933,7 +930,12 @@ function badges_open_badges_backpack_api() {
function badges_get_site_backpack($id) {
global $DB;

return $DB->get_record('badge_external_backpack', ['id' => $id]);
$sql = "SELECT beb.*, bb.id AS badgebackpack, bb.password, bb.email AS backpackemail
FROM {badge_external_backpack} beb
LEFT JOIN {badge_backpack} bb ON bb.externalbackpackid = beb.id AND bb.userid=:userid
WHERE beb.id=:id";

return $DB->get_record_sql($sql, ['id' => $id, 'userid' => 0]);
}

/**
Expand All @@ -955,11 +957,11 @@ function badges_get_site_primary_backpack() {
function badges_get_site_backpacks() {
global $DB, $CFG;

$sql = "SELECT beb.*
$sql = "SELECT beb.*, bb.id as badgebackpack, bb.password, bb.email as backpackemail
FROM {badge_external_backpack} beb
LEFT JOIN {badge_backpack} bb ON bb.externalbackpackid = beb.id
WHERE bb.id IS NULL";
$all = $DB->get_records_sql($sql);
WHERE bb.id IS NULL OR bb.userid=:userid";
$all = $DB->get_records_sql($sql, ['userid' => 0]);

foreach ($all as $key => $bp) {
if ($bp->id == $CFG->badges_site_backpack) {
Expand Down
4 changes: 2 additions & 2 deletions lib/db/install.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="lib/db" VERSION="20201007" COMMENT="XMLDB file for core Moodle tables"
<XMLDB PATH="lib/db" VERSION="20201008" COMMENT="XMLDB file for core Moodle tables"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../lib/xmldb/xmldb.xsd"
>
Expand Down Expand Up @@ -3188,6 +3188,7 @@
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
<KEY NAME="fk_userid" TYPE="foreign" FIELDS="userid" REFTABLE="user" REFFIELDS="id"/>
<KEY NAME="backpackcredentials" TYPE="unique" FIELDS="userid, externalbackpackid"/>
<KEY NAME="externalbackpack" TYPE="foreign" FIELDS="externalbackpackid" REFTABLE="badge_external_backpack" REFFIELDS="id"/>
</KEYS>
</TABLE>
Expand Down Expand Up @@ -3275,7 +3276,6 @@
<FIELD NAME="backpackweburl" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="apiversion" TYPE="char" LENGTH="12" NOTNULL="true" DEFAULT="1.0" SEQUENCE="false"/>
<FIELD NAME="sortorder" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="password" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false" COMMENT="Password to login into external backpack and issue badges."/>
<FIELD NAME="oauth2_issuerid" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="OAuth 2 Issuer"/>
</FIELDS>
<KEYS>
Expand Down
36 changes: 33 additions & 3 deletions lib/db/upgrade.php
Original file line number Diff line number Diff line change
Expand Up @@ -2863,10 +2863,40 @@ function xmldb_main_upgrade($oldversion) {
}

if ($oldversion < 2021052500.32) {
global $DB, $CFG;

$table = new xmldb_table('badge_backpack');
$uniquekey = new xmldb_key('backpackcredentials', XMLDB_KEY_UNIQUE, ['userid', 'externalbackpackid']);

// All external backpack providers/hosts are now exclusively stored in badge_external_backpack.
// All credentials are stored in badge_backpack and are unique per user, backpack.
if (!$dbman->find_key_name($table, $uniquekey)) {
$dbman->add_key($table, $uniquekey);
}

// If there is a current backpack set then copy it across to the new structure.
if ($CFG->badges_defaultissuercontact) {
// Get the currently used site backpacks.
$records = $DB->get_records_select('badge_external_backpack', "password IS NOT NULL AND password != ''");
$backpack = [
'userid' => '0',
'email' => $CFG->badges_defaultissuercontact,
'backpackuid' => -1
];

// Create records corresponding to the site backpacks.
foreach ($records as $record) {
$backpack['password'] = $record->password;
$backpack['externalbackpackid'] = $record->id;
$DB->insert_record('badge_backpack', (object) $backpack);
}
}

// Drop the password field as this is moved to badge_backpack.
$table = new xmldb_table('badge_external_backpack');
$field = new xmldb_field('backpackemail', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
$field = new xmldb_field('password', XMLDB_TYPE_CHAR, '50');
if ($dbman->field_exists($table, $field)) {
$dbman->drop_field($table, $field);
}

// Main savepoint reached.
Expand Down

0 comments on commit 3cae942

Please sign in to comment.