You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Hydro/packages/syzoj-ng-api/handlers/problem.ts

131 lines
5.0 KiB
TypeScript

import { FilterQuery } from 'mongodb';
import { Pdoc } from 'hydrooj/dist/interface';
import problem from 'hydrooj/dist/model/problem';
import record from 'hydrooj/dist/model/record';
import user from 'hydrooj/dist/model/user';
import { PERM, PRIV } from 'hydrooj/dist/model/builtin';
import {
Route, Handler, Types, post,
} from 'hydrooj/dist/service/server';
export class QueryProblemSetAPIHandler extends Handler {
@post('locale', Types.String, true)
@post('keyword', Types.String, true)
@post('ownerId', Types.Int, true)
@post('nonpublic', Types.Boolean, true)
@post('tagsIds', Types.Array, true)
@post('skipCount', Types.UnsignedInt, true)
@post('takeCount', Types.UnsignedInt, true)
async post(
domainId: string, locale: string, $search: string,
owner: number, nonpublic = false, tags = [],
skip = 0, take = 0,
) {
if (
(!this.user.hasPerm(PERM.PERM_VIEW_PROBLEM))
|| (nonpublic && !this.user.hasPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN))
) {
this.response.body = { error: 'PERMISSION_DENIED' };
return;
}
const query: FilterQuery<Pdoc> = {};
if ($search) query.$text = { $search };
if (tags?.length) query.$and = tags.map((tag) => ({ tag }));
if (owner) query.owner = owner;
if (!nonpublic) query.hidden = false;
const [raw, count] = await Promise.all([
problem.getMulti(domainId, query).sort({ pid: 1, docId: 1 })
.skip(skip).limit(take)
.toArray(),
problem.getMulti(domainId, query).count(),
]);
const result = [];
for (const doc of raw) {
// eslint-disable-next-line no-await-in-loop
const [rdoc] = await record
.getUserInProblemMulti(domainId, this.user._id, doc.docId)
.sort({ _id: -1 })
.limit(1)
.toArray();
let locales = [];
try {
const ct = typeof doc.content === 'string' ? JSON.parse(doc.content) : doc.content;
if (ct instanceof Array) locales = [this.session.viewLang || this.user.viewLang];
else locales = Object.keys(ct);
} catch (e) {
locales = [this.session.viewLang || this.user.viewLang];
}
result.push({
meta: {
id: doc.docId,
displayId: doc.pid,
type: 'Traditional',
isPublic: !doc.hidden,
publicTime: doc._id.getTimestamp(),
ownerId: doc.owner,
locales,
submissionCount: doc.nSubmit,
acceptedSubmissionCount: doc.nAccept,
},
title: doc.title,
tags: [], // TODO
resultLocale: this.session.viewLang || this.user.viewLang,
submission: rdoc
? {
id: rdoc._id,
isPublic: !doc.hidden,
codeLanguage: rdoc.lang,
answerSize: rdoc.code.length,
score: rdoc.score,
status: rdoc.status,
submitTime: rdoc._id.getTimestamp(),
timeUsed: rdoc.time,
memoryUsed: rdoc.memory,
}
: null,
});
}
this.response.body = {
result,
count,
permissions: {
createProblem: this.user.hasPerm(PERM.PERM_CREATE_PROBLEM),
manageTags: this.user.hasPerm(PERM.PERM_EDIT_PROBLEM),
filterByOwner: this.user.hasPerm(PERM.PERM_VIEW_PROBLEM),
filterNonpublic: this.user.hasPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN),
},
};
if (owner) {
const udoc = await user.getById(domainId, owner);
this.response.body.filterOwner = {
id: udoc._id,
username: udoc.uname,
email: udoc.mail,
nickname: udoc.displayName || udoc.uname,
bio: udoc.bio,
avatar: {
type: udoc.avatar.split(':')[0],
key: udoc.avatar.split(':')[1],
},
isAdmin: udoc.hasPriv(PRIV.PRIV_MANAGE_ALL_DOMAIN) || udoc.hasPerm(PERM.PERM_ADMIN),
acceptedProblemCount: udoc.nAccept,
submissionCount: udoc.nSubmit,
rating: udoc.rating,
registrationTime: udoc.regat,
};
}
if (tags) {
this.response.body.filterTags = tags.map((tag) => ({
id: tag,
name: tag,
color: '1',
nameLocale: locale,
}));
}
}
}
export async function apply() {
Route('syzoj_api_problem_queryProblemSet', '/api/problem/queryProblemSet', QueryProblemSetAPIHandler);
}