算法评测平台前端。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

384 lines
13 KiB

let Classify = syzoj.model('classify');
let Problem = syzoj.model('problem');
let CToP = syzoj.model('classify_to_problem');
let Article = syzoj.model('article');
let User = syzoj.model('user');
let UToP = syzoj.model('user_to_practice');
app.get('/practice', async (req, res) => {
if (!res.locals.user) {
res.render('error', {
err: new ErrorMessage('请先登录。')
});
} else {
async function getUserInfo(userId) {
let userQuery = await User.createQueryBuilder();
const currentUserInfo = await userQuery.where("id = :id", { id: userId }).getOne();
return currentUserInfo.current_p_id;
}
try {
let classifyQuery = Classify.createQueryBuilder();
let utopQuery = UToP.createQueryBuilder();
let result = await Classify.queryAll(classifyQuery);
let userQuery = await User.createQueryBuilder();
const userId = res.locals.user.id;
let currentPId = await getUserInfo(userId);
const unFinishedIdArray = [];
if (!currentPId) {
// 用户第一次进入练习板块
await userQuery.update(User).set({current_p_id: 1}).where("id = :id", { id:userId }).execute();
} else {
await result.forEachAsync(async resultItem => {
const c_id = resultItem.id;
let utopInfo = await utopQuery.where('c_id=:c_id',{c_id}).andWhere('u_id=:u_id',{u_id:userId}).andWhere("is_finished=1").getMany();
resultItem.ac_num = utopInfo.length || 0;
if (resultItem.ac_num === resultItem.problem_num) {
if (resultItem.order < result.length ) {
currentPId = resultItem.order + 1
await userQuery.update(User).set({current_p_id: currentPId}).where("id = :id", { id:userId }).execute();
}
} else {
unFinishedIdArray.push(resultItem.order);
}
});
}
if (unFinishedIdArray.length !== 0) {
const minOrder = Math.min.apply(null,unFinishedIdArray);
currentPId = minOrder;
await userQuery.update(User).set({current_p_id: minOrder}).where("id = :id", { id:userId }).execute();
}
result.sort(function(a,b) {
return a.order - b.order;
});
result.forEach(function(item) {
if (item.order <= currentPId) {
item.href = `/practice/classify/${item.id}`;
}
item.isNow = item.order === currentPId;
});
let userACArray = await utopQuery.where('u_id=:u_id',{u_id:userId}).andWhere("is_finished=1").getMany();
if (syzoj.config.practice_rating) {
const originRating = syzoj.config.default.user.rating;
const newRating = originRating + userACArray.length * syzoj.config.practice_rating;
await userQuery.update(User).set({rating: newRating}).where('id=:u_id',{u_id:userId}).execute();
}
res.render('practice', {
user:res.locals.user,
result
})
} catch (e) {
syzoj.log(e);
res.render('error', {
err: e
});
}
}
});
app.get('/practice/classify/:cid/problem/:pid', async (req, res) => {
try {
let id = parseInt(req.params.pid);
let cid = parseInt(req.params.cid);
let problem = await Problem.findById(id);
if (!problem) throw new ErrorMessage('无此题目。');
if (!await problem.isAllowedUseBy(res.locals.user)) {
throw new ErrorMessage('您没有权限进行此操作。');
}
problem.allowedEdit = await problem.isAllowedEditBy(res.locals.user);
problem.allowedManage = await problem.isAllowedManageBy(res.locals.user);
if (problem.is_public || problem.allowedEdit) {
await syzoj.utils.markdown(problem, ['description', 'input_format', 'output_format', 'example', 'limit_and_hint']);
} else {
throw new ErrorMessage('您没有权限进行此操作。');
}
let state = await problem.getJudgeState(res.locals.user, false);
problem.tags = await problem.getTags();
await problem.loadRelationships();
let testcases = await syzoj.utils.parseTestdata(problem.getTestdataPath(), problem.type === 'submit-answer');
let discussionCount = await Article.count({ problem_id: id });
res.render('practice_problem', {
problem: problem,
state: state,
lastLanguage: res.locals.user ? await res.locals.user.getLastSubmitLanguage() : null,
testcases: testcases,
discussionCount: discussionCount,
pid: id,
cid
});
} catch (e) {
syzoj.log(e);
res.render('error', {
err: e
});
}
});
app.get('/practice/classify/:id', async (req, res) => {
try {
const c_id = parseInt(req.params.id);
const u_id = res.locals.user.id;
let ctopQuery = CToP.createQueryBuilder();
let query = await Problem.createQueryBuilder();
let utopQuery = UToP.createQueryBuilder();
let problemArray = await ctopQuery.where("c_id = :id", { id:c_id }).getMany();
let utopResult = await utopQuery.where("c_id = :c_id", { c_id }).andWhere("u_id=:u_id", {u_id}).getMany();
let problems = await problemArray.mapAsync(async problemArrayInfo => query.where('id=:id', {id: problemArrayInfo.p_id}).getOne());
problems.forEach(function(problemItem) {
const obj = utopResult.find(function(item){return parseInt(item.p_id) === parseInt(problemItem.id)});
problemItem.href = `/practice/classify/${c_id}/problem/${problemItem.id}`;
if (obj) {
problemItem.statusStr = obj.is_practice && obj.is_finished ? '已练习且已通过' : '已练习但未通过';
} else {
problemItem.statusStr = '尚未练习'
}
});
problems.sort(function(a, b){
return a.id - b.id;
})
res.render('practice_classify', {
user:res.locals.user,
problems
})
} catch (e) {
syzoj.log(e);
res.render('error', {
err: e
});
}
});
app.get('/api/practice/classify/:id', async (req, res) => {
try {
let id = parseInt(req.params.id);
let query = await Classify.createQueryBuilder();
let classifyInfo = await query.where('id=:id',{id}).getOne();
let problem = await CToP.queryBy({c_id: id});
res.send({ classifyInfo, problem:problem.map(function(item){return item.p_id}) });
} catch(e) {
res.send({ error_code: e.errno, error_msg: '失败' });
}
});
app.get('/api/pass/:cid/:pid',async (req, res) => {
try {
const c_id = parseInt(req.params.cid);
const p_id = parseInt(req.params.pid);
const u_id = res.locals.user.id;
let utopQuery = UToP.createQueryBuilder();
let query = Classify.createQueryBuilder();
let userQuery = User.createQueryBuilder();
let classify = await Classify.queryAll(query);
classify.sort(function(a,b) {
return a.order - b.order;
});
let utopResult = await utopQuery.where("c_id = :c_id", { c_id }).andWhere("u_id=:u_id", {u_id}).andWhere("p_id=:p_id", {p_id}).getOne();
// 查询到结果了
if (utopResult ) {
// mock答题通过了
await utopQuery.update(UToP).set({is_finished: 1, practice_num: utopResult.practice_num + 1}).where("c_id = :c_id", { c_id }).andWhere("u_id=:u_id", {u_id}).andWhere("p_id=:p_id", {p_id}).execute();
// 说明两个题都练习过了
} else {
let utop = await UToP.create({
u_id,
c_id,
p_id,
is_practice: 1,
is_finished: 1,
practice_num: 1
});
await utop.save();
}
res.send();
} catch(e) {
res.send({ error_code: e.errno, error_msg: '练习失败,请稍后重试' });
}
});
app.get('/api/practice/nopass/:cid/:pid',async (req, res) => {
try {
const c_id = parseInt(req.params.cid);
const p_id = parseInt(req.params.pid);
const u_id = res.locals.user.id;
let utopQuery = UToP.createQueryBuilder();
let query = Classify.createQueryBuilder();
let utopResult = await utopQuery.where("c_id = :c_id", { c_id }).andWhere("u_id=:u_id", {u_id}).andWhere("p_id=:p_id", {p_id}).getOne();
// 查询到结果了
if (utopResult) {
// mock答题通过了
await utopQuery.update(UToP).set({is_practice:1, is_finished: 0, practice_num: utopResult.practice_num + 1}).where("c_id = :c_id", { c_id }).andWhere("u_id=:u_id", {u_id}).andWhere("p_id=:p_id", {p_id}).execute();
// 说明两个题都练习过了
} else {
let utop = await UToP.create({
u_id,
c_id,
p_id,
is_practice: 1,
practice_num: 1,
is_finished: 0
});
await utop.save();
}
res.send();
} catch(e) {
res.send({ error_code: e.errno, error_msg: '练习失败,请稍后重试' });
}
});
app.put('/api/practice/classify/update/:id', async (req, res) => {
try {
let id = parseInt(req.params.id);
let u_id = parseInt(res.locals.user.id);
let utopQuery = UToP.createQueryBuilder();
let classifyQuery = await Classify.createQueryBuilder();
let ctopQuery = await CToP.createQueryBuilder();
const {name, intro, problemIdArray, order} = req.body;
let classifyInfo = await classifyQuery.where('id=:id',{id}).getOne();
// 新增题
if (problemIdArray.length > classifyInfo.problem_num) {
/*
* 把当前练习的阶段设置为新增题的阶段因为新增题后当前阶段的题目就没答完
* */
}
// 删除题
if (problemIdArray.length < classifyInfo.problem_num) {
// 1。找出两个数组的差异
function findDifference(source, target){
const parseIntTarget = target.map(function(item){
return parseInt(item);
})
return source.filter(function(item){
return !parseIntTarget.includes(item);
})
}
let ctopInfo = await ctopQuery.where('c_id=:id',{id}).getMany();
const targetArray = ctopInfo.map(function(ctopInfoItem){
return ctopInfoItem.p_id;
})
// 2.从utop表里清除被删除题目的练习记录
const differenceArray = findDifference(targetArray, problemIdArray);
differenceArray.forEachAsync(async differenceItem => {
await utopQuery.delete().from(UToP).where("c_id = :id", { id }).andWhere("u_id=:u_id",{u_id}).andWhere("p_id=:p_id",{p_id:differenceItem}).execute();
})
}
let updateClassifyInfo = await classifyQuery.update(Classify).set({name, intro, order, problem_num: problemIdArray.length}).where("id = :id", { id }).execute();
await ctopQuery.delete().from(CToP).where("c_id = :id", { id }).execute();
problemIdArray.forEach(async function (item) {
let ctop = await CToP.create({
c_id: id,
p_id: item
});
await ctop.save();
})
res.send({ updateClassifyInfo });
} catch(e) {
res.send({ error_code: e.errno, error_msg: '失败' });
}
});
app.get('/api/pagination/allproblem', async (req, res) => {
try {
let query = await Problem.createQueryBuilder();
let problemInfo = await query.select('COUNT(*)', 'count').getRawOne();
res.send({ problemInfo});
} catch(e) {
res.send({ error_code: e.errno, error_msg: '失败' });
}
});
app.get('/api/pagination', async (req, res) => {
let pagesize = parseInt(req.query.pagesize);
let page = parseInt(req.query.page);
try {
let query = await Problem.createQueryBuilder();
let problemInfo = await query.limit(pagesize).offset(pagesize*page).getMany();
res.send({ problemInfo});
} catch(e) {
res.send({ error_code: e.errno, error_msg: '失败' });
}
});
app.get('/api/getProblem/:id', async (req, res) => {
let id = parseInt(req.params.id);
try {
let query = await Problem.createQueryBuilder();
let problemInfo = await query.where('id=:id', {id}).getOne()
res.send({ problemInfo});
} catch(e) {
res.send({ error_code: e.errno, error_msg: '失败' });
}
});
app.get('/api/practice/all', async (req, res) => {
try {
let classifyQuery = Classify.createQueryBuilder();
let ctopQuery = CToP.createQueryBuilder();
let result = await Classify.queryAll(classifyQuery);
result.sort(function(a,b) {
return a.order - b.order;
})
let problem = await CToP.queryAll(ctopQuery);
res.send({ result, problem});
} catch(e) {
res.send({ error_code: e.errno, error_msg: '失败' });
}
});
app.get('/api/admin/practice/all', async (req, res) => {
try {
let classifyQuery = Classify.createQueryBuilder();
let result = await Classify.queryAll(classifyQuery);
res.send({ result });
} catch(e) {
res.send({ error_code: e.errno, error_msg: '失败' });
}
});
app.post('/api/practice/create', async (req, res) => {
try {
const {name, intro, problemIdArray, order} = req.body;
let classify = await Classify.create({
name,
intro,
order,
problem_num: problemIdArray.length || 0,
updateTime: parseInt((new Date()).getTime() / 1000, 10),
createTime: parseInt((new Date()).getTime() / 1000)
});
await classify.save();
let query = Classify.createQueryBuilder();
let recordArray = await Classify.queryAll(query);
let lastRecordId = recordArray[recordArray.length - 1].id;
problemIdArray.forEach(async function (item) {
let ctop = await CToP.create({
c_id: lastRecordId,
p_id: item
})
await ctop.save();
})
res.send();
} catch(e) {
res.send({ error_code: e.errno, error_msg: '创建失败' });
}
});
app.get('/api/problem/all', async (req, res) => {
try {
let query = Problem.createQueryBuilder();
let result = await Problem.querySomeColumn(query);
res.send({ result });
} catch(e) {
res.send({ error_code: e.errno, error_msg: '失败' });
}
});