Skip to content

Commit 67d7d6d

Browse files
Merge pull request #55 from coding-blocks/validations
Validations
2 parents def4d72 + 7d47d10 commit 67d7d6d

File tree

11 files changed

+159
-32
lines changed

11 files changed

+159
-32
lines changed

docs/api_project.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/api_project.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{ "title": "judge-blocks API", "url": "https://judge2.codingblocks.com/api", "sampleUrl": "https://judge2.codingblocks.com/api", "name": "judge-api", "version": "1.2.0", "description": "Judge API", "defaultVersion": "0.0.0", "apidoc": "0.3.0", "generator": { "name": "apidoc", "time": "2020-04-11T15:13:28.923Z", "url": "http://apidocjs.com", "version": "0.17.7" }}
1+
{ "title": "judge-blocks API", "url": "https://judge2.codingblocks.com/api", "sampleUrl": "https://judge2.codingblocks.com/api", "name": "judge-api", "version": "1.2.0", "description": "Judge API", "defaultVersion": "0.0.0", "apidoc": "0.3.0", "generator": { "name": "apidoc", "time": "2020-04-17T14:09:53.972Z", "url": "http://apidocjs.com", "version": "0.17.7" }}

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"license": "Apache-2.0",
99
"private": true,
1010
"dependencies": {
11+
"@hapi/joi": "^17.1.1",
1112
"@types/amqplib": "^0.5.4",
1213
"amqplib": "^0.5.2",
1314
"apidoc": "^0.17.6",
@@ -24,6 +25,7 @@
2425
"@types/chai": "^4.0.4",
2526
"@types/debug": "^0.0.30",
2627
"@types/express": "^4.0.39",
28+
"@types/joi": "^14.3.4",
2729
"@types/minio": "^7.0.1",
2830
"@types/mocha": "^5.0.0",
2931
"@types/sequelize": "^4.0.79",

src/models/Submission.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ export const define = (
4040
allowNull: false
4141
},
4242
results: Sequelize.JSON,
43-
outputs: Sequelize.ARRAY(Sequelize.STRING),
4443
callback: Sequelize.STRING
4544
}, {
4645
paranoid: true, // We do not want to lose any submission data

src/routes/api/run/controller.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,7 @@ class RunController {
5252
}
5353

5454
async onSuccess(result: RunResponse) {
55-
const { url } = await upload(result)
56-
5755
const job = await DB.submissions.findById(result.id)
58-
job.outputs = [url]
59-
await job.save()
6056

6157
switch (job.mode) {
6258
case 'callback':

src/routes/api/run/validators.ts

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,38 @@
1-
import { Request, Response, NextFunction } from 'express'
1+
import { Handler } from 'express'
2+
import BaseValidator from 'validators/baseValidator'
3+
import * as Joi from '@hapi/joi'
24

3-
class RunValidator {
4-
POST(req: Request, res: Response, next: NextFunction) {
5-
if (!req.body.lang || (typeof req.body.lang !== 'string')) {
6-
return new Error('Invalid Language')
7-
}
8-
if (!req.body.source) {
9-
return new Error('Source not found')
10-
}
11-
if (!req.body.stdin) {
12-
req.body.stdin = ''
13-
}
14-
if (!req.body.mode) {
15-
req.body.mode = 'sync'
16-
}
17-
if (!['sync', 'callback'].includes(req.body.mode)) {
18-
return new Error('Mode must be one of sync, callback')
19-
}
20-
if (req.body.mode === 'callback' && !req.body.callback) {
21-
return new Error('Must specify a callback for callback mode')
22-
}
23-
24-
return next()
5+
class RunValidator extends BaseValidator {
6+
POST: Handler
7+
8+
constructor() {
9+
super()
10+
this.POST = this.requestValidator(this.POSTSchema)
2511
}
12+
13+
POSTSchema = Joi.object({
14+
lang: Joi
15+
.string()
16+
.required(),
17+
source: Joi
18+
.string()
19+
.required(),
20+
mode: Joi
21+
.string()
22+
.valid('sync', 'callback', 'poll'),
23+
stdin: Joi
24+
.string()
25+
.default(''),
26+
timelimit: Joi
27+
.number(),
28+
callback: Joi
29+
.string()
30+
.uri()
31+
.when('mode', { is: 'callback', then: Joi.string().required() }),
32+
enc: Joi
33+
.string()
34+
.valid('base64', 'url')
35+
})
2636
}
2737

2838
export default new RunValidator()

src/routes/api/submit/controller.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class SubmitController {
5555

5656
async onSuccess(result: SubmitResponse) {
5757
const job = await DB.submissions.findById(result.id)
58-
job.results = result.testcases
58+
job.results = result
5959
await job.save()
6060

6161
switch (job.mode) {

src/routes/api/submit/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { Router } from 'express'
22
import Controller from './controller'
3+
import Validator from './validators'
34
import { successListener } from 'rabbitmq/jobqueue'
45

56
const router: Router = Router()
67

7-
router.post('/', Controller.SubmitPOST)
8+
router.post('/', Validator.POST, Controller.SubmitPOST)
89
successListener.on('submit_result', Controller.onSuccess)
910

1011
export default router

src/routes/api/submit/validators.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { Handler } from 'express'
2+
import BaseValidator from 'validators/baseValidator'
3+
import * as Joi from '@hapi/joi'
4+
5+
class RunValidator extends BaseValidator {
6+
POST: Handler
7+
8+
constructor() {
9+
super()
10+
this.POST = this.requestValidator(this.POSTSchema)
11+
}
12+
13+
POSTSchema = Joi.object({
14+
lang: Joi
15+
.string()
16+
.required(),
17+
source: Joi
18+
.string()
19+
.required(),
20+
mode: Joi
21+
.string()
22+
.valid('sync', 'callback', 'poll'),
23+
timelimit: Joi
24+
.number(),
25+
callback: Joi
26+
.string()
27+
.uri()
28+
.when('mode', { is: 'callback', then: Joi.string().required() }),
29+
testcases: Joi
30+
.array()
31+
.min(1)
32+
.items(
33+
Joi.object({
34+
id: Joi.number().required(),
35+
stdin: Joi.string().uri(),
36+
stdout: Joi.string().uri()
37+
})
38+
)
39+
.required()
40+
})
41+
}
42+
43+
export default new RunValidator()

src/validators/baseValidator.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { Request, Response, NextFunction } from 'express';
2+
import * as Joi from '@hapi/joi';
3+
4+
export default class BaseValidator {
5+
constructor() {
6+
new Array(
7+
'requestValidator'
8+
).map(_ => {
9+
this[_] = this[_].bind(this)
10+
})
11+
}
12+
13+
forbid(err, res: Response) {
14+
return res
15+
.status(err.code || 400)
16+
.json({
17+
err
18+
})
19+
}
20+
21+
requestValidator(schema, key = 'body') {
22+
return (req: Request, res: Response, next: NextFunction) => {
23+
const { error } = schema.validate(req[key], { allowUnknown: true })
24+
if (error) {
25+
return this.forbid({message: error.details[0].message, code: 400}, res)
26+
}
27+
28+
next()
29+
}
30+
}
31+
}

0 commit comments

Comments
 (0)