11import datetime
22from http import HTTPStatus
3+ from typing import Literal
34
45from flask import redirect
56from flask_restx import Resource
6- from pydantic import BaseModel , Field
7- from werkzeug .exceptions import Conflict , NotFound
7+ from pydantic import BaseModel , Field , ValidationError
88
99from controllers .common .fields import RedirectResponse
1010from controllers .common .schema import register_response_schema_models , register_schema_models
2020from libs .helper import dump_response
2121from machinery .context import RequestContext
2222from models .account import TenantAccountRole
23+ from services .retention .workflow_run .archive_deletion_task import WorkflowRunArchiveDeletionStatus
2324from services .retention .workflow_run .archive_download_task import (
2425 WorkflowRunArchiveDownloadStatus ,
2526)
2627from services .retention .workflow_run .archive_log_service import (
27- WorkflowRunArchiveDownloadNotReadyError ,
28- WorkflowRunArchiveDownloadTaskNotFoundError ,
29- WorkflowRunArchiveNotFoundError ,
28+ WorkflowRunArchiveInvalidMonthError ,
3029)
3130
3231_WORKFLOW_RUN_ARCHIVE_ALLOWED_ROLES = frozenset ({TenantAccountRole .OWNER , TenantAccountRole .ADMIN })
3534class WorkflowRunArchiveDownloadPayload (BaseModel ):
3635 """Request body for preparing one monthly workflow-run archive download."""
3736
38- year : int = Field (ge = 1 )
37+ year : int = Field (ge = 1 , le = 9999 )
3938 month : int = Field (ge = 1 , le = 12 )
4039
4140
@@ -72,6 +71,21 @@ class WorkflowRunArchiveMonthResponse(ResponseModel):
7271 archive_bytes : int
7372 latest_archived_at : datetime .datetime
7473 download_task : WorkflowRunArchiveDownloadTaskResponse | None = None
74+ deletion_status : (
75+ Literal [
76+ WorkflowRunArchiveDeletionStatus .PENDING ,
77+ WorkflowRunArchiveDeletionStatus .PROCESSING ,
78+ WorkflowRunArchiveDeletionStatus .FAILED ,
79+ ]
80+ | None
81+ ) = None
82+
83+
84+ class WorkflowRunArchiveDeletionTaskResponse (ResponseModel ):
85+ year : int
86+ month : int
87+ status : WorkflowRunArchiveDeletionStatus
88+ error : str | None = None
7589
7690
7791class WorkflowRunArchiveListResponse (ResponseModel ):
@@ -86,6 +100,7 @@ class WorkflowRunArchiveListResponse(ResponseModel):
86100 WorkflowRunArchiveMonthResponse ,
87101 WorkflowRunArchiveListResponse ,
88102 WorkflowRunArchiveDownloadTaskResponse ,
103+ WorkflowRunArchiveDeletionTaskResponse ,
89104 RedirectResponse ,
90105)
91106
@@ -105,6 +120,38 @@ def get(self, request_context: RequestContext):
105120 return dump_response (WorkflowRunArchiveListResponse , archives )
106121
107122
123+ @console_ns .route ("/workflow-run-archives/<int:year>/<int:month>" )
124+ class WorkflowRunArchiveMonthApi (Resource ):
125+ @console_ns .doc ("delete_workflow_run_archive" )
126+ @console_ns .doc (description = "Permanently delete this workspace's monthly archive files and archive index" )
127+ @console_ns .doc (
128+ params = {
129+ "year" : {"in" : "path" , "type" : "integer" , "minimum" : 1 , "maximum" : 9999 },
130+ "month" : {"in" : "path" , "type" : "integer" , "minimum" : 1 , "maximum" : 12 },
131+ }
132+ )
133+ @console_ns .response (
134+ HTTPStatus .ACCEPTED ,
135+ "Archive deletion accepted" ,
136+ console_ns .models [WorkflowRunArchiveDeletionTaskResponse .__name__ ],
137+ )
138+ @console_account_admission (
139+ editions = frozenset ({DeploymentEdition .CLOUD }),
140+ # shortcut: allowed_roles only applies with RBAC disabled; add RBAC checks here when enabling it.
141+ allowed_roles = frozenset ({TenantAccountRole .OWNER }),
142+ )
143+ @cloud_edition_billing_paid_plan_required
144+ def delete (self , request_context : RequestContext , year : int , month : int ):
145+ try :
146+ archive_month = WorkflowRunArchiveDownloadPayload (year = year , month = month )
147+ except ValidationError as exc :
148+ raise WorkflowRunArchiveInvalidMonthError (str (exc )) from exc
149+ task = application_services ().workflow_run_archives .delete_archive (
150+ request_context , year = archive_month .year , month = archive_month .month
151+ )
152+ return dump_response (WorkflowRunArchiveDeletionTaskResponse , task ), HTTPStatus .ACCEPTED
153+
154+
108155@console_ns .route ("/workflow-run-archives/downloads" )
109156class WorkflowRunArchiveDownloadsApi (Resource ):
110157 @console_ns .doc ("create_workflow_run_archive_download" )
@@ -122,14 +169,11 @@ class WorkflowRunArchiveDownloadsApi(Resource):
122169 @cloud_edition_billing_paid_plan_required
123170 @model_validate (WorkflowRunArchiveDownloadPayload )
124171 def post (self , req_data : WorkflowRunArchiveDownloadPayload , request_context : RequestContext ):
125- try :
126- task = application_services ().workflow_run_archives .create_download (
127- request_context ,
128- year = req_data .year ,
129- month = req_data .month ,
130- )
131- except WorkflowRunArchiveNotFoundError as exc :
132- raise NotFound (str (exc )) from exc
172+ task = application_services ().workflow_run_archives .create_download (
173+ request_context ,
174+ year = req_data .year ,
175+ month = req_data .month ,
176+ )
133177 return dump_response (WorkflowRunArchiveDownloadTaskResponse , task ), HTTPStatus .ACCEPTED
134178
135179
@@ -144,13 +188,10 @@ class WorkflowRunArchiveDownloadApi(Resource):
144188 )
145189 @cloud_edition_billing_paid_plan_required
146190 def get (self , request_context : RequestContext , download_id : str ):
147- try :
148- task = application_services ().workflow_run_archives .get_download (
149- request_context ,
150- download_id = download_id ,
151- )
152- except WorkflowRunArchiveDownloadTaskNotFoundError as exc :
153- raise NotFound (str (exc )) from exc
191+ task = application_services ().workflow_run_archives .get_download (
192+ request_context ,
193+ download_id = download_id ,
194+ )
154195 return dump_response (WorkflowRunArchiveDownloadTaskResponse , task )
155196
156197
@@ -170,13 +211,8 @@ class WorkflowRunArchiveDownloadFileApi(Resource):
170211 )
171212 @cloud_edition_billing_paid_plan_required
172213 def get (self , request_context : RequestContext , download_id : str ):
173- try :
174- presigned_url = application_services ().workflow_run_archives .get_download_url (
175- request_context ,
176- download_id = download_id ,
177- )
178- except WorkflowRunArchiveDownloadTaskNotFoundError as exc :
179- raise NotFound (str (exc )) from exc
180- except WorkflowRunArchiveDownloadNotReadyError as exc :
181- raise Conflict (str (exc )) from exc
214+ presigned_url = application_services ().workflow_run_archives .get_download_url (
215+ request_context ,
216+ download_id = download_id ,
217+ )
182218 return redirect (presigned_url , code = HTTPStatus .FOUND )
0 commit comments