1
1
import json
2
+ import uuid
2
3
from http import HTTPStatus
3
4
4
5
import flask
13
14
InventoryReportCollectionInfo ,
14
15
InventoryReportInfo ,
15
16
)
16
- from palace .manager .api .admin .problem_details import ADMIN_NOT_AUTHORIZED
17
+ from palace .manager .api .admin .problem_details import (
18
+ ADMIN_NOT_AUTHORIZED ,
19
+ INVALID_REPORT_KEY ,
20
+ )
17
21
from palace .manager .celery .tasks .generate_inventory_and_hold_reports import (
18
22
generate_inventory_and_hold_reports ,
19
23
library_report_integrations ,
20
24
)
25
+ from palace .manager .celery .tasks .reports import (
26
+ REPORT_KEY_MAPPING ,
27
+ generate_report ,
28
+ )
21
29
from palace .manager .core .problem_details import INTERNAL_SERVER_ERROR
30
+ from palace .manager .reporting .reports .library_collection import LibraryCollectionReport
22
31
from palace .manager .service .integration_registry .license_providers import (
23
32
LicenseProvidersRegistry ,
24
33
)
27
36
from palace .manager .sqlalchemy .model .library import Library
28
37
from palace .manager .util .log import LoggerMixin
29
38
from palace .manager .util .problem_detail import ProblemDetail , ProblemDetailException
39
+ from palace .manager .util .uuid import uuid_encode
30
40
31
41
32
42
def _authorize_from_request (
@@ -36,7 +46,7 @@ def _authorize_from_request(
36
46
37
47
:param request: A Flask Request object.
38
48
:return: A 2-tuple of admin and library, if the admin is authorized for the library.
39
- :raise: ProblemDetailException, if no library or if admin not authorized for the library.
49
+ :raise: ProblemDetailException, if no library or if admin is not authorized for the library.
40
50
"""
41
51
library = required_library_from_request (request )
42
52
admin = required_admin_from_request (request )
@@ -46,10 +56,65 @@ def _authorize_from_request(
46
56
47
57
48
58
class ReportController (LoggerMixin ):
59
+
49
60
def __init__ (self , db : Session , registry : LicenseProvidersRegistry ):
50
61
self ._db = db
51
62
self .registry = registry
52
63
64
+ @classmethod
65
+ def report_for_key (cls , key : str ) -> type [LibraryCollectionReport ]:
66
+ if key not in REPORT_KEY_MAPPING :
67
+ detail = INVALID_REPORT_KEY .detail or "Unknown report key."
68
+ raise ProblemDetailException (
69
+ INVALID_REPORT_KEY .detailed (f"{ detail .rstrip ('. ' )} (key='{ key } ')." )
70
+ )
71
+ return REPORT_KEY_MAPPING [key ]
72
+
73
+ def generate_report (self , * , report_key : str ) -> Response :
74
+ """Generate the report indicated by the report_key."""
75
+
76
+ admin , library = _authorize_from_request (flask .request )
77
+ email_address = admin .email
78
+
79
+ report = self .report_for_key (report_key )
80
+ report_title = report .TITLE
81
+
82
+ request_id = uuid_encode (uuid .uuid4 ())
83
+
84
+ self .log .info (
85
+ f"Report '{ report_title } ' ({ report_key } ) requested by <{ email_address } >. (request ID: { request_id } )"
86
+ )
87
+ try :
88
+ task = generate_report .delay (
89
+ key = report_key ,
90
+ request_id = request_id ,
91
+ library_id = library .id ,
92
+ email_address = email_address ,
93
+ )
94
+ except Exception as e :
95
+ msg = f"Failed to generate report '{ report_title } ' ({ report_key } ). (request ID: { request_id } )"
96
+ self .log .error (msg = msg , exc_info = e )
97
+ self ._db .rollback ()
98
+ raise ProblemDetailException (
99
+ INTERNAL_SERVER_ERROR .detailed (detail = msg )
100
+ ) from e
101
+
102
+ self .log .info (
103
+ f"Report task created: '{ report_title } ' ({ report_key } ) for <{ email_address } >. "
104
+ f"(request ID: { request_id } , task ID: { task .id } )"
105
+ )
106
+
107
+ response_message = (
108
+ f"The '{ report_title } ' request was received. "
109
+ "Report processing may take a few minutes to complete, depending on current server load. "
110
+ f"Upon completion, a notification will be sent to { email_address } ."
111
+ )
112
+ return Response (
113
+ json .dumps ({"message" : response_message }),
114
+ HTTPStatus .ACCEPTED ,
115
+ mimetype = MediaTypes .APPLICATION_JSON_MEDIA_TYPE ,
116
+ )
117
+
53
118
def inventory_report_info (self ) -> Response :
54
119
"""InventoryReportInfo response of reportable collections for a library.
55
120
0 commit comments