mirror of
https://github.com/dartdavros/chatballs.git
synced 2026-10-05 09:14:58 +03:00
Документация переработана: действующее отделено от истории, отменённые контуры (продажи, биллинг, managed AI, отделы, сущность Product) убраны из действующих документов в архив. Здесь — только кодовая часть: ссылки на документы в комментариях. Ссылки на действующие документы переименованы ADR/SPEC/ARCH/BUS-HUB-NNNN → *-CHATBALLS-NNNN (274 ссылки в 173 файлах). Ссылки на документы, ушедшие в архив, намеренно сохранили прежний идентификатор: он совпадает с именем архивного файла. Логика не менялась — правки только в комментариях, докстрингах и одном описании теста. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
53 lines
1.6 KiB
Python
53 lines
1.6 KiB
Python
from __future__ import annotations
|
|
|
|
from django.db import models
|
|
|
|
|
|
class PlatformOperator(models.Model):
|
|
"""Global platform principal (ADR-CHATBALLS-0031 §9). Not derived from tenant
|
|
membership; never becomes an Organization OWNER. Authenticated via
|
|
PlatformToken (machine-to-machine)."""
|
|
|
|
name = models.CharField(max_length=128)
|
|
is_active = models.BooleanField(default=True)
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
|
|
class Meta:
|
|
ordering = ["name"]
|
|
|
|
def __str__(self) -> str:
|
|
return self.name
|
|
|
|
|
|
class PlatformToken(models.Model):
|
|
"""Opaque API token stored as a sha256 hash (mirror identity invitation tokens).
|
|
Plaintext is returned only once at creation time by the token service."""
|
|
|
|
operator = models.ForeignKey(
|
|
PlatformOperator,
|
|
on_delete=models.CASCADE,
|
|
related_name="tokens",
|
|
)
|
|
name = models.CharField(max_length=128)
|
|
token_hash = models.CharField(max_length=128, unique=True)
|
|
capabilities = models.JSONField(default=list, blank=True)
|
|
last_used_at = models.DateTimeField(null=True, blank=True)
|
|
revoked_at = models.DateTimeField(null=True, blank=True)
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
|
|
class Meta:
|
|
ordering = ["-created_at"]
|
|
constraints = [
|
|
models.CheckConstraint(
|
|
condition=models.Q(token_hash__isnull=False) & ~models.Q(token_hash=""),
|
|
name="platform_token_hash_present",
|
|
),
|
|
]
|
|
|
|
def __str__(self) -> str:
|
|
return f"{self.operator.name}:{self.name}"
|
|
|
|
@property
|
|
def is_revoked(self) -> bool:
|
|
return self.revoked_at is not None
|