Commit 9345d3e5 authored by Aaron Wells's avatar Aaron Wells
Browse files

Bug 1620879: Add page for non-admin users to manager app tokens

behatnotneeded: Test to come later

Change-Id: I2663d376f6bc50d7195d6d26d65206a47385e21c
parent 15334434
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -58,7 +58,7 @@
            <FIELD NAME="token" TYPE="char" LENGTH="128" NOTNULL="true" SEQUENCE="false" COMMENT="security token, aka private access key"/>
            <FIELD NAME="tokentype" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" COMMENT="type of token: 0=permanent, no session; 1=linked to current browser session via sid; 2=permanent, with emulated session"/>
            <FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" SEQUENCE="false" COMMENT="owner of the token"/>
            <FIELD NAME="institution" TYPE="char" LENGTH="255" NOTNULL="true"/>
            <FIELD NAME="institution" TYPE="char" LENGTH="255" NOTNULL="false"/>
            <FIELD NAME="externalserviceid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false"/>
            <FIELD NAME="sid" TYPE="char" LENGTH="128" NOTNULL="false" SEQUENCE="false" COMMENT="link to browser or emulated session"/>
            <FIELD NAME="creatorid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" DEFAULT="1" SEQUENCE="false" COMMENT="user id of the token creator (useful to know when the administrator created a token and so display the token to a specific administrator)"/>
@@ -175,7 +175,7 @@
            <FIELD NAME="timelogged" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false"/>
            <FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" SEQUENCE="false" COMMENT="usr ref"/>
            <FIELD NAME="externalserviceid" TYPE="int" LENGTH="10" NOTNULL="false" UNSIGNED="true" SEQUENCE="false"/>
            <FIELD NAME="institution" TYPE="char" LENGTH="255" NOTNULL="true"/>
            <FIELD NAME="institution" TYPE="char" LENGTH="255" NOTNULL="false"/>
            <FIELD NAME="protocol" TYPE="char" LENGTH="10" NOTNULL="true"/>
            <FIELD NAME="auth" TYPE="char" LENGTH="10" NOTNULL="true"/>
            <FIELD NAME="functionname" TYPE="char" LENGTH="200" NOTNULL="false" SEQUENCE="false"/>
+14 −0
Original line number Diff line number Diff line
@@ -564,6 +564,20 @@ function xmldb_auth_webservice_upgrade($oldversion=0) {
        add_field($table, $field);
    }

    if ($oldversion < 2016101100) {
        log_debug('Make external_tokens.institution nullable');
        $table = new XMLDBTable('external_tokens');
        $field = new XMLDBField('institution');
        $field->setAttributes(XMLDB_TYPE_CHAR, 255, null, null);
        change_field_notnull($table, $field, false);

        log_debug('Allow null institution in external_services_logs');
        $table = new XMLDBTable('external_services_logs');
        $field = new XMLDBField('institution');
        $field->setAttributes(XMLDB_TYPE_CHAR, 255);
        change_field_notnull($table, $field, false);
    }

    // sweep for webservice updates everytime
    $status = external_reload_webservices();

+2 −2
Original line number Diff line number Diff line
@@ -12,7 +12,7 @@
defined('INTERNAL') || die();

$config = new stdClass();
$config->version = 2016090700;
$config->release = '2.0.0';
$config->version = 2016101100;
$config->release = '2.0.1';
$config->requires_config = 0;
$config->requires_parent = 0;
+295 −0
Original line number Diff line number Diff line
<?php
/**
 *
 * @package    mahara
 * @subpackage module-mobileapi
 * @author     Catalyst IT Ltd
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL version 3 or later
 * @copyright  For copyright information on Mahara, please see the README file distributed with this software.
 *
 */

/**
 * This page lets non-admin users manage which apps they've granted
 * webservice access tokens to.
 *
 * See /webservice/apptokens.php for the more complex admin version.
 */
define('INTERNAL', 1);
define('MENUITEM', 'settings/webservice');
define('SECTION_PLUGINTYPE', 'core');
define('SECTION_PLUGINNAME', 'account');
define('SECTION_PAGE', 'webservice');

require('./../../init.php');
require_once($CFG->docroot . 'webservice/lib.php');
safe_require('module', 'mobileapi');
define('TITLE', get_string('mytokenspagetitle', 'module.mobileapi'));

// Users shouldn't be able to access this page if webservices are not enabled.
if (!PluginModuleMobileapi::is_service_ready()) {
    throw new AccessDeniedException(get_string('featuredisabled', 'auth.webservice'));
}

// get the list of services that are available for User Access Tokens usage
// determine if there is a corresponding token for the service
$dbservices = get_records_sql_array(
    "SELECT
        es.id || '_' || et.id || '_' || es.id as dispid,
        es.id,
        es.name,
        es.enabled,
        es.restrictedusers,
        et.token,
        " . db_format_tsfield('et.mtime', 'token_mtime') . ',
        ' . db_format_tsfield('et.ctime', 'token_ctime') . ',
        et.institution,
        et.validuntil as token_validuntil,
        et.clientname,
        et.clientenv,
        esu.validuntil as user_validuntil,
        esu.iprestriction
    FROM
        {external_services} es
        LEFT JOIN {external_tokens} et
            ON et.externalserviceid = es.id
            AND et.userid = ?
            AND et.tokentype = ?
        LEFT JOIN {external_services_users} esu
            ON esu.externalserviceid = es.id
            AND esu.userid = ?
    WHERE
        es.tokenusers = 1
        AND (es.restrictedusers = 0 OR esu.id IS NOT NULL)
        AND (et.id IS NOT NULL OR esu.id IS NOT NULL)'
    ,array(
        $USER->get('id'),
        EXTERNAL_TOKEN_USER,
        $USER->get('id')
    )
);

/*
 * display the access tokens for services
 */
if (empty($dbservices)) {
    $userform = get_string('nopersonaltokens', 'module.mobileapi');
}
else {
    $userform = array(
        'name'            => 'webservices_user_tokens',
        'elementclasses'  => false,
        'successcallback' => 'webservices_user_tokens_submit',
        'renderer'   => 'multicolumntable',
    );
    $elements = array();
    $elements['client_info'] = array(
        'title' => ' ',
        'datatable' => true,
        'type' => 'html',
        'value' => get_string('clientinfo', 'module.mobileapi'),
    );

    if (get_config_plugin('module', 'mobileapi', 'manualtokens')) {
        $elements['token'] = array(
            'title' => ' ',
            'datatable' => true,
            'type'  => 'html',
            'value' => get_string('token', 'module.mobileapi'),
        );
    }

    $elements['created'] = array(
        'title' => ' ',
        'datatable' => true,
        'type'  => 'html',
        'value' => get_string('tokencreated', 'module.mobileapi'),
    );

    // Action buttons (no title)
    $elements['actions'] = array(
        'title' => ' ',
        'datatable' => true,
        'type' => 'html',
        'value' => '',
    );
    $userform['elements'] = $elements;

    foreach ($dbservices as $service) {

        $client = '<h3 class="title">';
        if ($service->clientname) {
            $client .= $service->clientname;
        }
        else {
            $client .= get_string('clientnotspecified', 'module.mobileapi');
        }
        $client .= '</h3>';

        if ($service->clientenv) {
            $client .= " ({$service->clientenv})";
        }

        // information about the client that generated it
        $userform['elements']['id' . $service->dispid . '_client_info'] = array(
            'value'        =>  $client,
            'type'         => 'html',
            'key'        => $service->dispid,
        );

        if (get_config_plugin('module', 'mobileapi', 'manualtokens')) {
            $userform['elements']['id' . $service->dispid . '_token'] = array(
                'value'        =>  $service->token,
                'type'         => 'html',
                'key'        => $service->dispid,
            );
        }

        $userform['elements']['id' . $service->dispid . '_ctime'] = array(
            'value' => format_date($service->token_ctime),
            'type' => 'html',
            'key' => $service->dispid,
        );

        // generate button
        // delete button
        $userform['elements']['id' . $service->dispid . '_actions'] = array(
            'value' => pieform(
                array(
                    'name'            => 'webservices_user_token_delete_' . $service->dispid,
                    'renderer'        => 'div',
                    'elementclasses'  => false,
                    'successcallback' => 'webservices_user_token_submit',
                    'class'           => 'form-as-button pull-left',
                    'jsform'          => false,
                    'elements' => array(
                        'token'    => array('type' => 'hidden', 'value' => $service->token),
                        'action'     => array('type' => 'hidden', 'value' => 'delete'),
                        'submit'     => array(
                                'type'  => 'button',
                                'usebuttontag' => true,
                                'class' => 'btn-default btn-sm',
                                'value' => '<span class="icon icon-trash icon-lg text-danger left" role="presentation" aria-hidden="true"></span>' . get_string('delete'),
                                'elementtitle' => get_string('deletespecific', 'mahara', $service->dispid),
                            ),
                    ),
                )
            ),
            'type'         => 'html',
            'key'        => $service->dispid,
            'class'        => 'webserviceconfigcontrols' . (empty($service->token) ? ' only-button only-button-top' : ''),
        );
    }
    $pieform = pieform_instance($userform);
    $userform = $pieform->build(false);
}

$page_elements = array(
    // fieldset for managing service function list
    'user_tokens' => array(
        'type' => 'fieldset',
        'legend' => get_string('mytokenspagedesc', 'module.mobileapi'),
        'elements' => array(
            'sflist' => array(
                'type'         => 'html',
                'value' =>     $userform,
            )
        ),
        'collapsible' => false,
    )
);

// TODO: Currently this is hardcoded to only allow self-generation of the
// maharamobile service.
$service = get_record('external_services', 'component', 'module/mobileapi', 'shortname', 'maharamobile');
if (get_config_plugin('module', 'mobileapi', 'manualtokens')) {
    $page_elements['generate_user_token'] = array(
        'type' => 'fieldset',
        'legend' => get_string('generateusertoken', 'module.mobileapi'),
        'elements' => array(
            'generate_user_token_html' => array(
                'type' => 'html',
                'value' => pieform(
                    array(
                        'name'            => 'webservices_user_token_generate_' . $service->id,
                        'renderer'        => 'div',
                        'elementclasses'  => false,
                        'successcallback' => 'webservices_user_token_submit',
                        'class'           => 'form-as-button pull-left',
                        'jsform'          => false,
                        'elements' => array(
                            'action'     => array('type' => 'hidden', 'value' => 'generate'),
                            'submit'     => array(
                                    'type'  => 'button',
                                    'usebuttontag' => true,
                                    'class' => 'btn-default btn-sm',
                                    'value'   => '<span class="icon icon-refresh"></span> ' . get_string('gen', 'auth.webservice'),
                                    'elementtitle' => get_string('gen', 'auth.webservice')
                                ),
                        ),
                    )
                )
            )
        )
    );
}

$form = array(
    'renderer' => 'div',
    'type' => 'div',
    'id' => 'maintable',
    'name' => 'maincontainer',
    'dieaftersubmit' => false,
    'successcallback' => 'webservice_main_submit',
    'elements' => $page_elements,
);

/**
 * handle the callback for actions on the user token panel
 *  - generate noew token
 *  - delete token
 *
 * @param Pieform $form
 * @param array $values
 */
function webservices_user_token_submit(Pieform $form, $values) {
    global $USER, $SESSION;
    if ($values['action'] == 'generate') {
        // TODO: Currently this is hard-coded to only the maharamobile service
        if (
            get_config_plugin('module', 'mobileapi', 'manualtokens')
            && ($service = get_record('external_services', 'component', 'module/mobileapi', 'shortname', 'maharamobile', 'tokenusers', 1))
        ) {
            $token = webservice_generate_token(
                EXTERNAL_TOKEN_USER,
                $service,
                $USER->get('id'),
                null,
                null,
                null,
                get_string('tokenmanuallycreated', 'auth.webservice')
            );
            $SESSION->add_ok_msg(get_string('token_generated', 'auth.webservice'));
        }
        else {
            $SESSION->add_error_msg(get_string('noservices', 'auth.webservice'));
        }
    }
    else if ($values['action'] == 'delete') {
        delete_records('external_tokens', 'userid', $USER->get('id'), 'token', $values['token']);
        $SESSION->add_ok_msg(get_string('appaccessrevoked', 'module.mobileapi'));
    }
    redirect('/module/mobileapi/apps.php');
}

// render the page
$pieform = pieform_instance($form);
$form = $pieform->build(false);

$smarty = smarty();
setpageicon($smarty, 'icon-globe');
safe_require('auth', 'webservice');

$smarty->assign('form', $form);

$smarty->display('form.tpl');
+14 −1
Original line number Diff line number Diff line
@@ -25,3 +25,16 @@ $string['notreadylabel'] = 'Not ready';
$string['readylabel'] = 'Ready';
$string['restprotocolenabled'] = 'REST protocol enabled';
$string['webserviceproviderenabled'] = 'Incoming web service requests allowed';

// User management of webservice access tokens
$string['mytokensmenutitle'] = 'Apps';
$string['mytokenspagetitle'] = 'Applications';
$string['mytokenspagedesc'] = 'These applications can access your Mahara account.';
$string['nopersonaltokens'] = 'You have not granted access to any applications.';
$string['clientinfo'] = 'App';
$string['token'] = 'Access Token';
$string['tokencreated'] = 'Created';
$string['tokenmanuallycreated'] = 'Manually created';
$string['clientnotspecified'] = '(Unknown)';
$string['generateusertoken'] = 'Generate an app access token';
$string['appaccessrevoked'] = 'Access revoked';
 No newline at end of file
Loading