Coverage for functions \ flipdare \ generated \ model \ backend \ user_summary_entry_model.py: 81%
128 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#
3# Copyright (c) 2026 Flipdare Pty Ltd. All rights reserved.
4#
5# This file is part of Flipdare's proprietary software and contains
6# confidential and copyrighted material. Unauthorised copying,
7# modification, distribution, or use of this file is strictly
8# prohibited without prior written permission from Flipdare Pty Ltd.
9#
10# This software includes third-party components licensed under MIT,
11# BSD, and Apache 2.0 licences. See THIRD_PARTY_NOTICES for details.
12#
13# NOTE: THIS FILE IS AUTO GENERATED. DO NOT EDIT.
14#
15# Generated by codegen_models.py
16#
17# Modify 'codegen_models.py'
18# and re-run the script above to update.
19#
20from __future__ import annotations
21from datetime import datetime
22from google.cloud.firestore_v1.transforms import Sentinel
23from flipdare.core.firestore_field import FirestoreField
24from flipdare.util.time_util import FirestoreTime
25from typing import Any, TypedDict, cast, Unpack
26from enum import StrEnum
27from pydantic import Field, ConfigDict, TypeAdapter
28from flipdare.firestore.core.app_base_model import AppBaseModel
29from flipdare.generated.shared.backend.summary_email_entry_type import SummaryEmailEntryType
30from flipdare.generated.shared.backend.summary_email_category import SummaryEmailCategory
31from flipdare.generated.model.internal.image_model import ImageModel, ImageDict
34class UserSummaryEntryKeys(StrEnum):
35 ID = "id"
36 CREATED_AT = "created_at"
37 UPDATED_AT = "updated_at"
38 OBJ_ID = "obj_id"
39 ENTRY_TYPE = "entry_type"
40 CATEGORY = "category"
41 FROM_NAME = "from_name"
42 IMAGE = "image"
43 TO_NAME = "to_name"
44 GROUP_NAME = "group_name"
45 MEMBER_NAME = "member_name"
46 PLEDGE_AMOUNT = "pledge_amount"
47 TOTAL_AMOUNT = "total_amount"
48 DESCRIPTION = "description"
49 ACCEPTED_NAME = "accepted_name"
52# !! IMPORTANT !!
53# !!
54# !! this should only be used in the database to query.
55# !!
56class UserSummaryEntryInternalKeys(StrEnum):
57 CREATED_AT = "created_at"
58 UPDATED_AT = "updated_at"
61class UserSummaryEntryModel(AppBaseModel):
62 """Represents a user summary email."""
64 model_config = ConfigDict(populate_by_name=True, arbitrary_types_allowed=True)
66 id: str | None = Field(None, alias="id")
67 created_at: FirestoreField = Field(
68 default_factory=cast("Any", lambda: FirestoreTime.server_timestamp())
69 )
70 updated_at: FirestoreField = Field(
71 default_factory=cast("Any", lambda: FirestoreTime.server_timestamp())
72 )
73 obj_id: str | None = None
74 entry_type: SummaryEmailEntryType
75 category: SummaryEmailCategory
76 from_name: str
77 image: ImageModel | None = None
78 to_name: str | None = None
79 group_name: str | None = None
80 member_name: str | None = None
81 pledge_amount: int | None = None
82 total_amount: int | None = None
83 description: str | None = None
84 accepted_name: str | None = None
86 @classmethod
87 def validate_partial(cls, **data: Unpack[UserSummaryEntryDict]) -> dict[str, Any]:
88 """
89 Uses Unpack to give you autocomplete and static warnings
90 if you pass an invalid key or type in your code.
92 Returns a dict with Firestore field names (aliases) for use with batch.update().
93 """
94 result: dict[str, Any] = {}
95 for k, v in data.items():
96 if k in cls.__pydantic_fields__:
97 field_info = cls.__pydantic_fields__[k]
98 validated_value = cast(
99 "Any",
100 TypeAdapter(field_info.annotation).validate_python(v),
101 )
102 # Use alias if defined, otherwise use field name
103 output_key = field_info.alias or k
104 result[output_key] = validated_value
105 return result
107 # ---- Convenience factories -----------------------------------------
108 @classmethod
109 def create_friend_request(
110 cls,
111 from_name: str,
112 from_uid: str,
113 to_name: str,
114 is_accepted: bool,
115 from_avatar: ImageModel | None = None,
116 ) -> UserSummaryEntryModel:
117 entry_type: SummaryEmailEntryType
118 actual_from_name: str
119 actual_to_name: str
120 if is_accepted:
121 entry_type = SummaryEmailEntryType.FRIEND_REQUEST_ACCEPTED
122 actual_from_name = to_name
123 actual_to_name = from_name
124 else:
125 entry_type = SummaryEmailEntryType.FRIEND_REQUEST
126 actual_from_name = from_name
127 actual_to_name = to_name
129 return cls(
130 id=None,
131 entry_type=entry_type,
132 category=SummaryEmailCategory.FRIEND,
133 from_name=actual_from_name,
134 image=from_avatar,
135 obj_id=from_uid,
136 to_name=actual_to_name,
137 )
139 @classmethod
140 def create_count(
141 cls,
142 from_name: str,
143 entry_type: SummaryEmailEntryType,
144 from_avatar: ImageModel,
145 ) -> UserSummaryEntryModel:
146 if entry_type not in [
147 SummaryEmailEntryType.NEW_LIKE,
148 SummaryEmailEntryType.NEW_VIEW,
149 SummaryEmailEntryType.NEW_FOLLOWER,
150 ]:
151 msg = f"Invalid entry_type for create_count: {entry_type}"
152 raise ValueError(msg)
154 return cls(
155 id=None,
156 entry_type=entry_type,
157 category=SummaryEmailCategory.FRIEND,
158 from_name=from_name,
159 image=from_avatar,
160 )
162 @classmethod
163 def create_group_request(
164 cls,
165 owner_name: str,
166 group_name: str,
167 obj_id: str,
168 avatar: ImageModel,
169 member_name: str,
170 short_description: str,
171 is_accepted: bool,
172 ) -> UserSummaryEntryModel:
173 entry_type: SummaryEmailEntryType
174 from_name: str
175 to_name: str
177 if is_accepted:
178 entry_type = SummaryEmailEntryType.GROUP_REQUEST_ACCEPTED
179 from_name = member_name
180 to_name = owner_name
181 else:
182 entry_type = SummaryEmailEntryType.GROUP_REQUEST
183 from_name = owner_name
184 to_name = member_name
186 return cls(
187 id=None,
188 entry_type=entry_type,
189 category=SummaryEmailCategory.GROUP,
190 from_name=from_name,
191 image=avatar,
192 obj_id=obj_id,
193 to_name=to_name,
194 group_name=group_name,
195 description=short_description,
196 )
198 @classmethod
199 def create_dare(
200 cls,
201 from_name: str,
202 to_name: str,
203 obj_id: str,
204 short_description: str,
205 entry_type: SummaryEmailEntryType,
206 avatar: ImageModel | None = None,
207 ) -> UserSummaryEntryModel:
208 if entry_type not in [
209 SummaryEmailEntryType.DARE_REQUEST,
210 SummaryEmailEntryType.DARE_ACCEPTED,
211 SummaryEmailEntryType.DARE_COMPLETED,
212 ]:
213 msg = f"Invalid entry_type for create_dare: {entry_type}"
214 raise ValueError(msg)
216 return cls(
217 id=None,
218 entry_type=entry_type,
219 category=SummaryEmailCategory.DARE,
220 from_name=from_name,
221 to_name=to_name,
222 image=avatar,
223 obj_id=obj_id,
224 description=short_description,
225 )
227 @classmethod
228 def create_group_dare(
229 cls,
230 owner_name: str,
231 group_name: str,
232 obj_id: str,
233 avatar: ImageModel,
234 short_description: str,
235 entry_type: SummaryEmailEntryType,
236 member_name: str | None = None,
237 accepted_name: str | None = None,
238 ) -> UserSummaryEntryModel:
239 if entry_type not in [
240 SummaryEmailEntryType.GROUP_DARE_SENT,
241 SummaryEmailEntryType.GROUP_DARE_ACCEPTED,
242 SummaryEmailEntryType.GROUP_DARE_COMPLETED,
243 ]:
244 msg = f"Invalid entry_type for create_group_dare: {entry_type}"
245 raise ValueError(msg)
247 if (
248 entry_type
249 in (
250 SummaryEmailEntryType.GROUP_DARE_ACCEPTED,
251 SummaryEmailEntryType.GROUP_DARE_COMPLETED,
252 )
253 and accepted_name is None
254 ):
255 msg = "accepted_name should not be None for ACCEPTED/COMPLETED email type"
256 raise ValueError(msg)
258 return cls(
259 id=None,
260 entry_type=entry_type,
261 category=SummaryEmailCategory.GROUP,
262 from_name=owner_name,
263 image=avatar,
264 obj_id=obj_id,
265 to_name=member_name,
266 group_name=group_name,
267 description=short_description,
268 accepted_name=accepted_name,
269 )
271 @classmethod
272 def create_pledge_received(
273 cls,
274 from_name: str,
275 obj_id: str,
276 from_avatar: ImageModel,
277 pledge_amount: int,
278 total_amount: int,
279 short_description: str,
280 is_failed: bool,
281 ) -> UserSummaryEntryModel:
282 entry_type: SummaryEmailEntryType
283 if is_failed:
284 entry_type = SummaryEmailEntryType.PLEDGE_FAILED
285 else:
286 entry_type = SummaryEmailEntryType.PLEDGE_PROCESSED
288 return cls(
289 id=None,
290 entry_type=entry_type,
291 category=SummaryEmailCategory.PLEDGE,
292 from_name=from_name,
293 image=from_avatar,
294 obj_id=obj_id,
295 pledge_amount=pledge_amount,
296 total_amount=total_amount,
297 description=short_description,
298 )
300 @classmethod
301 def create_pledge_sent(
302 cls,
303 from_name: str,
304 obj_id: str,
305 from_avatar: ImageModel,
306 pledge_amount: int,
307 total_amount: int,
308 short_description: str,
309 is_complete: bool,
310 ) -> UserSummaryEntryModel:
311 entry_type: SummaryEmailEntryType
312 if is_complete:
313 entry_type = SummaryEmailEntryType.PLEDGE_PAYMENT_COMPLETE
314 else:
315 entry_type = SummaryEmailEntryType.PLEDGE_PAYMENT_NOTICE
317 return cls(
318 id=None,
319 entry_type=entry_type,
320 category=SummaryEmailCategory.PLEDGE,
321 from_name=from_name,
322 image=from_avatar,
323 obj_id=obj_id,
324 pledge_amount=pledge_amount,
325 total_amount=total_amount,
326 description=short_description,
327 )
330USERSUMMARYENTRY_FIELD_NAMES: list[str] = list(UserSummaryEntryModel.model_fields.keys())
333class UserSummaryEntryDict(TypedDict, total=False):
334 id: str | None
335 created_at: Sentinel | datetime | str
336 updated_at: Sentinel | datetime | str
337 obj_id: str | None
338 entry_type: SummaryEmailEntryType
339 category: SummaryEmailCategory
340 from_name: str
341 image: ImageDict | None
342 to_name: str | None
343 group_name: str | None
344 member_name: str | None
345 pledge_amount: int | None
346 total_amount: int | None
347 description: str | None
348 accepted_name: str | None