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

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# NOTE: triggers should be as lightweight as possible, just creating jobs for processing 

14 

15 

16from typing import Any 

17from firebase_functions import firestore_fn 

18 

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 

38 

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] 

61 

62 

63# 

64# User 

65# 

66 

67 

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) 

71 

72 

73@firestore_fn.on_document_updated(document="user/{doc_id}") 

74def tr_user_update(event: UpdateEventType) -> None: 

75 _upd(UserWrapper, AppJobType.TR_USER, event) 

76 

77 

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) 

81 

82 

83# 

84# Invite 

85# 

86 

87 

88@firestore_fn.on_document_created(document="invite/{doc_id}") 

89def tr_invite_new(event: BaseEventType) -> None: 

90 _new(InviteWrapper, AppJobType.TR_INVITE, event) 

91 

92 

93@firestore_fn.on_document_updated(document="invite/{doc_id}") 

94def tr_invite_update(event: UpdateEventType) -> None: 

95 _upd(InviteWrapper, AppJobType.TR_INVITE, event) 

96 

97 

98# 

99# Friend 

100# 

101 

102 

103@firestore_fn.on_document_created(document="friend/{doc_id}") 

104def tr_friend_new(event: BaseEventType) -> None: 

105 _new(FriendWrapper, AppJobType.TR_FRIEND, event) 

106 

107 

108@firestore_fn.on_document_updated(document="friend/{doc_id}") 

109def tr_friend_updated(event: UpdateEventType) -> None: 

110 _upd(FriendWrapper, AppJobType.TR_FRIEND, event) 

111 

112 

113# 

114# Chat 

115# 

116 

117 

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) 

121 

122 

123# 

124# dare 

125# 

126 

127 

128@firestore_fn.on_document_created(document="dare/{doc_id}") 

129def tr_dare_new(event: BaseEventType) -> None: 

130 _new(DareWrapper, AppJobType.TR_DARE, event) 

131 

132 

133@firestore_fn.on_document_updated(document="dare/{doc_id}") 

134def tr_dare_update(event: UpdateEventType) -> None: 

135 _upd(DareWrapper, AppJobType.TR_DARE, event) 

136 

137 

138# 

139# Group 

140# 

141 

142 

143@firestore_fn.on_document_created(document="group/{doc_id}") 

144def tr_group_created(event: BaseEventType) -> None: 

145 _new(GroupWrapper, AppJobType.TR_GROUP, event) 

146 

147 

148@firestore_fn.on_document_updated(document="group/{doc_id}") 

149def tr_group_updated(event: UpdateEventType) -> None: 

150 _upd(GroupWrapper, AppJobType.TR_GROUP, event) 

151 

152 

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) 

156 

157 

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) 

161 

162 

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) 

166 

167 

168# 

169# flag 

170# 

171 

172 

173@firestore_fn.on_document_created(document="flag/{doc_id}") 

174def tr_flag_created(event: BaseEventType) -> None: 

175 _new(FlagWrapper, AppJobType.TR_FLAG, event) 

176 

177 

178@firestore_fn.on_document_updated(document="flag/{doc_id}") 

179def tr_flag_updated(event: UpdateEventType) -> None: 

180 _upd(FlagWrapper, AppJobType.TR_FLAG, event) 

181 

182 

183# 

184# Pledge 

185# 

186 

187 

188@firestore_fn.on_document_created(document="pledge/{doc_id}") 

189def tr_pledge_created(event: BaseEventType) -> None: 

190 _new(PledgeWrapper, AppJobType.TR_PLEDGE, event) 

191 

192 

193@firestore_fn.on_document_updated(document="pledge/{doc_id}") 

194def tr_pledge_updated(event: UpdateEventType) -> None: 

195 _upd(PledgeWrapper, AppJobType.TR_PLEDGE, event) 

196 

197 

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. 

204 

205 

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) 

209 

210 

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) 

214 

215 

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) 

219 

220 

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) 

224 

225 

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) 

229 

230 

231# -------------------------------------------------------------------------------------------------- 

232# HELPERS 

233# -------------------------------------------------------------------------------------------------- 

234 

235 

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 ) 

248 

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}") 

252 

253 

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 ) 

266 

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}") 

270 

271 

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 ) 

284 

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}") 

288 

289 

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 ) 

302 

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}")