mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
core: allow extra user private & public fields (#1059)
This commit is contained in:
1 parent
8f2c5a17cd
commit
3a25e4e53f
11 files changed
+61
-46
No files matched your search
@@ -886,7 +886,7 @@ View Contest: 查看比赛
|
|||||||
View contests: 查看比赛
|
View contests: 查看比赛
|
||||||
View Details: 查看详情
|
View Details: 查看详情
|
||||||
View discussions: 查看讨论
|
View discussions: 查看讨论
|
||||||
View domain user displayname: 显示域中用户的显示名
|
View domain user private info: 显示域中用户的私有信息
|
||||||
View hidden contest submission status and scoreboard: 查看隐藏的比赛递交状态和成绩表
|
View hidden contest submission status and scoreboard: 查看隐藏的比赛递交状态和成绩表
|
||||||
View hidden homework submission status and scoreboard: 查看隐藏的作业递交状态和成绩表
|
View hidden homework submission status and scoreboard: 查看隐藏的作业递交状态和成绩表
|
||||||
View hidden problems: 查看隐藏的题目
|
View hidden problems: 查看隐藏的题目
|
||||||
|
|||||||
@@ -222,12 +222,7 @@ export class ContestPrintHandler extends ContestDetailBaseHandler {
|
|||||||
const tasks = await contest.getMultiPrintTask(domainId, tid, isContestAdmin ? {} : { owner: this.user._id })
|
const tasks = await contest.getMultiPrintTask(domainId, tid, isContestAdmin ? {} : { owner: this.user._id })
|
||||||
.project({ _id: 1, title: 1, owner: 1, status: 1 }).sort({ _id: 1 }).toArray();
|
.project({ _id: 1, title: 1, owner: 1, status: 1 }).sort({ _id: 1 }).toArray();
|
||||||
const uids = Array.from(new Set(tasks.map((i) => i.owner)));
|
const uids = Array.from(new Set(tasks.map((i) => i.owner)));
|
||||||
const udict = await user.getListForRender(
|
const udict = await user.getListForRender(domainId, uids, this.user.hasPerm(PERM.PERM_VIEW_USER_PRIVATE_INFO));
|
||||||
domainId, uids,
|
|
||||||
this.user.hasPerm(PERM.PERM_VIEW_DISPLAYNAME)
|
|
||||||
? ['displayName', 'school', 'studentId']
|
|
||||||
: [],
|
|
||||||
);
|
|
||||||
this.response.body = { tasks, udict };
|
this.response.body = { tasks, udict };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -516,7 +511,7 @@ export class ContestManagementHandler extends ContestManagementBaseHandler {
|
|||||||
files: sortFiles(this.tdoc.files || []),
|
files: sortFiles(this.tdoc.files || []),
|
||||||
udict: await user.getListForRender(
|
udict: await user.getListForRender(
|
||||||
domainId, tcdocs.map((i) => i.owner),
|
domainId, tcdocs.map((i) => i.owner),
|
||||||
this.user.hasPerm(PERM.PERM_VIEW_DISPLAYNAME) ? ['displayName'] : [],
|
this.user.hasPerm(PERM.PERM_VIEW_USER_PRIVATE_INFO),
|
||||||
),
|
),
|
||||||
tcdocs,
|
tcdocs,
|
||||||
urlForFile: (filename: string) => this.url('contest_file_download', { tid, filename }),
|
urlForFile: (filename: string) => this.url('contest_file_download', { tid, filename }),
|
||||||
@@ -628,7 +623,7 @@ export class ContestUserHandler extends ContestManagementBaseHandler {
|
|||||||
}
|
}
|
||||||
const udict = await user.getListForRender(
|
const udict = await user.getListForRender(
|
||||||
domainId, [this.tdoc.owner, ...tsdocs.map((i) => i.uid)],
|
domainId, [this.tdoc.owner, ...tsdocs.map((i) => i.uid)],
|
||||||
this.user.hasPerm(PERM.PERM_VIEW_DISPLAYNAME) ? ['displayName'] : [],
|
this.user.hasPerm(PERM.PERM_VIEW_USER_PRIVATE_INFO),
|
||||||
);
|
);
|
||||||
this.response.body = { tdoc: this.tdoc, tsdocs, udict };
|
this.response.body = { tdoc: this.tdoc, tsdocs, udict };
|
||||||
this.response.pjax = 'partials/contest_user.html';
|
this.response.pjax = 'partials/contest_user.html';
|
||||||
@@ -669,7 +664,7 @@ export class ContestBalloonHandler extends ContestManagementBaseHandler {
|
|||||||
owner_udoc: await user.getById(domainId, this.tdoc.owner),
|
owner_udoc: await user.getById(domainId, this.tdoc.owner),
|
||||||
pdict: await problem.getList(domainId, this.tdoc.pids, true, true, problem.PROJECTION_CONTEST_LIST),
|
pdict: await problem.getList(domainId, this.tdoc.pids, true, true, problem.PROJECTION_CONTEST_LIST),
|
||||||
bdocs,
|
bdocs,
|
||||||
udict: await user.getListForRender(domainId, uids, this.user.hasPerm(PERM.PERM_VIEW_DISPLAYNAME) ? ['displayName'] : []),
|
udict: await user.getListForRender(domainId, uids, this.user.hasPerm(PERM.PERM_VIEW_USER_PRIVATE_INFO)),
|
||||||
};
|
};
|
||||||
this.response.pjax = 'partials/contest_balloon.html';
|
this.response.pjax = 'partials/contest_balloon.html';
|
||||||
this.response.template = 'contest_balloon.html';
|
this.response.template = 'contest_balloon.html';
|
||||||
@@ -836,7 +831,7 @@ export async function apply(ctx: Context) {
|
|||||||
if (realtime && !this.user.own(tdoc)) {
|
if (realtime && !this.user.own(tdoc)) {
|
||||||
this.checkPerm(PERM.PERM_VIEW_CONTEST_HIDDEN_SCOREBOARD);
|
this.checkPerm(PERM.PERM_VIEW_CONTEST_HIDDEN_SCOREBOARD);
|
||||||
}
|
}
|
||||||
const config: ScoreboardConfig = { isExport: false, showDisplayName: this.user.hasPerm(PERM.PERM_VIEW_DISPLAYNAME) };
|
const config: ScoreboardConfig = { isExport: false, showDisplayName: this.user.hasPerm(PERM.PERM_VIEW_USER_PRIVATE_INFO) };
|
||||||
if (!realtime && this.tdoc.lockAt && !this.tdoc.unlocked) {
|
if (!realtime && this.tdoc.lockAt && !this.tdoc.unlocked) {
|
||||||
config.lockAt = this.tdoc.lockAt;
|
config.lockAt = this.tdoc.lockAt;
|
||||||
}
|
}
|
||||||
@@ -896,7 +891,7 @@ export async function apply(ctx: Context) {
|
|||||||
].concat(
|
].concat(
|
||||||
tdoc.pids.map((i, idx) => `@p ${pid(idx)},${escape(pdict[i]?.title || 'Unknown Problem')},20,0`),
|
tdoc.pids.map((i, idx) => `@p ${pid(idx)},${escape(pdict[i]?.title || 'Unknown Problem')},20,0`),
|
||||||
teams.map((i, idx) => {
|
teams.map((i, idx) => {
|
||||||
const showName = this.user.hasPerm(PERM.PERM_VIEW_DISPLAYNAME) && udict[i.uid].displayName
|
const showName = this.user.hasPerm(PERM.PERM_VIEW_USER_PRIVATE_INFO) && udict[i.uid].displayName
|
||||||
? udict[i.uid].displayName : udict[i.uid].uname;
|
? udict[i.uid].displayName : udict[i.uid].uname;
|
||||||
const teamName = `${i.rank ? '*' : ''}${escape(udict[i.uid].school || unknownSchool)}-${escape(showName)}`;
|
const teamName = `${i.rank ? '*' : ''}${escape(udict[i.uid].school || unknownSchool)}-${escape(showName)}`;
|
||||||
return `@t ${idx + 1},0,1,"${teamName}"`;
|
return `@t ${idx + 1},0,1,"${teamName}"`;
|
||||||
@@ -911,7 +906,7 @@ export async function apply(ctx: Context) {
|
|||||||
async display({ tdoc }) {
|
async display({ tdoc }) {
|
||||||
await this.limitRate('scoreboard_download', 60, 3);
|
await this.limitRate('scoreboard_download', 60, 3);
|
||||||
const [, rows] = await contest.getScoreboard.call(this, tdoc.domainId, tdoc._id, {
|
const [, rows] = await contest.getScoreboard.call(this, tdoc.domainId, tdoc._id, {
|
||||||
isExport: true, lockAt: this.tdoc.lockAt, showDisplayName: this.user.hasPerm(PERM.PERM_VIEW_DISPLAYNAME),
|
isExport: true, lockAt: this.tdoc.lockAt, showDisplayName: this.user.hasPerm(PERM.PERM_VIEW_USER_PRIVATE_INFO),
|
||||||
});
|
});
|
||||||
this.binary(await this.renderHTML('contest_scoreboard_download_html.html', { rows, tdoc }), `${this.tdoc.title}.html`);
|
this.binary(await this.renderHTML('contest_scoreboard_download_html.html', { rows, tdoc }), `${this.tdoc.title}.html`);
|
||||||
},
|
},
|
||||||
@@ -921,7 +916,7 @@ export async function apply(ctx: Context) {
|
|||||||
async display({ tdoc }) {
|
async display({ tdoc }) {
|
||||||
await this.limitRate('scoreboard_download', 60, 3);
|
await this.limitRate('scoreboard_download', 60, 3);
|
||||||
const [, rows] = await contest.getScoreboard.call(this, tdoc.domainId, tdoc._id, {
|
const [, rows] = await contest.getScoreboard.call(this, tdoc.domainId, tdoc._id, {
|
||||||
isExport: true, lockAt: this.tdoc.lockAt, showDisplayName: this.user.hasPerm(PERM.PERM_VIEW_DISPLAYNAME),
|
isExport: true, lockAt: this.tdoc.lockAt, showDisplayName: this.user.hasPerm(PERM.PERM_VIEW_USER_PRIVATE_INFO),
|
||||||
});
|
});
|
||||||
this.binary(toCSV(rows.map((r) => r.map((c) => c.value.toString())), { bom: true }), `${this.tdoc.title}.csv`);
|
this.binary(toCSV(rows.map((r) => r.map((c) => c.value.toString())), { bom: true }), `${this.tdoc.title}.csv`);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ class DomainUserHandler extends ManageHandler {
|
|||||||
user: 1,
|
user: 1,
|
||||||
role: 1,
|
role: 1,
|
||||||
join: 1,
|
join: 1,
|
||||||
...(this.user.hasPerm(PERM.PERM_VIEW_DISPLAYNAME) ? { displayName: 1 } : {}),
|
...(this.user.hasPerm(PERM.PERM_VIEW_USER_PRIVATE_INFO) ? { displayName: 1 } : {}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]).toArray(),
|
]).toArray(),
|
||||||
|
|||||||
@@ -974,7 +974,7 @@ export class ProblemStatisticsHandler extends ProblemDetailHandler {
|
|||||||
'record',
|
'record',
|
||||||
);
|
);
|
||||||
const [udict, udoc] = await Promise.all([
|
const [udict, udoc] = await Promise.all([
|
||||||
user.getListForRender(domainId, rsdocs.map((i) => i.uid), this.user.hasPerm(PERM.PERM_VIEW_DISPLAYNAME) ? ['displayName'] : []),
|
user.getListForRender(domainId, rsdocs.map((i) => i.uid), this.user.hasPerm(PERM.PERM_VIEW_USER_PRIVATE_INFO)),
|
||||||
user.getById(domainId, this.pdoc.owner),
|
user.getById(domainId, this.pdoc.owner),
|
||||||
]);
|
]);
|
||||||
this.response.template = 'problem_statistics.html';
|
this.response.template = 'problem_statistics.html';
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ class TrainingDetailHandler extends Handler {
|
|||||||
const canViewHidden = this.user.hasPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN) || this.user._id;
|
const canViewHidden = this.user.hasPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN) || this.user._id;
|
||||||
const [udoc, udict, pdict, psdict, selfPsdict] = await Promise.all([
|
const [udoc, udict, pdict, psdict, selfPsdict] = await Promise.all([
|
||||||
user.getById(domainId, tdoc.owner),
|
user.getById(domainId, tdoc.owner),
|
||||||
user.getListForRender(domainId, enrollUsers, this.user.hasPerm(PERM.PERM_VIEW_DISPLAYNAME) ? ['displayName'] : []),
|
user.getListForRender(domainId, enrollUsers, this.user.hasPerm(PERM.PERM_VIEW_USER_PRIVATE_INFO)),
|
||||||
problem.getList(domainId, pids, canViewHidden, true),
|
problem.getList(domainId, pids, canViewHidden, true),
|
||||||
problem.getListStatus(domainId, uid, pids),
|
problem.getListStatus(domainId, uid, pids),
|
||||||
shouldCompare ? problem.getListStatus(domainId, this.user._id, pids) : {},
|
shouldCompare ? problem.getListStatus(domainId, this.user._id, pids) : {},
|
||||||
|
|||||||
@@ -12,7 +12,9 @@ export const PERM = {
|
|||||||
// Domain Settings
|
// Domain Settings
|
||||||
PERM_VIEW: 1n << 0n,
|
PERM_VIEW: 1n << 0n,
|
||||||
PERM_EDIT_DOMAIN: 1n << 1n,
|
PERM_EDIT_DOMAIN: 1n << 1n,
|
||||||
|
/** @deprecated use PERM_VIEW_USER_PRIVATE_INFO instead */
|
||||||
PERM_VIEW_DISPLAYNAME: 1n << 67n,
|
PERM_VIEW_DISPLAYNAME: 1n << 67n,
|
||||||
|
PERM_VIEW_USER_PRIVATE_INFO: 1n << 67n,
|
||||||
PERM_MOD_BADGE: 1n << 2n,
|
PERM_MOD_BADGE: 1n << 2n,
|
||||||
|
|
||||||
// Problem
|
// Problem
|
||||||
@@ -105,7 +107,7 @@ export const Permission = (family: string, key: bigint, desc: string) => ({ fami
|
|||||||
|
|
||||||
export const PERMS = [
|
export const PERMS = [
|
||||||
Permission('perm_general', PERM.PERM_VIEW, 'View this domain'),
|
Permission('perm_general', PERM.PERM_VIEW, 'View this domain'),
|
||||||
Permission('perm_general', PERM.PERM_VIEW_DISPLAYNAME, 'View domain user displayname'),
|
Permission('perm_general', PERM.PERM_VIEW_USER_PRIVATE_INFO, 'View domain user private info'),
|
||||||
Permission('perm_general', PERM.PERM_EDIT_DOMAIN, 'Edit domain settings'),
|
Permission('perm_general', PERM.PERM_EDIT_DOMAIN, 'Edit domain settings'),
|
||||||
Permission('perm_general', PERM.PERM_MOD_BADGE, 'Show MOD badge'),
|
Permission('perm_general', PERM.PERM_MOD_BADGE, 'Show MOD badge'),
|
||||||
Permission('perm_problem', PERM.PERM_CREATE_PROBLEM, 'Create problems'),
|
Permission('perm_problem', PERM.PERM_CREATE_PROBLEM, 'Create problems'),
|
||||||
@@ -191,7 +193,7 @@ PERM.PERM_BASIC = PERM.PERM_VIEW
|
|||||||
| PERM.PERM_VIEW_RECORD;
|
| PERM.PERM_VIEW_RECORD;
|
||||||
|
|
||||||
PERM.PERM_DEFAULT = PERM.PERM_VIEW
|
PERM.PERM_DEFAULT = PERM.PERM_VIEW
|
||||||
| PERM.PERM_VIEW_DISPLAYNAME
|
| PERM.PERM_VIEW_USER_PRIVATE_INFO
|
||||||
| PERM.PERM_VIEW_PROBLEM
|
| PERM.PERM_VIEW_PROBLEM
|
||||||
| PERM.PERM_EDIT_PROBLEM_SELF
|
| PERM.PERM_EDIT_PROBLEM_SELF
|
||||||
| PERM.PERM_SUBMIT_PROBLEM
|
| PERM.PERM_SUBMIT_PROBLEM
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ export const FLAG_HIDDEN = 1;
|
|||||||
export const FLAG_DISABLED = 2;
|
export const FLAG_DISABLED = 2;
|
||||||
export const FLAG_SECRET = 4;
|
export const FLAG_SECRET = 4;
|
||||||
export const FLAG_PRO = 8;
|
export const FLAG_PRO = 8;
|
||||||
|
export const FLAG_PUBLIC = 16;
|
||||||
|
export const FLAG_PRIVATE = 32;
|
||||||
|
|
||||||
export const PREFERENCE_SETTINGS: _Setting[] = [];
|
export const PREFERENCE_SETTINGS: _Setting[] = [];
|
||||||
export const ACCOUNT_SETTINGS: _Setting[] = [];
|
export const ACCOUNT_SETTINGS: _Setting[] = [];
|
||||||
@@ -75,6 +77,7 @@ declare global {
|
|||||||
interface Meta<T> { // eslint-disable-line ts/no-unused-vars
|
interface Meta<T> { // eslint-disable-line ts/no-unused-vars
|
||||||
family?: string;
|
family?: string;
|
||||||
secret?: boolean;
|
secret?: boolean;
|
||||||
|
flag?: number;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -93,6 +96,7 @@ function schemaToSettings(schema: Schema<any>) {
|
|||||||
: s.meta?.role === 'markdown' ? 'markdown'
|
: s.meta?.role === 'markdown' ? 'markdown'
|
||||||
: s.meta?.role === 'textarea' ? 'textarea' : 'text';
|
: s.meta?.role === 'textarea' ? 'textarea' : 'text';
|
||||||
if (s.meta?.role === 'password') flag |= FLAG_SECRET;
|
if (s.meta?.role === 'password') flag |= FLAG_SECRET;
|
||||||
|
if (s.meta?.flag) flag |= s.meta?.flag;
|
||||||
const options = {};
|
const options = {};
|
||||||
for (const item of actualList || []) {
|
for (const item of actualList || []) {
|
||||||
if (item.type !== 'const') throw new Error(`List item must be a constant, got ${item.type}`);
|
if (item.type !== 'const') throw new Error(`List item must be a constant, got ${item.type}`);
|
||||||
@@ -256,9 +260,9 @@ AccountSetting(
|
|||||||
Setting('setting_info', 'qq', null, 'text', 'QQ'),
|
Setting('setting_info', 'qq', null, 'text', 'QQ'),
|
||||||
Setting('setting_info', 'gender', builtin.USER_GENDER_OTHER, builtin.USER_GENDER_RANGE, 'Gender'),
|
Setting('setting_info', 'gender', builtin.USER_GENDER_OTHER, builtin.USER_GENDER_RANGE, 'Gender'),
|
||||||
Setting('setting_info', 'bio', null, 'markdown', 'Bio'),
|
Setting('setting_info', 'bio', null, 'markdown', 'Bio'),
|
||||||
Setting('setting_info', 'school', '', 'text', 'School'),
|
Setting('setting_info', 'school', '', 'text', 'School', '', FLAG_PRIVATE),
|
||||||
Setting('setting_info', 'studentId', '', 'text', 'Student ID'),
|
Setting('setting_info', 'studentId', '', 'text', 'Student ID', '', FLAG_PRIVATE),
|
||||||
Setting('setting_info', 'phone', null, 'text', 'Phone', null, FLAG_DISABLED),
|
Setting('setting_info', 'phone', null, 'text', 'Phone', null, FLAG_DISABLED | FLAG_PRIVATE),
|
||||||
Setting('setting_customize', 'backgroundImage',
|
Setting('setting_customize', 'backgroundImage',
|
||||||
'/components/profile/backgrounds/1.jpg', 'text', 'Profile Background Image',
|
'/components/profile/backgrounds/1.jpg', 'text', 'Profile Background Image',
|
||||||
'Choose the background image in your profile page.'),
|
'Choose the background image in your profile page.'),
|
||||||
@@ -278,7 +282,8 @@ DomainSetting(
|
|||||||
);
|
);
|
||||||
|
|
||||||
DomainUserSetting(Schema.object({
|
DomainUserSetting(Schema.object({
|
||||||
displayName: Schema.transform(String, (input) => saslPrep(input)).default('').description('Display Name').extra('family', 'setting_info'),
|
displayName: Schema.transform(String, (input) => saslPrep(input)).default('').description('Display Name')
|
||||||
|
.extra('family', 'setting_info').extra('flag', FLAG_PRIVATE),
|
||||||
|
|
||||||
rpInfo: Schema.any().extra('family', 'setting_storage').disabled().hidden(),
|
rpInfo: Schema.any().extra('family', 'setting_storage').disabled().hidden(),
|
||||||
|
|
||||||
@@ -415,6 +420,8 @@ global.Hydro.model.setting = {
|
|||||||
FLAG_DISABLED,
|
FLAG_DISABLED,
|
||||||
FLAG_SECRET,
|
FLAG_SECRET,
|
||||||
FLAG_PRO,
|
FLAG_PRO,
|
||||||
|
FLAG_PUBLIC,
|
||||||
|
FLAG_PRIVATE,
|
||||||
PREFERENCE_SETTINGS,
|
PREFERENCE_SETTINGS,
|
||||||
ACCOUNT_SETTINGS,
|
ACCOUNT_SETTINGS,
|
||||||
SETTINGS,
|
SETTINGS,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { escapeRegExp, pick, uniq } from 'lodash';
|
import { escapeRegExp, omit, pick, uniq } from 'lodash';
|
||||||
import { LRUCache } from 'lru-cache';
|
import { LRUCache } from 'lru-cache';
|
||||||
import { Collection, Filter, ObjectId } from 'mongodb';
|
import { Collection, Filter, ObjectId } from 'mongodb';
|
||||||
import { serializer } from '@hydrooj/framework';
|
import { serializer } from '@hydrooj/framework';
|
||||||
@@ -59,6 +59,8 @@ export class User {
|
|||||||
_loginip: string;
|
_loginip: string;
|
||||||
_tfa: string;
|
_tfa: string;
|
||||||
_authenticators: Authenticator[];
|
_authenticators: Authenticator[];
|
||||||
|
_privateFields: string[] = [];
|
||||||
|
_publicFields: string[] = [];
|
||||||
|
|
||||||
mail: string;
|
mail: string;
|
||||||
uname: string;
|
uname: string;
|
||||||
@@ -101,14 +103,15 @@ export class User {
|
|||||||
this.tfa = !!udoc.tfa;
|
this.tfa = !!udoc.tfa;
|
||||||
this.authn = (udoc.authenticators || []).length > 0;
|
this.authn = (udoc.authenticators || []).length > 0;
|
||||||
if (dudoc.group) this.group = dudoc.group;
|
if (dudoc.group) this.group = dudoc.group;
|
||||||
|
const load = (settings: Record<string, ReturnType<typeof setting.Setting>>, source: any) => {
|
||||||
for (const key in setting.SETTINGS_BY_KEY) {
|
for (const key in settings) {
|
||||||
this[key] = udoc[key] ?? (setting.SETTINGS_BY_KEY[key].value || system.get(`preference.${key}`));
|
this[key] = source[key] ?? (settings[key].value || system.get(`preference.${key}`));
|
||||||
}
|
if (settings[key].flag & setting.FLAG_PUBLIC) this._publicFields.push(key);
|
||||||
|
if (settings[key].flag & setting.FLAG_PRIVATE) this._privateFields.push(key);
|
||||||
for (const key in setting.DOMAIN_USER_SETTINGS_BY_KEY) {
|
}
|
||||||
this[key] = dudoc[key] ?? (setting.DOMAIN_USER_SETTINGS_BY_KEY[key].value || system.get(`preference.${key}`));
|
};
|
||||||
}
|
load(setting.SETTINGS_BY_KEY, udoc);
|
||||||
|
load(setting.DOMAIN_USER_SETTINGS_BY_KEY, dudoc);
|
||||||
}
|
}
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
@@ -159,13 +162,14 @@ export class User {
|
|||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getFields(type: 'public' | 'private' = 'public') {
|
||||||
|
const fields = ['_id', 'uname', 'mail', 'perm', 'role', 'priv', 'regat', 'loginat', 'tfa', 'authn'].concat(this._publicFields);
|
||||||
|
return type === 'public' ? fields : fields.concat(this._privateFields);
|
||||||
|
}
|
||||||
|
|
||||||
serialize(h) {
|
serialize(h) {
|
||||||
if (!this._isPrivate) {
|
if (!this._isPrivate) {
|
||||||
const fields = ['_id', 'uname', 'mail', 'perm', 'role', 'priv', 'regat', 'loginat', 'tfa', 'authn'];
|
return pick(this, this.getFields(h?.user?.hasPerm(PERM.PERM_VIEW_USER_PRIVATE_INFO) ? 'private' : 'public'));
|
||||||
if (h?.user?.hasPerm(PERM.PERM_VIEW_DISPLAYNAME)) {
|
|
||||||
fields.push('displayName', 'school', 'studentId');
|
|
||||||
}
|
|
||||||
return pick(this, fields);
|
|
||||||
}
|
}
|
||||||
return JSON.stringify(this, serializer(true, h));
|
return JSON.stringify(this, serializer(true, h));
|
||||||
}
|
}
|
||||||
@@ -398,19 +402,26 @@ class UserModel {
|
|||||||
return projection ? coll.find(params).project<Udoc>(buildProjection(projection)) : coll.find(params);
|
return projection ? coll.find(params).project<Udoc>(buildProjection(projection)) : coll.find(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async getListForRender(domainId: string, uids: number[], showPrivateInfo: boolean, extraFields?: string[]): Promise<BaseUserDict>;
|
||||||
static async getListForRender(domainId: string, uids: number[], extraFields?: string[]): Promise<BaseUserDict>;
|
static async getListForRender(domainId: string, uids: number[], extraFields?: string[]): Promise<BaseUserDict>;
|
||||||
static async getListForRender(domainId: string, uids: number[], arg: string[] | boolean) {
|
static async getListForRender(domainId: string, uids: number[], arg: string[] | boolean, extraFields?: string[]) {
|
||||||
const fields = ['_id', 'uname', 'mail', 'avatar', 'school', 'studentId'].concat(arg instanceof Array ? arg : []);
|
const _extraFields = Array.isArray(arg) ? arg : Array.isArray(extraFields) ? extraFields : [];
|
||||||
const showDisplayName = arg instanceof Array ? fields.includes('displayName') : arg;
|
const showPrivateInfo = arg === true || _extraFields.includes('displayName');
|
||||||
|
const fields = Array.from(new Set([
|
||||||
|
...(await UserModel.getById('system', 0)).getFields(showPrivateInfo ? 'private' : 'public'),
|
||||||
|
..._extraFields,
|
||||||
|
]));
|
||||||
const [udocs, vudocs, dudocs] = await Promise.all([
|
const [udocs, vudocs, dudocs] = await Promise.all([
|
||||||
UserModel.getMulti({ _id: { $in: uids } }, fields).toArray(),
|
UserModel.getMulti({ _id: { $in: uids } }, fields).toArray(),
|
||||||
collV.find({ _id: { $in: uids } }).toArray(),
|
collV.find({ _id: { $in: uids } }).toArray(),
|
||||||
domain.getDomainUserMulti(domainId, uids).project({ uid: 1, ...(showDisplayName ? { displayName: 1 } : {}) }).toArray(),
|
domain.getDomainUserMulti(domainId, uids).project(buildProjection(fields.concat('uid'))).toArray(),
|
||||||
]);
|
]);
|
||||||
const udict = {};
|
const udict = {};
|
||||||
for (const udoc of udocs) udict[udoc._id] = udoc;
|
for (const udoc of udocs) udict[udoc._id] = udoc;
|
||||||
for (const udoc of vudocs) udict[udoc._id] = udoc;
|
for (const udoc of vudocs) udict[udoc._id] = udoc;
|
||||||
if (showDisplayName) for (const dudoc of dudocs) udict[dudoc.uid].displayName = dudoc.displayName;
|
if (showPrivateInfo) {
|
||||||
|
for (const dudoc of dudocs) Object.assign(udict[dudoc.uid], omit(dudoc, ['_id', 'uid']));
|
||||||
|
}
|
||||||
for (const uid of uids) udict[uid] ||= { ...UserModel.defaultUser };
|
for (const uid of uids) udict[uid] ||= { ...UserModel.defaultUser };
|
||||||
for (const key in udict) {
|
for (const key in udict) {
|
||||||
udict[key].school ||= '';
|
udict[key].school ||= '';
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<img class="small user-profile-avatar v-center" loading="lazy" src="{{ avatarUrl(udoc.avatar|default('')) }}" width="20" height="20">
|
<img class="small user-profile-avatar v-center" loading="lazy" src="{{ avatarUrl(udoc.avatar|default('')) }}" width="20" height="20">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a class="user-profile-name uname--lv{{ udoc.level|default(0) }}" href="{{ url('user_detail', uid=udoc._id) }}">
|
<a class="user-profile-name uname--lv{{ udoc.level|default(0) }}" href="{{ url('user_detail', uid=udoc._id) }}">
|
||||||
{% if handler.user.hasPerm(perm.PERM_VIEW_DISPLAYNAME) and udoc.displayName and udoc.displayName != udoc.uname %}
|
{% if handler.user.hasPerm(perm.PERM_VIEW_USER_PRIVATE_INFO) and udoc.displayName and udoc.displayName != udoc.uname %}
|
||||||
{{ udoc.displayName }} ({{ udoc.uname }})
|
{{ udoc.displayName }} ({{ udoc.uname }})
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ udoc.uname }}
|
{{ udoc.uname }}
|
||||||
|
|||||||
@@ -18,12 +18,12 @@
|
|||||||
</li>
|
</li>
|
||||||
<ul class="enroll_user_menu">
|
<ul class="enroll_user_menu">
|
||||||
{%- for uid, udoc in udict -%}
|
{%- for uid, udoc in udict -%}
|
||||||
<li class="menu__item enroll_user_menu_item" data-uid="{{ uid }}" data-uname="{{ udoc.uname }}" {% if handler.user.hasPerm(perm.PERM_VIEW_DISPLAYNAME) and udoc.displayName %}data-displayname="{{ udoc.displayName }}"{% endif %}>
|
<li class="menu__item enroll_user_menu_item" data-uid="{{ uid }}" data-uname="{{ udoc.uname }}" {% if handler.user.hasPerm(perm.PERM_VIEW_USER_PRIVATE_INFO) and udoc.displayName %}data-displayname="{{ udoc.displayName }}"{% endif %}>
|
||||||
<a href="./{{ tdoc._id }}?uid={{ uid }}" class="menu__link{% if (handler.request.query.uid or handler.user._id) == uid %} active{% endif %}">
|
<a href="./{{ tdoc._id }}?uid={{ uid }}" class="menu__link{% if (handler.request.query.uid or handler.user._id) == uid %} active{% endif %}">
|
||||||
<span class="user-profile-link">
|
<span class="user-profile-link">
|
||||||
<img class="small user-profile-avatar v-center" loading="lazy" src="{{ avatarUrl(udoc.avatar|default('')) }}" width="20" height="20">
|
<img class="small user-profile-avatar v-center" loading="lazy" src="{{ avatarUrl(udoc.avatar|default('')) }}" width="20" height="20">
|
||||||
<span class="user-profile-name">
|
<span class="user-profile-name">
|
||||||
{% if handler.user.hasPerm(perm.PERM_VIEW_DISPLAYNAME) and udoc.displayName and udoc.displayName != udoc.uname %}
|
{% if handler.user.hasPerm(perm.PERM_VIEW_USER_PRIVATE_INFO) and udoc.displayName and udoc.displayName != udoc.uname %}
|
||||||
{{ udoc.displayName }} ({{ udoc.uname }})
|
{{ udoc.displayName }} ({{ udoc.uname }})
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ udoc.uname }}
|
{{ udoc.uname }}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
<div class="media__body profile-header__main">
|
<div class="media__body profile-header__main">
|
||||||
<h1>
|
<h1>
|
||||||
{{ udoc['uname'] }}
|
{{ udoc['uname'] }}
|
||||||
{% if handler.user.hasPerm(perm.PERM_VIEW_DISPLAYNAME) and udoc.displayName %}<small>({{ udoc['displayName'] }})</small>{% endif %}
|
{% if handler.user.hasPerm(perm.PERM_VIEW_USER_PRIVATE_INFO) and udoc.displayName %}<small>({{ udoc['displayName'] }})</small>{% endif %}
|
||||||
</h1>
|
</h1>
|
||||||
<p>
|
<p>
|
||||||
{{ _('UID') }}: {{ udoc['_id'] }},
|
{{ _('UID') }}: {{ udoc['_id'] }},
|
||||||
|
|||||||
Reference in new issue
Block a user