Add issue resolution confirmation workflow
This commit is contained in:
@@ -19,6 +19,8 @@ from ..auth import get_current_user
|
||||
from ..runtime import get_runtime_settings
|
||||
from .images import cache_tmdb_image, is_tmdb_cached
|
||||
from ..db import (
|
||||
add_portal_item_activity,
|
||||
get_portal_item,
|
||||
save_action,
|
||||
get_recent_actions,
|
||||
get_recent_snapshots,
|
||||
@@ -1796,6 +1798,46 @@ def _replacement_file_payload(
|
||||
}
|
||||
|
||||
|
||||
def _linked_issue_for_replacement(
|
||||
issue_id: Any,
|
||||
*,
|
||||
request_id: str,
|
||||
user: Dict[str, str],
|
||||
) -> Optional[Dict[str, Any]]:
|
||||
if issue_id is None:
|
||||
return None
|
||||
if not isinstance(issue_id, int) or issue_id <= 0:
|
||||
raise HTTPException(status_code=400, detail="A valid linked issue is required")
|
||||
issue = get_portal_item(issue_id)
|
||||
if not issue or str(issue.get("kind") or "").lower() != "issue":
|
||||
raise HTTPException(status_code=404, detail="Linked issue not found")
|
||||
if str(issue.get("external_ref") or "") != f"/requests/{request_id}":
|
||||
raise HTTPException(status_code=409, detail="The issue is not linked to this request")
|
||||
is_admin = str(user.get("role") or "").lower() == "admin"
|
||||
is_owner = str(issue.get("created_by_username") or "").lower() == str(user.get("username") or "").lower()
|
||||
if not (is_admin or is_owner):
|
||||
raise HTTPException(status_code=403, detail="You cannot update this linked issue")
|
||||
return issue
|
||||
|
||||
|
||||
def _record_replacement_activity(
|
||||
issue: Optional[Dict[str, Any]],
|
||||
*,
|
||||
user: Dict[str, str],
|
||||
event_type: str,
|
||||
message: str,
|
||||
) -> None:
|
||||
if not issue:
|
||||
return
|
||||
add_portal_item_activity(
|
||||
int(issue["id"]),
|
||||
event_type=event_type,
|
||||
actor_username=str(user.get("username") or "unknown"),
|
||||
actor_role=str(user.get("role") or "user"),
|
||||
message=message,
|
||||
)
|
||||
|
||||
|
||||
async def _resolve_root_folder_path(client: Any, root_folder: str, service_name: str) -> str:
|
||||
if root_folder.isdigit():
|
||||
folders = await client.get_root_folders()
|
||||
@@ -1915,6 +1957,11 @@ async def action_replace_media(
|
||||
file_id = payload.get("file_id")
|
||||
if not isinstance(file_id, int) or file_id <= 0:
|
||||
raise HTTPException(status_code=400, detail="A valid managed file is required")
|
||||
linked_issue = _linked_issue_for_replacement(
|
||||
payload.get("issue_id"),
|
||||
request_id=request_id,
|
||||
user=user,
|
||||
)
|
||||
|
||||
runtime = get_runtime_settings()
|
||||
seerr = JellyseerrClient(runtime.jellyseerr_base_url, runtime.jellyseerr_api_key)
|
||||
@@ -1976,7 +2023,13 @@ async def action_replace_media(
|
||||
await sonarr.search_episodes(episode_ids)
|
||||
else:
|
||||
raise HTTPException(status_code=400, detail="Unknown request type")
|
||||
except HTTPException:
|
||||
except HTTPException as exc:
|
||||
_record_replacement_activity(
|
||||
linked_issue,
|
||||
user=user,
|
||||
event_type="replacement_failed",
|
||||
message=f"The media replacement could not be started: {exc.detail}",
|
||||
)
|
||||
raise
|
||||
except Exception as exc:
|
||||
logger.exception("%s media replacement failed request_id=%s file_id=%s", collector, request_id, file_id)
|
||||
@@ -1992,6 +2045,12 @@ async def action_replace_media(
|
||||
"failed",
|
||||
detail,
|
||||
)
|
||||
_record_replacement_activity(
|
||||
linked_issue,
|
||||
user=user,
|
||||
event_type="replacement_failed",
|
||||
message=detail,
|
||||
)
|
||||
raise HTTPException(status_code=502, detail=detail) from exc
|
||||
|
||||
message = f"{collector} removed {target_name} and started a replacement search."
|
||||
@@ -2003,6 +2062,12 @@ async def action_replace_media(
|
||||
"ok",
|
||||
message,
|
||||
)
|
||||
_record_replacement_activity(
|
||||
linked_issue,
|
||||
user=user,
|
||||
event_type="replacement_started",
|
||||
message=message,
|
||||
)
|
||||
return {
|
||||
"status": "ok",
|
||||
"message": message,
|
||||
|
||||
Reference in New Issue
Block a user