feat: db constistancy
This commit is contained in:
@@ -138,17 +138,24 @@ class Postgres(DatabaseBase, Database):
|
||||
)
|
||||
|
||||
if scoped_permissions:
|
||||
await domain.WorkspaceUserPermissionScope.bulk_create(
|
||||
[
|
||||
domain.WorkspaceUserPermissionScope(
|
||||
workspace_user_id=workspace_user_id,
|
||||
permission=permission,
|
||||
scope_type=scope_type,
|
||||
scope_id=scope_id,
|
||||
)
|
||||
for permission, scope_type, scope_id in scoped_permissions
|
||||
]
|
||||
)
|
||||
scope_objects = []
|
||||
for permission, scope_type, scope_id in scoped_permissions:
|
||||
kwargs = {
|
||||
'workspace_user_id': workspace_user_id,
|
||||
'permission': permission,
|
||||
}
|
||||
if scope_type == domain.PermissionScopeType.PROJECT:
|
||||
kwargs['project_id'] = scope_id
|
||||
elif scope_type == domain.PermissionScopeType.CREATIVE:
|
||||
kwargs['creative_id'] = scope_id
|
||||
elif scope_type == domain.PermissionScopeType.PLACEMENT:
|
||||
kwargs['placement_id'] = scope_id
|
||||
elif scope_type == domain.PermissionScopeType.CHANNEL:
|
||||
kwargs['channel_id'] = scope_id
|
||||
|
||||
scope_objects.append(domain.WorkspaceUserPermissionScope(**kwargs))
|
||||
|
||||
await domain.WorkspaceUserPermissionScope.bulk_create(scope_objects)
|
||||
|
||||
async def create_login_token(self, login_token: domain.LoginToken) -> None:
|
||||
await login_token.save()
|
||||
|
||||
@@ -12,7 +12,7 @@ if TYPE_CHECKING:
|
||||
class LoginToken(TimestampedModel):
|
||||
token = fields.CharField(max_length=255, unique=True, index=True)
|
||||
user: fields.ForeignKeyRelation['User'] = fields.ForeignKeyField(
|
||||
'models.User', related_name='login_tokens', on_delete=fields.CASCADE
|
||||
'models.User', related_name='login_tokens', on_delete=fields.CASCADE, index=True
|
||||
)
|
||||
expires_at = fields.DatetimeField()
|
||||
used_at = fields.DatetimeField(null=True)
|
||||
|
||||
@@ -22,3 +22,4 @@ class PostViewsHistory(TimestampedModel):
|
||||
|
||||
class Meta:
|
||||
table = 'post_views_history'
|
||||
unique_together = (('post_id', 'fetched_at'),)
|
||||
|
||||
@@ -9,6 +9,10 @@ from tortoise import fields
|
||||
from .base import TimestampedModel
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .channel import Channel
|
||||
from .creative import Creative
|
||||
from .placement import Placement
|
||||
from .project import Project
|
||||
from .user import User
|
||||
|
||||
|
||||
@@ -117,16 +121,31 @@ class WorkspaceUserPermission(TimestampedModel):
|
||||
|
||||
class WorkspaceUserPermissionScope(TimestampedModel):
|
||||
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
|
||||
)
|
||||
|
||||
# Exactly one of these must be set (enforced by CHECK constraint in migration)
|
||||
project: fields.ForeignKeyRelation[Project] | None = fields.ForeignKeyField(
|
||||
'models.Project', related_name='permission_scopes', on_delete=fields.CASCADE, null=True, index=True
|
||||
)
|
||||
creative: fields.ForeignKeyRelation[Creative] | None = fields.ForeignKeyField(
|
||||
'models.Creative', related_name='permission_scopes', on_delete=fields.CASCADE, null=True, index=True
|
||||
)
|
||||
placement: fields.ForeignKeyRelation[Placement] | None = fields.ForeignKeyField(
|
||||
'models.Placement', related_name='permission_scopes', on_delete=fields.CASCADE, null=True, index=True
|
||||
)
|
||||
channel: fields.ForeignKeyRelation[Channel] | None = fields.ForeignKeyField(
|
||||
'models.Channel', related_name='permission_scopes', on_delete=fields.CASCADE, null=True, index=True
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
workspace_user_id: uuid.UUID
|
||||
project_id: uuid.UUID | None
|
||||
creative_id: uuid.UUID | None
|
||||
placement_id: uuid.UUID | None
|
||||
channel_id: uuid.UUID | None
|
||||
|
||||
class Meta:
|
||||
table = 'workspace_user_permission_scope'
|
||||
unique_together = (('workspace_user_id', 'permission', 'scope_type', 'scope_id'),)
|
||||
|
||||
@@ -23,8 +23,18 @@ class WorkspacePermissions:
|
||||
|
||||
scoped_permissions: dict[tuple[PermissionKey, PermissionScopeType], set[UUID]] = {}
|
||||
for scope in getattr(membership, 'permission_scopes', []) or []:
|
||||
key = (scope.permission, scope.scope_type)
|
||||
scoped_permissions.setdefault(key, set()).add(scope.scope_id)
|
||||
if scope.project_id:
|
||||
key = (scope.permission, PermissionScopeType.PROJECT)
|
||||
scoped_permissions.setdefault(key, set()).add(scope.project_id)
|
||||
elif scope.creative_id:
|
||||
key = (scope.permission, PermissionScopeType.CREATIVE)
|
||||
scoped_permissions.setdefault(key, set()).add(scope.creative_id)
|
||||
elif scope.placement_id:
|
||||
key = (scope.permission, PermissionScopeType.PLACEMENT)
|
||||
scoped_permissions.setdefault(key, set()).add(scope.placement_id)
|
||||
elif scope.channel_id:
|
||||
key = (scope.permission, PermissionScopeType.CHANNEL)
|
||||
scoped_permissions.setdefault(key, set()).add(scope.channel_id)
|
||||
|
||||
return cls(global_permissions=global_permissions, scoped_permissions=scoped_permissions)
|
||||
|
||||
|
||||
@@ -37,6 +37,17 @@ async def fetch_placement_post_cycle(self: 'Usecase', interval_seconds: int) ->
|
||||
).first()
|
||||
|
||||
if matching_post:
|
||||
# Validate channel consistency
|
||||
if matching_post.channel_id != placement.placement_channel_id:
|
||||
log.error(
|
||||
'Post %s channel_id mismatch: expected %s, got %s. Skipping placement %s',
|
||||
matching_post.id,
|
||||
placement.placement_channel_id,
|
||||
matching_post.channel_id,
|
||||
placement.id,
|
||||
)
|
||||
continue
|
||||
|
||||
placement.post = matching_post
|
||||
await placement.save()
|
||||
updated_count += 1
|
||||
|
||||
Reference in New Issue
Block a user