Spaces:
Sleeping
Sleeping
Abineshkumar
commited on
Commit
·
51ac0e6
1
Parent(s):
f9f6e70
Add application file
Browse files- Dockerfile +16 -0
- README.md +4 -5
- __pycache__/config.cpython-310.pyc +0 -0
- __pycache__/main.cpython-310.pyc +0 -0
- auth/__init__.py +0 -0
- auth/__pycache__/__init__.cpython-310.pyc +0 -0
- auth/__pycache__/auth_bearer.cpython-310.pyc +0 -0
- auth/__pycache__/auth_handler.cpython-310.pyc +0 -0
- auth/auth_bearer.py +26 -0
- auth/auth_handler.py +39 -0
- config.py +16 -0
- main.py +11 -0
- models/__pycache__/user_model.cpython-310.pyc +0 -0
- models/user_model.py +76 -0
- requirements.txt +14 -0
- routes/__init__.py +0 -0
- routes/__pycache__/__init__.cpython-310.pyc +0 -0
- routes/__pycache__/users.cpython-310.pyc +0 -0
- routes/users.py +60 -0
- serviceAccountKey.json +13 -0
- services/1.txt +144 -0
- services/__pycache__/users_service.cpython-310.pyc +0 -0
- services/users_service.py +144 -0
Dockerfile
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Read the doc: https://huggingface.co/docs/hub/spaces-sdks-docker
|
| 2 |
+
# you will also find guides on how best to write your Dockerfile
|
| 3 |
+
|
| 4 |
+
FROM python:3.9
|
| 5 |
+
|
| 6 |
+
RUN useradd -m -u 1000 user
|
| 7 |
+
USER user
|
| 8 |
+
ENV PATH="/home/user/.local/bin:$PATH"
|
| 9 |
+
|
| 10 |
+
WORKDIR /app
|
| 11 |
+
|
| 12 |
+
COPY --chown=user ./requirements.txt requirements.txt
|
| 13 |
+
RUN pip install --no-cache-dir --upgrade -r requirements.txt
|
| 14 |
+
|
| 15 |
+
COPY --chown=user . /app
|
| 16 |
+
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
|
README.md
CHANGED
|
@@ -1,11 +1,10 @@
|
|
| 1 |
---
|
| 2 |
-
title: Age Better
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
sdk: docker
|
| 7 |
pinned: false
|
| 8 |
-
license: apache-2.0
|
| 9 |
---
|
| 10 |
|
| 11 |
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
|
| 1 |
---
|
| 2 |
+
title: Age Better Endpoints
|
| 3 |
+
emoji: 👀
|
| 4 |
+
colorFrom: red
|
| 5 |
+
colorTo: blue
|
| 6 |
sdk: docker
|
| 7 |
pinned: false
|
|
|
|
| 8 |
---
|
| 9 |
|
| 10 |
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
__pycache__/config.cpython-310.pyc
ADDED
|
Binary file (547 Bytes). View file
|
|
|
__pycache__/main.cpython-310.pyc
ADDED
|
Binary file (443 Bytes). View file
|
|
|
auth/__init__.py
ADDED
|
File without changes
|
auth/__pycache__/__init__.cpython-310.pyc
ADDED
|
Binary file (132 Bytes). View file
|
|
|
auth/__pycache__/auth_bearer.cpython-310.pyc
ADDED
|
Binary file (1.27 kB). View file
|
|
|
auth/__pycache__/auth_handler.cpython-310.pyc
ADDED
|
Binary file (1.22 kB). View file
|
|
|
auth/auth_bearer.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi import Request, HTTPException
|
| 2 |
+
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
|
| 3 |
+
from .auth_handler import decodeJWT
|
| 4 |
+
|
| 5 |
+
class JWTBearer(HTTPBearer):
|
| 6 |
+
"""Class to validate JWT tokens on protected routes."""
|
| 7 |
+
async def __call__(self, request: Request):
|
| 8 |
+
credentials: HTTPAuthorizationCredentials = await super(JWTBearer, self).__call__(request)
|
| 9 |
+
if credentials:
|
| 10 |
+
if not credentials.scheme == "Bearer":
|
| 11 |
+
raise HTTPException(status_code=403, detail="Invalid authentication scheme.")
|
| 12 |
+
if not self.verify_jwt(credentials.credentials):
|
| 13 |
+
raise HTTPException(status_code=403, detail="Invalid token or expired token.")
|
| 14 |
+
return credentials.credentials
|
| 15 |
+
else:
|
| 16 |
+
raise HTTPException(status_code=403, detail="Invalid authorization code.")
|
| 17 |
+
|
| 18 |
+
def verify_jwt(self, jwtoken: str) -> bool:
|
| 19 |
+
is_token_valid: bool = False
|
| 20 |
+
try:
|
| 21 |
+
payload = decodeJWT(jwtoken)
|
| 22 |
+
except:
|
| 23 |
+
payload = None
|
| 24 |
+
if payload:
|
| 25 |
+
is_token_valid = True
|
| 26 |
+
return is_token_valid
|
auth/auth_handler.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import time
|
| 2 |
+
import jwt
|
| 3 |
+
from typing import Dict
|
| 4 |
+
from decouple import config
|
| 5 |
+
|
| 6 |
+
# Load secret and algorithm from environment variables
|
| 7 |
+
JWT_SECRET = config("SECRET_KEY") # Example: from .env file or environment variable
|
| 8 |
+
JWT_ALGORITHM = config("ALGORITHM", default="HS256") # Default to HS256 if not set
|
| 9 |
+
|
| 10 |
+
def token_response(token: str) -> Dict[str, str]:
|
| 11 |
+
return {
|
| 12 |
+
"access_token": token
|
| 13 |
+
}
|
| 14 |
+
|
| 15 |
+
def signJWT(user_id: str) -> Dict[str, str]:
|
| 16 |
+
"""Sign a JWT for the user."""
|
| 17 |
+
payload = {
|
| 18 |
+
"user_id": user_id,
|
| 19 |
+
"expires": time.time() + 600 # 10-minute expiration
|
| 20 |
+
}
|
| 21 |
+
token = jwt.encode(payload, JWT_SECRET, algorithm=JWT_ALGORITHM)
|
| 22 |
+
return token_response(token)
|
| 23 |
+
|
| 24 |
+
def decodeJWT(token: str) -> dict:
|
| 25 |
+
"""Decode a JWT token."""
|
| 26 |
+
try:
|
| 27 |
+
decoded_token = jwt.decode(token, JWT_SECRET, algorithms=[JWT_ALGORITHM])
|
| 28 |
+
return decoded_token if decoded_token["expires"] >= time.time() else None
|
| 29 |
+
except:
|
| 30 |
+
return {}
|
| 31 |
+
|
| 32 |
+
def decodeJWT(token: str) -> dict:
|
| 33 |
+
try:
|
| 34 |
+
# Decode JWT to get payload containing user_id
|
| 35 |
+
decoded_token = jwt.decode(token, JWT_SECRET, algorithms=[JWT_ALGORITHM])
|
| 36 |
+
# Ensure token has not expired
|
| 37 |
+
return decoded_token if decoded_token["expires"] >= time.time() else None
|
| 38 |
+
except:
|
| 39 |
+
return {}
|
config.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import firebase_admin
|
| 2 |
+
from firebase_admin import credentials, firestore, auth
|
| 3 |
+
import os
|
| 4 |
+
from decouple import config
|
| 5 |
+
|
| 6 |
+
FIREBASE_API_KEY = os.getenv("AIzaSyDCu6_7nNK63tkX1EONVz3ndIVd6frcy9Y") # Set this environment variable with your Firebase API key
|
| 7 |
+
|
| 8 |
+
if not firebase_admin._apps:
|
| 9 |
+
cred = credentials.Certificate("serviceAccountKey.json") # Path to Firebase Admin SDK JSON file
|
| 10 |
+
firebase_admin.initialize_app(cred)
|
| 11 |
+
|
| 12 |
+
db = firestore.client()
|
| 13 |
+
|
| 14 |
+
# JWT config
|
| 15 |
+
SECRET_KEY = config("SECRET_KEY")
|
| 16 |
+
ALGORITHM = config("ALGORITHM", default="HS256")
|
main.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi import FastAPI
|
| 2 |
+
from routes import users
|
| 3 |
+
|
| 4 |
+
app = FastAPI()
|
| 5 |
+
|
| 6 |
+
# Register the user routes
|
| 7 |
+
app.include_router(users.router)
|
| 8 |
+
|
| 9 |
+
@app.get("/")
|
| 10 |
+
def read_root():
|
| 11 |
+
return {"message": "User Management System with JWT and Firebase is running"}
|
models/__pycache__/user_model.cpython-310.pyc
ADDED
|
Binary file (2.82 kB). View file
|
|
|
models/user_model.py
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from pydantic import BaseModel, EmailStr
|
| 2 |
+
|
| 3 |
+
class User(BaseModel):
|
| 4 |
+
id: str
|
| 5 |
+
name: str
|
| 6 |
+
surname: str
|
| 7 |
+
phone: str
|
| 8 |
+
email: EmailStr
|
| 9 |
+
role: str
|
| 10 |
+
status: str
|
| 11 |
+
|
| 12 |
+
class CreateUser(BaseModel):
|
| 13 |
+
email: EmailStr
|
| 14 |
+
password: str
|
| 15 |
+
|
| 16 |
+
class UpdateUser(BaseModel):
|
| 17 |
+
name: str = None
|
| 18 |
+
surname: str = None
|
| 19 |
+
phone: str = None
|
| 20 |
+
email: EmailStr = None
|
| 21 |
+
role: str = None
|
| 22 |
+
status: str = None
|
| 23 |
+
|
| 24 |
+
class OTPVerification(BaseModel):
|
| 25 |
+
email: EmailStr
|
| 26 |
+
otp: str
|
| 27 |
+
|
| 28 |
+
class ResetPassword(BaseModel):
|
| 29 |
+
email: EmailStr
|
| 30 |
+
newPassword: str
|
| 31 |
+
|
| 32 |
+
class ChangePassword(BaseModel):
|
| 33 |
+
currentPassword: str
|
| 34 |
+
newPassword: str
|
| 35 |
+
|
| 36 |
+
class DeleteUserRequest(BaseModel):
|
| 37 |
+
password: str
|
| 38 |
+
|
| 39 |
+
class TokenRequest(BaseModel):
|
| 40 |
+
email: EmailStr
|
| 41 |
+
|
| 42 |
+
class UserProfileData(BaseModel):
|
| 43 |
+
id: str
|
| 44 |
+
name: str
|
| 45 |
+
surname: str
|
| 46 |
+
phone: str
|
| 47 |
+
email: str
|
| 48 |
+
role: str
|
| 49 |
+
status: str
|
| 50 |
+
|
| 51 |
+
class UserProfileResponse(BaseModel):
|
| 52 |
+
isSuccess: bool
|
| 53 |
+
data: UserProfileData
|
| 54 |
+
|
| 55 |
+
class CreateUser(BaseModel):
|
| 56 |
+
email: EmailStr
|
| 57 |
+
password: str
|
| 58 |
+
|
| 59 |
+
class TokenRequest(BaseModel):
|
| 60 |
+
email: EmailStr
|
| 61 |
+
password: str
|
| 62 |
+
|
| 63 |
+
class DeleteUserRequest(BaseModel):
|
| 64 |
+
password: str
|
| 65 |
+
|
| 66 |
+
class UpdateProfile(BaseModel):
|
| 67 |
+
name: str = None
|
| 68 |
+
surname: str = None
|
| 69 |
+
|
| 70 |
+
class Config:
|
| 71 |
+
schema_extra = {
|
| 72 |
+
"example": {
|
| 73 |
+
"name": "John",
|
| 74 |
+
"surname": "Doe"
|
| 75 |
+
}
|
| 76 |
+
}
|
requirements.txt
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
firebase-admin
|
| 2 |
+
fastapi
|
| 3 |
+
uvicorn
|
| 4 |
+
sqlmodel
|
| 5 |
+
typer
|
| 6 |
+
dynaconf
|
| 7 |
+
jinja2
|
| 8 |
+
python-jose[cryptography]
|
| 9 |
+
passlib[bcrypt]
|
| 10 |
+
python-multipart
|
| 11 |
+
psycopg2-binary
|
| 12 |
+
uuid
|
| 13 |
+
pydantic
|
| 14 |
+
email-validator
|
routes/__init__.py
ADDED
|
File without changes
|
routes/__pycache__/__init__.cpython-310.pyc
ADDED
|
Binary file (142 Bytes). View file
|
|
|
routes/__pycache__/users.cpython-310.pyc
ADDED
|
Binary file (2.42 kB). View file
|
|
|
routes/users.py
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi import APIRouter, HTTPException, Header, Query, Depends,Body
|
| 2 |
+
from services.users_service import create_user_in_firestore, get_user_from_firestore, update_user_in_firestore,login_for_access_token, delete_user_profile, get_user_profile_from_firestore,update_user_profile
|
| 3 |
+
from models.user_model import CreateUser, UpdateUser, TokenRequest,DeleteUserRequest,UpdateProfile
|
| 4 |
+
from datetime import timedelta
|
| 5 |
+
from firebase_admin import credentials, auth, firestore
|
| 6 |
+
from config import db
|
| 7 |
+
from auth.auth_bearer import JWTBearer
|
| 8 |
+
from auth.auth_handler import decodeJWT
|
| 9 |
+
|
| 10 |
+
router = APIRouter(
|
| 11 |
+
prefix="/api/v1/users",
|
| 12 |
+
tags=["Users"]
|
| 13 |
+
)
|
| 14 |
+
|
| 15 |
+
@router.post("")
|
| 16 |
+
def create_user(user_data: CreateUser):
|
| 17 |
+
"""Route for creating a new user."""
|
| 18 |
+
return create_user_in_firestore(user_data.model_dump())
|
| 19 |
+
|
| 20 |
+
@router.get("/{id}")
|
| 21 |
+
def get_user(id: str):
|
| 22 |
+
return get_user_from_firestore(id)
|
| 23 |
+
|
| 24 |
+
@router.put("/{id}")
|
| 25 |
+
def edit_user(id: str, user_data: UpdateUser):
|
| 26 |
+
return update_user_in_firestore(id, user_data.model_dump())
|
| 27 |
+
|
| 28 |
+
@router.post("/login")
|
| 29 |
+
def login(user_data: TokenRequest):
|
| 30 |
+
"""Login route for generating JWT token."""
|
| 31 |
+
return login_for_access_token(user_data.email, user_data.password)
|
| 32 |
+
|
| 33 |
+
@router.delete("/me", dependencies=[Depends(JWTBearer())])
|
| 34 |
+
def delete_user(user_request: DeleteUserRequest, token: str = Depends(JWTBearer())):
|
| 35 |
+
# Decode the token to get the user_id
|
| 36 |
+
user_id = decodeJWT(token)["user_id"]
|
| 37 |
+
|
| 38 |
+
# Call the delete function with the user_id
|
| 39 |
+
return delete_user_profile(user_id, user_request.model_dump())
|
| 40 |
+
|
| 41 |
+
@router.get("/me", dependencies=[Depends(JWTBearer())])
|
| 42 |
+
def get_my_profile(token: str = Depends(JWTBearer())):
|
| 43 |
+
# Decode the JWT token to get the user_id
|
| 44 |
+
user_id = decodeJWT(token)["user_id"]
|
| 45 |
+
|
| 46 |
+
# Fetch the user profile based on the user_id
|
| 47 |
+
return get_user_profile_from_firestore(user_id)
|
| 48 |
+
|
| 49 |
+
@router.put("/me", dependencies=[Depends(JWTBearer())])
|
| 50 |
+
def edit_my_profile(user_data: UpdateProfile = Body(...), token: str = Depends(JWTBearer())):
|
| 51 |
+
# Decode JWT to get the user_id
|
| 52 |
+
user_id = decodeJWT(token)["user_id"]
|
| 53 |
+
|
| 54 |
+
# Update the user profile in Firestore
|
| 55 |
+
updated_user = update_user_profile(user_id, user_data.model_dump())
|
| 56 |
+
|
| 57 |
+
return {
|
| 58 |
+
"isSuccess": True,
|
| 59 |
+
"data": updated_user
|
| 60 |
+
}
|
serviceAccountKey.json
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"type": "service_account",
|
| 3 |
+
"project_id": "news-b7cae",
|
| 4 |
+
"private_key_id": "3393fd91e87ef8353deb8d226159d46c0d314f6a",
|
| 5 |
+
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDE7EL16g7NlpOK\n3Kcb+NixuMg/wwqJaKWZ1ts6iyt3l2Gn/I35it9bA+ocLsgE+JH+mHJdlt0e+/zv\nm40zQ8G432nZaTujq0BLMQH70qVFPxyeUZFCbw2OapNSPOcMBo1DgxG4JHMM74N8\nxUn5AOniP7yd+4ZlMkKk1q7vsO857okYqm4NajBsdV7EzV+XiS0J1ZbGvT2qRcYo\nXyUQwxX4NdxIzzT4wtajsMky8XewZzrOe5/IMRVEQE2ad13s/Lc9hoRKdD40XbuF\nw7uipgRO6UVLDb5+DGFXk9qP7oADjWDg5monZJ/4XLwDuFh/qdQZgn4XrI1abPAe\nRRlvva0XAgMBAAECggEARhbJZnmeNzJm5T/QAra5edgI/hjPgUTL3EuKz/WEzRYG\nXiIX7j+ta9mi09EaxBos7G8aFZGCtmp+BlJZGWv+YWyzYfyAi6qCQcD5scWxqUnj\nR75Ec17PdmccdGLU4YTbdrIJ9n6SrIH7TMdzorreg/anjZtepFoVOlJnBUz2eKl7\n3NyDykBtH++iFp2adwza0ZIpHIUCAp0VBNZjQbRH7WeKU8QS1Kfd1Mt1mzx9gsdR\nKXWgmZ5mD1xMjk0kwIEdyO4jVM+PCHTDeRGSRjtE8yVaIU1j0Rrhe+amEtu7aKHI\n0Tc0/ZDQBYKZMZhMdXniCZz3s8Fl8TPugaDko4ZBIQKBgQDveQ8aYpYft9jt7VXQ\nVG6b0X6/jVrF5zgGV84d20wyNSkrBRYL6UaTxGRccLEh+U1G5uIh27QA+xuliu7X\nVgIxdcwD31CvzHVusjpAXQwTg213dw2TVk1j7c1fBYT80kwlddQbnqq3yNjfg+8u\nA3tYWrBTlVUV0tk1jsTee+g2SQKBgQDSg3Dpqdw3KFJnbCh2eULj8awWCXHvw/EQ\nonTjNdIYUCYA4kiu7I5BMmLaY+NkMCrJ8z8JSoKocv9XwwqtHY3S/7kjTBeYajFD\nCd+IIvg5SlPzgjicbrlSBVqOUCjeFRSGyGExIofBnciqhHd354Ma4vuuOMEGz54X\nnEKi5uVIXwKBgEff186dhF1kurE+qKDsln4h9J7deD8p1MDinbSMW2Q+XGrTDfjp\nPQugyFaOZDvELZN4PKrY3D/nHjcjaegromDh8CfBYOBCx4Q/7gffZX591d8jVmnA\nX138w8UfTPjszXn40X6wsqCSobUETkdLODwejAmqKm1waU0P2rrECcAxAoGAMFlX\n+ZK1rUVph69jq7I2FrxO1dDdhj/uge+OARE/a64czF8samCSW48C/T2r4Drf2Pox\nJCUk1SN0WefF7/S1uhxZnS3AzZS2M7t0x4OglyfnGCp0bhlQHvJz1fO7LyaQTFSB\nXhOcMm/WwrMh7TwS9H3laCJI0xOkL7AH7fox9ukCgYBYGQkfPZUFo5grN+i9Z886\njSqODEhvnafLkiyr2nlSh/ZwL6nV0l9s77DBL9XVbGVCEPvCyn5XYJHwrn6B6JTZ\nOrPTmtJH+xQO4d3+MykoIjHNe4LUKKwGOESzSG0BzIFWrpkBe/2yEvIs/jlL6TLy\n6rQ3t9/+eYwMExTenGZGzQ==\n-----END PRIVATE KEY-----\n",
|
| 6 |
+
"client_email": "firebase-adminsdk-cxdji@news-b7cae.iam.gserviceaccount.com",
|
| 7 |
+
"client_id": "103570192779780992565",
|
| 8 |
+
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
| 9 |
+
"token_uri": "https://oauth2.googleapis.com/token",
|
| 10 |
+
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
| 11 |
+
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-cxdji%40news-b7cae.iam.gserviceaccount.com",
|
| 12 |
+
"universe_domain": "googleapis.com"
|
| 13 |
+
}
|
services/1.txt
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi import HTTPException
|
| 2 |
+
from config import db, auth
|
| 3 |
+
from datetime import datetime, timedelta
|
| 4 |
+
from zoneinfo import ZoneInfo
|
| 5 |
+
import jwt
|
| 6 |
+
|
| 7 |
+
SECRET_KEY = "your_jwt_secret_key"
|
| 8 |
+
|
| 9 |
+
def create_user_in_firestore(user_data):
|
| 10 |
+
try:
|
| 11 |
+
user = auth.create_user(
|
| 12 |
+
email=user_data["email"],
|
| 13 |
+
password=user_data["password"]
|
| 14 |
+
)
|
| 15 |
+
|
| 16 |
+
user_ref = db.collection("users").document(user.uid)
|
| 17 |
+
user_ref.set({
|
| 18 |
+
"uid": user.uid,
|
| 19 |
+
"email": user_data["email"],
|
| 20 |
+
"status": "Active"
|
| 21 |
+
})
|
| 22 |
+
|
| 23 |
+
return {"isSuccess": True, "message": "User created successfully", "uid": user.uid}
|
| 24 |
+
|
| 25 |
+
except Exception as e:
|
| 26 |
+
raise HTTPException(status_code=400, detail=str(e))
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def get_user_from_firestore(user_id: str):
|
| 30 |
+
try:
|
| 31 |
+
user_ref = db.collection("users").document(user_id)
|
| 32 |
+
user_snapshot = user_ref.get()
|
| 33 |
+
|
| 34 |
+
if user_snapshot.exists:
|
| 35 |
+
return {"isSuccess": True, "data": user_snapshot.to_dict()}
|
| 36 |
+
else:
|
| 37 |
+
raise HTTPException(status_code=404, detail="User not found")
|
| 38 |
+
except Exception as e:
|
| 39 |
+
raise HTTPException(status_code=500, detail=str(e))
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
def update_user_in_firestore(user_id: str, update_data):
|
| 43 |
+
try:
|
| 44 |
+
user_ref = db.collection("users").document(user_id)
|
| 45 |
+
user_ref.update(update_data)
|
| 46 |
+
|
| 47 |
+
if 'email' in update_data:
|
| 48 |
+
auth.update_user(user_id, email=update_data['email'])
|
| 49 |
+
if 'password' in update_data:
|
| 50 |
+
auth.update_user(user_id, password=update_data['password'])
|
| 51 |
+
|
| 52 |
+
return {"isSuccess": True, "message": "User updated successfully"}
|
| 53 |
+
except Exception as e:
|
| 54 |
+
raise HTTPException(status_code=400, detail=str(e))
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
def get_temporary_token_service(email: str):
|
| 58 |
+
try:
|
| 59 |
+
# Check if the user exists in Firestore
|
| 60 |
+
users_ref = db.collection("users")
|
| 61 |
+
query = users_ref.where("email", "==", email).stream()
|
| 62 |
+
|
| 63 |
+
user_doc = None
|
| 64 |
+
for doc in query:
|
| 65 |
+
user_doc = doc
|
| 66 |
+
break
|
| 67 |
+
|
| 68 |
+
if not user_doc:
|
| 69 |
+
raise HTTPException(status_code=404, detail="Use a registered email")
|
| 70 |
+
|
| 71 |
+
# Generate a temporary token valid for 300 seconds (5 minutes)
|
| 72 |
+
expiration = datetime.now(ZoneInfo("UTC")) + timedelta(seconds=300)
|
| 73 |
+
payload = {
|
| 74 |
+
"email": email,
|
| 75 |
+
"exp": expiration,
|
| 76 |
+
"uid": user_doc.id
|
| 77 |
+
}
|
| 78 |
+
token = jwt.encode(payload, SECRET_KEY, algorithm="HS256") # Ensure you use PyJWT's jwt
|
| 79 |
+
|
| 80 |
+
return {"isSuccess": True, "token": token}
|
| 81 |
+
|
| 82 |
+
except Exception as e:
|
| 83 |
+
raise HTTPException(status_code=500, detail=str(e))
|
| 84 |
+
|
| 85 |
+
# def get_user_profile_from_token(token: str):
|
| 86 |
+
# try:
|
| 87 |
+
# # Decode the token
|
| 88 |
+
# payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
|
| 89 |
+
# email = payload.get("email")
|
| 90 |
+
|
| 91 |
+
# if not email:
|
| 92 |
+
# raise HTTPException(status_code=401, detail="Invalid token")
|
| 93 |
+
|
| 94 |
+
# # Fetch user details from Firestore
|
| 95 |
+
# users_ref = db.collection("users")
|
| 96 |
+
# query = users_ref.where("email", "==", email).stream()
|
| 97 |
+
|
| 98 |
+
# user_doc = None
|
| 99 |
+
# for doc in query:
|
| 100 |
+
# user_doc = doc
|
| 101 |
+
# break
|
| 102 |
+
|
| 103 |
+
# if not user_doc:
|
| 104 |
+
# raise HTTPException(status_code=404, detail="User not found")
|
| 105 |
+
|
| 106 |
+
# return {"isSuccess": True, "data": user_doc.to_dict()}
|
| 107 |
+
|
| 108 |
+
# except jwt.ExpiredSignatureError:
|
| 109 |
+
# raise HTTPException(status_code=401, detail="Token has expired")
|
| 110 |
+
# except jwt.InvalidTokenError:
|
| 111 |
+
# raise HTTPException(status_code=401, detail="Invalid token")
|
| 112 |
+
# except Exception as e:
|
| 113 |
+
# raise HTTPException(status_code=500, detail=str(e))
|
| 114 |
+
|
| 115 |
+
from fastapi import APIRouter, HTTPException, Header, Query
|
| 116 |
+
from pydantic import EmailStr
|
| 117 |
+
from services.users_service import create_user_in_firestore, get_user_from_firestore, update_user_in_firestore, get_temporary_token_service
|
| 118 |
+
from models.user_model import CreateUser, UpdateUser, TokenRequest
|
| 119 |
+
|
| 120 |
+
router = APIRouter(
|
| 121 |
+
prefix="/api/v1/users",
|
| 122 |
+
tags=["Users"]
|
| 123 |
+
)
|
| 124 |
+
|
| 125 |
+
@router.post("/")
|
| 126 |
+
def create_user(user_data: CreateUser):
|
| 127 |
+
return create_user_in_firestore(user_data.model_dump())
|
| 128 |
+
|
| 129 |
+
@router.get("/{id}")
|
| 130 |
+
def get_user(id: str):
|
| 131 |
+
return get_user_from_firestore(id)
|
| 132 |
+
|
| 133 |
+
@router.put("/{id}")
|
| 134 |
+
def edit_user(id: str, user_data: UpdateUser):
|
| 135 |
+
return update_user_in_firestore(id, user_data.model_dump())
|
| 136 |
+
|
| 137 |
+
@router.post("/token")
|
| 138 |
+
def get_temporary_token(token_request: TokenRequest):
|
| 139 |
+
return get_temporary_token_service(token_request.email)
|
| 140 |
+
|
| 141 |
+
# @router.post("/me")
|
| 142 |
+
# def get_my_profile(token_request: TokenRequest1):
|
| 143 |
+
# token = token_request.token
|
| 144 |
+
# return get_user_profile_from_token(token)
|
services/__pycache__/users_service.cpython-310.pyc
ADDED
|
Binary file (3.88 kB). View file
|
|
|
services/users_service.py
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi import HTTPException
|
| 2 |
+
from config import db, auth
|
| 3 |
+
from datetime import datetime, timedelta
|
| 4 |
+
from zoneinfo import ZoneInfo
|
| 5 |
+
from jose import JWTError, jwt
|
| 6 |
+
from firebase_admin import auth, firestore
|
| 7 |
+
from auth.auth_handler import signJWT
|
| 8 |
+
|
| 9 |
+
SECRET_KEY = "your-secret-key"
|
| 10 |
+
ALGORITHM = "HS256"
|
| 11 |
+
ACCESS_TOKEN_EXPIRE_MINUTES = 30
|
| 12 |
+
|
| 13 |
+
def get_user_from_firestore(user_id: str):
|
| 14 |
+
try:
|
| 15 |
+
user_ref = db.collection("users").document(user_id)
|
| 16 |
+
user_snapshot = user_ref.get()
|
| 17 |
+
|
| 18 |
+
if user_snapshot.exists:
|
| 19 |
+
return {"isSuccess": True, "data": user_snapshot.to_dict()}
|
| 20 |
+
else:
|
| 21 |
+
raise HTTPException(status_code=404, detail="User not found")
|
| 22 |
+
except Exception as e:
|
| 23 |
+
raise HTTPException(status_code=500, detail=str(e))
|
| 24 |
+
|
| 25 |
+
def update_user_in_firestore(user_id: str, update_data):
|
| 26 |
+
try:
|
| 27 |
+
user_ref = db.collection("users").document(user_id)
|
| 28 |
+
user_ref.update(update_data)
|
| 29 |
+
|
| 30 |
+
if 'email' in update_data:
|
| 31 |
+
auth.update_user(user_id, email=update_data['email'])
|
| 32 |
+
if 'password' in update_data:
|
| 33 |
+
auth.update_user(user_id, password=update_data['password'])
|
| 34 |
+
|
| 35 |
+
return {"isSuccess": True, "message": "User updated successfully"}
|
| 36 |
+
except Exception as e:
|
| 37 |
+
raise HTTPException(status_code=400, detail=str(e))
|
| 38 |
+
|
| 39 |
+
def create_user_in_firestore(user_data):
|
| 40 |
+
"""Create user in Firebase Auth and Firestore."""
|
| 41 |
+
try:
|
| 42 |
+
user = auth.create_user(
|
| 43 |
+
email=user_data["email"],
|
| 44 |
+
password=user_data["password"]
|
| 45 |
+
)
|
| 46 |
+
|
| 47 |
+
user_ref = db.collection("users").document(user.uid)
|
| 48 |
+
user_ref.set({
|
| 49 |
+
"uid": user.uid,
|
| 50 |
+
"email": user_data["email"],
|
| 51 |
+
"status": "Active"
|
| 52 |
+
})
|
| 53 |
+
|
| 54 |
+
return {"isSuccess": True, "message": "User created successfully", "uid": user.uid}
|
| 55 |
+
|
| 56 |
+
except Exception as e:
|
| 57 |
+
raise HTTPException(status_code=400, detail=str(e))
|
| 58 |
+
|
| 59 |
+
def authenticate_user(email: str, password: str):
|
| 60 |
+
"""Authenticate Firebase user."""
|
| 61 |
+
try:
|
| 62 |
+
# In Firebase, password verification is handled on the client side.
|
| 63 |
+
user = auth.get_user_by_email(email)
|
| 64 |
+
return user
|
| 65 |
+
except Exception as e:
|
| 66 |
+
raise HTTPException(status_code=400, detail="Invalid credentials")
|
| 67 |
+
|
| 68 |
+
def login_for_access_token(email: str, password: str):
|
| 69 |
+
"""Verify user and return JWT token."""
|
| 70 |
+
user = authenticate_user(email, password)
|
| 71 |
+
if not user:
|
| 72 |
+
raise HTTPException(status_code=400, detail="Incorrect email or password")
|
| 73 |
+
|
| 74 |
+
# Generate JWT token for the user
|
| 75 |
+
return signJWT(user.uid)
|
| 76 |
+
|
| 77 |
+
def delete_user_profile(user_id: str, user_request: dict):
|
| 78 |
+
try:
|
| 79 |
+
# Retrieve the user's Firebase Auth record
|
| 80 |
+
user_record = auth.get_user(user_id)
|
| 81 |
+
if not user_record:
|
| 82 |
+
raise HTTPException(status_code=404, detail="User not found")
|
| 83 |
+
|
| 84 |
+
# Deleting the user from Firebase Auth
|
| 85 |
+
auth.delete_user(user_id)
|
| 86 |
+
|
| 87 |
+
# Deleting the user from Firestore
|
| 88 |
+
user_ref = db.collection("users").document(user_id)
|
| 89 |
+
user_snapshot = user_ref.get()
|
| 90 |
+
|
| 91 |
+
if user_snapshot.exists:
|
| 92 |
+
user_ref.delete()
|
| 93 |
+
return {"isSuccess": True, "message": "User deleted successfully"}
|
| 94 |
+
else:
|
| 95 |
+
raise HTTPException(status_code=404, detail="User not found in Firestore")
|
| 96 |
+
|
| 97 |
+
except Exception as e:
|
| 98 |
+
raise HTTPException(status_code=400, detail=str(e))
|
| 99 |
+
|
| 100 |
+
def get_user_profile_from_firestore(user_id: str):
|
| 101 |
+
try:
|
| 102 |
+
# Get the user's profile from Firestore
|
| 103 |
+
user_ref = db.collection("users").document(user_id)
|
| 104 |
+
user_snapshot = user_ref.get()
|
| 105 |
+
|
| 106 |
+
if user_snapshot.exists:
|
| 107 |
+
user_data = user_snapshot.to_dict()
|
| 108 |
+
return {
|
| 109 |
+
"isSuccess": True,
|
| 110 |
+
"data": {
|
| 111 |
+
"id": user_data.get("uid"),
|
| 112 |
+
"name": user_data.get("name"),
|
| 113 |
+
"surname": user_data.get("surname"),
|
| 114 |
+
"phone": user_data.get("phone"),
|
| 115 |
+
"email": user_data.get("email"),
|
| 116 |
+
"role": user_data.get("role"),
|
| 117 |
+
"status": user_data.get("status")
|
| 118 |
+
}
|
| 119 |
+
}
|
| 120 |
+
else:
|
| 121 |
+
raise HTTPException(status_code=404, detail="User profile not found in Firestore")
|
| 122 |
+
|
| 123 |
+
except Exception as e:
|
| 124 |
+
raise HTTPException(status_code=500, detail=str(e))
|
| 125 |
+
|
| 126 |
+
def update_user_profile(user_id: str, update_data: dict):
|
| 127 |
+
try:
|
| 128 |
+
# Access Firestore document for the user
|
| 129 |
+
user_ref = db.collection("users").document(user_id)
|
| 130 |
+
user_snapshot = user_ref.get()
|
| 131 |
+
|
| 132 |
+
# Check if user exists
|
| 133 |
+
if not user_snapshot.exists:
|
| 134 |
+
raise HTTPException(status_code=404, detail="User not found")
|
| 135 |
+
|
| 136 |
+
# Update the user profile with provided data
|
| 137 |
+
user_ref.update(update_data)
|
| 138 |
+
|
| 139 |
+
# Fetch updated user data from Firestore
|
| 140 |
+
updated_user = user_ref.get().to_dict()
|
| 141 |
+
|
| 142 |
+
return updated_user
|
| 143 |
+
except Exception as e:
|
| 144 |
+
raise HTTPException(status_code=500, detail=str(e))
|