async def add_reply(domain_id: str, did: objectid.ObjectId, owner_uid: int, content: str): validator.check_content(content) coll = db.Collection('discussion') coll_reply = db.Collection('discussion.reply') drdoc, _ = await asyncio.gather( coll_reply.insert_one({ 'domain_id': domain_id, 'content': content, 'owner_uid': owner_uid, 'parent_type': 'discussion', 'parent_id': did }), coll.find_one_and_update(filter={ 'domain_id': domain_id, '_id': did }, update={ '$inc': { 'num_replies': 1 }, '$set': { 'update_at': datetime.datetime.utcnow() } }, return_document=ReturnDocument.AFTER)) return drdoc
async def create_indexes(): coll = db.Collection('problem') await coll.create_index([('domain_id', 1), ('_id', 1)], unique=True) await coll.create_index([('domain_id', 1), ('owner_uid', 1), ('_id', -1)]) await coll.create_index([('domain_id', 1), ('category', 1), ('_id', 1)], sparse=True) await coll.create_index([('domain_id', 1), ('hidden', 1), ('category', 1), ('_id', 1)], sparse=True) await coll.create_index([('domain_id', 1), ('tag', 1), ('_id', 1)], sparse=True) await coll.create_index([('domain_id', 1), ('hidden', 1), ('tag', 1), ('_id', 1)], sparse=True) status_coll = db.Collection('problem.status') await status_coll.create_index([('domain_id', 1), ('uid', 1), ('pid', 1)], unique=True)
async def attend(domain_id: str, tid: int, uid: int): # TODO: check time. coll = db.Collection('contest.status') try: await coll.find_one_and_update(filter={ 'domain_id': domain_id, 'tid': tid, 'uid': uid, 'attend': { '$eq': 0 } }, update={'$set': { 'attend': 1 }}, upsert=True, return_document=ReturnDocument.AFTER) except errors.DuplicateKeyError: raise error.ContestAlreadyAttendedError(domain_id, tid, uid) from None coll = db.Collection('contest') return await coll.find_one_and_update(filter={ 'domain_id': domain_id, '_id': tid }, update={'$inc': { 'attend': 1 }}, return_document=ReturnDocument.AFTER)
async def create_indexes(): coll = db.Collection('domain') await coll.create_index('owner_uid') user_coll = db.Collection('domain.user') await user_coll.create_index('uid') await user_coll.create_index([('domain_id', 1), ('uid', 1)], unique=True) await user_coll.create_index([('domain_id', 1), ('role', 1)], sparse=True)
async def add_tail_reply(domain_id: str, drid: objectid.ObjectId, owner_uid: int, content: str): validator.check_content(content) sid = objectid.ObjectId() coll = db.Collection('discussion.reply') drdoc = await coll.find_one_and_update( filter={ 'domain_id': domain_id, '_id': drid }, update={ '$push': { 'reply': { '_id': sid, 'owner_uid': owner_uid, 'content': content } } }, return_document=ReturnDocument.AFTER) coll = db.Collection('discussion') await coll.find_one_and_update( filter={ 'domain_id': domain_id, '_id': drdoc['parent_id'] }, update={'$set': { 'update_at': datetime.datetime.utcnow() }}, return_document=ReturnDocument.AFTER) return drdoc, sid
async def delete_roles(domain_id: str, roles): roles = list(set(roles)) for role in roles: validator.check_role(role) for domain in builtin.DOMAINS: if domain['_id'] == domain_id: raise error.BuiltinDomainError(domain_id) user_coll = db.Collection('domain.user') await user_coll.update_many( { 'domain_id': domain_id, 'role': { '$in': list(roles) } }, {'$unset': { 'role': '' }}) coll = db.Collection('domain') return await coll.find_one_and_update(filter={'_id': domain_id}, update={ '$unset': dict(('roles.{0}'.format(role), '') for role in roles) }, return_document=True)
async def create_indexes(): coll = db.Collection('campaign') await coll.create_index('owner_uid') await coll.create_index([('begin_at', 1), ('end_at', 1)]) team_coll = db.Collection('campaign.team') await team_coll.create_index([('cid', 1), ('uid', 1)], unique=True) await team_coll.create_index([('cid', 1), ('members', 1)], sparse=True) await team_coll.create_index([('cid', 1), ('team_name', 1)])
async def attend(campaign_id: str, uid: int, mail: str, tel: str, team_name: str, is_newbie: bool, members: list): validator.check_mail(mail) validator.check_tel(tel) validator.check_team_name(team_name) members = list(OrderedSet(members)) coll = db.Collection('campaign.team') try: return await coll.find_one_and_update( filter={ 'cid': campaign_id, 'uid': uid }, update={ '$set': { 'mail': mail, 'tel': tel, 'team_name': team_name, 'is_newbie': is_newbie, 'members': members } }, upsert=True, return_document=ReturnDocument.AFTER) except errors.DuplicateKeyError: raise error.CampaignTeamAlreadyExistError(members, team_name)
async def rejudge(record_id: objectid.ObjectId, enqueue: bool = True): coll = db.Collection('record') doc = await coll.find_one_and_update( filter={'_id': record_id}, update={ '$unset': { 'judge_uid': '', 'judge_at': '', 'compiler_texts': '', 'judge_texts': '', 'cases': '' }, '$set': { 'status': constant.record.STATUS_WAITING, 'time_ms': 0, 'memory_kb': 0, 'rejudged': True } }, return_document=False) post_coros = [] pdoc = await problem.get(doc['domain_id'], doc['pid']) if pdoc['judge_mode'] == constant.record.MODE_SUBMIT_ANSWER: await judge.judge_answer(doc['domain_id'], record_id, pdoc, doc['code']) else: post_coros.append(bus.publish('record_change', doc['_id'])) if enqueue: post_coros.append(queue.publish('judge', rid=doc['_id'])) await asyncio.gather(*post_coros)
async def get_by_mail(mail: str, fields=PROJECTION_VIEW): mail_lower = mail.strip().lower() for user in builtin.USERS: if user['mail_lower'] == mail_lower: return user coll = db.Collection('user') return await coll.find_one({'mail_lower': mail_lower}, fields)
async def set_status_balloon(domain_id: str, tid: int, uid: int, pid: int, balloon: bool = True): tdoc = await get(domain_id, tid) if pid not in tdoc['pids']: raise error.ValidationError('pid') coll = db.Collection('contest.status') tsdoc = await coll.find_one_and_update( filter={ 'domain_id': domain_id, 'tid': tid, 'uid': uid, 'detail.pid': pid }, update={'$set': { 'detail.$.balloon': balloon }}, return_document=ReturnDocument.AFTER) udoc = await user.get_by_uid(uid) await bus.publish( 'balloon_change', json.encode({ 'uid': uid, 'uname': udoc['uname'], 'nickname': udoc.get('nickname', ''), 'tid': tid, 'pid': pid, 'letter': convert_to_letter(tdoc['pids'], pid), 'balloon': balloon })) return tsdoc
async def get_by_uname(uname: str, fields=PROJECTION_VIEW): uname_lower = uname.strip().lower() for user in builtin.USERS: if user['uname_lower'] == uname_lower: return user coll = db.Collection('user') return await coll.find_one({'uname_lower': uname_lower}, fields)
async def add(domain_id: str, title: str, content: str, owner_uid: int, rule: int, private: bool, begin_at: lambda i: datetime.datetime.utcfromtimestamp(int(i)), end_at: lambda i: datetime.datetime.utcfromtimestamp(int(i)), pids=[], **kwargs): validator.check_title(title) validator.check_content(content) if rule not in RULES: raise error.ValidationError('rule') if begin_at >= end_at: raise error.ValidationError('begin_at', 'end_at') # TODO: should we check problem existance here? tid = await system.inc_contest_counter() coll = db.Collection('contest') doc = { '_id': tid, 'domain_id': domain_id, 'title': title, 'content': content, 'owner_uid': owner_uid, 'rule': rule, 'private': private, 'begin_at': begin_at, 'end_at': end_at, 'pids': pids, 'attend': 0, **kwargs, } await coll.insert_one(doc) return tid
async def get_status(domain_id: str, did: objectid.ObjectId, uid: int): coll = db.Collection('discussion.status') return await coll.find_one({ 'domain_id': domain_id, '_id': did, 'uid': uid })
async def inc(op: str, id: str, period_secs: int, max_operations: int): coll = db.Collection('op_count') cur_time = int(time.time()) begin_at = datetime.datetime.utcfromtimestamp(cur_time - cur_time % period_secs) expire_at = begin_at + datetime.timedelta(seconds=period_secs) try: doc = await coll.find_one_and_update(filter={ 'id': id, 'begin_at': begin_at, 'expire_at': expire_at, op: { '$not': { '$gte': max_operations } } }, update={'$inc': { op: 1 }}, upsert=True, return_document=True) return doc except errors.DuplicateKeyError: raise error.OpCountExceededError(op, period_secs, max_operations)
async def unset(domain_id, fields): # TODO: check fields. coll = db.Collection('domain') return await coll.find_one_and_update( filter={'_id': domain_id}, update={'$unset': dict((f, '') for f in set(fields))}, return_document=True)
async def delete(fid: objectid.ObjectId): doc = await get(fid) coll = db.Collection('userfile') result = await coll.delete_one({'domain_id': STORE_DOMAIN_ID, '_id': fid}) result = bool(result.deleted_count) if result: await fs.unlink(doc['file_id']) return result
async def delete_reply(domain_id: str, drid: objectid.ObjectId): drdoc = await get_reply(domain_id, drid) if not drdoc: return None coll = db.Collection('discussion') coll_reply = db.Collection('discussion.reply') await coll_reply.delete_one({'domain_id': domain_id, '_id': drid}) await coll.find_one_and_update(filter={ 'domain_id': domain_id, 'parent_type': drdoc['parent_type'], 'parent_id': drdoc['parent_id'] }, update={'$inc': { 'num_replies': -1 }}, return_document=ReturnDocument.AFTER) return drdoc
async def inc_status(domain_id: str, pid: int, uid: int, key: str, value: int): coll = db.Collection('problem.status') doc = await coll.find_one_and_update(filter={'domain_id': domain_id, 'pid': pid, 'uid': uid}, update={'$inc': {key: value}}, return_document=True) return doc
async def rev_init_status(domain_id, pid, uid): coll = db.Collection('problem.status') return await coll.find_one_and_update(filter={'domain_id': domain_id, 'pid': pid, 'uid': uid}, update={'$inc': {'rev': 1}}, upsert=True, return_document=True)
async def edit(domain_id: str, did: objectid.ObjectId, **kwargs): coll = db.Collection('discussion') return await coll.find_one_and_update(filter={ 'domain_id': domain_id, '_id': did }, update={'$set': kwargs}, return_document=ReturnDocument.AFTER)
async def get_status(domain_id: str, tid: int, uid: int, projection=None): coll = db.Collection('contest.status') return await coll.find_one({ 'domain_id': domain_id, 'tid': tid, 'uid': uid }, projection=projection)
async def create_indexes(): coll = db.Collection('contest') await coll.create_index([('domain_id', 1), ('_id', 1)], unique=True) await coll.create_index([('domain_id', 1), ('pids', 1)], sparse=True) await coll.create_index([('domain_id', 1), ('rule', 1), ('_id', -1)], sparse=True) status_coll = db.Collection('contest.status') await status_coll.create_index([('domain_id', 1), ('uid', 1), ('tid', 1)], unique=True) await status_coll.create_index([('domain_id', 1), ('tid', 1), ('accept', -1), ('time', 1)], sparse=True) await status_coll.create_index([('domain_id', 1), ('tid', 1), ('detail.accept', 1), ('detail.balloon', -1)]) await status_coll.create_index([('domain_id', 1), ('tid', 1), ('uid', 1), ('detail.pid', 1)], sparse=True)
async def add(uname: str, password: str, mail: str, reg_ip: str = '', uid: int = None, priv: int = builtin.DEFAULT_PRIV, **kwargs): # Add a user. validator.check_uname(uname) # TODO: Filter name by keywords validator.check_password(password) validator.check_mail(mail) uname_lower = uname.strip().lower() mail_lower = mail.strip().lower() if not uid: uid = await system.inc_user_counter() for user in builtin.USERS: if user['_id'] == uid or user['uname_lower'] == uname_lower or user[ 'mail_lower'] == mail_lower: raise error.UserAlreadyExistError(uname) salt = pwhash.gen_salt() coll = db.Collection('user') try: return (await coll.insert_one({ '_id': uid, 'uname': uname, 'uname_lower': uname_lower, 'mail': mail, 'mail_lower': mail_lower, 'salt': salt, 'hash': pwhash.hash_password(password, salt), 'reg_at': datetime.datetime.utcnow(), 'reg_ip': reg_ip, 'priv': priv, 'login_at': datetime.datetime.utcnow(), 'login_ip': reg_ip, 'gravatar': mail, **kwargs })).inserted_id except errors.DuplicateKeyError: raise error.UserAlreadyExistError(uid, uname, mail) from None
async def remove_status(domain_id: str, tid: int, uid: int): tsdoc = await get_status(domain_id, tid, uid) if not tsdoc: raise error.UserNotFoundError(uid) for j in tsdoc['journal']: await record.remove_property(j['rid'], 'tid') coll = db.Collection('contest.status') await coll.delete_one({'domain_id': domain_id, 'tid': tid, 'uid': uid}) return tsdoc
async def edit(domain_id: str, did: objectid.ObjectId, **kwargs): coll = db.Collection('testdata') doc = await coll.find_one_and_update(filter={ 'domain_id': domain_id, '_id': did }, update={'$set': kwargs}, return_document=True) return doc
async def set_status(domain_id, pid, uid, **kwargs): coll = db.Collection('problem.status') doc = await coll.find_one_and_update(filter={'domain_id': domain_id, 'pid': pid, 'uid': uid}, update={'$set': kwargs}, upsert=True, return_document=True) return doc
async def rev_set_status(domain_id, pid, uid, rev, **kwargs): coll = db.Collection('problem.status') return await coll.find_one_and_update(filter={'domain_id': domain_id, 'pid': pid, 'uid': uid, 'rev': rev}, update={'$set': kwargs, '$inc': {'rev': 1}}, return_document=True)
async def unlink(file_id: objectid.ObjectId): """Unlink a file.""" coll = db.Collection('fs.files') doc = await coll.find_one_and_update(filter={'_id': file_id}, update={'$inc': {'metadata.link': -1}}, return_document=True) if not doc['metadata']['link']: fs = db.GridFS('fs') await fs.delete(file_id)
async def inc_user(domain_id, uid, **kwargs): coll = db.Collection('domain.user') return await coll.find_one_and_update(filter={ 'domain_id': domain_id, 'uid': uid }, update={'$inc': kwargs}, upsert=True, return_document=True)