Skip to content
Snippets Groups Projects
Verified Commit 336b341f authored by Hamza Remmal's avatar Hamza Remmal :homes:
Browse files

chore: add support to get the grade from Moodle

parent dbb15451
No related branches found
No related tags found
1 merge request!302Draft: Add the possibility to get the grade and feedback in the api
Pipeline #256184 passed
......@@ -5,7 +5,7 @@
<driver-ref>mysql.8</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver>
<jdbc-url>jdbc:mysql://localhost:3306/moodle</jdbc-url>
<jdbc-url>jdbc:mysql://localhost:3305/moodle</jdbc-url>
<jdbc-additional-properties>
<property name="com.intellij.clouds.kubernetes.db.host.port" />
<property name="com.intellij.clouds.kubernetes.db.enabled" value="false" />
......
<?php
// This file is part of Moodle - https://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <https://www.gnu.org/licenses/>.
/**
* This file defines the function to get the grade of a submission
*
* @see https://moodledev.io/docs/apis/subsystems/external/functions
* @author ???
* @package ???
* @copyright 2023 AUTOGRADE-EPFL <autograde-support@groupes.epfl.ch>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace assignsubmission_autograde\external;
defined('MOODLE_INTERNAL') || die();
use external_api;
use external_function_parameters;
use external_single_structure;
use external_value;
use context_course;
use moodle_exception;
use stdClass;
use assign_submission;
use function assignsubmission_autograde\utils\assignsubmission_autograde_get_assignment;
require_once(__DIR__.'/../../lib.php');
require_once(__DIR__.'/../../utils.php');
require_once($CFG->libdir . '/externallib.php');
require_once($CFG->dirroot . '/mod/assign/locallib.php');
final class autograde_get_grade extends external_api {
/**
* Define the function parameters
* @return external_function_parameters
*/
public static function get_grade_parameters(): external_function_parameters {
return new external_function_parameters([
'sid' => new external_value(PARAM_INT, 'The ID of the submission'),
]);
}
/**
* Retrieve the grade for a submission
* @param int $sid
* @return stdClass
* @throws moodle_exception
*/
public static function get_grade($sid): stdClass {
global $DB, $USER;
self::validate_parameters(self::get_grade_parameters(), ['sid' => $sid]);
$submission = $DB->get_record('assign_submission', [ 'id' => $sid ]);
$assignment = $DB->get_record('assign', [ 'id' => $submission->assignment ]);
require_capability('assignsubmission/autograde:viewgrades',
context_course::instance($assignment->course), $USER->id, false);
$grade = $DB->get_field('assign_grades', 'grade', ['assignment' => $assignment->id, 'attemptnumber' => $submission->attemptnumber]);
if (!$grade) {
throw new moodle_exception('Grade not found');
}
$result = new stdClass();
$result->grade = $grade;
return $result;
}
/**
* Define the return structure
* @return external_single_structure
*/
public static function get_grade_returns(): external_single_structure {
return new external_single_structure([
'grade' => new external_value(PARAM_FLOAT, 'The grade'),
]);
}
}
\ No newline at end of file
......@@ -36,6 +36,12 @@ $capabilities = array(
'clonepermissionsfrom' => 'mod/assign/submission/autograde:read_submission'
),
'assignsubmission/autograde:viewgrades' => array(
'riskbitmask' => RISK_PERSONAL,
'captype' => 'read',
'contextlevel' => CONTEXT_COURSE,
'archetypes' => array(),
),
// HR : Capability to write a feedback
'assignsubmission/autograde:grade' => array(
'riskbitmask' => RISK_SPAM | RISK_XSS,
......
......@@ -52,6 +52,12 @@ $functions = [
'description' => 'List all of the information for a given submission',
'capabilities' => 'assignsubmission/autograde:viewsubmission'
],
'mod_assignsubmission_autograde_get_grade' => [
'classname' => 'assignsubmission_autograde\external\autograde_get_grade' ,
'methodname' => 'get_grade',
'description' => 'Get the Grade of a Given Submission',
'capabilities' => 'assignsubmission/autograde:viewgrades'
],
'mod_assignsubmission_autograde_download_all_submissions' => [
'classname' => 'assignsubmission_autograde\external\autograde_download_all_submissions' ,
'methodname' => 'download_all_submissions',
......@@ -66,6 +72,7 @@ $services = [
'mod_assignsubmission_autograde_download_submission',
'mod_assignsubmission_autograde_list_submissions',
'mod_assignsubmission_autograde_submission_info',
'mod_assignsubmission_autograde_get_grade',
'mod_assignsubmission_autograde_download_all_submissions',
],
'restrictedusers' => 1,
......
......@@ -2,6 +2,7 @@ package ch.epfl.autograde.controller.api.v1;
import ch.epfl.autograde.model.request.CreateSubmissionRequest;
import ch.epfl.autograde.model.request.UploadFeedbackRequest;
import ch.epfl.autograde.model.response.SubmissionFeedbackResponse;
import ch.epfl.autograde.model.response.SubmissionInfoResponse;
import ch.epfl.autograde.model.response.SubmissionStatusResponse;
import ch.epfl.autograde.model.response.CreateSubmissionResponse;
......@@ -184,9 +185,13 @@ public final class SubmissionController {
* </ul>
*/
@GetMapping(value = "/{id}/feedback", consumes = MediaType.ALL_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> getFeedback(final @PathVariable int id) {
// TODO: Request the feedback from Moodle
return ResponseEntity.status(HttpStatus.NOT_IMPLEMENTED).build();
public ResponseEntity<SubmissionFeedbackResponse> getFeedback(final @PathVariable int id) {
return ResponseEntity
.status(HttpStatus.OK)
.body(new SubmissionFeedbackResponse(
moodle.getGradeForSubmission(id),
String.format("%s/api/v1/submission/%d/feedback/files", autograde.getUrl() , id)
));
}
/**
......@@ -207,27 +212,9 @@ public final class SubmissionController {
@GetMapping(value = "/{id}/feedback/files", consumes = MediaType.ALL_VALUE, produces = "application/zip")
public ResponseEntity<?> getFeedbackFiles(final @PathVariable int id) {
// TODO: Request the feedback files from Moodle
return ResponseEntity.status(HttpStatus.NOT_IMPLEMENTED).build();
}
/**
* REST Endpoint to request the grade of a given submission
*
* @param id The unique id of the requested submission
* @since 1.3.0
* @return
* <ul>
* <li>{@link HttpStatus.OK} if the request is successful</li>
* <li>{@link HttpStatus.UNAUTHORIZED} if the user is not authenticated</li>
* <li>{@link HttpStatus.FORBIDDEN} if the user is authenticated but not allowed to perform this action</li>
* <li>{@link HttpStatus.NOT_FOUND} if the submission is missing</li>
* <li>{@link HttpStatus.INTERNAL_SERVER_ERROR} in case of a server failure</li>
* </ul>
*/
@GetMapping(value = "/{id}/feedback/grade", consumes = MediaType.ALL_VALUE, produces = MediaType.TEXT_PLAIN_VALUE)
public ResponseEntity<?> getGrade(final @PathVariable int id) {
// TODO: Request the grade from Moodle
return ResponseEntity.status(HttpStatus.NOT_IMPLEMENTED).build();
return ResponseEntity
.status(HttpStatus.NOT_IMPLEMENTED)
.build();
}
}
package ch.epfl.autograde.model.response;
public record SubmissionFeedbackResponse(
float grade,
String files
) {
}
......@@ -222,4 +222,27 @@ public final class MoodleWebService {
}
public float getGradeForSubmission(int sid) {
record Grade(float grade) {}
// ----
log.info("Fetching grade for submission {}", sid);
final var FUNCTION_NAME = "mod_assignsubmission_autograde_get_grade";
final var params = Map.of("sid", sid);
try {
var response = call(FUNCTION_NAME, params, ofString(UTF_8));
if (response.statusCode() != HttpStatus.OK.value()) {
log.error("Failed to fetch grade for submission {}", sid);
throw new IllegalStateException();
}
System.out.println(response.body());
Grade result = mapper.readValue(response.body(), new TypeReference<Grade>() {});
return result.grade();
} catch (Exception e) {
log.error("Error fetching grade for submission {}: {}", sid, e.getMessage());
throw new RuntimeException(e);
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment