feat: register done

This commit is contained in:
akhdanre 2025-03-19 22:35:02 +07:00
parent bc5094ed7d
commit c06b7ab899
21 changed files with 126 additions and 45 deletions

View File

@ -1,5 +1,6 @@
from .default import default_blueprint from .default import default_blueprint
from .auth import auth_blueprint from .auth import auth_blueprint
from .user import user_blueprint
# from .user import user_blueprint # from .user import user_blueprint

View File

@ -1,4 +1,3 @@
import sys
from flask import Blueprint from flask import Blueprint
from controllers import AuthController from controllers import AuthController
from di_container import Container from di_container import Container
@ -8,12 +7,6 @@ from dependency_injector.wiring import inject, Provide
auth_blueprint = Blueprint("auth", __name__) auth_blueprint = Blueprint("auth", __name__)
@auth_blueprint.route("/register", methods=["POST"])
@inject
def register(auth_controller: AuthController = Provide[Container.auth_controller]):
return auth_controller.register()
@auth_blueprint.route("/login", methods=["POST"]) @auth_blueprint.route("/login", methods=["POST"])
@inject @inject
def login(auth_controller: AuthController = Provide[Container.auth_controller]): def login(auth_controller: AuthController = Provide[Container.auth_controller]):

View File

@ -1,12 +1,18 @@
from flask import Blueprint from flask import Blueprint
from controllers import UserController from controllers import UserController
from di_container import container from di_container import Container
from dependency_injector.wiring import inject, Provide
user_blueprint = Blueprint("user", __name__) user_blueprint = Blueprint("user", __name__)
user_controller = UserController(container.user_service)
@user_blueprint.route("/users", methods=["GET"]) @user_blueprint.route("/users", methods=["GET"])
def get_users(): @inject
def get_users(user_controller: UserController = Provide[Container.user_controller]):
return user_controller.get_users() return user_controller.get_users()
@user_blueprint.route("/register", methods=["POST"])
@inject
def register(user_controller: UserController = Provide[Container.user_controller]):
return user_controller.register()

View File

@ -4,7 +4,7 @@ from schemas.basic_response_schema import ResponseSchema
from schemas.google_login_schema import GoogleLoginSchema from schemas.google_login_schema import GoogleLoginSchema
from schemas import LoginSchema from schemas import LoginSchema
from services import UserService, AuthService from services import UserService, AuthService
from core import AuthException from exception import AuthException
class AuthController: class AuthController:
@ -17,10 +17,10 @@ class AuthController:
data = request.get_json() data = request.get_json()
dataSchema = LoginSchema(**data) dataSchema = LoginSchema(**data)
response = self.auth_service.login(dataSchema) response = self.auth_service.login(dataSchema)
return (
if response.success: jsonify(ResponseSchema(message="Register success", data=response)),
return jsonify({}), 200 200,
return jsonify({}), 400 )
except ValidationError as e: except ValidationError as e:
current_app.logger.error(f"Validation error: {e}") current_app.logger.error(f"Validation error: {e}")
response = ResponseSchema(message="Invalid input", data=None, meta=None) response = ResponseSchema(message="Invalid input", data=None, meta=None)
@ -79,11 +79,5 @@ class AuthController:
) )
return jsonify(response.model_dump()), 500 return jsonify(response.model_dump()), 500
def register(self):
return jsonify({"message": "register"}), 200
def logout(self): def logout(self):
return jsonify({"message": "logout"}), 200 return jsonify({"message": "logout"}), 200
def test(self):
return "test"

View File

@ -1,12 +1,41 @@
# /controllers/user_controller.py # /controllers/user_controller.py
from flask import jsonify from flask import jsonify, request, current_app
from services import UserService from services import UserService
from schemas import RegisterSchema
from pydantic import ValidationError
from schemas import ResponseSchema
from exception import AlreadyExistException
class UserController: class UserController:
def __init__(self, userService: UserService): def __init__(self, userService: UserService):
self.user_service = userService self.user_service = userService
def get_users(self): def register(self):
users = self.user_service.get_all_users() try:
return jsonify(users) request_data = request.get_json()
register_data = RegisterSchema(**request_data)
self.user_service.register_user(register_data)
return jsonify(ResponseSchema(message="Register Success").model_dump()), 200
except ValidationError as e:
current_app.logger.error(f"Validation error: {e}")
response = ResponseSchema(message="Invalid input", data=None, meta=None)
return jsonify(response.model_dump()), 400
except AlreadyExistException as e:
return (
jsonify(
ResponseSchema(message=str(e), data=None, meta=None).model_dump()
),
409,
)
except Exception as e:
current_app.logger.error(
f"Error during Google login: {str(e)}", exc_info=True
)
response = ResponseSchema(
message="Internal server error", data=None, meta=None
)
return jsonify(response.model_dump()), 500

View File

@ -1 +0,0 @@
from .exception import AuthException

View File

@ -1 +0,0 @@
from .auth_exception import AuthException

View File

@ -1,9 +0,0 @@
class AuthException(Exception):
"""Custom exception for authentication-related errors"""
def __init__(self, message):
super().__init__(message)
self.message = message
def __str__(self):
return f"AuthException: {self.message}"

View File

@ -1,4 +1,5 @@
from dependency_injector import containers, providers from dependency_injector import containers, providers
from controllers import UserController
from repositories.user_repository import UserRepository from repositories.user_repository import UserRepository
from services import UserService, AuthService from services import UserService, AuthService
from controllers import AuthController from controllers import AuthController
@ -19,3 +20,4 @@ class Container(containers.DeclarativeContainer):
# controllers # controllers
auth_controller = providers.Factory(AuthController, user_service, auth_service) auth_controller = providers.Factory(AuthController, user_service, auth_service)
user_controller = providers.Factory(UserController, user_service)

View File

@ -0,0 +1,2 @@
from .auth_exception import AuthException
from .already_exist_exception import AlreadyExistException

View File

@ -0,0 +1,6 @@
class AlreadyExistException(Exception):
def __init__(self, entity: str, message: str = None):
if message is None:
message = f"{entity} already exists"
self.message = message
super().__init__(self.message)

View File

@ -0,0 +1,8 @@
from .base_exception import BaseExceptionTemplate
class AuthException(BaseExceptionTemplate):
"""Exception for authentication-related errors"""
def __init__(self, message: str = "Authentication failed"):
super().__init__(message, status_code=401)

View File

@ -0,0 +1,10 @@
class BaseExceptionTemplate(Exception):
"""Base exception template for custom exceptions"""
def __init__(self, message: str, status_code: int = 400):
self.message = message
self.status_code = status_code
super().__init__(self.message)
def __str__(self):
return f"{self.__class__.__name__}: {self.message}"

View File

@ -2,7 +2,7 @@ from blueprints import default_blueprint
from di_container import Container from di_container import Container
from configs import Config, LoggerConfig from configs import Config, LoggerConfig
from flask import Flask from flask import Flask
from blueprints import auth_blueprint from blueprints import auth_blueprint, user_blueprint
from database import init_db from database import init_db
@ -19,10 +19,12 @@ def createApp() -> Flask:
container.mongo.override(mongo) container.mongo.override(mongo)
container.wire(modules=["blueprints.auth"]) container.wire(modules=["blueprints.auth"])
container.wire(modules=["blueprints.user"])
# Register Blueprints # Register Blueprints
app.register_blueprint(default_blueprint) app.register_blueprint(default_blueprint)
app.register_blueprint(auth_blueprint, url_prefix="/api") app.register_blueprint(auth_blueprint, url_prefix="/api")
app.register_blueprint(user_blueprint, url_prefix="/api")
# Initialize Logging # Initialize Logging
LoggerConfig.init_logger(app) LoggerConfig.init_logger(app)

View File

@ -1,6 +1,7 @@
from datetime import datetime from datetime import datetime
from typing import Dict, Optional from typing import Dict, Optional
from models import UserEntity from models import UserEntity
from schemas import RegisterSchema
class UserMapper: class UserMapper:
@ -22,3 +23,19 @@ class UserMapper:
updated_at=datetime.now(), updated_at=datetime.now(),
verification_token=None, verification_token=None,
) )
@staticmethod
def from_register(data: RegisterSchema) -> UserEntity:
return UserEntity(
email=data.email,
password=data.password,
name=data.name,
birth_date=datetime.strptime(data.birth_date, "%d-%m-%Y").date(),
phone=data.phone,
role="user",
is_active=False,
address=None,
created_at=datetime.now(),
updated_at=datetime.now(),
verification_token=None,
)

View File

@ -1,6 +1,6 @@
from typing import Optional from typing import Optional
from pydantic import BaseModel, EmailStr from pydantic import BaseModel, EmailStr
from datetime import date, datetime from datetime import datetime
from .base import PyObjectId from .base import PyObjectId
@ -10,7 +10,7 @@ class UserEntity(BaseModel):
email: EmailStr email: EmailStr
password: Optional[str] = None password: Optional[str] = None
name: str name: str
birth_date: Optional[date] = None birth_date: Optional[datetime] = None
pic_url: Optional[str] = None pic_url: Optional[str] = None
phone: Optional[str] = None phone: Optional[str] = None
locale: str = "en-US" locale: str = "en-US"

View File

@ -1,2 +1,3 @@
from .login_schema import LoginSchema from .login_schema import LoginSchema
from .basic_response_schema import ResponseSchema, MetaSchema from .basic_response_schema import ResponseSchema, MetaSchema
from .requests import RegisterSchema

View File

@ -0,0 +1 @@
from .register_schema import RegisterSchema

View File

@ -0,0 +1,10 @@
from pydantic import BaseModel
from typing import Optional
class RegisterSchema(BaseModel):
email: str
password: str
name: str
birth_date: str
phone: Optional[str] = None

View File

@ -4,7 +4,7 @@ from mapper import UserMapper
from google.oauth2 import id_token from google.oauth2 import id_token
from google.auth.transport import requests from google.auth.transport import requests
from configs import Config from configs import Config
from core import AuthException from exception import AuthException
from flask import current_app from flask import current_app
@ -13,14 +13,12 @@ class AuthService:
self.user_repository = userRepository self.user_repository = userRepository
def verify_google_id_token(self, id_token_str): def verify_google_id_token(self, id_token_str):
# Verifikasi token Google
payload = id_token.verify_oauth2_token( payload = id_token.verify_oauth2_token(
id_token_str, requests.Request(), Config.GOOGLE_CLIENT_ID id_token_str, requests.Request(), Config.GOOGLE_CLIENT_ID
) )
if not payload: if not payload:
return AuthException("Invalid Google ID Token") raise AuthException("Invalid Google ID Token")
google_id = payload.get("sub") google_id = payload.get("sub")
email = payload.get("email") email = payload.get("email")
@ -29,7 +27,7 @@ class AuthService:
if existing_user: if existing_user:
if existing_user.email == email: if existing_user.email == email:
return existing_user return existing_user
return AuthException("Email not match") raise AuthException("Email not match")
new_user = UserMapper.from_google_payload(google_id, email, payload) new_user = UserMapper.from_google_payload(google_id, email, payload)

View File

@ -1,4 +1,8 @@
from flask import current_app
from repositories import UserRepository from repositories import UserRepository
from schemas import RegisterSchema
from mapper import UserMapper
from exception import AlreadyExistException
class UserService: class UserService:
@ -7,3 +11,11 @@ class UserService:
def get_all_users(self): def get_all_users(self):
return self.user_repository.get_all_users() return self.user_repository.get_all_users()
def register_user(self, user_data: RegisterSchema):
existData = self.user_repository.get_user_by_email(user_data.email)
if existData:
raise AlreadyExistException(entity="Email")
data = UserMapper.from_register(user_data)
return self.user_repository.insert_user(data)