architectonics 0.0.12__tar.gz → 0.0.14__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {architectonics-0.0.12 → architectonics-0.0.14}/PKG-INFO +1 -1
- architectonics-0.0.14/architectonics/common/consts/roles_dict.py +7 -0
- architectonics-0.0.14/architectonics/common/consts/super_admin_user.py +8 -0
- architectonics-0.0.12/architectonics/models/abstract_base_model.py → architectonics-0.0.14/architectonics/common/entities/base_entity.py +3 -2
- architectonics-0.0.14/architectonics/common/enums/step_types.py +6 -0
- architectonics-0.0.14/architectonics/common/interfaces/base_entity_interface.py +19 -0
- architectonics-0.0.14/architectonics/common/interfaces/base_model_interface.py +17 -0
- architectonics-0.0.14/architectonics/common/interfaces/user_context_interface.py +13 -0
- architectonics-0.0.14/architectonics/common/models/base_model.py +22 -0
- architectonics-0.0.14/architectonics/common/models/error_message.py +6 -0
- architectonics-0.0.12/architectonics/config/base_database_settings.py → architectonics-0.0.14/architectonics/core/config/application_settings.py +2 -2
- {architectonics-0.0.12/architectonics → architectonics-0.0.14/architectonics/core/factory}/factory.py +2 -2
- architectonics-0.0.14/architectonics/infrastructure/config/database_settings.py +23 -0
- {architectonics-0.0.12 → architectonics-0.0.14}/pyproject.toml +1 -1
- {architectonics-0.0.12 → architectonics-0.0.14}/setup.py +12 -7
- architectonics-0.0.12/architectonics/config/database.py +0 -16
- architectonics-0.0.12/architectonics/repositories/exceptions.py +0 -18
- architectonics-0.0.12/architectonics/repositories/repository.py +0 -151
- architectonics-0.0.12/architectonics/schemas/response_schemas.py +0 -21
- architectonics-0.0.12/architectonics/services/exceptions.py +0 -0
- architectonics-0.0.12/architectonics/services/schemas.py +0 -21
- architectonics-0.0.12/architectonics/services/service.py +0 -147
- architectonics-0.0.12/architectonics/services/types.py +0 -4
- architectonics-0.0.12/architectonics/services/user_auth_service.py +0 -52
- architectonics-0.0.12/architectonics/utils.py +0 -5
- architectonics-0.0.12/architectonics/views/ping.py +0 -11
- {architectonics-0.0.12/architectonics → architectonics-0.0.14/architectonics/core}/__init__.py +0 -0
- {architectonics-0.0.12/architectonics → architectonics-0.0.14/architectonics/core}/config/__init__.py +0 -0
- {architectonics-0.0.12/architectonics/models → architectonics-0.0.14/architectonics/core/factory}/__init__.py +0 -0
- {architectonics-0.0.12/architectonics → architectonics-0.0.14/architectonics/core}/repositories/__init__.py +0 -0
- {architectonics-0.0.12/architectonics/services → architectonics-0.0.14/architectonics/infrastructure}/__init__.py +0 -0
- {architectonics-0.0.12/architectonics/views → architectonics-0.0.14/architectonics/infrastructure/config}/__init__.py +0 -0
|
@@ -3,11 +3,12 @@ import uuid
|
|
|
3
3
|
from sqlalchemy import Column, DateTime, String
|
|
4
4
|
from sqlalchemy.orm import as_declarative
|
|
5
5
|
|
|
6
|
-
from architectonics.
|
|
6
|
+
from architectonics.common.interfaces.base_entity_interface import BaseEntityInterface
|
|
7
|
+
from architectonics_old.utils import get_current_datetime
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
@as_declarative()
|
|
10
|
-
class
|
|
11
|
+
class BaseEntity(BaseEntityInterface):
|
|
11
12
|
__abstract__ = True
|
|
12
13
|
|
|
13
14
|
id = Column(
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from typing import ClassVar
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class BaseEntityInterface(ABC):
|
|
7
|
+
PK_FIELD: ClassVar[str]
|
|
8
|
+
|
|
9
|
+
@property
|
|
10
|
+
@abstractmethod
|
|
11
|
+
def id(self) -> str: ...
|
|
12
|
+
|
|
13
|
+
@property
|
|
14
|
+
@abstractmethod
|
|
15
|
+
def created_at(self) -> datetime: ...
|
|
16
|
+
|
|
17
|
+
@property
|
|
18
|
+
@abstractmethod
|
|
19
|
+
def updated_at(self) -> datetime: ...
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class BaseModelInterface(ABC):
|
|
6
|
+
|
|
7
|
+
@property
|
|
8
|
+
@abstractmethod
|
|
9
|
+
def id(self) -> str: ...
|
|
10
|
+
|
|
11
|
+
@property
|
|
12
|
+
@abstractmethod
|
|
13
|
+
def created_at(self) -> datetime: ...
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
@abstractmethod
|
|
17
|
+
def updated_at(self) -> datetime: ...
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
import uuid
|
|
4
|
+
|
|
5
|
+
from architectonics.common.interfaces.base_model_interface import BaseModelInterface
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class BaseModel(BaseModelInterface):
|
|
10
|
+
id: str = field(
|
|
11
|
+
default_factory=lambda: str(
|
|
12
|
+
uuid.uuid4(),
|
|
13
|
+
),
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
created_at: datetime = field(
|
|
17
|
+
default_factory=datetime.utcnow,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
updated_at: datetime = field(
|
|
21
|
+
default_factory=datetime.utcnow,
|
|
22
|
+
)
|
|
@@ -6,7 +6,7 @@ from pydantic import BaseModel
|
|
|
6
6
|
load_dotenv()
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
class
|
|
9
|
+
class ApplicationSettings(BaseModel):
|
|
10
10
|
DEBUG: bool = os.getenv("DEBUG", "False").lower() == "true"
|
|
11
11
|
|
|
12
12
|
DATABASE_PREFIX: str = "postgresql+asyncpg"
|
|
@@ -22,4 +22,4 @@ class BaseDatabaseSettings(BaseModel):
|
|
|
22
22
|
)
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
application_settings = ApplicationSettings()
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
from fastapi import FastAPI
|
|
2
2
|
from fastapi.middleware.cors import CORSMiddleware
|
|
3
3
|
|
|
4
|
-
from architectonics.config.
|
|
4
|
+
from architectonics.core.config.application_settings import application_settings
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class BaseAppFactory:
|
|
8
8
|
@classmethod
|
|
9
9
|
def create(cls, title) -> FastAPI:
|
|
10
10
|
app = FastAPI(
|
|
11
|
-
debug=
|
|
11
|
+
debug=application_settings.DEBUG,
|
|
12
12
|
title=title,
|
|
13
13
|
docs_url="/docs/",
|
|
14
14
|
)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
from dotenv import load_dotenv
|
|
4
|
+
from pydantic import BaseModel
|
|
5
|
+
|
|
6
|
+
load_dotenv()
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class DatabaseSettings(BaseModel):
|
|
10
|
+
DATABASE_PREFIX: str = "postgresql+asyncpg"
|
|
11
|
+
|
|
12
|
+
POSTGRES_USER: str = os.getenv("POSTGRES_USER")
|
|
13
|
+
POSTGRES_PASSWORD: str = os.getenv("POSTGRES_PASSWORD")
|
|
14
|
+
POSTGRES_HOST: str = os.getenv("POSTGRES_HOST")
|
|
15
|
+
POSTGRES_PORT: int = os.getenv("POSTGRES_PORT")
|
|
16
|
+
POSTGRES_DATABASE_NAME: str = os.getenv("POSTGRES_DATABASE_NAME")
|
|
17
|
+
|
|
18
|
+
DATABASE_CONNECTION_STRING: str = (
|
|
19
|
+
f"{DATABASE_PREFIX}://{POSTGRES_USER}:" f"{POSTGRES_PASSWORD}@{POSTGRES_HOST}:{POSTGRES_PORT}/{POSTGRES_DATABASE_NAME}"
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
database_settings = DatabaseSettings()
|
|
@@ -3,12 +3,17 @@ from setuptools import setup
|
|
|
3
3
|
|
|
4
4
|
packages = \
|
|
5
5
|
['architectonics',
|
|
6
|
-
'architectonics.
|
|
7
|
-
'architectonics.
|
|
8
|
-
'architectonics.
|
|
9
|
-
'architectonics.
|
|
10
|
-
'architectonics.
|
|
11
|
-
'architectonics.
|
|
6
|
+
'architectonics.common.consts',
|
|
7
|
+
'architectonics.common.entities',
|
|
8
|
+
'architectonics.common.enums',
|
|
9
|
+
'architectonics.common.interfaces',
|
|
10
|
+
'architectonics.common.models',
|
|
11
|
+
'architectonics.core',
|
|
12
|
+
'architectonics.core.config',
|
|
13
|
+
'architectonics.core.factory',
|
|
14
|
+
'architectonics.core.repositories',
|
|
15
|
+
'architectonics.infrastructure',
|
|
16
|
+
'architectonics.infrastructure.config']
|
|
12
17
|
|
|
13
18
|
package_data = \
|
|
14
19
|
{'': ['*']}
|
|
@@ -25,7 +30,7 @@ install_requires = \
|
|
|
25
30
|
|
|
26
31
|
setup_kwargs = {
|
|
27
32
|
'name': 'architectonics',
|
|
28
|
-
'version': '0.0.
|
|
33
|
+
'version': '0.0.14',
|
|
29
34
|
'description': '',
|
|
30
35
|
'long_description': None,
|
|
31
36
|
'author': 'Your Name',
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
|
|
2
|
-
from sqlalchemy.orm import sessionmaker
|
|
3
|
-
|
|
4
|
-
from architectonics.config.base_database_settings import base_database_settings
|
|
5
|
-
|
|
6
|
-
engine = create_async_engine(
|
|
7
|
-
base_database_settings.DATABASE_CONNECTION_STRING,
|
|
8
|
-
future=True,
|
|
9
|
-
echo=base_database_settings.DEBUG,
|
|
10
|
-
)
|
|
11
|
-
|
|
12
|
-
session = sessionmaker(
|
|
13
|
-
bind=engine,
|
|
14
|
-
class_=AsyncSession,
|
|
15
|
-
expire_on_commit=False,
|
|
16
|
-
)
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
class RepositoryException(Exception):
|
|
2
|
-
"""Base class for all repository exceptions."""
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class ObjectNotFoundRepositoryException(RepositoryException):
|
|
6
|
-
"""Exception raised when can't find a row."""
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class ForeignKeyViolationRepositoryException(RepositoryException):
|
|
10
|
-
"""Exception raised when foreign key constraint fails."""
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class ObjectAlreadyExistsRepositoryException(RepositoryException):
|
|
14
|
-
"""Exception raised when unique constraint failes."""
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class IntegrityErrorRepositoryException(RepositoryException):
|
|
18
|
-
"""Exception raised when integrity constraint fails."""
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
from abc import ABC
|
|
2
|
-
from typing import Callable
|
|
3
|
-
|
|
4
|
-
from asyncpg.exceptions import ForeignKeyViolationError
|
|
5
|
-
from sqlalchemy import delete, select, update
|
|
6
|
-
from sqlalchemy.exc import IntegrityError
|
|
7
|
-
from sqlalchemy.ext.asyncio import AsyncSession
|
|
8
|
-
|
|
9
|
-
from architectonics.config.database import session
|
|
10
|
-
from architectonics.models.abstract_base_model import AbstractBaseModel
|
|
11
|
-
from architectonics.repositories.exceptions import (
|
|
12
|
-
ForeignKeyViolationRepositoryException,
|
|
13
|
-
IntegrityErrorRepositoryException,
|
|
14
|
-
ObjectAlreadyExistsRepositoryException,
|
|
15
|
-
ObjectNotFoundRepositoryException,
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class AbstractBaseRepository(ABC):
|
|
20
|
-
_model: type[AbstractBaseModel] = NotImplemented
|
|
21
|
-
_session: Callable = session
|
|
22
|
-
_integrity_error: type[IntegrityError] = IntegrityError
|
|
23
|
-
|
|
24
|
-
def get_session(self) -> AsyncSession:
|
|
25
|
-
return self._session()
|
|
26
|
-
|
|
27
|
-
@property
|
|
28
|
-
def model_fields(self):
|
|
29
|
-
return self._model.__table__.columns
|
|
30
|
-
|
|
31
|
-
async def create_model(
|
|
32
|
-
self,
|
|
33
|
-
values: dict[str, any],
|
|
34
|
-
) -> AbstractBaseModel:
|
|
35
|
-
|
|
36
|
-
model = self._model(
|
|
37
|
-
**values,
|
|
38
|
-
)
|
|
39
|
-
|
|
40
|
-
async with self.get_session() as session:
|
|
41
|
-
|
|
42
|
-
session.add(model)
|
|
43
|
-
|
|
44
|
-
try:
|
|
45
|
-
await session.commit()
|
|
46
|
-
except self._integrity_error as e:
|
|
47
|
-
raise ObjectAlreadyExistsRepositoryException(e)
|
|
48
|
-
|
|
49
|
-
return model
|
|
50
|
-
|
|
51
|
-
async def get_model(
|
|
52
|
-
self,
|
|
53
|
-
model_id: str,
|
|
54
|
-
) -> AbstractBaseModel:
|
|
55
|
-
|
|
56
|
-
statement = select(
|
|
57
|
-
self._model,
|
|
58
|
-
).where(
|
|
59
|
-
self._model.id == model_id,
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
async with self.get_session() as session:
|
|
63
|
-
|
|
64
|
-
result = await session.execute(
|
|
65
|
-
statement=statement,
|
|
66
|
-
)
|
|
67
|
-
|
|
68
|
-
model = result.scalars().first()
|
|
69
|
-
|
|
70
|
-
if model is None:
|
|
71
|
-
raise ObjectNotFoundRepositoryException()
|
|
72
|
-
|
|
73
|
-
return model
|
|
74
|
-
|
|
75
|
-
async def update_model(
|
|
76
|
-
self,
|
|
77
|
-
model_id: str,
|
|
78
|
-
values: dict[str, any],
|
|
79
|
-
) -> AbstractBaseModel:
|
|
80
|
-
|
|
81
|
-
filtered_values = {k: v for k, v in values.items() if v is not None}
|
|
82
|
-
|
|
83
|
-
statement = (
|
|
84
|
-
update(
|
|
85
|
-
self._model,
|
|
86
|
-
)
|
|
87
|
-
.where(
|
|
88
|
-
self._model.id == model_id,
|
|
89
|
-
)
|
|
90
|
-
.values(
|
|
91
|
-
**filtered_values,
|
|
92
|
-
)
|
|
93
|
-
.returning(
|
|
94
|
-
self._model,
|
|
95
|
-
)
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
async with self.get_session() as session:
|
|
99
|
-
try:
|
|
100
|
-
result = await session.execute(
|
|
101
|
-
statement=statement,
|
|
102
|
-
)
|
|
103
|
-
await session.commit()
|
|
104
|
-
except self._integrity_error as e:
|
|
105
|
-
|
|
106
|
-
orig = getattr(e.orig, "__cause__", None)
|
|
107
|
-
|
|
108
|
-
if isinstance(orig, ForeignKeyViolationError):
|
|
109
|
-
raise ForeignKeyViolationRepositoryException()
|
|
110
|
-
|
|
111
|
-
raise IntegrityErrorRepositoryException(e)
|
|
112
|
-
|
|
113
|
-
model = result.scalars().first()
|
|
114
|
-
|
|
115
|
-
if model is None:
|
|
116
|
-
raise ObjectNotFoundRepositoryException()
|
|
117
|
-
|
|
118
|
-
return model
|
|
119
|
-
|
|
120
|
-
async def delete_model(
|
|
121
|
-
self,
|
|
122
|
-
model_id: str,
|
|
123
|
-
) -> None:
|
|
124
|
-
|
|
125
|
-
statement = delete(
|
|
126
|
-
self._model,
|
|
127
|
-
).where(
|
|
128
|
-
self._model.id == model_id,
|
|
129
|
-
)
|
|
130
|
-
|
|
131
|
-
async with self.get_session() as session:
|
|
132
|
-
await session.execute(statement)
|
|
133
|
-
await session.commit()
|
|
134
|
-
|
|
135
|
-
async def get_models_list(
|
|
136
|
-
self,
|
|
137
|
-
) -> list[AbstractBaseModel]:
|
|
138
|
-
|
|
139
|
-
statement = select(
|
|
140
|
-
self._model,
|
|
141
|
-
)
|
|
142
|
-
|
|
143
|
-
async with self.get_session() as session:
|
|
144
|
-
|
|
145
|
-
result = await session.execute(
|
|
146
|
-
statement=statement,
|
|
147
|
-
)
|
|
148
|
-
|
|
149
|
-
models = result.scalars().all()
|
|
150
|
-
|
|
151
|
-
return models
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
from pydantic import BaseModel, Field
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
class ObjectNotFoundResponseSchema(BaseModel):
|
|
5
|
-
detail: str = Field()
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class ObjectAlreadyExistsResponseSchema(BaseModel):
|
|
9
|
-
detail: str = Field()
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class ObjectDeletedResponseSchema(BaseModel):
|
|
13
|
-
detail: str = Field()
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class NotImplementedResponseSchema(BaseModel):
|
|
17
|
-
detail: str = Field()
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class UnauthorizedResponseSchema(BaseModel):
|
|
21
|
-
detail: str = Field()
|
|
File without changes
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
from pydantic import BaseModel
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
class AbstractModelCreateSchema(BaseModel):
|
|
5
|
-
pass
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class AbstractModelCreateErrorsSchema(BaseModel):
|
|
9
|
-
pass
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class AbstractModelGetSchema(BaseModel):
|
|
13
|
-
pass
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class AbstractModelUpdateSchema(BaseModel):
|
|
17
|
-
pass
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class AbstractModelUpdateErrorsSchema(BaseModel):
|
|
21
|
-
pass
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
from starlette.status import HTTP_200_OK, HTTP_204_NO_CONTENT, HTTP_404_NOT_FOUND, HTTP_409_CONFLICT, HTTP_422_UNPROCESSABLE_ENTITY
|
|
2
|
-
|
|
3
|
-
from architectonics.models.abstract_base_model import AbstractBaseModel
|
|
4
|
-
from architectonics.repositories.exceptions import (
|
|
5
|
-
ForeignKeyViolationRepositoryException,
|
|
6
|
-
IntegrityErrorRepositoryException,
|
|
7
|
-
ObjectAlreadyExistsRepositoryException,
|
|
8
|
-
ObjectNotFoundRepositoryException,
|
|
9
|
-
)
|
|
10
|
-
from architectonics.repositories.repository import AbstractBaseRepository
|
|
11
|
-
from architectonics.services.schemas import (
|
|
12
|
-
AbstractModelCreateSchema,
|
|
13
|
-
AbstractModelUpdateSchema,
|
|
14
|
-
)
|
|
15
|
-
from architectonics.services.types import ErrorsType, StatusCodeType
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class AbstractBaseService:
|
|
19
|
-
_repository: AbstractBaseRepository = NotImplemented
|
|
20
|
-
|
|
21
|
-
async def validate(self, **kwargs) -> dict[str, any]:
|
|
22
|
-
|
|
23
|
-
if not kwargs:
|
|
24
|
-
return {}
|
|
25
|
-
|
|
26
|
-
attrs = {field: value for field, value in kwargs.items() if field in self._repository.model_fields}
|
|
27
|
-
|
|
28
|
-
return attrs
|
|
29
|
-
|
|
30
|
-
async def _validate_values(self, **kwargs) -> tuple[dict[str, any], dict[str, list[str]]]:
|
|
31
|
-
|
|
32
|
-
errors = {}
|
|
33
|
-
|
|
34
|
-
for key, value in kwargs.items():
|
|
35
|
-
validation_method = f"validate_{key}"
|
|
36
|
-
|
|
37
|
-
if hasattr(self, validation_method):
|
|
38
|
-
result, error = getattr(
|
|
39
|
-
self,
|
|
40
|
-
validation_method,
|
|
41
|
-
)(
|
|
42
|
-
value,
|
|
43
|
-
kwargs,
|
|
44
|
-
)
|
|
45
|
-
|
|
46
|
-
if not result:
|
|
47
|
-
errors[key] = errors.get(key, []) + error
|
|
48
|
-
|
|
49
|
-
attrs = await self.validate(
|
|
50
|
-
**kwargs,
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
return attrs, errors
|
|
54
|
-
|
|
55
|
-
async def create_model(
|
|
56
|
-
self,
|
|
57
|
-
create_schema: AbstractModelCreateSchema,
|
|
58
|
-
) -> tuple[AbstractBaseModel | None, ErrorsType, StatusCodeType]:
|
|
59
|
-
|
|
60
|
-
schema_dict = create_schema.model_dump()
|
|
61
|
-
|
|
62
|
-
attrs, errors = await self._validate_values(
|
|
63
|
-
**schema_dict,
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
if errors:
|
|
67
|
-
return None, errors, HTTP_422_UNPROCESSABLE_ENTITY
|
|
68
|
-
|
|
69
|
-
try:
|
|
70
|
-
model = await self._repository.create_model(
|
|
71
|
-
values=attrs,
|
|
72
|
-
)
|
|
73
|
-
except ObjectAlreadyExistsRepositoryException:
|
|
74
|
-
return None, "object_already_exist", HTTP_409_CONFLICT
|
|
75
|
-
|
|
76
|
-
return model, None, HTTP_200_OK
|
|
77
|
-
|
|
78
|
-
async def get_model(
|
|
79
|
-
self,
|
|
80
|
-
model_id: str,
|
|
81
|
-
) -> tuple[AbstractBaseModel | None, ErrorsType, StatusCodeType]:
|
|
82
|
-
|
|
83
|
-
try:
|
|
84
|
-
model = await self._repository.get_model(
|
|
85
|
-
model_id=model_id,
|
|
86
|
-
)
|
|
87
|
-
except ObjectNotFoundRepositoryException:
|
|
88
|
-
return None, "object_not_found", HTTP_404_NOT_FOUND
|
|
89
|
-
|
|
90
|
-
return model, None, HTTP_200_OK
|
|
91
|
-
|
|
92
|
-
async def update_model(
|
|
93
|
-
self,
|
|
94
|
-
model_id: str,
|
|
95
|
-
update_schema: AbstractModelUpdateSchema,
|
|
96
|
-
) -> tuple[AbstractBaseModel | None, ErrorsType, StatusCodeType]:
|
|
97
|
-
|
|
98
|
-
schema_dict = update_schema.model_dump(
|
|
99
|
-
by_alias=False,
|
|
100
|
-
)
|
|
101
|
-
|
|
102
|
-
attrs, errors = await self._validate_values(
|
|
103
|
-
**schema_dict,
|
|
104
|
-
)
|
|
105
|
-
|
|
106
|
-
if errors:
|
|
107
|
-
return None, errors, HTTP_422_UNPROCESSABLE_ENTITY
|
|
108
|
-
|
|
109
|
-
try:
|
|
110
|
-
model = await self._repository.update_model(
|
|
111
|
-
model_id=model_id,
|
|
112
|
-
values=attrs,
|
|
113
|
-
)
|
|
114
|
-
except ForeignKeyViolationRepositoryException as e:
|
|
115
|
-
return None, f"{e}", HTTP_422_UNPROCESSABLE_ENTITY
|
|
116
|
-
except IntegrityErrorRepositoryException as e:
|
|
117
|
-
return None, f"{e}", HTTP_404_NOT_FOUND
|
|
118
|
-
except ObjectNotFoundRepositoryException:
|
|
119
|
-
return None, "object_not_found", HTTP_404_NOT_FOUND
|
|
120
|
-
|
|
121
|
-
return model, None, HTTP_200_OK
|
|
122
|
-
|
|
123
|
-
async def delete_model(
|
|
124
|
-
self,
|
|
125
|
-
model_id: str,
|
|
126
|
-
) -> tuple[None, ErrorsType, StatusCodeType]:
|
|
127
|
-
|
|
128
|
-
_, errors, status_code = await self.get_model(
|
|
129
|
-
model_id=model_id,
|
|
130
|
-
)
|
|
131
|
-
|
|
132
|
-
if errors:
|
|
133
|
-
return None, errors, status_code
|
|
134
|
-
|
|
135
|
-
await self._repository.delete_model(
|
|
136
|
-
model_id=model_id,
|
|
137
|
-
)
|
|
138
|
-
|
|
139
|
-
return None, None, HTTP_204_NO_CONTENT
|
|
140
|
-
|
|
141
|
-
async def get_models_list(
|
|
142
|
-
self,
|
|
143
|
-
) -> tuple[list[AbstractBaseModel], ErrorsType, StatusCodeType]:
|
|
144
|
-
|
|
145
|
-
models = await self._repository.get_models_list()
|
|
146
|
-
|
|
147
|
-
return models, None, HTTP_200_OK
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
from uuid import UUID
|
|
2
|
-
|
|
3
|
-
from fastapi import Depends, Header, HTTPException
|
|
4
|
-
from starlette import status
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def get_user_id(
|
|
8
|
-
x_user_id: str = Header(
|
|
9
|
-
alias="X-User-Id",
|
|
10
|
-
description="Идентификатор пользователя",
|
|
11
|
-
),
|
|
12
|
-
) -> str:
|
|
13
|
-
if not x_user_id:
|
|
14
|
-
raise HTTPException(
|
|
15
|
-
status_code=status.HTTP_400_BAD_REQUEST,
|
|
16
|
-
detail="X-User-Id header is required",
|
|
17
|
-
)
|
|
18
|
-
|
|
19
|
-
try:
|
|
20
|
-
_ = UUID(x_user_id, version=4) # version=4 для проверки UUID v4
|
|
21
|
-
except ValueError:
|
|
22
|
-
raise HTTPException(
|
|
23
|
-
status_code=status.HTTP_400_BAD_REQUEST,
|
|
24
|
-
detail="not_valid_uuid",
|
|
25
|
-
)
|
|
26
|
-
|
|
27
|
-
return x_user_id
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def get_user_roles(
|
|
31
|
-
x_user_roles: str = Header(
|
|
32
|
-
alias="X-User-Roles",
|
|
33
|
-
description="Роли пользователя",
|
|
34
|
-
),
|
|
35
|
-
) -> str:
|
|
36
|
-
if not x_user_roles:
|
|
37
|
-
raise HTTPException(
|
|
38
|
-
status_code=status.HTTP_400_BAD_REQUEST,
|
|
39
|
-
detail="X-User-Roles header is required",
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
return x_user_roles.split(",")
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
class UserAuthService:
|
|
46
|
-
def __init__(
|
|
47
|
-
self,
|
|
48
|
-
user_id: str = Depends(get_user_id),
|
|
49
|
-
user_roles: list[str] = Depends(get_user_roles),
|
|
50
|
-
):
|
|
51
|
-
self.user_id = user_id
|
|
52
|
-
self.user_roles = user_roles
|
{architectonics-0.0.12/architectonics → architectonics-0.0.14/architectonics/core}/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|