Skip to content

Commit

Permalink
MDL-28646 Web service: core_course_get_contents()
Browse files Browse the repository at this point in the history
1. Implement core_course_get_contents web service
2. Implement callbacks in folder, resource, page and url modules
3. Implement download script for web service
  • Loading branch information
Dongsheng Cai authored and mouneyrac committed Nov 28, 2011
1 parent 1de9151 commit ec0d6ea
Show file tree
Hide file tree
Showing 13 changed files with 1,354 additions and 768 deletions.
205 changes: 204 additions & 1 deletion course/externallib.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,209 @@
*/
class core_course_external extends external_api {

/**
* Returns description of method parameters
* @return external_function_parameters
*/
public static function get_course_contents_parameters() {
return new external_function_parameters(
array('courseid' => new external_value(PARAM_INT, 'course id'),
'options' => new external_multiple_structure (
new external_single_structure(
array('name' => new external_value(PARAM_ALPHANUM, 'option name'),
'value' => new external_value(PARAM_RAW, 'the value of the option, this param is personaly validated in the external function.')
)
), 'Options, not used yet, might be used in later version', VALUE_DEFAULT, array())
)
);
}

/**
* Get course contents
* @param int $courseid
* @param array $options, not used yet, might be used in later version
* @return array
*/
public static function get_course_contents($courseid, $options) {
global $CFG, $DB;
require_once($CFG->dirroot . "/course/lib.php");

//validate parameter
$params = self::validate_parameters(self::get_course_contents_parameters(),
array('courseid' => $courseid, 'options' => $options));

//retrieve the course
$course = $DB->get_record('course', array('id' => $params['courseid']), '*', MUST_EXIST);

//check course format exist
if (!file_exists($CFG->dirroot . '/course/format/' . $course->format . '/lib.php')) {
throw new moodle_exception('cannotgetcoursecontents', 'webservice', '', null, get_string('courseformatnotfound', 'error', '', $course->format));
} else {
require_once($CFG->dirroot . '/course/format/' . $course->format . '/lib.php');
}

// now security checks
$context = get_context_instance(CONTEXT_COURSE, $course->id);
try {
self::validate_context($context);
} catch (Exception $e) {
$exceptionparam = new stdClass();
$exceptionparam->message = $e->getMessage();
$exceptionparam->courseid = $course->id;
throw new moodle_exception('errorcoursecontextnotvalid', 'webservice', '', $exceptionparam);
}

$canupdatecourse = has_capability('moodle/course:update', $context);

//create return value
$coursecontents = array();

if ($canupdatecourse or $course->visible
or has_capability('moodle/course:viewhiddencourses', $context)) {

//retrieve sections
$modinfo = get_fast_modinfo($course);
$sections = get_all_sections($course->id);

//for each sections (first displayed to last displayed)
foreach ($sections as $key => $section) {

$showsection = (has_capability('moodle/course:viewhiddensections', $context) or $section->visible or !$course->hiddensections);
if (!$showsection) {
continue;
}

// reset $sectioncontents
$sectionvalues = array();
$sectionvalues['id'] = $section->id;
$sectionvalues['name'] = get_section_name($course, $section);
$summary = file_rewrite_pluginfile_urls($section->summary, 'webservice/pluginfile.php', $context->id, 'course', 'section', $section->id);
$sectionvalues['visible'] = $section->visible;
$sectionvalues['summary'] = format_text($summary, $section->summaryformat);
$sectioncontents = array();

//for each module of the section
foreach ($modinfo->sections[$section->section] as $cmid) { //matching /course/lib.php:print_section() logic
$cm = $modinfo->cms[$cmid];

// stop here if the module is not visible to the user
if (!$cm->uservisible) {
continue;
}

$module = array();

//common info (for people being able to see the module or availability dates)
$module['id'] = $cm->id;
$module['name'] = format_string($cm->name, true);
$module['modname'] = $cm->modname;
$module['modplural'] = $cm->modplural;
$module['modicon'] = $cm->get_icon_url()->out(false);
$module['indent'] = $cm->indent;

$modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);

if (!empty($cm->showdescription)) {
$module['description'] = $cm->get_content();
}

//url of the module
$url = $cm->get_url();
if ($url) { //labels don't have url
$module['url'] = $cm->get_url()->out();
}

$canviewhidden = has_capability('moodle/course:viewhiddenactivities',
get_context_instance(CONTEXT_MODULE, $cm->id));
//user that can view hidden module should know about the visibility
$module['visible'] = $cm->visible;

//availability date (also send to user who can see hidden module when the showavailabilyt is ON)
if ($canupdatecourse or ($CFG->enableavailability && $canviewhidden && $cm->showavailability)) {
$module['availablefrom'] = $cm->availablefrom;
$module['availableuntil'] = $cm->availableuntil;
}

$baseurl = 'webservice/pluginfile.php';

//call $modulename_export_contents
//(each module callback take care about checking the capabilities)
require_once($CFG->dirroot . '/mod/' . $cm->modname . '/lib.php');
$getcontentfunction = $cm->modname.'_export_contents';
if (function_exists($getcontentfunction)) {
if ($contents = $getcontentfunction($cm, $baseurl)) {
$module['contents'] = $contents;
}
}

//assign result to $sectioncontents
$sectioncontents[] = $module;

}
$sectionvalues['modules'] = $sectioncontents;

// assign result to $coursecontents
$coursecontents[] = $sectionvalues;
}
}
return $coursecontents;
}

/**
* Returns description of method result value
* @return external_description
*/
public static function get_course_contents_returns() {
return new external_multiple_structure(
new external_single_structure(
array(
'id' => new external_value(PARAM_INT, 'Section ID'),
'name' => new external_value(PARAM_TEXT, 'Section name'),
'visible' => new external_value(PARAM_INT, 'is the section visible', VALUE_OPTIONAL),
'summary' => new external_value(PARAM_RAW, 'Section description'),
'modules' => new external_multiple_structure(
new external_single_structure(
array(
'id' => new external_value(PARAM_INT, 'activity id'),
'url' => new external_value(PARAM_URL, 'activity url', VALUE_OPTIONAL),
'name' => new external_value(PARAM_TEXT, 'activity module name'),
'description' => new external_value(PARAM_RAW, 'activity description', VALUE_OPTIONAL),
'visible' => new external_value(PARAM_INT, 'is the module visible', VALUE_OPTIONAL),
'modicon' => new external_value(PARAM_URL, 'activity icon url'),
'modname' => new external_value(PARAM_PLUGIN, 'activity module type'),
'modplural' => new external_value(PARAM_TEXT, 'activity module plural name'),
'availablefrom' => new external_value(PARAM_INT, 'module availability start date', VALUE_OPTIONAL),
'availableuntil' => new external_value(PARAM_INT, 'module availability en date', VALUE_OPTIONAL),
'indent' => new external_value(PARAM_INT, 'number of identation in the site'),
'contents' => new external_multiple_structure(
new external_single_structure(
array(
// content info
'type'=> new external_value(PARAM_TEXT, 'a file or a folder or external link'),
'filename'=> new external_value(PARAM_FILE, 'filename'),
'filepath'=> new external_value(PARAM_PATH, 'filepath'),
'filesize'=> new external_value(PARAM_INT, 'filesize'),
'fileurl' => new external_value(PARAM_URL, 'downloadable file url', VALUE_OPTIONAL),
'content' => new external_value(PARAM_RAW, 'Raw content, will be used when type is content', VALUE_OPTIONAL),
'timecreated' => new external_value(PARAM_INT, 'Time created'),
'timemodified' => new external_value(PARAM_INT, 'Time modified'),
'sortorder' => new external_value(PARAM_INT, 'Content sort order'),

// copyright related info
'userid' => new external_value(PARAM_INT, 'User who added this content to moodle'),
'author' => new external_value(PARAM_TEXT, 'Content owner'),
'license' => new external_value(PARAM_TEXT, 'Content license'),
)
), VALUE_DEFAULT, array()
)
)
), 'list of module'
)
)
)
);
}

/**
* Returns description of method parameters
* @return external_function_parameters
Expand Down Expand Up @@ -430,4 +633,4 @@ public static function create_courses_returns() {
return core_course_external::create_courses_returns();
}

}
}
1 change: 1 addition & 0 deletions lang/en/error.php
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@
$string['couldnotupdatenoexistinguser'] = 'Cannot update the user - user doesn\'t exist';
$string['countriesphpempty'] = 'Error: The file countries.php in language pack {$a} is empty or missing.';
$string['coursedoesnotbelongtocategory'] = 'The course doesn\'t belong to this category';
$string['courseformatnotfound'] = 'The course format \'{$a}\' doesn\'t exist or is not recognized';
$string['coursegroupunknown'] = 'Course corresponding to group {$a} not specified';
$string['courseidnotfound'] = 'Course id doesn\'t exist';
$string['coursemisconf'] = 'Course is misconfigured';
Expand Down
3 changes: 3 additions & 0 deletions lang/en/webservice.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
$string['arguments'] = 'Arguments';
$string['authmethod'] = 'Authentication method';
$string['cannotcreatetoken'] = 'No permission to create web service token for the service {$a}.';
$string['cannotgetcoursecontents'] = 'Cannot get course contents';
$string['configwebserviceplugins'] = 'For security reasons, only protocols that are in use should be enabled.';
$string['context'] = 'Context';
$string['createservicedescription'] = 'A service is a set of web service functions. You will allow the user to access to a new service. On the <strong>Add service</strong> page check \'Enable\' and \'Authorised users\' options. Select \'No required capability\'.';
Expand Down Expand Up @@ -74,6 +75,7 @@
$string['enableprotocolsdescription'] = 'At least one protocol should be enabled. For security reasons, only protocols that are to be used should be enabled.';
$string['enablews'] = 'Enable web services';
$string['enablewsdescription'] = 'Web services must be enabled in Advanced features.';
$string['enabledirectdownload'] = 'Web service file downloading must be enabled in external service settings';
$string['entertoken'] = 'Enter a security key/token:';
$string['error'] = 'Error: {$a}';
$string['errorcatcontextnotvalid'] = 'You cannot execute functions in the category context (category id:{$a->catid}). The context error message was: {$a->message}';
Expand Down Expand Up @@ -177,6 +179,7 @@
$string['tokenauthlog'] = 'Token authentication';
$string['tokencreatedbyadmin'] = 'Can only be reset by administrator (*)';
$string['tokencreator'] = 'Creator';
$string['unknownoptionkey'] = 'Unknown option key ({$a})';
$string['updateusersettings'] = 'Update';
$string['userasclients'] = 'Users as clients with token';
$string['userasclientsdescription'] = 'The following steps help you to set up the Moodle web service for users as clients. These steps also help to set up the recommended token (security keys) authentication method. In this use case, the user will generate his token from the security keys page via My profile settings.';
Expand Down
12 changes: 11 additions & 1 deletion lib/db/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,15 @@
'capabilities'=> 'moodle/course:create,moodle/course:visibility',
),

'core_course_get_contents' => array(
'classname' => 'core_course_external',
'methodname' => 'get_course_contents',
'classpath' => 'course/externallib.php',
'description' => 'Get course contents',
'type' => 'read',
'capabilities'=> 'moodle/course:update,moodle/course:viewhiddencourses',
),

// === message related functions ===

'moodle_message_send_instantmessages' => array(
Expand Down Expand Up @@ -474,7 +483,8 @@
'moodle_notes_create_notes',
'moodle_user_get_course_participants_by_id',
'moodle_user_get_users_by_courseid',
'moodle_message_send_instantmessages'),
'moodle_message_send_instantmessages',
'core_course_get_contents'),
'enabled' => 0,
'restrictedusers' => 0,
'shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE,
Expand Down
Loading

0 comments on commit ec0d6ea

Please sign in to comment.