async def delete_account(request: Request): """ Delete account (stop monitoring) """ try: user_id = request.session["user_id"] except KeyError: LOGGER.debug( "Unauthenticated user attempted to delete account [%s]", request.client, ) return RedirectResponse("/") try: user = await User.objects.get(id=user_id) except orm.exceptions.NoMatch: LOGGER.warning( "User %s not found in the database; cannot delete [%s]", user_id, request.client, ) else: await user.delete() LOGGER.info("User %s deleted account [%s]", user_id, request.client) auth.sign_out(request) return RedirectResponse("/")
async def shutdown(): """ Shutdown actions """ # pylint:disable=import-outside-toplevel current_task = asyncio.current_task() other_tasks = [t for t in asyncio.all_tasks() if t is not current_task] LOGGER.info("Cancelling %s outstanding tasks", len(other_tasks)) for task in other_tasks: task.cancel() await DATABASE.disconnect() await asyncio.gather(*other_tasks, return_exceptions=True)
async def sign_out(request: Request): """ Sign out """ try: user_id = request.session["user_id"] except KeyError: LOGGER.debug("Unauthenticated user attempted to sign out [%s]", request.client) else: LOGGER.info("User %s signed out [%s]", user_id, request.client) auth.sign_out(request) return RedirectResponse("/")
async def sign_in(request: Request) -> Optional[User]: """ Try signing in the user (creating or updated them) Returns None if the user can't be signed in. """ user, created = await get_or_create_from_session(session=request.session) if user: LOGGER.info( "User %s signed in (%s) [%s]", user.id, "created" if created else "updated", request.client, ) request.session.clear() request.session["user_id"] = user.id else: LOGGER.debug("User sign in attempt failed [%s]", request.client) return user
async def _set_user_status(user: User, user_profile_args: UserProfileArgs, status_set_last_time: bool) -> bool: global UPDATE_THRESHOLD """ Set the user status & update their database entry. Returns success status """ try: current_profile = await get_status(user.slackAccessToken) if current_profile.profile.status_text == user_profile_args.status_text: return True LOGGER.info("Setting user status %s", user_profile_args) await asyncio.sleep(1) user_profile_data: UserProfileData = await set_status( user_profile_args, user.slackAccessToken) except SlackApiError as err: LOGGER.warning( "Exiting update loop. Could not set status for user %s: %s", user.id, err, ) UPDATE_THRESHOLD = datetime.now(timezone.utc) + timedelta(seconds=6) return False if not user_profile_data.ok: LOGGER.warning( "Exiting update loop. Could not set status for user %s: %s", user.id, user_profile_data.error, ) if user_profile_data.error in {"token_revoked"}: LOGGER.warning("Slack token revoked. Deleting user %s", user.id) await user.delete() return False await user.update( statusSetLastTime=status_set_last_time, updatedAt=datetime.now(timezone.utc), ) return True
@APP.on_event("shutdown") async def shutdown(): """ Shutdown actions """ await DATABASE.disconnect() if __name__ == "__main__": logging.basicConfig(level=2, format="%(levelname)-9s %(message)s") CONFIG = uvicorn.Config( "backend.main:APP", host="0.0.0.0", port=SETTINGS.port, loop="uvloop", log_level="info", use_colors=True, ) SERVER = uvicorn.Server(config=CONFIG) # Start both the server & worker together CONFIG.setup_event_loop() LOOP = asyncio.get_event_loop() try: LOOP.run_until_complete( asyncio.gather(SERVER.serve(), worker_entrypoint())) finally: LOOP.close() LOGGER.info("Shutdown successful")