You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
315 lines
11 KiB
JavaScript
315 lines
11 KiB
JavaScript
5 years ago
|
const
|
||
|
validator = require('../utils').validator,
|
||
|
user = require('./user'),
|
||
|
{ DomainAlreadyExistError, DomainNotFoundError } = require('../error'),
|
||
|
db = require('../service/db.js'),
|
||
|
coll = db.collection('domain');
|
||
|
|
||
|
module.exports = {
|
||
|
/**
|
||
|
* @param {string} domainId
|
||
|
* @param {int} owner
|
||
|
* @param {roles} roles
|
||
|
* @param {str} name
|
||
|
* @param {str} gravatar
|
||
|
* @param {str} bulletin
|
||
|
*/
|
||
|
async add(domainId, owner, roles, name, gravatar, bulletin = '') {
|
||
|
validator.checkDomainId(domainId);
|
||
|
validator.checkName(name);
|
||
|
validator.checkBulletin(bulletin);
|
||
|
try {
|
||
|
let result = await coll.insertOne({
|
||
|
_id: domainId, pending: true, owner, roles, name, gravatar, bulletin
|
||
|
});
|
||
|
domainId = result.insertedId;
|
||
|
} catch (e) {
|
||
|
throw new DomainAlreadyExistError(domainId);
|
||
|
}
|
||
|
await (await user.getById(owner, domainId)).joinDomain('root');
|
||
|
await coll.updateOne({ _id: domainId }, { $unset: { pending: '' } });
|
||
|
return domainId;
|
||
|
},
|
||
|
/**
|
||
|
* @param {string} domainId
|
||
|
* @param {object} fields
|
||
|
*/
|
||
|
async get(domainId, fields) {
|
||
|
let ddoc = await coll.findOne({ _id: domainId }, fields);
|
||
|
if (!ddoc) throw new DomainNotFoundError(domainId);
|
||
|
return ddoc;
|
||
|
},
|
||
|
/**
|
||
|
* Increments the problem ID counter.
|
||
|
* @param {string} domainId
|
||
|
* @returns {number} Integer value before increment.
|
||
|
*/
|
||
|
async incPidCounter(domainId) {
|
||
|
await coll.updateOne({ _id: domainId, pidCounter: { $exists: false } },
|
||
|
{ $set: { pidCounter: 1000 } });
|
||
|
let doc = await coll.findOneAndUpdate({ _id: domainId }, { $inc: { pidCounter: 1 } });
|
||
|
return doc.value.pidCounter;
|
||
|
},
|
||
|
async incUser(domainId, uid, $inc) {
|
||
|
let res = await coll.findOneAndUpdate({ domainId, uid }, { $inc }, { upsert: true });
|
||
|
return res.value;
|
||
|
}
|
||
|
};
|
||
|
/*
|
||
|
|
||
|
async def add_continue(domainId: str, ensure_owner_uid: int=None):
|
||
|
ddoc = await get(domainId)
|
||
|
if 'pending' not in ddoc:
|
||
|
raise error.DomainNotFoundError(domainId)
|
||
|
owner_uid = ddoc['owner_uid']
|
||
|
if ensure_owner_uid != None and owner_uid != ensure_owner_uid:
|
||
|
raise error.DomainNotFoundError(domainId)
|
||
|
try:
|
||
|
await add_user_role(domainId, owner_uid, builtin.ROLE_ROOT)
|
||
|
except error.UserAlreadyDomainMemberError:
|
||
|
pass
|
||
|
coll = db.coll('domain')
|
||
|
await coll.update_one({'_id': domainId},
|
||
|
{'$unset': {'pending': ''}})
|
||
|
|
||
|
def get_multi(*, fields=None, **kwargs):
|
||
|
coll = db.coll('domain')
|
||
|
return coll.find(kwargs, fields)
|
||
|
|
||
|
|
||
|
@argmethod.wrap
|
||
|
async def get_list(*, fields=None, limit: int=None, **kwargs):
|
||
|
coll = db.coll('domain')
|
||
|
return await coll.find(kwargs, fields).limit(limit).to_list(None)
|
||
|
|
||
|
|
||
|
def get_pending(**kwargs):
|
||
|
return get_multi(pending=True, **kwargs)
|
||
|
|
||
|
|
||
|
@argmethod.wrap
|
||
|
async def edit(domainId: str, **kwargs):
|
||
|
for domain in builtin.DOMAINS:
|
||
|
if domain['_id'] == domainId:
|
||
|
raise error.BuiltinDomainError(domainId)
|
||
|
coll = db.coll('domain')
|
||
|
if 'owner_uid' in kwargs:
|
||
|
del kwargs['owner_uid']
|
||
|
if 'name' in kwargs:
|
||
|
validator.check_name(kwargs['name'])
|
||
|
# TODO(twd2): check kwargs
|
||
|
return await coll.find_one_and_update(filter={'_id': domainId},
|
||
|
update={'$set': {**kwargs}},
|
||
|
return_document=ReturnDocument.AFTER)
|
||
|
|
||
|
|
||
|
async def unset(domainId, fields):
|
||
|
# TODO(twd2): check fields
|
||
|
coll = db.coll('domain')
|
||
|
return await coll.find_one_and_update(filter={'_id': domainId},
|
||
|
update={'$unset': dict((f, '') for f in set(fields))},
|
||
|
return_document=ReturnDocument.AFTER)
|
||
|
|
||
|
|
||
|
@argmethod.wrap
|
||
|
async def set_role(domainId: str, role: str, perm: int):
|
||
|
return await set_roles(domainId, {role: perm})
|
||
|
|
||
|
|
||
|
@argmethod.wrap
|
||
|
async def set_roles(domainId: str, roles):
|
||
|
roles = {str(role): int(perm) for role, perm in roles.items()}
|
||
|
update = {}
|
||
|
for role in roles:
|
||
|
validator.check_role(role)
|
||
|
if role in builtin.BUILTIN_ROLE_DESCRIPTORS:
|
||
|
if not builtin.BUILTIN_ROLE_DESCRIPTORS[role].modifiable:
|
||
|
raise error.ModifyBuiltinRoleError(domainId, role)
|
||
|
update['roles.{0}'.format(role)] = roles[role]
|
||
|
for domain in builtin.DOMAINS:
|
||
|
if domain['_id'] == domainId:
|
||
|
raise error.BuiltinDomainError(domainId)
|
||
|
coll = db.coll('domain')
|
||
|
return await coll.find_one_and_update(filter={'_id': domainId},
|
||
|
update={'$set': update},
|
||
|
return_document=ReturnDocument.AFTER)
|
||
|
|
||
|
|
||
|
@argmethod.wrap
|
||
|
async def delete_role(domainId: str, role: str):
|
||
|
return await delete_roles(domainId, [role])
|
||
|
|
||
|
|
||
|
async def delete_roles(domainId: str, roles):
|
||
|
roles = list(set(roles))
|
||
|
for role in roles:
|
||
|
validator.check_role(role)
|
||
|
if role in builtin.BUILTIN_ROLE_DESCRIPTORS:
|
||
|
raise error.ModifyBuiltinRoleError(domainId, role)
|
||
|
for domain in builtin.DOMAINS:
|
||
|
if domain['_id'] == domainId:
|
||
|
raise error.BuiltinDomainError(domainId)
|
||
|
user_coll = db.coll('domain.user')
|
||
|
await user_coll.update_many({'domainId': domainId, 'role': {'$in': list(roles)}},
|
||
|
{'$unset': {'role': ''}})
|
||
|
coll = db.coll('domain')
|
||
|
return await coll.find_one_and_update(filter={'_id': domainId},
|
||
|
update={'$unset': dict(('roles.{0}'.format(role), '')
|
||
|
for role in roles)},
|
||
|
return_document=ReturnDocument.AFTER)
|
||
|
|
||
|
|
||
|
@argmethod.wrap
|
||
|
async def transfer(domainId: str, old_owner_uid: int, new_owner_uid: int):
|
||
|
for domain in builtin.DOMAINS:
|
||
|
if domain['_id'] == domainId:
|
||
|
raise error.BuiltinDomainError(domainId)
|
||
|
coll = db.coll('domain')
|
||
|
return await coll.find_one_and_update(filter={'_id': domainId, 'owner_uid': old_owner_uid},
|
||
|
update={'$set': {'owner_uid': new_owner_uid}},
|
||
|
return_document=ReturnDocument.AFTER)
|
||
|
|
||
|
|
||
|
async def set_user(domainId, uid, **kwargs):
|
||
|
coll = db.coll('domain.user')
|
||
|
return await coll.find_one_and_update(filter={'domainId': domainId, 'uid': uid},
|
||
|
update={'$set': kwargs},
|
||
|
upsert=True,
|
||
|
return_document=ReturnDocument.AFTER)
|
||
|
|
||
|
|
||
|
async def unset_user(domainId, uid, fields):
|
||
|
coll = db.coll('domain.user')
|
||
|
return await coll.find_one_and_update(filter={'domainId': domainId, 'uid': uid},
|
||
|
update={'$unset': dict((f, '') for f in set(fields))},
|
||
|
upsert=True,
|
||
|
return_document=ReturnDocument.AFTER)
|
||
|
|
||
|
|
||
|
async def set_users(domainId, uids, **kwargs):
|
||
|
coll = db.coll('domain.user')
|
||
|
await coll.update_many({'domainId': domainId, 'uid': {'$in': list(set(uids))}},
|
||
|
{'$set': kwargs},
|
||
|
upsert=False)
|
||
|
|
||
|
|
||
|
async def unset_users(domainId, uids, fields):
|
||
|
coll = db.coll('domain.user')
|
||
|
await coll.update_many({'domainId': domainId, 'uid': {'$in': list(set(uids))}},
|
||
|
{'$unset': dict((f, '') for f in set(fields))},
|
||
|
upsert=True)
|
||
|
|
||
|
|
||
|
|
||
|
@argmethod.wrap
|
||
|
async def set_user_role(domainId: str, uid: int, role: str):
|
||
|
validator.check_role(role)
|
||
|
# use set_users to utilize "upsert=False"
|
||
|
return await set_users(domainId, [uid], role=role)
|
||
|
|
||
|
|
||
|
@argmethod.wrap
|
||
|
async def unset_user_role(domainId: str, uid: int):
|
||
|
return await unset_user(domainId, uid, ['role'])
|
||
|
|
||
|
|
||
|
async def set_users_role(domainId: str, uids, role: str):
|
||
|
validator.check_role(role)
|
||
|
await set_users(domainId, uids, role=role)
|
||
|
|
||
|
|
||
|
async def unset_users_role(domainId: str, uids):
|
||
|
await unset_users(domainId, uids, ['role'])
|
||
|
|
||
|
|
||
|
async def inc_user_usage(domainId: str, uid: int, usage_field: str, usage: int, quota: int):
|
||
|
coll = db.coll('domain.user')
|
||
|
try:
|
||
|
return await coll.find_one_and_update(filter={'domainId': domainId, 'uid': uid,
|
||
|
usage_field: {'$not': {'$gte': quota - usage}}},
|
||
|
update={'$inc': {usage_field: usage}},
|
||
|
upsert=True,
|
||
|
return_document=ReturnDocument.AFTER)
|
||
|
except errors.DuplicateKeyError:
|
||
|
raise error.UsageExceededError(domainId, uid, usage_field, usage, quota)
|
||
|
|
||
|
|
||
|
def get_multi_user(*, fields=None, **kwargs):
|
||
|
coll = db.coll('domain.user')
|
||
|
return coll.find(kwargs, fields)
|
||
|
|
||
|
|
||
|
async def get_dict_user_by_uid(domainId, uids, *, fields=None):
|
||
|
result = dict()
|
||
|
async for dudoc in get_multi_user(
|
||
|
domainId=domainId, uid={'$in': list(set(uids))}, fields=fields):
|
||
|
result[dudoc['uid']] = dudoc
|
||
|
return result
|
||
|
|
||
|
|
||
|
async def get_dict_user_by_domainId(uid, *, fields=None):
|
||
|
result = dict()
|
||
|
async for dudoc in get_multi_user(uid=uid, fields=fields):
|
||
|
result[dudoc['domainId']] = dudoc
|
||
|
return result
|
||
|
|
||
|
|
||
|
def get_all_roles(ddoc):
|
||
|
builtin_roles = {role: rd.default_permission for role, rd in builtin.BUILTIN_ROLE_DESCRIPTORS.items()}
|
||
|
domain_roles = ddoc['roles']
|
||
|
return {**builtin_roles, **domain_roles}
|
||
|
|
||
|
|
||
|
def get_join_settings(ddoc, now):
|
||
|
if 'join' not in ddoc:
|
||
|
return None
|
||
|
join_settings = ddoc['join']
|
||
|
if not join_settings:
|
||
|
return None
|
||
|
if join_settings['method'] == constant.domain.JOIN_METHOD_NONE:
|
||
|
return None
|
||
|
if join_settings['role'] not in ddoc['roles']:
|
||
|
return None
|
||
|
if join_settings['expire'] != None and join_settings['expire'] < now:
|
||
|
return None
|
||
|
return join_settings
|
||
|
|
||
|
|
||
|
@argmethod.wrap
|
||
|
async def get_prefix_search(prefix: str, fields={}, limit: int=50):
|
||
|
prefix_lower = prefix.lower()
|
||
|
builtin_ddocs = []
|
||
|
for domain in builtin.DOMAINS:
|
||
|
if domain['_id'].lower().startswith(prefix_lower) or \
|
||
|
domain['name'].lower().startswith(prefix_lower):
|
||
|
builtin_ddocs.append(domain)
|
||
|
regex = r'\A\Q{0}\E'.format(prefix.replace(r'\E', r'\E\\E\Q'))
|
||
|
coll = db.coll('domain')
|
||
|
ddocs = await coll.find({'$or': [{'_id': {'$regex': regex}},
|
||
|
{'name': {'$regex': regex}}]},
|
||
|
projection=fields) \
|
||
|
.limit(limit) \
|
||
|
.to_list()
|
||
|
return builtin_ddocs + ddocs
|
||
|
|
||
|
|
||
|
@argmethod.wrap
|
||
|
async def ensure_indexes():
|
||
|
coll = db.coll('domain')
|
||
|
await coll.create_index('owner_uid')
|
||
|
await coll.create_index('name')
|
||
|
user_coll = db.coll('domain.user')
|
||
|
await user_coll.create_index('uid')
|
||
|
await user_coll.create_index([('domainId', 1),
|
||
|
('uid', 1)], unique=True)
|
||
|
await user_coll.create_index([('domainId', 1),
|
||
|
('role', 1)], sparse=True)
|
||
|
await user_coll.create_index([('domainId', 1),
|
||
|
('rp', -1)])
|
||
|
await user_coll.create_index([('domainId', 1),
|
||
|
('rank', 1)])
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
argmethod.invoke_by_args()
|
||
|
*/
|