|
from fastapi import APIRouter, HTTPException, status, Depends, Query |
|
from fastapi.responses import JSONResponse |
|
from .Schema import ( |
|
RegisterUserRequest, |
|
LoginUserRequest, |
|
AccessTokenResponse, |
|
ForgotPasswordRequest, |
|
VerifyResetTokenRequest, |
|
ResetPasswordRequest, |
|
BaseResponse, |
|
UserResponse, |
|
) |
|
from .Model import User |
|
from jose import jwt |
|
from typing import List |
|
from datetime import datetime, timedelta |
|
from App.Subscriptions.Model import Subscription |
|
from App.Android.Android import AndroidClient |
|
from App.Android.Schema import RegisterUserRequest as AndroidRegister |
|
from App.Templates.Templates import MessageTemplate |
|
from .dependencies import get_current_active_user, get_admin_user |
|
from App.Android.Schema import APIResponse |
|
|
|
|
|
|
|
SECRET_KEY = "your_secret_key_here" |
|
ALGORITHM = "HS256" |
|
ACCESS_TOKEN_EXPIRE_MINUTES = 300 |
|
user_router = APIRouter(tags=["User"]) |
|
client = AndroidClient() |
|
templates = MessageTemplate() |
|
|
|
|
|
def create_access_token(data: dict, expires_delta: timedelta = None): |
|
to_encode = data.copy() |
|
expire = datetime.utcnow() + ( |
|
expires_delta or timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) |
|
) |
|
to_encode.update({"exp": expire}) |
|
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@user_router.post( |
|
"/user/register", response_model=BaseResponse, status_code=status.HTTP_201_CREATED |
|
) |
|
async def register_user(request: RegisterUserRequest): |
|
existing_user = await User.filter(phoneNumber=request.phoneNumber).first() |
|
if existing_user: |
|
raise HTTPException( |
|
status_code=status.HTTP_400_BAD_REQUEST, detail="User already exists." |
|
) |
|
|
|
new_user = await User.create_user(request.dict()) |
|
return BaseResponse( |
|
code=200, message="User created successfully", payload={"user_id": new_user.id} |
|
) |
|
|
|
|
|
@user_router.post( |
|
"/user/login", response_model=AccessTokenResponse, status_code=status.HTTP_200_OK |
|
) |
|
async def login_user(request: LoginUserRequest): |
|
|
|
db_user: User = await User.filter(phoneNumber=request.phoneNumber).first() |
|
|
|
|
|
if db_user is None: |
|
raise HTTPException( |
|
status_code=status.HTTP_404_NOT_FOUND, detail="User not found." |
|
) |
|
|
|
valid_password = await db_user.verify_password(request.password) |
|
|
|
if db_user and valid_password: |
|
|
|
|
|
subscription = await Subscription.filter(user=db_user, active=True).first() |
|
|
|
|
|
subscription_end = ( |
|
subscription.expiration_time.isoformat() if subscription else None |
|
) |
|
|
|
is_active = await db_user.is_active() |
|
if is_active: |
|
await db_user.remover_user_session() |
|
access_token = create_access_token( |
|
data={ |
|
"user_type": db_user.user_type, |
|
"user_name": db_user.name, |
|
"sub": db_user.phoneNumber, |
|
"locked": db_user.account_locked, |
|
"userId": db_user.id, |
|
"subscription_end": subscription_end, |
|
} |
|
) |
|
return AccessTokenResponse(access_token=access_token, token_type="bearer") |
|
|
|
|
|
raise HTTPException( |
|
status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid credentials" |
|
) |
|
|
|
|
|
@user_router.post( |
|
"/user/forgot-password", response_model=BaseResponse, status_code=status.HTTP_200_OK |
|
) |
|
async def forgot_password(request: ForgotPasswordRequest): |
|
user = await User.filter(phoneNumber=request.phoneNumber).first() |
|
if not user: |
|
raise HTTPException( |
|
status_code=status.HTTP_404_NOT_FOUND, detail="User not found." |
|
) |
|
await user.initiate_password_reset() |
|
return BaseResponse(code=200, message="Password reset token sent to your phone.") |
|
|
|
|
|
@user_router.post( |
|
"/user/verify-reset-token", |
|
response_model=BaseResponse, |
|
status_code=status.HTTP_200_OK, |
|
) |
|
async def verify_reset_token(request: VerifyResetTokenRequest): |
|
user = await User.filter( |
|
phoneNumber=request.phoneNumber, reset_token=request.reset_token |
|
).first() |
|
if not user or datetime.utcnow() > user.reset_token_expiration: |
|
raise HTTPException( |
|
status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid or expired token." |
|
) |
|
return BaseResponse(code=200, message="Token verified. Proceed to reset password.") |
|
|
|
|
|
@user_router.post( |
|
"/user/reset-password", response_model=BaseResponse, status_code=status.HTTP_200_OK |
|
) |
|
async def reset_password(request: ResetPasswordRequest): |
|
user = await User.filter(phoneNumber=request.phoneNumber).first() |
|
if not user: |
|
raise HTTPException( |
|
status_code=status.HTTP_404_NOT_FOUND, detail="User not found." |
|
) |
|
if not await user.reset_password(request.reset_token, request.new_password): |
|
raise HTTPException( |
|
status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid or expired token." |
|
) |
|
return BaseResponse(code=200, message="Password has been reset successfully.") |
|
|
|
|
|
@user_router.get( |
|
"/user/all", |
|
response_model=List[UserResponse], |
|
status_code=status.HTTP_200_OK, |
|
) |
|
async def get_all_users(admin: User = Depends(get_admin_user)): |
|
users = await User.all() |
|
return [UserResponse.from_orm(user) for user in users] |
|
|
|
|
|
@user_router.delete( |
|
"/user/{user_id}", response_model=BaseResponse, status_code=status.HTTP_200_OK |
|
) |
|
async def delete_user(user_id: str, admin: User = Depends(get_current_active_user)): |
|
user = await User.filter(id=user_id).first() |
|
if not user: |
|
raise HTTPException( |
|
status_code=status.HTTP_404_NOT_FOUND, detail="User not found." |
|
) |
|
await user.delete() |
|
return BaseResponse(code=200, message="User deleted successfully.") |
|
|
|
|
|
@user_router.put( |
|
"/user/toggle_status/{user_id}", |
|
response_model=BaseResponse, |
|
status_code=status.HTTP_200_OK, |
|
) |
|
async def toggle_user_status(user_id: str): |
|
user = await User.filter(id=user_id).first() |
|
if not user: |
|
raise HTTPException( |
|
status_code=status.HTTP_404_NOT_FOUND, detail="User not found." |
|
) |
|
await user.toggle_status() |
|
message = ( |
|
"User disabled successfully." |
|
if user.account_locked |
|
else "User enabled successfully." |
|
) |
|
return BaseResponse(code=200, message=message) |
|
|
|
|
|
@user_router.get( |
|
"/user/me", response_model=UserResponse, status_code=status.HTTP_200_OK |
|
) |
|
async def get_user_details(current_user: User = Depends(get_current_active_user)): |
|
""" |
|
Get the current user's details and balance. |
|
""" |
|
return UserResponse.from_orm(current_user) |
|
|
|
|
|
@user_router.post("/user/{user_id}/activate", response_model=BaseResponse) |
|
async def activate_user(user_id: str): |
|
user = await User.get_or_none(id=user_id) |
|
if not user: |
|
raise HTTPException( |
|
status_code=status.HTTP_404_NOT_FOUND, detail="User not found." |
|
) |
|
|
|
if await user.activate_user(): |
|
return BaseResponse(code=200, message="User activated successfully.") |
|
else: |
|
raise HTTPException( |
|
status_code=status.HTTP_400_BAD_REQUEST, detail="Failed to activate user." |
|
) |
|
|
|
|
|
@user_router.get( |
|
"/users/active", response_model=List[str] |
|
) |
|
async def get_active_users(): |
|
|
|
api_response: APIResponse = await client.get_active_users() |
|
active_users = api_response.active_users |
|
|
|
if not api_response or not active_users: |
|
return JSONResponse(content={"status": 200, "message": "no users online"}) |
|
|
|
|
|
active_phone_numbers = [user["phone"] for user in active_users] |
|
|
|
|
|
users_in_db = await User.filter(phoneNumber__in=active_phone_numbers).all() |
|
|
|
|
|
usernames = [ |
|
{"name": user.name, "phone": user.phoneNumber} for user in users_in_db |
|
] |
|
|
|
if not usernames: |
|
return JSONResponse( |
|
content={"status": 200, "message": "No matching active users found."} |
|
) |
|
|
|
return JSONResponse( |
|
content={ |
|
"status": 200, |
|
"message": f"Found {len(usernames)} active", |
|
"payload": usernames, |
|
} |
|
) |
|
|
|
|
|
@user_router.get("/user/active", response_model=List[UserResponse]) |
|
async def get_active_user(phone_numbers: List[str] = Query(...)): |
|
|
|
api_response: APIResponse = await client.get_active_users() |
|
active_users = api_response.active_users |
|
if not api_response or not api_response.active_users: |
|
return JSONResponse(content={"status": 200, "message": "no users online"}) |
|
|
|
|
|
matched_users = [ |
|
UserResponse.from_orm(user) |
|
for user in active_users |
|
if user["phone"] in phone_numbers |
|
] |
|
|
|
if not matched_users: |
|
return JSONResponse( |
|
content={"status": 200, "message": "No matching active users found."} |
|
) |
|
|
|
return matched_users |
|
|