Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions devU-api/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions devU-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"@types/morgan": "^1.9.2",
"@types/multer": "^1.4.7",
"@types/node": "^15.12.2",
"@types/node-fetch": "^2.6.11",
"@types/passport": "^1.0.6",
"@types/passport-strategy": "^0.2.35",
"@types/swagger-jsdoc": "^6.0.0",
Expand All @@ -61,6 +62,7 @@
"body-parser": "^1.19.0",
"colors": "^1.4.0",
"config": "^3.3.6",
"node-fetch": "^2.7.0",
"cookie-parser": "^1.4.5",
"cors": "^2.8.5",
"devu-shared-modules": "./devu-shared-modules",
Expand All @@ -71,6 +73,7 @@
"minio": "^7.0.18",
"morgan": "^1.10.0",
"multer": "^1.4.2",
"node-fetch": "^2.7.0",
"passport": "^0.6.0",
"passport-saml": "^3.2.2",
"pg": "^8.4.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,12 @@ export async function update(
containerAutoGrader.graderFile = filename
}

if (makefileInputFile) {
const bucket: string = 'makefiles'
const makefileFilename: string = generateFilename(makefileInputFile.originalname, userId)
await filesUpload(bucket, makefileInputFile, containerAutoGrader, makefileFilename, userId)
containerAutoGrader.makefileFile = makefileFilename
}
if (makefileInputFile) {
const bucket: string = 'makefiles'
const makefileFilename: string = generateFilename(makefileInputFile.originalname, userId)
await filesUpload(bucket, makefileInputFile, containerAutoGrader, makefileFilename, userId)
containerAutoGrader.makefileFile = makefileFilename
}

const { id, assignmentId, graderFile, makefileFile, autogradingImage, timeout } = containerAutoGrader
return await connect().update(id, { assignmentId, graderFile, makefileFile, autogradingImage, timeout })
Expand All @@ -110,10 +110,9 @@ export async function getGraderObjectByAssignmentId(assignmentId: number) {
return await connect().find({ assignmentId: assignmentId, deletedAt: IsNull() })
}

export async function listByAssignmentId(assignmentId: number) {
if (!assignmentId) throw new Error('Missing AssignmentId')
return await connect().find({ assignmentId: assignmentId, deletedAt: IsNull() })
}
export async function getGraderByAssignmentId(assignmentId: number){
const containerAutoGraders = await connect().findOne({ assignmentId: assignmentId, deletedAt: IsNull() })
if (!containerAutoGraders) return {graderData: null, makefileData: null, autogradingImage: null, timeout: null}

export async function getGraderByAssignmentId(assignmentId: number) {
const containerAutoGraders = await connect().findOne({ assignmentId: assignmentId, deletedAt: IsNull() })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ import validate from '../../middleware/validator/generic.validator'

const assignmentId = check('assignmentId').isNumeric()

const graderFile = check('graderFile')
.optional({ nullable: true })
.custom(({ req }) => {
const graderFile = check('graderFile').optional({ nullable: true }).custom(({req}) => {

const file = req?.files['grader']
if (file !== null) {
if (file.size <= 0) {
Expand Down
36 changes: 23 additions & 13 deletions devU-api/src/entities/grader/grader.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,31 @@ import { Request, Response, NextFunction } from 'express'

import GraderService from './grader.service'

import { GenericResponse, NotFound } from '../../utils/apiResponse.utils'
import { GenericResponse } from '../../utils/apiResponse.utils' //, NotFound

import { serialize } from './grader.serializer'
//import { serialize } from '../grader/grader.serializer'

export async function grade(req: Request, res: Response, next: NextFunction) {
try {
const submissionId = parseInt(req.params.id)
const grade = await GraderService.grade(submissionId)
if (!grade || grade.length === 0) return res.status(404).json(NotFound)
const response = serialize(grade)

res.status(200).json(response)
} catch (err) {
res.status(400).json(new GenericResponse(err.message))
}
try {
const submissionId = parseInt(req.params.id)
const response = await GraderService.grade(submissionId) //grade

res.status(200).json(response)
} catch (err) {
res.status(400).json(new GenericResponse(err.message))
}
}

export async function tangoCallback(req: Request, res: Response, next: NextFunction) {
try {
const outputFile = req.params.outputFile
const response = await GraderService.tangoCallback(outputFile)

res.status(200).json(response)
} catch (err) {
res.status(400).json(new GenericResponse(err.message))
}

}

export default { grade }
export default { grade, tangoCallback }
30 changes: 28 additions & 2 deletions devU-api/src/entities/grader/grader.router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import express from 'express'
// Middleware
//import validator from './grader.validator'
import { asInt } from '../../middleware/validator/generic.validator'

import { isAuthorized } from '../../authorization/authorization.middleware'


// Controller
import GraderController from './grader.controller'

Expand All @@ -31,12 +33,36 @@ const Router = express.Router({ mergeParams: true })
* schema:
* type: integer
*/
Router.post('/:id', isAuthorized('enrolled'), asInt(), GraderController.grade)
// TODO: This one might be tricky. Can every student hit this endpoint for their own submissions? That's probably
Router.post('/:id', asInt(), GraderController.grade)

/**
* @swagger
* tags:
* - name: Grader callback
* description:
* /grade/callback/{outputFilename}:
* post:
* summary: Not directly called by the user. Tells the API that a container grading job has finished and creates relevant entities from the results.
* tags:
* - Grader
* responses:
* '200':
* description: OK
* parameters:
* - name: outputFilename
* in: path
* required: true
* schema:
* type: string
*/
Router.post('/callback/:outputFile', GraderController.tangoCallback) //Unauthorized route so tango can make callback without needing token

// TODO: This one might be tricky for authorization. Can every student hit this endpoint for their own submissions? That's probably
// the easiest way to handle it. If not, how does this endpoint get hit when they make a submission without
// sacrificing RESTfullness? eg. Sometimes we want to make submissions without running the grader so the front end
// should have control of this endpoint
// -or- do we only let students hit this once per submission. Regrades must be by someone with permission. Then
// add a second endpoint that is /regrade


export default Router
Loading