mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-17 17:36:08 +08:00
core: user_group: draft
This commit is contained in:
1 parent
07c5793fb8
commit
f699d67019
5 files changed
+99
-55
No files matched your search
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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"> <!-- space placeholder --></div>
|
||||
|
||||
Reference in new issue
Block a user