feat: add workspace
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
__all__ = (
|
||||
'User',
|
||||
'Workspace',
|
||||
'WorkspaceUser',
|
||||
'TargetChannel',
|
||||
'ExternalChannel',
|
||||
'Creative',
|
||||
@@ -17,6 +19,8 @@ __all__ = (
|
||||
'PostViewsAvailability',
|
||||
'LoginToken',
|
||||
'UserNotFound',
|
||||
'WorkspaceNotFound',
|
||||
'WorkspaceAccessDenied',
|
||||
'LoginTokenNotFound',
|
||||
'LoginTokenExpired',
|
||||
'LoginTokenAlreadyUsed',
|
||||
@@ -44,6 +48,8 @@ from .error import (
|
||||
PlacementNotFound,
|
||||
TargetChannelNotFound,
|
||||
UserNotFound,
|
||||
WorkspaceAccessDenied,
|
||||
WorkspaceNotFound,
|
||||
)
|
||||
from .external_channel import ExternalChannel
|
||||
from .login_token import LoginToken
|
||||
@@ -54,3 +60,4 @@ from .subscription import Subscription, SubscriptionStatus
|
||||
from .target_channel import TargetChannel, TargetChannelStatus
|
||||
from .telegram_state import TelegramState, TelegramStateEnum
|
||||
from .user import User
|
||||
from .workspace import Workspace, WorkspaceUser
|
||||
|
||||
@@ -8,7 +8,7 @@ from .base import TimestampedModel
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .target_channel import TargetChannel
|
||||
from .user import User
|
||||
from .workspace import Workspace
|
||||
|
||||
|
||||
class CreativeStatus(str, enum.Enum):
|
||||
@@ -23,15 +23,15 @@ class Creative(TimestampedModel):
|
||||
status = fields.CharEnumField(CreativeStatus, default=CreativeStatus.ACTIVE)
|
||||
placements_count = fields.IntField(default=0)
|
||||
|
||||
user: fields.ForeignKeyRelation['User'] = fields.ForeignKeyField(
|
||||
'models.User', related_name='creatives', on_delete=fields.CASCADE, index=True
|
||||
workspace: fields.ForeignKeyRelation['Workspace'] = fields.ForeignKeyField(
|
||||
'models.Workspace', related_name='creatives', on_delete=fields.CASCADE, index=True
|
||||
)
|
||||
target_channel: fields.ForeignKeyRelation['TargetChannel'] = fields.ForeignKeyField(
|
||||
'models.TargetChannel', related_name='creatives', on_delete=fields.CASCADE, index=True
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
user_id: UUID
|
||||
workspace_id: UUID
|
||||
target_channel_id: UUID
|
||||
|
||||
class Meta:
|
||||
|
||||
@@ -64,3 +64,15 @@ def PlacementNotFound(placement_id: uuid.UUID | None = None) -> HTTPException:
|
||||
if placement_id is None:
|
||||
return HTTPException(status.HTTP_404_NOT_FOUND, 'Placement not found')
|
||||
return HTTPException(status.HTTP_404_NOT_FOUND, f'Placement {placement_id} not found')
|
||||
|
||||
|
||||
def WorkspaceNotFound(workspace_id: uuid.UUID | None = None) -> HTTPException:
|
||||
if workspace_id is None:
|
||||
return HTTPException(status.HTTP_404_NOT_FOUND, 'Workspace not found')
|
||||
return HTTPException(status.HTTP_404_NOT_FOUND, f'Workspace {workspace_id} not found')
|
||||
|
||||
|
||||
def WorkspaceAccessDenied(workspace_id: uuid.UUID | None = None) -> HTTPException:
|
||||
if workspace_id is None:
|
||||
return HTTPException(status.HTTP_403_FORBIDDEN, 'Workspace access denied')
|
||||
return HTTPException(status.HTTP_403_FORBIDDEN, f'Workspace {workspace_id} access denied')
|
||||
|
||||
@@ -7,7 +7,7 @@ from .base import TimestampedModel
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .target_channel import TargetChannel
|
||||
from .user import User
|
||||
from .workspace import Workspace
|
||||
|
||||
|
||||
class ExternalChannel(TimestampedModel):
|
||||
@@ -18,14 +18,13 @@ class ExternalChannel(TimestampedModel):
|
||||
description = fields.TextField(null=True)
|
||||
subscribers_count = fields.IntField(null=True)
|
||||
|
||||
user: fields.ForeignKeyRelation['User'] = fields.ForeignKeyField(
|
||||
'models.User', related_name='external_channels', on_delete=fields.CASCADE, index=True
|
||||
workspace: fields.ForeignKeyRelation['Workspace'] = fields.ForeignKeyField(
|
||||
'models.Workspace', related_name='external_channels', on_delete=fields.CASCADE, index=True
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
target_channels: fields.ManyToManyRelation['TargetChannel']
|
||||
user_id: UUID
|
||||
workspace_id: UUID
|
||||
|
||||
class Meta:
|
||||
table = 'external_channel'
|
||||
unique_together = (('user_id', 'telegram_id'),)
|
||||
|
||||
@@ -10,7 +10,7 @@ if TYPE_CHECKING:
|
||||
from .creative import Creative
|
||||
from .external_channel import ExternalChannel
|
||||
from .target_channel import TargetChannel
|
||||
from .user import User
|
||||
from .workspace import Workspace
|
||||
|
||||
|
||||
class PlacementStatus(str, enum.Enum):
|
||||
@@ -59,15 +59,15 @@ class Placement(TimestampedModel):
|
||||
creative: fields.ForeignKeyRelation['Creative'] = fields.ForeignKeyField(
|
||||
'models.Creative', related_name='placements', on_delete=fields.CASCADE, index=True
|
||||
)
|
||||
user: fields.ForeignKeyRelation['User'] = fields.ForeignKeyField(
|
||||
'models.User', related_name='placements', on_delete=fields.CASCADE, index=True
|
||||
workspace: fields.ForeignKeyRelation['Workspace'] = fields.ForeignKeyField(
|
||||
'models.Workspace', related_name='placements', on_delete=fields.CASCADE, index=True
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
target_channel_id: UUID
|
||||
external_channel_id: UUID
|
||||
creative_id: UUID
|
||||
user_id: UUID
|
||||
workspace_id: UUID
|
||||
|
||||
class Meta:
|
||||
table = 'placement'
|
||||
|
||||
@@ -8,7 +8,7 @@ from .base import TimestampedModel
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .external_channel import ExternalChannel
|
||||
from .user import User
|
||||
from .workspace import Workspace
|
||||
|
||||
|
||||
class TargetChannelStatus(str, enum.Enum):
|
||||
@@ -24,8 +24,8 @@ class TargetChannel(TimestampedModel):
|
||||
username = fields.CharField(max_length=255, null=True, index=True)
|
||||
status = fields.CharEnumField(TargetChannelStatus, default=TargetChannelStatus.ACTIVE)
|
||||
|
||||
user: fields.ForeignKeyRelation['User'] = fields.ForeignKeyField(
|
||||
'models.User', related_name='target_channels', on_delete=fields.CASCADE, index=True
|
||||
workspace: fields.ForeignKeyRelation['Workspace'] = fields.ForeignKeyField(
|
||||
'models.Workspace', related_name='target_channels', on_delete=fields.CASCADE, index=True
|
||||
)
|
||||
|
||||
external_channels: fields.ManyToManyRelation['ExternalChannel'] = fields.ManyToManyField(
|
||||
@@ -37,7 +37,7 @@ class TargetChannel(TimestampedModel):
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
user_id: UUID
|
||||
workspace_id: UUID
|
||||
|
||||
class Meta:
|
||||
table = 'target_channel'
|
||||
|
||||
38
src/domain/workspace.py
Normal file
38
src/domain/workspace.py
Normal file
@@ -0,0 +1,38 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from tortoise import fields
|
||||
|
||||
from .base import TimestampedModel
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .user import User
|
||||
|
||||
|
||||
class Workspace(TimestampedModel):
|
||||
id = fields.UUIDField(pk=True)
|
||||
name = fields.CharField(max_length=255)
|
||||
|
||||
class Meta:
|
||||
table = 'workspace'
|
||||
|
||||
|
||||
class WorkspaceUser(TimestampedModel):
|
||||
id = fields.UUIDField(pk=True)
|
||||
|
||||
workspace: fields.ForeignKeyRelation[Workspace] = fields.ForeignKeyField(
|
||||
'models.Workspace', related_name='workspace_users', on_delete=fields.CASCADE, index=True
|
||||
)
|
||||
user: fields.ForeignKeyRelation[User] = fields.ForeignKeyField(
|
||||
'models.User', related_name='workspace_users', on_delete=fields.CASCADE, index=True
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
workspace_id: uuid.UUID
|
||||
user_id: uuid.UUID
|
||||
|
||||
class Meta:
|
||||
table = 'workspace_user'
|
||||
unique_together = (('workspace_id', 'user_id'),)
|
||||
Reference in New Issue
Block a user