From ed5a2182a1a06cbb132cca4429b94e01ed81b854 Mon Sep 17 00:00:00 2001
From: Hamza Remmal <56235032+hamzaremmal@users.noreply.github.com>
Date: Tue, 18 Jul 2023 17:51:13 +0100
Subject: [PATCH] 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
---
 .github/workflows/autograde-service-tests.yml |   5 +-
 .idea/dataSources.xml                         |  12 ++
 .idea/moodle-autograde.iml                    |  78 ++++++++++++-
 .idea/php.xml                                 |   6 +
 .idea/phpunit.xml                             |  80 +++++++++++++
 .../classes/autograde_webservice.php          |  47 +++++++-
 .../autograde_download_credentials.php        |  90 +++++++++++++++
 .../db/services.php                           |   9 +-
 .../locallib.php                              | 107 ++++++++++++------
 .../settings.php                              |   2 +-
 .../RegistryCredentialsController.java        |  52 +++++++++
 .../api/v1/dto/DownloadCredentialsDTO.java    |  23 ++++
 .../api/v1/dto/UploadCredentialsDTO.java      |  19 ++++
 .../api/v1/service/MoodleWebService.java      |  31 +++++
 14 files changed, 517 insertions(+), 44 deletions(-)
 create mode 100644 .idea/dataSources.xml
 create mode 100644 .idea/php.xml
 create mode 100644 .idea/phpunit.xml
 create mode 100644 moodle-assignsubmission-autograde/classes/external/autograde_download_credentials.php
 create mode 100644 moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/controller/RegistryCredentialsController.java
 create mode 100644 moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/dto/DownloadCredentialsDTO.java
 create mode 100644 moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/dto/UploadCredentialsDTO.java

diff --git a/.github/workflows/autograde-service-tests.yml b/.github/workflows/autograde-service-tests.yml
index 5c56afda..b861b07e 100644
--- a/.github/workflows/autograde-service-tests.yml
+++ b/.github/workflows/autograde-service-tests.yml
@@ -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
diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml
new file mode 100644
index 00000000..039b9aa0
--- /dev/null
+++ b/.idea/dataSources.xml
@@ -0,0 +1,12 @@
+<?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
diff --git a/.idea/moodle-autograde.iml b/.idea/moodle-autograde.iml
index d6ebd480..1fb44a34 100644
--- a/.idea/moodle-autograde.iml
+++ b/.idea/moodle-autograde.iml
@@ -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>
diff --git a/.idea/php.xml b/.idea/php.xml
new file mode 100644
index 00000000..0e09af40
--- /dev/null
+++ b/.idea/php.xml
@@ -0,0 +1,6 @@
+<?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
diff --git a/.idea/phpunit.xml b/.idea/phpunit.xml
new file mode 100644
index 00000000..d8758d74
--- /dev/null
+++ b/.idea/phpunit.xml
@@ -0,0 +1,80 @@
+<?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
diff --git a/moodle-assignsubmission-autograde/classes/autograde_webservice.php b/moodle-assignsubmission-autograde/classes/autograde_webservice.php
index 875aba0e..cc7b9058 100644
--- a/moodle-assignsubmission-autograde/classes/autograde_webservice.php
+++ b/moodle-assignsubmission-autograde/classes/autograde_webservice.php
@@ -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 =========================================
     // ============================================================================================
diff --git a/moodle-assignsubmission-autograde/classes/external/autograde_download_credentials.php b/moodle-assignsubmission-autograde/classes/external/autograde_download_credentials.php
new file mode 100644
index 00000000..ccffa273
--- /dev/null
+++ b/moodle-assignsubmission-autograde/classes/external/autograde_download_credentials.php
@@ -0,0 +1,90 @@
+<?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
diff --git a/moodle-assignsubmission-autograde/db/services.php b/moodle-assignsubmission-autograde/db/services.php
index 1c59d829..5b5181e5 100644
--- a/moodle-assignsubmission-autograde/db/services.php
+++ b/moodle-assignsubmission-autograde/db/services.php
@@ -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,
diff --git a/moodle-assignsubmission-autograde/locallib.php b/moodle-assignsubmission-autograde/locallib.php
index 7ef0c5a2..29d41f20 100644
--- a/moodle-assignsubmission-autograde/locallib.php
+++ b/moodle-assignsubmission-autograde/locallib.php
@@ -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
diff --git a/moodle-assignsubmission-autograde/settings.php b/moodle-assignsubmission-autograde/settings.php
index 02330bb5..a815f99f 100644
--- a/moodle-assignsubmission-autograde/settings.php
+++ b/moodle-assignsubmission-autograde/settings.php
@@ -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
diff --git a/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/controller/RegistryCredentialsController.java b/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/controller/RegistryCredentialsController.java
new file mode 100644
index 00000000..c02c41a1
--- /dev/null
+++ b/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/controller/RegistryCredentialsController.java
@@ -0,0 +1,52 @@
+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);
+        }
+    }
+
+}
diff --git a/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/dto/DownloadCredentialsDTO.java b/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/dto/DownloadCredentialsDTO.java
new file mode 100644
index 00000000..ebb9d6f3
--- /dev/null
+++ b/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/dto/DownloadCredentialsDTO.java
@@ -0,0 +1,23 @@
+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;
+    }
+
+}
diff --git a/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/dto/UploadCredentialsDTO.java b/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/dto/UploadCredentialsDTO.java
new file mode 100644
index 00000000..e1c2bd78
--- /dev/null
+++ b/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/dto/UploadCredentialsDTO.java
@@ -0,0 +1,19 @@
+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;
+
+
+}
diff --git a/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/service/MoodleWebService.java b/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/service/MoodleWebService.java
index 6aaffa67..8aba0021 100644
--- a/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/service/MoodleWebService.java
+++ b/moodle-grading-service/src/main/java/ch/epfl/cs107/grading/moodle/api/v1/service/MoodleWebService.java
@@ -1,5 +1,6 @@
 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()));
+        }
+    }
+
 }
-- 
GitLab