Skip to content
Snippets Groups Projects
Commit b5ec3d23 authored by Hamza Remmal's avatar Hamza Remmal
Browse files

Merge branch 'hj/downloadAllButton' into 'master'

Download All Submissions

See merge request !276
parents ba2080a1 1449f6d4
No related branches found
No related tags found
1 merge request!276Download All Submissions
Pipeline #236056 passed
......@@ -7,6 +7,8 @@ import ch.epfl.autograde.service.MoodleWebService;
import ch.epfl.autograde.service.AutogradeService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
......@@ -115,4 +117,24 @@ public final class AssignmentController {
return ResponseEntity.status(HttpStatus.OK).body(submissions);
}
/**
* REST Endpoint to download all submissions linked to the assignment in a zipped file
*
* @param id The unique id of the requested assignment
* @since 1.1.0
* @return
* <ul>
* <li>{@link HttpStatus.OK} if the request is successful</li>
* <li>{@link HttpStatus.NOT_FOUND} if the assignment is missing (TODO)</li>
* <li>{@link HttpStatus.INTERNAL_SERVER_ERROR} in case of a server failure</li>
* </ul>
*/
@GetMapping(value = "/{id}/submissions", produces = "application/zip")
public Resource download(final @PathVariable int id) {
log.info("Received request to download the submissions for assignment {}", id);
var files = moodle.download_all_submissions(id);
log.info("Successfully download the submissions for assignment {}", id);
return new InputStreamResource(files);
}
}
......@@ -157,6 +157,30 @@ public final class MoodleWebService {
throw new RuntimeException(e);
}
}
public InputStream download_all_submissions(int assignmentid) {
log.info("Downloading all submissions of assignment with id {} from Moodle ({})", assignmentid, properties.baseUrl());
final var FUNCTION_NAME = "mod_assignsubmission_autograde_download_all_submissions";
final var params = Map.of(
"assignmentid", assignmentid
);
try {
var response = call(FUNCTION_NAME, params, ofInputStream());
// HR : Check the http status
if(response.statusCode() != HttpStatus.OK.value()){
log.error("call to the moodle-autograde api failed - download_all_submissions - id {}", assignmentid);
throw new IllegalStateException();
}
// HR : Deserialize the request
return response.body();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public List<Submission> list_submissions(int id) {
log.info("Listing the submissions for assignment with id '{}' from Moodle", id);
......
<?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 download all submissions
*
* @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;
use context_course;
use external_api;
use external_function_parameters;
use external_value;
use moodle_exception;
use stdClass;
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');
class autograde_download_all_submissions extends external_api{
/**
* ???
* @return external_function_parameters ???
*/
public static function download_all_submissions_parameters(): external_function_parameters
{
return new external_function_parameters([
'assignmentid' => new external_value(PARAM_INT, 'The ID of the assignment'),
]);
}
/**
* @throws \dml_exception
* @throws \required_capability_exception
* @throws \moodle_exception
*/
public static function download_all_submissions($assignmentid){
global $DB, $USER;
$course_id = $DB->get_field('assign', 'course', array('id' => $assignmentid));
// HR : Check if the user has the necessary capabilities
require_capability('assignsubmission/autograde:exportsubmissions',
context_course::instance($course_id), $USER->id, false);
// HR : Fetch the correct assignment instance
$assignment = assignsubmission_autograde_get_assignment($assignmentid);
// Check if group submissions are enabled
$is_group_submission = $DB->get_field('assign', 'teamsubmission', ['id' => $assignmentid]);
//Fetch the submissions from the DB
$submissions = $is_group_submission ?
$DB->get_records_select(
'assign_submission',
'assignment = :assignmentid AND groupid != 0',
['assignmentid' => $assignmentid]
):
$DB->get_records('assign_submission', ['assignment' => $assignmentid]) ;
if (empty($submissions)) {
throw new moodle_exception('nosubmissions', 'mod_assign');
}
$files_to_zip = [];
foreach ($submissions as $submission){
$group_name = '';
if ($is_group_submission) {
// Handle group submissions
// Fetch group members
$group_members = $DB->get_records('groups_members', ['groupid' => $submission->groupid], '', 'userid');
if (empty($group_members)) {
throw new moodle_exception('invalidgroup', 'mod_assign', '', 'Group has no members.');
}
// Concatenate idnumbers of group members to create the group name
$group_idnumbers = [];
foreach ($group_members as $member) {
$user = $DB->get_record('user', ['id' => $member->userid], 'idnumber', MUST_EXIST);
$group_idnumbers[] = $user->idnumber;
}
$group_name = implode('_', $group_idnumbers); // Example: "idnumber1_idnumber2"
} else {
// Handle individual submissions
if (!empty($submission->userid)) {
$user = $DB->get_record('user', ['id' => $submission->userid], 'idnumber', MUST_EXIST);
$group_name = $user->idnumber;
} else {
throw new moodle_exception('invalidsubmission', 'mod_assign', '', 'Submission has no valid user or group ID.');
}
}
// HR : Retrieve the files associated with the specified area and item
$submission_files = array();
foreach ($assignment->get_submission_plugins() as $plugin){
if($plugin->is_enabled() && $plugin->is_visible() && $plugin->allow_submissions())
$submission_files += $plugin->get_files($submission, new stdClass());
}
foreach ($submission_files as $file) {
$filepath = $file->get_filepath();
$filename = $file->get_filename();
// We observed by looking in the $DB that the $filepath always starts and ends with
// '/'. If the filepath is empty, then it's the single character '/'
$files_to_zip[$group_name . '/' . $submission->attemptnumber . $filepath . $filename] = $file;
}
}
if (empty($files_to_zip)) {
throw new moodle_exception('nofiles', 'mod_assign');
}
//Prepare a temporary file for zipping
$tempdir = make_temp_directory('submission_files') ;
$zipfilename = "assignment_{$assignmentid}_submissions.zip" ;
$tempzipfile = "$tempdir/$zipfilename" ;
//Use Moodle's packer to create a zip file
$packer = get_file_packer('application/zip') ;
//Pack the files into the zip archive
if (!$packer->archive_to_pathname($files_to_zip, $tempzipfile)) {
throw new moodle_exception('couldnotcreatezip');
}
//Send the zip file as a response using Moodle's API
send_temp_file($tempzipfile, $zipfilename);
}
/**
* @return void
*/
public static function download_all_submissions_returns() {
}
}
\ No newline at end of file
......@@ -51,7 +51,12 @@ $functions = [
'methodname' => 'info_submissions',
'description' => 'List all of the information for a given submission',
'capabilities' => 'assignsubmission/autograde:viewsubmission'
]
],
'mod_assignsubmission_autograde_download_all_submissions' => [
'classname' => 'assignsubmission_autograde\external\autograde_download_all_submissions' ,
'methodname' => 'download_all_submissions',
'description' => 'Download all submissions of a given assignment',
]
];
$services = [
......@@ -61,6 +66,7 @@ $services = [
'mod_assignsubmission_autograde_download_submission',
'mod_assignsubmission_autograde_list_submissions',
'mod_assignsubmission_autograde_submission_info',
'mod_assignsubmission_autograde_download_all_submissions',
],
'restrictedusers' => 1,
'enabled' => 1,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment