core: user_group: draft

This commit is contained in:
undefined committed 2022-01-07 18:20:05 +08:00
1 parent 07c5793fb8
commit f699d67019
5 files changed
+99 -55

No files matched your search

+20 -16
View File
@@ -24,7 +24,7 @@ import * as training from '../model/training';
import user from '../model/user';
import * as bus from '../service/bus';
import {
Connection, ConnectionHandler, Handler, param, Route, Types,
Connection, ConnectionHandler, Handler, param, query, Route, Types,
} from '../service/server';
const { geoip, useragent } = global.Hydro.lib;
@@ -291,28 +291,32 @@ class UserChangemailWithCodeHandler extends Handler {
}
class HomeDomainHandler extends Handler {
async get() {
let ddocs: DomainDoc[] = [];
let dudict: Record<string, DomainDoc> = {};
if (!this.user.hasPriv(PRIV.PRIV_VIEW_ALL_DOMAIN)) {
@query('all', Types.Boolean)
async get(domainId: string, all: boolean) {
let res: DomainDoc[] = [];
let dudict: Record<string, any> = {};
if (!all) {
dudict = await domain.getDictUserByDomainId(this.user._id);
const dids = Object.keys(dudict);
ddocs = await domain.getMulti({ _id: { $in: dids } }).toArray();
res = await domain.getMulti({ _id: { $in: dids } }).toArray();
} else {
const _ddocs = await domain.getMulti().toArray();
for (const ddoc of _ddocs) {
// eslint-disable-next-line no-await-in-loop
const pcount = await ProblemModel.count(ddoc._id, {});
if (pcount >= 3 || ddoc.owner === this.user._id) {
dudict[ddoc._id] = ddoc;
ddocs.push(ddoc);
}
}
this.checkPriv(PRIV.PRIV_VIEW_ALL_DOMAIN);
res = await domain.getMulti().toArray();
await Promise.all(res.map(async (ddoc) => {
dudict[ddoc._id] = await user.getById(domainId, this.user._id);
}));
}
const canManage = {};
for (const ddoc of ddocs) {
const ddocs = [];
for (const ddoc of res) {
// eslint-disable-next-line no-await-in-loop
const udoc = (await user.getById(ddoc._id, this.user._id))!;
const dudoc = dudict[ddoc._id];
if (['default', 'guest'].includes(dudoc.role)) {
delete dudict[ddoc._id];
continue;
}
ddocs.push(ddoc);
canManage[ddoc._id] = udoc.hasPerm(PERM.PERM_EDIT_DOMAIN)
|| udoc.hasPriv(PRIV.PRIV_MANAGE_ALL_DOMAIN);
}
+24 -15
View File
@@ -87,6 +87,13 @@ export interface VUdoc {
loginip: '127.0.0.1';
}
export interface GDoc {
_id: ObjectID;
domainId: string;
name: string;
uids: number[];
}
export type ownerInfo = { owner: number, maintainer?: number[] };
export interface User extends Record<string, any> {
@@ -326,25 +333,26 @@ export interface TrainingNode {
}
export interface Tdoc<docType = document['TYPE_CONTEST'] | document['TYPE_TRAINING']> extends Document {
docId: ObjectID,
docType: docType & number,
beginAt: Date,
endAt: Date,
attend: number,
title: string,
content: string,
rule: string,
pids: number[],
rated?: boolean,
_code?: string,
docId: ObjectID;
docType: docType & number;
beginAt: Date;
endAt: Date;
attend: number;
title: string;
content: string;
rule: string;
pids: number[];
rated?: boolean;
_code?: string;
assign?: string[];
// For homework
penaltySince?: Date,
penaltyRules?: PenaltyRules,
penaltySince?: Date;
penaltyRules?: PenaltyRules;
// For training
description?: string,
dag?: TrainingNode[],
description?: string;
dag?: TrainingNode[];
}
export interface TrainingDoc extends Tdoc {
@@ -583,6 +591,7 @@ export interface Collections {
'problem': ProblemDoc;
'user': Udoc;
'vuser': VUdoc;
'user.group': GDoc;
'check': any;
'message': MessageDoc;
'token': TokenDoc;
+2 -6
View File
@@ -225,12 +225,8 @@ class DomainModel {
@ArgMethod
static async getDictUserByDomainId(uid: number) {
const dudocs = await collUser.find({ uid }).toArray();
const dudict = {};
for (const dudoc of dudocs) {
// eslint-disable-next-line no-await-in-loop
dudict[dudoc.domainId] = await DomainModel.get(dudoc.domainId);
dudict[dudoc.domainId].role = dudoc.role;
}
const dudict: Record<string, any> = {};
for (const dudoc of dudocs) dudict[dudoc.domainId] = dudoc;
return dudict;
}
+44 -9
View File
@@ -1,10 +1,10 @@
import { escapeRegExp, pick } from 'lodash';
import LRU from 'lru-cache';
import { Collection } from 'mongodb';
import { Collection, ObjectID } from 'mongodb';
import { LoginError, UserAlreadyExistError, UserNotFoundError } from '../error';
import {
FileInfo, Udict, Udoc,
User as _User, VUdoc,
FileInfo, GDoc, Udict,
Udoc, User as _User, VUdoc,
} from '../interface';
import pwhash from '../lib/hash.hydro';
import { Logger } from '../logger';
@@ -21,6 +21,7 @@ import token from './token';
const coll: Collection<Udoc> = db.collection('user');
// Virtual user, only for display in contest.
const collV: Collection<VUdoc> = db.collection('vuser');
const collGroup: Collection<GDoc> = db.collection('user.group');
const logger = new Logger('model/user');
const cache = new LRU<string, User>({ max: 500, maxAge: 300 * 1000 });
@@ -144,7 +145,7 @@ function handleMailLower(mail: string) {
if (data.endsWith('@googlemail.com')) data = data.replace('@googlemail.com', '@gmail.com');
if (data.endsWith('@gmail.com')) {
const [prev] = data.split('@');
data = `${prev.replace(/\.\+/g, '')}@gmail.com`;
data = `${prev.replace(/[.+]/g, '')}@gmail.com`;
}
return data;
}
@@ -371,12 +372,46 @@ class UserModel {
token.delByUid(uid),
]);
}
static createGroup(domainId: string, name: string, uids: number[]) {
return collGroup.insertOne({ domainId, name, uids });
}
static async listGroup(domainId: string, uid?: number) {
const groups = await collGroup.find(uid ? { domainId, uids: uid } : { domainId }).toArray();
if (uid) {
groups.push({
_id: new ObjectID(), domainId, uids: [uid], name: uid.toString(),
});
}
return groups;
}
static delGroup(domainId: string, name: string) {
return collGroup.deleteOne({ domainId, name });
}
static updateGroup(domainId: string, name: string, uids: number[]) {
return collGroup.updateOne({ domainId, name }, { $set: { uids } });
}
}
bus.once('app/started', () => db.ensureIndexes(
coll,
{ key: { unameLower: 1 }, name: 'uname', unique: true },
{ key: { mailLower: 1 }, name: 'mail', unique: true },
));
bus.once('app/started', () => Promise.all([
db.ensureIndexes(
coll,
{ key: { unameLower: 1 }, name: 'uname', unique: true },
{ key: { mailLower: 1 }, name: 'mail', unique: true },
),
db.ensureIndexes(
collV,
{ key: { unameLower: 1 }, name: 'uname', unique: true },
{ key: { mailLower: 1 }, name: 'mail', unique: true },
),
db.ensureIndexes(
collGroup,
{ key: { domainId: 1, name: 1 }, name: 'name', unique: true },
{ key: { domainId: 1, uids: 1 }, name: 'uid' },
),
]));
export default UserModel;
global.Hydro.model.user = UserModel;
@@ -9,17 +9,19 @@
{{ tdoc['content'] }}
</div>
<div class="section__body typo">
{% if not handler.user.hasPriv(PRIV.PRIV_USER_PROFILE) %}
<blockquote class="typo note">
<p>{{ _('Login to join training plan') }}</p>
</blockquote>
{% elif not tsdoc.enroll %}
<blockquote class="typo note">
<p>{{ _('page.training_detail.invalid_when_not_enrolled') }}</p>
</blockquote>
{% endif %}
{{ tdoc.description|default('')|markdown|safe }}
</div>
</div>
<div class="section">
{% if not tsdoc.enroll %}
<div class="section__body">
<blockquote class="typo warn">
<p>{{ _('page.training_detail.invalid_when_not_enrolled') }}</p>
</blockquote>
</div>
{% endif %}
{%- for node in tdoc['dag'] -%}
<div data-heading-extract-to="#menu-item-training_detail" class="training__section {% if nsdict[node['_id']]['isDone'] %}done{% elif nsdict[node['_id']]['isProgress'] %}progress{% elif nsdict[node['_id']]['isOpen'] %}open{% else %}invalid{% endif %} {% if nsdict[node['_id']]['isProgress'] or nsdict[node['_id']]['isOpen'] %}expanded{% else %}collapsed{% endif %}">
<div class="section__header clearfix">
@@ -42,7 +44,6 @@
</h1>
</div>
</div>
{% if tsdoc.enroll %}
<div class="section__body">
<ul class="supplementary dot list">
<li>
@@ -153,7 +154,6 @@
</table>
</div>
</div>
{% endif %}
</div>
{%- endfor -%}
<div class="section__body">&nbsp;<!-- space placeholder --></div>