let Sequelize = require('sequelize'); const randomstring = require('randomstring'); let db = syzoj.db; let User = syzoj.model('user'); let Problem = syzoj.model('problem'); let Contest = syzoj.model('contest'); let Judger = syzoj.lib('judger'); let model = db.define('judge_state', { id: { type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true }, // The data zip's md5 if it's a submit-answer problem code: { type: Sequelize.TEXT('medium') }, language: { type: Sequelize.STRING(20) }, status: { type: Sequelize.STRING(50) }, task_id: { type: Sequelize.STRING(50) }, score: { type: Sequelize.INTEGER }, total_time: { type: Sequelize.INTEGER }, code_length: { type: Sequelize.INTEGER }, pending: { type: Sequelize.BOOLEAN }, max_memory: { type: Sequelize.INTEGER }, // For NOI contest compilation: { type: Sequelize.JSON }, result: { type: Sequelize.JSON }, user_id: { type: Sequelize.INTEGER }, problem_id: { type: Sequelize.INTEGER }, submit_time: { type: Sequelize.INTEGER }, /* * "type" indicate it's contest's submission(type = 1) or normal submission(type = 0) * if it's contest's submission (type = 1), the type_info is contest_id * use this way represent because it's easy to expand // Menci:这锅我不背,是 Chenyao 留下来的坑。 */ type: { type: Sequelize.INTEGER }, type_info: { type: Sequelize.INTEGER }, is_public: { type: Sequelize.BOOLEAN } }, { timestamps: false, tableName: 'judge_state', indexes: [ { fields: ['status'], }, { fields: ['score'], }, { fields: ['user_id'], }, { fields: ['problem_id'], }, { fields: ['task_id'], }, { fields: ['id', 'is_public', 'type_info', 'type'] } ] }); let Model = require('./common'); class JudgeState extends Model { static async create(val) { return JudgeState.fromRecord(JudgeState.model.build(Object.assign({ code: '', code_length: 0, language: null, user_id: 0, problem_id: 0, submit_time: parseInt((new Date()).getTime() / 1000), type: 0, type_info: 0, pending: false, score: null, total_time: null, max_memory: null, status: 'Unknown', compilation: {}, result: {}, task_id: randomstring.generate(10), is_public: false }, val))); } async loadRelationships() { if (!this.user) { this.user = await User.fromID(this.user_id); } if (!this.problem) { if (this.problem_id) this.problem = await Problem.fromID(this.problem_id); } } async isAllowedVisitBy(user) { await this.loadRelationships(); if (user && user.id === this.problem.user_id) return true; else if (this.type === 0) return this.problem.is_public || (user && (await user.hasPrivilege('manage_problem'))); else if (this.type === 1) { let contest = await Contest.fromID(this.type_info); if (contest.isRunning()) { return user && await contest.isSupervisior(user); } else { return true; } } } async updateRelatedInfo(newSubmission) { await syzoj.utils.lock(['JudgeState::updateRelatedInfo', 'problem', this.problem_id], async () => { await syzoj.utils.lock(['JudgeState::updateRelatedInfo', 'user', this.user_id], async () => { if (this.type === 0) { await this.loadRelationships(); await this.user.refreshSubmitInfo(); await this.user.save(); await this.problem.resetSubmissionCount(); } else if (this.type === 1) { let contest = await Contest.fromID(this.type_info); await contest.newSubmission(this); } }); }); } async rejudge() { await syzoj.utils.lock(['JudgeState::rejudge', this.id], async () => { await this.loadRelationships(); let oldStatus = this.status; this.status = 'Unknown'; this.pending = false; this.score = null; if (this.language) { // language is empty if it's a submit-answer problem this.total_time = null; this.max_memory = null; } this.result = {}; this.task_id = randomstring.generate(10); await this.save(); /* let WaitingJudge = syzoj.model('waiting_judge'); let waiting_judge = await WaitingJudge.create({ judge_id: this.id, priority: 2, type: 'submission' }); await waiting_judge.save(); */ await this.problem.resetSubmissionCount(); if (oldStatus === 'Accepted') { await this.user.refreshSubmitInfo(); await this.user.save(); } if (this.type === 1) { let contest = await Contest.fromID(this.type_info); await contest.newSubmission(this); } try { await Judger.judge(this, this.problem, 1); this.pending = true; this.status = 'Waiting'; await this.save(); } catch (err) { console.log("Error while connecting to judge frontend: " + err.toString()); throw new ErrorMessage("无法开始评测。"); } }); } async getProblemType() { await this.loadRelationships(); return this.problem.type; } getModel() { return model; } } JudgeState.model = model; module.exports = JudgeState;