Skip to content

Commit

Permalink
Merged in tag-updates (pull request coding-blocks#41)
Browse files Browse the repository at this point in the history
React to tag changes appropriately

Approved-by: Varun Hasija <[email protected]>
  • Loading branch information
Varun Hasija committed Feb 19, 2018
2 parents 4eca271 + d55e1f6 commit d937ca7
Show file tree
Hide file tree
Showing 10 changed files with 314 additions and 72 deletions.
28 changes: 28 additions & 0 deletions migrations/20180217150447-add-tag-fk-to-practice-categories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
'use strict';

module.exports = {
up: (Q, Sequelize) => {
return Q.addColumn (
'practice_categories',
'tag_id',
{
type: Sequelize.INTEGER,
references: {
model: 'tags',
key: 'id'
},
onUpdate: 'cascade',
onDelete: 'cascade'
}
)
.then (() => {
return Q.sequelize.query (
'update practice_categories set tag_id = tags.id from tags where tags.name = practice_categories.name'
)
})
},

down: (Q, Sequelize) => {
return Q.removeColumn ('practice_categories', 'tag_id')
}
};
40 changes: 20 additions & 20 deletions models/practice_category.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
/**
* Created by umair on 3/27/17.
* Fixed by prajjwal on 17/02/18.
*/

const db = require('../util/sequelize');
const Sequelize = require('sequelize');
const Problem = require('./problem');
const Contest = require('./contest');

const PracticeCategory = db.define('practice_category', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
c_id: Sequelize.INTEGER,
name: Sequelize.STRING,
status: Sequelize.INTEGER
const db = require ('../util/sequelize');

const Contest = require ('./contest');
const Problem = require ('./problem');
const Sequelize = require ('sequelize');
const Tag = require ('./tag');

const PracticeCategory = db.define ('practice_category', {
id : {
type : Sequelize.INTEGER,
primaryKey : true,
autoIncrement : true
},
c_id : Sequelize.INTEGER,
name : Sequelize.STRING,
status : Sequelize.INTEGER,
tag_id : Sequelize.INTEGER,
});

PracticeCategory.belongsTo(Contest, { foreignKey: 'c_id', as: 'contests'});
PracticeCategory.belongsTo (Contest, { foreignKey: 'c_id', as: 'contests'});
PracticeCategory.belongsTo (Tag, { foreignKey: 'tag_id' });

module.exports = PracticeCategory;





17 changes: 16 additions & 1 deletion models/tag.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,22 @@ const Tag = db.define('tags', {
primaryKey: true,
autoIncrement: true
},
name: Sequelize.STRING

name: {
type: Sequelize.STRING,
validate: {
// -----------------
// Tag names should:
// -----------------
// - Consist exclusively of uppercase alphanumeric characters, punctuated
// with hypens ('-') and spaces (\s).
// - It must start with an alphabetic character.
// - It must end with an alphanumeric character.
// - It may not be > 80 chars in length.
is: /^[A-Z][ A-Z0-9-]+[A-Z0-9]$/,
len: [2, 80]
}
}
})

module.exports = Tag;
30 changes: 30 additions & 0 deletions policies/tags.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,34 @@
const JsonAPI = require ('../util/json-api'),
R = require ('ramda'),
U = require ('../util/acl-util')
;

// -- [Helpers] --

const canCreateTag =
R.anyPass ([U.currentUserIsAdmin, U.currentUserIsModerator])

// -- [/Helpers] --

const GETPolicy = (request, response, next) =>
next ()

const POSTPolicy = (request, response, next) =>
canCreateTag (response)
? next ()
: response.sendStatus (403)

const PATCHPolicy = (request, response, next) =>
U.currentUserIsAdmin (response)
? next ()
: response.sendStatus (403)

const DELETEPolicy = (request, response, next) =>
U.currentUserIsAdmin (response)
? next ()
: response.sendStatus (403)

exports.GETPolicy = GETPolicy
exports.POSTPolicy = POSTPolicy
exports.PATCHPolicy = PATCHPolicy
exports.DELETEPolicy = DELETEPolicy
110 changes: 69 additions & 41 deletions routes/problem.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
/**
* Created by abhishek on 04/04/17.
*/
'use strict';

const express = require('express');
Expand All @@ -9,6 +6,16 @@ const jsonapi = require('../util/json-api');
const ProblemPolicy = require('../policies/problem');
const router = express.Router();

const Problem = require ('../models/problem'),
Tag = require ('../models/tag')
;

const PracticeService = require ('../services/practice')
;

const R = require ('ramda')
;

/**
* @api {get} /api/problems It provides a endpoint to view all problems.
* @apiName GetProblem
Expand All @@ -23,15 +30,13 @@ router.get('/', ProblemPolicy.GETPolicy, function (req, res, next) {
ProblemService.getAllowedProblems(res.locals.problem_ids,res.locals.user.id).then(function (result) {
jsonapi.success(res, JSON.parse(JSON.stringify(result)), "problem");
}).catch(function (err) {
console.error (err)
jsonapi.error(res, 500, err);
});
} else {
// check if user is admin or student and then send source data
ProblemService.getProblems(req.query, res.locals.user.id, req.filter).then(function (result) {
jsonapi.success(res, result, "problem");
}).catch(function (err) {
console.error (err)
jsonapi.error(res, 500, err);
});
}
Expand All @@ -47,16 +52,39 @@ router.get('/', ProblemPolicy.GETPolicy, function (req, res, next) {
* @apiHeader {String} Access-Token Your Judge API Access Token.
*
*/
router.patch('/:id', ProblemPolicy.PATCHPolicy, (req,res)=>{
router.patch('/:id', ProblemPolicy.PATCHPolicy, (request, response) => {
const problem = jsonapi.deserialize ('problem', request.body)

const problem = jsonapi.deserialize('problem',req.body);
ProblemService.updateProblem(problem , res.locals.user.id).then(result=>{
res.sendStatus(204);
}).catch(function (err) {
jsonapi.error(res, 500, err);
});
Problem.findById (problem.id, {
include: [
{ model: Tag, attributes: ['id'] }
]
})
.then (result => {
const existingTags = result.tags.map (tag => tag.id),
newTags = problem.tags.map (R.nAry (1, parseInt)),
tagsToDelete = existingTags.filter (id => ! R.contains (id, newTags)),
tagsToAdd = newTags.filter (id => ! R.contains (id, existingTags))
;

});
return Promise.all ([
tagsToAdd,
tagsToDelete,
ProblemService.updateProblem (problem, response.locals.user.id)
])
})

.then (([tagsToAdd, tagsToDelete, result]) => {
PracticeService.addProblemToPracticeCategories (problem, tagsToAdd)
PracticeService.removeProblemFromPracticeCategories (problem, tagsToDelete)

return response.sendStatus (204)
})

.catch((error) => {
return jsonapi.error(response, 500, error)
})
})

/**
* @api {post} /api/problems It provides a endpoint to add a problem.
Expand All @@ -70,13 +98,14 @@ router.patch('/:id', ProblemPolicy.PATCHPolicy, (req,res)=>{
*/

router.post('/', ProblemPolicy.POSTPolicy, (req,res) => {
let problem = jsonapi.deserialize('problem',req.body);
problem.created_by = res.locals.user.id;
ProblemService.addProblem(problem , res.locals.user.id).then(result => {
jsonapi.success(res,JSON.parse(JSON.stringify(result)) , 'problem');
}).catch(function (err) {
jsonapi.error(res, 500, err);
});
let problem = jsonapi.deserialize('problem',req.body);
problem.created_by = res.locals.user.id;
ProblemService.addProblem(problem , res.locals.user.id).then(result => {
// Add problem to corresponding practice categories.
jsonapi.success(res,JSON.parse(JSON.stringify(result)) , 'problem');
}).catch(function (err) {
jsonapi.error(res, 500, err);
});
});

/**
Expand All @@ -90,11 +119,11 @@ router.post('/', ProblemPolicy.POSTPolicy, (req,res) => {
*
*/
router.delete('/:id', ProblemPolicy.DELETEPolicy, (req,res) => {
ProblemService.deleteProblem(req.params.id).then(result=>{
res.sendStatus(204);
}).catch(function (err) {
jsonapi.error(res, 500, err);
});
ProblemService.deleteProblem(req.params.id).then(result=>{
res.sendStatus(204);
}).catch(function (err) {
jsonapi.error(res, 500, err);
});
})

/**
Expand All @@ -109,11 +138,11 @@ router.delete('/:id', ProblemPolicy.DELETEPolicy, (req,res) => {
*/

router.get('/weekly/:problem_id', (req, res) => {
ProblemService.getProblem(req.params.problem_id, true).then(function (result) {
jsonapi.success(res, result, 'problem');
}).catch(function (err) {
jsonapi.error(res, 500, err);
});
ProblemService.getProblem(req.params.problem_id, true).then(function (result) {
jsonapi.success(res, result, 'problem');
}).catch(function (err) {
jsonapi.error(res, 500, err);
});
});

/**
Expand All @@ -127,16 +156,15 @@ router.get('/weekly/:problem_id', (req, res) => {
*
*/
router.get('/:problem_id', ProblemPolicy.GETByIdPolicy, (req, res) => {
ProblemService.getProblem(req.params.problem_id, false, res.locals.user.id).then(function (result) {
let plain_result = result.get({plain: true});
if(res.locals.currentUserIsNotAdmin) {
delete plain_result.source;
}
jsonapi.success(res, plain_result, 'problem');
}).catch(function (err) {
console.error (err)
jsonapi.error(res, 500, err);
});
ProblemService.getProblem(req.params.problem_id, false, res.locals.user.id).then(function (result) {
let plain_result = result.get({plain: true});
if(res.locals.currentUserIsNotAdmin) {
delete plain_result.source;
}
jsonapi.success(res, plain_result, 'problem');
}).catch(function (err) {
jsonapi.error(res, 500, err);
});
});

module.exports = router;
module.exports = router;
1 change: 0 additions & 1 deletion routes/submission.js
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,6 @@ router.post('/result/:submission_id', function (request, response, next) {
response.status (200).json ({ message: "Submission Updated" })
})
.catch (error => {
console.error (error)
response.status (500).json ({ message: "Submission Couldn't be Updated" })
})

Expand Down
Loading

0 comments on commit d937ca7

Please sign in to comment.