middle way of refactoring the code
This commit is contained in:
parent
c8361e71c7
commit
58a2e122aa
23
apps/authentication/.env
Normal file
23
apps/authentication/.env
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
APP_NAME=authentication
|
||||||
|
export SERVICE_API_ACCESS_HOST=0.0.0.0
|
||||||
|
export SERVICE_API_ACCESS_PORT=8004
|
||||||
|
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 MONGODB_NAME=freeleaps2
|
||||||
|
export MONGODB_PORT=27017
|
||||||
|
export JWT_SECRET_KEY=ea84edf152976b2fcec12b78aa8e45bc26a5cf0ef61bf16f5c317ae33b3fd8b0
|
||||||
|
GIT_REPO_ROOT=/mnt/freeleaps/freeleaps-service-hub
|
||||||
|
CODEBASE_ROOT=/mnt/freeleaps/freeleaps-service-hub/apps/authentication
|
||||||
|
SITE_DEPLOY_FOLDER=/mnt/freeleaps/freeleaps-service-hub/sites/authentication/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 MONGODB_URI=mongodb://localhost:27017/
|
||||||
|
export FREELEAPS_ENV=local
|
||||||
|
|
||||||
@ -1,19 +1,38 @@
|
|||||||
# Dockerfile for Python Service
|
FROM python:3.10-slim-buster
|
||||||
FROM python:3.10-slim
|
|
||||||
|
|
||||||
# Set the working directory inside the container
|
# docker settings
|
||||||
WORKDIR /app
|
ARG CONTAINER_APP_ROOT=
|
||||||
|
ENV APP_NAME=
|
||||||
|
|
||||||
# Copy the requirements.txt to the working directory and install dependencies
|
ENV AZURE_STORAGE_DOCUMENT_API_KEY=""
|
||||||
COPY requirements.txt ./
|
ENV AZURE_STORAGE_DOCUMENT_API_ENDPOINT=""
|
||||||
|
|
||||||
|
#site_settings
|
||||||
|
ENV SERVICE_API_ACCESS_HOST=0.0.0.0
|
||||||
|
ENV SERVICE_API_ACCESS_PORT=8004
|
||||||
|
ENV MONGODB_NAME=
|
||||||
|
ENV MONGODB_PORT=
|
||||||
|
ENV MONGODB_URI=
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#log_settings
|
||||||
|
ENV LOG_BASE_PATH=
|
||||||
|
ENV BACKEND_LOG_FILE_NAME=
|
||||||
|
ENV APPLICATION_ACTIVITY_LOG=
|
||||||
|
|
||||||
|
|
||||||
|
WORKDIR ${CONTAINER_APP_ROOT}
|
||||||
|
COPY requirements.txt .
|
||||||
|
|
||||||
|
RUN pip install --upgrade pip
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
# Copy the application code to the working directory
|
COPY . ${CONTAINER_APP_ROOT}
|
||||||
COPY . /app
|
|
||||||
|
|
||||||
# Expose the port used by the FastAPI app
|
RUN apt update
|
||||||
EXPOSE 8004
|
RUN apt install -y netcat
|
||||||
|
RUN ln -s /bin/bash /usr/bin/bash
|
||||||
|
|
||||||
|
EXPOSE ${SERVICE_API_ACCESS_PORT}
|
||||||
# Run the application using the start script
|
CMD ["uvicorn", "webapi.main:app", "--reload", "--port=${SERVICE_API_ACCESS_PORT}", "--host=${SERVICE_API_ACCESS_HOST}"]
|
||||||
CMD ["uvicorn", "app.authentication.webapi.main:app", "--reload", "--port=8004", "--host=0.0.0.0"]
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
from typing import Optional, Tuple
|
from typing import Optional, Tuple
|
||||||
from infra.log.log_utils import log_entry_exit_async
|
from common.log.log_utils import log_entry_exit_async
|
||||||
from app.authentication.backend.business.signin_manager import SignInManager
|
from backend.business.signin_manager import SignInManager
|
||||||
from app.authentication.backend.models.user.constants import UserLoginAction
|
from backend.models.user.constants import UserLoginAction
|
||||||
|
|
||||||
|
|
||||||
class SignInHub:
|
class SignInHub:
|
||||||
|
|||||||
@ -1,25 +1,25 @@
|
|||||||
import random
|
import random
|
||||||
from typing import Tuple, Optional
|
from typing import Tuple, Optional
|
||||||
from app.authentication.backend.services.auth.user_auth_service import UserAuthService
|
from backend.services.auth.user_auth_service import UserAuthService
|
||||||
from infra.i18n.region_handler import RegionHandler
|
from common.utils.region import RegionHandler
|
||||||
from app.authentication.backend.models.user.constants import (
|
from backend.models.user.constants import (
|
||||||
UserLoginAction,
|
UserLoginAction,
|
||||||
NewUserMethod,
|
NewUserMethod,
|
||||||
)
|
)
|
||||||
from app.authentication.backend.models.user.constants import UserLoginAction
|
from backend.models.user.constants import UserLoginAction
|
||||||
from app.authentication.backend.services.user.user_management_service import (
|
from backend.services.user.user_management_service import (
|
||||||
UserManagementService,
|
UserManagementService,
|
||||||
)
|
)
|
||||||
from app.authentication.backend.services.code_depot.code_depot_service import (
|
from backend.services.code_depot.code_depot_service import (
|
||||||
CodeDepotService,
|
CodeDepotService,
|
||||||
)
|
)
|
||||||
from infra.log.module_logger import ModuleLogger
|
from common.log.module_logger import ModuleLogger
|
||||||
from infra.utils.string import check_password_complexity
|
from common.utils.string import check_password_complexity
|
||||||
from infra.exception.exceptions import InvalidDataError
|
from common.exception.exceptions import InvalidDataError
|
||||||
from app.authentication.backend.services.notification.notification_service import (
|
from backend.services.notification.notification_service import (
|
||||||
NotificationService,
|
NotificationService,
|
||||||
)
|
)
|
||||||
from app.authentication.backend.models.user.constants import (
|
from backend.models.user.constants import (
|
||||||
AuthType,
|
AuthType,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -2,21 +2,21 @@ import bcrypt
|
|||||||
from datetime import datetime, timedelta, timezone
|
from datetime import datetime, timedelta, timezone
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from infra.utils.string import generate_auth_code
|
from common.utils.string import generate_auth_code
|
||||||
from app.authentication.backend.infra.code_management.depot_handler import (
|
from backend.infra.code_management.depot_handler import (
|
||||||
CodeDepotHandler,
|
CodeDepotHandler,
|
||||||
)
|
)
|
||||||
from app.authentication.backend.models.user.constants import (
|
from backend.models.user.constants import (
|
||||||
AuthType,
|
AuthType,
|
||||||
)
|
)
|
||||||
from app.authentication.backend.models.user.models import (
|
from backend.models.user.models import (
|
||||||
AuthCodeDoc,
|
AuthCodeDoc,
|
||||||
UserEmailDoc,
|
UserEmailDoc,
|
||||||
UserMobileDoc,
|
UserMobileDoc,
|
||||||
UserPasswordDoc,
|
UserPasswordDoc,
|
||||||
)
|
)
|
||||||
|
|
||||||
from app.authentication.backend.models.user_profile.models import BasicProfileDoc
|
from backend.models.user_profile.models import BasicProfileDoc
|
||||||
|
|
||||||
|
|
||||||
class UserAuthHandler:
|
class UserAuthHandler:
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
from infra.log.module_logger import ModuleLogger
|
from common.log.module_logger import ModuleLogger
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,15 +1,15 @@
|
|||||||
from infra.models.constants import UserRegion
|
from common.constants.region import UserRegion
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import datetime, timedelta, timezone
|
||||||
from app.authentication.backend.models.user.models import UserAccountDoc
|
from backend.models.user.models import UserAccountDoc
|
||||||
from app.authentication.backend.models.user.constants import (
|
from backend.models.user.constants import (
|
||||||
UserAccountProperty,
|
UserAccountProperty,
|
||||||
)
|
)
|
||||||
from app.authentication.backend.models.permission.constants import (
|
from backend.models.permission.constants import (
|
||||||
AdministrativeRole,
|
AdministrativeRole,
|
||||||
Capability,
|
Capability,
|
||||||
)
|
)
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from app.authentication.backend.models.user_profile.models import (
|
from backend.models.user_profile.models import (
|
||||||
SelfIntro,
|
SelfIntro,
|
||||||
Tags,
|
Tags,
|
||||||
Photo,
|
Photo,
|
||||||
@ -22,7 +22,7 @@ from app.authentication.backend.models.user_profile.models import (
|
|||||||
ExpectedSalary,
|
ExpectedSalary,
|
||||||
)
|
)
|
||||||
|
|
||||||
from app.authentication.backend.models.user.constants import UserRegionToCurrency
|
from backend.models.user.constants import UserRegionToCurrency
|
||||||
|
|
||||||
|
|
||||||
class UserProfileHandler:
|
class UserProfileHandler:
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
from typing import Dict, Optional
|
from typing import Dict, Optional
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from beanie import Document
|
from beanie import Document
|
||||||
from app.authentication.backend.models.gitea.constants import (
|
from backend.models.gitea.constants import (
|
||||||
DepotStatus,
|
DepotStatus,
|
||||||
UserAccountStatus,
|
UserAccountStatus,
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
from infra.models.constants import UserRegion
|
from common.constants.region import UserRegion
|
||||||
|
|
||||||
|
|
||||||
class NewUserMethod(IntEnum):
|
class NewUserMethod(IntEnum):
|
||||||
|
|||||||
@ -3,12 +3,12 @@ from typing import Optional
|
|||||||
from beanie import Document
|
from beanie import Document
|
||||||
|
|
||||||
from .constants import UserAccountProperty
|
from .constants import UserAccountProperty
|
||||||
from app.authentication.backend.models.permission.constants import (
|
from backend.models.permission.constants import (
|
||||||
AdministrativeRole,
|
AdministrativeRole,
|
||||||
Capability,
|
Capability,
|
||||||
)
|
)
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from infra.models.constants import UserRegion
|
from common.constants.region import UserRegion
|
||||||
from .constants import AuthType
|
from .constants import AuthType
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@ from pydantic import BaseModel, EmailStr
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from infra.models.constants import UserRegion
|
from common.constants.region import UserRegion
|
||||||
|
|
||||||
|
|
||||||
class Tags(BaseModel):
|
class Tags(BaseModel):
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
from app.authentication.backend.infra.auth.user_auth_handler import (
|
from backend.infra.auth.user_auth_handler import (
|
||||||
UserAuthHandler,
|
UserAuthHandler,
|
||||||
)
|
)
|
||||||
from app.authentication.backend.models.user.constants import (
|
from backend.models.user.constants import (
|
||||||
AuthType,
|
AuthType,
|
||||||
)
|
)
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|||||||
@ -1,23 +1,23 @@
|
|||||||
from infra.log.module_logger import ModuleLogger
|
from common.log.module_logger import ModuleLogger
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from app.authentication.backend.models.user.constants import (
|
from backend.models.user.constants import (
|
||||||
NewUserMethod,
|
NewUserMethod,
|
||||||
UserAccountProperty,
|
UserAccountProperty,
|
||||||
)
|
)
|
||||||
from app.authentication.backend.models.user.models import UserAccountDoc
|
from backend.models.user.models import UserAccountDoc
|
||||||
from app.authentication.backend.models.permission.constants import (
|
from backend.models.permission.constants import (
|
||||||
AdministrativeRole,
|
AdministrativeRole,
|
||||||
Capability,
|
Capability,
|
||||||
)
|
)
|
||||||
from app.authentication.backend.infra.auth.user_auth_handler import (
|
from backend.infra.auth.user_auth_handler import (
|
||||||
UserAuthHandler,
|
UserAuthHandler,
|
||||||
)
|
)
|
||||||
from app.authentication.backend.infra.user_profile.user_profile_handler import (
|
from backend.infra.user_profile.user_profile_handler import (
|
||||||
UserProfileHandler,
|
UserProfileHandler,
|
||||||
)
|
)
|
||||||
from infra.log.log_utils import log_entry_exit_async
|
from common.log.log_utils import log_entry_exit_async
|
||||||
from infra.models.constants import UserRegion
|
from common.constants.region import UserRegion
|
||||||
|
|
||||||
|
|
||||||
class UserManagementService:
|
class UserManagementService:
|
||||||
|
|||||||
@ -3,14 +3,17 @@ from pydantic_settings import BaseSettings
|
|||||||
|
|
||||||
class AppSettings(BaseSettings):
|
class AppSettings(BaseSettings):
|
||||||
NAME: str = "central_storage"
|
NAME: str = "central_storage"
|
||||||
|
APP_NAME:str = NAME
|
||||||
|
|
||||||
GITEA_URL: str = ""
|
JWT_SECRET_KEY: str = ""
|
||||||
GITEA_TOKEN: str = ""
|
ACCESS_TOKEN_EXPIRE_MINUTES:int = 3600
|
||||||
GITEA_DEPOT_ORGANIZATION: str = ""
|
REFRESH_TOKEN_EXPIRE_DAYS:int = 1
|
||||||
|
|
||||||
CODE_DEPOT_DOMAIN_NAME: str = ""
|
MONGODB_URI:str= ""
|
||||||
CODE_DEPOT_SSH_PORT: str = ""
|
MONGODB_NAME:str= ""
|
||||||
CODE_DEPOT_HTTP_PORT: str = ""
|
|
||||||
|
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"
|
||||||
|
|||||||
17
apps/authentication/common/config/log_settings.py
Normal file
17
apps/authentication/common/config/log_settings.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
|
||||||
|
class LogSettings():
|
||||||
|
LOG_LEVEL: str = "DEBUG"
|
||||||
|
LOG_PATH_BASE: str = (
|
||||||
|
"./logs"
|
||||||
|
)
|
||||||
|
LOG_PATH: str = LOG_PATH_BASE + '/' + "app" + '.log'
|
||||||
|
LOG_RETENTION: str = "14 days"
|
||||||
|
LOG_ROTATION: str = "00:00" # mid night
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
env_file = ".log.env"
|
||||||
|
env_file_encoding = "utf-8"
|
||||||
|
|
||||||
|
|
||||||
|
log_settings = LogSettings()
|
||||||
0
apps/authentication/common/constants/__init__.py
Normal file
0
apps/authentication/common/constants/__init__.py
Normal file
8
apps/authentication/common/constants/contract.py
Normal file
8
apps/authentication/common/constants/contract.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
from enum import IntEnum
|
||||||
|
|
||||||
|
|
||||||
|
class UserContractRole(IntEnum):
|
||||||
|
VISITER = 0x1
|
||||||
|
REQUESTER = 0x2
|
||||||
|
PROVIDER = 0x4
|
||||||
|
|
||||||
5
apps/authentication/common/constants/payment.py
Normal file
5
apps/authentication/common/constants/payment.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
from enum import IntEnum
|
||||||
|
|
||||||
|
class PaymentPlanType(IntEnum):
|
||||||
|
STAGED = 0
|
||||||
|
|
||||||
5
apps/authentication/common/constants/region.py
Normal file
5
apps/authentication/common/constants/region.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
from enum import IntEnum
|
||||||
|
|
||||||
|
class UserRegion(IntEnum):
|
||||||
|
OTHER = 0
|
||||||
|
ZH_CN = 1
|
||||||
0
apps/authentication/common/exception/__init__.py
Normal file
0
apps/authentication/common/exception/__init__.py
Normal file
23
apps/authentication/common/exception/exceptions.py
Normal file
23
apps/authentication/common/exception/exceptions.py
Normal 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
|
||||||
0
apps/authentication/common/log/__init__.py
Normal file
0
apps/authentication/common/log/__init__.py
Normal file
14
apps/authentication/common/log/application_logger.py
Normal file
14
apps/authentication/common/log/application_logger.py
Normal 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,
|
||||||
|
)
|
||||||
139
apps/authentication/common/log/base_logger.py
Normal file
139
apps/authentication/common/log/base_logger.py
Normal 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_PATH_BASE + "/" + 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)
|
||||||
25
apps/authentication/common/log/business_metric_logger.py
Normal file
25
apps/authentication/common/log/business_metric_logger.py
Normal 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"
|
||||||
|
)
|
||||||
50
apps/authentication/common/log/function_logger.py
Normal file
50
apps/authentication/common/log/function_logger.py
Normal 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
|
||||||
|
},
|
||||||
|
)
|
||||||
25
apps/authentication/common/log/log_utils.py
Normal file
25
apps/authentication/common/log/log_utils.py
Normal 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
|
||||||
46
apps/authentication/common/log/module_logger.py
Normal file
46
apps/authentication/common/log/module_logger.py
Normal 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,
|
||||||
|
)
|
||||||
14
apps/authentication/common/log/user_logger.py
Normal file
14
apps/authentication/common/log/user_logger.py
Normal 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
|
||||||
|
)
|
||||||
80
apps/authentication/common/token/token_manager.py
Normal file
80
apps/authentication/common/token/token_manager.py
Normal 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"
|
||||||
|
)
|
||||||
22
apps/authentication/common/utils/date.py
Normal file
22
apps/authentication/common/utils/date.py
Normal 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
|
||||||
13
apps/authentication/common/utils/region.py
Normal file
13
apps/authentication/common/utils/region.py
Normal 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
|
||||||
87
apps/authentication/common/utils/string.py
Normal file
87
apps/authentication/common/utils/string.py
Normal 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
|
||||||
40
apps/authentication/start_fastapi.sh
Executable file
40
apps/authentication/start_fastapi.sh
Executable file
@ -0,0 +1,40 @@
|
|||||||
|
#! /bin/bash
|
||||||
|
rp=$(dirname "$(realpath '$1'))")
|
||||||
|
pushd $rp
|
||||||
|
|
||||||
|
APP_NAME=authentication
|
||||||
|
APP_PARENT_FOLDER=apps
|
||||||
|
|
||||||
|
GIT_REPO_ROOT=$(git rev-parse --show-toplevel)
|
||||||
|
CODEBASE_ROOT=$GIT_REPO_ROOT/$APP_PARENT_FOLDER/$APP_NAME
|
||||||
|
SITE_DEPLOY_FOLDER=$GIT_REPO_ROOT/sites/$APP_NAME/deploy
|
||||||
|
|
||||||
|
|
||||||
|
echo APP_NAME=$APP_NAME > .env
|
||||||
|
cat $SITE_DEPLOY_FOLDER/common/.env >> .env
|
||||||
|
echo GIT_REPO_ROOT=$(git rev-parse --show-toplevel) >> .env
|
||||||
|
echo CODEBASE_ROOT=$GIT_REPO_ROOT/$APP_PARENT_FOLDER/$APP_NAME >> .env
|
||||||
|
echo SITE_DEPLOY_FOLDER=$GIT_REPO_ROOT/sites/$APP_NAME/deploy >> .env
|
||||||
|
cat $SITE_DEPLOY_FOLDER/common/.host.env >> .env
|
||||||
|
cat $SITE_DEPLOY_FOLDER/local/.env >> .env
|
||||||
|
|
||||||
|
. .env
|
||||||
|
|
||||||
|
if [ -d "$VENV_DIR" ]
|
||||||
|
then
|
||||||
|
echo "Folder $VENV_DIR exists. Proceed to next steps"
|
||||||
|
else
|
||||||
|
echo "Folder $VENV_DIR dosen't exist. create it"
|
||||||
|
sudo apt install python3-pip
|
||||||
|
python3 -m pip install virtualenv
|
||||||
|
python3 -m virtualenv $VENV_DIR
|
||||||
|
fi
|
||||||
|
|
||||||
|
source $VENV_DIR/bin/activate
|
||||||
|
pip install --upgrade pip
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
uvicorn webapi.main:app --reload --host 0.0.0.0 --port $SERVICE_API_ACCESS_PORT
|
||||||
|
|
||||||
|
|
||||||
|
popd
|
||||||
@ -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.authentication.webapi.providers import common
|
from webapi.providers import common
|
||||||
from app.authentication.webapi.providers import logger
|
from webapi.providers import logger
|
||||||
from app.authentication.webapi.providers import router
|
from webapi.providers import router
|
||||||
from app.authentication.webapi.providers import database
|
from webapi.providers import database
|
||||||
|
|
||||||
# from app.authentication.webapi.providers import scheduler
|
# from webapi.providers import scheduler
|
||||||
from app.authentication.webapi.providers import exception_handler
|
from webapi.providers import exception_handler
|
||||||
from .freeleaps_app import FreeleapsApp
|
from .freeleaps_app import FreeleapsApp
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
from app.authentication.webapi.bootstrap.application import create_app
|
from webapi.bootstrap.application import create_app
|
||||||
from app.authentication.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
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
import uvicorn
|
import uvicorn
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
from app.authentication.webapi.config.site_settings import site_settings
|
from webapi.config.site_settings import site_settings
|
||||||
|
|
||||||
|
|
||||||
def register(app):
|
def register(app):
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
from infra.config.app_settings import app_settings
|
from common.config.app_settings import app_settings
|
||||||
from beanie import init_beanie
|
from beanie import init_beanie
|
||||||
from motor.motor_asyncio import AsyncIOMotorClient
|
from motor.motor_asyncio import AsyncIOMotorClient
|
||||||
from app.authentication.backend.models import backend_models
|
from backend.models import backend_models
|
||||||
|
|
||||||
|
|
||||||
def register(app):
|
def register(app):
|
||||||
|
|||||||
@ -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):
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
from app.authentication.webapi.routes import api_router
|
from webapi.routes import api_router
|
||||||
|
|
||||||
from starlette import routing
|
from starlette import routing
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
from app.authentication.backend.application.signin_hub import SignInHub
|
from backend.application.signin_hub import SignInHub
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from infra.token.token_manager import TokenManager
|
from common.token.token_manager import TokenManager
|
||||||
from fastapi.encoders import jsonable_encoder
|
from fastapi.encoders import jsonable_encoder
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
from fastapi import APIRouter, Depends, HTTPException
|
from fastapi import APIRouter, Depends, HTTPException
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
from app.authentication.backend.application.signin_hub import SignInHub
|
from backend.application.signin_hub import SignInHub
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from infra.token.token_manager import TokenManager
|
from common.token.token_manager import TokenManager
|
||||||
from fastapi.encoders import jsonable_encoder
|
from fastapi.encoders import jsonable_encoder
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
from fastapi import APIRouter, Depends, HTTPException
|
from fastapi import APIRouter, Depends, HTTPException
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
from app.authentication.backend.application.signin_hub import SignInHub
|
from backend.application.signin_hub import SignInHub
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
from fastapi.encoders import jsonable_encoder
|
from fastapi.encoders import jsonable_encoder
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
from app.authentication.backend.application.signin_hub import SignInHub
|
from backend.application.signin_hub import SignInHub
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
from infra.token.token_manager import TokenManager
|
from common.token.token_manager import TokenManager
|
||||||
from fastapi import APIRouter, Depends
|
from fastapi import APIRouter, Depends
|
||||||
from fastapi.encoders import jsonable_encoder
|
from fastapi.encoders import jsonable_encoder
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
|
|||||||
@ -7,8 +7,8 @@ from fastapi.encoders import jsonable_encoder
|
|||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from app.authentication.backend.application.signin_hub import SignInHub
|
from backend.application.signin_hub import SignInHub
|
||||||
from infra.token.token_manager import TokenManager
|
from common.token.token_manager import TokenManager
|
||||||
|
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|||||||
@ -9,8 +9,8 @@ from fastapi.responses import JSONResponse
|
|||||||
from fastapi import Depends, HTTPException
|
from fastapi import Depends, HTTPException
|
||||||
from starlette.status import HTTP_401_UNAUTHORIZED
|
from starlette.status import HTTP_401_UNAUTHORIZED
|
||||||
|
|
||||||
from app.authentication.backend.application.signin_hub import SignInHub
|
from backend.application.signin_hub import SignInHub
|
||||||
from infra.token.token_manager import TokenManager
|
from common.token.token_manager import TokenManager
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
token_manager = TokenManager()
|
token_manager = TokenManager()
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
from app.authentication.backend.application.signin_hub import SignInHub
|
from backend.application.signin_hub import SignInHub
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
from fastapi.encoders import jsonable_encoder
|
from fastapi.encoders import jsonable_encoder
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
from app.authentication.backend.application.signin_hub import SignInHub
|
from backend.application.signin_hub import SignInHub
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
from infra.token.token_manager import TokenManager
|
from common.token.token_manager import TokenManager
|
||||||
from fastapi import APIRouter, Depends
|
from fastapi import APIRouter, Depends
|
||||||
from fastapi.encoders import jsonable_encoder
|
from fastapi.encoders import jsonable_encoder
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
from app.authentication.backend.application.signin_hub import SignInHub
|
from backend.application.signin_hub import SignInHub
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
from infra.token.token_manager import TokenManager
|
from common.token.token_manager import TokenManager
|
||||||
from fastapi import APIRouter, Depends
|
from fastapi import APIRouter, Depends
|
||||||
from fastapi.encoders import jsonable_encoder
|
from fastapi.encoders import jsonable_encoder
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import datetime, timedelta, timezone
|
||||||
from infra.token.token_manager import TokenManager
|
from common.token.token_manager import TokenManager
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
token_manager = TokenManager() # Initialize TokenManager
|
token_manager = TokenManager() # Initialize TokenManager
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
from fastapi import APIRouter, HTTPException
|
from fastapi import APIRouter, HTTPException
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from infra.token.token_manager import TokenManager
|
from common.token.token_manager import TokenManager
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
token_manager = TokenManager() # Initialize TokenManager
|
token_manager = TokenManager() # Initialize TokenManager
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
from fastapi import APIRouter, HTTPException
|
from fastapi import APIRouter, HTTPException
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from infra.token.token_manager import TokenManager
|
from common.token.token_manager import TokenManager
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
token_manager = TokenManager() # Initialize TokenManager
|
token_manager = TokenManager() # Initialize TokenManager
|
||||||
|
|||||||
@ -1,2 +0,0 @@
|
|||||||
export AZURE_STORAGE_DOCUMENT_API_KEY=xbiFtFeQ6v5dozgVM99fZ9huUomL7QcLu6s0y8zYHtIXZ8XdneKDMcg4liQr/9oNlVoRFcZhWjLY+ASt9cjICQ==
|
|
||||||
export JWT_SECRET_KEY=ea84edf152976b2fcec12b78aa8e45bc26a5cf0ef61bf16f5c317ae33b3fd8b0
|
|
||||||
3
sites/authentication/deploy/alpha/.env
Executable file
3
sites/authentication/deploy/alpha/.env
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
export MONGODB_URI='mongodb+srv://jetli:8IHKx6dZK8BfugGp@freeleaps2.hanbj.mongodb.net/'
|
||||||
|
export FREELEAPS_ENV=alpha
|
||||||
|
|
||||||
9
sites/authentication/deploy/common/.env
Executable file
9
sites/authentication/deploy/common/.env
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
export SERVICE_API_ACCESS_HOST=0.0.0.0
|
||||||
|
export SERVICE_API_ACCESS_PORT=8004
|
||||||
|
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 MONGODB_NAME=freeleaps2
|
||||||
|
export MONGODB_PORT=27017
|
||||||
|
export JWT_SECRET_KEY=ea84edf152976b2fcec12b78aa8e45bc26a5cf0ef61bf16f5c317ae33b3fd8b0
|
||||||
7
sites/authentication/deploy/common/.host.env
Executable file
7
sites/authentication/deploy/common/.host.env
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
#!/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
|
||||||
37
sites/authentication/deploy/common/docker-compose.yaml
Executable file
37
sites/authentication/deploy/common/docker-compose.yaml
Executable file
@ -0,0 +1,37 @@
|
|||||||
|
services:
|
||||||
|
central_storage:
|
||||||
|
container_name: $APP_NAME
|
||||||
|
build:
|
||||||
|
context: ${CODEBASE_ROOT}
|
||||||
|
args:
|
||||||
|
CONTAINER_APP_ROOT: ${CONTAINER_APP_ROOT}
|
||||||
|
profiles: [prod,alpha,dev]
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
- 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_PORT=${SERVICE_API_ACCESS_PORT}
|
||||||
|
- AZURE_STORAGE_DOCUMENT_API_KEY=${AZURE_STORAGE_DOCUMENT_API_KEY}
|
||||||
|
- AZURE_STORAGE_DOCUMENT_API_ENDPOINT=${AZURE_STORAGE_DOCUMENT_API_ENDPOINT}
|
||||||
|
- LOG_BASE_PATH=${LOG_BASE_PATH}
|
||||||
|
- BACKEND_LOG_FILE_NAME=${BACKEND_LOG_FILE_NAME}
|
||||||
|
- APPLICATION_ACTIVITY_LOG=${APPLICATION_ACTIVITY_LOG}
|
||||||
|
ports:
|
||||||
|
- ${SERVICE_API_ACCESS_PORT}:${SERVICE_API_ACCESS_PORT}
|
||||||
|
command:
|
||||||
|
- /bin/sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
uvicorn webapi.main:app --reload --port=${SERVICE_API_ACCESS_PORT} --host=${SERVICE_API_ACCESS_HOST}
|
||||||
|
networks:
|
||||||
|
- devbox_freeleaps2-network
|
||||||
|
volumes:
|
||||||
|
- type: bind
|
||||||
|
source: $DOCKER_BACKEND_LOG_HOME
|
||||||
|
target: $LOG_BASE_PATH
|
||||||
|
networks:
|
||||||
|
devbox_freeleaps2-network:
|
||||||
|
external: true
|
||||||
91
sites/authentication/deploy/deploy.sh
Executable file
91
sites/authentication/deploy/deploy.sh
Executable file
@ -0,0 +1,91 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
DW_BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
|
||||||
|
APP_NAME=authentication
|
||||||
|
APP_PARENT_FOLDER=apps
|
||||||
|
PROJECT_NAME=authentication
|
||||||
|
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
--target* | -u*)
|
||||||
|
if [[ "$1" != *=* ]]; then shift; fi # Value is next arg if no `=`
|
||||||
|
TARGET_ENV="${1#*=}"
|
||||||
|
;;
|
||||||
|
--help | -h)
|
||||||
|
printf "$BASE_NAME --target=<prod | alpha | dev>\n" # Flag argument
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf >&2 "Error: Invalid argument\n"
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ "${TARGET_ENV}" != "prod" && "${TARGET_ENV}" != "alpha" && "${TARGET_ENV}" != "dev" ]]; then
|
||||||
|
printf "$BASE_NAME --target=<prod | alpha | dev>\n" # Flag argument
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if git rev-parse --git-dir > /dev/null 2>&1; then
|
||||||
|
# git repo!
|
||||||
|
GIT_REPO_ROOT=$(git rev-parse --show-toplevel)
|
||||||
|
CODEBASE_ROOT=$GIT_REPO_ROOT/$APP_PARENT_FOLDER/$APP_NAME
|
||||||
|
WORKING_DIR=$GIT_REPO_ROOT/sites/$APP_NAME/deploy
|
||||||
|
|
||||||
|
else
|
||||||
|
# NOT a git repo!
|
||||||
|
printf "Please run this command under a git repo"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
. $DW_BASE_DIR/common/.host.env
|
||||||
|
|
||||||
|
|
||||||
|
DW_PUSHD_COUNTER=0
|
||||||
|
|
||||||
|
ENV_FOLDER=$WORKING_DIR/$TARGET_ENV
|
||||||
|
COMMON_ENV_FOLDER=$WORKING_DIR/common
|
||||||
|
|
||||||
|
|
||||||
|
pushd $WORKING_DIR
|
||||||
|
DW_PUSHD_COUNTER=$((DW_PUSHD_COUNTER + 1))
|
||||||
|
|
||||||
|
echo export APP_NAME=$APP_NAME > $WORKING_DIR/.env
|
||||||
|
echo export GIT_REPO_ROOT=$GIT_REPO_ROOT >> $WORKING_DIR/.env
|
||||||
|
echo export APP_PARENT_FOLDER=$APP_PARENT_FOLDER >> $WORKING_DIR/.env
|
||||||
|
|
||||||
|
cat $COMMON_ENV_FOLDER/.env >> $WORKING_DIR/.env
|
||||||
|
echo export CODEBASE_ROOT=$CODEBASE_ROOT >> $WORKING_DIR/.env
|
||||||
|
echo export WORKING_DIR=$WORKING_DIR >> $WORKING_DIR/.env
|
||||||
|
cat $COMMON_ENV_FOLDER/.host.env >> $WORKING_DIR/.env
|
||||||
|
cat $ENV_FOLDER/.env >>$WORKING_DIR/.env
|
||||||
|
|
||||||
|
DOCKER_COMPOSE_YAML=$WORKING_DIR/docker-compose-$APP_NAME.yaml
|
||||||
|
cp $DW_BASE_DIR/common/docker-compose.yaml $DOCKER_COMPOSE_YAML -u
|
||||||
|
|
||||||
|
. $WORKING_DIR/.env
|
||||||
|
|
||||||
|
sudo mkdir $DOCKER_BACKEND_LOG_HOME -p
|
||||||
|
|
||||||
|
sudo docker compose -p $PROJECT_NAME -f $DOCKER_COMPOSE_YAML --profile $TARGET_ENV down --remove-orphans
|
||||||
|
sudo docker compose -p $PROJECT_NAME -f $DOCKER_COMPOSE_YAML --profile $TARGET_ENV build --no-cache
|
||||||
|
|
||||||
|
# Clean up any previous resources that are not needed
|
||||||
|
# sudo docker system prune -f --volumes
|
||||||
|
# sudo docker image prune -f
|
||||||
|
# sudo docker container prune -f
|
||||||
|
# sudo docker network prune -f
|
||||||
|
|
||||||
|
# Start up the Docker containers in detached mode and remove orphans
|
||||||
|
sudo docker compose -p $PROJECT_NAME -f $DOCKER_COMPOSE_YAML --profile $TARGET_ENV up --detach --remove-orphans
|
||||||
|
echo 'You can use "sudo docker compose logs -f" to check the output of the containers'
|
||||||
|
sudo docker ps -a
|
||||||
|
|
||||||
|
rm $WORKING_DIR/.env
|
||||||
|
rm $DOCKER_COMPOSE_YAML
|
||||||
|
|
||||||
|
while [[ "$DW_PUSHD_COUNTER" -gt 0 ]]; do
|
||||||
|
DW_PUSHD_COUNTER=$((DW_PUSHD_COUNTER - 1))
|
||||||
|
popd
|
||||||
|
done
|
||||||
|
|
||||||
3
sites/authentication/deploy/dev/.env
Executable file
3
sites/authentication/deploy/dev/.env
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
export MONGODB_URI=mongodb://freeleaps2-mongodb:27017/
|
||||||
|
export FREELEAPS_ENV=dev
|
||||||
|
|
||||||
3
sites/authentication/deploy/local/.env
Normal file
3
sites/authentication/deploy/local/.env
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export MONGODB_URI=mongodb://localhost:27017/
|
||||||
|
export FREELEAPS_ENV=local
|
||||||
|
|
||||||
2
sites/authentication/deploy/prod/.env
Executable file
2
sites/authentication/deploy/prod/.env
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
export MONGODB_URI='mongodb+srv://freeadmin:0eMV0bt8oyaknA0m@freeleaps2.zmsmpos.mongodb.net/?retryWrites=true&w=majority'
|
||||||
|
export FREELEAPS_ENV=prod
|
||||||
Loading…
Reference in New Issue
Block a user