From f95552ff4d4b700671de9f5edcd451132e6eb190 Mon Sep 17 00:00:00 2001 From: YuehuCao Date: Mon, 11 Aug 2025 18:50:43 +0800 Subject: [PATCH] chore: add local testing configs and MongoDB message templates --- .../notification/backend/infra/sms_handler.py | 22 ++++++--- .../common/config/app_settings.py | 3 ++ .../common/token/token_manager.py | 2 +- apps/notification/create_global_templates.py | 49 ++++++++++++++++--- apps/notification/local.env | 31 ++++++++++++ .../webapi/config/site_settings.py | 2 +- .../notification/webapi/providers/database.py | 36 +++++++++++++- 7 files changed, 129 insertions(+), 16 deletions(-) create mode 100644 apps/notification/local.env diff --git a/apps/notification/backend/infra/sms_handler.py b/apps/notification/backend/infra/sms_handler.py index b6f784e..50147ba 100644 --- a/apps/notification/backend/infra/sms_handler.py +++ b/apps/notification/backend/infra/sms_handler.py @@ -5,14 +5,24 @@ from twilio.rest import Client class SmsHandler: def __init__(self) -> None: - self.twillo_client = Client( - app_settings.TWILIO_ACCOUNT_SID, - app_settings.TWILIO_AUTH_TOKEN, - http_client=AsyncTwilioHttpClient(), - ) + # delay the initialization of the twillio client, not to be created in the constructor + self._twillo_client = None + + async def _get_client(self): + """delay the initialization of the twillio client""" + if self._twillo_client is None: + self._twillo_client = Client( + app_settings.TWILIO_ACCOUNT_SID, + app_settings.TWILIO_AUTH_TOKEN, + http_client=AsyncTwilioHttpClient(), + ) + return self._twillo_client async def send_sms(self, sender: str, receiver: str, message: str): - message = await self.twillo_client.messages.create_async( + # 获取客户端(延迟初始化) + client = await self._get_client() + + message = await client.messages.create_async( to=receiver, from_=sender, body=message ) print("this is message", message) diff --git a/apps/notification/common/config/app_settings.py b/apps/notification/common/config/app_settings.py index 4d634c7..b1e3dc5 100644 --- a/apps/notification/common/config/app_settings.py +++ b/apps/notification/common/config/app_settings.py @@ -22,6 +22,9 @@ class AppSettings(BaseSettings): SECRET_KEY: str = "" + ACCESS_TOKEN_EXPIRE_MINUTES: int = 3600 + REFRESH_TOKEN_EXPIRE_DAYS: int = 1 + SENDGRID_API_KEY: str = "" diff --git a/apps/notification/common/token/token_manager.py b/apps/notification/common/token/token_manager.py index 3034e1f..a2501e7 100644 --- a/apps/notification/common/token/token_manager.py +++ b/apps/notification/common/token/token_manager.py @@ -9,7 +9,7 @@ from starlette.status import HTTP_401_UNAUTHORIZED class TokenManager: def __init__(self): - self.secret_key = app_settings.JWT_SECRET_KEY + self.secret_key = app_settings.SECRET_KEY self.algorithm = "HS256" self.access_token_expire_minutes = app_settings.ACCESS_TOKEN_EXPIRE_MINUTES self.refresh_token_expire_days = app_settings.REFRESH_TOKEN_EXPIRE_DAYS diff --git a/apps/notification/create_global_templates.py b/apps/notification/create_global_templates.py index 7adca6a..667aa1f 100644 --- a/apps/notification/create_global_templates.py +++ b/apps/notification/create_global_templates.py @@ -8,25 +8,62 @@ import aiohttp import json import os import sys -from datetime import datetime +from datetime import datetime, timezone, timedelta +from jose import jwt -# import existing token retrieval logic sys.path.append('.') -from test_config import get_tokens_with_fallback +from common.config.app_settings import app_settings +from webapi.config.site_settings import site_settings class GlobalTemplateCreator: def __init__(self): - self.base_url = "http://localhost:8103/api/notification" + # use site_settings to get base_url + host = 'localhost' if site_settings.SERVER_HOST == '0.0.0.0' else site_settings.SERVER_HOST + port = site_settings.SERVER_PORT + self.base_url = f"http://{host}:{port}/api/notification" self.admin_token = None self.templates = [] + print(f"🔧 use config: {self.base_url}") + + def generate_test_tokens(self): + """generate test JWT token""" + secret_key = app_settings.SECRET_KEY + algorithm = "HS256" + + # generate admin token + admin_payload = { + "id": "test_admin_user", + "role": 8, # ADMINISTRATOR = 8 + "tenant_id": None, + "exp": datetime.now(timezone.utc) + timedelta(hours=1) + } + admin_token = jwt.encode(admin_payload, secret_key, algorithm=algorithm) + + # generate tenant token + tenant_payload = { + "id": "test_tenant_user", + "role": 2, # BUSINESS = 2 + "tenant_id": "test_tenant_user", + "exp": datetime.now(timezone.utc) + timedelta(hours=1) + } + tenant_token = jwt.encode(tenant_payload, secret_key, algorithm=algorithm) + + print("\n🔑 generated test tokens:") + print("=" * 60) + print(f"Admin Token: {admin_token}") + print(f"Tenant Token: {tenant_token}") + print(f"Secret Key: {secret_key[:20]}...") + print("=" * 60) + + return admin_token, tenant_token + async def get_admin_token(self): """get admin token""" print("🔑 get admin token...") try: - # use existing token retrieval logic - admin_token, tenant_token = get_tokens_with_fallback() + admin_token, tenant_token = self.generate_test_tokens() self.admin_token = admin_token if self.admin_token: diff --git a/apps/notification/local.env b/apps/notification/local.env new file mode 100644 index 0000000..34e05c9 --- /dev/null +++ b/apps/notification/local.env @@ -0,0 +1,31 @@ +export APP_NAME=notification +export SERVICE_API_ACCESS_HOST=0.0.0.0 +export SERVICE_API_ACCESS_PORT=8104 +export CONTAINER_APP_ROOT=/app +export LOG_BASE_PATH=$CONTAINER_APP_ROOT/log/$APP_NAME +export BACKEND_LOG_FILE_NAME=$APP_NAME +export APPLICATION_ACTIVITY_LOG=$APP_NAME-activity +export SENDGRID_API_KEY=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 +export EMAIL_FROM=freeleaps@freeleaps.com +export TWILIO_ACCOUNT_SID=ACf8c9283a6acda060258eadb29be58bc8 +export TWILIO_AUTH_TOKEN=ef160748cc22c8b7195b49df4b8eca7e +export SYSTEM_USER_ID=117f191e810c19729de860aa +export SMS_FROM=+16898887156 +export EMAIL_FROM=freeleaps@freeleaps.com +export SECRET_KEY=ea84edf152976b2fcec12b78aa8e45bc26a5cf0ef61bf16f5c317ae33b3fd8b0 +export GIT_REPO_ROOT=/mnt/freeleaps/freeleaps-service-hub +export CODEBASE_ROOT=/mnt/freeleaps/freeleaps-service-hub/apps/notification +export SITE_DEPLOY_FOLDER=/mnt/freeleaps/freeleaps-service-hub/sites/notification/deploy +#!/bin/bash +export VENV_DIR=venv_t +export VENV_ACTIVATE=venv_t/bin/activate +export DOCKER_HOME=/var/lib/docker +export DOCKER_APP_HOME=$DOCKER_HOME/app +export DOCKER_BACKEND_HOME=$DOCKER_APP_HOME/$APP_NAME +export DOCKER_BACKEND_LOG_HOME=$DOCKER_BACKEND_HOME/log +export RABBITMQ_HOST=localhost +export RABBITMQ_PORT=5672 +export MONGODB_URI="mongodb+srv://jetli:8IHKx6dZK8BfugGp@freeleaps2.hanbj.mongodb.net/" +export MONGODB_NAME="freeleaps2" +export FREELEAPS_ENV=local +export LOG_BASE_PATH=./log diff --git a/apps/notification/webapi/config/site_settings.py b/apps/notification/webapi/config/site_settings.py index 43d05d6..4293e5c 100644 --- a/apps/notification/webapi/config/site_settings.py +++ b/apps/notification/webapi/config/site_settings.py @@ -10,7 +10,7 @@ class SiteSettings(BaseSettings): ENV: str = "dev" SERVER_HOST: str = "0.0.0.0" - SERVER_PORT: int = 8103 + SERVER_PORT: int = 8104 URL: str = "http://localhost" TIME_ZONE: str = "UTC" diff --git a/apps/notification/webapi/providers/database.py b/apps/notification/webapi/providers/database.py index ccc3992..9228a49 100644 --- a/apps/notification/webapi/providers/database.py +++ b/apps/notification/webapi/providers/database.py @@ -1,7 +1,30 @@ from webapi.config.site_settings import site_settings from beanie import init_beanie from motor.motor_asyncio import AsyncIOMotorClient +from backend.models.models import MessageTemplateDoc, EmailSenderDoc, EmailSendStatusDoc, EmailTrackingDoc, EmailBounceDoc +import os +# MongoDB config +MONGODB_URI = os.getenv('MONGODB_URI', 'mongodb+srv://jetli:8IHKx6dZK8BfugGp@freeleaps2.hanbj.mongodb.net/') +MONGODB_NAME = os.getenv('MONGODB_NAME', 'freeleaps2') + +# create MongoDB client +client = AsyncIOMotorClient( + MONGODB_URI, + serverSelectionTimeoutMS=60000, + minPoolSize=5, + maxPoolSize=20, + heartbeatFrequencyMS=20000, +) + +# define all document models +document_models = [ + MessageTemplateDoc, + EmailSenderDoc, + EmailSendStatusDoc, + EmailTrackingDoc, + EmailBounceDoc +] def register(app): app.debug = site_settings.DEBUG @@ -13,5 +36,14 @@ def register(app): async def initiate_database(): - # init your database here - pass + """initiate Beanie database connection""" + try: + await init_beanie( + database=client[MONGODB_NAME], + document_models=document_models + ) + print(f"✅ database initialized successfully: {MONGODB_NAME}") + print(f" URI: {MONGODB_URI}") + except Exception as e: + print(f"❌ database initialization failed: {e}") + raise