mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-17 17:36:08 +08:00
80 lines
3.4 KiB
TypeScript
80 lines
3.4 KiB
TypeScript
import {
|
|
avatar, ContestModel, Context, db, ForbiddenError,
|
|
ObjectId, PERM, STATUS, Time, UserModel,
|
|
} from 'hydrooj';
|
|
import { ResolverInput } from './interface';
|
|
|
|
interface IpLoginInfo {
|
|
_id: string;
|
|
uid: number;
|
|
}
|
|
|
|
declare module 'hydrooj' {
|
|
interface Collections {
|
|
iplogin: IpLoginInfo;
|
|
}
|
|
}
|
|
const coll = db.collection('iplogin');
|
|
|
|
function normalizeIp(ip: string) {
|
|
if (ip.startsWith('::ffff:')) return ip.slice(7);
|
|
return ip;
|
|
}
|
|
|
|
export function apply(ctx: Context) {
|
|
ctx.on('handler/init', async (that) => {
|
|
const iplogin = await coll.findOne({ _id: normalizeIp(that.request.ip) });
|
|
if (iplogin) {
|
|
that.user = await UserModel.getById(that.domain._id, iplogin.uid);
|
|
if (!that.user) {
|
|
that.user = await UserModel.getById(that.domain._id, 0);
|
|
throw new ForbiddenError(`User ${iplogin.uid}not found`);
|
|
}
|
|
that.session.ipLoggedIn = true;
|
|
that.session.uid = iplogin.uid;
|
|
that.session.user = that.user;
|
|
}
|
|
});
|
|
|
|
ctx.inject(['scoreboard'], ({ scoreboard }) => {
|
|
scoreboard.addView('resolver-tiny', 'Resolver(Tiny)', { tdoc: 'tdoc' }, {
|
|
async display({ tdoc }) {
|
|
if (!this.user.own(tdoc)) this.checkPerm(PERM.PERM_VIEW_CONTEST_HIDDEN_SCOREBOARD);
|
|
const teams = await ContestModel.getMultiStatus(tdoc.domainId, { docId: tdoc.docId }).toArray();
|
|
const udict = await UserModel.getList(tdoc.domainId, teams.map((i) => i.uid));
|
|
const teamIds: Record<number, number> = {};
|
|
for (let i = 1; i <= teams.length; i++) teamIds[teams[i - 1].uid] = i;
|
|
const time = (t: ObjectId) => Math.floor((t.getTimestamp().getTime() - tdoc.beginAt.getTime()) / Time.second);
|
|
const pid = (i: number) => String.fromCharCode(65 + i);
|
|
const unknownSchool = this.translate('Unknown School');
|
|
const submissions = teams.flatMap((i) => {
|
|
if (!i.journal) return [];
|
|
return i.journal.filter((s) => tdoc.pids.includes(s.pid)).map((s) => ({ ...s, uid: i.uid }));
|
|
});
|
|
this.response.body = {
|
|
payload: {
|
|
name: tdoc.title,
|
|
duration: Math.floor((new Date(tdoc.endAt).getTime() - new Date(tdoc.beginAt).getTime()) / 1000),
|
|
frozen: Math.floor((new Date(tdoc.lockAt).getTime() - new Date(tdoc.beginAt).getTime()) / 1000),
|
|
problems: tdoc.pids.map((i, n) => ({ name: pid(n), id: i.toString() })),
|
|
teams: teams.map((t) => ({
|
|
id: t.uid.toString(),
|
|
name: udict[t.uid].uname,
|
|
avatar: avatar(udict[t.uid].avatar),
|
|
institution: udict[t.uid].school || unknownSchool,
|
|
})),
|
|
submissions: submissions.map((i) => ({
|
|
team: i.uid.toString(),
|
|
problem: i.pid.toString(),
|
|
verdict: i.status === STATUS.STATUS_ACCEPTED ? 'AC' : 'RJ',
|
|
time: time(i.rid),
|
|
})),
|
|
} as ResolverInput,
|
|
};
|
|
this.response.template = 'resolver.html';
|
|
},
|
|
supportedRules: ['acm'],
|
|
});
|
|
});
|
|
}
|