Coverage for functions \ flipdare \ mailer \ user \ voting_email.py: 85%
68 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 __future__ import annotations
15from typing import Literal, Self, override
16from flipdare.app_globals import truncate_string
17from flipdare.mailer._jinja_email_template import JinjaEmailTemplate
18from flipdare.mailer.app_email_params import AppEmailParams
19from flipdare.mailer.app_email_type import AppEmailType
20from flipdare.generated.schema.email.subject.user.vote_subject_schema import VoteSubjectSchema
21from flipdare.generated.schema.email.body.user.voting_email_schema import VotingEmailSchema
22from flipdare.generated.shared.app_deep_link import AppDeepLink
23from flipdare.generated.shared.model.dare.ballot_result import BallotResult
24from flipdare.message.vote_message import VoteMessage
25from flipdare.wrapper import DareWrapper, UserWrapper
27__all__ = ["VotingEmail"]
29type VotingEmailType = Literal[
30 AppEmailType.USR_VOTE_STARTED,
31 AppEmailType.USR_VOTE_REMINDER,
32 AppEmailType.USR_VOTE_DECISION,
33]
36class VotingEmail(JinjaEmailTemplate[VotingEmailSchema]):
38 SCHEMA_CLASS = VotingEmailSchema
40 def __init__(
41 self,
42 to_user: UserWrapper,
43 voting_email_type: VotingEmailType,
44 dare_id: str,
45 dare_name: str,
46 title: str,
47 status_str: str,
48 description: str,
49 ) -> None:
50 data = self._build_data(
51 to_user=to_user,
52 dare_id=dare_id,
53 title=title,
54 description=description,
55 status_str=status_str,
56 )
58 super().__init__(
59 data=data,
60 params=AppEmailParams(
61 email_type=voting_email_type,
62 schema=VoteSubjectSchema(
63 name=dare_name,
64 ),
65 ),
66 )
68 @classmethod
69 def from_dare(
70 cls,
71 dare: DareWrapper,
72 to_user: UserWrapper,
73 ) -> Self:
74 dare_id = dare.doc_id
75 dare_name = dare.short_description
76 status_str = VoteMessage.STARTED
78 return cls(
79 to_user=to_user,
80 dare_id=dare_id,
81 dare_name=dare_name,
82 title=dare.title,
83 description=dare.message,
84 status_str=status_str,
85 voting_email_type=AppEmailType.USR_VOTE_STARTED,
86 )
88 @classmethod
89 def from_dare_result(
90 cls,
91 dare: DareWrapper,
92 to_user: UserWrapper,
93 result: BallotResult | None = None,
94 ) -> Self:
95 dare_id = dare.doc_id
96 dare_name = dare.short_description
97 status_str = VoteMessage.from_result(result)
99 return cls(
100 to_user=to_user,
101 dare_id=dare_id,
102 dare_name=dare_name,
103 title=dare.title,
104 description=dare.message,
105 status_str=status_str,
106 voting_email_type=VotingEmail.type_from_result(result),
107 )
109 @staticmethod
110 def type_from_result(result: BallotResult | None) -> VotingEmailType:
111 if result is None:
112 return AppEmailType.USR_VOTE_STARTED
114 match result:
115 case (
116 BallotResult.TIE
117 | BallotResult.EXPIRED
118 | BallotResult.ACCEPTED
119 | BallotResult.AUTO_ACCEPTED
120 | BallotResult.REJECTED
121 | BallotResult.AUTO_REJECTED
122 ):
123 return AppEmailType.USR_VOTE_DECISION
124 case BallotResult.NOT_ENOUGH_VOTES:
125 return AppEmailType.USR_VOTE_REMINDER
127 @override
128 def newline_fields(self) -> list[str]:
129 return ["description"]
131 @property
132 @override
133 def data(self) -> VotingEmailSchema:
134 assert isinstance(self._data, dict) # narrowing, we known we have a dict..
135 return self._data
137 @property
138 def status(self) -> str:
139 return self.data["status"]
141 @property
142 def dare_link(self) -> str:
143 return self.data["dare_link"]
145 @property
146 def dare_link_text(self) -> str:
147 return self.data["dare_link_text"]
149 @property
150 def to_name(self) -> str:
151 return self.data["to_name"]
153 @property
154 def description(self) -> str:
155 return self.data["description"]
157 def _build_data(
158 self,
159 to_user: UserWrapper,
160 dare_id: str,
161 title: str,
162 description: str,
163 status_str: str,
164 ) -> VotingEmailSchema:
166 to_name = to_user.model.contact_name
167 dare_link = AppDeepLink.DARE.app_link(dare_id)
168 dare_link_text = truncate_string(title)
170 return VotingEmailSchema(
171 to_name=to_name,
172 status=status_str,
173 dare_link=dare_link,
174 dare_link_text=dare_link_text,
175 description=description,
176 )