async def force(ctx: lightbulb.Context) -> None: if ctx.options.type.lower() == "contest": q = session.query(Contest_DB).filter(Contest_DB.key == ctx.options.key) if q.count() == 0: await ctx.respond( f"There is no contests with the key {ctx.options.key} " f"cached. Will try fetching contest") else: q.delete() session.commit() query = Query() try: await query.get_contest(ctx.options.key) except ObjectNotFound: return await ctx.respond("Contest not found") await ctx.respond(f"Recached contest {ctx.options.key}") if ctx.options.type.lower() == "problem": q = session.query(Problem_DB).filter( Problem_DB.code == ctx.options.key) if q.count() == 0: await ctx.respond( f"There is no problems with the key {ctx.options.key} " f"cached. Will try fetching problem") else: q.delete() session.commit() query = Query() try: await query.get_problem(ctx.options.key) except ObjectNotFound: return await ctx.respond("Problem not found") await ctx.respond(f"Recached problem {ctx.options.key}") else: await ctx.send_help()
async def async_init(self): language_qq = session.query(Language_DB).\ filter(Language_DB.key.in_(self._languages)) language_q = session.query(Language_DB.key).\ filter(Language_DB.key.in_(self._languages)).all() language_q = list(map(itemgetter(0), language_q)) for language_key in self._languages: if language_key not in language_q: api = API() await api.get_languages() for language in api.data.objects: if language.key == language_key: session.add(Language_DB(language)) session.commit() break self.languages = language_qq.all() organization_qq = session.query(Organization_DB).\ filter(Organization_DB.id.in_(self._organizations)) organization_q = session.query(Organization_DB.id).\ filter(Organization_DB.id.in_(self._organizations)).all() organization_q = list(map(itemgetter(0), organization_q)) for organization_id in self._organizations: if organization_id not in organization_q: api = API() await api.get_organizations() for organization in api.data.objects: if organization.id == organization_id: session.add(Organization_DB(organization)) session.commit() break self.organizations = organization_qq.all()
async def get_problems(self, partial=None, group=None, _type=None, organization=None, search=None, cached=False) -> List[Problem_DB]: q = session.query(Problem_DB).\ filter(self.parse(Problem_DB.partial, partial)).\ filter(self.parse(Problem_DB.group, group)).\ filter(self.parse(Problem_DB.types, _type)).\ filter(self.parse(Problem_DB.organizations, organization)) if cached: return q.all() a = API() if search is not None: # Can't bother to implement something with db # maybe future me can do this await a.get_problems(partial=partial, group=group, _type=_type, organization=organization, search=search) return list(map(Problem_DB, a.data.objects)) page = 1 await a.get_problems(partial=partial, group=group, _type=_type, organization=organization, search=search, page=page) if a.data.total_objects == q.count(): return q.all() for problem in a.data.objects: qq = session.query(Problem_DB).\ filter(Problem_DB.code == problem.code) if qq.count() == 0: session.add(Problem_DB(problem)) while a.data.has_more: page += 1 await a.get_problems(partial=partial, group=group, _type=_type, organization=organization, search=search, page=page) for problem in a.data.objects: qq = session.query(Problem_DB).\ filter(Problem_DB.code == problem.code) if qq.count() == 0: session.add(Problem_DB(problem)) session.commit() return q.all()
async def async_map(_type, objects, is_latest=False): # is_latest is to optimize parsing little submissions # and many submissions if not is_latest: problems = session.query(Problem_DB.code, Problem_DB).all() problems = {k: v for k, v in problems} users = session.query(User_DB.username, User_DB).all() users = {k: v for k, v in users} languages = session.query(Language_DB.key, Language_DB).all() languages = {k: v for k, v in languages} to_gather = [] lock_table = {} for obj in objects: if is_latest: to_gather.append(obj.async_old()) else: # If a user attempts to cache submissions after the latest release of a contest, there is a chance it will cause a db error # this is because any submissions which are not in the db will be called by the api and stored into the db # but in between that moment of calling the api and storing into the db, another process will call the api for the same problem # because it is technically not in memory yet # This fix to this is two global tables and a lock to_gather.append( obj.async_init(problems, users, languages, lock_table) ) await asyncio.gather(*to_gather) session.commit()
async def get_contests(self, tag=None, organization=None) -> List[Contest_DB]: a = API() page = 1 await a.get_contests(tag=tag, organization=organization, page=page) q = session.query(Contest_DB).\ filter(self.parse(Contest_DB.tags, tag)).\ filter(self.parse(Contest_DB.organizations, organization)) if a.data.total_objects == q.count(): return q.all() for contest in a.data.objects: qq = session.query(Contest_DB).\ filter(Contest_DB.key == contest.key) if qq.count() == 0: session.add(Contest_DB(contest)) while a.data.has_more: page += 1 await a.get_contests(tag=tag, organization=organization, page=page) for contest in a.data.objects: qq = session.query(Contest_DB).\ filter(Contest_DB.key == contest.key) if qq.count() == 0: session.add(Contest_DB(contest)) session.commit() return q.all()
async def _set(self, ctx, member: discord.Member, username: str): """Manually link two accounts together""" query = Query() user = await query.get_user(username) if user is None: await ctx.send(f'{username} does not exist on dmoj') return username = user.username if query.get_handle(member.id, ctx.guild.id): await ctx.send( '%s, this handle is already linked with %s.' % (ctx.author.mention, query.get_handle(member.id, ctx.guild.id)) ) return if query.get_handle_user(username, ctx.guild.id): await ctx.send('This handle is already linked with another user') return handle = Handle_DB() handle.id = member.id handle.handle = username handle.user_id = user.id handle.guild_id = ctx.guild.id session.add(handle) session.commit() return await ctx.send("%s, %s is now linked with %s." % (ctx.author.name, member.name, username))
def refresh_data(): fetch = requests.get('http://network:5000/devices/') devices = fetch.json() for device in devices: del device["id"] active = device.pop("active_connection") upload = device.pop("upload_speed") download = device.pop("download_speed") found_device = session.query(StaticData).filter_by( mac_address=device["mac_address"]).first() if found_device: static_data_id = found_device.id else: new_device = StaticData(**device) session.add(new_device) session.commit() static_data_id = new_device.id snap_shot = { "static_data_id": static_data_id, "time_stamp": datetime.now(), "active_connection": active, "upload_speed": upload, "download_speed": download } dynamic_data = DynamicData(**snap_shot) session.add(dynamic_data) session.commit()
async def async_init(self): organization_qq = session.query(Organization_DB).filter( Organization_DB.id.in_(self._organizations)) organization_q = session.query(Organization_DB.id).filter( Organization_DB.id.in_(self._organizations)).all() organization_q = list(map(itemgetter(0), organization_q)) for organization_id in self._organizations: if organization_id not in organization_q: api = API() await api.get_organizations() for organization in api.data.objects: if organization.id not in organization_q and organization.id in self._organizations: session.add(Organization_DB(organization)) session.commit() break self.organizations = organization_qq.all() # perhaps I should check if it's the general or detailed version self._problem_codes = list(map(itemgetter("code"), self._problems)) problem_qq = session.query(Problem_DB).filter( Problem_DB.code.in_(self._problem_codes)) problem_q = session.query(Problem_DB.code).filter( Problem_DB.code.in_(self._problem_codes)).all() problem_q = list(map(itemgetter(0), problem_q)) for problem_dict in self._problems: problem_code = problem_dict["code"] try: if problem_code not in problem_q: api = API() await api.get_problem(problem_code) session.add(Problem_DB(api.data.object)) session.commit() except ObjectNotFound: pass self.problems = problem_qq.all()
async def get_users(self, organization=None) -> List[User_DB]: a = API() page = 1 await a.get_users(organization=organization, page=page) q = session.query(User_DB).\ filter(self.parse(User_DB.organizations, organization)) if a.data.total_objects == q.count(): return q.all() for user in a.data.objects: qq = session.query(User_DB).\ filter(User_DB.id == user.id) if qq.count() == 0: session.add(User_DB(user)) while a.data.has_more: page += 1 await a.get_users(organization=organization, page=page) for user in a.data.objects: qq = session.query(User_DB).\ filter(User_DB.id == user.id) if qq.count() == 0: session.add(User_DB(user)) session.commit() return q.all()
async def link(self, ctx, username: str): """Links your discord account to your dmoj account""" # Check if user exists query = Query() user = await query.get_user(username) if user is None: await ctx.send(f"{username} does not exist on DMOJ") return username = user.username if query.get_handle(ctx.author.id, ctx.guild.id): await ctx.send('%s, your handle is already linked with %s.' % (ctx.author.mention, query.get_handle(ctx.author.id, ctx.guild.id))) return if query.get_handle_user(username, ctx.guild.id): await ctx.send('This handle is already linked with another user') return problem = query.get_random_problem() if problem is None: await ctx.send('No problems are cached.. ' 'Pls do something about that') # Will implement this # Just cache the problems and get a random one return await ctx.send( '%s, submit a compiler error to <https://dmoj.ca/problem/%s> ' 'within 60 seconds' % (ctx.author.mention, problem.code)) await asyncio.sleep(60) submissions = await query.get_latest_submissions(username, 10) # if the user links twice, it might break the db # Should add decorator to prevent this if query.get_handle(ctx.author.id, ctx.guild.id): return for submission in submissions: if (submission.result == 'CE' and submission.problem[0].code == problem.code): handle = Handle_DB() handle.id = ctx.author.id handle.handle = username handle.user_id = user.id handle.guild_id = ctx.guild.id session.add(handle) session.commit() return await ctx.send( "%s, you now have linked your account to %s." % (ctx.author.name, username)) else: return await ctx.send('I don\'t see anything :monkey: ' '(Failed to link accounts)')
async def force(self, ctx, _type, key): ''' Force a recache of a problem, or contest ''' if _type.lower() == 'contest': q = session.query(Contest_DB).filter(Contest_DB.key == key) if q.count() == 0: await ctx.send(f'There is no contests with the key {key} ' f'cached. Will try fetching contest') else: q.delete() session.commit() query = Query() try: await query.get_contest(key) except ObjectNotFound: return await ctx.send('Contest not found') await ctx.send(f'Recached contest {key}') if _type.lower() == 'problem': q = session.query(Problem_DB).filter(Problem_DB.code == key) if q.count() == 0: await ctx.send(f'There is no problems with the key {key} ' f'cached. Will try fetching problem') else: q.delete() session.commit() query = Query() try: await query.get_problem(key) except ObjectNotFound: return await ctx.send('Problem not found') await ctx.send(f'Recached problem {key}')
async def update_problems(self, ctx): """Update all problems in db (For when Nick nukes problems)""" msg = await ctx.send("Updating...") session.query(Problem_DB).delete() session.commit() query = Query() await query.get_problems() return await msg.edit(content="Updated all problems")
async def link(ctx: lightbulb.Context) -> None: username = ctx.options.username # Check if user exists query = Query() try: user = await query.get_user(username) if user is None: raise ObjectNotFound() except ObjectNotFound: await ctx.respond(escape_markdown(f"{username} does not exist on DMOJ")) return username = user.username if query.get_handle(ctx.author.id, ctx.get_guild().id): await ctx.respond( "%s, your handle is already linked with %s." % (ctx.author.mention, query.get_handle(ctx.author.id, ctx.get_guild().id)) ) return if query.get_handle_user(username, ctx.get_guild().id): await ctx.respond("This handle is already linked with another user") return # verify from dmoj user description description = await query.get_user_description(username) userKey = hashlib.sha256(str(ctx.author.id).encode()).hexdigest() if userKey not in description: await ctx.respond( "Put `" + userKey + "` in your DMOJ user description (https://dmoj.ca/edit/profile/) " "and run the command again." ) return handle = Handle_DB() handle.id = ctx.author.id handle.handle = username handle.user_id = user.id handle.guild_id = ctx.get_guild().id session.add(handle) session.commit() await ctx.respond(escape_markdown("%s, you now have linked your account to %s" % (ctx.author, username))) rank_to_role = {} rc = lightbulb.RoleConverter(ctx) for role_id in ctx.get_guild().get_roles(): role = await rc.convert(str(role_id)) if role.name in RANKS: rank_to_role[role.name] = role rank = rating_to_rank(user.rating) # TODO Add guild specific option to disable updating roles if rank in rank_to_role: await _update_rank(ctx.member, rank_to_role[rank], "Dmoj account linked") else: await ctx.respond("You are missing the `" + rank + "` role")
def insert(self, handle, guild_id, point, problem, time): db = Gitgud_DB() db.handle = handle db.guild_id = guild_id db.point = point db.problem_id = problem db.time = time session.add(db) session.commit()
async def update_problems(ctx: lightbulb.Context) -> None: """Update all problems in db (For when Nick nukes problems)""" # TODO Add live counter msg = await ctx.respond("Updating...") session.query(Problem_DB).delete() session.commit() query = Query() await query.get_problems() return await msg.edit(content="Updated all problems")
def post(self): stus = [] for i in range(100): stu = Students() stu.s_name = 'nz1904_%s' % i stus.append(stu) session.add_all(stus) session.commit() self.write('添加数据成功')
async def _set(self, ctx, member, username: str): """Manually link two accounts together""" query = Query() member = await query.parseUser(ctx, member) if username != "+remove": user = await query.get_user(username) if user is None: await ctx.send(f'{username} does not exist on dmoj') return username = user.username handle = query.get_handle(member.id, ctx.guild.id) if handle == username: return await ctx.send( f'{member.display_name} is already linked with {handle}') if handle: handle = session.query(Handle_DB)\ .filter(Handle_DB.id == member.id)\ .filter(Handle_DB.guild_id == ctx.guild.id).first() session.delete(handle) session.commit() await ctx.send( f'Unlinked {member.display_name} with handle {handle.handle}') if username == "+remove": return if query.get_handle_user(username, ctx.guild.id): await ctx.send('This handle is already linked with another user') return handle = Handle_DB() handle.id = member.id handle.handle = username handle.user_id = user.id handle.guild_id = ctx.guild.id session.add(handle) session.commit() await ctx.send(f"Linked {member.name} with {username}.") rank_to_role = { role.name: role for role in ctx.guild.roles if role.name in RANKS } rank = self.rating_to_rank(user.rating) if rank in rank_to_role: await self._update_rank(ctx.author, rank_to_role[rank], 'Dmoj account linked') else: await ctx.send("You are missing the " + rank.name + " role")
async def unlink(self, ctx): """Unlink your discord account with your dmoj account""" query = Query() if not query.get_handle(ctx.author.id, ctx.guild.id): await ctx.send('You are not linked with any user') return handle = session.query(Handle_DB)\ .filter(Handle_DB.id == ctx.author.id)\ .filter(Handle_DB.guild_id == ctx.guild.id).first() session.delete(handle) session.commit() await ctx.send(f'Unlinked you with handle {handle.handle}')
async def cache_contests(self, ctx): '''Individually caches every contest''' msg = await ctx.send('Caching...') query = Query() contests = await query.get_contests() for contest in contests: q = session.query(Contest_DB).filter(Contest_DB.key == contest.key) if q.count() > 0: q.delete() session.commit() await query.get_contest(contest.key) return await msg.edit(content=f'Cached {len(contests)} contests')
async def link(self, ctx, username: str): '''Links your discord account to your dmoj account''' # Check if user exists query = Query() user = await query.get_user(username) if user is None: await ctx.send(f'{username} does not exist on DMOJ') return username = user.username if query.get_handle(ctx.author.id, ctx.guild.id): await ctx.send('%s, your handle is already linked with %s.' % (ctx.author.mention, query.get_handle(ctx.author.id, ctx.guild.id))) return if query.get_handle_user(username, ctx.guild.id): await ctx.send('This handle is already linked with another user') return # verify from dmoj user description description = await query.get_user_description(username) userKey = hashlib.sha256(str(ctx.author.id).encode()).hexdigest() if userKey not in description: await ctx.send( 'Put `' + userKey + '` in your DMOJ user description (https://dmoj.ca/edit/profile/) ' 'and run the command again.') return handle = Handle_DB() handle.id = ctx.author.id handle.handle = username handle.user_id = user.id handle.guild_id = ctx.guild.id session.add(handle) session.commit() await ctx.send('%s, you now have linked your account to %s' % (ctx.author.name, username)) return rank_to_role = { role.name: role for role in ctx.guild.roles if role.name in RANKS } rank = self.rating_to_rank(user.rating) if rank in rank_to_role: await self._update_rank(ctx.author, rank_to_role[rank], 'Dmoj account linked') else: await ctx.send('You are missing the ' + rank.name + ' role')
async def get_languages(self, common_name=None) -> [Language_DB]: q = session.query(Language_DB).\ filter(self.parse(Language_DB.common_name, common_name)) if q.count(): return q.all() a = API() await a.get_languages(common_name=common_name) languages = list(map(Language_DB, a.data.objects)) for language in languages: session.add(language) session.commit() return languages
async def get_contest(self, key) -> Contest_DB: q = session.query(Contest_DB).\ filter(Contest_DB.key == key) if q.count(): # is_rated checks if it has detailed rows if q.first().is_rated is not None: return q.first() a = API() await a.get_contest(key) if q.count(): q.delete() session.add(Contest_DB(a.data.object)) session.commit() return q.first()
def bind(self, handle, guild_id, problem_id, point, time): result = self.get_current(handle, guild_id) if result is None: db = CurrentGitgud_DB() db.handle = handle db.guild_id = guild_id db.problem_id = problem_id db.point = point db.time = time session.add(db) else: result.problem_id = problem_id result.point = point result.time = time session.commit()
async def get_problem(self, code) -> Problem_DB: q = session.query(Problem_DB).\ filter(Problem_DB.code == code) if q.count(): # has_rating check if it has a detailed row if q.first().short_circuit is not None: return q.first() a = API() await a.get_problem(code) if q.count(): q.delete() session.add(Problem_DB(a.data.object)) session.commit() return q.first()
async def get_user(self, username) -> User_DB: q = session.query(User_DB).\ filter(func.lower(User_DB.username) == func.lower(username)) # if q.count(): # # solved_problems checks if it has detailed rows # if len(q.first().solved_problems) != 0: # return q.first() a = API() await a.get_user(username) if q.count(): # Needs to be fetch, the default (evaluate) is not able to eval # the query q.delete(synchronize_session='fetch') session.add(User_DB(a.data.object)) session.commit() return q.first()
async def get_contest(self, key: str) -> Contest_DB: q = session.query(Contest_DB).\ filter(Contest_DB.key == key) if q.count(): # is_rated checks if it has detailed rows if q.first().is_rated is not None: return q.first() a = API() await a.get_contest(key) # Requery the key to prevent path traversal from killing db q = session.query(Contest_DB).\ filter(Contest_DB.key == a.data.object.key) if q.count(): q.delete() session.add(Contest_DB(a.data.object)) session.commit() return q.first()
async def unlink(ctx: lightbulb.Context) -> None: # TODO: Add admin ability to manually unlink query = Query() if not query.get_handle(ctx.author.id, ctx.get_guild().id): await ctx.respond("You are not linked with any user") return handle = ( session.query(Handle_DB) .filter(Handle_DB.id == ctx.author.id) .filter(Handle_DB.guild_id == ctx.get_guild().id) .first() ) session.query(User_DB).filter(User_DB.id == handle.user_id).delete() session.query(Submission_DB).filter(Submission_DB._user == handle.handle).delete() session.delete(handle) session.commit() await ctx.respond(escape_markdown(f"Unlinked you with handle {handle.handle}"))
async def postcontest(self, ctx, key): """Updates post-contest role""" await ctx.message.delete() query = Query() username = query.get_handle(ctx.author.id, ctx.guild.id) if username is None: return await ctx.send("Your account is not linked!") q = session.query(Contest_DB).filter(Contest_DB.key == key) # Clear cache if q.count(): q.delete() session.commit() try: contest = await query.get_contest(key) except ObjectNotFound: await ctx.send("Contest not found") return if contest.is_organization_private: return await ctx.send("Contest not found") role = get(ctx.guild.roles, name="postcontest " + key) if not role: return await ctx.send(f"No `postcontest {key}` role found.") for ranking in contest.rankings: if ranking['user'].lower() != username.lower(): continue endTime = datetime.strptime(ranking['end_time'], '%Y-%m-%dT%H:%M:%S%z') if endTime > datetime.now(timezone.utc).astimezone(): return await ctx.send("Your window is not done.") else: try: await ctx.author.add_roles(role) except discord.Forbidden: return await ctx.send("No permission to assign the role.") return await ctx.send("You've been added to post contest.") return await ctx.send("You haven't joined the contest yet.")
async def update_submissions(self, ctx): """Updates the submissions of every user in db (Warning! Slow!)""" q = session.query(Submission_DB._user).distinct(Submission_DB._user) usernames = list(map(itemgetter(0), q.all())) await ctx.send(f"Recaching submissions for {len(usernames)}" f" users. This will take a long time (perhaps hours).") session.query(Submission_DB).delete() session.commit() query = Query() count = 0 msg = await ctx.send(f"{count}/{len(usernames)} users cached...") for username in usernames: await msg.edit(content=f"{count}/{len(usernames)} users cached..." f" ({username})") await query.get_submissions(username) time.sleep(30) # PLS DON'T GET CLOUDFLARED count += 1 await msg.edit(content=f"{len(usernames)} users cache. Done!")
async def async_init(self): user = session.query(User_DB).filter(User_DB.username == self._user) if user.count() == 0: api = API() await api.get_user(self._user) session.add(api.data.object) session.commit() self.user = user.first() contest = session.query(Contest_DB).filter( Contest_DB.key == self._contest) if contest.count() == 0: api = API() await api.get_contest(self._contest) session.add(api.data.object) session.commit() self.contest = contest.first()