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