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 backend.content.models import DocumentDoc
from backend.document.models import BasicProfileDoc
from datetime import datetime, timezone
import httpx
import base64
@ -53,9 +54,12 @@ class DocumentManager:
print(f"Failed to queue deletion: {response.text}")
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
documents = await DocumentDoc.find(
{"created_by": {"$regex": "^content-service-"}}
{"created_by": {"$regex": "^content-service-"},
"create_time": {"$lt": today_start}}
).to_list()
if documents:

View File

@ -1,5 +1,6 @@
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.triggers.date import DateTrigger
from apscheduler.triggers.cron import CronTrigger
from datetime import datetime, timedelta
from scheduler.refresh_sharepoint_content_job import (
refresh_sharepoint_content_job,
@ -28,15 +29,11 @@ async def register_job(scheduler: AsyncIOScheduler):
"date",
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
# Run already, now comment it out
# await init_lock(ScheduleJobLocker.CLEANUP_DOCUMENT_JOB_LOCKER)
# execution_time = datetime.now() + timedelta(
# seconds=60
# ) # 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
# )
await init_lock(ScheduleJobLocker.CLEANUP_DOCUMENT_JOB_LOCKER)
scheduler.add_job(
cleanup_document_job,
trigger=CronTrigger(hour=2, minute=0), # Runs every day at 2:00 AM
id="cleanup_document_daily",
)

View File

@ -86,27 +86,45 @@ class NotificationManager:
properties: dict,
region: Optional[UserRegion] = None,
) -> str:
# leverage the information in properties to enrich the message.
message_subject = None
message = None
if subject.lower() == "payment":
pass
# Default region to be international if not set
# Default region to international if not set
if region is None:
region = UserRegion.OTHER
message_subject = SystemNotifications[region][subject.lower()][event.lower()][
"message_subject"
]
message = SystemNotifications[region][subject.lower()][event.lower()]["message"]
subject_lower = subject.lower()
event_lower = event.lower()
if event.lower() == "authentication":
try:
# Get message template and subject from SystemNotifications
notification_config = SystemNotifications[region][subject_lower][event_lower]
message = notification_config["message"]
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"])
if not message:
raise RuntimeError("unsupported event:{}".format(event))
# 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(
self, receiver_id: str, subject: str, event: str, properties: dict = None
) -> None:

View File

@ -14,6 +14,7 @@ from webapi.providers import metrics
from .freeleaps_app import FreeleapsApp
from common.config.app_settings import app_settings
from prometheus_fastapi_instrumentator import Instrumentator
def create_app() -> FastAPI:
logging.info("App initializing")
@ -38,6 +39,8 @@ def create_app() -> FastAPI:
# Call the custom_openapi function to change the OpenAPI version
customize_openapi_security(app)
# expose prometheus metrics
Instrumentator().instrument(app).expose(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]:
account = stripe.Account.retrieve(account_id)
# 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:
login_link = stripe.Account.create_login_link(
account_id,
@ -284,10 +292,10 @@ class StripeManager:
},
},
mode="payment",
success_url="{}/work-space".format(
success_url="{}/projects".format(
self.site_url_root
), # 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: