diff --git a/ExpressAPI/prisma/migrations/20240309094026_add_correction_to_assignment/migration.sql b/ExpressAPI/prisma/migrations/20240309094026_add_correction_to_assignment/migration.sql new file mode 100644 index 0000000000000000000000000000000000000000..afb678b3703c2917b030524c6f2f23762b59f6f7 --- /dev/null +++ b/ExpressAPI/prisma/migrations/20240309094026_add_correction_to_assignment/migration.sql @@ -0,0 +1,7 @@ +-- CreateTable +CREATE TABLE `SubmissionTag` ( + `name` CHAR(36) NOT NULL, + `type` ENUM('LANGUAGE', 'FRAMEWORK', 'THEME', 'USERDEFINED') NOT NULL, + + PRIMARY KEY (`name`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; diff --git a/ExpressAPI/prisma/migrations/20240309201554_tags/migration.sql b/ExpressAPI/prisma/migrations/20240309201554_tags/migration.sql new file mode 100644 index 0000000000000000000000000000000000000000..af5102c8ba20cc6051c01d3ca06b2e7f8d7e14d9 --- /dev/null +++ b/ExpressAPI/prisma/migrations/20240309201554_tags/migration.sql @@ -0,0 +1 @@ +-- This is an empty migration. \ No newline at end of file diff --git a/ExpressAPI/prisma/migrations/20240309204629_tag_type/migration.sql b/ExpressAPI/prisma/migrations/20240309204629_tag_type/migration.sql new file mode 100644 index 0000000000000000000000000000000000000000..af5102c8ba20cc6051c01d3ca06b2e7f8d7e14d9 --- /dev/null +++ b/ExpressAPI/prisma/migrations/20240309204629_tag_type/migration.sql @@ -0,0 +1 @@ +-- This is an empty migration. \ No newline at end of file diff --git a/ExpressAPI/prisma/migrations/20240311140413_tag_type/migration.sql b/ExpressAPI/prisma/migrations/20240311140413_tag_type/migration.sql new file mode 100644 index 0000000000000000000000000000000000000000..af5102c8ba20cc6051c01d3ca06b2e7f8d7e14d9 --- /dev/null +++ b/ExpressAPI/prisma/migrations/20240311140413_tag_type/migration.sql @@ -0,0 +1 @@ +-- This is an empty migration. \ No newline at end of file diff --git a/ExpressAPI/prisma/schema.prisma b/ExpressAPI/prisma/schema.prisma index 57139d4af976b627e9c9f45360fb9b3752b154ab..452ec479ff150d9bb5ea287a249da49621d1ff35 100644 --- a/ExpressAPI/prisma/schema.prisma +++ b/ExpressAPI/prisma/schema.prisma @@ -13,13 +13,19 @@ enum UserRole { ADMIN } -enum Type{ +enum TagType { LANGUAGE FRAMEWORK THEME USERDEFINED } +enum SubmissionStatus{ + PENDINGAPPROVAL + DECLINED + APPROVED +} + model User { id Int @id /// The user's id is the same as their gitlab id name String? @@ -84,8 +90,13 @@ model Result { model Tag { name String @id @db.Char(36) - type Type + type TagType assignment Assignment[] exercise Exercise[] +} + +model SubmissionTag { + name String @id @db.Char(36) + type TagType } \ No newline at end of file diff --git a/ExpressAPI/prisma/seed.ts b/ExpressAPI/prisma/seed.ts index cf91fde62d2f027827f9f3593208618d13073865..6ac1a5d060fb2009293ea630763ec747a2790beb 100644 --- a/ExpressAPI/prisma/seed.ts +++ b/ExpressAPI/prisma/seed.ts @@ -6,12 +6,12 @@ import SharedConfig from '../src/shared/config/SharedConfig.js'; import { UserRole } from '@prisma/client'; import logger from '../src/shared/logging/WinstonLogger.js'; import db from '../src/helpers/DatabaseHelper.js'; -import TagsManager from '../src/managers/TagsManager'; - +import TagManager from '../src/managers/TagManager'; +import { TagType } from '@prisma/client'; async function main() { await users(); - await assignments();s + await assignments(); await exercises(); await results(); await tag(); @@ -1590,7 +1590,7 @@ async function tag() { update: {}, create: { name : 'C', - type : TagsManager.TagType.Language, + type : TagType.LANGUAGE } }); await db.tag.upsert({ @@ -1598,7 +1598,7 @@ async function tag() { update: {}, create: { name : 'Java', - type : TagsManager.TagType.Language, + type : TagType.LANGUAGE, } }); await db.tag.upsert({ @@ -1606,7 +1606,7 @@ async function tag() { update: {}, create: { name : 'Scala', - type : TagsManager.TagType.Language, + type : TagType.LANGUAGE, } }); await db.tag.upsert({ @@ -1614,7 +1614,7 @@ async function tag() { update: {}, create: { name : 'Kotlin', - type : TagsManager.TagType.Language, + type : TagType.LANGUAGE, } }); await db.tag.upsert({ @@ -1622,7 +1622,7 @@ async function tag() { update: {}, create: { name : 'Rust', - type : TagsManager.TagType.Language, + type : TagType.LANGUAGE, } }); await db.tag.upsert({ @@ -1630,7 +1630,7 @@ async function tag() { update: {}, create: { name : 'JavaScript', - type : TagsManager.TagType.Language, + type : TagType.LANGUAGE, } }); await db.tag.upsert({ @@ -1638,7 +1638,7 @@ async function tag() { update: {}, create: { name : 'TypeScript', - type : TagsManager.TagType.Language, + type : TagType.LANGUAGE, } }); await db.tag.upsert({ @@ -1646,7 +1646,7 @@ async function tag() { update: {}, create: { name : 'Python', - type : TagsManager.TagType.Language, + type : TagType.LANGUAGE, } }); await db.tag.upsert({ @@ -1654,7 +1654,7 @@ async function tag() { update: {}, create: { name : 'HTML', - type : TagsManager.TagType.Language, + type : TagType.LANGUAGE, } }); await db.tag.upsert({ @@ -1662,7 +1662,7 @@ async function tag() { update: {}, create: { name : 'CSS', - type : TagsManager.TagType.Language, + type : TagType.LANGUAGE, } }); await db.tag.upsert({ @@ -1670,7 +1670,7 @@ async function tag() { update: {}, create: { name : 'C++', - type : TagsManager.TagType.Language, + type : TagType.LANGUAGE, } }); await db.tag.upsert({ @@ -1678,7 +1678,7 @@ async function tag() { update: {}, create: { name : 'Go', - type : TagsManager.TagType.Language, + type : TagType.LANGUAGE, } }); await db.tag.upsert({ @@ -1686,7 +1686,7 @@ async function tag() { update: {}, create: { name : 'PHP', - type : TagsManager.TagType.Language, + type : TagType.LANGUAGE, } }); await db.tag.upsert({ @@ -1694,7 +1694,7 @@ async function tag() { update: {}, create: { name : 'C#', - type : TagsManager.TagType.Language, + type : TagType.LANGUAGE, } }); await db.tag.upsert({ @@ -1702,7 +1702,7 @@ async function tag() { update: {}, create: { name : 'Swift', - type : TagsManager.TagType.Language, + type : TagType.LANGUAGE, } }); await db.tag.upsert({ @@ -1710,7 +1710,7 @@ async function tag() { update: {}, create: { name : 'Matlab', - type : TagsManager.TagType.Language, + type : TagType.LANGUAGE, } }); await db.tag.upsert({ @@ -1718,7 +1718,7 @@ async function tag() { update: {}, create: { name : 'SQL', - type : TagsManager.TagType.Language, + type : TagType.LANGUAGE, } }); await db.tag.upsert({ @@ -1726,7 +1726,7 @@ async function tag() { update: {}, create: { name : 'Assembly', - type : TagsManager.TagType.Language, + type : TagType.LANGUAGE, } }); await db.tag.upsert({ @@ -1734,7 +1734,7 @@ async function tag() { update: {}, create: { name : 'Ruby', - type : TagsManager.TagType.Language, + type : TagType.LANGUAGE, } }); await db.tag.upsert({ @@ -1742,7 +1742,7 @@ async function tag() { update: {}, create: { name : 'Fortran', - type : TagsManager.TagType.Language, + type : TagType.LANGUAGE, } }); await db.tag.upsert({ @@ -1750,7 +1750,7 @@ async function tag() { update: {}, create: { name : 'Pascal', - type : TagsManager.TagType.Language, + type : TagType.LANGUAGE, } }); await db.tag.upsert({ @@ -1758,7 +1758,7 @@ async function tag() { update: {}, create: { name : 'Visual Basic', - type : TagsManager.TagType.Language, + type : TagType.LANGUAGE, } }); await db.tag.upsert({ @@ -1766,7 +1766,7 @@ async function tag() { update: {}, create: { name : 'R', - type : TagsManager.TagType.Language, + type : TagType.LANGUAGE, } }); await db.tag.upsert({ @@ -1774,7 +1774,7 @@ async function tag() { update: {}, create: { name : 'Objective-C', - type : TagsManager.TagType.Language, + type : TagType.LANGUAGE, } }); await db.tag.upsert({ @@ -1782,7 +1782,7 @@ async function tag() { update: {}, create: { name : 'Lua', - type : TagsManager.TagType.Language, + type : TagType.LANGUAGE, } }); await db.tag.upsert({ @@ -1790,7 +1790,7 @@ async function tag() { update: {}, create: { name : 'Ada', - type : TagsManager.TagType.Language, + type : TagType.LANGUAGE, } }); await db.tag.upsert({ @@ -1798,7 +1798,7 @@ async function tag() { update: {}, create: { name : 'Haskell', - type : TagsManager.TagType.Language, + type : TagType.LANGUAGE, } }); await db.tag.upsert({ @@ -1806,7 +1806,7 @@ async function tag() { update: {}, create: { name : 'Shell/PowerShell', - type : TagsManager.TagType.Language, + type : TagType.LANGUAGE, } }); await db.tag.upsert({ @@ -1814,7 +1814,7 @@ async function tag() { update: {}, create: { name : 'Express', - type : TagsManager.TagType.Framework, + type : TagType.FRAMEWORK } }); await db.tag.upsert({ @@ -1822,7 +1822,7 @@ async function tag() { update: {}, create: { name : 'Django', - type : TagsManager.TagType.Framework, + type : TagType.FRAMEWORK } }); await db.tag.upsert({ @@ -1830,7 +1830,7 @@ async function tag() { update: {}, create: { name : 'Ruby on Rails', - type : TagsManager.TagType.Framework, + type : TagType.FRAMEWORK } }); await db.tag.upsert({ @@ -1838,7 +1838,7 @@ async function tag() { update: {}, create: { name : 'Angular', - type : TagsManager.TagType.Framework, + type : TagType.FRAMEWORK } }); await db.tag.upsert({ @@ -1846,7 +1846,7 @@ async function tag() { update: {}, create: { name : 'React', - type : TagsManager.TagType.Framework, + type : TagType.FRAMEWORK } }); await db.tag.upsert({ @@ -1854,7 +1854,7 @@ async function tag() { update: {}, create: { name : 'Flutter', - type : TagsManager.TagType.Framework, + type : TagType.FRAMEWORK } }); await db.tag.upsert({ @@ -1862,7 +1862,7 @@ async function tag() { update: {}, create: { name : 'Ionic', - type : TagsManager.TagType.Framework, + type : TagType.FRAMEWORK } }); await db.tag.upsert({ @@ -1870,7 +1870,7 @@ async function tag() { update: {}, create: { name : 'Flask', - type : TagsManager.TagType.Framework, + type : TagType.FRAMEWORK } }); await db.tag.upsert({ @@ -1878,7 +1878,7 @@ async function tag() { update: {}, create: { name : 'React Native', - type : TagsManager.TagType.Framework, + type : TagType.FRAMEWORK } }); await db.tag.upsert({ @@ -1886,7 +1886,7 @@ async function tag() { update: {}, create: { name : 'Xamarin', - type : TagsManager.TagType.Framework, + type : TagType.FRAMEWORK } }); await db.tag.upsert({ @@ -1894,7 +1894,7 @@ async function tag() { update: {}, create: { name : 'Laravel', - type : TagsManager.TagType.Framework, + type : TagType.FRAMEWORK } }); await db.tag.upsert({ @@ -1902,7 +1902,7 @@ async function tag() { update: {}, create: { name : 'Spring', - type : TagsManager.TagType.Framework, + type : TagType.FRAMEWORK } }); await db.tag.upsert({ @@ -1910,7 +1910,7 @@ async function tag() { update: {}, create: { name : 'Play', - type : TagsManager.TagType.Framework, + type : TagType.FRAMEWORK } }); await db.tag.upsert({ @@ -1918,7 +1918,7 @@ async function tag() { update: {}, create: { name : 'Symfony', - type : TagsManager.TagType.Framework, + type : TagType.FRAMEWORK } }); await db.tag.upsert({ @@ -1926,7 +1926,7 @@ async function tag() { update: {}, create: { name : 'ASP.NET', - type : TagsManager.TagType.Framework, + type : TagType.FRAMEWORK } }); await db.tag.upsert({ @@ -1934,7 +1934,7 @@ async function tag() { update: {}, create: { name : 'Meteor', - type : TagsManager.TagType.Framework, + type : TagType.FRAMEWORK } }); await db.tag.upsert({ @@ -1942,7 +1942,7 @@ async function tag() { update: {}, create: { name : 'Vue.js', - type : TagsManager.TagType.Framework, + type : TagType.FRAMEWORK } }); await db.tag.upsert({ @@ -1950,7 +1950,7 @@ async function tag() { update: {}, create: { name : 'Svelte', - type : TagsManager.TagType.Framework, + type : TagType.FRAMEWORK } }); await db.tag.upsert({ @@ -1958,7 +1958,7 @@ async function tag() { update: {}, create: { name : 'Express.js', - type : TagsManager.TagType.Framework, + type : TagType.FRAMEWORK } }); } diff --git a/ExpressAPI/src/managers/TagManager.ts b/ExpressAPI/src/managers/TagManager.ts new file mode 100644 index 0000000000000000000000000000000000000000..51d2320ee02bc45327df3ffee711a64581a1c9fa --- /dev/null +++ b/ExpressAPI/src/managers/TagManager.ts @@ -0,0 +1,17 @@ +import { Prisma } from '@prisma/client'; +import { Assignment, User } from '../types/DatabaseTypes'; +import db from '../helpers/DatabaseHelper'; + +enum TagType{ + Language, + Framework, + Theme, + UserDefined +} + +class TagManager { + +} + + +export default new TagManager(); diff --git a/ExpressAPI/src/managers/TagsManager.ts b/ExpressAPI/src/managers/TagsManager.ts deleted file mode 100644 index 884459caecd935303661c63ec6634318af9151f4..0000000000000000000000000000000000000000 --- a/ExpressAPI/src/managers/TagsManager.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { Prisma } from '@prisma/client'; -import { Assignment, User } from '../types/DatabaseTypes'; -import db from '../helpers/DatabaseHelper'; - -enum TagType{ - Language, - Framework, - Theme, - UserDefined -} - -class TagsManager { - async isUserAllowedToAccessTag(tag: Tags, user: User): Promise<boolean> { - if ( !tag.staff ) { - tag.staff = await db.assignment.findUnique({ - where: { - name: tag.name - } - }).staff() ?? []; - } - return tag.staff.findIndex(staff => staff.id === user.id) !== -1; - } - - async getByName(name: string, include: Prisma.TagInclude | undefined = undefined): Promise<Tag | undefined> { - return await db.assignment.findUnique({ - where : { - name: name - }, include: include - }) as unknown as Tag ?? undefined; - } - - getByGitlabLink(gitlabLink: string, include: Prisma.AssignmentInclude | undefined = undefined): Promise<Assignment | undefined> { - const name = gitlabLink.replace('.git', '').split('/').pop()!; - - return this.getByName(name, include); - } - - get(nameOrUrl: string, include: Prisma.AssignmentInclude | undefined = undefined): Promise<Assignment | undefined> { - // We can use the same function for both name and url because the name is the last part of the url and the name extraction from the url doesn't corrupt the name - return this.getByGitlabLink(nameOrUrl, include); - } -} - - -export default new TagManager(); diff --git a/ExpressAPI/src/routes/TagsRoutes.ts b/ExpressAPI/src/routes/TagsRoutes.ts index f7174dcb7e675ef267059f55f93f73830395b6bc..d8bc764c813d414a423544eaf2deea02905b1916 100644 --- a/ExpressAPI/src/routes/TagsRoutes.ts +++ b/ExpressAPI/src/routes/TagsRoutes.ts @@ -17,7 +17,7 @@ import logger from '../shared/logging/WinstonLogger'; import DojoValidators from '../helpers/DojoValidators'; import { Prisma } from '@prisma/client'; import db from '../helpers/DatabaseHelper'; -import { Assignment } from '../types/DatabaseTypes'; +import { Tags } from '../types/DatabaseTypes'; import AssignmentManager from '../managers/AssignmentManager'; import GitlabVisibility from '../shared/types/Gitlab/GitlabVisibility'; import fs from 'fs'; @@ -25,7 +25,15 @@ import path from 'path'; import SharedAssignmentHelper from '../shared/helpers/Dojo/SharedAssignmentHelper'; import GlobalHelper from '../helpers/GlobalHelper'; import DojoStatusCode from '../shared/types/Dojo/DojoStatusCode'; -import TagsManager from '../managers/TagsManager'; +import TagsManager from '../managers/TagManager'; +import { TagType } from '@prisma/client'; + + +enum SubmitStatus{ + PendingApproval, + Declined, + Approved +} class TagRoutes implements RoutesManager { private readonly tagsValidator: ExpressValidator.Schema = { @@ -42,16 +50,16 @@ class TagRoutes implements RoutesManager { registerOnBackend(backend: Express) { backend.post('/tags', SecurityMiddleware.check(true, SecurityCheckType.TEACHING_STAFF), ParamsValidatorMiddleware.validate(this.tagsValidator), this.addTag.bind(this)); backend.delete('/tags/:tagId', SecurityMiddleware.check(true, SecurityCheckType.ADMIN), ParamsValidatorMiddleware.validate(this.tagsValidator), this.deleteTag.bind(this)); - backend.get('/tags/proposals', SecurityMiddleware.check(true, SecurityCheckType.ADMIN), ParamsValidatorMiddleware.validate(this.tagsValidator), this.getSubmittedTag.bind(this)); + backend.get('/tags/proposals/state?', SecurityMiddleware.check(true, SecurityCheckType.ADMIN), ParamsValidatorMiddleware.validate(this.tagsValidator), this.getSubmittedTag.bind(this)); backend.post('/tags/proposals', SecurityMiddleware.check(true, SecurityCheckType.TEACHING_STAFF), ParamsValidatorMiddleware.validate(this.tagsValidator), this.SubmitTag.bind(this)); backend.patch('/tags/proposals/:tagProposalName', SecurityMiddleware.check(true, SecurityCheckType.ADMIN), ParamsValidatorMiddleware.validate(this.tagsValidator), this.validateTag.bind(this)); } private async addTag(req: express.Request, res: express.Response) { - let tagName = req.body.name + const tagName = req.body.name const tagType = req.body.type - if(tagType != TagsManager.TagType.UserDefined && !req.session.profile.isAdmin) { + if(tagType != TagType.USERDEFINED && !req.session.profile.isAdmin) { return req.session.sendResponse(res, StatusCodes.FORBIDDEN); } @@ -63,6 +71,10 @@ class TagRoutes implements RoutesManager { type : tagType, } }) + return req.session.sendResponse(res, StatusCodes.OK, { + tag : (req.boundParams.tag as Tags), + name : req.body.name + }, "Tag ajouté avec succès"); } private async deleteTag(req: express.Request, res: express.Response) { let tagName = req.body.name @@ -70,22 +82,55 @@ class TagRoutes implements RoutesManager { db.tag.delete({ where : { name: tagName } }) - + return req.session.sendResponse(res, StatusCodes.OK, "Tag supprimé avec succès"); } private async getSubmittedTag(req: express.Request, res: express.Response) { - - + let tagState = req.body.state + if(req.body.state == null){ + tagState = tagState.PendingApproval + } + //TODO Here? return req.session.sendResponse(res, StatusCodes.OK, { - assignment : (req.boundParams.exercise as Exercise).assignment, - assignmentFile: dojoAssignmentFile, - immutable : immutableFiles + name : req.body.name, + tag : (req.boundParams.tag as Tags) }); } private async SubmitTag(req: express.Request, res: express.Response) { - + const tagName = req.body.name + const tagType = req.body.type + + db.tag.upsert({ + where : { name: tagName }, + update: {}, + create: { + name : tagName, + type : tagType, + } + }) + + return req.session.sendResponse(res, StatusCodes.OK, { + name : req.body.name, + tag : (req.boundParams.tag as Tags) + }); } private async validateTag(req: express.Request, res: express.Response) { - + if(req.body.state == SubmitStatus.PendingApproval){ + return req.session.sendResponse(res, StatusCodes.OK, "Approbation toujours en attente"); + } else if (req.body.state == SubmitStatus.Declined){ + return req.session.sendResponse(res, StatusCodes.OK, req.body.details); + } else{ + let tagName = req.params.tagProposalName + let tagType = req.body.type + db.tag.upsert({ + where : { name: tagName }, + update: {}, + create: { + name : tagName, + type : tagType, + } + }) + } + return req.session.sendResponse(res, StatusCodes.OK, "Tag accepté"); } } diff --git a/ExpressAPI/src/types/DatabaseTypes.ts b/ExpressAPI/src/types/DatabaseTypes.ts index 1636dd79f43fd643b1d92f9a457db4ab2465c0c0..24b87219bdd7bdd9f03a79e0fdcf738a27f23085 100644 --- a/ExpressAPI/src/types/DatabaseTypes.ts +++ b/ExpressAPI/src/types/DatabaseTypes.ts @@ -26,10 +26,10 @@ const resultBase = Prisma.validator<Prisma.ResultDefaultArgs>()({ exercise: true } }); -const tagsBase = Prisma.validator<Prisma.TagsDefaultArgs>()({ +const tagsBase = Prisma.validator<Prisma.TagDefaultArgs>()({ include: { - exercises: true, - assignments: true, + exercise: true, + assignment: true, } });