# ✅ 授权管理接口:manager 给 user 授权网站 + 普通用户申请接口 from ninja import Router, Schema, Query from pydantic import Field from typing import List, Optional from django.shortcuts import get_object_or_404 from django.db import models from accounts.models import User from websites.models import Website from utils.auth import jwt_auth from utils.permissions import manager_required, login_required router = Router(tags=["授权管理"]) class WebsiteAccessRequest(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) website = models.ForeignKey(Website, on_delete=models.CASCADE) status = models.CharField( max_length=20, choices=[("pending", "待审批"), ("approved", "已通过"), ("rejected", "已拒绝")], default="pending" ) reason = models.TextField(blank=True) created_at = models.DateTimeField(auto_now_add=True) class AuthorizeIn(Schema): user_id: int = Field(..., description="被授权的用户ID") website_ids: List[int] = Field(..., description="要授权的网站ID列表") class AccessRequestIn(Schema): website_id: int = Field(...) reason: Optional[str] = Field(None, description="申请原因") @router.post("/authorize", auth=jwt_auth) @manager_required def authorize_user(request, data: AuthorizeIn): manager = request.user target_user = get_object_or_404(User, id=data.user_id) if target_user.role != "user": return {"success": False, "message": "只能授权给普通用户"} managed_ids = set(manager.managed_websites.values_list("id", flat=True)) for wid in data.website_ids: if wid not in managed_ids: return {"success": False, "message": f"无权授权网站ID:{wid}"} target_user.authorized_websites.add(*data.website_ids) # 如果用户曾申请过,设置为已批准 WebsiteAccessRequest.objects.filter(user=target_user, website_id__in=data.website_ids).update(status="approved") return { "success": True, "message": f"已授权 {target_user.username} 访问 {len(data.website_ids)} 个网站", } @router.post("/apply", auth=jwt_auth) @login_required def request_access(request, data: AccessRequestIn): user = request.user site = get_object_or_404(Website, id=data.website_id) # 不允许重复申请 if WebsiteAccessRequest.objects.filter(user=user, website=site, status="pending").exists(): return {"success": False, "message": "您已申请,正在等待审批"} WebsiteAccessRequest.objects.create(user=user, website=site, reason=data.reason or "") return {"success": True, "message": "申请已提交,等待分管理审批"} @router.get("/pending", auth=jwt_auth) @manager_required def list_pending_requests(request): manager = request.user managed_ids = manager.managed_websites.values_list("id", flat=True) requests = WebsiteAccessRequest.objects.filter(website_id__in=managed_ids, status="pending") return { "success": True, "items": [ { "id": r.id, "user": r.user.username, "website": r.website.name, "reason": r.reason, "created_at": r.created_at, } for r in requests ] } @router.post("/approve", auth=jwt_auth) @manager_required def approve_request(request, request_id: int = Query(...), approve: bool = Query(True)): r = get_object_or_404(WebsiteAccessRequest, id=request_id) if r.website not in request.user.managed_websites.all(): return {"success": False, "message": "无权审批此申请"} r.status = "approved" if approve else "rejected" r.save() if approve: r.user.authorized_websites.add(r.website) return {"success": True, "message": f"已{'通过' if approve else '拒绝'} {r.user.username} 的访问申请"} @router.get("/my-sites", auth=jwt_auth) @login_required def list_my_authorized_websites(request): user = request.user sites = user.authorized_websites.all().values("id", "name", "db_alias") return {"success": True, "websites": list(sites)} @router.get("/public-sites") def list_public_websites(request): websites = Website.objects.all().values("id", "name", "db_alias", "description") return {"success": True, "websites": list(websites)}