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

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# 

12 

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 

25 

26from flipdare.task.report.core._base_report import BaseReport 

27from flipdare.util.time_util import TimeUtil 

28 

29 

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 ) 

42 

43 @abstractmethod 

44 def compose(self) -> EmailComposer | None: ... 

45 

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 ) 

55 

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 ) 

63 

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 ) 

71 

72 @override 

73 def build_template(self) -> JinjaEmailTemplate[Any] | OutputResult: 

74 result = self.try_compose() 

75 if isinstance(result, OutputResult): 

76 return result 

77 

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 

86 

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) 

101 

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 )