Coverage for functions \ flipdare \ mailer \ user \ dared_email.py: 74%

87 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 

14from enum import StrEnum 

15from typing import Any, Self, override 

16from flipdare.mailer._jinja_email_template import JinjaEmailTemplate 

17from flipdare.mailer.app_email_params import AppEmailParams 

18from flipdare.mailer.app_email_type import AppEmailType 

19from flipdare.generated.schema.email.body.user.dared_email_schema import DaredEmailSchema 

20from flipdare.generated.schema.email.subject.user.dare_subject_schema import DareSubjectSchema 

21from flipdare.generated.schema.email.subject.user.group_dare_subject_schema import ( 

22 GroupDareSubjectSchema, 

23) 

24from flipdare.generated.shared.app_deep_link import AppDeepLink 

25from flipdare.wrapper import DareWrapper, UserWrapper 

26 

27__all__ = ["DaredEmail"] 

28 

29 

30class DaredEmailType(StrEnum): 

31 CREATE = "creation" 

32 RESPONSE = "response" 

33 COMPLETE = "complete" 

34 

35 @property 

36 def is_complete(self) -> bool: 

37 return self == DaredEmailType.COMPLETE 

38 

39 @property 

40 def is_response(self) -> bool: 

41 return self == DaredEmailType.RESPONSE 

42 

43 

44class DaredEmail(JinjaEmailTemplate[DaredEmailSchema]): 

45 

46 SCHEMA_CLASS = DaredEmailSchema 

47 

48 def __init__(self, data: DaredEmailSchema, params: AppEmailParams[Any]) -> None: 

49 super().__init__( 

50 data=data, 

51 params=params, 

52 ) 

53 

54 @classmethod 

55 def group_dare( 

56 cls, 

57 dare: DareWrapper, 

58 to_user: UserWrapper, 

59 from_user: UserWrapper, 

60 group_name: str, 

61 dared_email_type: DaredEmailType, 

62 ) -> Self: 

63 from_model = from_user.model 

64 to_model = to_user.model 

65 is_complete = dared_email_type.is_complete 

66 

67 to_name = from_model.contact_name if is_complete else to_model.contact_name 

68 

69 email_type: AppEmailType 

70 match dared_email_type: 

71 case DaredEmailType.COMPLETE: 

72 email_type = AppEmailType.USR_GROUP_DARED_COMPLETE 

73 case DaredEmailType.RESPONSE: 

74 email_type = AppEmailType.USR_GROUP_DARED_RESPONSE 

75 case DaredEmailType.CREATE: 

76 email_type = AppEmailType.USR_GROUP_DARED 

77 

78 data = cls._build_data( 

79 dare=dare, 

80 to_name=to_name, 

81 name=group_name, 

82 dared_email_type=dared_email_type, 

83 ) 

84 

85 ctx = GroupDareSubjectSchema( 

86 name=group_name, 

87 group_name=group_name, 

88 ) 

89 

90 return cls( 

91 data=data, 

92 params=AppEmailParams( 

93 email_type=email_type, 

94 schema=ctx, 

95 ), 

96 ) 

97 

98 @classmethod 

99 def dare( 

100 cls, 

101 dare: DareWrapper, 

102 to_user: UserWrapper, 

103 from_user: UserWrapper, 

104 dared_email_type: DaredEmailType, 

105 ) -> Self: 

106 is_complete = dared_email_type.is_complete 

107 

108 to_name = from_user.contact_name if is_complete else to_user.contact_name 

109 name = to_user.contact_name if is_complete else from_user.contact_name 

110 

111 email_type: AppEmailType 

112 match dared_email_type: 

113 case DaredEmailType.COMPLETE: 

114 email_type = AppEmailType.USR_DARED_COMPLETE 

115 case DaredEmailType.RESPONSE: 

116 email_type = AppEmailType.USR_DARED_RESPONSE 

117 case DaredEmailType.CREATE: 

118 email_type = AppEmailType.USR_DARED 

119 

120 ctx = DareSubjectSchema( 

121 name=name, 

122 dare_name=dare.short_description, 

123 ) 

124 

125 data = cls._build_data( 

126 dare=dare, 

127 to_name=to_name, 

128 name=name, 

129 dared_email_type=dared_email_type, 

130 ) 

131 

132 return cls( 

133 data=data, 

134 params=AppEmailParams( 

135 email_type=email_type, 

136 schema=ctx, 

137 ), 

138 ) 

139 

140 @staticmethod 

141 def _build_data( 

142 dare: DareWrapper, 

143 to_name: str, 

144 name: str, 

145 dared_email_type: DaredEmailType, 

146 ) -> DaredEmailSchema: 

147 message: str = dare.message 

148 app_link = AppDeepLink.DARE.app_link(dare.doc_id) 

149 

150 return DaredEmailSchema( 

151 { 

152 "to_name": to_name, 

153 "name": name, 

154 "is_response": dared_email_type.is_response, 

155 "is_complete": dared_email_type.is_complete, 

156 "message": message, 

157 "app_link": app_link, 

158 }, 

159 ) 

160 

161 @override 

162 def newline_fields(self) -> list[str]: 

163 return ["message"] 

164 

165 @property 

166 @override 

167 def data(self) -> DaredEmailSchema: 

168 assert isinstance(self._data, dict) # narrowing, we known we have a dict.. 

169 return self._data 

170 

171 @property 

172 def is_complete(self) -> bool: 

173 return self.data["is_complete"] 

174 

175 @property 

176 def is_response(self) -> bool: 

177 return self.data["is_response"] 

178 

179 @property 

180 def app_link(self) -> str: 

181 return self.data["app_link"] 

182 

183 @property 

184 def to_name(self) -> str: 

185 return self.data["to_name"] 

186 

187 @property 

188 def name(self) -> str: 

189 return self.data["name"] 

190 

191 @property 

192 def message(self) -> str: 

193 return self.data["message"]