Coverage for functions \ flipdare \ task \ report \ core \ _admin_report.py: 90%
48 statements
« prev ^ index » next coverage.py v7.13.0, created at 2026-05-08 12:22 +1000
« prev ^ index » next coverage.py v7.13.0, created at 2026-05-08 12:22 +1000
1#!/usr/bin/env python
2# Copyright (c) 2026 Flipdare Pty Ltd. All rights reserved.
3#
4# This file is part of Flipdare's proprietary software and contains
5# confidential and copyrighted material. Unauthorised copying,
6# modification, distribution, or use of this file is strictly
7# prohibited without prior written permission from Flipdare Pty Ltd.
8#
9# This software includes third-party components licensed under MIT,
10# BSD, and Apache 2.0 licences. See THIRD_PARTY_NOTICES for details.
11#
13from abc import abstractmethod
14from typing import Any, override
15from flipdare.backend.app_logger import AppLogger
16from flipdare.app_log import LOG
17from flipdare.constants import IS_TRACE
18from flipdare.mailer._jinja_email_template import JinjaEmailTemplate
19from flipdare.mailer.core.email_composer import ComposedEmailResult, EmailComposer
20from flipdare.result.output_result import OutputResult
21from flipdare.mailer.admin.admin_report_email import AdminReportEmail
22from flipdare.mailer.admin_mailer import AdminMailer
23from flipdare.generated.shared.app_error_code import AppErrorCode
24from flipdare.generated.shared.backend.app_job_type import AppJobType
26from flipdare.task.report.core._base_report import BaseReport
27from flipdare.util.time_util import TimeUtil
30class AdminReport(BaseReport):
31 def __init__(
32 self,
33 job_type: AppJobType,
34 app_logger: AppLogger,
35 mailer: AdminMailer,
36 ) -> None:
37 super().__init__(
38 job_type=job_type,
39 app_logger=app_logger,
40 mailer=mailer,
41 )
43 @abstractmethod
44 def compose(self) -> EmailComposer | None: ...
46 def try_compose(self) -> ComposedEmailResult | OutputResult:
47 try:
48 report = self.compose()
49 if report is None:
50 msg = "No report data generated."
51 return self._error_result(
52 code=AppErrorCode.REPORT_DATA_GENERATION,
53 msg=msg,
54 )
56 result = report.load()
57 if result.is_error:
58 msg = f"Load Error: {result.error}"
59 return self._error_result(
60 code=AppErrorCode.REPORT_DATA_GENERATION,
61 msg=msg,
62 )
64 return result
65 except Exception as ex:
66 msg = f"Exception: {ex}"
67 return self._error_result(
68 code=AppErrorCode.REPORT,
69 msg=msg,
70 )
72 @override
73 def build_template(self) -> JinjaEmailTemplate[Any] | OutputResult:
74 result = self.try_compose()
75 if isinstance(result, OutputResult):
76 return result
78 now = TimeUtil.formatted_now()
79 html = result.html
80 text = result.text
81 images = result.images
82 priority = self.priority
83 report_name = self.report_name
84 description = self.report_description
85 error_str = self.error_string
87 if IS_TRACE:
88 msg = (
89 f"Preparing to send report email for {report_name} with priority {priority.name}\n"
90 f"Description: {description}\n"
91 f"Errors: {error_str or 'None'}\n"
92 f"HTML length: {len(html)} characters\n"
93 f"Text length: {len(text)} characters\n"
94 f"Number of images: {len(images) if images else 0}\n"
95 f"-------------- TEXT --------------\n"
96 f"{text}\n"
97 f"-------------- HTML --------------\n"
98 f"{html}\n"
99 )
100 LOG().trace(msg)
102 return AdminReportEmail(
103 report_name=report_name,
104 report_date=now,
105 report_description=description,
106 report_error=error_str,
107 html=html,
108 text=text,
109 priority=priority,
110 images=images,
111 )