From 80f47542b36f888afd019efedde54c687e41d12d Mon Sep 17 00:00:00 2001 From: ablogo Date: Sat, 5 Sep 2026 14:22:19 +0900 Subject: [PATCH 1/2] improve how to get env variables and dependency injection --- src/config/settings_validator.py | 70 +++++++++++++++++++ src/dependency_injection/containers.py | 2 +- .../mongo_db.py} | 2 - src/main.py | 2 +- src/models/address_model.py | 4 +- src/models/user_model.py | 2 +- src/routers/admin/users_router.py | 2 +- src/routers/products_router.py | 2 +- src/routers/users_router.py | 14 ++-- src/services/jwt_service.py | 14 ++-- src/services/oauth_google_service.py | 28 +++++--- src/services/totp_service.py | 2 +- src/services/user_service.py | 38 +++++----- src/settings_validator.py | 66 ----------------- 14 files changed, 132 insertions(+), 116 deletions(-) create mode 100644 src/config/settings_validator.py rename src/{dependencies.py => dependency_injection/mongo_db.py} (91%) delete mode 100644 src/settings_validator.py diff --git a/src/config/settings_validator.py b/src/config/settings_validator.py new file mode 100644 index 0000000..e491f13 --- /dev/null +++ b/src/config/settings_validator.py @@ -0,0 +1,70 @@ +import os, sys, signal +from dotenv import load_dotenv + +load_dotenv() + +class Settings(): + DB_URL: str + DB_NAME: str = "auth-service" + DB_USERS_COLLECTION: str = "users" + DB_USERS_PICTURES_COLLECTION: str = "users.pictures" + DB_USERS_CONTACTS_COLLECTION: str = "users.contacts" + DB_USERS_MESSAGES_COLLECTION: str = "users.messages" + LOG_DB_URL: str + LOG_DATABASE_NAME: str = "auth-service-logs" + LOG_LEVEL: str = "DEBUG" + JWT_SECRET_KEY: str + JWT_ALGORITHM: str = "HS256" + JWT_EXPIRE_MINUTES: int = 240 + CORS_ALLOWED_HOSTS: str = "" + TOTP_SECRET: str + TOTP_DIGEST: str = "sha1" + TOTP_RETURN_DIGITS: int = 8 + TOTP_TIME_STEP: int = 30 + GOOGLE_OAUTH_ID: str + GOOGLE_OAUTH_CLIENT: str + GOOGLE_OAUTH_SECRET: str + GOOGLE_OAUTH_REDIRECT_RESPONSE: str = "https://127.0.0.1:8000/auth/google-response" + GOOGLE_OAUTH_JS_ORIGINS: str = "http://127.0.0.1:8000,http://localhost:8081" + GOOGLE_OAUTH_SCOPES: str = "https://www.googleapis.com/auth/userinfo.email,https://www.googleapis.com/auth/userinfo.profile,openid" + CORS_ALLOWED_HOSTS: str + TZ: str = "UTC" + + def __init__(self) -> None: + try: + self.DB_URL = self.get_env("DB_URL") + self.DB_NAME = self.get_env("DB_NAME") + self.DB_USERS_COLLECTION = self.get_env("DB_USERS_COLLECTION") + self.DB_USERS_PICTURES_COLLECTION = self.get_env("DB_USERS_PICTURES_COLLECTION") + self.DB_USERS_CONTACTS_COLLECTION = self.get_env("DB_USERS_CONTACTS_COLLECTION") + self.DB_USERS_MESSAGES_COLLECTION = self.get_env("DB_USERS_MESSAGES_COLLECTION") + self.LOG_DB_URL = self.get_env("LOG_DB_URL") + self.LOG_DATABASE_NAME = self.get_env("LOG_DATABASE_NAME") + self.LOG_LEVEL = self.get_env("LOG_LEVEL") + self.JWT_SECRET_KEY = self.get_env("JWT_SECRET_KEY") + self.JWT_ALGORITHM = self.get_env("JWT_ALGORITHM") + self.JWT_EXPIRE_MINUTES = int(self.get_env("JWT_EXPIRE_MINUTES")) + self.CORS_ALLOWED_HOSTS = self.get_env("CORS_ALLOWED_HOSTS") + self.TOTP_SECRET = self.get_env("TOTP_SECRET") + self.TOTP_DIGEST = self.get_env("TOTP_DIGEST") + self.TOTP_RETURN_DIGITS = int(self.get_env("TOTP_RETURN_DIGITS")) + self.TOTP_TIME_STEP = int(self.get_env("TOTP_TIME_STEP")) + self.GOOGLE_OAUTH_ID = self.get_env("GOOGLE_OAUTH_ID") + self.GOOGLE_OAUTH_CLIENT = self.get_env("GOOGLE_OAUTH_CLIENT") + self.GOOGLE_OAUTH_SECRET = self.get_env("GOOGLE_OAUTH_SECRET") + self.GOOGLE_OAUTH_REDIRECT_RESPONSE = self.get_env("GOOGLE_OAUTH_REDIRECT_RESPONSE") + self.GOOGLE_OAUTH_JS_ORIGINS = self.get_env("GOOGLE_OAUTH_JS_ORIGINS") + self.GOOGLE_OAUTH_SCOPES = self.get_env("GOOGLE_OAUTH_SCOPES") + self.CORS_ALLOWED_HOSTS = self.get_env("CORS_ALLOWED_HOSTS") + self.TZ = self.get_env("TZ") + except Exception as e: + print("Missing or incorrect configuration value: " + e.__str__()) + os.kill(os.getppid(), signal.SIGTERM) + sys.exit(78) + + def get_env(self, name: str) -> str: + v = os.environ[name] + if not v or not str(v).strip(): + raise ValueError(f"Variable {name} is None, empty, or just whitespace.") + else: + return v \ No newline at end of file diff --git a/src/dependency_injection/containers.py b/src/dependency_injection/containers.py index e421805..d0ba033 100644 --- a/src/dependency_injection/containers.py +++ b/src/dependency_injection/containers.py @@ -1,7 +1,7 @@ from dependency_injector import containers, providers from log2mongo import log2mongo -from src.settings_validator import Settings +from src.config.settings_validator import Settings from src.services import mongodb_service from src.services.crypto_service import CryptoService from src.services.totp_service import TOTP diff --git a/src/dependencies.py b/src/dependency_injection/mongo_db.py similarity index 91% rename from src/dependencies.py rename to src/dependency_injection/mongo_db.py index bca9557..8e940ff 100644 --- a/src/dependencies.py +++ b/src/dependency_injection/mongo_db.py @@ -1,9 +1,7 @@ from pymongo import AsyncMongoClient from pymongo.server_api import ServerApi -from dotenv import load_dotenv import os -load_dotenv() client = AsyncMongoClient(os.environ["DB_URL"], server_api= ServerApi(version='1', strict=True, deprecation_errors=True)) database = client.get_database(os.environ["DB_NAME"]) diff --git a/src/main.py b/src/main.py index a0bdbb8..c98cabd 100644 --- a/src/main.py +++ b/src/main.py @@ -8,7 +8,7 @@ from src.middlewares.jwt_middleware import JWTMiddleware from src.middlewares.http_middleware import HttpMiddleware from src.dependency_injection.containers import Container -from src.dependencies import close_db +from src.dependency_injection.mongo_db import close_db container = Container() origins = container.config.d.CORS_ALLOWED_HOSTS().split(',') if container.config.d.CORS_ALLOWED_HOSTS() else [] diff --git a/src/models/address_model.py b/src/models/address_model.py index 3509ca2..83549d7 100644 --- a/src/models/address_model.py +++ b/src/models/address_model.py @@ -1,7 +1,7 @@ from datetime import datetime from typing import Annotated, Optional from bson import ObjectId -from pydantic import BaseModel, PlainValidator, Field +from pydantic import AliasChoices, BaseModel, PlainValidator, Field from src.models.pydantic_objects import PyObjectId @@ -14,7 +14,7 @@ def set_id(value): class Address(BaseModel): - id: Annotated[Optional[PyObjectId], PlainValidator(set_id), Field(validate_default=True, serialization_alias="_id")] = Field(default=None, validation_alias="_id") + id: Annotated[Optional[PyObjectId], PlainValidator(set_id), Field(validate_default=True, serialization_alias="_id")] = Field(default=None, validation_alias=AliasChoices("id", "_id")) country: str state: str colony: str diff --git a/src/models/user_model.py b/src/models/user_model.py index d58f15d..3fe32a9 100644 --- a/src/models/user_model.py +++ b/src/models/user_model.py @@ -1,7 +1,7 @@ from datetime import datetime from typing import Annotated, List, Optional from bson import ObjectId -from pydantic import AfterValidator, BaseModel, BeforeValidator, ConfigDict, Field, field_validator +from pydantic import BaseModel, BeforeValidator, Field, field_validator from src.models.address_model import Address from src.models.pydantic_objects import PyObjectId diff --git a/src/routers/admin/users_router.py b/src/routers/admin/users_router.py index 2c78cd1..15585fd 100644 --- a/src/routers/admin/users_router.py +++ b/src/routers/admin/users_router.py @@ -7,7 +7,7 @@ from src.models.user_model import User from src.models.address_model import Address from src.services.user_service import change_password, get_address, insert_address -from src.dependencies import get_db +from src.dependency_injection.mongo_db import get_db from src.middlewares.auth_roles_jwt import JWTCustom from src.dependency_injection.containers import Container import src.services.user_service as uSvc diff --git a/src/routers/products_router.py b/src/routers/products_router.py index f2ed7e9..3c325ab 100644 --- a/src/routers/products_router.py +++ b/src/routers/products_router.py @@ -7,7 +7,7 @@ from src.custom_json import MJSONEncoder from src.models.product_model import Product from src.middlewares.auth_jwt import JWTCustom -from src.dependencies import get_db +from src.dependency_injection.mongo_db import get_db oauth2_scheme = JWTCustom(tokenUrl="/auth/sign-in") router = APIRouter(tags=["products"]) diff --git a/src/routers/users_router.py b/src/routers/users_router.py index 3d3936a..ddcad62 100644 --- a/src/routers/users_router.py +++ b/src/routers/users_router.py @@ -13,7 +13,7 @@ from src.services.jwt_service import verify_token_from_requests from src.services.totp_service import TOTP import src.services.user_service as uSvc -from src.dependencies import get_db +from src.dependency_injection.mongo_db import get_db oauth2_scheme = JWTCustom(tokenUrl="/auth/sign-in") router = APIRouter( @@ -24,7 +24,7 @@ totp_dependency = Annotated[TOTP, Depends(Provide[Container.totp])] # Route to add an users -@router.get("/user") +@router.get("/user", response_model_by_alias = False, response_model = User) @inject async def get_user(db: db_dependency, email: Annotated[str, Depends(verify_token_from_requests)]): user = await uSvc.get_user(email, db.get_db()) @@ -33,7 +33,7 @@ async def get_user(db: db_dependency, email: Annotated[str, Depends(verify_token else: return Response(status_code = status.HTTP_404_NOT_FOUND) -@router.post("/user/img", response_model_by_alias = False) +@router.post("/user/img") @inject async def add_user_image(file: UploadFile, db: db_dependency, email: Annotated[str, Depends(verify_token_from_requests)]): result = await uSvc.add_user_picture(email, db.get_db(), file = file, content_type = file.content_type) @@ -42,7 +42,7 @@ async def add_user_image(file: UploadFile, db: db_dependency, email: Annotated[s else: return Response(status_code= status.HTTP_400_BAD_REQUEST) -@router.get("/user/img", response_model_by_alias = False) +@router.get("/user/img") @inject async def get_user_image(db: db_dependency, email: Annotated[str, Depends(verify_token_from_requests)]): result = await uSvc.get_user_picture(email, db.get_db()) @@ -51,7 +51,7 @@ async def get_user_image(db: db_dependency, email: Annotated[str, Depends(verify else: return Response(status_code= status.HTTP_400_BAD_REQUEST) -@router.put("/user") +@router.put("/user", response_model = User, response_model_by_alias = False) @inject async def update_user(db: db_dependency, model: User, email: Annotated[str, Depends(oauth2_scheme)]): user = await uSvc.update_user(db.get_db(), model) @@ -85,7 +85,7 @@ async def verify_2f_code(code: str, email: Annotated[str, Depends(oauth2_scheme) else: return Response(status_code = status.HTTP_401_UNAUTHORIZED) -@router.post("/user/address") +@router.post("/user/address", response_model_by_alias = False, response_model = Address) @inject async def create_address(db: db_dependency, model: Address, email: Annotated[str, Depends(oauth2_scheme)]): address = await insert_address(email, model, db.get_db()) @@ -94,7 +94,7 @@ async def create_address(db: db_dependency, model: Address, email: Annotated[str else: return Response(status_code=status.HTTP_400_BAD_REQUEST) -@router.get("/user/address") +@router.get("/user/address", response_model_by_alias = False, response_model = list[Address]) @inject async def get_addresses(db: db_dependency, email: Annotated[str, Depends(oauth2_scheme)]): addresses = await get_address(db.get_db(), email) diff --git a/src/services/jwt_service.py b/src/services/jwt_service.py index 9dbe3a5..b588b6d 100644 --- a/src/services/jwt_service.py +++ b/src/services/jwt_service.py @@ -10,10 +10,14 @@ crypto_service: CryptoService = Provide[Container.crypto_service] log_service: log2mongo = Provide[Container.logging] -config = Container.config.d() + +def get_jwt_expire_time() -> timedelta: + # Solving DI framework problem, executes later, when the route is called + minutes = int(Container.config.d()["JWT_EXPIRE_MINUTES"]) + return timedelta(minutes=minutes) @inject -async def create_token(data: dict, expire_time: timedelta = timedelta(minutes=int(config["JWT_EXPIRE_MINUTES"])), crypto = crypto_service, log = log_service): +async def create_token(data: dict, expire_time: timedelta = get_jwt_expire_time(), crypto = crypto_service, log = log_service): try: for item in data: if isinstance(data[item], list): @@ -25,7 +29,7 @@ async def create_token(data: dict, expire_time: timedelta = timedelta(minutes=in expire = datetime.now(timezone.utc) + expire_time data.update({ "exp": expire }) - encode_jwt = jwt.encode(data, str(config["JWT_SECRET_KEY"]), algorithm= config["JWT_ALGORITHM"]) + encode_jwt = jwt.encode(data, Container.config.d()["JWT_SECRET_KEY"], algorithm= Container.config.d()["JWT_ALGORITHM"]) return encode_jwt except Exception as e: log.logger.error(e) @@ -73,7 +77,7 @@ async def verify_token_from_requests(request: Request): @inject async def verify(request_token: str, log = log_service): try: - payload = jwt.decode(request_token, str(config["JWT_SECRET_KEY"]), config["JWT_ALGORITHM"]) + payload = jwt.decode(request_token, Container.config.d()["JWT_SECRET_KEY"], Container.config.d()["JWT_ALGORITHM"]) return payload except jwt.ExpiredSignatureError as e: log.logger.error(e) @@ -88,7 +92,7 @@ async def verify(request_token: str, log = log_service): @inject async def get_email(token: str, crypto = crypto_service, log = log_service): try: - payload = jwt.decode(token, str(config["JWT_SECRET_KEY"]), config["JWT_ALGORITHM"]) + payload = jwt.decode(token, Container.config.d()["JWT_SECRET_KEY"], Container.config.d()["JWT_ALGORITHM"]) return await crypto.decrypt_text(payload.get("sub")) except Exception as e: log.logger.error(e) diff --git a/src/services/oauth_google_service.py b/src/services/oauth_google_service.py index 5feb125..de969d3 100644 --- a/src/services/oauth_google_service.py +++ b/src/services/oauth_google_service.py @@ -1,4 +1,3 @@ -import google.oauth2.credentials from log2mongo import log2mongo import google_auth_oauthlib.flow from dependency_injector.wiring import Provide, inject @@ -6,16 +5,22 @@ from src.dependency_injection.containers import Container log_service: log2mongo = Provide[Container.logging] -config = Container.config.d() @inject async def get_auth_url(log = log_service): try: + oauth_client = Container.config.d()["GOOGLE_OAUTH_CLIENT"] + oauth_id = Container.config.d()["GOOGLE_OAUTH_ID"] + oauth_js_origins = Container.config.d()["GOOGLE_OAUTH_JS_ORIGINS"] + oauth_secret = Container.config.d()["GOOGLE_OAUTH_SECRET"] + oauth_scopes = Container.config.d()["GOOGLE_OAUTH_SCOPES"] + oauth_redirect_response = Container.config.d()["GOOGLE_OAUTH_REDIRECT_RESPONSE"] + flow = google_auth_oauthlib.flow.Flow.from_client_config( - {"web":{"client_id":config["GOOGLE_OAUTH_CLIENT"],"project_id":config["GOOGLE_OAUTH_ID"],"auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":config["GOOGLE_OAUTH_SECRET"],"javascript_origins":config["GOOGLE_OAUTH_JS_ORIGINS"].split(',') if config["GOOGLE_OAUTH_JS_ORIGINS"] else []}}, - scopes = config["GOOGLE_OAUTH_SCOPES"].split(',') if config["GOOGLE_OAUTH_SCOPES"] else [] + {"web":{"client_id":oauth_client,"project_id":oauth_id,"auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":oauth_secret,"javascript_origins":oauth_js_origins.split(',') if oauth_js_origins else []}}, + scopes = oauth_scopes.split(',') if oauth_scopes else [] ) - flow.redirect_uri = config["GOOGLE_OAUTH_REDIRECT_RESPONSE"] + flow.redirect_uri = oauth_redirect_response auth_url , state = flow.authorization_url( acces_type = 'offline', @@ -32,11 +37,18 @@ async def get_auth_url(log = log_service): async def get_auth_response(url: str, log = log_service): try: credentials = None + oauth_client = Container.config.d()["GOOGLE_OAUTH_CLIENT"] + oauth_id = Container.config.d()["GOOGLE_OAUTH_ID"] + oauth_js_origins = Container.config.d()["GOOGLE_OAUTH_JS_ORIGINS"] + oauth_secret = Container.config.d()["GOOGLE_OAUTH_SECRET"] + oauth_scopes = Container.config.d()["GOOGLE_OAUTH_SCOPES"] + oauth_redirect_response = Container.config.d()["GOOGLE_OAUTH_REDIRECT_RESPONSE"] + flow = google_auth_oauthlib.flow.Flow.from_client_config( - {"web":{"client_id":config["GOOGLE_OAUTH_CLIENT"],"project_id":config["GOOGLE_OAUTH_ID"],"auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":config["GOOGLE_OAUTH_SECRET"],"javascript_origins":config["GOOGLE_OAUTH_JS_ORIGINS"].split(',') if config["GOOGLE_OAUTH_JS_ORIGINS"] else []}}, - scopes = config["GOOGLE_OAUTH_SCOPES"].split(',') if config["GOOGLE_OAUTH_SCOPES"] else [] + {"web":{"client_id":oauth_client,"project_id":oauth_id,"auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":oauth_secret,"javascript_origins":oauth_js_origins.split(',') if oauth_js_origins else []}}, + scopes = oauth_scopes.split(',') if oauth_scopes else [] ) - flow.redirect_uri = config["GOOGLE_OAUTH_REDIRECT_RESPONSE"] + flow.redirect_uri = oauth_redirect_response auth_reponse = flow.fetch_token(authorization_response = url) credentials = flow.credentials diff --git a/src/services/totp_service.py b/src/services/totp_service.py index 817e52e..b18d3a9 100644 --- a/src/services/totp_service.py +++ b/src/services/totp_service.py @@ -1,7 +1,7 @@ from datetime import datetime +import time from typing import Optional, Union from src.services.otp_service import OTP -import time from log2mongo import log2mongo class TOTP(OTP): diff --git a/src/services/user_service.py b/src/services/user_service.py index 3b20a74..71285a2 100644 --- a/src/services/user_service.py +++ b/src/services/user_service.py @@ -69,7 +69,7 @@ async def add_user_picture(email: str, db: AsyncDatabase, file: UploadFile | Non if user_picture is not None: query_filter = {"_id": user_bd["_id"]} - update_op = {"$set" : {"picture" : Binary(img), "content_type": content_type, "picture_url": "" }} + update_op = { "$set": { "picture": Binary(img), "content_type": content_type, "picture_url": "" }} op_result = await db[users_pics_collection].update_one(query_filter, update_op) if op_result.modified_count > 0: @@ -82,8 +82,8 @@ async def add_user_picture(email: str, db: AsyncDatabase, file: UploadFile | Non result = True elif pic_url: if user_picture is not None: - query_filter = {"_id": user_bd["_id"]} - update_op = {"$set" : {"picture_url" : pic_url, "content_type": 'text/plain', "picture": None }} + query_filter = { "_id": user_bd["_id"] } + update_op = { "$set": { "picture_url": pic_url, "content_type": 'text/plain', "picture": None }} op_result = await db[users_pics_collection].update_one(query_filter, update_op) if op_result.modified_count > 0: @@ -137,7 +137,7 @@ async def disabled_user(db: AsyncDatabase, email: str, log = log_service) -> boo if user_db != None: query_filter = {"email": email} - update_op = {"$set" : {"disabled" : False }} + update_op = { "$set": { "disabled": False }} op_result = await db[users_collection].update_one(query_filter, update_op) if op_result.modified_count > 0: @@ -164,7 +164,7 @@ async def update_user(db: AsyncDatabase, model: User, log = log_service) -> User update_fields[key]= value if update_fields: - update_result = await db[users_collection].update_one({'_id': ObjectId(model.id)}, { "$set": update_fields }) + update_result = await db[users_collection].update_one({ '_id': ObjectId(model.id) }, { "$set": update_fields }) if update_result.modified_count > 0: user = User(**user_db) except Exception as e: @@ -191,8 +191,8 @@ async def change_password(db: AsyncDatabase, email: str, new_password: str, cryp user_db = await db[users_collection].find_one({'email': email}) if user_db != None: - query_filter = {"email": email} - update_op = {"$set" : {"password" : await crypto.get_psw_hash(new_password) }} + query_filter = { "email": email } + update_op = { "$set": { "password": await crypto.get_psw_hash(new_password) }} if (await db[users_collection].update_one(query_filter, update_op)).modified_count > 0: result = True @@ -209,11 +209,11 @@ async def insert_address(email: str, address: Address, db: AsyncDatabase, log = user_db = await db[users_collection].find_one({'email': email}) if user_db is not None: - query_filter = {"email": email} + query_filter = { "email": email } new_address = address.model_dump() id = new_address.pop("id") new_address.update({ "_id": id }) - update_op = {"$push" : {"address" : new_address }} + update_op = { "$push": { "address": new_address }} updated_result = await db[users_collection].update_one(query_filter, update_op) if updated_result.modified_count > 0: @@ -228,10 +228,10 @@ async def insert_address(email: str, address: Address, db: AsyncDatabase, log = async def get_address(db: AsyncDatabase, email: str, log = log_service) -> list[Address] | None: try: addresses = None - query = {'email': email} - projection = {"address": 1, "_id": 0} + query = { 'email': email } + projection = { "address": 1, "_id": 0 } result = await db[users_collection].find_one(query, projection) - addresses = result["address"] # type: ignore + addresses = [Address.model_validate(item) for item in result["address"]] # type: ignore except Exception as e: log.logger.error(e) @@ -242,13 +242,11 @@ async def get_address(db: AsyncDatabase, email: str, log = log_service) -> list[ async def update_address(db: AsyncDatabase, email: str, address: Address, log = log_service) -> bool: try: result = False - updated_address = address.model_dump() - id = updated_address.pop("id") - updated_address.update({ "_id": id }) + updated_address = address.model_dump(by_alias = True) - query_filter = {"email": email, "address._id": address.id } - update_op = {"$set" : {"address.$[elem]" : address.model_dump() }} - array_filter = [{"elem._id": address.id}] + query_filter = { "email": email, "address._id": address.id } + update_op = {"$set": { "address.$[elem]": updated_address }} + array_filter = [{ "elem._id": address.id }] updated_result = await db[users_collection].update_one(query_filter, update_op, array_filters = array_filter) if updated_result.matched_count > 0 or updated_result.modified_count > 0: @@ -266,8 +264,8 @@ async def change_status(status: bool, email: str, db: AsyncDatabase, log = log_s user_db = await db[users_collection].find_one({'email': email}) if user_db != None: - query_filter = {"email": email} - update_op = {"$set" : {"online" : status }} + query_filter = { "email": email } + update_op = { "$set": { "online": status }} op_result = await db[users_collection].update_one(query_filter, update_op) if op_result.modified_count > 0: diff --git a/src/settings_validator.py b/src/settings_validator.py deleted file mode 100644 index 3ffe948..0000000 --- a/src/settings_validator.py +++ /dev/null @@ -1,66 +0,0 @@ -import os, sys -from dotenv import load_dotenv - -load_dotenv() - -class Settings(): - DB_URL: str - DB_NAME: str = "auth-service" - DB_USERS_COLLECTION: str = "users" - DB_USERS_PICTURES_COLLECTION: str = "users.pictures" - DB_USERS_CONTACTS_COLLECTION: str = "users.contacts" - DB_USERS_MESSAGES_COLLECTION: str = "users.messages" - LOG_DB_URL: str - LOG_DATABASE_NAME: str = "auth-service-logs" - LOG_LEVEL: str = "DEBUG" - JWT_SECRET_KEY: str - JWT_ALGORITHM: str = "HS256" - JWT_EXPIRE_MINUTES: int = 240 - CORS_ALLOWED_HOSTS: str = "http://localhost:8081,http://localhost:8002" - TOTP_SECRET: str - TOTP_DIGEST: str = "sha1" - TOTP_RETURN_DIGITS: int = 8 - TOTP_TIME_STEP: int = 30 - GOOGLE_OAUTH_ID: str - GOOGLE_OAUTH_CLIENT: str - GOOGLE_OAUTH_SECRET: str - GOOGLE_OAUTH_REDIRECT_RESPONSE: str = "https://127.0.0.1:8000/auth/google-response" - GOOGLE_OAUTH_JS_ORIGINS: str = "http://127.0.0.1:8000,http://localhost:8081" - GOOGLE_OAUTH_SCOPES: str = "https://www.googleapis.com/auth/userinfo.email,https://www.googleapis.com/auth/userinfo.profile,openid" - CORS_ALLOWED_HOSTS: str - TZ: str = "UTC" - ERROR: bool = False - ERROR_MESSAGE: str - - def __init__(self) -> None: - try: - self.DB_URL = os.environ["DB_URL"] - self.DB_NAME = os.environ["DB_NAME"] - self.DB_USERS_COLLECTION = os.environ["DB_USERS_COLLECTION"] - self.DB_USERS_PICTURES_COLLECTION = os.environ["DB_USERS_PICTURES_COLLECTION"] - self.DB_USERS_CONTACTS_COLLECTION = os.environ["DB_USERS_CONTACTS_COLLECTION"] - self.DB_USERS_MESSAGES_COLLECTION = os.environ["DB_USERS_MESSAGES_COLLECTION"] - self.LOG_DB_URL = os.environ["LOG_DB_URL"] - self.LOG_DATABASE_NAME = os.environ["LOG_DATABASE_NAME"] - self.LOG_LEVEL = os.environ["LOG_LEVEL"] - self.JWT_SECRET_KEY = os.environ["JWT_SECRET_KEY"] - self.JWT_ALGORITHM = os.environ["JWT_ALGORITHM"] - self.JWT_EXPIRE_MINUTES = int(os.environ["JWT_EXPIRE_MINUTES"]) - self.CORS_ALLOWED_HOSTS = os.environ["CORS_ALLOWED_HOSTS"] - self.TOTP_SECRET = os.environ["TOTP_SECRET"] - self.TOTP_DIGEST = os.environ["TOTP_DIGEST"] - self.TOTP_RETURN_DIGITS = int(os.environ["TOTP_RETURN_DIGITS"]) - self.TOTP_TIME_STEP = int(os.environ["TOTP_TIME_STEP"]) - self.GOOGLE_OAUTH_ID = os.environ["GOOGLE_OAUTH_ID"] - self.GOOGLE_OAUTH_CLIENT = os.environ["GOOGLE_OAUTH_CLIENT"] - self.GOOGLE_OAUTH_SECRET = os.environ["GOOGLE_OAUTH_SECRET"] - self.GOOGLE_OAUTH_REDIRECT_RESPONSE = os.environ["GOOGLE_OAUTH_REDIRECT_RESPONSE"] - self.GOOGLE_OAUTH_JS_ORIGINS = os.environ["GOOGLE_OAUTH_JS_ORIGINS"] - self.GOOGLE_OAUTH_SCOPES = os.environ["GOOGLE_OAUTH_SCOPES"] - self.CORS_ALLOWED_HOSTS = os.environ["CORS_ALLOWED_HOSTS"] - self.TZ = os.environ["TZ"] - except Exception as e: - self.ERROR = True - self.ERROR_MESSAGE = "Missing or incorrect configuration value: " + e.__str__() - print(self.ERROR_MESSAGE) - sys.exit(78) \ No newline at end of file From 74191a70f446e31cf22fe92325529106efb91194 Mon Sep 17 00:00:00 2001 From: ablogo Date: Sat, 5 Sep 2026 14:25:10 +0900 Subject: [PATCH 2/2] increase version number --- src/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/__init__.py b/src/__init__.py index 10f3f45..8b4dc1c 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -1,2 +1,2 @@ "Authentication microservice, the goal of this project is to learn Python and FastApi" -__version__= "1.0.1" \ No newline at end of file +__version__= "1.0.2" \ No newline at end of file