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.
Hydro/hydro/model/domain.js

315 lines
11 KiB
JavaScript

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()
*/