diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..8a844ed Binary files /dev/null and b/.DS_Store differ diff --git a/app/admin/__pycache__/views.cpython-312.pyc b/app/admin/__pycache__/views.cpython-312.pyc index a3b2fb0..c328c01 100644 Binary files a/app/admin/__pycache__/views.cpython-312.pyc and b/app/admin/__pycache__/views.cpython-312.pyc differ diff --git a/app/admin/routes.py b/app/admin/routes.py index 9eee2c5..9fc904f 100644 --- a/app/admin/routes.py +++ b/app/admin/routes.py @@ -9,6 +9,8 @@ from starlette.responses import RedirectResponse from app.db import crud from app.db.engine import get_session from app.db.models import JobStatus +from app.security.audit import log_event +from app.security.permissions import button_permission_code, request_has_permission from app.tasks.execute import execute_job @@ -21,6 +23,9 @@ def _redirect_with_error(referer: str, msg: str) -> RedirectResponse: @router.post("/admin/joblogs/{log_id}/retry") def retry_joblog(request: Request, log_id: int): + if not request_has_permission(request, button_permission_code("joblog:retry")): + referer = request.headers.get("Referer") or str(request.url_for("admin:list", identity="job-log")) + return _redirect_with_error(referer, "无权限执行该操作。") session = get_session() try: log = crud.get_job_log(session, log_id) @@ -52,12 +57,22 @@ def retry_joblog(request: Request, log_id: int): ) execute_job.delay(snapshot_params=snapshot, log_id=int(new_log.id)) url = request.url_for("admin:details", identity="job-log", pk=str(new_log.id)) + log_event( + session, + action="admin.action", + target=f"joblog:{log_id}:retry", + detail={"new_log_id": int(new_log.id)}, + request=request, + ) return RedirectResponse(url, status_code=303) finally: session.close() @router.post("/admin/jobs/{job_id}/run") def run_job(request: Request, job_id: str): + if not request_has_permission(request, button_permission_code("job:run")): + referer = request.headers.get("Referer") or str(request.url_for("admin:list", identity="job")) + return _redirect_with_error(referer, "无权限执行该操作。") session = get_session() try: job = crud.get_job(session, job_id) @@ -86,6 +101,13 @@ def run_job(request: Request, job_id: str): ) execute_job.delay(job_id=job.id, log_id=int(new_log.id)) url = request.url_for("admin:details", identity="job-log", pk=str(new_log.id)) + log_event( + session, + action="admin.action", + target=f"job:{job_id}:run", + detail={"new_log_id": int(new_log.id)}, + request=request, + ) return RedirectResponse(url, status_code=303) finally: session.close() diff --git a/app/admin/secure.py b/app/admin/secure.py new file mode 100644 index 0000000..c58ff30 --- /dev/null +++ b/app/admin/secure.py @@ -0,0 +1,37 @@ +from __future__ import annotations + +from sqladmin import ModelView + +from app.security.permissions import request_has_permission, table_permission_code + + +class SecureModelView(ModelView): + def _table_name(self) -> str: + return getattr(self.model, "__tablename__", self.identity) + + def _table_permission(self, action: str) -> str: + return table_permission_code(self._table_name(), action) + + def is_accessible(self, request) -> bool: # type: ignore[override] + return request_has_permission(request, self._table_permission("read")) + + def is_create_allowed(self, request) -> bool: # type: ignore[override] + return request_has_permission(request, self._table_permission("write")) + + def is_edit_allowed(self, request) -> bool: # type: ignore[override] + return request_has_permission(request, self._table_permission("write")) + + def is_delete_allowed(self, request) -> bool: # type: ignore[override] + return request_has_permission(request, self._table_permission("write")) + + def has_action_permission(self, request, action_name: str) -> bool: + code = self.get_action_permission_code(action_name) + if not code: + return True + return request_has_permission(request, code) + + def get_action_permission_code(self, action_name: str) -> str | None: + return None + + def has_permission_code(self, request, code: str) -> bool: + return request_has_permission(request, code) diff --git a/app/admin/templates/job_list.html b/app/admin/templates/job_list.html index e9f41e1..3cf2ee1 100644 --- a/app/admin/templates/job_list.html +++ b/app/admin/templates/job_list.html @@ -41,7 +41,7 @@ {% endif %} {% endif %} - {% if model_view.can_create %} + {% if model_view.is_create_allowed(request) %}