async def add_post(user_id: int, post: InPost) -> TaskResponse: user = await UsersDataAccessLayer.get_user(user_id, without_error=True) if not user: raise DALError(HTTPStatus.NOT_FOUND.value, Message.USER_DOES_NOT_EXISTS.value) ids = post.marked_users_ids if ids is not None and ( not await PostsDAL._are_marked_users_correct(ids) or user_id in ids): raise DALError(HTTPStatus.BAD_REQUEST.value, Message.INCORRECTLY_MARKED_USERS.value) task_id = str(uuid4()) job = RedisInstances.redis_queue().enqueue(process_image, user_id, post, task_id) async_redis = await RedisInstances.async_redis() async_redis.sadd(RedisKey.TASKS_IN_PROGRESS.value, task_id) job_result: Optional[WorkerResult] = job.result if job_result: if job_result.post_id: return TaskResponse( task_id=task_id, status=Message.POST_READY.value, post_id=job_result.post_id, ) return TaskResponse( task_id=task_id, status=Message.POST_TASK_FALLEN.value, error_text=job_result.error, ) return TaskResponse(task_id=task_id, status=Message.POST_ACCEPTED_FOR_PROCESSING.value)
def _authenticate_user(username: str, password: str) -> Awaitable[OutUser]: message = Message.INCORRECT_USERNAME_OR_PASSWORD.value with create_session() as session: user: Optional[User] = session.query(User).filter( User.username == username).first() user = deepcopy(user) if user is None: raise DALError(HTTPStatus.UNAUTHORIZED.value, message) if _is_password_correct(password, user.password_hash): return OutUser.from_orm(user) # type: ignore raise DALError(HTTPStatus.UNAUTHORIZED.value, message)
def _get_user_id(token: str) -> int: try: payload: Dict[str, Any] = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) user_id = payload.get('sub') if not user_id or not isinstance(user_id, int): raise DALError(HTTPStatus.UNAUTHORIZED.value, Message.NOT_EXPECTING_PAYLOAD.value) return user_id except PyJWTError: raise DALError(HTTPStatus.UNAUTHORIZED.value, Message.COULD_NOT_VALIDATE_CREDENTIALS.value)
def _get_post(post_id: int, session: Session) -> Awaitable[DBPost]: post: DBPost = session.query(DBPost).filter( DBPost.id == post_id).first() if not post: raise DALError(HTTPStatus.NOT_FOUND.value, Message.POST_NOT_EXISTS.value) return post # type: ignore
def get_all_user_images(user_id: int) -> List[ImageWithPath]: users_folder = _get_project_root() / _get_name_for_grouping_id(user_id) user_folder = users_folder / str(user_id) if not user_folder.exists(): raise DALError(HTTPStatus.NOT_FOUND.value, Message.USER_DOES_NOT_HAVE_IMAGES.value) return _get_all_images_from_folder(user_folder)
def get_image(image_path: Path) -> Base64: if not image_path.exists(): raise DALError(HTTPStatus.NOT_FOUND.value, Message.IMAGE_DOES_NOT_EXISTS_ON_STORAGE.value) with image_path.open('rb') as f: image_bytes = f.read() return encode_bytes_to_base64(image_bytes)
async def _get_user_from_db(user_id: int) -> UserWithTokens: user = await UsersDataAccessLayer.get_user(user_id, without_error=True, need_tokens=True) if not user: raise DALError(HTTPStatus.UNAUTHORIZED.value, Message.USER_DOES_NOT_EXISTS.value) return user # type: ignore
async def get_posts(user_id: int) -> List[PostWithImage]: with create_session() as session: user = session.query(User).filter(User.id == user_id).first() if not user: raise DALError(HTTPStatus.NOT_FOUND.value, Message.USER_DOES_NOT_EXISTS.value) posts = user.posts if not posts: raise DALError(HTTPStatus.NOT_FOUND.value, Message.POSTS_DO_NOT_EXIST.value) try: images: List[ ImageWithPath] = await storage_client.get_all_user_images( user_id) except StorageError as e: raise DALError(HTTPStatus.BAD_REQUEST.value, e) return join_posts_with_images(posts, images)
def test_add_user_returns_error_message_when_error_raised( client: TestClient, in_user, mocker): mocker.patch.object(UsersDataAccessLayer, 'add_user').side_effect = DALError( HTTPStatus.BAD_REQUEST.value, Message.USER_ALREADY_EXISTS.value) response: Response = client.post('/users/', json=dict(in_user)) assert response.status_code == HTTPStatus.BAD_REQUEST assert response.json()['detail'] == Message.USER_ALREADY_EXISTS.value
def test_login_returns_expected_error(mocked_auth, client, auth_data): mocked_auth.generate_tokens.side_effect = DALError( HTTPStatus.UNAUTHORIZED.value, Message.INCORRECT_USERNAME_OR_PASSWORD.value) response = client.post('/auth/token', data=auth_data) assert response.status_code == HTTPStatus.UNAUTHORIZED json = response.json() assert len(json) == 1 assert json['detail'] == Message.INCORRECT_USERNAME_OR_PASSWORD.value
def test_refresh_token_with_error_returns_expected_value( mocked_auth, client, refresh_token_payload): mocked_auth.refresh_tokens.side_effect = DALError( HTTPStatus.BAD_REQUEST.value, Message.INVALID_REFRESH_TOKEN.value) response = client.post('/auth/fresh_token', json=refresh_token_payload) assert response.status_code == HTTPStatus.BAD_REQUEST json = response.json() assert len(json) == 1 assert json['detail'] == Message.INVALID_REFRESH_TOKEN.value
async def refresh_tokens(refresh_token: str) -> TokensResponse: ''' Проверяет refresh_token и возвращает новую пару токенов ''' user_id = _get_user_id(refresh_token) user = await _get_user_from_db(user_id) if not _is_valid_token(refresh_token, user.refresh_token.decode()): raise DALError(HTTPStatus.UNAUTHORIZED.value, Message.INVALID_REFRESH_TOKEN.value) return await _create_tokens(user)
async def like(post_id: int, user_id_who_likes: int) -> List[OutUser]: with create_session() as session: post = await PostDAL._get_post(post_id, session) likes = post.likes user = await PostDAL._get_user(user_id_who_likes, session) if PostDAL._is_user_has_like(likes, user): raise DALError( HTTPStatus.BAD_REQUEST.value, Message.USER_HAS_ALREADY_LIKE_THIS_POST.value, ) likes.append(user) return [OutUser.from_orm(user) for user in likes]
async def check_authorization(token: str = Depends(oauth_scheme), ) -> OutUser: ''' Обрабатывает jwt :raises HttpException со статусом 401 если произошла ошибка при обработке токена :return: user ''' user_id = _get_user_id(token) user = await _get_user_from_db(user_id) if _is_valid_token(token, user.access_token.decode()): return OutUser.from_orm(user) raise DALError(HTTPStatus.UNAUTHORIZED.value, Message.ACCESS_TOKEN_OUTDATED.value)
async def remove_like(post_id: int, user_id_who_wants_delete_like: int) -> None: with create_session() as session: post = await PostDAL._get_post(post_id, session) user = await PostDAL._get_user(user_id_who_wants_delete_like, session) likes = post.likes if not PostDAL._is_user_has_like(likes, user): raise DALError( HTTPStatus.NOT_FOUND.value, Message.USER_DID_NOT_LIKE_THIS_POST.value, ) likes.remove(user)
async def get_post(post_id: int) -> PostWithImage: with create_session() as session: post = await PostDAL._get_post(post_id, session) try: image: Base64 = (await storage_client.get_image_from_storage_async( post.image_path)).image except StorageError: raise DALError( HTTPStatus.NOT_FOUND.value, Message.IMAGE_DOES_NOT_EXISTS_ON_STORAGE.value, ) serialized_post: Post = serialize(post) # type: ignore return PostWithImage(**serialized_post.dict(), image=image)
async def get_task_status(task_id: str) -> TaskResponse: redis = await RedisInstances.async_redis() solved_task: Optional[bytes] = (await redis.hmget( RedisKey.SOLVED_TASKS.value, task_id))[0] if solved_task: return TaskResponse( task_id=task_id, status=Message.POST_READY.value, post_id=solved_task.decode(), ) fallen_task: Optional[bytes] = (await redis.hmget( RedisKey.FALLEN_TASKS.value, task_id))[0] if fallen_task: return TaskResponse( task_id=task_id, status=Message.POST_TASK_FALLEN.value, error_text=fallen_task.decode(), ) if await redis.sismember(RedisKey.TASKS_IN_PROGRESS.value, task_id): return TaskResponse( task_id=task_id, status=Message.POST_ACCEPTED_FOR_PROCESSING.value) raise DALError(HTTPStatus.NOT_FOUND.value, Message.TASK_NOT_EXISTS.value)
def _get_user(user_id: int, session: Session) -> Awaitable[User]: user = session.query(User).filter(User.id == user_id).first() if user: return user raise DALError(HTTPStatus.NOT_FOUND.value, Message.USER_DOES_NOT_EXISTS.value)