feat: add stage 0 foundation

This commit is contained in:
hailin
2026-06-30 15:55:46 +08:00
parent 6d373da09f
commit 604f456e03
68 changed files with 4884 additions and 0 deletions

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1,3 @@
from ninja import Router
router = Router(tags=["accounts"])

View File

@@ -0,0 +1,6 @@
from django.apps import AppConfig
class AccountsConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "apps.accounts"

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1,33 @@
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
from django.core.management.base import BaseCommand
from apps.accounts.permissions import DEFAULT_GROUPS, PERMISSIONS
class Command(BaseCommand):
help = "Seed MVP permissions and default user groups."
def handle(self, *args, **options):
content_type, _ = ContentType.objects.get_or_create(
app_label="system",
model="platformpermission",
)
permissions_by_codename: dict[str, Permission] = {}
for spec in PERMISSIONS:
permission, _ = Permission.objects.get_or_create(
content_type=content_type,
codename=spec.codename,
defaults={"name": spec.name},
)
if permission.name != spec.name:
permission.name = spec.name
permission.save(update_fields=["name"])
permissions_by_codename[spec.codename] = permission
for group_name, codenames in DEFAULT_GROUPS.items():
group, _ = Group.objects.get_or_create(name=group_name)
group.permissions.set(permissions_by_codename[codename] for codename in codenames)
self.stdout.write(self.style.SUCCESS("Seeded permissions and groups."))

View File

@@ -0,0 +1 @@
# Use Django's built-in User, Group, and Permission models for MVP RBAC.

View File

@@ -0,0 +1,61 @@
from dataclasses import dataclass
@dataclass(frozen=True)
class PermissionSpec:
codename: str
name: str
PERMISSIONS: tuple[PermissionSpec, ...] = (
PermissionSpec("ticket.view", "View tickets"),
PermissionSpec("ticket.create", "Create tickets"),
PermissionSpec("ticket.edit", "Edit tickets"),
PermissionSpec("ticket.export", "Export tickets"),
PermissionSpec("ticket.assign", "Assign tickets"),
PermissionSpec("ticket.close", "Close tickets"),
PermissionSpec("knowledge.view", "View knowledge"),
PermissionSpec("knowledge.manage", "Manage knowledge"),
PermissionSpec("solution.view", "View solutions"),
PermissionSpec("solution.manage", "Manage solutions"),
PermissionSpec("agent.use", "Use Agents"),
PermissionSpec("agent.manage", "Manage Agents"),
PermissionSpec("model.manage", "Manage model configs"),
PermissionSpec("tool.manage", "Manage MCP tools"),
PermissionSpec("audit.view", "View audit logs"),
PermissionSpec("system.manage", "Manage system settings"),
)
DEFAULT_GROUPS: dict[str, tuple[str, ...]] = {
"System Admin": tuple(permission.codename for permission in PERMISSIONS),
"Knowledge Admin": (
"ticket.view",
"knowledge.view",
"knowledge.manage",
"solution.view",
"solution.manage",
"agent.use",
),
"Support Engineer": (
"ticket.view",
"ticket.create",
"ticket.edit",
"ticket.assign",
"ticket.close",
"knowledge.view",
"solution.view",
"agent.use",
),
"Requester": (
"ticket.view",
"ticket.create",
"knowledge.view",
"solution.view",
),
"Auditor": (
"ticket.view",
"knowledge.view",
"solution.view",
"audit.view",
),
}

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1,17 @@
from django.contrib.auth.models import Group, Permission
from django.core.management import call_command
from apps.accounts.permissions import DEFAULT_GROUPS, PERMISSIONS
def test_seed_permissions_creates_permissions_and_groups(db):
call_command("seed_permissions")
assert Permission.objects.filter(
codename__in=[permission.codename for permission in PERMISSIONS]
).count() == len(PERMISSIONS)
for group_name, codenames in DEFAULT_GROUPS.items():
group = Group.objects.get(name=group_name)
actual = set(group.permissions.values_list("codename", flat=True))
assert actual == set(codenames)