修复参加比赛的错误

pull/1/head
masnn 5 years ago
parent 32ad47e031
commit f40e4e2c74

@ -92,6 +92,12 @@ class ContestNotAttendedError extends ForbiddenError {
this.params = [tid];
}
}
class ContestAlreadyAttendedError extends ForbiddenError {
constructor(tid, uid) {
super('You\'ve already attended this contest.');
this.params = [tid, uid];
}
}
class ContestNotLiveError extends ForbiddenError {
constructor(tid) {
super('This contest is not live.');
@ -148,7 +154,7 @@ module.exports = {
ValidationError, ProblemNotFoundError, TrainingNotFoundError,
ContestNotFoundError, RecordNotFoundError, SolutionNotFoundError,
AlreadyVotedError, ContestNotAttendedError, ContestNotLiveError,
ContestScoreboardHiddenError
ContestScoreboardHiddenError, ContestAlreadyAttendedError
};
/*
@ -278,12 +284,6 @@ class InvalidJoinInvitationCodeError(ForbiddenError):
return 'The invitation code you provided is invalid.'
class ContestAlreadyAttendedError(ForbiddenError):
@property
def message(self):
return "You've already attended this contest."
class HomeworkScoreboardHiddenError(ForbiddenError):
@property
def message(self):

@ -14,10 +14,10 @@ const
class ContestHandler extends Handler {
canViewHiddenScoreboard() {
return this.hasPerm(PERM_VIEW_CONTEST_HIDDEN_SCOREBOARD);
return this.user.hasPerm(PERM_VIEW_CONTEST_HIDDEN_SCOREBOARD);
}
canShowRecord(tdoc, allowPermOverride = true) {
if (contest.RULES[tdoc.rule].showRecordFunc(tdoc, new Date())) return true;
if (contest.RULES[tdoc.rule].showRecord(tdoc, new Date())) return true;
if (allowPermOverride && this.canViewHiddenScoreboard(tdoc)) return true;
return false;
}
@ -27,14 +27,15 @@ class ContestHandler extends Handler {
return false;
}
async getScoreboard(tid, isExport = false) {
let [tdoc, tsdocs] = await contest.getAndListStatus(tid);
let tdoc = await contest.get(tid);
if (!this.canShowScoreboard(tdoc)) throw new ContestScoreboardHiddenError(tid);
let tsdocs = await contest.getMultiStatus(tid).sort(contest.RULES[tdoc.rule].statusSort).toArray();
let uids = [];
for (let tsdoc of tsdocs) uids.push(tsdoc.uid);
let [udict, pdict] = await Promise.all([user.getList(uids), problem.getList(tdoc['pids'])]);
let ranked_tsdocs = contest.RULES[tdoc.rule].rank(tsdocs);
let rows = contest.RULES[tdoc.rule].scoreboard(isExport, this.translate, tdoc, ranked_tsdocs, udict, pdict);
return tdoc, rows, udict;
let rows = contest.RULES[tdoc.rule].scoreboard(isExport, str => str ? str.toString().translate(this.user.language) : '', tdoc, ranked_tsdocs, udict, pdict);
return [tdoc, rows, udict];
}
async verifyProblems(pids) {
console.log(pids);
@ -61,17 +62,17 @@ class ContestListHandler extends ContestHandler {
this.response.template = 'contest_main.html';
let tdocs, qs, tpcount;
if (!rule) {
tdocs = contest.getMulti();
tdocs = contest.getMulti().sort({ beginAt: -1 });
qs = '';
} else {
if (!contest.CONTEST_RULES.includes(rule)) throw new ValidationError('rule');
tdocs = contest.getMulti({ rule });
tdocs = contest.getMulti({ rule }).sort({ beginAt: -1 });
qs = 'rule={0}'.format(rule);
}
[tdocs, tpcount] = await paginate(tdocs, page, constants.CONTEST_PER_PAGE);
let tids = [];
for (let tdoc of tdocs) tids.push(tdoc._id);
let tsdict = await contest.getListStatus(this.uid, tids);
let tsdict = await contest.getListStatus(this.user._id, tids);
this.response.body = {
page, tpcount, qs, rule, tdocs, tsdict
};
@ -84,7 +85,7 @@ class ContestDetailHandler extends ContestHandler {
async get({ page = 1 }) {
this.response.template = 'contest_detail.html';
let [tsdoc, pdict] = await Promise.all([
contest.getStatus(this.tdoc._id, this.uid),
contest.getStatus(this.tdoc._id, this.user._id),
problem.getList(this.tdoc.pids)
]);
let psdict = {}, rdict = {}, attended;
@ -111,7 +112,7 @@ class ContestDetailHandler extends ContestHandler {
}
async post_attend() {
if (contest.is_done(this.tdoc)) throw new ContestNotLiveError(this.tdoc._id);
await contest.attend(this.tdoc._id, this.uid);
await contest.attend(this.tdoc._id, this.user._id);
this.back();
}
}

@ -11,6 +11,9 @@ exports.datetime_span = function (dt, relative = true, format = '%Y-%m-%d %H:%M:
dt.format(format)
);
};
exports.nl2br = function (self) {
return self.replace(/\n/gm, '<br>');
};
exports.paginate = function* (page, num_pages) {
let radius = 2, first, last;
if (page > 1) {

@ -0,0 +1,11 @@
module.exports = function* ranked(diter, equ = (a, b) => a == b) {
let last_doc = null;
let r = 0, count = 0;
for (let doc of diter) {
count++;
if (count == 1 || !equ(last_doc, doc))
r = count;
last_doc = doc;
yield [r, doc];
}
};

@ -1,6 +1,6 @@
const
validator = require('../lib/validator'),
{ ValidationError, ContestNotFoundError } = require('../error'),
{ ValidationError, ContestNotFoundError, ContestAlreadyAttendedError } = require('../error'),
db = require('../service/db.js'),
coll = db.collection('contest'),
coll_status = db.collection('contest.status');
@ -56,7 +56,7 @@ async function getListStatus(uid, tids) {
}
async function attend(tid, uid) {
try {
await coll_status.insertOne({ tid, uid });
await coll_status.insertOne({ tid, uid, attend: 1 });
} catch (e) {
throw new ContestAlreadyAttendedError(tid, uid);
}
@ -70,10 +70,10 @@ function is_new(tdoc, days = 1) {
function is_upcoming(tdoc, days = 1) {
let now = new Date().getTime();
let readyAt = tdoc.beginAt.getTime();
return (now > readyAt + days * 24 * 3600 * 1000 && now < tdoc.beginAt);
return (now > readyAt - days * 24 * 3600 * 1000 && now < tdoc.beginAt);
}
function is_not_started(tdoc) {
return new Date() < tdoc.beginAt;
return (new Date()) < tdoc.beginAt;
}
function is_ongoing(tdoc) {
let now = new Date();

@ -1,6 +1,8 @@
module.exports = {
TEXT: 'ACM/ICPC',
check: () => { },
showScoreboard: () => true,
showRecord: (tdoc, now) => now > tdoc.endAt,
stat: (tdoc, journal) => {
let naccept = {}, effective = {}, detail = [], accept = 0, time = 0;
for (let j in journal) {

@ -1,3 +1,5 @@
const ranked = require('../../lib/rank');
module.exports = {
TEXT: 'OI',
check: () => { },
@ -10,10 +12,13 @@ module.exports = {
}
return { score, detail };
},
showScoreboard(tdoc,now){
return now>tdoc.endAt;
showScoreboard(tdoc, now) {
return now > tdoc.endAt;
},
scoreboard(is_export, _, tdoc, ranked_tsdocs, udict, dudict, pdict) {
showRecord(tdoc, now) {
return now > tdoc.endAt;
},
scoreboard(is_export, _, tdoc, ranked_tsdocs, udict, pdict) {
let columns = [
{ type: 'rank', value: _('Rank') },
{ type: 'user', value: _('User') },
@ -49,5 +54,6 @@ module.exports = {
rows.push(row);
}
return rows;
}
},
rank: tdocs => ranked(tdocs, (a, b) => a.score == b.score)
};

@ -252,7 +252,7 @@ class ConnectionHandler {
return new Promise((resolve, reject) => {
template.render(name, Object.assign(context, {
handler: this,
_: this.translate,
_: str => str ? str.toString().translate(this.user.language) : '',
user: this.user
}), (error, res) => {
console.timeEnd(name);

@ -1,3 +1,4 @@
{% set page_name = "contest_scoreboard" %}
{% extends "layout/basic.html" %}
{% block content %}
<div class="row"><div class="medium-12 columns">
@ -21,25 +22,25 @@
<tr>
{%- for column in rows[0] -%}
<th class="col--{{ column['type'] }}">
{% if column['type'] == 'problem_detail' %}
<a href="{{ reverse_url('contest_detail_problem' if tdoc['doc_type'] == vj4.model.document.TYPE_CONTEST else 'homework_detail_problem', tid=tdoc['doc_id'], pid=column['raw']['doc_id']) }}" data-tooltip="{{ column['raw']['title'] }}">{{ column['value'] }}</a>
{% if column.type == 'problem_detail' %}
<a href="{{ reverse_url('contest_detail_problem' , tid=tdoc._id, pid=column.raw._id) }}" data-tooltip="{{ column['raw']['title'] }}">{{ column['value'] }}</a>
{% else %}
{{ column['value'] }}
{{ column.value }}
{% endif %}
</th>
{%- endfor -%}
</tr>
</thead>
<tbody>
{%- for row in rows[1:] -%}
{%- for i, row in rows -%}{% if i>0 %}
<tr>
{%- for column in row -%}
<td class="col--{{ rows[0][loop.index0]['type'] }}">
{% if column['type'] == 'user' %}
{{ user.render_inline(column['raw'], badge=false) }}
{% elif column['type'] == 'record' %}
{% if column['raw'] %}
<a href="{{ reverse_url('record_detail', rid=column['raw']) }}">{{ column['value']|nl2br }}</a>
{% if column.type == 'user' %}
{{ user.render_inline(column.raw, badge=false) }}
{% elif column.type == 'record' %}
{% if column.raw %}
<a href="/r/{{ column.raw }}">{{ column.value|nl2br }}</a>
{% else %}
{{ column['value']|nl2br }}
{% endif %}
@ -49,7 +50,7 @@
</td>
{%- endfor -%}
</tr>
{%- endfor -%}
{% endif %}{%- endfor -%}
</tbody>
</table>
</div>

@ -43,11 +43,11 @@
{% endif %}
</li>
{% endif %}
{% if handler.can_show_scoreboard(tdoc, False) %}
{% if handler.canShowScoreboard(tdoc, False) %}
<li class="menu__item"><a class="menu__link" href="{{ reverse_url('homework_scoreboard', tid=tdoc['doc_id']) }}">
<span class="icon icon-statistics"></span> {{ _('Scoreboard') }}
</a></li>
{% elif handler.can_view_hidden_scoreboard(tdoc) %}
{% elif handler.canViewHiddenScoreboard(tdoc) %}
<li class="menu__item"><a class="menu__link" href="{{ reverse_url('homework_scoreboard', tid=tdoc['doc_id']) }}">
<span class="icon icon-statistics"></span> {{ _('Scoreboard (Hidden)') }}
</a></li>

Loading…
Cancel
Save