This commit is contained in:
2026-07-08 20:28:24 +09:00
parent 38b5c2492e
commit 76d91efcb8
11 changed files with 1064 additions and 7 deletions
+182 -3
View File
@@ -10,9 +10,15 @@ from .B01_Dashboard_Repository import (
add_company_member,
assign_user_company,
change_user_role,
count_company_admins,
create_company,
create_project_automation,
delete_project_automation,
get_dashboard_me,
get_project,
get_project_automation,
get_system_resources,
get_user_admin_target,
get_user_company,
join_company,
list_all_companies,
@@ -22,19 +28,28 @@ from .B01_Dashboard_Repository import (
list_company_members,
list_company_projects,
list_join_requests,
list_project_automations,
list_user_projects,
mark_project_automation_executed,
process_join_request,
remove_company_member,
search_companies,
soft_delete_project,
update_admin_user,
update_project,
update_project_automation,
update_user_profile,
)
from .B01_Dashboard_Schema import (
AddMemberRequest,
AdminUpdateUserRequest,
AssignCompanyRequest,
AutomationRequest,
ChangeUserRoleRequest,
CreateCompanyRequest,
JoinCompanyRequest,
ProcessJoinRequest,
UpdateProjectRequest,
UpdateUserRequest,
)
@@ -56,6 +71,30 @@ def _require_company_id(session: dict[str, Any]) -> int:
return int(company_id)
def _same_company(session: dict[str, Any], company_id: int | None) -> bool:
return company_id is not None and int(session.get("company_id") or 0) == int(company_id)
def _can_edit_project(session: dict[str, Any], project: dict[str, Any]) -> bool:
if session["role"] == "SYSTEM_ADMIN":
return True
return _same_company(session, project.get("company_id"))
def _can_manage_automation(session: dict[str, Any], project: dict[str, Any]) -> bool:
if session["role"] == "SYSTEM_ADMIN":
return True
return session["role"] == "ADMIN" and _same_company(session, project.get("company_id"))
def _can_edit_user(session: dict[str, Any], target: dict[str, Any]) -> bool:
if session["role"] == "SYSTEM_ADMIN":
return True
if session["role"] == "ADMIN":
return _same_company(session, target.get("company_id"))
return int(session["user_id"]) == int(target["id"])
@router.get("/me")
async def dashboard_me(session: dict[str, Any] = Depends(verify_session)):
user = await get_dashboard_me(int(session["user_id"]))
@@ -149,11 +188,12 @@ async def admin_process_join_request(
payload: ProcessJoinRequest,
session: dict[str, Any] = Depends(require_company_admin),
):
company_id = None if session["role"] == "SYSTEM_ADMIN" else _require_company_id(session)
changed = await process_join_request(
request_id,
int(session["user_id"]),
payload.action == "APPROVE",
_require_company_id(session),
company_id,
)
if not changed:
raise HTTPException(status_code=404, detail="처리할 가입 신청을 찾을 수 없습니다.")
@@ -168,6 +208,32 @@ async def admin_projects(session: dict[str, Any] = Depends(require_company_admin
}
@router.put("/projects/{project_id}")
async def dashboard_update_project(
project_id: str,
payload: UpdateProjectRequest,
session: dict[str, Any] = Depends(verify_session),
):
project = await get_project(project_id)
if not project:
raise HTTPException(status_code=404, detail="프로젝트를 찾을 수 없습니다.")
if not _can_edit_project(session, project):
raise HTTPException(status_code=403, detail="프로젝트 수정 권한이 없습니다.")
if not await update_project(project_id, payload.model_dump(), int(session["user_id"])):
raise HTTPException(status_code=404, detail="프로젝트를 찾을 수 없습니다.")
return {"status": "success"}
@router.delete("/projects/{project_id}")
async def dashboard_delete_project(
project_id: str,
session: dict[str, Any] = Depends(require_system_admin),
):
if not await soft_delete_project(project_id, int(session["user_id"])):
raise HTTPException(status_code=404, detail="프로젝트를 찾을 수 없습니다.")
return {"status": "success"}
@router.get("/admin/companies")
async def system_companies(session: dict[str, Any] = Depends(require_system_admin)):
_ = session
@@ -184,14 +250,50 @@ async def system_users(session: dict[str, Any] = Depends(require_system_admin)):
async def system_change_role(
user_id: int,
payload: ChangeUserRoleRequest,
session: dict[str, Any] = Depends(require_system_admin),
session: dict[str, Any] = Depends(verify_session),
):
_ = session
target = await get_user_admin_target(user_id)
if not target:
raise HTTPException(status_code=404, detail="사용자를 찾을 수 없습니다.")
if payload.role == "SYSTEM_ADMIN" or target["role"] == "SYSTEM_ADMIN":
raise HTTPException(
status_code=403, detail="시스템 관리자 역할은 API에서 변경할 수 없습니다."
)
if session["role"] == "ADMIN":
if not _same_company(session, target.get("company_id")):
raise HTTPException(status_code=403, detail="같은 회사 사용자만 변경할 수 있습니다.")
if target["role"] == "ADMIN" and payload.role == "USER":
admins = await count_company_admins(int(target["company_id"]))
if admins <= 1:
raise HTTPException(
status_code=409, detail="회사의 마지막 관리자는 변경할 수 없습니다."
)
elif session["role"] != "SYSTEM_ADMIN":
raise HTTPException(status_code=403, detail="역할 변경 권한이 없습니다.")
if not await change_user_role(user_id, payload.role):
raise HTTPException(status_code=404, detail="사용자를 찾을 수 없습니다.")
return {"status": "success"}
@router.put("/admin/users/{user_id}")
async def admin_update_user(
user_id: int,
payload: AdminUpdateUserRequest,
session: dict[str, Any] = Depends(verify_session),
):
target = await get_user_admin_target(user_id)
if not target:
raise HTTPException(status_code=404, detail="사용자를 찾을 수 없습니다.")
if not _can_edit_user(session, target):
raise HTTPException(status_code=403, detail="사용자 수정 권한이 없습니다.")
data = payload.model_dump()
if session["role"] == "USER":
data["status"] = None
if not await update_admin_user(user_id, data):
raise HTTPException(status_code=404, detail="사용자를 찾을 수 없습니다.")
return {"status": "success"}
@router.patch("/admin/users/{user_id}/company")
async def system_assign_company(
user_id: int,
@@ -244,3 +346,80 @@ async def system_projects(session: dict[str, Any] = Depends(require_system_admin
_ = session
return {"status": "success", "projects": await list_all_projects()}
@router.get("/projects/{project_id}/automations")
async def dashboard_project_automations(
project_id: str,
session: dict[str, Any] = Depends(verify_session),
):
project = await get_project(project_id)
if not project:
raise HTTPException(status_code=404, detail="프로젝트를 찾을 수 없습니다.")
if not _can_edit_project(session, project):
raise HTTPException(status_code=403, detail="자동화 로직 조회 권한이 없습니다.")
return {"status": "success", "automations": await list_project_automations(project_id)}
@router.post("/projects/{project_id}/automations")
async def dashboard_create_automation(
project_id: str,
payload: AutomationRequest,
session: dict[str, Any] = Depends(verify_session),
):
project = await get_project(project_id)
if not project:
raise HTTPException(status_code=404, detail="프로젝트를 찾을 수 없습니다.")
if not _can_manage_automation(session, project):
raise HTTPException(status_code=403, detail="자동화 로직 생성 권한이 없습니다.")
automation = await create_project_automation(
project_id, int(session["user_id"]), payload.model_dump()
)
return {"status": "success", "automation": automation}
@router.put("/automations/{automation_id}")
async def dashboard_update_automation(
automation_id: int,
payload: AutomationRequest,
session: dict[str, Any] = Depends(verify_session),
):
automation = await get_project_automation(automation_id)
if not automation:
raise HTTPException(status_code=404, detail="자동화 로직을 찾을 수 없습니다.")
if not _can_manage_automation(session, automation):
raise HTTPException(status_code=403, detail="자동화 로직 수정 권한이 없습니다.")
if not await update_project_automation(
automation_id, int(session["user_id"]), payload.model_dump()
):
raise HTTPException(status_code=404, detail="자동화 로직을 찾을 수 없습니다.")
return {"status": "success"}
@router.delete("/automations/{automation_id}")
async def dashboard_delete_automation(
automation_id: int,
session: dict[str, Any] = Depends(verify_session),
):
automation = await get_project_automation(automation_id)
if not automation:
raise HTTPException(status_code=404, detail="자동화 로직을 찾을 수 없습니다.")
if not _can_manage_automation(session, automation):
raise HTTPException(status_code=403, detail="자동화 로직 삭제 권한이 없습니다.")
if not await delete_project_automation(automation_id, int(session["user_id"])):
raise HTTPException(status_code=404, detail="자동화 로직을 찾을 수 없습니다.")
return {"status": "success"}
@router.post("/automations/{automation_id}/execute")
async def dashboard_execute_automation(
automation_id: int,
session: dict[str, Any] = Depends(verify_session),
):
automation = await get_project_automation(automation_id)
if not automation:
raise HTTPException(status_code=404, detail="자동화 로직을 찾을 수 없습니다.")
if not _can_manage_automation(session, automation):
raise HTTPException(status_code=403, detail="자동화 로직 실행 권한이 없습니다.")
if not await mark_project_automation_executed(automation_id, int(session["user_id"])):
raise HTTPException(status_code=404, detail="자동화 로직을 찾을 수 없습니다.")
return {"status": "success"}