From 3d3f3b778d662518191f826e6b25f45ef46d8d55 Mon Sep 17 00:00:00 2001
From: "kelly.nguyen" <kelly.nguyen@etu.hesge.ch>
Date: Mon, 17 Jun 2024 14:27:17 +0200
Subject: [PATCH] add function for export full repo

---
 .../migration.sql                             |  2 +
 ExpressAPI/prisma/schema.prisma               |  2 +
 ExpressAPI/src/managers/GitlabManager.ts      | 17 ++++
 ExpressAPI/src/routes/AssignmentRoutes.ts     | 95 ++++++++++++++++++-
 .../src/shared/types/Gitlab/GitlabRoute.ts    |  3 +
 5 files changed, 115 insertions(+), 4 deletions(-)
 create mode 100644 ExpressAPI/prisma/migrations/20240603201959_add_correction_commit_to_exercise/migration.sql

diff --git a/ExpressAPI/prisma/migrations/20240603201959_add_correction_commit_to_exercise/migration.sql b/ExpressAPI/prisma/migrations/20240603201959_add_correction_commit_to_exercise/migration.sql
new file mode 100644
index 0000000..cf8fa02
--- /dev/null
+++ b/ExpressAPI/prisma/migrations/20240603201959_add_correction_commit_to_exercise/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE `Exercise` ADD COLUMN `correctionCommit` JSON NULL;
diff --git a/ExpressAPI/prisma/schema.prisma b/ExpressAPI/prisma/schema.prisma
index 52ee5ab..0f3a81b 100644
--- a/ExpressAPI/prisma/schema.prisma
+++ b/ExpressAPI/prisma/schema.prisma
@@ -51,6 +51,8 @@ model Exercise {
     gitlabLastInfo     Json     @db.Json
     gitlabLastInfoDate DateTime
 
+    correctionCommit Json? @db.Json
+
     assignment Assignment @relation(fields: [assignmentName], references: [name], onDelete: NoAction, onUpdate: Cascade)
 
     members User[]
diff --git a/ExpressAPI/src/managers/GitlabManager.ts b/ExpressAPI/src/managers/GitlabManager.ts
index 8809faa..a0636c4 100644
--- a/ExpressAPI/src/managers/GitlabManager.ts
+++ b/ExpressAPI/src/managers/GitlabManager.ts
@@ -286,6 +286,23 @@ class GitlabManager {
         });
         return response.data;
     }
+
+    async scheduleExportRepository(repoId : number) {
+        const response = await axios.post(this.getApiUrl(GitlabRoute.REPOSITORY_SCHEDULE_EXPORT).replace('{{id}}', String(repoId)));
+        return response.data;
+    }
+
+    async exportStatusRepository(repoId : number) {
+        const response = await axios.get(this.getApiUrl(GitlabRoute.REPOSITORY_EXPORT_STATUS).replace('{{id}}', String(repoId)));
+        return response.data;
+    }
+
+    async exportDownloadRepository(repoId : number) {
+        const response = await axios.get(this.getApiUrl(GitlabRoute.REPOSITORY_DOWNLOAD).replace('{{id}}', String(repoId)), {
+            responseType: 'arraybuffer',
+          });
+        return response.data;
+    }
 }
 
 
diff --git a/ExpressAPI/src/routes/AssignmentRoutes.ts b/ExpressAPI/src/routes/AssignmentRoutes.ts
index b5fbd84..47d40a2 100644
--- a/ExpressAPI/src/routes/AssignmentRoutes.ts
+++ b/ExpressAPI/src/routes/AssignmentRoutes.ts
@@ -52,6 +52,8 @@ class AssignmentRoutes implements RoutesManager {
         backend.patch('/assignments/:assignmentNameOrUrl/unpublish', SecurityMiddleware.check(true, SecurityCheckType.ASSIGNMENT_STAFF), this.unpublishAssignment.bind(this));
         
         backend.patch('/assignments/:assignmentNameOrUrl/deleted', SecurityMiddleware.check(true, SecurityCheckType.ASSIGNMENT_STAFF), this.deleteAssignment.bind(this));
+        backend.get('/assignments/:assignmentNameOrUrl/export', SecurityMiddleware.check(true, SecurityCheckType.TEACHING_STAFF), this.exportAssign.bind(this));
+        backend.get('/assignments/:assignmentNameOrUrl/createSummary', SecurityMiddleware.check(true, SecurityCheckType.TEACHING_STAFF), this.createSummary.bind(this));
     }
     // Get an assignment by its name or gitlab url
     private async getAssignment(req: express.Request, res: express.Response) {
@@ -214,17 +216,17 @@ class AssignmentRoutes implements RoutesManager {
     
     private async deleteAssignment(req : express.Request, res : express.Response) {
         const nameAssignment = req.params.assignmentNameOrUrl;
-
+        
         const repo = await db.assignment.findUnique({
             where : {
                 name : String(nameAssignment)
             }
         });
-
+        
         if (!repo) {
             return req.session.sendResponse(res, StatusCodes.NOT_FOUND);
         }
-
+        
         // const members = await GitlabManager.getRepositoryMembers(String(repo['gitlabId']));
         const members = await GitlabManager.getRepositoryDirectMembers(String(repo['gitlabId']));
         members.forEach(async member => {
@@ -242,7 +244,7 @@ class AssignmentRoutes implements RoutesManager {
             await GitlabManager.moveRepositorySubGroup(repo['gitlabId'], 14193);
             logger.debug("Repo was successfully move");
         } catch (error) {
-            logger.debug(`Error while moving the repo to "deleted" with  the error : ${error}`);
+            logger.debug(`Error while moving the repo to "deleted" with the error : ${error}`);
         }
         
         await db.assignment.update({
@@ -256,6 +258,91 @@ class AssignmentRoutes implements RoutesManager {
         
         return req.session.sendResponse(res, StatusCodes.OK);
     }
+    
+    // private async exportAssign(req : express.Request, res : express.Response) {
+    //     const nameAssignment = req.params.assignmentNameOrUrl;
+    //     let exportFinished = false;
+    //     const repo = await db.assignment.findUnique({
+    //         where : {
+    //             name : String(nameAssignment)
+    //         }
+    //     });
+        
+    //     if (!repo) {
+    //         return req.session.sendResponse(res, StatusCodes.NOT_FOUND);
+    //     }
+    //     const repoId = repo['gitlabId'];
+    //     try {
+    //         const resExport = await GitlabManager.scheduleExportRepository(repoId);
+    //         if (resExport['message'] == '202 Accepted') {
+    //             while (!exportFinished) {
+    //                 const exportStatus = await GitlabManager.exportStatusRepository(repoId);
+    //                 if (exportStatus['export_status'] == 'finished') {
+    //                     exportFinished = true;
+    //                     const repoData = await GitlabManager.exportDownloadRepository(repo['gitlabId']);
+    //                     logger.debug(repoData);
+    //                     // fs.writeFileSync('./tmprepo.tar', repoData.data);
+    //                     return req.session.sendResponse(res, StatusCodes.OK, exportStatus['_links']['web_url']);
+    //                 }
+    //             }
+    //         }
+    //     } catch (error) {
+    //         logger.error(`Error while downloading the repo with the error : ${error}`);
+    //     }
+        
+    //     return req.session.sendResponse(res, StatusCodes.OK);
+    // }
+
+    private async exportAssign(req: express.Request, res: express.Response) {
+        const nameAssignment = req.params.assignmentNameOrUrl;
+        let exportFinished = false;
+    
+        const repo = await db.assignment.findUnique({
+            where: { name: String(nameAssignment) }
+        });
+    
+        if (!repo) {
+            return req.session.sendResponse(res, StatusCodes.NOT_FOUND);
+        }
+    
+        const repoId = repo['gitlabId'];
+    
+        try {
+            const resExport = await GitlabManager.scheduleExportRepository(repoId);
+            if (resExport['message'] === '202 Accepted') {
+                while (!exportFinished) {
+                    const exportStatus = await GitlabManager.exportStatusRepository(repoId);
+    
+                    if (exportStatus['export_status'] === 'finished') {
+                        exportFinished = true;
+    
+                        const repoData = await GitlabManager.exportDownloadRepository(repoId);
+                        logger.debug(repoData);
+    
+                        if (!repoData.data || repoData.data.length === 0) {
+                            logger.error('The downloaded export file is empty.');
+                            return req.session.sendResponse(res, StatusCodes.INTERNAL_SERVER_ERROR, 'Export file is empty.');
+                        }
+    
+                        // Écriture du fichier exporté
+                        // fs.writeFileSync('./tmprepo.tar', repoData.data);
+    
+                        return req.session.sendResponse(res, StatusCodes.OK, exportStatus['_links']['web_url']);
+                    } else {
+                        await new Promise(resolve => setTimeout(resolve, 5000));
+                    }
+                }
+            } else {
+                logger.error(`Failed to initiate export: ${resExport['message']}`);
+                return req.session.sendResponse(res, StatusCodes.INTERNAL_SERVER_ERROR, 'Failed to initiate export.');
+            }
+        } catch (error) {
+            logger.error(`Error while downloading the repo: ${error}`);
+            return req.session.sendResponse(res, StatusCodes.INTERNAL_SERVER_ERROR, `Error while downloading the repo: ${error}`);
+        }
+    
+        return req.session.sendResponse(res, StatusCodes.OK);
+    }
 }
 
 
diff --git a/ExpressAPI/src/shared/types/Gitlab/GitlabRoute.ts b/ExpressAPI/src/shared/types/Gitlab/GitlabRoute.ts
index 4485f38..c30e4a5 100644
--- a/ExpressAPI/src/shared/types/Gitlab/GitlabRoute.ts
+++ b/ExpressAPI/src/shared/types/Gitlab/GitlabRoute.ts
@@ -19,6 +19,9 @@ enum GitlabRoute {
     REPOSITORY_PIPELINES            = '/projects/{{id}}/pipelines',
     REPOSITORY_MEMBER_DELETE        = '/projects/{{id}}/members/{{user_id}}',
     REPOSITORY_MOVE_SUBGROUP        = '/projects/{{id}}/transfer',
+    REPOSITORY_SCHEDULE_EXPORT      = '/projects/{{id}}/export',
+    REPOSITORY_EXPORT_STATUS        = '/projects/{{id}}/export',
+    REPOSITORY_DOWNLOAD             = '/projects/{{id}}/export/download',
 }
 
 
-- 
GitLab