Coverage for functions \ flipdare \ util \ template_file.py: 73%

62 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 

13 

14import re 

15from pathlib import Path 

16 

17from flipdare.result.app_result import AppResult 

18from flipdare.error.app_error import ServerError 

19from flipdare.generated.shared.app_error_code import AppErrorCode 

20 

21_error_type: AppErrorCode = AppErrorCode.EMAIL_TEMPLATE 

22 

23 

24class TemplateFile: 

25 

26 def __init__(self, file_path: Path) -> None: 

27 self._file_path = file_path 

28 

29 @property 

30 def file_path(self) -> Path: 

31 return self._file_path 

32 

33 @staticmethod 

34 def format_param(param_name: str) -> str: 

35 return f"__{param_name.upper()}__" 

36 

37 @staticmethod 

38 def format_param_regex() -> str: 

39 return r"__([A-Z0-9_]+)__" 

40 

41 @staticmethod 

42 def _get_actual_key(key: str, params: dict[str, str]) -> str: 

43 if key in params: 

44 return key 

45 if f"{key}_html" in params: 

46 return f"{key}_html" 

47 if f"{key}_text" in params: 

48 return f"{key}_text" 

49 return key 

50 

51 @staticmethod 

52 def valid(required: list[str], params: dict[str, str]) -> bool: 

53 missing = [] 

54 for key in required: 

55 actual_key = TemplateFile._get_actual_key(key, params) 

56 if actual_key not in params: 

57 missing.append(key) 

58 

59 if len(missing) <= 0: 

60 return True 

61 

62 raise ServerError( 

63 message=f"Missing required parameters: {', '.join(missing)}", 

64 error_code=_error_type, 

65 ) 

66 

67 def parse(self, params: dict[str, str], start_at: int = 0, end_at: int = -1) -> str: 

68 if not self._file_path.is_file(): 

69 raise ServerError( 

70 message=f"Template path not found {self._file_path}", 

71 error_code=_error_type, 

72 ) 

73 

74 result: AppResult = AppResult() 

75 

76 content = "" 

77 with self._file_path.open(encoding="utf-8") as file: 

78 content = file.read() 

79 

80 if end_at != -1: 

81 # split to lines, get the range, and re-join 

82 lines = content.splitlines() 

83 selected_lines = lines[start_at:end_at] 

84 content = "\n".join(selected_lines) 

85 

86 for key, value in params.items(): 

87 actual_key = self._get_actual_key(key, params) 

88 formatted_key = TemplateFile.format_param(actual_key) 

89 new_content = content.replace(formatted_key, value) 

90 if new_content == content: 

91 result.add_error(_error_type, f"Parameter {formatted_key} not found in template.") 

92 content = new_content 

93 

94 re_matches = re.findall(TemplateFile.format_param_regex(), content) 

95 for match in re_matches: 

96 result.add_error( 

97 _error_type, 

98 f"Parameter __{match}__ not found in provided parameters.", 

99 ) 

100 

101 if result.is_error: 

102 error_str = result.formatted 

103 raise ServerError(message=error_str, error_code=_error_type) 

104 

105 return content