update sign up notifications
Build and Push Docker Images / Build and Push Docker Images (push) Failing after 9s
Build and Push Docker Images / Build and Push Docker Images (push) Failing after 9s
This commit is contained in:
+20
@@ -70,6 +70,26 @@ async def send_telegram_alert(markdown_message: str):
|
||||
)
|
||||
|
||||
|
||||
async def send_telegram_photo(photo, markdown_caption: str):
|
||||
"""Send a photo. `photo` may be raw bytes / a file-like object (uploaded
|
||||
directly to Telegram) or a public URL string."""
|
||||
logger.info("[TELEGRAM] Preparing to send photo...")
|
||||
kwargs = {}
|
||||
if TOPIC_ID:
|
||||
kwargs["message_thread_id"] = int(TOPIC_ID)
|
||||
await bot.send_photo(
|
||||
chat_id=str(CHAT_ID),
|
||||
photo=photo,
|
||||
caption=markdown_caption,
|
||||
parse_mode=ParseMode.MARKDOWN_V2,
|
||||
# Uploading media is slower than a text send; the defaults (5s) time out.
|
||||
connect_timeout=15,
|
||||
read_timeout=30,
|
||||
write_timeout=60,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
def escape_markdown_v2(text: str) -> str:
|
||||
escape_chars = r"_~`>#+-=|{}.!\\"
|
||||
return re.sub(f"([{re.escape(escape_chars)}])", r"\\\1", text)
|
||||
|
||||
@@ -8,7 +8,9 @@ class Command(BaseCommand):
|
||||
help = "Seeds baseline reference data (atolls and islands) required for sign up."
|
||||
|
||||
def handle(self, *args, **options):
|
||||
atoll, atoll_created = Atoll.objects.get_or_create(name="Faafu")
|
||||
# Atoll name must match the person-verify API's `atoll_en` (the atoll
|
||||
# code letter, e.g. "F" for Faafu) or user verification fails.
|
||||
atoll, atoll_created = Atoll.objects.get_or_create(name="F")
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS(f"Created atoll: {atoll.name}")
|
||||
if atoll_created
|
||||
|
||||
+65
-15
@@ -9,13 +9,20 @@ from django.utils import timezone
|
||||
|
||||
# from api.notifications import send_clean_telegram_markdown
|
||||
from api.omada import Omada
|
||||
from api.bot import send_telegram_alert, telegram_loop, escape_markdown_v2
|
||||
from api.bot import (
|
||||
send_telegram_alert,
|
||||
send_telegram_photo,
|
||||
telegram_loop,
|
||||
escape_markdown_v2,
|
||||
)
|
||||
import asyncio
|
||||
from apibase.env import env, BASE_DIR
|
||||
from procrastinate.contrib.django import app
|
||||
from procrastinate import builtin_tasks
|
||||
import time
|
||||
import io
|
||||
import requests
|
||||
from PIL import Image
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -163,10 +170,58 @@ def verify_user_with_person_api_task(user_id: int):
|
||||
response = requests.get(f"{PERSON_VERIFY_BASE_URL}/api/person/{t_user.t_id_card}")
|
||||
|
||||
|
||||
verification_failed_message = f"""*The following user verification failed*:\n\n*ID Card:* {t_user.t_id_card}\n*Name:* {t_user.t_first_name} {t_user.t_last_name}\n*House Name:* {t_user.t_address}\n*Date of Birth:* {t_user.t_dob}\n*Island:* {(t_user.t_atoll.name if t_user.t_atoll else "N/A")} {(t_user.t_island.name if t_user.t_island else "N/A")}\n*Mobile:* {t_user.t_mobile}\nVisit [SAR Link Portal](https://portal.sarlink.net/users/{user_id}/details) to manually verify this user.
|
||||
"""
|
||||
user_details = (
|
||||
f"*NID:* {t_user.t_id_card}\n"
|
||||
f"*Name:* {t_user.t_first_name} {t_user.t_last_name}\n"
|
||||
f"*Phone:* {t_user.t_mobile}\n"
|
||||
f"*Date of Birth:* {t_user.t_dob}\n"
|
||||
f"*Address:* {t_user.t_address}\n"
|
||||
f"*Island:* {(t_user.t_atoll.name if t_user.t_atoll else 'N/A')}. "
|
||||
f"{(t_user.t_island.name if t_user.t_island else 'N/A')}"
|
||||
)
|
||||
|
||||
logger.info(verification_failed_message)
|
||||
verification_failed_message = (
|
||||
f"⚠️ *User verification failed*\n\n{user_details}\n"
|
||||
f"Visit [SAR Link Portal](https://portal.sarlink.net/users/{user_id}/details) "
|
||||
f"to manually verify this user."
|
||||
)
|
||||
|
||||
verification_success_message = (
|
||||
f"✅ *New user registered and verified*\n\n{user_details}\n"
|
||||
f"View on [SAR Link Portal](https://portal.sarlink.net/users/{user_id}/details)."
|
||||
)
|
||||
|
||||
def _run(coro) -> None:
|
||||
asyncio.run_coroutine_threadsafe(coro, telegram_loop).result()
|
||||
|
||||
def _fetch_photo(url: str) -> io.BytesIO:
|
||||
"""Download the ID photo and convert it to a Telegram-safe JPEG.
|
||||
|
||||
The image lives on a private-network URL that Telegram's servers can't
|
||||
reach, so we fetch the bytes here and upload them directly. Conversion
|
||||
to JPEG avoids Telegram rejecting formats like webp.
|
||||
"""
|
||||
resp = requests.get(url, timeout=10)
|
||||
resp.raise_for_status()
|
||||
buf = io.BytesIO()
|
||||
Image.open(io.BytesIO(resp.content)).convert("RGB").save(buf, format="JPEG")
|
||||
buf.seek(0)
|
||||
buf.name = "photo.jpg"
|
||||
return buf
|
||||
|
||||
def send_telegram(message: str, photo_url: str | None = None) -> None:
|
||||
caption = escape_markdown_v2(message)
|
||||
if photo_url:
|
||||
try:
|
||||
_run(send_telegram_photo(_fetch_photo(photo_url), caption))
|
||||
return
|
||||
except Exception as e:
|
||||
logger.warning(f"[Registration] TELEGRAM PHOTO ERROR: {e}")
|
||||
# Fall through to a plain text alert below.
|
||||
try:
|
||||
_run(send_telegram_alert(markdown_message=caption))
|
||||
except Exception as e:
|
||||
logger.warning(f"[Registration] TELEGRAM ALERT ERROR: {e}")
|
||||
|
||||
|
||||
if response.status_code == 200:
|
||||
@@ -177,6 +232,7 @@ def verify_user_with_person_api_task(user_id: int):
|
||||
api_dob = data.get("dob")
|
||||
api_atoll = data.get("atoll_en")
|
||||
api_island_name = data.get("island_name_en")
|
||||
api_image_url = data.get("image_url")
|
||||
|
||||
if not t_user.t_mobile or t_user.t_dob is None:
|
||||
logger.error("User mobile or date of birth is not set.")
|
||||
@@ -230,22 +286,16 @@ def verify_user_with_person_api_task(user_id: int):
|
||||
):
|
||||
t_user.t_verified = True
|
||||
t_user.save()
|
||||
|
||||
logger.info(verification_success_message)
|
||||
send_telegram(verification_success_message, photo_url=api_image_url)
|
||||
return True
|
||||
else:
|
||||
t_user.t_verified = False
|
||||
t_user.save()
|
||||
|
||||
# send_clean_telegram_markdown(message=verification_failed_message)
|
||||
|
||||
try:
|
||||
asyncio.run_coroutine_threadsafe(
|
||||
send_telegram_alert(
|
||||
markdown_message=escape_markdown_v2(verification_failed_message)
|
||||
),
|
||||
telegram_loop,
|
||||
).result()
|
||||
except Exception as e:
|
||||
logger.warning("[Registration] TELEGRAM ALERT ERROR", e)
|
||||
logger.info(verification_failed_message)
|
||||
send_telegram(verification_failed_message, photo_url=api_image_url)
|
||||
return False
|
||||
else:
|
||||
# Handle the error case
|
||||
|
||||
Reference in New Issue
Block a user