Skip to content
Snippets Groups Projects
externallib.php 16.63 KiB
<?php
// This file is part of VPL for Moodle - http://vpl.dis.ulpgc.es/
//
// VPL for 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.
//
// VPL for 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 VPL for Moodle.  If not, see <http://www.gnu.org/licenses/>.

/**
 * @package mod_vpl
 * @copyright 2014 Juan Carlos Rodríguez-del-Pino
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 * @author Juan Carlos Rodríguez-del-Pino <jcrodriguez@dis.ulpgc.es>
 */

// TODO Organize security checks.

defined( 'MOODLE_INTERNAL' ) || die();
require_once($CFG->libdir . "/externallib.php");
require_once(dirname( __FILE__ ) . '/locallib.php');
require_once(dirname( __FILE__ ) . '/forms/edit.class.php');
require_once(dirname( __FILE__ ) . '/vpl_submission.class.php');
class mod_vpl_webservice extends external_api {
    private static function initial_checks($id, $password) {
        $vpl = new mod_vpl( $id );
        if (! $vpl->pass_network_check()) {
            throw new Exception( get_string( 'opnotallowfromclient', VPL ) . ' ' . getremoteaddr() );
        }
        if (! $vpl->pass_password_check( $password )) {
            throw new moodle_exception('requiredpassword', VPL);
        }
        return $vpl;
    }
    /*
     * info function. return information of the activity
     */
    public static function info_parameters() {
        return new external_function_parameters( array (
                'id' => new external_value( PARAM_INT, 'Activity id (course_module)', VALUE_REQUIRED ),
                'password' => new external_value( PARAM_RAW, 'Activity password', VALUE_DEFAULT, '' )
        ) );
    }
    public static function info($id, $password) {
        $params = self::validate_parameters( self::info_parameters(), array (
                'id' => $id,
                'password' => $password
        ) );
        $vpl = self::initial_checks( $id, $password );
        $vpl->require_capability( VPL_VIEW_CAPABILITY );
        if (! $vpl->is_visible()) {
            throw new Exception( get_string( 'notavailable' ) );
        }
        $instance = $vpl->get_instance();
        $ret = array (
                'name' => $instance->name,
                'shortdescription' => $instance->shortdescription,
                'intro' => $instance->intro,
                'introformat' => ( int ) $instance->introformat,
                'reqpassword' => ($instance->password > '' ? 1 : 0),
                'example' => ( int ) $instance->example,
                'restrictededitor' => ( int ) $instance->restrictededitor,
                'maxfiles' => ( int ) $instance->maxfiles,
                'reqfiles' => array (),
                'execfiles' => array (),
                'corrfiles' => array ()
        );
        $files = mod_vpl_edit::get_requested_files( $vpl );
        // Adapt array[name]=content to format array[]=array(name,data).
        $files = mod_vpl_edit::files2object( $files );
        $ret ['reqfiles'] = $files;

        $hasteacherrights = $vpl->has_capability( VPL_MANAGE_CAPABILITY );
        if ($hasteacherrights) {
            $execfiles = $vpl->get_fgm('execution')->getAllFiles();
            $ret ['execfiles'] = mod_vpl_edit::files2object( $execfiles );
            $correctedfiles = $vpl->get_fgm('corrected')->getAllFiles();
            $ret ['corrfiles'] = mod_vpl_edit::files2object( $correctedfiles );
        }
        return $ret;
    }
    public static function info_returns() {
        return new external_single_structure( array (
                'name' => new external_value( PARAM_TEXT, 'Name' ),
                'shortdescription' => new external_value( PARAM_TEXT, 'Short description' ),
                'intro' => new external_value( PARAM_RAW, 'Full description' ),
                'introformat' => new external_value( PARAM_INT, 'Description format' ),
                'reqpassword' => new external_value( PARAM_INT, 'Activity requiere password' ),
                'example' => new external_value( PARAM_INT, 'Activity is an example' ),
                'restrictededitor' => new external_value( PARAM_INT, 'Activity edition is restricted' ),
                'maxfiles' => new external_value( PARAM_INT, 'Maximum number of file acepted' ),
                'reqfiles' => new external_multiple_structure( new external_single_structure( array (
                        'name' => new external_value( PARAM_TEXT, 'File name' ),
                        'data' => new external_value( PARAM_RAW, 'File content' )
                ) ) ),
                'execfiles' => new external_multiple_structure( new external_single_structure( array (
                        'name' => new external_value( PARAM_TEXT, 'File name' ),
                        'data' => new external_value( PARAM_RAW, 'File content' )
                ) ) ),
                'corrfiles' => new external_multiple_structure( new external_single_structure( array (
                        'name' => new external_value( PARAM_TEXT, 'File name' ),
                        'data' => new external_value( PARAM_RAW, 'File content' )
                ) ) )
        ) );
    }

    /*
     * save teacher files (required, corrected and execution) function. save/submit the teacher files
     */
    public static function save_required_files_parameters() {
        return new external_function_parameters( array (
            'id' => new external_value( PARAM_INT, 'Activity id (course_module)', VALUE_REQUIRED ),
            'files' => new external_multiple_structure( new external_single_structure( array (
                'name' => new external_value( PARAM_RAW, 'File name' ),
                'data' => new external_value( PARAM_RAW, 'File content' )
            ) ) ),
            'password' => new external_value( PARAM_RAW, 'Activity password', VALUE_DEFAULT, '' )
        ) );
    }
    public static function save_required_files( $id, $files = array(), $password = '' ) {
        self::save_teacher_files( $id, $files, $password, 'required' );
    }
    public static function save_required_files_returns() {
        return null;
    }

    public static function save_corrected_files_parameters() {
        return new external_function_parameters( array (
            'id' => new external_value( PARAM_INT, 'Activity id (course_module)', VALUE_REQUIRED ),
            'files' => new external_multiple_structure( new external_single_structure( array (
                'name' => new external_value( PARAM_RAW, 'File name' ),
                'data' => new external_value( PARAM_RAW, 'File content' )
            ) ) ),
            'password' => new external_value( PARAM_RAW, 'Activity password', VALUE_DEFAULT, '' )
        ) );
    }
    public static function save_corrected_files( $id, $files = array(), $password = '' ) {
        self::save_teacher_files( $id, $files, $password, 'corrected' );
    }
    public static function save_corrected_files_returns() {
        return null;
    }

    public static function save_execution_files_parameters() {
        return new external_function_parameters( array (
            'id' => new external_value( PARAM_INT, 'Activity id (course_module)', VALUE_REQUIRED ),
            'files' => new external_multiple_structure( new external_single_structure( array (
                'name' => new external_value( PARAM_RAW, 'File name' ),
                'data' => new external_value( PARAM_RAW, 'File content' )
            ) ) ),
            'password' => new external_value( PARAM_RAW, 'Activity password', VALUE_DEFAULT, '' )
        ) );
    }
    public static function save_execution_files( $id, $files = array(), $password = '' ) {
        self::save_teacher_files( $id, $files, $password, 'execution' );
    }
    public static function save_execution_files_returns() {
        return null;
    }

    public static function save_teacher_files($id, $files = array(), $password = '', $type) {
        global $USER;
        $params = self::validate_parameters( self::save_parameters(), array (
            'id' => $id,
            'files' => $files,
            'password' => $password
        ) );
        $vpl = self::initial_checks( $id, $password );
        $vpl->require_capability( VPL_MANAGE_CAPABILITY );
        if (! $vpl->is_submit_able()) {
            throw new Exception( get_string( 'notavailable' ) );
        }
        $instance = $vpl->get_instance();
        if ($instance->example or $instance->restrictededitor) {
            throw new Exception( get_string( 'notavailable' ) );
        }
        // Adapts to the file format VPL3.2.
        $oldfiles = $files;
        $files = array();
        foreach ( $oldfiles as $file ) {
            $files [ $file['name'] ] = $file['data'];
        }
        mod_vpl_edit::save_teacher_files( $vpl, $USER->id, $files, $type );
    }


    /*
     * save function. save/submit the students files
     */
    public static function save_parameters() {
        return new external_function_parameters( array (
                'id' => new external_value( PARAM_INT, 'Activity id (course_module)', VALUE_REQUIRED ),
                'files' => new external_multiple_structure( new external_single_structure( array (
                        'name' => new external_value( PARAM_RAW, 'File name' ),
                        'data' => new external_value( PARAM_RAW, 'File content' )
                ) ) ),
                'password' => new external_value( PARAM_RAW, 'Activity password', VALUE_DEFAULT, '' )
        ) );
    }
    public static function save($id, $files = array(), $password = '') {
        global $USER;
        $params = self::validate_parameters( self::save_parameters(), array (
                'id' => $id,
                'files' => $files,
                'password' => $password
        ) );
        $vpl = self::initial_checks( $id, $password );
        $vpl->require_capability( VPL_SUBMIT_CAPABILITY );
        if (! $vpl->is_submit_able()) {
            throw new Exception( get_string( 'notavailable' ) );
        }
        $instance = $vpl->get_instance();
        if ($instance->example or $instance->restrictededitor) {
            throw new Exception( get_string( 'notavailable' ) );
        }
        // Adapts to the file format VPL3.2.
        $oldfiles = $files;
        $files = array();
        foreach ( $oldfiles as $file ) {
            $files [ $file['name'] ] = $file['data'];
        }
        mod_vpl_edit::save( $vpl, $USER->id, $files );
    }
    public static function save_returns() {
        return null;
    }

    /*
     * open function. return the student's submitted files
     */
    public static function open_parameters() {
        return new external_function_parameters( array (
                'id' => new external_value( PARAM_INT, 'Activity id (course_module)', VALUE_REQUIRED ),
                'password' => new external_value( PARAM_RAW, 'Activity password', VALUE_DEFAULT, '' )
        ) );
    }
    public static function open($id, $password) {
        global $USER;
        $params = self::validate_parameters( self::open_parameters(), array (
                'id' => $id,
                'password' => $password
        ) );
        $vpl = self::initial_checks( $id, $password );
        $vpl->require_capability( VPL_VIEW_CAPABILITY );
        if (! $vpl->is_visible()) {
            throw new Exception( get_string( 'notavailable' ) );
        }
        $files = mod_vpl_edit::get_submitted_files( $vpl, $USER->id, $compilationexecution );
        // Adapt array[name]=content to format array[]=array(name,data).
        $files = mod_vpl_edit::files2object( $files );
        $ret = array (
                'files' => $files,
                'compilation' => '',
                'evaluation' => '',
                'grade' => ''
        );
        if ($compilationexecution && $vpl->get_instance()->evaluate) {
            $ret ['compilation'] = $compilationexecution->compilation;
            $ret ['evaluation'] = $compilationexecution->evaluation;
            $ret ['grade'] = $compilationexecution->grade;
        }
        return $ret;
    }
    public static function open_returns() {
        return new external_single_structure( array (
                'files' => new external_multiple_structure( new external_single_structure( array (
                        'name' => new external_value( PARAM_TEXT, 'File name' ),
                        'data' => new external_value( PARAM_RAW, 'File content' )
                ) ) ),
                'compilation' => new external_value( PARAM_RAW, 'Compilation result' ),
                'evaluation' => new external_value( PARAM_RAW, 'Evaluation result' ),
                'grade' => new external_value( PARAM_RAW, 'Proposed or final grade' )
        ) );
    }

    /*
     * evaluate function. evaluate the student's submitted files
     */
    public static function evaluate_parameters() {
        return new external_function_parameters( array (
                'id' => new external_value( PARAM_INT, 'Activity id (course_module)', VALUE_REQUIRED ),
                'password' => new external_value( PARAM_RAW, 'Activity password', VALUE_DEFAULT, '' )
        ) );
    }
    public static function evaluate($id, $password) {
        global $USER;
        $params = self::validate_parameters( self::evaluate_parameters(), array (
                'id' => $id,
                'password' => $password
        ) );
        $vpl = self::initial_checks( $id, $password );
        $vpl->require_capability( VPL_SUBMIT_CAPABILITY );
        $instance = $vpl->get_instance();
        if (! $vpl->is_submit_able()) {
            throw new Exception( get_string( 'notavailable' ) );
        }
        if ($instance->example or $instance->restrictededitor or ! $instance->evaluate) {
            throw new Exception( get_string( 'notavailable' ) );
        }
        $ret = mod_vpl_edit::execute( $vpl, $USER->id, 'evaluate' );
        return array (
                'monitorURL' => $ret->monitorURL
        );
    }
    public static function evaluate_returns() {
        $desc = "URL to the service that monitor the evaluation in the jail server.
Protocol WebSocket may be ws: or wss: (SSL).
The jail send information as text in this format:
    (message|retrieve|close):(state(:detail)?)?
'message': the jail server reports about the changes to the client.
           With 'state' and optional 'detail?'
'retrieve': the client must get the results of the evaluation
            (call mod_vpl_get_result, the server is waiting).
'close': the conection is to be closed.
if the websocket client send something to the server then the evaluation is stopped.";
        return new external_single_structure( array (
                'monitorURL' => new external_value( PARAM_RAW, $desc )
        ) );
    }

    /*
     * get_result function. retrieve the result of the evaluation
     */
    public static function get_result_parameters() {
        return new external_function_parameters( array (
                'id' => new external_value( PARAM_INT, 'Activity id (course_module)', VALUE_REQUIRED ),
                'password' => new external_value( PARAM_RAW, 'Activity password', VALUE_DEFAULT, '' )
        ) );
    }
    public static function get_result($id, $password) {
        global $USER;
        $params = self::validate_parameters( self::get_result_parameters(), array (
                'id' => $id,
                'password' => $password
        ) );
        $vpl = self::initial_checks( $id, $password );
        $vpl->require_capability( VPL_SUBMIT_CAPABILITY );
        $instance = $vpl->get_instance();
        if (! $vpl->is_submit_able()) {
            throw new Exception( get_string( 'notavailable' ) );
        }
        if ($instance->example or $instance->restrictededitor or ! $instance->evaluate) {
            throw new Exception( get_string( 'notavailable' ) );
        }
        $compilationexecution = mod_vpl_edit::retrieve_result( $vpl, $USER->id );
        return array (
                'compilation' => $compilationexecution->compilation,
                'evaluation' => $compilationexecution->evaluation,
                'grade' => $compilationexecution->grade
        );
    }
    public static function get_result_returns() {
        return new external_single_structure( array (
                'compilation' => new external_value( PARAM_RAW, 'Compilation result' ),
                'evaluation' => new external_value( PARAM_RAW, 'Evaluation result' ),
                'grade' => new external_value( PARAM_RAW, 'Proposed or final grade' )
        ) );
    }
}