Craft proper response for user registration
This commit is contained in:
parent
8d98bbd9f6
commit
d8e90f74fc
|
@ -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…
Reference in New Issue