async def login(response: Response, credentials: OAuth2PasswordRequestForm = Depends()): user = await fapiuser.db.authenticate(credentials) if user is None or not user.is_active or not user.is_verified: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=ErrorCode.LOGIN_BAD_CREDENTIALS, ) try: token = await update_refresh_token(user) except DoesNotExist: token = await create_refresh_token(user) cookie = refresh_cookie(REFRESH_TOKEN_KEY, token) response.set_cookie(**cookie) partialkey = s.CACHE_USERNAME.format(user.id) if not red.exists(partialkey): await UserMod.get_and_cache(user.id) data = { **await jwtauth.get_login_response(user, response), 'is_verified': user.is_verified } if not user.is_verified: data.update( dict(details='User is not verified yet so user cannot log in.')) return data
async def get_perms(self) -> list: """ Get group + user perms from cache else query. :return: List of perms """ allperms = set() # Get group perms from cache for group in self.groups: # noqa group_partialkey = s.CACHE_GROUPNAME.format(group) if red.exists(group_partialkey): cached_perms = red.get(group_partialkey) allperms.update(cached_perms) else: queried_perms = await Group.get_and_cache(group) allperms.update(queried_perms) # Include any user perms if any allperms.update(self.permissions) # noqa return list(allperms)
async def get_and_cache(cls, group: str) -> list: """ Get a group's permissions and cache it for future use. Replaces data if exists. Only one group must be given so each can be cached separately. :param group: Group name :return: list """ perms = await Permission.filter(groups__name=group ).values_list('code', flat=True) perms = perms or [] if perms: # Save back to cache partialkey = s.CACHE_GROUPNAME.format(group) red.set(partialkey, perms, ttl=-1, clear=True) grouplist = red.exists('groups') and red.get('groups') or [] if group not in grouplist: grouplist.append(group) red.set('groups', grouplist, clear=True) return perms
async def get_data(cls, id, force_query=False, debug=False): """ Get the UserDBComplete data whether it be via cache or query. Checks cache first else query. :param force_query: Force use query instead of checking the cache :param id: User id :param debug: Debug data for tests :return: UserDBComplete/tuple or None """ from app.auth import userdb debug = debug if s.DEBUG else False partialkey = s.CACHE_USERNAME.format(id) if not force_query and red.exists(partialkey): source = 'CACHE' user_data = cache.restoreuser_dict(red.get(partialkey)) user = userdb.usercomplete(**user_data) else: source = 'QUERY' user = await UserMod.get_and_cache(id) if debug: return user, source return user
async def get_groups(self, force_query=False, debug=False) -> Union[list, tuple]: """ Return a user's groups as a list from the cache or not. Uses cache else query. :param force_query: Don't use cache :param debug: Return debug data for tests :return: List of groups if not debug """ from app.auth import userdb debug = debug if s.DEBUG else False partialkey = s.CACHE_USERNAME.format(self.id) if not force_query and red.exists(partialkey): user_dict = red.get(partialkey) source = 'CACHE' user_dict = cache.restoreuser_dict(user_dict) user = userdb.usercomplete(**user_dict) else: source = 'QUERY' user = await UserMod.get_and_cache(self.id) if debug: return user.groups, source return user.groups
async def update_group(res: Response, groupdata: UpdateGroupVM, user=Depends(current_user)): if not await user.has_perm('group.update'): raise x.PermissionDenied() try: group = await Group.get_or_none(pk=groupdata.id ).only('id', 'name', 'summary') if not group: raise x.NotFoundError('Group') await group.update_group(groupdata) res.status_code = 204 # Update the cache if exists oldkey = s.CACHE_GROUPNAME.format(group.name) newkey = s.CACHE_GROUPNAME.format(groupdata.name) if red.exists(oldkey): formatted_oldkey = red.formatkey(oldkey) formatted_newkey = red.formatkey(newkey) red.rename(formatted_oldkey, formatted_newkey) except (BaseORMException, RedisError): raise x.BADERROR_503() except Exception: raise x.AppError()
def test_redis_key(self): self.assertTrue(red.exists(self.game_id))
def test_get_permissions(tempdb, loop, groups, perms, remove, src): async def ab(): await tempdb() return await Group.get_permissions(*listify(groups), debug=True) groups = listify(groups) for idx, group in enumerate(groups): partialkey = s.CACHE_GROUPNAME.format(group) remove = listify(remove) if remove[idx]: red.delete(partialkey) assert not red.get(partialkey) assert not red.exists(partialkey) loop.run_until_complete(ab()) # ic(x) # allperms, sources = loop.run_until_complete(ab()) # assert Counter(allperms) == Counter(perms) # assert Counter(sources) == Counter(listify(src)) # param = [ # ('user.create', 'AdminGroup', True), # ('user.create', 'NoaddGroup', True), # ('page.create', 'ContentGroup', True), # ('page.create', 'NoaddGroup', False), # ('page.create', 'abc', False), # ('', 'abc', False), # ('page.create', '', False), # ] # @pytest.mark.parametrize('perm, group, out', param) # @pytest.mark.focus # def test_is_group(loop, perm, group, out): # async def ab(): # assert await Permission.is_group(perm, group) == out # loop.run_until_complete(ab()) # # @pytest.mark.focus # def test_abc(loop, tempdb): # from app.authentication import Option # # async def ab(): # await tempdb() # await Option.create(name='foo', value='bar') # opt = await Option.all() # ic(opt) # # loop.run_until_complete(ab())