TS-ResHub/accounts/api/authorize.py
2025-04-15 16:33:40 +08:00

127 lines
4.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ✅ 授权管理接口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="申请原因")
# =========================
# 授权接口POST
# =========================
@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)} 个网站",
}
# =========================
# 用户发起申请POST
# =========================
@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} 的访问申请"}