|
@@ -1,27 +1,28 @@
|
|
|
-from re import U
|
|
|
import uuid
|
|
|
import os
|
|
|
+from datetime import datetime, timedelta
|
|
|
from typing import Optional
|
|
|
-from fastapi import FastAPI, Form, Depends, HTTPException, status
|
|
|
+from fastapi import FastAPI, Depends, HTTPException, status
|
|
|
from fastapi.templating import Jinja2Templates
|
|
|
+# from fastapi_jwt_auth import AuthJWT
|
|
|
from dotenv import load_dotenv
|
|
|
from os.path import join, dirname
|
|
|
from linepay import LinePayApi
|
|
|
-from pydantic.networks import EmailStr
|
|
|
from starlette.responses import HTMLResponse
|
|
|
from sqlalchemy.orm import Session
|
|
|
from fastapi.encoders import jsonable_encoder
|
|
|
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
|
|
|
|
|
|
from sql.database import get_db_session
|
|
|
-from sql.crud import create_order, get_user
|
|
|
-from sql.models import order_info_linepay
|
|
|
-from sql.schemas import order_info_linepay as orderSechmas
|
|
|
-from sql.schemas import User
|
|
|
+from sql.crud import create_payment, get_user
|
|
|
+from sql.models import Payment, User
|
|
|
+from sql.schemas import PaymentSchema
|
|
|
+from sql.schemas import UserSchema
|
|
|
|
|
|
from jose import JWTError, jwt
|
|
|
from passlib.context import CryptContext
|
|
|
|
|
|
+
|
|
|
# TBD load_env
|
|
|
SECRET_KEY = "df2f77bd544240801a048bd4293afd8eeb7fff3cb7050e42c791db4b83ebadcd"
|
|
|
ALGORITHM = "HS256"
|
|
@@ -36,12 +37,46 @@ def verify_password(plain_password, hashed_password):
|
|
|
def get_password_hash(password):
|
|
|
return pwd_context.hash(password)
|
|
|
|
|
|
-
|
|
|
+def authenticate_user(db_sesion: Session, username: str, password: str):
|
|
|
+ user = get_user(db_sesion, username)
|
|
|
+ if not user:
|
|
|
+ return False
|
|
|
+ if not verify_password(password, user.password):
|
|
|
+ return False
|
|
|
+ return user
|
|
|
+
|
|
|
+def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
|
|
|
+ to_encode = data.copy()
|
|
|
+ if expires_delta:
|
|
|
+ expire = datetime.utcnow() + expires_delta
|
|
|
+ else:
|
|
|
+ expire = datetime.utcnow() + timedelta(minutes=15)
|
|
|
+ to_encode.update({"exp": expire})
|
|
|
+ encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
|
|
|
+ return encoded_jwt
|
|
|
+
|
|
|
+def get_current_user(db_sesion: Session, token: str = Depends(oauth2_scheme)):
|
|
|
+ credentials_exception = HTTPException(
|
|
|
+ status_code=status.HTTP_401_UNAUTHORIZED,
|
|
|
+ detail="Could not validate credentials",
|
|
|
+ headers={"WWW-Authenticate": "Bearer"},
|
|
|
+ )
|
|
|
+ try:
|
|
|
+ payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
|
|
|
+ username: str = payload.get("sub")
|
|
|
+ if username is None:
|
|
|
+ raise credentials_exception
|
|
|
+ except JWTError:
|
|
|
+ raise credentials_exception
|
|
|
+ user = get_user(db_sesion, username=username)
|
|
|
+ if user is None:
|
|
|
+ raise credentials_exception
|
|
|
+ return user
|
|
|
|
|
|
|
|
|
# dotenv
|
|
|
-dotenv_path = join(dirname(__file__),'./env/.env')
|
|
|
-# dotenv_path = join(dirname(__file__),'./env/test.env') ## sandbox
|
|
|
+# dotenv_path = join(dirname(__file__),'./env/.env')
|
|
|
+dotenv_path = join(dirname(__file__),'./env/test.env') ## sandbox
|
|
|
load_dotenv(dotenv_path)
|
|
|
|
|
|
# logger (TBD)
|
|
@@ -53,8 +88,8 @@ templates = Jinja2Templates(directory="templates")
|
|
|
LINE_PAY_CHANNEL_ID = os.environ.get("LINE_PAY_CHANNEL_ID")
|
|
|
LINE_PAY_CHANNEL_SECRET = os.environ.get("LINE_PAY_CHANNEL_SECRET")
|
|
|
LINE_PAY_REQEST_BASE_URL = "https://{}".format(os.environ.get("HOST_NAME"))
|
|
|
-line = LinePayApi(LINE_PAY_CHANNEL_ID, LINE_PAY_CHANNEL_SECRET, is_sandbox=False)
|
|
|
-# line = LinePayApi(LINE_PAY_CHANNEL_ID, LINE_PAY_CHANNEL_SECRET, is_sandbox=True)
|
|
|
+# line = LinePayApi(LINE_PAY_CHANNEL_ID, LINE_PAY_CHANNEL_SECRET, is_sandbox=False)
|
|
|
+line = LinePayApi(LINE_PAY_CHANNEL_ID, LINE_PAY_CHANNEL_SECRET, is_sandbox=True)
|
|
|
|
|
|
# CACHE
|
|
|
CACHE = {}
|
|
@@ -63,27 +98,45 @@ CACHE = {}
|
|
|
app = FastAPI()
|
|
|
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
|
|
|
|
|
|
+
|
|
|
@app.get('/')
|
|
|
-def hello(token: str = Depends(oauth2_scheme)):
|
|
|
+def hello():
|
|
|
+ return templates.TemplateResponse("login.html",{"request": {}})
|
|
|
+
|
|
|
+
|
|
|
+@app.post('/')
|
|
|
+def hello(form_data: OAuth2PasswordRequestForm = Depends(), db_sesion: Session = Depends(get_db_session)):
|
|
|
+ user = authenticate_user(db_sesion, form_data.username, form_data.password)
|
|
|
+ if not user:
|
|
|
+ raise HTTPException(
|
|
|
+ status_code=status.HTTP_401_UNAUTHORIZED,
|
|
|
+ detail="Incorrect username or password",
|
|
|
+ headers={"WWW-Authenticate": "Bearer"},
|
|
|
+ )
|
|
|
+ access_token_expires = timedelta(days=ACCESS_TOKEN_EXPIRE_DAYS)
|
|
|
+ access_token = create_access_token(
|
|
|
+ data={"sub": user.username}, expires_delta=access_token_expires
|
|
|
+ )
|
|
|
index = {}
|
|
|
index["product"] = "早鳥方案"
|
|
|
index["amount"] = 1200
|
|
|
index["url"] = "/request"
|
|
|
+ index["name"] = user.username
|
|
|
# return {"product" : ,"amount" : 1200}
|
|
|
- return templates.TemplateResponse("index.html", {"request":index})
|
|
|
+ # return templates.TemplateResponse("index.html", {"request":index, "access_token": access_token, "token_type": "bearer"})
|
|
|
+ return {"access_token": access_token, "token_type": "bearer"}
|
|
|
|
|
|
## Request
|
|
|
@app.post('/request', response_class=HTMLResponse)
|
|
|
-async def pay_request(email: EmailStr= Form(...), phone: str= Form(...),full_name: str= Form(...)):
|
|
|
+async def pay_request(token: str = Depends(oauth2_scheme), db_sesion: Session = Depends(get_db_session)):
|
|
|
+ user = get_current_user(db_sesion, token)
|
|
|
order_id = str(uuid.uuid4())
|
|
|
amount = 1200
|
|
|
currency = "TWD"
|
|
|
- CACHE["email"] = email
|
|
|
- CACHE["phone"] = phone
|
|
|
- CACHE["full_name"] = full_name
|
|
|
CACHE["orderid"] = order_id
|
|
|
CACHE["amount"] = amount
|
|
|
CACHE["currency"] = currency
|
|
|
+ CACHE["userid"] = user.id
|
|
|
request_options ={
|
|
|
"amount" : amount,
|
|
|
"currency" : currency,
|
|
@@ -115,9 +168,7 @@ async def pay_request(email: EmailStr= Form(...), phone: str= Form(...),full_nam
|
|
|
response["transaction_id"] = transaction_id
|
|
|
response["paymentStatusCheckReturnCode"] = check_result.get("returnCode", None)
|
|
|
response["paymentStatusCheckReturnMessage"] = check_result.get("returnMessage", None)
|
|
|
- response["email"] = email
|
|
|
- response["phone"] = phone
|
|
|
- response["full_name"] = full_name
|
|
|
+ response["full_name"] = user.username
|
|
|
return templates.TemplateResponse("request.html", {"request":response})
|
|
|
# return response
|
|
|
|
|
@@ -135,11 +186,12 @@ async def pay_confirm(transactionId: int, orderId: Optional[str] = None, db_sesi
|
|
|
response["payment_details"] = payment_details
|
|
|
if(response["paymentStatusCheckReturnCode"] == '0123'):
|
|
|
orderin = {}
|
|
|
- orderin["orderid"] = CACHE["orderid"]
|
|
|
- orderin["email"] = CACHE["email"]
|
|
|
- orderin["phone"] = CACHE["phone"]
|
|
|
- orderin["full_name"] = CACHE["full_name"]
|
|
|
- create_order(db_sesion, order_in= orderin)
|
|
|
+ orderin["OrderId"] = CACHE["orderid"]
|
|
|
+ orderin["UserId"] = CACHE["userid"]
|
|
|
+ orderin["TransactionId"] = CACHE["transaction_id"]
|
|
|
+ orderin["Source"] = "linepay"
|
|
|
+ orderin["UpdateTime"] = datetime.now()
|
|
|
+ create_payment(db_sesion, order_in= orderin)
|
|
|
return templates.TemplateResponse("confirm.html", {"request":response})
|
|
|
# return {"transactionId" : str(transactionId), "orderId" : orderId}
|
|
|
## Capture
|