Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions backend/api/api_v1/projects/list_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
ProjectWithRenderCreate,
ProjectWithRenderResponse,
)
from services.projects.project_pagination import ProjectPaginationService

router = APIRouter()

Expand All @@ -26,7 +25,7 @@
],
)
async def get_public_projects(
project_pagination_service: ProjectPaginationService,
project_pagination_service: ProjectPaginationServiceDep,
size: PaginationSizeDep = 10,
page: PaginationPageDep = 1,
) -> ProjectResponseList:
Expand Down
4 changes: 2 additions & 2 deletions backend/api/api_v1/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ async def update_current_user_profile(
@router.delete(
"/about-me",
response_model=None,
status_code=status.HTTP_200_OK,
status_code=status.HTTP_204_NO_CONTENT,
)
async def delete_current_user_profile(
user_id: AuthUserByAccessTokenDep,
Expand All @@ -50,7 +50,7 @@ async def delete_current_user_profile(
response_model=UserResponse,
status_code=status.HTTP_200_OK,
)
async def get_user_by_id(
async def get_user_profile(
user_id: int,
user_service: UserServiceDep,
) -> UserResponse:
Expand Down
2 changes: 1 addition & 1 deletion backend/api/exception_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def exception_handler(
status_code=status.HTTP_404_NOT_FOUND,
)
conflict_error_exception_handler = exception_handler_factory(
status_code=status.HTTP_400_BAD_REQUEST,
status_code=status.HTTP_409_CONFLICT,
)
authentication_error_exception_handler = exception_handler_factory(
status_code=status.HTTP_403_FORBIDDEN,
Expand Down
27 changes: 27 additions & 0 deletions backend/core/interfaces/services.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from abc import ABC, abstractmethod
from typing import BinaryIO

from infrastructure.database.models import Project
from schemas.file import FileResponse


Expand All @@ -18,3 +19,29 @@ async def upload(
"""
Метод для загрузки файла.
"""


class AbstractProjectAccessValidatorService(ABC):
"""
Интерфейс для сервиса проверки прав доступа к проекту.
"""

@abstractmethod
async def validate_access_to_get_project(
self,
project_id: int,
user_id: int,
) -> Project:
"""
Метод для проверки прав доступа на просмотр проекта.
"""

@abstractmethod
async def validate_access_to_change_project(
self,
project_id: int,
user_id: int,
) -> Project:
"""
Метод для проверки прав доступа на изменение данных проекта.
"""
2 changes: 1 addition & 1 deletion backend/dependencies/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
from infrastructure.minio.client import MinioClient
from services.auth import AuthService
from services.file_uploader import FileUploader
from services.projects.access_validator import ProjectAccessValidatorService
from services.projects.project import ProjectService
from services.projects.project_access_validator import ProjectAccessValidatorService
from services.projects.project_pagination import ProjectPaginationService
from services.tag import TagService
from services.user import UserService
Expand Down
5 changes: 2 additions & 3 deletions backend/services/projects/project.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from core.config.application import settings
from core.exceptions.file import FileIdNotFoundError
from core.interfaces.clients import AbstractS3Client, AbstractUnitOfWorkClient
from core.interfaces.services import AbstractProjectAccessValidatorService
from core.logging import get_logger
from infrastructure.database.repositories import (
FileRepository,
Expand All @@ -22,8 +23,6 @@
)
from schemas.render import RenderCreate

from services.projects.access_validator import ProjectAccessValidatorService

logger = get_logger(__name__)


Expand All @@ -38,7 +37,7 @@ class ProjectService:
def __init__(
self,
unit_of_work: AbstractUnitOfWorkClient,
project_access_validator: ProjectAccessValidatorService,
project_access_validator: AbstractProjectAccessValidatorService,
) -> None:
self.project_access_validator = project_access_validator
self.unit_of_work = unit_of_work
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
from core.exceptions.project import ProjectIdNotFoundError
from core.exceptions.user import UserIdNotFoundError
from core.interfaces.clients import AbstractUnitOfWorkClient
from core.interfaces.services import AbstractProjectAccessValidatorService
from infrastructure.database.models import Project
from infrastructure.database.repositories import (
ProjectRepository,
)


class ProjectAccessValidatorService:
class ProjectAccessValidatorService(AbstractProjectAccessValidatorService):
def __init__(
self,
unit_of_work: AbstractUnitOfWorkClient,
Expand Down
2 changes: 1 addition & 1 deletion backend/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
from infrastructure.minio.client import MinioClient
from services.auth import AuthService
from services.file_uploader import FileUploader
from services.projects.access_validator import ProjectAccessValidatorService
from services.projects.project import ProjectService
from services.projects.project_access_validator import ProjectAccessValidatorService
from services.projects.project_pagination import ProjectPaginationService
from services.projects.render_generate_handler import RenderGenerateHandlerService
from services.tag import TagService
Expand Down
Empty file.
135 changes: 135 additions & 0 deletions backend/tests/test_api/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
from collections.abc import Generator
from datetime import datetime
from unittest.mock import AsyncMock

import pytest
from application_factory import create_app
from core.constants import BEARER_TOKEN_TYPE
from dependencies.auth import get_auth_user_by_access_token
from fastapi import FastAPI
from fastapi.testclient import TestClient
from schemas.file import FileResponse
from schemas.tag import TagResponse, TagResponseList
from schemas.token import TokenInfo
from schemas.user import UserFullResponse, UserResponse
from services.auth import AuthService
from services.file_uploader import FileUploader
from services.tag import TagService
from services.user import UserService


@pytest.fixture(scope="session")
def application() -> FastAPI:
application = create_app()
return application


@pytest.fixture(scope="session")
def client(application: FastAPI) -> TestClient:
return TestClient(application)


@pytest.fixture(scope="function")
def auth_client(application: FastAPI) -> Generator[TestClient]:
user_id = 1
application.dependency_overrides[get_auth_user_by_access_token] = lambda: user_id
yield TestClient(application)
application.dependency_overrides.pop(get_auth_user_by_access_token)


@pytest.fixture(scope="session")
def file_uploader() -> FileUploader:
file_uploader = AsyncMock()
file_response = FileResponse(
id=1,
name="test_name",
size=1000,
)
file_uploader.upload = AsyncMock(
return_value=file_response,
)
return file_uploader


@pytest.fixture(scope="session")
def auth_service() -> AuthService:
auth_service = AsyncMock()
register_token = TokenInfo(
access_token="access_token",
refresh_token="refresh_token",
token_type=BEARER_TOKEN_TYPE,
)
login_token = TokenInfo(
access_token="login_access_token",
refresh_token="login_refresh_token",
token_type=BEARER_TOKEN_TYPE,
)
refresh_access_token_response = TokenInfo(
access_token="access_token",
token_type=BEARER_TOKEN_TYPE,
)

auth_service.register = AsyncMock(
return_value=register_token,
)
auth_service.authenticate_user = AsyncMock(
return_value=login_token,
)
auth_service.refresh_access_token = AsyncMock(
return_value=refresh_access_token_response,
)
return auth_service


@pytest.fixture(scope="session")
def user_service() -> UserService:
user_service = AsyncMock()
user_full_response = UserFullResponse(
id=1,
registration_date=datetime(
year=2025,
month=1,
day=1,
hour=0,
minute=0,
second=0,
),
surname="surname",
name="name",
username="username",
email="email@email.com",
)
user_response = UserResponse(
id=1,
registration_date=datetime(
year=2025,
month=1,
day=1,
hour=0,
minute=0,
second=0,
),
surname="surname",
name="name",
username="username",
)
user_service.get_profile_by_id = AsyncMock(return_value=user_full_response)
user_service.update_user = AsyncMock(return_value=user_response)
user_service.delete_by_id = AsyncMock(return_value=None)
user_service.get_by_id = AsyncMock(return_value=user_response)
return user_service


@pytest.fixture(scope="function")
def tag_service() -> TagService:
tag_service = AsyncMock()
tag_response = TagResponse(
id=1,
project_id=1,
name="tag_name",
)
tag_response_list = TagResponseList(tag_list=[tag_response])
tag_service.create_tag = AsyncMock(return_value=tag_response)
tag_service.delete_by_id = AsyncMock(return_value=None)
tag_service.get_project_tags = AsyncMock(return_value=tag_response_list)
return tag_service
Empty file.
Loading
Loading