247 lines
7.8 KiB
Python
247 lines
7.8 KiB
Python
"""B01_Dashboard 역할별 대시보드 API."""
|
|
|
|
from typing import Any
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, Query
|
|
|
|
from common_util.common_util_auth import require_system_admin, verify_session
|
|
|
|
from .B01_Dashboard_Repository import (
|
|
add_company_member,
|
|
assign_user_company,
|
|
change_user_role,
|
|
create_company,
|
|
get_dashboard_me,
|
|
get_system_resources,
|
|
get_user_company,
|
|
join_company,
|
|
list_all_companies,
|
|
list_all_projects,
|
|
list_all_users,
|
|
list_audit_logs,
|
|
list_company_members,
|
|
list_company_projects,
|
|
list_join_requests,
|
|
list_user_projects,
|
|
process_join_request,
|
|
remove_company_member,
|
|
search_companies,
|
|
update_user_profile,
|
|
)
|
|
from .B01_Dashboard_Schema import (
|
|
AddMemberRequest,
|
|
AssignCompanyRequest,
|
|
ChangeUserRoleRequest,
|
|
CreateCompanyRequest,
|
|
JoinCompanyRequest,
|
|
ProcessJoinRequest,
|
|
UpdateUserRequest,
|
|
)
|
|
|
|
router = APIRouter(prefix="/api/dashboard", tags=["B01_Dashboard"])
|
|
|
|
|
|
async def require_company_admin(
|
|
session: dict[str, Any] = Depends(verify_session),
|
|
) -> dict[str, Any]:
|
|
if session["role"] not in ("ADMIN", "SYSTEM_ADMIN") and not session["is_master"]:
|
|
raise HTTPException(status_code=403, detail="회사 관리자 권한이 필요합니다.")
|
|
return session
|
|
|
|
|
|
def _require_company_id(session: dict[str, Any]) -> int:
|
|
company_id = session.get("company_id")
|
|
if company_id is None:
|
|
raise HTTPException(status_code=403, detail="회사 연결이 필요합니다.")
|
|
return int(company_id)
|
|
|
|
|
|
@router.get("/me")
|
|
async def dashboard_me(session: dict[str, Any] = Depends(verify_session)):
|
|
user = await get_dashboard_me(int(session["user_id"]))
|
|
if not user:
|
|
raise HTTPException(status_code=404, detail="사용자 정보를 찾을 수 없습니다.")
|
|
return {"status": "success", "user": user}
|
|
|
|
|
|
@router.patch("/me")
|
|
async def patch_dashboard_me(
|
|
payload: UpdateUserRequest,
|
|
session: dict[str, Any] = Depends(verify_session),
|
|
):
|
|
user = await update_user_profile(int(session["user_id"]), payload.model_dump())
|
|
return {"status": "success", "user": user}
|
|
|
|
|
|
@router.get("/user/projects")
|
|
async def user_projects(session: dict[str, Any] = Depends(verify_session)):
|
|
return {"status": "success", "projects": await list_user_projects(int(session["user_id"]))}
|
|
|
|
|
|
@router.get("/user/company")
|
|
async def user_company(session: dict[str, Any] = Depends(verify_session)):
|
|
return {"status": "success", "company": await get_user_company(session.get("company_id"))}
|
|
|
|
|
|
@router.get("/user/companies")
|
|
async def user_company_search(
|
|
q: str = Query(min_length=1, max_length=100),
|
|
session: dict[str, Any] = Depends(verify_session),
|
|
):
|
|
_ = session
|
|
return {"status": "success", "companies": await search_companies(q.strip())}
|
|
|
|
|
|
@router.post("/user/company/create")
|
|
async def user_company_create(
|
|
payload: CreateCompanyRequest,
|
|
session: dict[str, Any] = Depends(verify_session),
|
|
):
|
|
result = await create_company(int(session["user_id"]), payload.model_dump())
|
|
return {"status": "success", **result}
|
|
|
|
|
|
@router.post("/user/company/join")
|
|
async def user_company_join(
|
|
payload: JoinCompanyRequest,
|
|
session: dict[str, Any] = Depends(verify_session),
|
|
):
|
|
result = await join_company(int(session["user_id"]), payload.company_id)
|
|
return {"status": "success", **result}
|
|
|
|
|
|
@router.get("/admin/members")
|
|
async def admin_members(session: dict[str, Any] = Depends(require_company_admin)):
|
|
return {
|
|
"status": "success",
|
|
"members": await list_company_members(_require_company_id(session)),
|
|
}
|
|
|
|
|
|
@router.post("/admin/members")
|
|
async def admin_add_member(
|
|
payload: AddMemberRequest,
|
|
session: dict[str, Any] = Depends(require_company_admin),
|
|
):
|
|
member = await add_company_member(_require_company_id(session), payload.email)
|
|
if not member:
|
|
raise HTTPException(status_code=409, detail="사용자를 찾을 수 없거나 이미 팀원입니다.")
|
|
return {"status": "success", "member": member}
|
|
|
|
|
|
@router.delete("/admin/members/{user_id}")
|
|
async def admin_remove_member(
|
|
user_id: int, session: dict[str, Any] = Depends(require_company_admin)
|
|
):
|
|
if not await remove_company_member(_require_company_id(session), user_id):
|
|
raise HTTPException(status_code=404, detail="제거할 팀원을 찾을 수 없습니다.")
|
|
return {"status": "success"}
|
|
|
|
|
|
@router.get("/admin/join-requests")
|
|
async def admin_join_requests(session: dict[str, Any] = Depends(require_company_admin)):
|
|
return {"status": "success", "requests": await list_join_requests(_require_company_id(session))}
|
|
|
|
|
|
@router.patch("/admin/join-requests/{request_id}")
|
|
async def admin_process_join_request(
|
|
request_id: int,
|
|
payload: ProcessJoinRequest,
|
|
session: dict[str, Any] = Depends(require_company_admin),
|
|
):
|
|
changed = await process_join_request(
|
|
request_id,
|
|
int(session["user_id"]),
|
|
payload.action == "APPROVE",
|
|
_require_company_id(session),
|
|
)
|
|
if not changed:
|
|
raise HTTPException(status_code=404, detail="처리할 가입 신청을 찾을 수 없습니다.")
|
|
return {"status": "success"}
|
|
|
|
|
|
@router.get("/admin/projects")
|
|
async def admin_projects(session: dict[str, Any] = Depends(require_company_admin)):
|
|
return {
|
|
"status": "success",
|
|
"projects": await list_company_projects(_require_company_id(session)),
|
|
}
|
|
|
|
|
|
@router.get("/admin/companies")
|
|
async def system_companies(session: dict[str, Any] = Depends(require_system_admin)):
|
|
_ = session
|
|
return {"status": "success", "companies": await list_all_companies()}
|
|
|
|
|
|
@router.get("/admin/users")
|
|
async def system_users(session: dict[str, Any] = Depends(require_system_admin)):
|
|
_ = session
|
|
return {"status": "success", "users": await list_all_users()}
|
|
|
|
|
|
@router.patch("/admin/users/{user_id}/role")
|
|
async def system_change_role(
|
|
user_id: int,
|
|
payload: ChangeUserRoleRequest,
|
|
session: dict[str, Any] = Depends(require_system_admin),
|
|
):
|
|
_ = session
|
|
if not await change_user_role(user_id, payload.role):
|
|
raise HTTPException(status_code=404, detail="사용자를 찾을 수 없습니다.")
|
|
return {"status": "success"}
|
|
|
|
|
|
@router.patch("/admin/users/{user_id}/company")
|
|
async def system_assign_company(
|
|
user_id: int,
|
|
payload: AssignCompanyRequest,
|
|
session: dict[str, Any] = Depends(require_system_admin),
|
|
):
|
|
_ = session
|
|
if not await assign_user_company(user_id, payload.company_id):
|
|
raise HTTPException(status_code=404, detail="사용자를 찾을 수 없습니다.")
|
|
return {"status": "success"}
|
|
|
|
|
|
@router.get("/admin/join-requests-all")
|
|
async def system_join_requests(session: dict[str, Any] = Depends(require_system_admin)):
|
|
_ = session
|
|
return {"status": "success", "requests": await list_join_requests()}
|
|
|
|
|
|
@router.patch("/admin/join-requests/{request_id}/approve")
|
|
async def system_approve_join_request(
|
|
request_id: int,
|
|
session: dict[str, Any] = Depends(require_system_admin),
|
|
):
|
|
if not await process_join_request(request_id, int(session["user_id"]), True):
|
|
raise HTTPException(status_code=404, detail="처리할 가입 신청을 찾을 수 없습니다.")
|
|
return {"status": "success"}
|
|
|
|
|
|
@router.get("/admin/audit-logs")
|
|
async def system_audit_logs(
|
|
page: int = Query(1, ge=1),
|
|
limit: int = Query(50, ge=1, le=100),
|
|
session: dict[str, Any] = Depends(require_system_admin),
|
|
):
|
|
_ = session
|
|
return {"status": "success", **await list_audit_logs(limit, (page - 1) * limit)}
|
|
|
|
|
|
@router.get("/admin/resources")
|
|
async def system_resources(
|
|
days: int = Query(30, ge=1, le=90),
|
|
session: dict[str, Any] = Depends(require_system_admin),
|
|
):
|
|
_ = session
|
|
return {"status": "success", **await get_system_resources(days)}
|
|
|
|
|
|
@router.get("/admin/projects-all")
|
|
async def system_projects(session: dict[str, Any] = Depends(require_system_admin)):
|
|
_ = session
|
|
return {"status": "success", "projects": await list_all_projects()}
|
|
|