Skip to content
Snippets Groups Projects
Unverified Commit ed5a2182 authored by Hamza Remmal's avatar Hamza Remmal Committed by GitHub
Browse files

Change how credentials are stored and managed (#44)

* Add the RegistryCredentials end point in the service

* add index to moodle in intellij metadata

* Add skeleton for the webservice to download the credentials

* first draft of the file credentials in te

* remove path since we require this workflow to pass in PRs

* Send request from moodle to the autograde service to fetch the credentials

* Implement the download_credentials function

* Add credentials file options

* change description of the admin setting

* implement data_preprocessing + change the tye of the api_key input to be password

* implement the upload_credentials in function for the autograde service in moodle

* fetch the config from the file area in data_preprocessing

* Add function to fetch the credentials in the moodle service

* fix the download credentials DTO to be compatible with jackson

* Add todo note
parent 7db83237
No related branches found
No related tags found
No related merge requests found
Showing
with 517 additions and 44 deletions
......@@ -2,9 +2,6 @@ name: Spring App tests
on:
push:
paths:
- "moodle-grading-service/**"
- ".github/workflows/autograde-service-tests.yml"
jobs:
build:
......@@ -23,4 +20,4 @@ jobs:
uses: actions/upload-artifact@v3
with:
name: test-report
path: moodle-grading-service/target/surefire-reports
\ No newline at end of file
path: moodle-grading-service/target/surefire-reports
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="moodle-dev" uuid="55f0af50-0db1-4bef-8422-991545d60c56">
<driver-ref>mysql.8</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver>
<jdbc-url>jdbc:mysql://localhost:3305/moodle</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component>
</project>
\ No newline at end of file
......@@ -2,7 +2,83 @@
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/moodle/admin/presets/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/admin/roles/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/admin/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/analytics/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/auth/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/availability/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/backup/controller/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/backup/converter/moodle1/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/backup/moodle2/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/backup/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/backup/util" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/badges/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/blocks/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/blog/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/cache/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/calendar/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/cohort/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/comment/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/competency/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/completion/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/contentbank/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/course/format/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/course/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/customfield/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/enrol/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/favourites/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/files/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/filter/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/grade/grading/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/grade/import/csv/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/grade/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/group/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/h5p/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/iplookup/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/lib/behat/extension" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/lib/ddl/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/lib/dml/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/lib/editor/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/lib/external/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/lib/filebrowser/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/lib/filestorage/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/lib/form/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/lib/grade/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/lib/maxmind/MaxMind/src/MaxMind/Db" isTestSource="false" packagePrefix="MaxMind\Db\" />
<sourceFolder url="file://$MODULE_DIR$/moodle/lib/maxmind/MaxMind/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/lib/maxmind/MaxMind/tests/MaxMind/Db/Test/Reader" isTestSource="true" packagePrefix="MaxMind\Db\Test\Reader\" />
<sourceFolder url="file://$MODULE_DIR$/moodle/lib/php-jwt/src" isTestSource="false" packagePrefix="Firebase\JWT\" />
<sourceFolder url="file://$MODULE_DIR$/moodle/lib/php-jwt/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/lib/phpunit/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/lib/table/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/lib/testing" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/lib/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/lib/userkey/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/lib/xapi/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/login/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/message/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/mnet/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/my/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/notes/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/payment/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/plagiarism/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/portfolio/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/privacy/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/question/engine/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/question/engine/upgrade/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/question/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/question/type/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/rating/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/reportbuilder/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/repository/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/rss/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/search/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/tag/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/user/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/moodle/webservice/tests" isTestSource="true" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
......
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PhpProjectSharedConfiguration" php_language_level="7.4">
<option name="suggestChangeDefaultLanguageLevel" value="false" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PHPUnit">
<option name="directories">
<list>
<option value="$PROJECT_DIR$/moodle/lib/php-jwt/tests" />
<option value="$PROJECT_DIR$/moodle/lib/maxmind/MaxMind/tests" />
<option value="$PROJECT_DIR$/moodle/lib/phpunit/tests" />
<option value="$PROJECT_DIR$/moodle/lib/testing" />
<option value="$PROJECT_DIR$/moodle/lib/ddl/tests" />
<option value="$PROJECT_DIR$/moodle/lib/dml/tests" />
<option value="$PROJECT_DIR$/moodle/lib/tests" />
<option value="$PROJECT_DIR$/moodle/favourites/tests" />
<option value="$PROJECT_DIR$/moodle/lib/form/tests" />
<option value="$PROJECT_DIR$/moodle/lib/filestorage/tests" />
<option value="$PROJECT_DIR$/moodle/lib/filebrowser/tests" />
<option value="$PROJECT_DIR$/moodle/files/tests" />
<option value="$PROJECT_DIR$/moodle/filter/tests" />
<option value="$PROJECT_DIR$/moodle/admin/roles/tests" />
<option value="$PROJECT_DIR$/moodle/cohort/tests" />
<option value="$PROJECT_DIR$/moodle/lib/grade/tests" />
<option value="$PROJECT_DIR$/moodle/grade/tests" />
<option value="$PROJECT_DIR$/moodle/grade/grading/tests" />
<option value="$PROJECT_DIR$/moodle/grade/import/csv/tests" />
<option value="$PROJECT_DIR$/moodle/analytics/tests" />
<option value="$PROJECT_DIR$/moodle/availability/tests" />
<option value="$PROJECT_DIR$/moodle/backup/controller/tests" />
<option value="$PROJECT_DIR$/moodle/backup/converter/moodle1/tests" />
<option value="$PROJECT_DIR$/moodle/backup/moodle2/tests" />
<option value="$PROJECT_DIR$/moodle/backup/tests" />
<option value="$PROJECT_DIR$/moodle/backup/util" />
<option value="$PROJECT_DIR$/moodle/badges/tests" />
<option value="$PROJECT_DIR$/moodle/blog/tests" />
<option value="$PROJECT_DIR$/moodle/customfield/tests" />
<option value="$PROJECT_DIR$/moodle/iplookup/tests" />
<option value="$PROJECT_DIR$/moodle/course/tests" />
<option value="$PROJECT_DIR$/moodle/course/format/tests" />
<option value="$PROJECT_DIR$/moodle/privacy/tests" />
<option value="$PROJECT_DIR$/moodle/question/engine/tests" />
<option value="$PROJECT_DIR$/moodle/question/tests" />
<option value="$PROJECT_DIR$/moodle/question/type/tests" />
<option value="$PROJECT_DIR$/moodle/question/engine/upgrade/tests" />
<option value="$PROJECT_DIR$/moodle/cache/tests" />
<option value="$PROJECT_DIR$/moodle/calendar/tests" />
<option value="$PROJECT_DIR$/moodle/enrol/tests" />
<option value="$PROJECT_DIR$/moodle/group/tests" />
<option value="$PROJECT_DIR$/moodle/lib/external/tests" />
<option value="$PROJECT_DIR$/moodle/message/tests" />
<option value="$PROJECT_DIR$/moodle/notes/tests" />
<option value="$PROJECT_DIR$/moodle/tag/tests" />
<option value="$PROJECT_DIR$/moodle/rating/tests" />
<option value="$PROJECT_DIR$/moodle/repository/tests" />
<option value="$PROJECT_DIR$/moodle/lib/userkey/tests" />
<option value="$PROJECT_DIR$/moodle/user/tests" />
<option value="$PROJECT_DIR$/moodle/webservice/tests" />
<option value="$PROJECT_DIR$/moodle/mnet/tests" />
<option value="$PROJECT_DIR$/moodle/completion/tests" />
<option value="$PROJECT_DIR$/moodle/comment/tests" />
<option value="$PROJECT_DIR$/moodle/search/tests" />
<option value="$PROJECT_DIR$/moodle/competency/tests" />
<option value="$PROJECT_DIR$/moodle/my/tests" />
<option value="$PROJECT_DIR$/moodle/auth/tests" />
<option value="$PROJECT_DIR$/moodle/blocks/tests" />
<option value="$PROJECT_DIR$/moodle/login/tests" />
<option value="$PROJECT_DIR$/moodle/plagiarism/tests" />
<option value="$PROJECT_DIR$/moodle/portfolio/tests" />
<option value="$PROJECT_DIR$/moodle/lib/editor/tests" />
<option value="$PROJECT_DIR$/moodle/rss/tests" />
<option value="$PROJECT_DIR$/moodle/lib/table/tests" />
<option value="$PROJECT_DIR$/moodle/h5p/tests" />
<option value="$PROJECT_DIR$/moodle/lib/xapi/tests" />
<option value="$PROJECT_DIR$/moodle/contentbank/tests" />
<option value="$PROJECT_DIR$/moodle/payment/tests" />
<option value="$PROJECT_DIR$/moodle/reportbuilder/tests" />
<option value="$PROJECT_DIR$/moodle/admin/presets/tests" />
<option value="$PROJECT_DIR$/moodle/admin/tests" />
</list>
</option>
</component>
</project>
\ No newline at end of file
......@@ -12,9 +12,12 @@ use stdClass;
*/
final class autograde_webservice {
private $api_key;
private string $api_key;
public function __construct($api_key) {
/**
* @param string $api_key ???
*/
public function __construct(string $api_key) {
$this->api_key = $api_key;
}
......@@ -98,6 +101,46 @@ final class autograde_webservice {
return $r;
}
/**
* ???
* @param $courseid ???
* @param $assignmentid
* @return stdClass ???
* @throws dml_exception
*/
public function upload_credentials($courseid, $assignmentid): stdClass {
// HR : Build the URL for the grade function
$url = $this->url('/api/v1/registry/credentials/upload');
// HR : Prepare the request body (JSON)
$body = array(
'courseid' => $courseid,
'assignmentid' => $assignmentid,
);
// HR : Prepare the headers
$headers = [
$this->api_key_header($this->api_key),
'Content-Type: application/json'
];
// HR : Prepare cURL options
$options = array(
CURLOPT_URL => $url,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($body),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => $headers
);
// HR : Send request using cURL
$curl = curl_init();
curl_setopt_array($curl, $options);
$response = curl_exec($curl);
curl_close($curl);
// Return the response
$r = new stdClass();
$r->response = $response;
$r->info = curl_getinfo($curl);
return $r;
}
// ============================================================================================
// =================================== HELPER METHODS =========================================
// ============================================================================================
......
<?php
namespace assignsubmission_autograde\external;
use coding_exception;
use context_course;
use external_api;
use external_function_parameters;
use external_single_structure;
use external_value;
use moodle_exception;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->libdir . '/externallib.php');
require_once($CFG->dirroot . '/mod/assign/locallib.php');
/**
* ???
*
* @author Hamza REMMAL (hamza.remmal@epfl.ch)
*/
final class autograde_download_credentials extends external_api {
/**
* ???
* @return external_function_parameters ???
*/
public static function download_credentials_parameters(): external_function_parameters {
return new external_function_parameters([
'courseid' => new external_value(PARAM_INT, 'Course ID'),
'assignmentid' => new external_value(PARAM_INT, 'Assignment ID')
]);
}
/**
* ???
* @param $courseid ???
* @param $assignmentid ???
* @return object ???
* @throws coding_exception ???
* @throws moodle_exception ???
*/
public static function download_credentials($courseid, $assignmentid): object {
$context = context_course::instance($courseid);
$component = 'assignsubmission_autograde';
$filearea = 'credentials';
$fs = get_file_storage();
$files = $fs->get_area_files(
$context->id,
$component,
$filearea,
0,
'itemid, filepath, filename',
false
);
// HR : Check if files are found
if (!empty($files)) {
// HR : Iterate over al the available files
foreach ($files as $file){
// HR : If we find a non-empty file, return it
// HR : We allow only one file for now
if(!empty($file->get_content())){
// HR : Return the base64 encoding of the file's content
return (object) [
'content' => base64_encode($file->get_content())
];
}
}
} else {
// No files found, return an error
throw new moodle_exception('nofilefound', 'autograde');
}
throw new moodle_exception('all files are empty', 'autograde');
}
/**
* ???
* @return external_single_structure ???
*/
public static function download_credentials_returns(): external_single_structure{
return new external_single_structure([
'content' => new external_value(PARAM_TEXT, 'File Content')
]);
}
}
\ No newline at end of file
......@@ -18,6 +18,12 @@ $functions = [
'description' => 'Download an autograde submission',
//'capabilities' => '',
],
'mod_assignsubmission_autograde_download_credentials' => [
'classname' => 'assignsubmission_autograde\external\autograde_download_credentials',
'methodname' => 'download_credentials',
'description' => 'Download an autograde credential',
//'capabilities' => '',
],
];
// https://moodledev.io/docs/apis/subsystems/external/advanced/custom-services
......@@ -26,7 +32,8 @@ $services = [
'AUTOGRADE' => [
'functions' => [
'mod_assignsubmission_autograde_upload_feedback',
'mod_assignsubmission_autograde_download_submission'
'mod_assignsubmission_autograde_download_submission',
'mod_assignsubmission_autograde_download_credentials'
],
'restrictedusers' => 1,
'enabled' => 1,
......
......@@ -7,6 +7,8 @@ defined('MOODLE_INTERNAL') || die();
const ASSIGNSUBMISSION_AUTOGRADE_SUBMISSION_FILEAREA = 'submissions';
const ASSIGNSUBMISSION_AUTOGRADE_CREDENTIALS_FILEAREA = 'credentials';
/**
* Autograde Submission plugin.
*
......@@ -65,24 +67,17 @@ final class assign_submission_autograde extends assign_submission_plugin {
'assignsubmission_autograde_enabled',
'notchecked');
// HR : Add text input to store the docker registry token
$mform->addElement(
"text",
self::setting_docker_registry_token_id,
get_string("setting_docker-registry-token", self::COMPONENT_NAME),
null);
$mform->addHelpButton(
self::setting_docker_registry_token_id,
"setting_docker-registry-token",
self::COMPONENT_NAME);
// HR : Add filemanager to store the docker registry token
$credentials_options = $this->get_credentials_option();
$mform->addElement("filemanager", "credentials", "Registry Credentials", null, $credentials_options);
$mform->hideIf(
self::setting_docker_registry_token_id,
'credentials',
'assignsubmission_autograde_enabled',
'notchecked');
// HR : Add entry to store the API_KEY
$mform->addElement(
"text",
"password",
self::setting_webservice_key_id,
get_string("setting_webservice-key", self::COMPONENT_NAME),
null);
......@@ -102,30 +97,41 @@ final class assign_submission_autograde extends assign_submission_plugin {
* @note See documentation : https://moodledev.io/docs/apis/plugintypes/assign/submission#save_settings
* @param stdClass $data ???
* @return bool ???
* @throws dml_exception ???
* @throws coding_exception
* @throws dml_exception
*/
public function save_settings(stdClass $data): bool {
// HR : Store the Docker image in the configuration
global $COURSE;
$this->set_config(self::setting_docker_image_id, $data->docker_image);
// HR : Store the Docker registry token in the configuration
$this->set_config(self::setting_docker_registry_token_id, $data->docker_registry_token);
// HR : Store the WebService API_KEY in the configuration setting
$this->set_config(self::setting_webservice_key_id, $data->webservice_key);
// HR : Ping the server with the API_KEY to verify that the key is working
// NOTE HR : a timeout need to be set, and it should be small so that this function doesn't
// block that long
// HR : Save the credentials in the corresponding file area
file_save_draft_area_files(
$data->credentials,
context_course::instance($COURSE->id)->id,
self::COMPONENT_NAME,
ASSIGNSUBMISSION_AUTOGRADE_CREDENTIALS_FILEAREA,
0
);
// HR : Send request to the autograde service to update the credentials
// HR : also test the API_KEY
$autograde_webservice = new autograde_webservice($this->get_config(self::setting_webservice_key_id));
$response = $autograde_webservice->ping(1, true);
$response = $autograde_webservice->upload_credentials($COURSE->id, $this->assignment->get_instance()->id);
// HR : Analyze the response
if($response === false){
$this->set_error('Request failed (Server not responding)!');
return false;
} else if ($response['http_code'] == 200){
notification::info('The provided API_KEY is valid !');
} else if ($response['http_code'] == 403){
if ($response->info['http_code'] == 200){
notification::info('The credentials were correctly updated in the service');
} else if ($response->info['http_code'] == 403) {
$this->set_error('The provided API_KEY is not valid !');
return false;
} else if($response->info['http_code'] == 500){
$this->set_error("internal error : " . $response->response);
return false;
} else if($response->info['http_code'] == 0){
$this->set_error("autograde service not found. please contact the support.");
return false;
}
return true;
}
......@@ -136,7 +142,26 @@ final class assign_submission_autograde extends assign_submission_plugin {
* @return void ???
*/
public function data_preprocessing(&$defaultvalues) {
// TODO HR : Implement this function
// HR : Call the parent function
global $COURSE;
parent::data_preprocessing($defaultvalues);
// HR : Fill in the docker image setting if it was previously filled
$defaultvalues[self::setting_docker_image_id] =
$this->get_config(self::setting_docker_image_id);
// HR : Fill in the API-KEY setting if it was previously filled
$defaultvalues[self::setting_webservice_key_id] =
$this->get_config(self::setting_webservice_key_id);
$draftitemid = file_get_submitted_draft_itemid('credentials');
file_prepare_draft_area(
$draftitemid,
context_course::instance($COURSE->id)->id,
self::COMPONENT_NAME,
ASSIGNSUBMISSION_AUTOGRADE_CREDENTIALS_FILEAREA,
0,
$this->get_credentials_option()
);
$defaultvalues['credentials'] = $draftitemid;
}
// ============================================================================================
......@@ -160,7 +185,7 @@ final class assign_submission_autograde extends assign_submission_plugin {
$userid): bool {
global $COURSE;
// HR : Accepted files
$fileoptions = $this->get_file_options();
$fileoptions = $this->get_submission_options();
// HR : Prepare the filemanager for the submission
$data = file_prepare_standard_filemanager(
......@@ -200,7 +225,7 @@ final class assign_submission_autograde extends assign_submission_plugin {
// HR : Without this step, the download_submission webservice won't work
$data = file_postupdate_standard_filemanager($data,
'tasks',
$this->get_file_options(),
$this->get_submission_options(),
context_course::instance($COURSE->id),
self::COMPONENT_NAME,
ASSIGNSUBMISSION_AUTOGRADE_SUBMISSION_FILEAREA,
......@@ -270,10 +295,14 @@ final class assign_submission_autograde extends assign_submission_plugin {
return $result;
}
/**
* ???
* @return string[] ???
*/
public function get_file_areas(): array {
// TODO HR : Implement this function
return array(
ASSIGNSUBMISSION_AUTOGRADE_SUBMISSION_FILEAREA => "store the submissions"
ASSIGNSUBMISSION_AUTOGRADE_SUBMISSION_FILEAREA => "store the submissions",
ASSIGNSUBMISSION_AUTOGRADE_CREDENTIALS_FILEAREA => "store the credentials"
);
}
......@@ -285,10 +314,9 @@ final class assign_submission_autograde extends assign_submission_plugin {
* View of the summary (visible by the student)
*
* @note See documentation : https://moodledev.io/docs/apis/plugintypes/assign/submission#view_summary
* @param stdClass $submissionorgrade
* @param bool &$showviewlink
* @return string
* @throws coding_exception
* @param $submission ???
* @param bool &$showviewlink ???
* @return string ???
*/
public function view_summary($submission, &$showviewlink): string {
// TODO HR : 1- Fetch the path to the file to render from the database
......@@ -342,7 +370,7 @@ final class assign_submission_autograde extends assign_submission_plugin {
*
* @return array ???
*/
private function get_file_options(): array{
private function get_submission_options(): array{
return array(
'subdirs' => 1,
"maxfiles" => 1,
......@@ -351,4 +379,13 @@ final class assign_submission_autograde extends assign_submission_plugin {
);
}
private function get_credentials_option() : array {
return array(
'subdirs' => 1,
"maxfiles" => 1,
'accepted_types' => array(".config"),
'return_types' => FILE_INTERNAL | FILE_EXTERNAL
);
}
}
\ No newline at end of file
......@@ -5,6 +5,6 @@ defined('MOODLE_INTERNAL') || die();
$settings->add(
new admin_setting_configtext("assignsubmission_autograde/service_url",
"Service URL",
"URL to the kubernetes cluster hosting the service",
"URL to the autograde service",
"")
);
\ No newline at end of file
package ch.epfl.cs107.grading.moodle.api.v1.controller;
import ch.epfl.cs107.grading.moodle.api.v1.dto.UploadCredentialsDTO;
import ch.epfl.cs107.grading.moodle.api.v1.service.KubernetesJobService;
import ch.epfl.cs107.grading.moodle.api.v1.service.MoodleWebService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* ???
*
* @author Hamza REMMAL (hamza.remmal@epfl.ch)
*/
@RestController
@RequestMapping("/api/v1/registry/credentials")
public final class RegistryCredentialsController {
/** ??? */
private final KubernetesJobService k8s;
/** ??? */
private final MoodleWebService moodle;
/**
* ???
* @param k8s ???
*/
@Autowired
public RegistryCredentialsController(KubernetesJobService k8s, MoodleWebService moodle) {
this.k8s = k8s;
this.moodle = moodle;
}
/**
* ???
* @return ???
*/
@PostMapping("/upload")
public ResponseEntity<?> uploadCredentials(@RequestBody UploadCredentialsDTO credentials){
try(var cred = moodle.download_credentials(credentials.getCourseid(), credentials.getAssignmentid())){
// TODO : Use k8s to store the credentials in the corresponding namespace in the cluster
return ResponseEntity.ok().body(null);
} catch (Exception e){
return ResponseEntity.internalServerError().body(e);
}
}
}
package ch.epfl.cs107.grading.moodle.api.v1.dto;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* ???
*
* @author Hamza REMMAL (hamza.remmal@epfl.ch)
*/
@Data
public class DownloadCredentialsDTO {
/** ??? */
private final String content;
@JsonCreator
public DownloadCredentialsDTO(@JsonProperty("content") String content) {
this.content = content;
}
}
package ch.epfl.cs107.grading.moodle.api.v1.dto;
import lombok.Data;
/**
* ???
*
* @author Hamza REMMAL (hamza.remmal@epfl.ch)
*/
@Data
public final class UploadCredentialsDTO {
/** ???? */
private final int courseid;
private final int assignmentid;
}
package ch.epfl.cs107.grading.moodle.api.v1.service;
import ch.epfl.cs107.grading.moodle.api.v1.dto.DownloadCredentialsDTO;
import ch.epfl.cs107.grading.moodle.api.v1.dto.DownloadSubmissionDTO;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Value;
......@@ -154,4 +155,34 @@ public final class MoodleWebService {
}
}
/**
* ???
* @param courseid ???
* @param assignmentid ???
* @return ???
* @throws URISyntaxException ???
* @throws IOException ???
* @throws InterruptedException ???
*/
public InputStream download_credentials(int courseid, int assignmentid) throws URISyntaxException, IOException, InterruptedException {
final var FUNCTION_NAME = "mod_assignsubmission_autograde_download_credentials";
final var params = new HashMap<String, Object>();
params.put("courseid", courseid);
params.put("assignmentid", assignmentid);
var response = call(FUNCTION_NAME, params, ofString());
System.out.println(response.body());
var objectMapper = new ObjectMapper();
var submission = objectMapper.readValue(response.body(), DownloadCredentialsDTO.class);
if(response.statusCode() != HttpStatus.OK.value()){
throw new IllegalStateException(submission.getContent());
} else {
return new ByteArrayInputStream(Base64.getDecoder().decode(submission.getContent()));
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment