This commit is contained in:
Mike Liao 2024-10-30 20:49:50 -07:00
parent 234c5a491f
commit ee5e80acd9
49 changed files with 658 additions and 76 deletions

View File

@ -12,8 +12,9 @@ class AppSettings(BaseSettings):
MONGODB_URI:str= "" MONGODB_URI:str= ""
MONGODB_NAME:str= "" MONGODB_NAME:str= ""
LOG_BASE_PATH : str = "./log"
BACKEND_LOG_FILE_NAME: str = APP_NAME
APPLICATION_ACTIVITY_LOG: str = APP_NAME + "-application-activity" APPLICATION_ACTIVITY_LOG: str = APP_NAME + "-application-activity"
BUSINESS_METRIC_LOG: str = APP_NAME + "-business-metrics"
class Config: class Config:
env_file = ".myapp.env" env_file = ".myapp.env"

View File

@ -4,11 +4,16 @@ from pydantic_settings import BaseSettings
class AppSettings(BaseSettings): class AppSettings(BaseSettings):
NAME: str = "central_storage" NAME: str = "central_storage"
APP_NAME:str = NAME
AZURE_STORAGE_DOCUMENT_API_ENDPOINT: str = "" AZURE_STORAGE_DOCUMENT_API_ENDPOINT: str = ""
AZURE_STORAGE_DOCUMENT_API_KEY: str = "" AZURE_STORAGE_DOCUMENT_API_KEY: str = ""
LOG_BASE_PATH : str = "./log"
BACKEND_LOG_FILE_NAME: str = APP_NAME
APPLICATION_ACTIVITY_LOG: str = APP_NAME + "-application-activity"
class Config: class Config:
env_file = ".myapp.env" env_file = ".myapp.env"
env_file_encoding = "utf-8" env_file_encoding = "utf-8"

View File

@ -9,8 +9,9 @@ class AppSettings():
CENTRAL_STORAGE_WEBAPI_URL_BASE:str ="" CENTRAL_STORAGE_WEBAPI_URL_BASE:str =""
LOG_BASE_PATH : str = "./log"
BACKEND_LOG_FILE_NAME: str = APP_NAME
APPLICATION_ACTIVITY_LOG: str = APP_NAME + "-application-activity" APPLICATION_ACTIVITY_LOG: str = APP_NAME + "-application-activity"
BUSINESS_METRIC_LOG: str = APP_NAME + "-business-metrics"
class Config: class Config:
env_file = ".content.env" env_file = ".content.env"

View File

@ -1,6 +1,6 @@
from typing import Dict from typing import Dict
from app.notification.backend.business.notification_manager import NotificationManager from backend.business.notification_manager import NotificationManager
from app.notification.backend.models.constants import NotificationChannel from backend.models.constants import NotificationChannel
class NotificationHub: class NotificationHub:

View File

@ -1,11 +1,11 @@
from typing import Dict from typing import Dict
from app.notification.backend.services.sms_service import SmsService from backend.services.sms_service import SmsService
from app.notification.backend.services.in_app_notif_service import InAppNotifService from backend.services.in_app_notif_service import InAppNotifService
from app.notification.backend.services.email_service import EmailService from backend.services.email_service import EmailService
from app.notification.backend.services.notification_publisher_service import ( from backend.services.notification_publisher_service import (
NotificationPublisherService, NotificationPublisherService,
) )
from app.notification.backend.models.constants import ( from backend.models.constants import (
NotificationChannel, NotificationChannel,
NotificationMessage, NotificationMessage,
SystemNotifications, SystemNotifications,
@ -14,8 +14,8 @@ import threading
from datetime import datetime, timezone from datetime import datetime, timezone
from typing import Optional, Type from typing import Optional, Type
from types import TracebackType from types import TracebackType
from infra.models.constants import UserRegion from common.constants.region import UserRegion
from app.notification.common.config.app_settings import app_settings from common.config.app_settings import app_settings
from datetime import datetime, timezone from datetime import datetime, timezone

View File

@ -1,7 +1,7 @@
from app.notification.common.config.app_settings import app_settings from common.config.app_settings import app_settings
from sendgrid import SendGridAPIClient from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail from sendgrid.helpers.mail import Mail
from infra.log.module_logger import ModuleLogger from common.log.module_logger import ModuleLogger
class EmailHandler: class EmailHandler:

View File

@ -1,5 +1,5 @@
from app.notification.common.config.app_settings import app_settings from common.config.app_settings import app_settings
from infra.log.module_logger import ModuleLogger from common.log.module_logger import ModuleLogger
import asyncio import asyncio
from asyncio import AbstractEventLoop from asyncio import AbstractEventLoop
import aio_pika import aio_pika
@ -17,7 +17,7 @@ class AsyncMQClient:
self.process_callable = None self.process_callable = None
self.routing_key = self.channel_name self.routing_key = self.channel_name
self.module_logger = ModuleLogger(sender_id="AsyncMQClient") self.module_logger = ModuleLogger(sender_id="AsyncMQClient")
self.connection_url = "amqp://guest:guest@{}:{}/".format(app_settings.RABBITMQ_HOST,app_settings.RABBITMQ_PORT)
async def bind(self, max_retries=10, event_loop: AbstractEventLoop = None): async def bind(self, max_retries=10, event_loop: AbstractEventLoop = None):
retry_count = 0 retry_count = 0
retry_interval = 1 # Start with a 1-second interval retry_interval = 1 # Start with a 1-second interval
@ -25,7 +25,7 @@ class AsyncMQClient:
while retry_count < max_retries: while retry_count < max_retries:
try: try:
self.connection = await aio_pika.connect_robust( self.connection = await aio_pika.connect_robust(
"amqp://guest:guest@rabbitmq:5672/", self.connection_url,
loop=event_loop, loop=event_loop,
) )
self.channel = await self.connection.channel() self.channel = await self.connection.channel()

View File

@ -1,4 +1,4 @@
from infra.log.module_logger import ModuleLogger from common.log.module_logger import ModuleLogger
from .async_client import AsyncMQClient from .async_client import AsyncMQClient
import aio_pika import aio_pika
import json import json

View File

@ -1,5 +1,5 @@
from asyncio import AbstractEventLoop from asyncio import AbstractEventLoop
from infra.log.module_logger import ModuleLogger from common.log.module_logger import ModuleLogger
import json import json
import asyncio import asyncio
from .async_client import AsyncMQClient from .async_client import AsyncMQClient

View File

@ -1,4 +1,4 @@
from app.notification.common.config.app_settings import app_settings from common.config.app_settings import app_settings
from twilio.http.async_http_client import AsyncTwilioHttpClient from twilio.http.async_http_client import AsyncTwilioHttpClient
from twilio.rest import Client from twilio.rest import Client

View File

@ -1,6 +1,6 @@
from enum import Enum from enum import Enum
from pydantic import BaseModel from pydantic import BaseModel
from infra.models.constants import UserRegion from common.constants.region import UserRegion
class NotificationChannel(Enum): class NotificationChannel(Enum):

View File

@ -1,5 +1,5 @@
from app.notification.backend.models.constants import NotificationChannel from backend.models.constants import NotificationChannel
from app.notification.backend.infra.rabbitmq.async_publisher import AsyncMQPublisher from backend.infra.rabbitmq.async_publisher import AsyncMQPublisher
class NotificationPublisherService: class NotificationPublisherService:

View File

@ -4,22 +4,26 @@ from pydantic_settings import BaseSettings
class AppSettings(BaseSettings): class AppSettings(BaseSettings):
NAME: str = "notification" NAME: str = "notification"
APP_NAME:str = NAME
RABBITMQ_HOST: str = "rabbitmq"
RABBITMQ_HOST: str = ""
RABBITMQ_PORT: int = 5672 RABBITMQ_PORT: int = 5672
SYSTEM_USER_ID: str = "117f191e810c19729de860aa" SYSTEM_USER_ID: str = ""
SMS_FROM: str = "+16898887156" SMS_FROM: str = ""
EMAIL_FROM: str = "freeleaps@freeleaps.com" EMAIL_FROM: str = ""
SECRET_KEY: str = "" SECRET_KEY: str = ""
SENDGRID_API_KEY: str = ( SENDGRID_API_KEY: str = ""
"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"
)
TWILIO_ACCOUNT_SID: str = "ACf8c9283a6acda060258eadb29be58bc8" TWILIO_ACCOUNT_SID: str = ""
TWILIO_AUTH_TOKEN: str = "ef160748cc22c8b7195b49df4b8eca7e" TWILIO_AUTH_TOKEN: str = ""
LOG_BASE_PATH : str = "./log"
BACKEND_LOG_FILE_NAME: str = APP_NAME
APPLICATION_ACTIVITY_LOG: str = APP_NAME + "-application-activity"
class Config: class Config:
env_file = ".myapp.env" env_file = ".myapp.env"

View File

@ -0,0 +1,8 @@
from enum import IntEnum
class UserContractRole(IntEnum):
VISITER = 0x1
REQUESTER = 0x2
PROVIDER = 0x4

View File

@ -0,0 +1,5 @@
from enum import IntEnum
class PaymentPlanType(IntEnum):
STAGED = 0

View File

@ -0,0 +1,5 @@
from enum import IntEnum
class UserRegion(IntEnum):
OTHER = 0
ZH_CN = 1

View File

@ -0,0 +1,23 @@
class DoesNotExistError(Exception):
def __init__(self, message: str = "Does Not Exist"):
self.message = message
class AuthenticationError(Exception):
def __init__(self, message: str = "Unauthorized"):
self.message = message
class AuthorizationError(Exception):
def __init__(self, message: str = "Forbidden"):
self.message = message
class InvalidOperationError(Exception):
def __init__(self, message: str = "Invalid Operation"):
self.message = message
class InvalidDataError(Exception):
def __init__(self, message: str = "Invalid Data"):
self.message = message

View File

View File

@ -0,0 +1,14 @@
from .base_logger import LoggerBase
from common.config.app_settings import app_settings
import json
class ApplicationLogger(LoggerBase):
def __init__(self, application_activities: dict[str, any] = {}) -> None:
extra_fileds = {}
if application_activities:
extra_fileds.update(application_activities)
super().__init__(
logger_name=app_settings.APPLICATION_ACTIVITY_LOG,
extra_fileds=extra_fileds,
)

View File

@ -0,0 +1,139 @@
from loguru import logger as guru_logger
from common.config.log_settings import log_settings
from typing import List
import socket
import json
import logging
import threading
class LoggerBase:
binded_loggers = {}
logger_lock = threading.Lock()
def __init__(
self, logger_name: str, extra_fileds: dict[str, any]
) -> None:
self.__logger_name = logger_name
self.extra_fileds = extra_fileds
with LoggerBase.logger_lock:
if self.__logger_name in LoggerBase.binded_loggers:
self.logger = LoggerBase.binded_loggers[self.__logger_name]
return
log_filename = (
log_settings.LOG_BASE_PATH + "/" + self.__logger_name + ".log"
)
log_retention = log_settings.LOG_RETENTION
log_rotation = log_settings.LOG_ROTATION
log_level = "INFO"
log_message_format = "{message}"
guru_logger.add(
sink=log_filename,
level=log_level,
retention=log_retention,
rotation=log_rotation,
format=log_message_format,
serialize=True,
filter=lambda record: "extra" in record
and "topic" in record["extra"]
and record["extra"]["topic"] == self.__logger_name,
)
host_name = socket.gethostname()
host_ip = socket.gethostbyname(host_name)
self.logger = guru_logger.bind(
topic=self.__logger_name,
host_ip=host_ip,
host_name=host_name,
)
with LoggerBase.logger_lock:
LoggerBase.binded_loggers[self.__logger_name] = self.logger
async def log_event(
self,
sender_id: str,
receiver_id: str,
subject: str,
event: str,
properties: dict[str, any],
text: str = ""
) -> None:
local_logger = self.logger.bind(
sender_id=sender_id,
receiver_id=receiver_id,
subject=subject,
event=event,
properties=properties
)
local_logger.info(text)
async def log_exception(
self,
sender_id: str,
receiver_id: str,
subject: str,
exception: Exception,
text: str = "",
properties: dict[str, any] = None,
) -> None:
local_logger = self.logger.bind(
sender_id=sender_id,
receiver_id=receiver_id,
subject=subject,
event="exception",
properties=properties,
exception=exception
)
local_logger.exception(text)
async def log_info(
self,
sender_id: str,
receiver_id: str,
subject: str,
text: str = "",
properties: dict[str, any] = None,
) -> None:
local_logger = self.logger.bind(
sender_id=sender_id,
receiver_id=receiver_id,
subject=subject,
event="information",
properties=properties,
)
local_logger.info(text)
async def log_warning(
self,
sender_id: str,
receiver_id: str,
subject: str,
text: str = "",
properties: dict[str, any] = None,
) -> None:
local_logger = self.logger.bind(
sender_id=sender_id,
receiver_id=receiver_id,
subject=subject,
event="warning",
properties=properties,
)
local_logger.warning(text)
async def log_error(
self,
sender_id: str,
receiver_id: str,
subject: str,
text: str = "",
properties: dict[str, any] = None,
) -> None:
local_logger = self.logger.bind(
sender_id=sender_id,
receiver_id=receiver_id,
subject=subject,
event="error",
properties=properties,
)
local_logger.error(text)

View File

@ -0,0 +1,25 @@
from .base_logger import LoggerBase
from common.config.app_settings import app_settings
import json
class BusinessMetricLogger(LoggerBase):
def __init__(self, business_metrics: dict[str, any] = {}) -> None:
extra_fileds = {}
if business_metrics:
extra_fileds.update(business_metrics)
super().__init__(
logger_name=app_settings.BUSINESS_METRIC_LOG,
extra_fileds=extra_fileds,
)
async def log_metrics(self, business_metrics: dict[str, any] = {}) -> None:
return await super().log_event(
sender_id="business_metric_manager",
receiver_id="business_metric_logger",
subject="metrics",
event="logging",
properties=business_metrics,
text="business metric logged"
)

View File

@ -0,0 +1,50 @@
from .application_logger import ApplicationLogger
class FunctionLogger(ApplicationLogger):
def __init__(self, sender_id: str, receiver_id:str) -> None:
super().__init__()
self.event_sender_id = sender_id
self.event_receiver_id = receiver_id
self.event_subject = "function"
async def log_enter(self, function: str, file: str):
return await super().log_event(
sender_id=self.event_sender_id,
receiver_id=self.event_receiver_id,
subject=self.event_subject,
event="enter",
properties={
"function": function,
"file": file,
},
text="Enter:{} of {}".format(function, file)
)
async def log_exit(self, function: str, file: str, excution_time_in_ns: int):
return await super().log_event(
sender_id=self.event_sender_id,
receiver_id=self.event_receiver_id,
subject=self.event_subject,
event="exit",
properties={
"function": function,
"file": file,
"excution_time_in_ns": excution_time_in_ns
},
text="Exit:{} of {}".format(function, file)
)
async def log_exception(self, exception: Exception, function: str, file: str, excution_time_in_ns: int) -> None:
return await super().log_exception(
sender_id=self.event_sender_id,
receiver_id=self.event_receiver_id,
subject=self.event_subject,
exception=exception,
text="Exception:{} of {}".format(function, file),
properties={
"function": function,
"file": file,
"excution_time_in_ns": excution_time_in_ns
},
)

View File

@ -0,0 +1,25 @@
import os
from .function_logger import FunctionLogger
import time
import functools
def log_entry_exit_async(func):
@functools.wraps(func)
async def wrapper(*args, **kwargs):
file_path = os.path.relpath(func.__code__.co_filename)
function_logger = FunctionLogger(sender_id="log_entry_exit_async", receiver_id="function_logger")
start_time = time.process_time_ns()
try:
await function_logger.log_enter(func.__name__, file_path)
result = await func(*args, **kwargs)
await function_logger.log_exit(func.__name__, file_path, time.process_time_ns() - start_time)
return result
except Exception as exception:
await function_logger.log_exception(
exception=exception,
function=func.__name__,
file=file_path,
excution_time_in_ns=time.process_time_ns() - start_time)
raise
return wrapper

View File

@ -0,0 +1,46 @@
from .application_logger import ApplicationLogger
class ModuleLogger(ApplicationLogger):
def __init__(self, sender_id: str) -> None:
super().__init__()
self.event_sender_id = sender_id
self.event_receiver_id = "ModuleLogger"
self.event_subject = "module"
async def log_exception(self, exception: Exception, text: str = "Exception", properties: dict[str, any] = None) -> None:
return await super().log_exception(
sender_id=self.event_sender_id,
receiver_id=self.event_receiver_id,
subject=self.event_subject,
exception=exception,
text=text,
properties=properties,
)
async def log_info(self, info: str, properties: dict[str, any] = None) -> None:
return await super().log_info(
sender_id=self.event_sender_id,
receiver_id=self.event_receiver_id,
subject=self.event_subject,
text=info,
properties=properties,
)
async def log_warning(self, warning: str, properties: dict[str, any] = None) -> None:
return await super().log_warning(
sender_id=self.event_sender_id,
receiver_id=self.event_receiver_id,
subject=self.event_subject,
text=warning,
properties=properties,
)
async def log_error(self, error: str, properties: dict[str, any] = None) -> None:
return await super().log_error(
sender_id=self.event_sender_id,
receiver_id=self.event_receiver_id,
subject=self.event_subject,
text=error,
properties=properties,
)

View File

@ -0,0 +1,14 @@
from .base_logger import LoggerBase
from common.config.app_settings import app_settings
import json
class UserLogger(LoggerBase):
def __init__(self, user_activities: dict[str, any] = {}) -> None:
extra_fileds = {}
if user_activities:
extra_fileds.update(user_activities)
super().__init__(
logger_name=app_settings.USER_ACTIVITY_LOG, extra_fileds=extra_fileds
)

View File

@ -0,0 +1,80 @@
from datetime import datetime, timedelta, timezone
from typing import Dict
from jose import jwt, JWTError
from common.config.app_settings import app_settings
from fastapi import Depends, HTTPException
from fastapi.security import OAuth2PasswordBearer
from starlette.status import HTTP_401_UNAUTHORIZED
class TokenManager:
def __init__(self):
self.secret_key = app_settings.JWT_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
def create_access_token(self, subject: Dict[str, str]) -> str:
"""
Generates an access token with a short expiration time.
"""
expire = datetime.now(timezone.utc) + timedelta(
minutes=self.access_token_expire_minutes
)
to_encode = subject.copy()
to_encode.update({"exp": expire})
return jwt.encode(to_encode, self.secret_key, algorithm=self.algorithm)
def create_refresh_token(self, subject: Dict[str, str]) -> str:
"""
Generates a refresh token with a longer expiration time.
"""
expire = datetime.now(timezone.utc) + timedelta(
days=self.refresh_token_expire_days
)
to_encode = subject.copy()
to_encode.update({"exp": expire})
return jwt.encode(to_encode, self.secret_key, algorithm=self.algorithm)
def decode_token(self, token: str) -> Dict:
"""
Decodes a JWT token and returns the payload.
"""
try:
payload = jwt.decode(token, self.secret_key, algorithms=[self.algorithm])
return payload
except JWTError:
raise ValueError("Invalid token")
def verify_refresh_token(self, token: str) -> bool:
"""
Verifies a refresh token to ensure it is valid and not expired.
"""
try:
payload = self.decode_token(token)
return True
except ValueError:
return False
def refresh_access_token(self, refresh_token: str, subject: Dict[str, str]) -> str:
"""
Verifies the refresh token and creates a new access token.
"""
if self.verify_refresh_token(refresh_token):
return self.create_access_token(subject)
else:
raise ValueError("Invalid refresh token")
async def get_current_user(
self, token: str = Depends(OAuth2PasswordBearer(tokenUrl="token"))
) -> Dict:
"""
Extract and validate user information from the JWT token.
"""
try:
payload = self.decode_token(token) # Decode JWT token
return payload
except ValueError:
raise HTTPException(
status_code=HTTP_401_UNAUTHORIZED, detail="Invalid or expired token"
)

View File

@ -0,0 +1,22 @@
import datetime
from datetime import timedelta, timezone
def get_sunday(date):
return date - datetime.timedelta(days=date.weekday()) + timedelta(days=6)
def get_last_sunday_dates(number, include_current_week=True):
now_utc = datetime.datetime.now(timezone.utc)
today = datetime.datetime(now_utc.year, now_utc.month, now_utc.day)
if include_current_week:
days_to_last_sunday = (6 - today.weekday()) % 7
last_sunday = today + datetime.timedelta(days=days_to_last_sunday)
else:
days_to_last_sunday = (today.weekday() - 6) % 7
last_sunday = today - datetime.timedelta(days=days_to_last_sunday)
last_n_sundays = []
for i in range(number):
sunday = last_sunday - datetime.timedelta(days=i * 7)
last_n_sundays.append(sunday.date())
return last_n_sundays

View File

@ -0,0 +1,13 @@
from common.constants.region import UserRegion
class RegionHandler:
def __init__(self):
self._zh_cn_patterns = [".cn", "cn.", "host"]
def detect_from_host(self, host: str) -> UserRegion:
# Now we set user preferred region based on host
for parttern in self._zh_cn_patterns:
if parttern in host.lower():
return UserRegion.ZH_CN
return UserRegion.OTHER

View File

@ -0,0 +1,87 @@
import random
import re
import jieba
from typing import List
SKILL_TAGS = [
"C++",
"Java",
"Python",
"TypeScript",
"iOS",
"Android",
"Web",
"Javascript",
"Vue",
"Go",
]
# dynamically update skill tags? maybe based on the most commonly extracted keywords to help the system adapt to change
def updateSkillTags(string):
SKILL_TAGS.append(string)
def generate_auth_code():
filtered = "0123456789"
code = "".join(random.choice(filtered) for i in range(6))
return code
# TODO: Need to optimize
def generate_self_intro_summary(content_html: str) -> str:
element_html = re.compile("<.*?>")
content_text = re.sub(element_html, "", content_html).strip()
return content_text[:50]
# TODO: Need to optimize
def extract_skill_tags(content_html: str) -> List[str]:
element_html = re.compile("<.*?>")
content_text = re.sub(element_html, "", content_html).strip()
words = set([word.lower() for word in jieba.cut(content_text) if word.strip()])
results = []
for tag in SKILL_TAGS:
if tag.lower() in words:
results.append(tag)
return results
def extract_title(content_html: str) -> List[str]:
element_html = re.compile("<.*?>")
content_text = re.sub(element_html, "\n", content_html).strip()
cut_point_indexes = []
for cut_point in [".", ",", ";", "\r", "\n"]:
result = content_text.find(cut_point)
if result > 0:
cut_point_indexes.append(result)
title = (
content_text[: min(cut_point_indexes)]
if len(cut_point_indexes) > 0
else content_text
)
return title
def check_password_complexity(password):
lowercase_pattern = r"[a-z]"
uppercase_pattern = r"[A-Z]"
digit_pattern = r"\d"
special_pattern = r'[!@#$%^&*(),.?":{}|<>]'
password_lowercase_one = bool(re.search(lowercase_pattern, password))
password_uppercase_one = bool(re.search(uppercase_pattern, password))
password_digit_one = bool(re.search(digit_pattern, password))
password_special_one = bool(re.search(special_pattern, password))
if (
password_lowercase_one
and password_uppercase_one
and password_digit_one
and password_special_one
):
return True
else:
return False

View File

@ -10,11 +10,11 @@ CODEBASE_ROOT=$GIT_REPO_ROOT/$APP_PARENT_FOLDER/$APP_NAME
SITE_DEPLOY_FOLDER=$GIT_REPO_ROOT/sites/$APP_NAME/deploy SITE_DEPLOY_FOLDER=$GIT_REPO_ROOT/sites/$APP_NAME/deploy
echo APP_NAME=$APP_NAME > .env echo export APP_NAME=$APP_NAME > .env
cat $SITE_DEPLOY_FOLDER/common/.env >> .env cat $SITE_DEPLOY_FOLDER/common/.env >> .env
echo GIT_REPO_ROOT=$(git rev-parse --show-toplevel) >> .env echo export GIT_REPO_ROOT=$(git rev-parse --show-toplevel) >> .env
echo CODEBASE_ROOT=$GIT_REPO_ROOT/$APP_PARENT_FOLDER/$APP_NAME >> .env echo export CODEBASE_ROOT=$GIT_REPO_ROOT/$APP_PARENT_FOLDER/$APP_NAME >> .env
echo SITE_DEPLOY_FOLDER=$GIT_REPO_ROOT/sites/$APP_NAME/deploy >> .env echo export SITE_DEPLOY_FOLDER=$GIT_REPO_ROOT/sites/$APP_NAME/deploy >> .env
cat $SITE_DEPLOY_FOLDER/common/.host.env >> .env cat $SITE_DEPLOY_FOLDER/common/.host.env >> .env
cat $SITE_DEPLOY_FOLDER/local/.env >> .env cat $SITE_DEPLOY_FOLDER/local/.env >> .env

View File

@ -2,13 +2,13 @@ import logging
from fastapi import FastAPI from fastapi import FastAPI
from fastapi.openapi.utils import get_openapi from fastapi.openapi.utils import get_openapi
from app.notification.webapi.providers import common from webapi.providers import common
from app.notification.webapi.providers import logger from webapi.providers import logger
from app.notification.webapi.providers import router from webapi.providers import router
from app.notification.webapi.providers import database from webapi.providers import database
from app.notification.webapi.providers import scheduler from webapi.providers import scheduler
from app.notification.webapi.providers import message_queue from webapi.providers import message_queue
from app.notification.webapi.providers import exception_handler from webapi.providers import exception_handler
from .freeleaps_app import FreeleapsApp from .freeleaps_app import FreeleapsApp

View File

@ -1,8 +1,8 @@
from fastapi import FastAPI from fastapi import FastAPI
from app.notification.backend.infra.rabbitmq.async_subscriber import AsyncMQSubscriber from backend.infra.rabbitmq.async_subscriber import AsyncMQSubscriber
from app.notification.backend.models.constants import NotificationChannel from backend.models.constants import NotificationChannel
from app.notification.webapi.utils.email_consumer import EmailMQConsumer from webapi.utils.email_consumer import EmailMQConsumer
from app.notification.webapi.utils.sms_consumer import SmsMQConsumer from webapi.utils.sms_consumer import SmsMQConsumer
class FreeleapsApp(FastAPI): class FreeleapsApp(FastAPI):

View File

@ -1,5 +1,5 @@
from app.notification.webapi.bootstrap.application import create_app from webapi.bootstrap.application import create_app
from app.notification.webapi.config.site_settings import site_settings from webapi.config.site_settings import site_settings
from fastapi.responses import RedirectResponse from fastapi.responses import RedirectResponse
import uvicorn import uvicorn
from typing import Any from typing import Any

View File

@ -1,5 +1,5 @@
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
from app.notification.webapi.config.site_settings import site_settings from webapi.config.site_settings import site_settings
def register(app): def register(app):

View File

@ -1,4 +1,4 @@
from app.notification.webapi.config.site_settings import site_settings from webapi.config.site_settings import site_settings
from beanie import init_beanie from beanie import init_beanie
from motor.motor_asyncio import AsyncIOMotorClient from motor.motor_asyncio import AsyncIOMotorClient

View File

@ -1,7 +1,7 @@
import logging import logging
import sys import sys
from loguru import logger from loguru import logger
from infra.config.log_settings import log_settings from common.config.log_settings import log_settings
def register(app=None): def register(app=None):

View File

@ -1,4 +1,4 @@
from app.notification.webapi.routes import api_router from webapi.routes import api_router
from starlette import routing from starlette import routing

View File

@ -8,9 +8,9 @@ from fastapi import (
WebSocketDisconnect, WebSocketDisconnect,
) )
from starlette.websockets import WebSocketState from starlette.websockets import WebSocketState
from infra.log.module_logger import ModuleLogger from common.log.module_logger import ModuleLogger
from app.notification.common.config.app_settings import app_settings from common.config.app_settings import app_settings
from app.notification.backend.business.notification_manager import NotificationManager from backend.business.notification_manager import NotificationManager
async def consume_message(requester_key, message, args): async def consume_message(requester_key, message, args):

View File

@ -2,9 +2,9 @@ from fastapi import APIRouter, Depends, HTTPException
import traceback import traceback
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
from starlette.status import HTTP_500_INTERNAL_SERVER_ERROR from starlette.status import HTTP_500_INTERNAL_SERVER_ERROR
from app.notification.backend.application.notification_hub import NotificationHub from backend.application.notification_hub import NotificationHub
from pydantic import BaseModel from pydantic import BaseModel
from app.notification.backend.models.constants import NotificationChannel from backend.models.constants import NotificationChannel
from typing import Dict from typing import Dict
router = APIRouter() router = APIRouter()

View File

@ -1,6 +1,6 @@
from app.notification.common.config.app_settings import app_settings from common.config.app_settings import app_settings
from app.notification.backend.infra.rabbitmq.async_subscriber import AsyncMQSubscriber from backend.infra.rabbitmq.async_subscriber import AsyncMQSubscriber
from app.notification.backend.infra.email_handler import EmailHandler from backend.infra.email_handler import EmailHandler
class EmailMQConsumer: class EmailMQConsumer:

View File

@ -1,7 +1,7 @@
from app.notification.common.config.app_settings import app_settings from common.config.app_settings import app_settings
from app.notification.backend.infra.rabbitmq.async_subscriber import AsyncMQSubscriber from backend.infra.rabbitmq.async_subscriber import AsyncMQSubscriber
from app.notification.backend.infra.sms_handler import SmsHandler from backend.infra.sms_handler import SmsHandler
from infra.log.module_logger import ModuleLogger from common.log.module_logger import ModuleLogger
class SmsMQConsumer: class SmsMQConsumer:

View File

@ -1,3 +1,4 @@
export MONGODB_URI='mongodb+srv://jetli:8IHKx6dZK8BfugGp@freeleaps2.hanbj.mongodb.net/' export RABBITMQ_HOST=if030-w2-if-vm.mathmast.com
export RABBITMQ_PORT=5672
export FREELEAPS_ENV=alpha export FREELEAPS_ENV=alpha

View File

@ -1,5 +1,5 @@
export SERVICE_API_ACCESS_HOST=0.0.0.0 export SERVICE_API_ACCESS_HOST=0.0.0.0
export SERVICE_API_ACCESS_PORT=8004 export SERVICE_API_ACCESS_PORT=8003
export CONTAINER_APP_ROOT=/app export CONTAINER_APP_ROOT=/app
export LOG_BASE_PATH=$CONTAINER_APP_ROOT/log/$APP_NAME export LOG_BASE_PATH=$CONTAINER_APP_ROOT/log/$APP_NAME
export BACKEND_LOG_FILE_NAME=$APP_NAME export BACKEND_LOG_FILE_NAME=$APP_NAME
@ -8,3 +8,7 @@ export SENDGRID_API_KEY='SG.jAZatAvjQiCAfIwmIu36JA.8NWnGfNcVNkDfwFqGMX-S_DsiOsqU
export EMAIL_FROM=freeleaps@freeleaps.com export EMAIL_FROM=freeleaps@freeleaps.com
export TWILIO_ACCOUNT_SID=ACf8c9283a6acda060258eadb29be58bc8 export TWILIO_ACCOUNT_SID=ACf8c9283a6acda060258eadb29be58bc8
export TWILIO_AUTH_TOKEN=ef160748cc22c8b7195b49df4b8eca7e export TWILIO_AUTH_TOKEN=ef160748cc22c8b7195b49df4b8eca7e
export SYSTEM_USER_ID=117f191e810c19729de860aa
export SMS_FROM=+16898887156
export EMAIL_FROM=freeleaps@freeleaps.com
export SECRET_KEY=ea84edf152976b2fcec12b78aa8e45bc26a5cf0ef61bf16f5c317ae33b3fd8b0

View File

@ -9,15 +9,20 @@ services:
restart: always restart: always
environment: environment:
- APP_NAME=${APP_NAME} - APP_NAME=${APP_NAME}
- MONGODB_NAME=${MONGODB_NAME}
- MONGODB_PORT=${MONGODB_PORT}
- MONGODB_URI=${MONGODB_URI}
- SERVICE_API_ACCESS_HOST=${SERVICE_API_ACCESS_HOST} - SERVICE_API_ACCESS_HOST=${SERVICE_API_ACCESS_HOST}
- SERVICE_API_ACCESS_PORT=${SERVICE_API_ACCESS_PORT} - SERVICE_API_ACCESS_PORT=${SERVICE_API_ACCESS_PORT}
- RABBITMQ_HOST=${RABBITMQ_HOST}
- RABBITMQ_PORT=${RABBITMQ_PORT}
- SYSTEM_USER_ID=${SYSTEM_USER_ID}
- SMS_FROM=${SMS_FROM}
- EMAIL_FROM=${EMAIL_FROM}
- SECRET_KEY=${SECRET_KEY}
- SENDGRID_API_KEY=${SENDGRID_API_KEY}
- TWILIO_ACCOUNT_SID=${TWILIO_ACCOUNT_SID}
- TWILIO_AUTH_TOKEN=${TWILIO_AUTH_TOKEN}
- LOG_BASE_PATH=${LOG_BASE_PATH} - LOG_BASE_PATH=${LOG_BASE_PATH}
- BACKEND_LOG_FILE_NAME=${BACKEND_LOG_FILE_NAME} - BACKEND_LOG_FILE_NAME=${BACKEND_LOG_FILE_NAME}
- APPLICATION_ACTIVITY_LOG=${APPLICATION_ACTIVITY_LOG} - APPLICATION_ACTIVITY_LOG=${APPLICATION_ACTIVITY_LOG}
- JWT_SECRET_KEY=${JWT_SECRET_KEY}
ports: ports:
- ${SERVICE_API_ACCESS_PORT}:${SERVICE_API_ACCESS_PORT} - ${SERVICE_API_ACCESS_PORT}:${SERVICE_API_ACCESS_PORT}
command: command:

View File

@ -1,3 +1,4 @@
export MONGODB_URI=mongodb://freeleaps2-mongodb:27017/ export RABBITMQ_HOST=freeleaps2-rabbitmq
export RABBITMQ_PORT=5672
export FREELEAPS_ENV=dev export FREELEAPS_ENV=dev

View File

@ -1,3 +1,6 @@
export MONGODB_URI=mongodb://localhost:27017/ export RABBITMQ_HOST=localhost
export RABBITMQ_PORT=5672
export FREELEAPS_ENV=local export FREELEAPS_ENV=local
export LOG_BASE_PATH=${CODEBASE_ROOT}/log

View File

@ -1,2 +1,3 @@
export MONGODB_URI='mongodb+srv://freeadmin:0eMV0bt8oyaknA0m@freeleaps2.zmsmpos.mongodb.net/?retryWrites=true&w=majority' export RABBITMQ_HOST=if010-w2-if-vm.mathmast.com
export RABBITMQ_PORT=5672
export FREELEAPS_ENV=prod export FREELEAPS_ENV=prod