Merge branch 'dev' into refactor/logging

This commit is contained in:
zhenyus 2025-04-21 02:58:52 +00:00
commit fcc6d22e4d
7 changed files with 88 additions and 31 deletions

26
CHANGELOG.md Normal file
View File

@ -0,0 +1,26 @@
## [1.1.1](https://dev.azure.com/freeleaps/freeleaps-service-hub/_git/freeleaps-service-hub/compare/v1.1.0...v1.1.1) (2025-03-17)
### Bug Fixes
* invalid import path for app config ([4dfbab4](https://dev.azure.com/freeleaps/freeleaps-service-hub/_git/freeleaps-service-hub/commit/4dfbab4d4de83fbe5140c05071d8138cb09ef688))
# [1.1.0](https://dev.azure.com/freeleaps/freeleaps-service-hub/_git/freeleaps-service-hub/compare/v1.0.0...v1.1.0) (2025-03-17)
### Features
* **observability:** add configuration options and implement metrics/probes APIs ([d5e42d3](https://dev.azure.com/freeleaps/freeleaps-service-hub/_git/freeleaps-service-hub/commit/d5e42d31a4ce1ac64f6c5dcf5688c0acae1fdaa6))
* **probes:** add metrics and probes APIs for application health checks ([9754576](https://dev.azure.com/freeleaps/freeleaps-service-hub/_git/freeleaps-service-hub/commit/9754576d28066c9805e5e4673e03fd79b3a603bd))
# 1.0.0 (2025-03-06)
### Bug Fixes
* **rabbitmq:** correct syntax for port and virtual host parameters in AsyncMQClient ([78c7217](https://dev.azure.com/freeleaps/freeleaps-service-hub/_git/freeleaps-service-hub/commit/78c72179ec3fdb15d4af01bee15a441f0e383638))
### Features
* **notification:** add rabbitmq credentials relates notification services configs ([853d817](https://dev.azure.com/freeleaps/freeleaps-service-hub/_git/freeleaps-service-hub/commit/853d81793332513e89286d61429444d520252c27))

1
VERSION Normal file
View File

@ -0,0 +1 @@
1.1.1

View File

@ -1,6 +1,7 @@
from common.config.app_settings import app_settings from common.config.app_settings import app_settings
from backend.content.models import DocumentDoc from backend.content.models import DocumentDoc
from backend.document.models import BasicProfileDoc from backend.document.models import BasicProfileDoc
from datetime import datetime, timezone
import httpx import httpx
import base64 import base64
@ -53,9 +54,12 @@ class DocumentManager:
print(f"Failed to queue deletion: {response.text}") print(f"Failed to queue deletion: {response.text}")
async def cleanup_document(self): async def cleanup_document(self):
# Get today's date at midnight (UTC)
today_start = datetime.now(timezone.utc).replace(hour=0, minute=0, second=0, microsecond=0)
# Corrected query with regex # Corrected query with regex
documents = await DocumentDoc.find( documents = await DocumentDoc.find(
{"created_by": {"$regex": "^content-service-"}} {"created_by": {"$regex": "^content-service-"},
"create_time": {"$lt": today_start}}
).to_list() ).to_list()
if documents: if documents:

View File

@ -1,5 +1,6 @@
from apscheduler.schedulers.asyncio import AsyncIOScheduler from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.triggers.date import DateTrigger from apscheduler.triggers.date import DateTrigger
from apscheduler.triggers.cron import CronTrigger
from datetime import datetime, timedelta from datetime import datetime, timedelta
from scheduler.refresh_sharepoint_content_job import ( from scheduler.refresh_sharepoint_content_job import (
refresh_sharepoint_content_job, refresh_sharepoint_content_job,
@ -28,15 +29,11 @@ async def register_job(scheduler: AsyncIOScheduler):
"date", "date",
run_date=datetime(2025, 2, 7, 20, 0, 0), run_date=datetime(2025, 2, 7, 20, 0, 0),
) )
# Register cleanup_document_job as a one-time job
# This job is just one-time job for removing many unused documents await init_lock(ScheduleJobLocker.CLEANUP_DOCUMENT_JOB_LOCKER)
# Run already, now comment it out scheduler.add_job(
# await init_lock(ScheduleJobLocker.CLEANUP_DOCUMENT_JOB_LOCKER) cleanup_document_job,
# execution_time = datetime.now() + timedelta( trigger=CronTrigger(hour=2, minute=0), # Runs every day at 2:00 AM
# seconds=60 id="cleanup_document_daily",
# ) # Schedule to run 60 seconds from now )
# scheduler.add_job(
# cleanup_document_job, # Job function
# trigger=DateTrigger(run_date=execution_time), # One-time trigger
# id="cleanup_document_one_time", # Optional: Give the job an ID
# )

View File

@ -86,26 +86,44 @@ class NotificationManager:
properties: dict, properties: dict,
region: Optional[UserRegion] = None, region: Optional[UserRegion] = None,
) -> str: ) -> str:
# leverage the information in properties to enrich the message. # Default region to international if not set
message_subject = None
message = None
if subject.lower() == "payment":
pass
# Default region to be international if not set
if region is None: if region is None:
region = UserRegion.OTHER region = UserRegion.OTHER
message_subject = SystemNotifications[region][subject.lower()][event.lower()][ subject_lower = subject.lower()
"message_subject" event_lower = event.lower()
]
message = SystemNotifications[region][subject.lower()][event.lower()]["message"]
if event.lower() == "authentication": try:
message = message.format(properties["auth_code"]) # Get message template and subject from SystemNotifications
if not message: notification_config = SystemNotifications[region][subject_lower][event_lower]
raise RuntimeError("unsupported event:{}".format(event)) message = notification_config["message"]
return message, message_subject message_subject = notification_config["message_subject"]
# Handle authentication specific formatting
if event_lower == "authentication" and "auth_code" in properties:
message = message.format(properties["auth_code"])
# Append content_text if it exists in properties
if properties.get("content_text"):
if isinstance(properties["content_text"], dict):
# If content_text is a dictionary, use format with kwargs
message = message.format(**properties["content_text"])
elif isinstance(properties["content_text"], str):
# If content_text is a string, append it with proper spacing
content = properties["content_text"].strip()
if message and content:
# Use HTML line breaks for email compatibility
message = f"{message.rstrip()}<br><br>{content}"
else:
# If either is empty, just use the non-empty one
message = message or content
return message, message_subject
except KeyError as e:
raise RuntimeError(f"Unsupported configuration - subject: {subject_lower}, event: {event_lower}, error: {str(e)}")
except ValueError as e:
raise RuntimeError(f"Invalid message format - error: {str(e)}")
async def send_in_app_notification( async def send_in_app_notification(
self, receiver_id: str, subject: str, event: str, properties: dict = None self, receiver_id: str, subject: str, event: str, properties: dict = None

View File

@ -14,6 +14,7 @@ from webapi.providers import metrics
from .freeleaps_app import FreeleapsApp from .freeleaps_app import FreeleapsApp
from common.config.app_settings import app_settings from common.config.app_settings import app_settings
from prometheus_fastapi_instrumentator import Instrumentator
def create_app() -> FastAPI: def create_app() -> FastAPI:
logging.info("App initializing") logging.info("App initializing")
@ -38,6 +39,8 @@ def create_app() -> FastAPI:
# Call the custom_openapi function to change the OpenAPI version # Call the custom_openapi function to change the OpenAPI version
customize_openapi_security(app) customize_openapi_security(app)
# expose prometheus metrics
Instrumentator().instrument(app).expose(app)
return app return app

View File

@ -25,6 +25,14 @@ class StripeManager:
async def create_account_link(self, account_id: str, link_type: str = "account_onboarding") -> Optional[str]: async def create_account_link(self, account_id: str, link_type: str = "account_onboarding") -> Optional[str]:
account = stripe.Account.retrieve(account_id) account = stripe.Account.retrieve(account_id)
# For account_update, try to show dashboard if TOS is accepted # For account_update, try to show dashboard if TOS is accepted
self.module_logger.log_info("create_account_link urls",
{
"redirect_url": "{}/work".format(self.site_url_root),
"refresh_url": "{}/front-door".format(self.site_url_root),
"return_url": "{}/work".format(self.site_url_root)
}
)
if link_type == "account_update" and account.tos_acceptance.date: if link_type == "account_update" and account.tos_acceptance.date:
login_link = stripe.Account.create_login_link( login_link = stripe.Account.create_login_link(
account_id, account_id,
@ -284,10 +292,10 @@ class StripeManager:
}, },
}, },
mode="payment", mode="payment",
success_url="{}/work-space".format( success_url="{}/projects".format(
self.site_url_root self.site_url_root
), # needs to be set, local: http://localhost/ ), # needs to be set, local: http://localhost/
cancel_url="{}/work-space".format(self.site_url_root), cancel_url="{}/projects".format(self.site_url_root),
) )
if session: if session: