Craft proper response for user registration

This commit is contained in:
coolneng 2020-09-22 13:59:29 +02:00
parent 8d98bbd9f6
commit d8e90f74fc
Signed by: coolneng
GPG Key ID: 9893DA236405AF57
7 changed files with 71 additions and 52 deletions

2
.gitignore vendored
View File

@ -1,3 +1,3 @@
constants.py constants.py
assets assets
/**/__pycache__ !assets/responses.org

View File

@ -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)

View File

@ -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")

View File

@ -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)

View File

@ -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)

View File

@ -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()

View File

@ -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"))