|
|
|
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 test = [];
|
|
|
|
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 {
|
|
|
|
test.push(resultItem.order);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if (test.length !== 0) {
|
|
|
|
const minOrder = Math.min.apply(null,test);
|
|
|
|
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();
|
|
|
|
|
|
|
|
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,
|
|
|
|
newRating
|
|
|
|
})
|
|
|
|
} 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/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;
|
|
|
|
})
|
|
|
|
// if (result.length !== 0) {
|
|
|
|
// const currentClassifyId = result[0].id;
|
|
|
|
//
|
|
|
|
// }
|
|
|
|
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: '失败' });
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
|