Skip to content

Commit

Permalink
MDL-61449 tool_mobile: New Web Service tool_mobile_get_content
Browse files Browse the repository at this point in the history
  • Loading branch information
jleyva committed Apr 4, 2018
1 parent 73d85fe commit b9e6db9
Show file tree
Hide file tree
Showing 5 changed files with 247 additions and 2 deletions.
128 changes: 128 additions & 0 deletions admin/tool/mobile/classes/external.php
Expand Up @@ -28,6 +28,7 @@
require_once("$CFG->libdir/externallib.php");

use external_api;
use external_files;
use external_function_parameters;
use external_value;
use external_single_structure;
Expand All @@ -37,6 +38,7 @@
use moodle_exception;
use moodle_url;
use core_text;
use coding_exception;

/**
* This is the external API for this tool.
Expand Down Expand Up @@ -332,4 +334,130 @@ public static function get_autologin_key_returns() {
)
);
}

/**
* Returns description of get_content() parameters
*
* @return external_function_parameters
* @since Moodle 3.5
*/
public static function get_content_parameters() {
return new external_function_parameters(
array(
'component' => new external_value(PARAM_COMPONENT, 'Component where the class is e.g. mod_assign.'),
'method' => new external_value(PARAM_ALPHANUMEXT, 'Method to execute in class \$component\output\mobile.'),
'args' => new external_multiple_structure(
new external_single_structure(
array(
'name' => new external_value(PARAM_ALPHANUMEXT, 'Param name.'),
'value' => new external_value(PARAM_RAW, 'Param value.')
)
), 'Args for the method are optional.', VALUE_OPTIONAL
)
)
);
}

/**
* Returns a piece of content to be displayed in the Mobile app, it usually returns a template, javascript and
* other structured data that will be used to render a view in the Mobile app..
*
* Callbacks (placed in \$component\output\mobile) that are called by this web service are responsible for doing the
* appropriate security checks to access the information to be returned.
*
* @param string $component fame of the component.
* @param string $method function method name in class \$component\output\mobile.
* @param array $args optional arguments for the method.
* @return array HTML, JavaScript and other required data and information to create a view in the app.
* @since Moodle 3.5
* @throws coding_exception
*/
public static function get_content($component, $method, $args = array()) {
global $OUTPUT, $PAGE, $USER;

$params = self::validate_parameters(self::get_content_parameters(),
array(
'component' => $component,
'method' => $method,
'args' => $args
)
);

// Reformat arguments into something less unwieldy.
$arguments = array();
foreach ($params['args'] as $paramargument) {
$arguments[$paramargument['name']] = $paramargument['value'];
}

// The component was validated via the PARAM_COMPONENT parameter type.
$classname = '\\' . $params['component'] .'\output\mobile';
if (!method_exists($classname, $params['method'])) {
throw new coding_exception("Missing method in $classname");
}
$result = call_user_func_array(array($classname, $params['method']), array($arguments));

// Populate otherdata.
$otherdata = array();
if (!empty($result['otherdata'])) {
$result['otherdata'] = (array) $result['otherdata'];
foreach ($result['otherdata'] as $name => $value) {
$otherdata[] = array(
'name' => $name,
'value' => $value
);
}
}

return array(
'templates' => !empty($result['templates']) ? $result['templates'] : array(),
'javascript' => !empty($result['javascript']) ? $result['javascript'] : '',
'otherdata' => $otherdata,
'files' => !empty($result['files']) ? $result['files'] : array(),
'restrict' => !empty($result['restrict']) ? $result['restrict'] : array(),
);
}

/**
* Returns description of get_content() result value
*
* @return array
* @since Moodle 3.5
*/
public static function get_content_returns() {
return new external_single_structure(
array(
'templates' => new external_multiple_structure(
new external_single_structure(
array(
'id' => new external_value(PARAM_TEXT, 'ID of the template.'),
'html' => new external_value(PARAM_RAW, 'HTML code.'),
)
),
'Templates required by the generated content.'
),
'javascript' => new external_value(PARAM_RAW, 'JavaScript code.'),
'otherdata' => new external_multiple_structure(
new external_single_structure(
array(
'name' => new external_value(PARAM_RAW, 'Field name.'),
'value' => new external_value(PARAM_RAW, 'Field value.')
)
),
'Other data that can be used or manipulated by the template via 2-way data-binding.'
),
'files' => new external_files('Files in the content.'),
'restrict' => new external_single_structure(
array(
'users' => new external_multiple_structure(
new external_value(PARAM_INT, 'user id'), 'List of allowed users.', VALUE_OPTIONAL
),
'courses' => new external_multiple_structure(
new external_value(PARAM_INT, 'course id'), 'List of allowed courses.', VALUE_OPTIONAL
),
),
'Restrict this content to certain users or courses.'
)
)
);
}
}
9 changes: 8 additions & 1 deletion admin/tool/mobile/db/services.php
Expand Up @@ -60,6 +60,13 @@
Is created only in https sites and is restricted by time and ip address.',
'type' => 'write',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
)
),
'tool_mobile_get_content' => array(
'classname' => 'tool_mobile\external',
'methodname' => 'get_content',
'description' => 'Returns a piece of content to be displayed in the Mobile app.',
'type' => 'read',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
),
);

50 changes: 50 additions & 0 deletions admin/tool/mobile/tests/externallib_test.php
Expand Up @@ -29,6 +29,7 @@
global $CFG;

require_once($CFG->dirroot . '/webservice/tests/helpers.php');
require_once($CFG->dirroot . '/admin/tool/mobile/tests/fixtures/output/mobile.php');

use tool_mobile\external;
use tool_mobile\api;
Expand Down Expand Up @@ -305,4 +306,53 @@ public function test_get_autologin_key_missing_locked() {
$this->expectExceptionMessage(get_string('autologinkeygenerationlockout', 'tool_mobile'));
$result = external::get_autologin_key($token->privatetoken);
}

/**
* Test get_content.
*/
public function test_get_content() {

$paramval = 16;
$result = external::get_content('tool_mobile', 'test_view', array(array('name' => 'param1', 'value' => $paramval)));
$result = external_api::clean_returnvalue(external::get_content_returns(), $result);
$this->assertCount(1, $result['templates']);
$this->assertCount(1, $result['otherdata']);
$this->assertCount(2, $result['restrict']['users']);
$this->assertCount(2, $result['restrict']['courses']);
$this->assertEquals('alert();', $result['javascript']);
$this->assertEquals('main', $result['templates'][0]['id']);
$this->assertEquals('The HTML code', $result['templates'][0]['html']);
$this->assertEquals('otherdata1', $result['otherdata'][0]['name']);
$this->assertEquals($paramval, $result['otherdata'][0]['value']);
$this->assertEquals(array(1, 2), $result['restrict']['users']);
$this->assertEquals(array(3, 4), $result['restrict']['courses']);
$this->assertEmpty($result['files']);
}

/**
* Test get_content non existent function in valid component.
*/
public function test_get_content_non_existent_function() {

$this->expectException('coding_exception');
$result = external::get_content('tool_mobile', 'test_blahblah');
}

/**
* Test get_content incorrect component.
*/
public function test_get_content_invalid_component() {

$this->expectException('moodle_exception');
$result = external::get_content('tool_mobile\hack', 'test_view');
}

/**
* Test get_content non existent component.
*/
public function test_get_content_non_existent_component() {

$this->expectException('moodle_exception');
$result = external::get_content('tool_blahblahblah', 'test_view');
}
}
60 changes: 60 additions & 0 deletions admin/tool/mobile/tests/fixtures/output/mobile.php
@@ -0,0 +1,60 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

/**
* Mock class for get_content.
*
* @package tool_mobile
* @copyright 2018 Juan Leyva
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

namespace tool_mobile\output;

defined('MOODLE_INTERNAL') || die;

/**
* Mock class for get_content.
*
* @package tool_mobile
* @copyright 2018 Juan Leyva
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class mobile {

/**
* Returns a test view.
* @param array $args Arguments from tool_mobile_get_content WS
*
* @return array HTML, javascript and otherdata
*/
public static function test_view($args) {
$args = (object) $args;

return array(
'templates' => array(
array(
'id' => 'main',
'html' => 'The HTML code',
),
),
'javascript' => 'alert();',
'otherdata' => array('otherdata1' => $args->param1),
'restrict' => array('users' => array(1, 2), 'courses' => array(3, 4)),
'files' => array()
);
}
}
2 changes: 1 addition & 1 deletion admin/tool/mobile/version.php
Expand Up @@ -23,7 +23,7 @@
*/

defined('MOODLE_INTERNAL') || die();
$plugin->version = 2017111300; // The current plugin version (Date: YYYYMMDDXX).
$plugin->version = 2017111301; // The current plugin version (Date: YYYYMMDDXX).
$plugin->requires = 2017110800; // Requires this Moodle version.
$plugin->component = 'tool_mobile'; // Full name of the plugin (used for diagnostics).
$plugin->dependencies = array(
Expand Down

0 comments on commit b9e6db9

Please sign in to comment.