Coverage for src/couchers/notifications/render.py: 84%

196 statements  

« prev     ^ index     » next       coverage.py v7.5.0, created at 2024-12-29 01:26 +0000

1import logging 

2from dataclasses import dataclass 

3 

4from couchers import urls 

5from couchers.notifications.unsubscribe import generate_unsub_topic_action 

6from couchers.templates.v2 import v2avatar, v2date, v2esc, v2phone, v2timestamp 

7from proto import notification_data_pb2 

8 

9logger = logging.getLogger(__name__) 

10 

11 

12@dataclass(kw_only=True) 

13class RenderedNotification: 

14 # whether the notification is critical and cannot be turned off 

15 is_critical: bool = False 

16 # email subject 

17 email_subject: str 

18 # shows up when listing emails in many clients 

19 email_preview: str 

20 # corresponds to .mjml + .txt file in templates/v2 

21 email_template_name: str 

22 # other template args 

23 email_template_args: dict 

24 # the link label on the topic_action unsubscribe link 

25 email_topic_action_unsubscribe_text: str = None 

26 # the link label on the topic_key unsubscribe link 

27 email_topic_key_unsubscribe_text: str = None 

28 # url to unsubscribe with one click 

29 email_list_unsubscribe_url: str = None 

30 # push notification title 

31 push_title: str 

32 # push notification content 

33 push_body: str 

34 # url to an icon for push notifications 

35 push_icon: str 

36 # url to where clicking on the notification should take you 

37 push_url: str 

38 

39 

40def render_notification(user, notification) -> RenderedNotification: 

41 data = notification.topic_action.data_type.FromString(notification.data) 

42 if notification.topic == "host_request": 

43 view_link = urls.host_request(host_request_id=data.host_request.host_request_id) 

44 if notification.action == "missed_messages": 

45 their_your = "their" if data.am_host else "your" 

46 other = data.user 

47 # "declined your host request", or similar 

48 message = f"{other.name} sent you message(s) in {their_your} host request" 

49 return RenderedNotification( 

50 email_subject=message, 

51 email_preview=message, 

52 email_template_name="host_request__plain", 

53 email_template_args={ 

54 "view_link": view_link, 

55 "host_request": data.host_request, 

56 "message": message, 

57 "other": other, 

58 }, 

59 email_topic_action_unsubscribe_text="missed messages in host requests", 

60 push_title=message, 

61 push_body="Check the app for more info.", 

62 push_icon=v2avatar(other), 

63 push_url=view_link, 

64 ) 

65 elif notification.action in ["create", "message"]: 

66 if notification.action == "create": 

67 other = data.surfer 

68 message = f"{other.name} sent you a host request" 

69 topic_action_unsub_text = "new host requests" 

70 elif notification.action == "message": 

71 other = data.user 

72 if data.am_host: 

73 message = f"{other.name} sent you a message in their host request" 

74 else: 

75 message = f"{other.name} sent you a message in your host request" 

76 topic_action_unsub_text = "messages in host request" 

77 return RenderedNotification( 

78 email_subject=message, 

79 email_preview=message, 

80 email_template_name="host_request__message", 

81 email_template_args={ 

82 "view_link": view_link, 

83 "host_request": data.host_request, 

84 "message": message, 

85 "other": other, 

86 "text": data.text, 

87 }, 

88 email_topic_action_unsubscribe_text=topic_action_unsub_text, 

89 push_title=f"{message}", 

90 push_body=f"Dates: {v2date(data.host_request.from_date, user)} to {v2date(data.host_request.to_date, user)}.\n\n{data.text}", 

91 push_icon=v2avatar(other), 

92 push_url=view_link, 

93 ) 

94 elif notification.action in ["accept", "reject", "confirm", "cancel"]: 

95 if notification.action in ["accept", "reject"]: 

96 other = data.host 

97 their_your = "your" 

98 else: 

99 other = data.surfer 

100 their_your = "their" 

101 actioned = { 

102 "accept": "accepted", 

103 "reject": "declined", 

104 "confirm": "confirmed", 

105 "cancel": "cancelled", 

106 }[notification.action] 

107 # "declined your host request", or similar 

108 message = f"{other.name} {actioned} {their_your} host request" 

109 return RenderedNotification( 

110 email_subject=message, 

111 email_preview=message, 

112 email_template_name="host_request__plain", 

113 email_template_args={ 

114 "view_link": view_link, 

115 "host_request": data.host_request, 

116 "message": message, 

117 "other": other, 

118 }, 

119 email_topic_action_unsubscribe_text=f"{actioned} host requests", 

120 push_title=message, 

121 push_body="Check the app for more info.", 

122 push_icon=v2avatar(other), 

123 push_url=view_link, 

124 ) 

125 elif notification.topic_action.display == "password:change": 

126 title = "Your password was changed" 

127 message = "Your login password for Couchers.org was changed." 

128 return RenderedNotification( 

129 is_critical=True, 

130 email_subject=title, 

131 email_preview=message, 

132 email_template_name="security", 

133 email_template_args={ 

134 "title": title, 

135 "message": message, 

136 }, 

137 push_title=title, 

138 push_body=message, 

139 push_icon=urls.icon_url(), 

140 push_url=urls.account_settings_link(), 

141 ) 

142 elif notification.topic_action.display == "password_reset:start": 

143 message = "Someone initiated a password change on your account." 

144 return RenderedNotification( 

145 is_critical=True, 

146 email_subject="Reset your Couchers.org password", 

147 email_preview=message, 

148 email_template_name="password_reset", 

149 email_template_args={ 

150 "password_reset_link": urls.password_reset_link(password_reset_token=data.password_reset_token) 

151 }, 

152 push_title="A password reset was initiated on your account", 

153 push_body=message, 

154 push_icon=urls.icon_url(), 

155 push_url=urls.account_settings_link(), 

156 ) 

157 elif notification.topic_action.display == "password_reset:complete": 

158 title = "Your password was successfully reset" 

159 message = "Your password on Couchers.org was changed. If that was you, then no further action is needed." 

160 return RenderedNotification( 

161 is_critical=True, 

162 email_subject=title, 

163 email_preview=title, 

164 email_template_name="security", 

165 email_template_args={ 

166 "title": title, 

167 "message": message, 

168 }, 

169 push_title=title, 

170 push_body=message, 

171 push_icon=urls.icon_url(), 

172 push_url=urls.account_settings_link(), 

173 ) 

174 elif notification.topic_action.display == "email_address:change": 

175 title = "An email change was initiated on your account" 

176 message = f"An email change to the email <b>{data.new_email}</b> was initiated on your account." 

177 message_plain = f"An email change to the email {data.new_email} was initiated on your account." 

178 return RenderedNotification( 

179 is_critical=True, 

180 email_subject=title, 

181 email_preview=title, 

182 email_template_name="security", 

183 email_template_args={ 

184 "title": title, 

185 "message": message, 

186 }, 

187 push_title=title, 

188 push_body=message_plain, 

189 push_icon=urls.icon_url(), 

190 push_url=urls.account_settings_link(), 

191 ) 

192 elif notification.topic_action.display == "email_address:verify": 

193 title = "Email change completed" 

194 message = "Your new email address has been verified." 

195 return RenderedNotification( 

196 is_critical=True, 

197 email_subject=title, 

198 email_preview=message, 

199 email_template_name="security", 

200 email_template_args={ 

201 "title": title, 

202 "message": message, 

203 }, 

204 push_title=title, 

205 push_body=message, 

206 push_icon=urls.icon_url(), 

207 push_url=urls.account_settings_link(), 

208 ) 

209 elif notification.topic_action.display == "phone_number:change": 

210 title = "Phone verification started" 

211 message = f"You started phone number verification with the number <b>{v2phone(data.phone)}</b>." 

212 message_plain = f"You started phone number verification with the number {v2phone(data.phone)}." 

213 return RenderedNotification( 

214 is_critical=True, 

215 email_subject=title, 

216 email_preview=message, 

217 email_template_name="security", 

218 email_template_args={ 

219 "title": title, 

220 "message": message, 

221 }, 

222 push_title=title, 

223 push_body=message_plain, 

224 push_icon=urls.icon_url(), 

225 push_url=urls.feature_preview_link(), 

226 ) 

227 elif notification.topic_action.display == "phone_number:verify": 

228 title = "Phone successfully verified" 

229 message = f"Your phone was successfully verified as <b>{v2phone(data.phone)}</b> on Couchers.org." 

230 message_plain = f"Your phone was successfully verified as {v2phone(data.phone)} on Couchers.org." 

231 return RenderedNotification( 

232 is_critical=True, 

233 email_subject=title, 

234 email_preview=message_plain, 

235 email_template_name="security", 

236 email_template_args={ 

237 "title": title, 

238 "message": message, 

239 }, 

240 push_title=title, 

241 push_body=message_plain, 

242 push_icon=urls.icon_url(), 

243 push_url=urls.feature_preview_link(), 

244 ) 

245 elif notification.topic_action.display == "gender:change": 

246 title = "Your gender was changed" 

247 message = f"Your gender on Couchers.org was changed to <b>{data.gender}</b> by an admin." 

248 message_plain = f"Your gender on Couchers.org was changed to {data.gender} by an admin." 

249 return RenderedNotification( 

250 is_critical=True, 

251 email_subject=title, 

252 email_preview=message_plain, 

253 email_template_name="security", 

254 email_template_args={ 

255 "title": title, 

256 "message": message, 

257 }, 

258 push_title=title, 

259 push_body=message_plain, 

260 push_icon=urls.icon_url(), 

261 push_url=urls.account_settings_link(), 

262 ) 

263 elif notification.topic_action.display == "birthdate:change": 

264 title = "Your date of birth was changed" 

265 message = ( 

266 f"Your date of birth on Couchers.org was changed to <b>{v2date(data.birthdate, user)}</b> by an admin." 

267 ) 

268 message_plain = f"Your date of birth on Couchers.org was changed to {v2date(data.birthdate, user)} by an admin." 

269 return RenderedNotification( 

270 is_critical=True, 

271 email_subject=title, 

272 email_preview=message_plain, 

273 email_template_name="security", 

274 email_template_args={ 

275 "title": title, 

276 "message": message, 

277 }, 

278 push_title=title, 

279 push_body=message_plain, 

280 push_icon=urls.icon_url(), 

281 push_url=urls.account_settings_link(), 

282 ) 

283 elif notification.topic_action.display == "api_key:create": 

284 return RenderedNotification( 

285 is_critical=True, 

286 email_subject="Your API key for Couchers.org", 

287 email_preview="We have issued you an API key as per your request.", 

288 email_template_name="api_key", 

289 email_template_args={ 

290 "api_key": data.api_key, 

291 "expiry": data.expiry, 

292 }, 

293 push_title="An API key was created for your account", 

294 push_body="Details were sent to you via email.", 

295 push_icon=urls.icon_url(), 

296 push_url=urls.app_link(), 

297 ) 

298 elif notification.topic_action.display in ["badge:add", "badge:remove"]: 

299 actioned = "added to" if notification.action == "add" else "removed from" 

300 title = f"The {data.badge_name} badge was {actioned} your profile" 

301 return RenderedNotification( 

302 email_subject=title, 

303 email_preview=title, 

304 email_template_name="badge", 

305 email_template_args={ 

306 "badge_name": data.badge_name, 

307 "actioned": actioned, 

308 "unsub_type": "badge additions" if notification.action == "add" else "badge removals", 

309 }, 

310 email_topic_action_unsubscribe_text="badge additions" if notification.action == "add" else "badge removals", 

311 push_title=title, 

312 push_body=( 

313 "Check out your profile to see the new badge!" 

314 if notification.action == "add" 

315 else "You can see all your badges on your profile." 

316 ), 

317 push_icon=urls.icon_url(), 

318 push_url=urls.profile_link(), 

319 email_list_unsubscribe_url=generate_unsub_topic_action(notification), 

320 ) 

321 elif notification.topic_action.display == "donation:received": 

322 title = "Thank you for your donation to Couchers.org!" 

323 message = f"Thank you so much for your donation of ${data.amount} to Couchers.org." 

324 return RenderedNotification( 

325 is_critical=True, 

326 email_subject=title, 

327 email_preview=message, 

328 email_template_name="donation_received", 

329 email_template_args={ 

330 "amount": data.amount, 

331 "receipt_url": data.receipt_url, 

332 }, 

333 push_title=title, 

334 push_body=message, 

335 push_icon=urls.icon_url(), 

336 push_url=data.receipt_url, 

337 ) 

338 elif notification.topic_action.display == "friend_request:create": 

339 other = data.other_user 

340 preview = f"You've received a friend request from {other.name}" 

341 return RenderedNotification( 

342 email_subject=f"{other.name} wants to be your friend on Couchers.org!", 

343 email_preview=preview, 

344 email_template_name="friend_request", 

345 email_template_args={ 

346 "friend_requests_link": urls.friend_requests_link(), 

347 "other": other, 

348 }, 

349 email_topic_action_unsubscribe_text="new friend requests", 

350 push_title=f"{other.name} wants to be your friend", 

351 push_body=preview, 

352 push_icon=v2avatar(other), 

353 push_url=urls.friend_requests_link(), 

354 ) 

355 elif notification.topic_action.display == "friend_request:accept": 

356 other = data.other_user 

357 title = f"{other.name} accepted your friend request!" 

358 preview = f"{v2esc(other.name)} has accepted your friend request" 

359 return RenderedNotification( 

360 email_subject=title, 

361 email_preview=preview, 

362 email_template_name="friend_request_accepted", 

363 email_template_args={ 

364 "other_user_link": urls.user_link(username=other.username), 

365 "other": other, 

366 }, 

367 email_topic_action_unsubscribe_text="accepted friend requests", 

368 push_title=title, 

369 push_body=preview, 

370 push_icon=v2avatar(other), 

371 push_url=urls.user_link(username=other.username), 

372 ) 

373 elif notification.topic_action.display == "account_deletion:start": 

374 return RenderedNotification( 

375 is_critical=True, 

376 email_subject="Confirm your Couchers.org account deletion", 

377 email_preview="Please confirm that you want to delete your Couchers.org account.", 

378 email_template_name="account_deletion_start", 

379 email_template_args={ 

380 "deletion_link": urls.delete_account_link(account_deletion_token=data.deletion_token), 

381 }, 

382 push_title="Account deletion initiated", 

383 push_body="Someone initiated the deletion of your Couchers.org account. To delete your account, please follow the link in the email we sent you.", 

384 push_icon=urls.icon_url(), 

385 push_url=urls.app_link(), 

386 ) 

387 elif notification.topic_action.display == "account_deletion:complete": 

388 title = "Your Couchers.org account has been deleted" 

389 return RenderedNotification( 

390 is_critical=True, 

391 email_subject=title, 

392 email_preview="We have deleted your Couchers.org account, to undo, follow the link in this email.", 

393 email_template_name="account_deletion_complete", 

394 email_template_args={ 

395 "undelete_link": urls.recover_account_link(account_undelete_token=data.undelete_token), 

396 "days": data.undelete_days, 

397 }, 

398 push_title=title, 

399 push_body=f"You can still undo this by following the link we emailed to you within {data.undelete_days} days.", 

400 push_icon=urls.icon_url(), 

401 push_url=urls.app_link(), 

402 ) 

403 elif notification.topic_action.display == "account_deletion:recovered": 

404 title = "Your Couchers.org account has been recovered!" 

405 subtitle = "We have recovered your Couchers.org account as per your request! Welcome back!" 

406 return RenderedNotification( 

407 is_critical=True, 

408 email_subject=title, 

409 email_preview=subtitle, 

410 email_template_name="account_deletion_recovered", 

411 email_template_args={ 

412 "app_link": urls.app_link(), 

413 }, 

414 push_title=title, 

415 push_body=subtitle, 

416 push_icon=urls.icon_url(), 

417 push_url=urls.app_link(), 

418 ) 

419 elif notification.topic_action.display == "chat:message": 

420 return RenderedNotification( 

421 email_subject=data.message, 

422 email_preview="You received a message on Couchers.org!", 

423 email_template_name="chat_message", 

424 email_template_args={ 

425 "author": data.author, 

426 "message": data.message, 

427 "text": data.text, 

428 "view_link": urls.chat_link(chat_id=data.group_chat_id), 

429 }, 

430 email_topic_action_unsubscribe_text="new chat messages", 

431 email_topic_key_unsubscribe_text="this chat (mute)", 

432 push_title=data.message, 

433 push_body=data.text, 

434 push_icon=v2avatar(data.author), 

435 push_url=urls.chat_link(chat_id=data.group_chat_id), 

436 ) 

437 elif notification.topic_action.display == "chat:missed_messages": 

438 return RenderedNotification( 

439 email_subject="You have unseen messages on Couchers.org!", 

440 email_preview="You missed some messages on the platform.", 

441 email_template_name="chat_unseen_messages", 

442 email_template_args={ 

443 "items": [ 

444 { 

445 "author": item.author, 

446 "message": item.message, 

447 "text": item.text, 

448 "view_link": urls.chat_link(chat_id=item.group_chat_id), 

449 } 

450 for item in data.messages 

451 ] 

452 }, 

453 email_topic_action_unsubscribe_text="unseen chat messages", 

454 push_title="You have unseen messages on Couchers.org", 

455 push_body="Please check out any messages you missed.", 

456 push_icon=urls.icon_url(), 

457 push_url=urls.messages_link(), 

458 ) 

459 elif notification.topic == "event": 

460 event = data.event 

461 time_display = f"{v2timestamp(event.start_time, user)} - {v2timestamp(event.end_time, user)}" 

462 event_link = urls.event_link(occurrence_id=event.event_id, slug=event.slug) 

463 if notification.action in ["create_approved", "create_any"]: 

464 body = f"{time_display}\n" 

465 body += f"Invited by {data.inviting_user.name}\n\n" 

466 body += event.content 

467 community_link = ( 

468 urls.community_link(node_id=data.in_community.community_id, slug=data.in_community.slug) 

469 if data.in_community 

470 else None 

471 ) 

472 return RenderedNotification( 

473 email_subject=f'{data.inviting_user.name} invited you to "{event.title}"', 

474 email_preview="You've been invited to a new event on Couchers.org!", 

475 email_template_name="event_create", 

476 email_template_args={ 

477 "inviting_user": data.inviting_user, 

478 "time_display": time_display, 

479 "nearby": "nearby" if data.nearby else None, 

480 "community": data.in_community if data.in_community else None, 

481 "community_link": community_link, 

482 "nearby_or_community_text_plain": ( 

483 "nearby" if data.nearby else f"in the {data.in_community.name} community" 

484 ), 

485 "event": event, 

486 "view_link": event_link, 

487 }, 

488 email_topic_action_unsubscribe_text=( 

489 "new events by community members" 

490 if notification.action == "create_any" 

491 else "new events approved by moderators" 

492 ), 

493 push_title=f'{data.inviting_user.name} invited you to "{event.title}"', 

494 push_body=body, 

495 push_icon=v2avatar(data.inviting_user), 

496 push_url=event_link, 

497 ) 

498 elif notification.action == "update": 

499 updated_text = ", ".join(data.updated_items) 

500 body = f"{time_display}\n" 

501 body += f"{data.updating_user.name} updated: {updated_text}\n\n" 

502 body += event.content 

503 return RenderedNotification( 

504 email_subject=f'{data.updating_user.name} updated "{event.title}"', 

505 email_preview="An event you are subscribed to was updated.", 

506 email_template_name="event_update", 

507 email_template_args={ 

508 "updating_user": data.updating_user, 

509 "time_display": time_display, 

510 "event": event, 

511 "updated_text": updated_text, 

512 "view_link": event_link, 

513 }, 

514 email_topic_action_unsubscribe_text="event updates", 

515 push_title=f'{data.updating_user.name} updated "{event.title}"', 

516 push_body=body, 

517 push_icon=v2avatar(data.updating_user), 

518 push_url=event_link, 

519 ) 

520 elif notification.action == "cancel": 

521 body = f"{time_display}\n" 

522 body += f"The event has been cancelled by {data.cancelling_user.name}.\n\n" 

523 body += event.content 

524 return RenderedNotification( 

525 email_subject=f'{data.cancelling_user.name} cancelled "{event.title}"', 

526 email_preview="An event you are subscribed to has been cancelled.", 

527 email_template_name="event_cancel", 

528 email_template_args={ 

529 "cancelling_user": data.cancelling_user, 

530 "time_display": time_display, 

531 "event": event, 

532 "view_link": event_link, 

533 }, 

534 email_topic_action_unsubscribe_text="event cancellations", 

535 push_title=f'{data.cancelling_user.name} cancelled "{event.title}"', 

536 push_body=body, 

537 push_icon=v2avatar(data.cancelling_user), 

538 push_url=event_link, 

539 ) 

540 elif notification.action == "delete": 

541 return RenderedNotification( 

542 email_subject=f'A moderator deleted "{event.title}"', 

543 email_preview="An event you are subscribed to has been deleted.", 

544 email_template_name="event_delete", 

545 email_template_args={ 

546 "time_display": time_display, 

547 "event": event, 

548 }, 

549 email_topic_action_unsubscribe_text="event deletions", 

550 push_title=f'A moderator deleted "{event.title}"', 

551 push_body=f"{time_display}\nThe event has been deleted by the moderators.", 

552 push_icon=urls.icon_url(), 

553 push_url=urls.app_link(), 

554 ) 

555 elif notification.action == "invite_organizer": 

556 body = f"{time_display}\n" 

557 body += f"Invited to co-organize by {data.inviting_user.name}\n\n" 

558 body += event.content 

559 return RenderedNotification( 

560 email_subject=f'{data.inviting_user.name} invited you to co-organize "{event.title}"', 

561 email_preview="You were invited to co-organize an event on Couchers.org.", 

562 email_template_name="event_invite_organizer", 

563 email_template_args={ 

564 "inviting_user": data.inviting_user, 

565 "time_display": time_display, 

566 "event": event, 

567 "view_link": event_link, 

568 }, 

569 email_topic_action_unsubscribe_text="invitations to co-organize events", 

570 push_title=f'{data.inviting_user.name} invited you to co-organize "{event.title}"', 

571 push_body=body, 

572 push_icon=v2avatar(data.inviting_user), 

573 push_url=event_link, 

574 ) 

575 elif notification.topic == "reference": 

576 if notification.action == "receive_friend": 

577 title = f"You've received a friend reference from {data.from_user.name}!" 

578 return RenderedNotification( 

579 email_subject=title, 

580 email_preview=v2esc(data.text), 

581 email_template_name="friend_reference", 

582 email_template_args={ 

583 "from_user": data.from_user, 

584 "profile_references_link": urls.profile_references_link(), 

585 "text": data.text, 

586 }, 

587 email_topic_action_unsubscribe_text="new references from friends", 

588 push_title=title, 

589 push_body=data.text, 

590 push_icon=v2avatar(data.from_user), 

591 push_url=urls.profile_references_link(), 

592 ) 

593 elif notification.action in ["receive_hosted", "receive_surfed"]: 

594 title = f"You've received a reference from {data.from_user.name}!" 

595 # what was my type? i surfed with them if i received a "hosted" request 

596 surfed = notification.action == "receive_hosted" 

597 leave_reference_link = urls.leave_reference_link( 

598 reference_type="surfed" if surfed else "hosted", 

599 to_user_id=data.from_user.user_id, 

600 host_request_id=data.host_request_id, 

601 ) 

602 profile_references_link = urls.profile_references_link() 

603 if data.text: 

604 body = v2esc(data.text) 

605 push_url = profile_references_link 

606 else: 

607 body = "Please go and write a reference for them too. It's a nice gesture and helps us build a community together!" 

608 push_url = leave_reference_link 

609 return RenderedNotification( 

610 email_subject=title, 

611 email_preview=body, 

612 email_template_name="host_reference", 

613 email_template_args={ 

614 "from_user": data.from_user, 

615 "leave_reference_link": leave_reference_link, 

616 "profile_references_link": profile_references_link, 

617 "text": data.text, 

618 "both_written": True if data.text else False, 

619 "surfed": surfed, 

620 }, 

621 email_topic_action_unsubscribe_text="new references from " + ("hosts" if surfed else "surfers"), 

622 push_title=title, 

623 push_body=body, 

624 push_icon=v2avatar(data.from_user), 

625 push_url=push_url, 

626 ) 

627 elif notification.action in ["reminder_hosted", "reminder_surfed"]: 

628 # what was my type? i surfed with them if i get a surfed reminder 

629 surfed = notification.action == "reminder_surfed" 

630 leave_reference_link = urls.leave_reference_link( 

631 reference_type="surfed" if surfed else "hosted", 

632 to_user_id=data.other_user.user_id, 

633 host_request_id=data.host_request_id, 

634 ) 

635 title = f"You have {data.days_left} days to write a reference for {data.other_user.name}!" 

636 preview = "It's a nice gesture to write references and helps us build a community together! References will become visible 2 weeks after the stay, or when you've both written a reference for each other, whichever happens first." 

637 return RenderedNotification( 

638 email_subject=title, 

639 email_preview=preview, 

640 email_template_name="reference_reminder", 

641 email_template_args={ 

642 "other_user": data.other_user, 

643 "leave_reference_link": leave_reference_link, 

644 "days_left": str(data.days_left), 

645 "surfed": surfed, 

646 }, 

647 email_topic_action_unsubscribe_text=("surfed" if surfed else "hosted") + " reference reminders", 

648 push_title=title, 

649 push_body=preview, 

650 push_icon=v2avatar(data.other_user), 

651 push_url=leave_reference_link, 

652 ) 

653 elif notification.topic_action.display == "onboarding:reminder": 

654 if notification.key == "1": 

655 return RenderedNotification( 

656 email_subject="Welcome to Couchers.org and the future of couch surfing", 

657 email_preview="We are so excited to have you join our community!", 

658 email_template_name="onboarding1", 

659 email_template_args={ 

660 "app_link": urls.app_link(), 

661 "edit_profile_link": urls.edit_profile_link(), 

662 }, 

663 email_topic_action_unsubscribe_text="onboarding emails", 

664 push_title="Welcome to Couchers.org and the future of couch surfing", 

665 push_body=f"Hi {v2esc(user.name)}! We are excited that you have joined us! Please take a moment to complete your profile with a picture and a bit of text about yourself!", 

666 push_icon=urls.icon_url(), 

667 push_url=urls.edit_profile_link(), 

668 ) 

669 elif notification.key == "2": 

670 return RenderedNotification( 

671 email_subject="Complete your profile on Couchers.org", 

672 email_preview="We would ask one big favour of you: please fill out your profile by adding a photo and some text.", 

673 email_template_name="onboarding2", 

674 email_template_args={ 

675 "edit_profile_link": urls.edit_profile_link(), 

676 }, 

677 email_topic_action_unsubscribe_text="onboarding emails", 

678 push_title="Please complete your profile on Couchers.org!", 

679 push_body=f"Hi {v2esc(user.name)}! We would ask one big favour of you: please fill out your profile by adding a photo and some text.", 

680 push_icon=urls.icon_url(), 

681 push_url=urls.edit_profile_link(), 

682 ) 

683 elif notification.topic_action.display == "modnote:create": 

684 title = "You have received a mod note" 

685 message = "You have received an important note from the moderators. You must read and acknowledge it before continuing to use the platform." 

686 return RenderedNotification( 

687 is_critical=True, 

688 email_subject=title, 

689 email_preview=message, 

690 email_template_name="mod_note", 

691 email_template_args={"title": title}, 

692 push_title="You received a mod note", 

693 push_body="You need to read and acknowledge the note before continuing to use the platform.", 

694 push_icon=urls.icon_url(), 

695 push_url=urls.app_link(), 

696 ) 

697 elif notification.topic_action.display == "verification:sv_success": 

698 title = "Strong Verification succeeded" 

699 message = "You have been verified with Strong Verification! You will now see a tick next to your name on the platform." 

700 return RenderedNotification( 

701 is_critical=True, 

702 email_subject=title, 

703 email_preview=title, 

704 email_template_name="security", 

705 email_template_args={ 

706 "title": title, 

707 "message": message, 

708 }, 

709 push_title=title, 

710 push_body=message, 

711 push_icon=urls.icon_url(), 

712 push_url=urls.account_settings_link(), 

713 ) 

714 elif notification.topic_action.display == "verification:sv_fail": 

715 title = "Strong Verification failed" 

716 message: str 

717 if data.reason == notification_data_pb2.SV_FAIL_REASON_WRONG_BIRTHDATE_OR_GENDER: 

718 message = "The date of birth or gender on your profile does not match the date of birth or sex on your passport. Please contact the support team to update your date of birth or gender, or if your passport sex does not match your gender identity." 

719 elif data.reason == notification_data_pb2.SV_FAIL_REASON_NOT_A_PASSPORT: 

720 message = "You tried to verify with a document that is not a passport. You can only use a passport for Strong Verification." 

721 elif data.reason == notification_data_pb2.SV_FAIL_REASON_DUPLICATE: 

722 message = "You tried to verify with a passport that has already been used for verification. Please use another passport." 

723 else: 

724 raise Exception("Shouldn't get here") 

725 return RenderedNotification( 

726 is_critical=True, 

727 email_subject=title, 

728 email_preview=title, 

729 email_template_name="security", 

730 email_template_args={ 

731 "title": title, 

732 "message": message, 

733 }, 

734 push_title=title, 

735 push_body=message, 

736 push_icon=urls.icon_url(), 

737 push_url=urls.account_settings_link(), 

738 ) 

739 else: 

740 raise NotImplementedError(f"Unknown topic-action: {notification.topic}:{notification.action}")