feat: переименование доменной области
This commit is contained in:
@@ -2,16 +2,29 @@ __all__ = (
|
||||
'User',
|
||||
'Workspace',
|
||||
'WorkspaceUser',
|
||||
'TargetChannel',
|
||||
'ExternalChannel',
|
||||
'WorkspaceInvite',
|
||||
'WorkspaceInviteStatus',
|
||||
'WorkspaceUserStatus',
|
||||
'WorkspaceUserPermission',
|
||||
'WorkspaceUserPermissionScope',
|
||||
'PermissionKey',
|
||||
'PermissionScopeType',
|
||||
'Channel',
|
||||
'ChannelVerificationStatus',
|
||||
'Project',
|
||||
'ProjectStatus',
|
||||
'PurchasePlan',
|
||||
'PurchasePlanChannel',
|
||||
'PurchasePlanStatus',
|
||||
'PurchasePlanChannelStatus',
|
||||
'Creative',
|
||||
'Placement',
|
||||
'Subscription',
|
||||
'Subscriber',
|
||||
'PlacementViewsHistory',
|
||||
'TelegramState',
|
||||
'TelegramStateEnum',
|
||||
'TargetChannelStatus',
|
||||
'ChannelNotFound',
|
||||
'ProjectNotFound',
|
||||
'CreativeStatus',
|
||||
'PlacementStatus',
|
||||
'SubscriptionStatus',
|
||||
@@ -24,40 +37,57 @@ __all__ = (
|
||||
'LoginTokenNotFound',
|
||||
'LoginTokenExpired',
|
||||
'LoginTokenAlreadyUsed',
|
||||
'TargetChannelNotFound',
|
||||
'ProjectNotFound',
|
||||
'PurchasePlanNotFound',
|
||||
'PurchasePlanChannelNotFound',
|
||||
'ChannelNotFound',
|
||||
'ChannelAlreadyExists',
|
||||
'ChannelNoAdminRights',
|
||||
'ExternalChannelNotFound',
|
||||
'ExternalChannelAlreadyExists',
|
||||
'CreativeNotFound',
|
||||
'CreativeInUse',
|
||||
'PlacementNotFound',
|
||||
)
|
||||
|
||||
from .channel import Channel, ChannelVerificationStatus
|
||||
from .creative import Creative, CreativeStatus
|
||||
from .error import (
|
||||
ChannelAlreadyExists,
|
||||
ChannelNoAdminRights,
|
||||
ChannelNotFound,
|
||||
CreativeInUse,
|
||||
CreativeNotFound,
|
||||
ExternalChannelAlreadyExists,
|
||||
ExternalChannelNotFound,
|
||||
LoginTokenAlreadyUsed,
|
||||
LoginTokenExpired,
|
||||
LoginTokenNotFound,
|
||||
PlacementNotFound,
|
||||
TargetChannelNotFound,
|
||||
ProjectNotFound,
|
||||
PurchasePlanChannelNotFound,
|
||||
PurchasePlanNotFound,
|
||||
UserNotFound,
|
||||
WorkspaceAccessDenied,
|
||||
WorkspaceNotFound,
|
||||
)
|
||||
from .external_channel import ExternalChannel
|
||||
from .login_token import LoginToken
|
||||
from .placement import InviteLinkType, Placement, PlacementStatus, PostViewsAvailability
|
||||
from .placement_views_history import PlacementViewsHistory
|
||||
from .subscriber import Subscriber
|
||||
from .project import Project, ProjectStatus
|
||||
from .purchase_plan import (
|
||||
PurchasePlan,
|
||||
PurchasePlanChannel,
|
||||
PurchasePlanChannelStatus,
|
||||
PurchasePlanStatus,
|
||||
)
|
||||
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
|
||||
from .workspace import (
|
||||
PermissionKey,
|
||||
PermissionScopeType,
|
||||
Workspace,
|
||||
WorkspaceInvite,
|
||||
WorkspaceInviteStatus,
|
||||
WorkspaceUser,
|
||||
WorkspaceUserPermission,
|
||||
WorkspaceUserPermissionScope,
|
||||
WorkspaceUserStatus,
|
||||
)
|
||||
|
||||
34
src/domain/channel.py
Normal file
34
src/domain/channel.py
Normal file
@@ -0,0 +1,34 @@
|
||||
import enum
|
||||
import uuid
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from tortoise import fields
|
||||
|
||||
from .base import TimestampedModel
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .workspace import Workspace
|
||||
|
||||
|
||||
class ChannelVerificationStatus(str, enum.Enum):
|
||||
UNVERIFIED = 'unverified'
|
||||
VERIFIED = 'verified'
|
||||
FAILED = 'failed'
|
||||
|
||||
|
||||
class Channel(TimestampedModel):
|
||||
id = fields.UUIDField(pk=True)
|
||||
telegram_id = fields.BigIntField(null=True, unique=True, index=True)
|
||||
username = fields.CharField(max_length=255, null=True, index=True)
|
||||
title = fields.CharField(max_length=255, null=True)
|
||||
verification_status = fields.CharEnumField(ChannelVerificationStatus, default=ChannelVerificationStatus.UNVERIFIED)
|
||||
|
||||
workspace: fields.ForeignKeyRelation['Workspace'] = fields.ForeignKeyField(
|
||||
'models.Workspace', related_name='channels', on_delete=fields.CASCADE, index=True
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
workspace_id: uuid.UUID
|
||||
|
||||
class Meta:
|
||||
table = 'channel'
|
||||
@@ -7,7 +7,7 @@ from tortoise import fields
|
||||
from .base import TimestampedModel
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .target_channel import TargetChannel
|
||||
from .project import Project
|
||||
from .workspace import Workspace
|
||||
|
||||
|
||||
@@ -26,13 +26,13 @@ class Creative(TimestampedModel):
|
||||
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
|
||||
project: fields.ForeignKeyRelation['Project'] = fields.ForeignKeyField(
|
||||
'models.Project', related_name='creatives', on_delete=fields.CASCADE, index=True
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
workspace_id: UUID
|
||||
target_channel_id: UUID
|
||||
project_id: UUID
|
||||
|
||||
class Meta:
|
||||
table = 'creative'
|
||||
|
||||
@@ -21,10 +21,28 @@ def LoginTokenAlreadyUsed() -> HTTPException:
|
||||
return HTTPException(status.HTTP_400_BAD_REQUEST, 'Login token has already been used')
|
||||
|
||||
|
||||
def TargetChannelNotFound(channel_id: uuid.UUID | None = None) -> HTTPException:
|
||||
def ChannelNotFound(channel_id: uuid.UUID | None = None) -> HTTPException:
|
||||
if channel_id is None:
|
||||
return HTTPException(status.HTTP_404_NOT_FOUND, 'Target channel not found')
|
||||
return HTTPException(status.HTTP_404_NOT_FOUND, f'Target channel {channel_id} not found')
|
||||
return HTTPException(status.HTTP_404_NOT_FOUND, 'Channel not found')
|
||||
return HTTPException(status.HTTP_404_NOT_FOUND, f'Channel {channel_id} not found')
|
||||
|
||||
|
||||
def ProjectNotFound(project_id: uuid.UUID | None = None) -> HTTPException:
|
||||
if project_id is None:
|
||||
return HTTPException(status.HTTP_404_NOT_FOUND, 'Project not found')
|
||||
return HTTPException(status.HTTP_404_NOT_FOUND, f'Project {project_id} not found')
|
||||
|
||||
|
||||
def PurchasePlanNotFound(plan_id: uuid.UUID | None = None) -> HTTPException:
|
||||
if plan_id is None:
|
||||
return HTTPException(status.HTTP_404_NOT_FOUND, 'Purchase plan not found')
|
||||
return HTTPException(status.HTTP_404_NOT_FOUND, f'Purchase plan {plan_id} not found')
|
||||
|
||||
|
||||
def PurchasePlanChannelNotFound(plan_channel_id: uuid.UUID | None = None) -> HTTPException:
|
||||
if plan_channel_id is None:
|
||||
return HTTPException(status.HTTP_404_NOT_FOUND, 'Purchase plan channel not found')
|
||||
return HTTPException(status.HTTP_404_NOT_FOUND, f'Purchase plan channel {plan_channel_id} not found')
|
||||
|
||||
|
||||
def ChannelAlreadyExists(telegram_id: int) -> HTTPException:
|
||||
@@ -37,16 +55,6 @@ def ChannelNoAdminRights() -> HTTPException:
|
||||
)
|
||||
|
||||
|
||||
def ExternalChannelNotFound(channel_id: uuid.UUID | None = None) -> HTTPException:
|
||||
if channel_id is None:
|
||||
return HTTPException(status.HTTP_404_NOT_FOUND, 'External channel not found')
|
||||
return HTTPException(status.HTTP_404_NOT_FOUND, f'External channel {channel_id} not found')
|
||||
|
||||
|
||||
def ExternalChannelAlreadyExists(telegram_id: int) -> HTTPException:
|
||||
return HTTPException(status.HTTP_409_CONFLICT, f'External channel {telegram_id} already exists')
|
||||
|
||||
|
||||
def CreativeNotFound(creative_id: uuid.UUID | None = None) -> HTTPException:
|
||||
if creative_id is None:
|
||||
return HTTPException(status.HTTP_404_NOT_FOUND, 'Creative not found')
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
from typing import TYPE_CHECKING
|
||||
from uuid import UUID
|
||||
|
||||
from tortoise import fields
|
||||
|
||||
from .base import TimestampedModel
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .target_channel import TargetChannel
|
||||
from .workspace import Workspace
|
||||
|
||||
|
||||
class ExternalChannel(TimestampedModel):
|
||||
id = fields.UUIDField(pk=True)
|
||||
telegram_id = fields.BigIntField(index=True)
|
||||
title = fields.CharField(max_length=255)
|
||||
username = fields.CharField(max_length=255, null=True, index=True)
|
||||
description = fields.TextField(null=True)
|
||||
subscribers_count = fields.IntField(null=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']
|
||||
workspace_id: UUID
|
||||
|
||||
class Meta:
|
||||
table = 'external_channel'
|
||||
@@ -7,9 +7,9 @@ from tortoise import fields
|
||||
from .base import TimestampedModel
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .channel import Channel
|
||||
from .creative import Creative
|
||||
from .external_channel import ExternalChannel
|
||||
from .target_channel import TargetChannel
|
||||
from .project import Project
|
||||
from .workspace import Workspace
|
||||
|
||||
|
||||
@@ -50,11 +50,11 @@ class Placement(TimestampedModel):
|
||||
views_availability = fields.CharEnumField(PostViewsAvailability, default=PostViewsAvailability.UNKNOWN)
|
||||
last_views_fetch_at = fields.DatetimeField(null=True)
|
||||
|
||||
target_channel: fields.ForeignKeyRelation['TargetChannel'] = fields.ForeignKeyField(
|
||||
'models.TargetChannel', related_name='placements', on_delete=fields.CASCADE, index=True
|
||||
project: fields.ForeignKeyRelation['Project'] = fields.ForeignKeyField(
|
||||
'models.Project', related_name='placements', on_delete=fields.CASCADE, index=True
|
||||
)
|
||||
external_channel: fields.ForeignKeyRelation['ExternalChannel'] = fields.ForeignKeyField(
|
||||
'models.ExternalChannel', related_name='placements', on_delete=fields.CASCADE, index=True
|
||||
placement_channel: fields.ForeignKeyRelation['Channel'] = fields.ForeignKeyField(
|
||||
'models.Channel', related_name='placements', on_delete=fields.CASCADE, index=True
|
||||
)
|
||||
creative: fields.ForeignKeyRelation['Creative'] = fields.ForeignKeyField(
|
||||
'models.Creative', related_name='placements', on_delete=fields.CASCADE, index=True
|
||||
@@ -64,8 +64,8 @@ class Placement(TimestampedModel):
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
target_channel_id: UUID
|
||||
external_channel_id: UUID
|
||||
project_id: UUID
|
||||
placement_channel_id: UUID
|
||||
creative_id: UUID
|
||||
workspace_id: UUID
|
||||
|
||||
|
||||
37
src/domain/project.py
Normal file
37
src/domain/project.py
Normal file
@@ -0,0 +1,37 @@
|
||||
import enum
|
||||
from typing import TYPE_CHECKING
|
||||
from uuid import UUID
|
||||
|
||||
from tortoise import fields
|
||||
|
||||
from .base import TimestampedModel
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .channel import Channel
|
||||
from .workspace import Workspace
|
||||
|
||||
|
||||
class ProjectStatus(str, enum.Enum):
|
||||
ACTIVE = 'active'
|
||||
INACTIVE = 'inactive'
|
||||
ARCHIVED = 'archived'
|
||||
|
||||
|
||||
class Project(TimestampedModel):
|
||||
id = fields.UUIDField(pk=True)
|
||||
status = fields.CharEnumField(ProjectStatus, default=ProjectStatus.ACTIVE)
|
||||
|
||||
workspace: fields.ForeignKeyRelation['Workspace'] = fields.ForeignKeyField(
|
||||
'models.Workspace', related_name='projects', on_delete=fields.CASCADE, index=True
|
||||
)
|
||||
channel: fields.ForeignKeyRelation['Channel'] = fields.ForeignKeyField(
|
||||
'models.Channel', related_name='projects', on_delete=fields.CASCADE, index=True
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
workspace_id: UUID
|
||||
channel_id: UUID
|
||||
|
||||
class Meta:
|
||||
table = 'project'
|
||||
unique_together = (('workspace_id', 'channel_id'),)
|
||||
63
src/domain/purchase_plan.py
Normal file
63
src/domain/purchase_plan.py
Normal file
@@ -0,0 +1,63 @@
|
||||
import enum
|
||||
import uuid
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from tortoise import fields
|
||||
|
||||
from .base import TimestampedModel
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .channel import Channel
|
||||
from .project import Project
|
||||
from .workspace import Workspace
|
||||
|
||||
|
||||
class PurchasePlanStatus(str, enum.Enum):
|
||||
ACTIVE = 'active'
|
||||
ARCHIVED = 'archived'
|
||||
|
||||
|
||||
class PurchasePlanChannelStatus(str, enum.Enum):
|
||||
PLANNED = 'planned'
|
||||
APPROVED = 'approved'
|
||||
REJECTED = 'rejected'
|
||||
IN_PROGRESS = 'in_progress'
|
||||
COMPLETED = 'completed'
|
||||
|
||||
|
||||
class PurchasePlan(TimestampedModel):
|
||||
id = fields.UUIDField(pk=True)
|
||||
status = fields.CharEnumField(PurchasePlanStatus, default=PurchasePlanStatus.ACTIVE)
|
||||
|
||||
workspace: fields.ForeignKeyRelation['Workspace'] = fields.ForeignKeyField(
|
||||
'models.Workspace', related_name='purchase_plans', on_delete=fields.CASCADE, index=True
|
||||
)
|
||||
project: fields.ForeignKeyRelation['Project'] = fields.ForeignKeyField(
|
||||
'models.Project', related_name='purchase_plans', on_delete=fields.CASCADE, index=True
|
||||
)
|
||||
|
||||
class Meta:
|
||||
table = 'purchase_plan'
|
||||
indexes = (('project', 'status'),)
|
||||
|
||||
|
||||
class PurchasePlanChannel(TimestampedModel):
|
||||
id = fields.UUIDField(pk=True)
|
||||
status = fields.CharEnumField(PurchasePlanChannelStatus, default=PurchasePlanChannelStatus.PLANNED)
|
||||
planned_cost = fields.FloatField(null=True)
|
||||
comment = fields.TextField(null=True)
|
||||
|
||||
purchase_plan: fields.ForeignKeyRelation['PurchasePlan'] = fields.ForeignKeyField(
|
||||
'models.PurchasePlan', related_name='channels', on_delete=fields.CASCADE, index=True
|
||||
)
|
||||
channel: fields.ForeignKeyRelation['Channel'] = fields.ForeignKeyField(
|
||||
'models.Channel', related_name='purchase_plan_channels', on_delete=fields.CASCADE, index=True
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
purchase_plan_id: uuid.UUID
|
||||
channel_id: uuid.UUID
|
||||
|
||||
class Meta:
|
||||
table = 'purchase_plan_channel'
|
||||
unique_together = (('purchase_plan_id', 'channel_id'),)
|
||||
@@ -1,14 +0,0 @@
|
||||
from tortoise import fields
|
||||
|
||||
from .base import TimestampedModel
|
||||
|
||||
|
||||
class Subscriber(TimestampedModel):
|
||||
id = fields.UUIDField(pk=True)
|
||||
telegram_id = fields.BigIntField(unique=True, index=True)
|
||||
username = fields.CharField(max_length=255, null=True)
|
||||
first_name = fields.CharField(max_length=255, null=True)
|
||||
last_name = fields.CharField(max_length=255, null=True)
|
||||
|
||||
class Meta:
|
||||
table = 'subscriber'
|
||||
@@ -8,8 +8,7 @@ from .base import TimestampedModel
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .placement import Placement
|
||||
from .subscriber import Subscriber
|
||||
from .target_channel import TargetChannel
|
||||
from .user import User
|
||||
|
||||
|
||||
class SubscriptionStatus(str, enum.Enum):
|
||||
@@ -26,17 +25,13 @@ class Subscription(TimestampedModel):
|
||||
placement: fields.ForeignKeyRelation['Placement'] = fields.ForeignKeyField(
|
||||
'models.Placement', related_name='subscriptions', on_delete=fields.CASCADE, index=True
|
||||
)
|
||||
subscriber: fields.ForeignKeyRelation['Subscriber'] = fields.ForeignKeyField(
|
||||
'models.Subscriber', related_name='subscriptions', on_delete=fields.CASCADE, index=True
|
||||
)
|
||||
target_channel: fields.ForeignKeyRelation['TargetChannel'] = fields.ForeignKeyField(
|
||||
'models.TargetChannel', related_name='subscriptions', on_delete=fields.CASCADE, index=True
|
||||
subscriber: fields.ForeignKeyRelation['User'] = fields.ForeignKeyField(
|
||||
'models.User', related_name='subscriptions', on_delete=fields.CASCADE, index=True
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
placement_id: UUID
|
||||
subscriber_id: UUID
|
||||
target_channel_id: UUID
|
||||
|
||||
class Meta:
|
||||
table = 'subscription'
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
import enum
|
||||
from typing import TYPE_CHECKING
|
||||
from uuid import UUID
|
||||
|
||||
from tortoise import fields
|
||||
|
||||
from .base import TimestampedModel
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .external_channel import ExternalChannel
|
||||
from .workspace import Workspace
|
||||
|
||||
|
||||
class TargetChannelStatus(str, enum.Enum):
|
||||
ACTIVE = 'active'
|
||||
INACTIVE = 'inactive'
|
||||
ARCHIVED = 'archived'
|
||||
|
||||
|
||||
class TargetChannel(TimestampedModel):
|
||||
id = fields.UUIDField(pk=True)
|
||||
telegram_id = fields.BigIntField(unique=True, index=True)
|
||||
title = fields.CharField(max_length=255)
|
||||
username = fields.CharField(max_length=255, null=True, index=True)
|
||||
status = fields.CharEnumField(TargetChannelStatus, default=TargetChannelStatus.ACTIVE)
|
||||
|
||||
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(
|
||||
'models.ExternalChannel',
|
||||
related_name='target_channels',
|
||||
through='target_external_channel',
|
||||
forward_key='external_channel_id',
|
||||
backward_key='target_channel_id',
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
workspace_id: UUID
|
||||
|
||||
class Meta:
|
||||
table = 'target_channel'
|
||||
@@ -10,7 +10,7 @@ class TelegramStateEnum(str, enum.Enum):
|
||||
CREATIVE_WAITING_CHANNEL = 'creative_waiting_channel'
|
||||
CREATIVE_WAITING_NAME = 'creative_waiting_name'
|
||||
CREATIVE_WAITING_TEXT = 'creative_waiting_text'
|
||||
TARGET_CHANNEL_WAITING_WORKSPACE = 'target_channel_waiting_workspace'
|
||||
PROJECT_WAITING_WORKSPACE = 'project_waiting_workspace'
|
||||
|
||||
|
||||
class TelegramState(TimestampedModel):
|
||||
|
||||
@@ -7,6 +7,8 @@ class User(TimestampedModel):
|
||||
id = fields.UUIDField(pk=True)
|
||||
telegram_id = fields.BigIntField(unique=True, index=True)
|
||||
username = fields.CharField(max_length=255, null=True)
|
||||
first_name = fields.CharField(max_length=255, null=True)
|
||||
last_name = fields.CharField(max_length=255, null=True)
|
||||
|
||||
class Meta:
|
||||
table = 'user'
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import enum
|
||||
import uuid
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
@@ -19,8 +20,15 @@ class Workspace(TimestampedModel):
|
||||
table = 'workspace'
|
||||
|
||||
|
||||
class WorkspaceUserStatus(str, enum.Enum):
|
||||
ACTIVE = 'active'
|
||||
INVITED = 'invited'
|
||||
REMOVED = 'removed'
|
||||
|
||||
|
||||
class WorkspaceUser(TimestampedModel):
|
||||
id = fields.UUIDField(pk=True)
|
||||
status = fields.CharEnumField(WorkspaceUserStatus, default=WorkspaceUserStatus.ACTIVE)
|
||||
|
||||
workspace: fields.ForeignKeyRelation[Workspace] = fields.ForeignKeyField(
|
||||
'models.Workspace', related_name='workspace_users', on_delete=fields.CASCADE, index=True
|
||||
@@ -36,3 +44,65 @@ class WorkspaceUser(TimestampedModel):
|
||||
class Meta:
|
||||
table = 'workspace_user'
|
||||
unique_together = (('workspace_id', 'user_id'),)
|
||||
|
||||
|
||||
class WorkspaceInviteStatus(str, enum.Enum):
|
||||
PENDING = 'pending'
|
||||
ACCEPTED = 'accepted'
|
||||
REVOKED = 'revoked'
|
||||
|
||||
|
||||
class WorkspaceInvite(TimestampedModel):
|
||||
id = fields.UUIDField(pk=True)
|
||||
status = fields.CharEnumField(WorkspaceInviteStatus, default=WorkspaceInviteStatus.PENDING)
|
||||
|
||||
workspace: fields.ForeignKeyRelation[Workspace] = fields.ForeignKeyField(
|
||||
'models.Workspace', related_name='invites', on_delete=fields.CASCADE, index=True
|
||||
)
|
||||
invited_by: fields.ForeignKeyRelation[User] = fields.ForeignKeyField(
|
||||
'models.User', related_name='sent_invites', on_delete=fields.CASCADE, index=True
|
||||
)
|
||||
user: fields.ForeignKeyRelation[User] = fields.ForeignKeyField(
|
||||
'models.User', related_name='workspace_invites', on_delete=fields.CASCADE, index=True
|
||||
)
|
||||
|
||||
class Meta:
|
||||
table = 'workspace_invite'
|
||||
unique_together = (('workspace_id', 'user_id'),)
|
||||
|
||||
|
||||
class PermissionKey(str, enum.Enum):
|
||||
MANAGE_PROJECTS = 'manage_projects'
|
||||
MANAGE_PLACEMENTS = 'manage_placements'
|
||||
VIEW_ANALYTICS = 'view_analytics'
|
||||
|
||||
|
||||
class PermissionScopeType(str, enum.Enum):
|
||||
WORKSPACE = 'workspace'
|
||||
PROJECT = 'project'
|
||||
|
||||
|
||||
class WorkspaceUserPermission(TimestampedModel):
|
||||
workspace_user: fields.ForeignKeyRelation[WorkspaceUser] = fields.ForeignKeyField(
|
||||
'models.WorkspaceUser', related_name='permissions', on_delete=fields.CASCADE, index=True
|
||||
)
|
||||
permission = fields.CharEnumField(PermissionKey)
|
||||
|
||||
class Meta:
|
||||
table = 'workspace_user_permission'
|
||||
unique_together = (('workspace_user_id', 'permission'),)
|
||||
|
||||
|
||||
class WorkspaceUserPermissionScope(TimestampedModel):
|
||||
id = fields.UUIDField(pk=True)
|
||||
permission = fields.CharEnumField(PermissionKey)
|
||||
scope_type = fields.CharEnumField(PermissionScopeType)
|
||||
scope_id = fields.UUIDField()
|
||||
|
||||
workspace_user: fields.ForeignKeyRelation[WorkspaceUser] = fields.ForeignKeyField(
|
||||
'models.WorkspaceUser', related_name='permission_scopes', on_delete=fields.CASCADE, index=True
|
||||
)
|
||||
|
||||
class Meta:
|
||||
table = 'workspace_user_permission_scope'
|
||||
unique_together = (('workspace_user_id', 'permission', 'scope_type', 'scope_id'),)
|
||||
|
||||
Reference in New Issue
Block a user