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.
408 lines
14 KiB
408 lines
14 KiB
let Classify = syzoj.model('classify'); |
|
let JudgeState = syzoj.model('judge_state'); |
|
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(); |
|
currentPId = 1; |
|
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; |
|
}); |
|
} 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; |
|
}); |
|
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/:sid',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; |
|
const s_id = parseInt(req.params.sid); |
|
let utopQuery = UToP.createQueryBuilder(); |
|
let query = Classify.createQueryBuilder(); |
|
let userQuery = User.createQueryBuilder(); |
|
let judgeStateQuery = JudgeState.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, |
|
s_id, |
|
is_practice: 1, |
|
is_finished: 1, |
|
practice_num: 1 |
|
}); |
|
await utop.save(); |
|
} |
|
let newutopQuery = UToP.createQueryBuilder(); |
|
let userACArray = await newutopQuery.select("p_id").where('u_id=:u_id',{u_id}).andWhere("is_finished=1").getRawMany(); |
|
if (syzoj.config.practice_rating) { |
|
const scoreArray = await judgeStateQuery.select("score").addSelect("problem_id").where("user_id=:u_id",{u_id}).andWhere("type=2").andWhere("score>=100").getRawMany(); |
|
let newScore = 0; |
|
if (scoreArray && scoreArray.length !== 0) { |
|
let num = 0; |
|
for(let i=0;i<userACArray.length;i++){ |
|
const problem_id = userACArray[i].p_id; |
|
const item = scoreArray.find(item => item.problem_id === problem_id) |
|
num+=parseInt(item.score); |
|
} |
|
newScore = num - userACArray.length * 100; |
|
} |
|
const originRating = syzoj.config.default.user.rating; |
|
const newRating = originRating + newScore; |
|
await userQuery.update(User).set({rating: newRating}).where('id=:u_id',{u_id}).execute(); |
|
res.send({newRating: newRating}); |
|
} |
|
} catch(e) { |
|
console.log(e); |
|
res.send({ error_code: e.errno, error_msg: '练习失败,请稍后重试' }); |
|
} |
|
}); |
|
|
|
app.get('/api/nopass/:cid/:pid/:sid',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; |
|
const s_id = parseInt(req.params.sid); |
|
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, |
|
s_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('id').addSelect('title').getRawMany(); |
|
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: '失败' }); |
|
} |
|
}); |
|
|
|
|
|
|