Coverage for functions \ flipdare \ app_triggers.py: 60%
111 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#
13# NOTE: triggers should be as lightweight as possible, just creating jobs for processing
16from typing import Any
17from firebase_functions import firestore_fn
19from flipdare.app_log import LOG
20from flipdare.app_types import BaseEventType, UpdateEventType
21from flipdare.generated.shared.backend.app_job_type import AppJobType
22from flipdare.services import get_job_admin
23from flipdare.job.trigger_data import SubCollectionTriggerData, TriggerData, UpdateTriggerData
24from flipdare.wrapper import (
25 ChatCommentWrapper,
26 DareWrapper,
27 GroupMemberWrapper,
28 GroupWrapper,
29 InviteWrapper,
30 UserWrapper,
31)
32from flipdare.wrapper._persisted_wrapper import PersistedWrapper
33from flipdare.wrapper.chat_wrapper import ChatWrapper
34from flipdare.wrapper.content_wrapper import ContentWrapper
35from flipdare.wrapper.friend_wrapper import FriendWrapper
36from flipdare.wrapper.issue.flag_wrapper import FlagWrapper
37from flipdare.wrapper.payment.pledge_wrapper import PledgeWrapper
39__all__ = [
40 "tr_user_new",
41 "tr_user_update",
42 "tr_user_content_created",
43 "tr_invite_new",
44 "tr_invite_update",
45 "tr_friend_new",
46 "tr_friend_updated",
47 "tr_chat_comment_new",
48 "tr_dare_new",
49 "tr_dare_update",
50 "tr_dare_deleted",
51 "tr_group_created",
52 "tr_group_updated",
53 "tr_group_content_created",
54 "tr_group_member_created",
55 "tr_group_member_updated",
56 "tr_flag_created",
57 "tr_flag_updated",
58 "tr_pledge_created",
59 "tr_pledge_updated",
60]
63#
64# User
65#
68@firestore_fn.on_document_created(document="user/{doc_id}") # pyright: ignore[reportCallIssue]
69def tr_user_new(event: BaseEventType) -> None:
70 _new(UserWrapper, AppJobType.TR_USER, event)
73@firestore_fn.on_document_updated(document="user/{doc_id}")
74def tr_user_update(event: UpdateEventType) -> None:
75 _upd(UserWrapper, AppJobType.TR_USER, event)
78@firestore_fn.on_document_created(document="user_content/{doc_id}")
79def tr_user_content_created(event: BaseEventType) -> None:
80 _new(UserWrapper, AppJobType.TR_USER, event)
83#
84# Invite
85#
88@firestore_fn.on_document_created(document="invite/{doc_id}")
89def tr_invite_new(event: BaseEventType) -> None:
90 _new(InviteWrapper, AppJobType.TR_INVITE, event)
93@firestore_fn.on_document_updated(document="invite/{doc_id}")
94def tr_invite_update(event: UpdateEventType) -> None:
95 _upd(InviteWrapper, AppJobType.TR_INVITE, event)
98#
99# Friend
100#
103@firestore_fn.on_document_created(document="friend/{doc_id}")
104def tr_friend_new(event: BaseEventType) -> None:
105 _new(FriendWrapper, AppJobType.TR_FRIEND, event)
108@firestore_fn.on_document_updated(document="friend/{doc_id}")
109def tr_friend_updated(event: UpdateEventType) -> None:
110 _upd(FriendWrapper, AppJobType.TR_FRIEND, event)
113#
114# Chat
115#
118@firestore_fn.on_document_created(document="chat/{parent_id}/chat_comments/{doc_id}")
119def tr_chat_comment_new(event: BaseEventType) -> None:
120 _sub(ChatCommentWrapper, AppJobType.TR_CHAT, event)
123#
124# dare
125#
128@firestore_fn.on_document_created(document="dare/{doc_id}")
129def tr_dare_new(event: BaseEventType) -> None:
130 _new(DareWrapper, AppJobType.TR_DARE, event)
133@firestore_fn.on_document_updated(document="dare/{doc_id}")
134def tr_dare_update(event: UpdateEventType) -> None:
135 _upd(DareWrapper, AppJobType.TR_DARE, event)
138#
139# Group
140#
143@firestore_fn.on_document_created(document="group/{doc_id}")
144def tr_group_created(event: BaseEventType) -> None:
145 _new(GroupWrapper, AppJobType.TR_GROUP, event)
148@firestore_fn.on_document_updated(document="group/{doc_id}")
149def tr_group_updated(event: UpdateEventType) -> None:
150 _upd(GroupWrapper, AppJobType.TR_GROUP, event)
153@firestore_fn.on_document_created(document="group/{doc_id}")
154def tr_group_content_created(event: BaseEventType) -> None:
155 _new(GroupWrapper, AppJobType.TR_GROUP, event)
158@firestore_fn.on_document_created(document="group_member/{doc_id}")
159def tr_group_member_created(event: BaseEventType) -> None:
160 _new(GroupMemberWrapper, AppJobType.TR_GROUP_MEMBER, event)
163@firestore_fn.on_document_updated(document="group_member/{doc_id}")
164def tr_group_member_updated(event: UpdateEventType) -> None:
165 _upd(GroupMemberWrapper, AppJobType.TR_GROUP_MEMBER, event)
168#
169# flag
170#
173@firestore_fn.on_document_created(document="flag/{doc_id}")
174def tr_flag_created(event: BaseEventType) -> None:
175 _new(FlagWrapper, AppJobType.TR_FLAG, event)
178@firestore_fn.on_document_updated(document="flag/{doc_id}")
179def tr_flag_updated(event: UpdateEventType) -> None:
180 _upd(FlagWrapper, AppJobType.TR_FLAG, event)
183#
184# Pledge
185#
188@firestore_fn.on_document_created(document="pledge/{doc_id}")
189def tr_pledge_created(event: BaseEventType) -> None:
190 _new(PledgeWrapper, AppJobType.TR_PLEDGE, event)
193@firestore_fn.on_document_updated(document="pledge/{doc_id}")
194def tr_pledge_updated(event: UpdateEventType) -> None:
195 _upd(PledgeWrapper, AppJobType.TR_PLEDGE, event)
198#
199# deleted (for compliance)
200#
201# !! This is for compliance with various countries.
202# !! We move the object to a backup location for a certain period of time before permanent deletion.
203# !! This trigger should create a job to handle that backup and delayed deletion process.
206@firestore_fn.on_document_deleted(document="user/{doc_id}")
207def tr_user_deleted(event: BaseEventType) -> None:
208 _del(UserWrapper, AppJobType.TR_USER_ANONYMIZE, event)
211@firestore_fn.on_document_deleted(document="content/{doc_id}")
212def tr_content_deleted(event: BaseEventType) -> None:
213 _del(ContentWrapper, AppJobType.TR_CONTENT_DELETE, event)
216@firestore_fn.on_document_deleted(document="dare/{doc_id}")
217def tr_dare_deleted(event: BaseEventType) -> None:
218 _del(DareWrapper, AppJobType.TR_DARE_DELETE, event)
221@firestore_fn.on_document_deleted(document="chat/{doc_id}")
222def tr_chat_deleted(event: BaseEventType) -> None:
223 _del(ChatWrapper, AppJobType.TR_CHAT_DELETE, event)
226@firestore_fn.on_document_deleted(document="pledge/{doc_id}")
227def tr_pledge_deleted(event: BaseEventType) -> None:
228 _del(PledgeWrapper, AppJobType.TR_PLEDGE_DELETE, event)
231# --------------------------------------------------------------------------------------------------
232# HELPERS
233# --------------------------------------------------------------------------------------------------
236def _new[T: PersistedWrapper[Any]](
237 wrapper_class: type[T],
238 job_type: AppJobType,
239 event: BaseEventType,
240) -> None:
241 """Run a created-document trigger."""
242 try:
243 trigger_data = TriggerData(
244 job_type=job_type,
245 event=event,
246 wrapper_class=wrapper_class,
247 )
249 get_job_admin().trigger_job(job_type, trigger_data)
250 except Exception as e:
251 LOG().error(f"Error in trigger {job_type.label}: {e}")
254def _del[T: PersistedWrapper[Any]](
255 wrapper_class: type[T],
256 job_type: AppJobType,
257 event: BaseEventType,
258) -> None:
259 """Run a deleted-document trigger."""
260 try:
261 trigger_data = TriggerData(
262 job_type=job_type,
263 event=event,
264 wrapper_class=wrapper_class,
265 )
267 get_job_admin().trigger_job(job_type, trigger_data)
268 except Exception as e:
269 LOG().error(f"Error in trigger {job_type.label}: {e}")
272def _upd[T: PersistedWrapper[Any]](
273 wrapper_class: type[T],
274 job_type: AppJobType,
275 event: UpdateEventType,
276) -> None:
277 """Run an updated-document trigger."""
278 try:
279 trigger_data = UpdateTriggerData(
280 job_name=job_type,
281 event=event,
282 wrapper_class=wrapper_class,
283 )
285 get_job_admin().trigger_job(job_type, trigger_data)
286 except Exception as e:
287 LOG().error(f"Error in trigger {job_type.label}: {e}")
290def _sub[T: PersistedWrapper[Any]](
291 wrapper_class: type[T],
292 job_type: AppJobType,
293 event: BaseEventType,
294) -> None:
295 """Run a sub-collection created-document trigger."""
296 try:
297 trigger_data = SubCollectionTriggerData(
298 job_name=job_type,
299 event=event,
300 wrapper_class=wrapper_class,
301 )
303 get_job_admin().trigger_job(job_type, trigger_data)
304 except Exception as e:
305 LOG().error(f"Error in trigger {job_type.label}: {e}")