core: user-import: enhanced

This commit is contained in:
undefined committed 2022-11-28 17:33:28 +08:00
1 parent 27528f9a4d
commit 89fb04bfb3
4 files changed
+34 -18

No files matched your search

+2
View File
@@ -57,8 +57,10 @@ pager_previous: ‹ Previous
perm_contest: Contests
perm_discussion: Discussions
perm_general: General
perm_homework: Homework
perm_problem_solution: Problem Solutions
perm_problem: Problems
perm_ranking: Ranking
perm_record: Records
perm_training: Trainings
problem_create: Problem Create
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "hydrooj",
"version": "4.4.1",
"version": "4.4.2",
"bin": "bin/hydrooj.js",
"main": "src/plugin-api",
"module": "src/plugin-api",
+4 -4
View File
@@ -232,6 +232,7 @@ export class ContestScoreboardHandler extends ContestDetailBaseHandler {
@param('tid', Types.ObjectID)
@param('ext', Types.Range(['csv', 'html', 'ghost']), true)
async get(domainId: string, tid: ObjectID, ext = '') {
if (!contest.canShowScoreboard.call(this, this.tdoc, true)) throw new ContestScoreboardHiddenError(tid);
if (ext) {
await this.exportScoreboard(domainId, tid, ext);
return;
@@ -248,8 +249,7 @@ export class ContestScoreboardHandler extends ContestDetailBaseHandler {
}
async exportGhost(domainId: string, tid: ObjectID) {
const tdoc = await contest.get(domainId, tid);
if (!contest.canShowScoreboard.call(this, tdoc)) throw new ContestScoreboardHiddenError(tid);
const tdoc = this.tdoc;
const [pdict, teams] = await Promise.all([
problem.getList(domainId, tdoc.pids, true, false, undefined, true),
contest.getMultiStatus(domainId, { docId: tid }).toArray(),
@@ -538,8 +538,8 @@ export async function apply(ctx) {
ctx.Route('contest_detail', '/contest/:tid', ContestDetailHandler, PERM.PERM_VIEW_CONTEST);
ctx.Route('contest_broadcast', '/contest/:tid/broadcast', ContestBroadcastHandler);
ctx.Route('contest_edit', '/contest/:tid/edit', ContestEditHandler, PERM.PERM_VIEW_CONTEST);
ctx.Route('contest_scoreboard', '/contest/:tid/scoreboard', ContestScoreboardHandler, PERM.PERM_VIEW_CONTEST);
ctx.Route('contest_scoreboard_download', '/contest/:tid/export/:ext', ContestScoreboardHandler, PERM.PERM_VIEW_CONTEST);
ctx.Route('contest_scoreboard', '/contest/:tid/scoreboard', ContestScoreboardHandler, PERM.PERM_VIEW_CONTEST_SCOREBOARD);
ctx.Route('contest_scoreboard_download', '/contest/:tid/export/:ext', ContestScoreboardHandler, PERM.PERM_VIEW_CONTEST_SCOREBOARD);
ctx.Route('contest_code', '/contest/:tid/code', ContestCodeHandler, PERM.PERM_VIEW_CONTEST);
ctx.Route('contest_files', '/contest/:tid/file', ContestFilesHandler, PERM.PERM_VIEW_CONTEST);
ctx.Route('contest_file_download', '/contest/:tid/file/:filename', ContestFileDownloadHandler, PERM.PERM_VIEW_CONTEST);
+27 -13
View File
@@ -209,6 +209,7 @@ class SystemConfigHandler extends SystemHandler {
}
}
/* eslint-disable no-await-in-loop */
class SystemUserImportHandler extends SystemHandler {
async get() {
this.response.body.users = [];
@@ -219,49 +220,62 @@ class SystemUserImportHandler extends SystemHandler {
@param('draft', Types.Boolean)
async post(domainId: string, _users: string, draft: boolean) {
const users = _users.split('\n');
const udocs = [];
const udocs: { email: string, username: string, password: string, displayName?: string, payload?: any }[] = [];
const messages = [];
const mapping = {};
const groups: Record<string, string[]> = {};
for (const i in users) {
const u = users[i];
if (!u.trim()) continue;
let [email, username, password, displayName] = u.split(',').map((t) => t.trim());
if (!email || !username || !password) [email, username, password, displayName] = u.split('\t').map((t) => t.trim());
let [email, username, password, displayName, extra] = u.split(',').map((t) => t.trim());
if (!email || !username || !password) [email, username, password, displayName, extra] = u.split('\t').map((t) => t.trim());
if (email && username && password) {
if (!isEmail(email)) messages.push(`Line ${+i + 1}: Invalid email.`);
else if (!Types.Username[1](username)) messages.push(`Line ${+i + 1}: Invalid username`);
else if (!isPassword(password)) messages.push(`Line ${+i + 1}: Invalid password`);
// eslint-disable-next-line no-await-in-loop
else if (await user.getByEmail('system', email)) {
messages.push(`Line ${+i + 1}: Email ${email} already exists.`);
// eslint-disable-next-line no-await-in-loop
} else if (await user.getByUname('system', username)) {
messages.push(`Line ${+i + 1}: Username ${username} already exists.`);
} else {
const payload: any = {};
try {
const data = JSON.parse(extra);
if (data.group) {
if (!groups[data.group]) groups[data.group] = [];
groups[data.group].push(email);
}
if (data.school) payload.school = data.school;
} catch (e) { }
udocs.push({
email, username, password, displayName,
email, username, password, displayName, payload,
});
}
} else messages.push(`Line ${+i + 1}: Input invalid.`);
}
messages.push(`${udocs.length} users found.`);
if (!draft) {
for (const {
email, username, password, displayName,
} of udocs) {
for (const udoc of udocs) {
try {
// eslint-disable-next-line no-await-in-loop
const uid = await user.create(email, username, password);
// eslint-disable-next-line no-await-in-loop
if (displayName) await domain.setUserInDomain(domainId, uid, { displayName });
const uid = await user.create(udoc.email, udoc.username, udoc.password);
mapping[udoc.email] = uid;
if (udoc.displayName) await domain.setUserInDomain(domainId, uid, { displayName: udoc.displayName });
if (udoc.payload?.school) await user.setById(uid, { school: udoc.payload.school });
if (udoc.payload?.studentId) await user.setById(uid, { studentId: udoc.payload.studentId });
} catch (e) {
messages.push(e.message);
}
}
}
for (const name in groups) {
const uids = groups[name].map((i) => mapping[i]).filter((i) => i);
if (uids.length) await user.updateGroup(domainId, name, uids);
}
this.response.body.users = udocs;
this.response.body.messages = messages;
}
}
/* eslint-enable no-await-in-loop */
const Priv = Object.fromEntries(Object.entries(PRIV).filter(
(i) => (!i[0].endsWith('SELF') && !['PRIV_DEFAULT', 'PRIV_NEVER', 'PRIV_NONE', 'PRIV_ALL'].includes(i[0])),