feat: register done
This commit is contained in:
parent
bc5094ed7d
commit
c06b7ab899
|
@ -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
|
||||||
|
|
|
@ -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]):
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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"
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
from .exception import AuthException
|
|
|
@ -1 +0,0 @@
|
||||||
from .auth_exception import AuthException
|
|
|
@ -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}"
|
|
|
@ -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)
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
from .auth_exception import AuthException
|
||||||
|
from .already_exist_exception import AlreadyExistException
|
|
@ -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)
|
|
@ -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)
|
|
@ -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}"
|
|
@ -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)
|
||||||
|
|
|
@ -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,
|
||||||
|
)
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
from .register_schema import RegisterSchema
|
|
@ -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
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue