|
| 1 | +# -*- coding: utf-8 -*- |
| 2 | +# Copyright (c) 2022 Ricardo Bartels. All rights reserved. |
| 3 | +# |
| 4 | +# wordpress-hash-event-api |
| 5 | +# |
| 6 | +# This work is licensed under the terms of the MIT license. |
| 7 | +# For a copy, see file LICENSE.txt included in this |
| 8 | +# repository or visit: <https://opensource.org/licenses/MIT>. |
| 9 | + |
| 10 | +import hashlib |
| 11 | +from fastapi import APIRouter, HTTPException |
| 12 | +from time import time |
| 13 | + |
| 14 | +from api.models.run import HashParams |
| 15 | +from api.models.send_newsletter import SendNewsletterParams, ListmonkReturnDataList |
| 16 | +from api.models.exceptions import CredentialsInvalid |
| 17 | +from api.factory.runs import get_hash_runs |
| 18 | +from source.database import get_db_handler |
| 19 | +from common.misc import php_deserialize, grab |
| 20 | +from common.log import get_logger |
| 21 | +from listmonk.handler import get_listmonk_handler |
| 22 | + |
| 23 | + |
| 24 | +log = get_logger() |
| 25 | + |
| 26 | +newsletter = APIRouter( |
| 27 | + prefix="/send-newsletter", |
| 28 | + tags=["newsletter"] |
| 29 | +) |
| 30 | + |
| 31 | + |
| 32 | +# noinspection PyShadowingBuiltins |
| 33 | +@newsletter.post("/{post_id}", response_model=ListmonkReturnDataList, summary="post run", |
| 34 | + description="post run via newsletter") |
| 35 | +async def get_run(post_id: int, params: SendNewsletterParams): |
| 36 | + """ |
| 37 | + To post/update a run to listmonk |
| 38 | +
|
| 39 | + - **id**: The integer id of the desired run |
| 40 | + """ |
| 41 | + |
| 42 | + db_handler = get_db_handler() |
| 43 | + |
| 44 | + # query user metadata from database |
| 45 | + user_params = db_handler.get_usermeta(params.user) |
| 46 | + session_tokens = None |
| 47 | + for item in user_params: |
| 48 | + if item.get("meta_key") == "session_tokens": |
| 49 | + session_tokens = item.get("meta_value") |
| 50 | + |
| 51 | + if session_tokens is None: |
| 52 | + log.debug(f"No session_tokens metadata found in wordpress DB for user id {params.user}") |
| 53 | + raise CredentialsInvalid |
| 54 | + |
| 55 | + # use hashed session token to find session in database |
| 56 | + hashed_token_sha256 = hashlib.sha256(params.token.encode()).hexdigest() |
| 57 | + hashed_token_sha1 = hashlib.sha1(params.token.encode()).hexdigest() |
| 58 | + |
| 59 | + session_data = None |
| 60 | + try: |
| 61 | + session_data = php_deserialize(session_tokens).get(hashed_token_sha256) |
| 62 | + if session_data is None: |
| 63 | + session_data = php_deserialize(session_tokens).get(hashed_token_sha1) |
| 64 | + except Exception as e: |
| 65 | + log.debug(f"PHP deserialization of 'session_tokens' failed: {e}") |
| 66 | + |
| 67 | + if session_data is None: |
| 68 | + log.debug(f"No session data found in wordpress DB for user id {params.user}") |
| 69 | + raise CredentialsInvalid |
| 70 | + |
| 71 | + # check if session has not expired |
| 72 | + expiration_ts = session_data.get("expiration") |
| 73 | + if not isinstance(expiration_ts, int): |
| 74 | + log.debug(f"session data expiration is not an int: {session_data}") |
| 75 | + raise CredentialsInvalid |
| 76 | + |
| 77 | + if expiration_ts < int(time()): |
| 78 | + log.debug(f"session already expired") |
| 79 | + raise CredentialsInvalid |
| 80 | + |
| 81 | + # all checks passed and user presented a valid session |
| 82 | + |
| 83 | + # fetch post |
| 84 | + # noinspection PyArgumentList |
| 85 | + result = get_hash_runs(HashParams(id=post_id)) |
| 86 | + |
| 87 | + if result is None or len(result) == 0: |
| 88 | + raise HTTPException(status_code=404, detail="Run not found") |
| 89 | + |
| 90 | + event = result[0] |
| 91 | + |
| 92 | + # fetch template from listmonk |
| 93 | + listmonk_handler = get_listmonk_handler() |
| 94 | + listmonk_template = listmonk_handler.get_template(listmonk_handler.config.body_template_id) |
| 95 | + |
| 96 | + if listmonk_template is None: |
| 97 | + raise HTTPException(status_code=404, |
| 98 | + detail=f"Listmonk template {listmonk_handler.config.body_template_id} not found") |
| 99 | + |
| 100 | + template_body = grab(listmonk_template, "data.body") |
| 101 | + |
| 102 | + if template_body is None: |
| 103 | + template_body = event.event_description |
| 104 | + |
| 105 | + # set all paragraph text to center |
| 106 | + event.event_description = event.event_description.replace('<p>', '<p style="text-align: center;">') |
| 107 | + |
| 108 | + # use data from post and apply to template |
| 109 | + try: |
| 110 | + campaign_body = template_body.format(**event.__dict__) |
| 111 | + except Exception as e: |
| 112 | + log.error(f"Failed to format template: {e}") |
| 113 | + raise HTTPException(status_code=500, detail=f"Failed to format template: {e}") |
| 114 | + |
| 115 | + # fetch post metadata to check if newsletter has already been sent before |
| 116 | + post_meta_data = db_handler.get_posts_meta([post_id]) |
| 117 | + post_campaign_id = None |
| 118 | + subject_prefix = "" |
| 119 | + for post_meta in post_meta_data: |
| 120 | + if post_meta.get("meta_key") == "listmonk_campaign_id": |
| 121 | + post_campaign_id = post_meta.get("meta_value") |
| 122 | + |
| 123 | + if post_campaign_id is not None: |
| 124 | + subject_prefix = "UPDATE: " |
| 125 | + |
| 126 | + # prepare campaign data |
| 127 | + campaign_data = { |
| 128 | + "name": f"{subject_prefix}{event.event_name}", |
| 129 | + "subject": f"{subject_prefix}[{event.kennel_name}] Run #{event.run_number}, " |
| 130 | + f"{event.start_date:%A %d %B %Y, %H:%M} @ {event.location_name}", |
| 131 | + "lists": listmonk_handler.config.list_ids, |
| 132 | + "type": "regular", |
| 133 | + "content_type": "html", |
| 134 | + "body": campaign_body |
| 135 | + } |
| 136 | + |
| 137 | + if listmonk_handler.config.campaign_template_id is not None: |
| 138 | + campaign_data["template_id"] = listmonk_handler.config.campaign_template_id |
| 139 | + |
| 140 | + # create listmonk campaign |
| 141 | + campaign_result = listmonk_handler.add_campaign(campaign_data) |
| 142 | + |
| 143 | + if campaign_result is None: |
| 144 | + raise HTTPException(status_code=503, detail=f"Upstream request failed") |
| 145 | + |
| 146 | + campaign_id = grab(campaign_result, "data.id") |
| 147 | + |
| 148 | + # send campaign |
| 149 | + if listmonk_handler.config.send_campaign is True: |
| 150 | + campaign_result = listmonk_handler.set_campaign_status(campaign_id, "running") |
| 151 | + |
| 152 | + if campaign_result is None: |
| 153 | + raise HTTPException(status_code=503, detail=f"Upstream request failed, unable to start campaign") |
| 154 | + |
| 155 | + # write campaign id to WP database |
| 156 | + if post_campaign_id is not None: |
| 157 | + db_handler.update_post_meta(post_id, "listmonk_campaign_id", campaign_id) |
| 158 | + else: |
| 159 | + db_handler.add_post_meta(post_id, "listmonk_campaign_id", campaign_id) |
| 160 | + |
| 161 | + return ListmonkReturnDataList(**campaign_result) |
| 162 | + |
| 163 | +# EOF |
0 commit comments