feat(keys): auto-generate entity keys and remove manual key input from admin create forms
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.keygen import generate_key
|
||||
from app.core.config import get_settings
|
||||
from app.db.session import get_db
|
||||
from app.models.api_client import ApiClient
|
||||
@@ -81,6 +82,14 @@ def _split_module_key(payload_module: str | None) -> str:
|
||||
return payload_module
|
||||
|
||||
|
||||
def _generate_unique_key(prefix: str, exists_fn) -> str:
|
||||
for salt in range(1000):
|
||||
key = generate_key(prefix=prefix, salt=salt)
|
||||
if not exists_fn(key):
|
||||
return key
|
||||
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"failed_to_generate_{prefix.lower()}_key")
|
||||
|
||||
|
||||
def _sync_member_to_authentik(
|
||||
*,
|
||||
authentik_sub: str,
|
||||
@@ -124,9 +133,8 @@ def create_system(
|
||||
db: Session = Depends(get_db),
|
||||
) -> SystemItem:
|
||||
repo = SystemsRepository(db)
|
||||
if repo.get_by_key(payload.system_key):
|
||||
raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="system_key_already_exists")
|
||||
row = repo.create(system_key=payload.system_key, name=payload.name, status=payload.status)
|
||||
system_key = _generate_unique_key("ST", repo.get_by_key)
|
||||
row = repo.create(system_key=system_key, name=payload.name, status=payload.status)
|
||||
return SystemItem(id=row.id, system_key=row.system_key, name=row.name, status=row.status)
|
||||
|
||||
|
||||
@@ -180,9 +188,8 @@ def create_module(
|
||||
system = systems_repo.get_by_key(payload.system_key)
|
||||
if not system:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="system_not_found")
|
||||
full_module_key = f"{payload.system_key}.{payload.module_key}"
|
||||
if modules_repo.get_by_key(full_module_key):
|
||||
raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="module_key_already_exists")
|
||||
leaf_module_key = _generate_unique_key("MD", lambda k: modules_repo.get_by_key(f"{payload.system_key}.{k}"))
|
||||
full_module_key = f"{payload.system_key}.{leaf_module_key}"
|
||||
row = modules_repo.create(
|
||||
module_key=full_module_key,
|
||||
name=payload.name,
|
||||
@@ -317,9 +324,8 @@ def create_company(
|
||||
db: Session = Depends(get_db),
|
||||
) -> CompanyItem:
|
||||
repo = CompaniesRepository(db)
|
||||
if repo.get_by_key(payload.company_key):
|
||||
raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="company_key_already_exists")
|
||||
row = repo.create(company_key=payload.company_key, name=payload.name, status=payload.status)
|
||||
company_key = _generate_unique_key("CP", repo.get_by_key)
|
||||
row = repo.create(company_key=company_key, name=payload.name, status=payload.status)
|
||||
return CompanyItem(id=row.id, company_key=row.company_key, name=row.name, status=row.status)
|
||||
|
||||
|
||||
@@ -414,9 +420,8 @@ def create_site(
|
||||
company = companies_repo.get_by_key(payload.company_key)
|
||||
if not company:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="company_not_found")
|
||||
if sites_repo.get_by_key(payload.site_key):
|
||||
raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="site_key_already_exists")
|
||||
row = sites_repo.create(site_key=payload.site_key, company_id=company.id, name=payload.name, status=payload.status)
|
||||
site_key = _generate_unique_key("ST", sites_repo.get_by_key)
|
||||
row = sites_repo.create(site_key=site_key, company_id=company.id, name=payload.name, status=payload.status)
|
||||
return SiteItem(id=row.id, site_key=row.site_key, company_key=payload.company_key, name=row.name, status=row.status)
|
||||
|
||||
|
||||
@@ -688,9 +693,8 @@ def create_permission_group(
|
||||
db: Session = Depends(get_db),
|
||||
) -> PermissionGroupItem:
|
||||
repo = PermissionGroupsRepository(db)
|
||||
if repo.get_by_key(payload.group_key):
|
||||
raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="group_key_already_exists")
|
||||
row = repo.create(group_key=payload.group_key, name=payload.name, status=payload.status)
|
||||
group_key = _generate_unique_key("GP", repo.get_by_key)
|
||||
row = repo.create(group_key=group_key, name=payload.name, status=payload.status)
|
||||
return PermissionGroupItem(id=row.id, group_key=row.group_key, name=row.name, status=row.status)
|
||||
|
||||
|
||||
|
||||
9
backend/app/core/keygen.py
Normal file
9
backend/app/core/keygen.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from datetime import datetime
|
||||
import time
|
||||
|
||||
|
||||
def generate_key(prefix: str, salt: int = 0) -> str:
|
||||
date_str = datetime.now().strftime("%Y%m%d")
|
||||
tail = (int(time.time() * 1000) + salt) % 10000
|
||||
return f"{prefix}{date_str}X{tail:04d}"
|
||||
|
||||
@@ -3,7 +3,6 @@ from typing import Literal
|
||||
|
||||
|
||||
class SystemCreateRequest(BaseModel):
|
||||
system_key: str
|
||||
name: str
|
||||
status: str = "active"
|
||||
|
||||
@@ -22,7 +21,6 @@ class SystemItem(BaseModel):
|
||||
|
||||
class ModuleCreateRequest(BaseModel):
|
||||
system_key: str
|
||||
module_key: str
|
||||
name: str
|
||||
status: str = "active"
|
||||
|
||||
@@ -41,7 +39,6 @@ class ModuleItem(BaseModel):
|
||||
|
||||
|
||||
class CompanyCreateRequest(BaseModel):
|
||||
company_key: str
|
||||
name: str
|
||||
status: str = "active"
|
||||
|
||||
@@ -59,7 +56,6 @@ class CompanyItem(BaseModel):
|
||||
|
||||
|
||||
class SiteCreateRequest(BaseModel):
|
||||
site_key: str
|
||||
company_key: str
|
||||
name: str
|
||||
status: str = "active"
|
||||
@@ -114,7 +110,6 @@ class ListResponse(BaseModel):
|
||||
|
||||
|
||||
class PermissionGroupCreateRequest(BaseModel):
|
||||
group_key: str
|
||||
name: str
|
||||
status: str = "active"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user