Craft proper response for user registration
This commit is contained in:
		
							parent
							
								
									8d98bbd9f6
								
							
						
					
					
						commit
						d8e90f74fc
					
				
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -1,3 +1,3 @@
 | 
				
			|||||||
constants.py
 | 
					constants.py
 | 
				
			||||||
assets
 | 
					assets
 | 
				
			||||||
/**/__pycache__
 | 
					!assets/responses.org
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,7 @@
 | 
				
			|||||||
from secrets import randbits
 | 
					 | 
				
			||||||
from twilio.rest import Client
 | 
					from twilio.rest import Client
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from constants import ACCOUNT_ID, SMS_SENDER, TOKEN
 | 
					from constants import ACCOUNT_ID, SMS_SENDER, TOKEN
 | 
				
			||||||
from database.crud import save_otp
 | 
					from database.crud import fetch_otp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def create_twilio_client(account_sid, auth_token):
 | 
					def create_twilio_client(account_sid, auth_token):
 | 
				
			||||||
@ -10,9 +9,8 @@ def create_twilio_client(account_sid, auth_token):
 | 
				
			|||||||
    return client
 | 
					    return client
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def send_otp(receiver):
 | 
					def send_otp(data, db):
 | 
				
			||||||
    client = create_twilio_client(account_sid=ACCOUNT_ID, auth_token=TOKEN)
 | 
					    client = create_twilio_client(account_sid=ACCOUNT_ID, auth_token=TOKEN)
 | 
				
			||||||
    code = randbits(k=16)
 | 
					    code = fetch_otp(access_key=data.access_key, db=db)
 | 
				
			||||||
    message = "Your OTP code is {0}".format(code)
 | 
					    message = "Your OTP code is {0}".format(code)
 | 
				
			||||||
    client.messages.create(to=receiver, from_=SMS_SENDER, body=message)
 | 
					    client.messages.create(to=data.mobile, from_=SMS_SENDER, body=message)
 | 
				
			||||||
    save_otp(receiver, code)
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -1,32 +1,28 @@
 | 
				
			|||||||
from fastapi import APIRouter, Depends, HTTPException, Response
 | 
					from fastapi import APIRouter, Depends, HTTPException
 | 
				
			||||||
from sqlalchemy.orm import Session
 | 
					from sqlalchemy.orm import Session
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from app.schemas import *
 | 
					 | 
				
			||||||
from app.external_services import send_otp
 | 
					from app.external_services import send_otp
 | 
				
			||||||
 | 
					from app.schemas import *
 | 
				
			||||||
from database.crud import get_db, insert_data, verify_otp
 | 
					from database.crud import get_db, insert_data, verify_otp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
router = APIRouter()
 | 
					router = APIRouter()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@router.post("/register")
 | 
					@router.post("/register", response_model=UserCreateResponse)
 | 
				
			||||||
def create_user(request: UserCreate, db: Session = Depends(get_db)):
 | 
					def create_user(data: UserCreate, db: Session = Depends(get_db)):
 | 
				
			||||||
    insert_data(model="Users", data=request, db=db)
 | 
					    user = insert_data(model="Users", data=data, db=db)
 | 
				
			||||||
    send_otp(receiver=request.mobile)
 | 
					    send_otp(data=user, db=db)
 | 
				
			||||||
    return {"message": "User created, pending OTP verification"}
 | 
					    return user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# FIXME Use OAuth2 for verification
 | 
					# FIXME Use OAuth2 for verification
 | 
				
			||||||
@router.post("/login")
 | 
					@router.post("/login", response_model=UserLoginResponse)
 | 
				
			||||||
async def log_in(request: UserLogin, response: Response, db: Session = Depends(get_db)):
 | 
					def log_in(request: UserLogin, db: Session = Depends(get_db)):
 | 
				
			||||||
    return {"message": "Logged in successfully"}
 | 
					    pass
 | 
				
			||||||
    # response.status_code = status.HTTP_400_BAD_REQUEST
 | 
					 | 
				
			||||||
    # return {"message": "The email/password combination is not correct"}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@router.post("/otpVerification")
 | 
					@router.post("/otpVerification", response_model=OTPVerifyResponse)
 | 
				
			||||||
async def validate_otp(
 | 
					def validate_otp(request: OTPVerify, db: Session = Depends(get_db)):
 | 
				
			||||||
    request: OTPVerify, response: Response, db: Session = Depends(get_db)
 | 
					 | 
				
			||||||
):
 | 
					 | 
				
			||||||
    if verify_otp(data=request, db=db):
 | 
					    if verify_otp(data=request, db=db):
 | 
				
			||||||
        return {"message": "The OTP has been verified successfully"}
 | 
					        return {"message": "The OTP has been verified successfully"}
 | 
				
			||||||
    raise HTTPException(status_code=400, detail="The OTP is not correct")
 | 
					    raise HTTPException(status_code=400, detail="The OTP is not correct")
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,9 @@
 | 
				
			|||||||
 | 
					from datetime import datetime, timedelta
 | 
				
			||||||
 | 
					from secrets import randbits, token_hex
 | 
				
			||||||
 | 
					from typing import Optional
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from fastapi import Query
 | 
					from fastapi import Query
 | 
				
			||||||
from pydantic import BaseModel, EmailStr
 | 
					from pydantic import BaseModel, EmailStr
 | 
				
			||||||
from typing import Optional
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class UserBase(BaseModel):
 | 
					class UserBase(BaseModel):
 | 
				
			||||||
@ -18,6 +21,29 @@ class UserCreate(UserBase):
 | 
				
			|||||||
    user_image: Optional[str] = None
 | 
					    user_image: Optional[str] = None
 | 
				
			||||||
    device_type: int = Query(None, ge=1, le=2)
 | 
					    device_type: int = Query(None, ge=1, le=2)
 | 
				
			||||||
    city_id: int
 | 
					    city_id: int
 | 
				
			||||||
 | 
					    access_key: str = token_hex()
 | 
				
			||||||
 | 
					    otp: int = randbits(16)
 | 
				
			||||||
 | 
					    otp_valid_time: datetime = datetime.now() + timedelta(minutes=10)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class Config:
 | 
				
			||||||
 | 
					        orm_mode = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class UserCreateResponse(UserBase):
 | 
				
			||||||
 | 
					    id: int
 | 
				
			||||||
 | 
					    full_name: str
 | 
				
			||||||
 | 
					    password: str
 | 
				
			||||||
 | 
					    gender: int = Query(None, ge=1, le=3)
 | 
				
			||||||
 | 
					    mobile: str = Query(None, min_length=8, max_length=13)
 | 
				
			||||||
 | 
					    user_image: Optional[str] = None
 | 
				
			||||||
 | 
					    device_type: int = Query(None, ge=1, le=2)
 | 
				
			||||||
 | 
					    access_key: str
 | 
				
			||||||
 | 
					    otp: int
 | 
				
			||||||
 | 
					    otp_valid_time: datetime
 | 
				
			||||||
 | 
					    status: int = Query(None, ge=0, le=1)
 | 
				
			||||||
 | 
					    admin_status: int = Query(None, ge=0, le=1)
 | 
				
			||||||
 | 
					    created: datetime
 | 
				
			||||||
 | 
					    updated: datetime = Query(None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class Config:
 | 
					    class Config:
 | 
				
			||||||
        orm_mode = True
 | 
					        orm_mode = True
 | 
				
			||||||
@ -30,6 +56,13 @@ class UserLogin(UserBase):
 | 
				
			|||||||
        orm_mode = True
 | 
					        orm_mode = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class UserLoginResponse(UserBase):
 | 
				
			||||||
 | 
					    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class Config:
 | 
				
			||||||
 | 
					        orm_mode = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SocialLogin(UserBase):
 | 
					class SocialLogin(UserBase):
 | 
				
			||||||
    type: int = Query(None, ge=1, le=2)
 | 
					    type: int = Query(None, ge=1, le=2)
 | 
				
			||||||
    social_id: str
 | 
					    social_id: str
 | 
				
			||||||
@ -41,21 +74,21 @@ class SocialLogin(UserBase):
 | 
				
			|||||||
        orm_mode = True
 | 
					        orm_mode = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CreateResponse(UserBase):
 | 
					class OTPVerify(BaseModel):
 | 
				
			||||||
    id: int
 | 
					    access_key: str
 | 
				
			||||||
    full_name: str
 | 
					    otp: int
 | 
				
			||||||
    password: str
 | 
					
 | 
				
			||||||
    gender: int = Query(None, ge=1, le=3)
 | 
					    class Config:
 | 
				
			||||||
    mobile: str = Query(None, min_length=8, max_length=13)
 | 
					        orm_mode = True
 | 
				
			||||||
    user_image: Optional[str] = None
 | 
					
 | 
				
			||||||
    device_type: int = Query(None, ge=1, le=2)
 | 
					
 | 
				
			||||||
    otp: int = Query(None, ge=6, le=6)
 | 
					class OTPVerifyResponse(BaseModel):
 | 
				
			||||||
 | 
					    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class Config:
 | 
					    class Config:
 | 
				
			||||||
        orm_mode = True
 | 
					        orm_mode = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class OTPVerify(BaseModel):
 | 
					 | 
				
			||||||
    access_key: str
 | 
					    access_key: str
 | 
				
			||||||
    otp: int = Query(None, ge=6, le=6)
 | 
					    otp: int = Query(None, ge=6, le=6)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,7 @@ from sqlalchemy import create_engine
 | 
				
			|||||||
from sqlalchemy.ext.declarative import declarative_base
 | 
					from sqlalchemy.ext.declarative import declarative_base
 | 
				
			||||||
from sqlalchemy.orm import sessionmaker
 | 
					from sqlalchemy.orm import sessionmaker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from constants import DB
 | 
					from constants import TESTING_DB as DB
 | 
				
			||||||
 | 
					
 | 
				
			||||||
engine = create_engine(DB, connect_args={"check_same_thread": False})
 | 
					engine = create_engine(DB, connect_args={"check_same_thread": False})
 | 
				
			||||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
 | 
					SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
 | 
				
			||||||
 | 
				
			|||||||
@ -24,12 +24,13 @@ def insert_data(model, data, db):
 | 
				
			|||||||
    db.add(item)
 | 
					    db.add(item)
 | 
				
			||||||
    db.commit()
 | 
					    db.commit()
 | 
				
			||||||
    db.refresh(item)
 | 
					    db.refresh(item)
 | 
				
			||||||
 | 
					    return item
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# FIXME db.id has to be replaced with the table's UID
 | 
					# FIXME db.id has to be replaced with the table's UID
 | 
				
			||||||
def delete_data(schema, data, db):
 | 
					def delete_data(model, data, db):
 | 
				
			||||||
    model = schema.replace('"', "")
 | 
					    item = instantiate_model(model=model, data=data)
 | 
				
			||||||
    result = db.query(model).filter(model.email == data.email).delete()
 | 
					    result = db.query(item).filter(item.email == data.email).delete()
 | 
				
			||||||
    return result
 | 
					    return result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -38,22 +39,14 @@ def fetch_user(data, db):
 | 
				
			|||||||
    return result
 | 
					    return result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def fetch_otp(data: OTPVerify, db):
 | 
					def fetch_otp(access_key, db):
 | 
				
			||||||
    result = db.query(Users).filter(Users.access_key == data.access_key).first()
 | 
					    result = db.query(Users).filter(Users.access_key == access_key).first()
 | 
				
			||||||
    return result
 | 
					    return result.otp
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def save_otp(data: OTPVerify, db):
 | 
					 | 
				
			||||||
    db.query(Users).filter(Users.access_key == data.access_key).update(
 | 
					 | 
				
			||||||
        {Users.otp: data.otp}
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    db.commit()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def activate_account(data: OTPVerify, db):
 | 
					def activate_account(data: OTPVerify, db):
 | 
				
			||||||
    timestamp = datetime.now() + timedelta(minutes=10)
 | 
					 | 
				
			||||||
    db.query(Users).filter(Users.access_key == data.access_key).update(
 | 
					    db.query(Users).filter(Users.access_key == data.access_key).update(
 | 
				
			||||||
        {Users.otp_valid_time: timestamp, Users.status: 1}
 | 
					        {Users.status: 1}
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    db.commit()
 | 
					    db.commit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,3 @@
 | 
				
			|||||||
from secrets import token_hex
 | 
					 | 
				
			||||||
from sqlalchemy import Column, DateTime, Enum, ForeignKey, Integer, String, Text, text
 | 
					from sqlalchemy import Column, DateTime, Enum, ForeignKey, Integer, String, Text, text
 | 
				
			||||||
from sqlalchemy.sql import func
 | 
					from sqlalchemy.sql import func
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -21,7 +20,7 @@ class Users(Base):
 | 
				
			|||||||
    user_type = Column(Integer)
 | 
					    user_type = Column(Integer)
 | 
				
			||||||
    otp = Column(String(255))
 | 
					    otp = Column(String(255))
 | 
				
			||||||
    otp_valid_time = Column(DateTime)
 | 
					    otp_valid_time = Column(DateTime)
 | 
				
			||||||
    access_key = Column(Text, unique=True, default=token_hex)
 | 
					    access_key = Column(Text, unique=True)
 | 
				
			||||||
    lang_type = Column(Integer)
 | 
					    lang_type = Column(Integer)
 | 
				
			||||||
    badge = Column(Integer, server_default=text("0"))
 | 
					    badge = Column(Integer, server_default=text("0"))
 | 
				
			||||||
    status = Column(Integer, server_default=text("0"))
 | 
					    status = Column(Integer, server_default=text("0"))
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user