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(); currentPId = 1; } 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/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: '失败' }); } });