|
@@ -1,9 +1,9 @@
|
|
|
-from fastapi import APIRouter, Form, Depends, HTTPException
|
|
|
-from fastapi.security import OAuth2PasswordRequestForm
|
|
|
+from fastapi import APIRouter, Form, Depends, HTTPException, Body
|
|
|
+from fastapi.security import OAuth2PasswordRequestForm, OAuth2PasswordBearer
|
|
|
from app.models.models import User
|
|
|
from app.api import deps
|
|
|
from sqlalchemy.orm import Session
|
|
|
-from typing import Any, Dict
|
|
|
+from typing import Any, Dict, Optional
|
|
|
import secrets
|
|
|
from fastapi_login.exceptions import InvalidCredentialsException
|
|
|
from fastapi_login import LoginManager
|
|
@@ -15,6 +15,13 @@ import emails
|
|
|
from emails.template import JinjaTemplate
|
|
|
import logging
|
|
|
import bcrypt
|
|
|
+import smtplib
|
|
|
+from email.mime.text import MIMEText
|
|
|
+from google.oauth2 import id_token
|
|
|
+from google.auth.transport import requests
|
|
|
+from fastapi.openapi.models import OAuthFlows as OAuthFlowsModel
|
|
|
+from fastapi.security.utils import get_authorization_scheme_param
|
|
|
+
|
|
|
|
|
|
|
|
|
users = APIRouter()
|
|
@@ -30,7 +37,7 @@ async def query_user(user_id: str):
|
|
|
:param user_id: E-Mail of the user
|
|
|
:return: None or the user object
|
|
|
"""
|
|
|
- result = await User.filter(email=user_id).first()
|
|
|
+ result = User.filter(email=user_id).first()
|
|
|
if not result:
|
|
|
print('[]')
|
|
|
return []
|
|
@@ -74,6 +81,42 @@ async def login(data: OAuth2PasswordRequestForm = Depends()):
|
|
|
else:
|
|
|
return {"message": "Invalid username or password"}
|
|
|
|
|
|
+oauth2_scheme = OAuth2PasswordBearer(tokenUrl="https://oauth2.googleapis.com/token")
|
|
|
+
|
|
|
+CLIENT_ID = settings.CLIENT_ID
|
|
|
+@users.post("/login/google/access-token")
|
|
|
+async def login(db: Session = Depends(deps.get_db), data: OAuth2PasswordRequestForm = Depends(), add_time_code: Optional[str] = None
|
|
|
+ ) -> Any:
|
|
|
+ """
|
|
|
+ OAuth2 compatible token login, get an access token for future requests
|
|
|
+ """
|
|
|
+ user = await User.filter(username=data.username).first()
|
|
|
+ if not user:
|
|
|
+ u = await User.create(username=data.username, password=data.password)
|
|
|
+
|
|
|
+ access_token = manager.create_access_token(
|
|
|
+ data={'sub': data.username}
|
|
|
+ )
|
|
|
+ return_msg = {
|
|
|
+ "access_token": access_token,
|
|
|
+ "token_type": "bearer",
|
|
|
+ }
|
|
|
+ return return_msg
|
|
|
+ # if add_time_code:
|
|
|
+ # available_ser_no = crud.serial_number.available(db, ser_no=add_time_code)
|
|
|
+ # print(available_ser_no)
|
|
|
+ # if available_ser_no:
|
|
|
+ # user_in = schemas.UserUpdate(available_time=user.available_time + available_ser_no.time)
|
|
|
+ # crud.user.update(db, db_obj=user, obj_in=user_in)
|
|
|
+ #
|
|
|
+ # ser_no_in = schemas.SerialNumberUpdate(code=available_ser_no.code, is_used=True,
|
|
|
+ # used_datetime=str(datetime.now()), owner_id=user.id)
|
|
|
+ # crud.serial_number.update(db, db_obj=available_ser_no, obj_in=ser_no_in)
|
|
|
+ # print(available_ser_no.time, type(available_ser_no.time))
|
|
|
+ # return_msg['time_added'] = available_ser_no.time
|
|
|
+ # else:
|
|
|
+ # return_msg['time_added'] = -1
|
|
|
+ # return return_msg
|
|
|
|
|
|
@users.post("/logout")
|
|
|
async def logout():
|
|
@@ -94,7 +137,10 @@ async def add(username: str = Form(default=''), password: str = Form(default='')
|
|
|
hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
|
|
|
u = await User.create(username=username, password=hashed_password, email=email)
|
|
|
if u:
|
|
|
- # send_email()
|
|
|
+ message = '註冊成功'
|
|
|
+ subject = '註冊信'
|
|
|
+ print(message)
|
|
|
+ send_email(email,message,subject)
|
|
|
return {"msg": "註冊成功", "code": 200}
|
|
|
else:
|
|
|
return {"msg":"確認密碼錯誤","code":403}
|
|
@@ -108,18 +154,25 @@ def generate_password_reset_token(email: str) -> str:
|
|
|
expires = now + delta
|
|
|
exp = expires.timestamp()
|
|
|
encoded_jwt = jwt.encode(
|
|
|
- {"exp": exp, "nbf": now, "sub": email}, settings.SECRET_KEY, algorithm="HS256",
|
|
|
- )
|
|
|
+ {"exp": exp, "nbf": now, "sub": email}, settings.SECRET_KEY, algorithm="HS256",)
|
|
|
+ print(encoded_jwt)
|
|
|
return encoded_jwt
|
|
|
|
|
|
+def verify_password_reset_token(token: str):
|
|
|
+ try:
|
|
|
+ decoded_token = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"])
|
|
|
+ print(decoded_token)
|
|
|
+ return decoded_token["sub"]
|
|
|
+ except jwt.JWTError:
|
|
|
+ return None
|
|
|
+
|
|
|
|
|
|
def send_email(
|
|
|
email_to: str,
|
|
|
subject_template: str = "",
|
|
|
html_template: str = "",
|
|
|
environment: Dict[str, Any] = {},
|
|
|
-) -> None:
|
|
|
- # assert settings.EMAILS_ENABLED, "no provided configuration for email variables"
|
|
|
+):
|
|
|
message = emails.Message(
|
|
|
subject=JinjaTemplate(subject_template),
|
|
|
html=JinjaTemplate(html_template),
|
|
@@ -133,7 +186,30 @@ def send_email(
|
|
|
if settings.SMTP_PASSWORD:
|
|
|
smtp_options["password"] = settings.SMTP_PASSWORD
|
|
|
response = message.send(to=email_to, render=environment, smtp=smtp_options)
|
|
|
- logging.info(f"send email result: {response}")
|
|
|
+ return {"message":f"send email result: {response}"}
|
|
|
+ # logging.info(f"send email result: {response}")
|
|
|
+ # email_content = MIMEText(message)
|
|
|
+ # email_content["Subject"] = subject
|
|
|
+ # email_content["From"] = 'zooey@choozmo.com'
|
|
|
+ # email_content["To"] = email_to
|
|
|
+ # try:
|
|
|
+ # print('測試成功')
|
|
|
+ # # Connect to the SMTP server
|
|
|
+ # smtp_server = smtplib.SMTP(settings.SMTP_HOST, settings.SMTP_PORT)
|
|
|
+ # smtp_server.starttls()
|
|
|
+ #
|
|
|
+ # # Login to the email account
|
|
|
+ # smtp_server.login(settings.SMTP_HOST, settings.SMTP_PASSWORD)
|
|
|
+ #
|
|
|
+ # # Send the email
|
|
|
+ # smtp_server.sendmail(settings.SMTP_HOST, email_to, email_content.as_string())
|
|
|
+ #
|
|
|
+ # # Close the connection
|
|
|
+ # smtp_server.quit()
|
|
|
+ #
|
|
|
+ # return {"message": "Email sent successfully."}
|
|
|
+ # except Exception as e:
|
|
|
+ # print('測試失敗')
|
|
|
|
|
|
|
|
|
def send_reset_password_email(email_to: str, email: str, token: str) -> None:
|
|
@@ -142,12 +218,13 @@ def send_reset_password_email(email_to: str, email: str, token: str) -> None:
|
|
|
template_str = f.read()
|
|
|
server_host = settings.SERVER_HOST
|
|
|
link = f"{server_host}/reset-password?token={token}"
|
|
|
+ message = '重新設定密碼'
|
|
|
send_email(
|
|
|
email_to=email_to,
|
|
|
subject_template=subject,
|
|
|
html_template=template_str,
|
|
|
environment={
|
|
|
- # "project_name": settings.PROJECT_NAME,
|
|
|
+ "project_name": settings.PROJECT_NAME,
|
|
|
"username": email,
|
|
|
"email": email_to,
|
|
|
"valid_hours": settings.EMAIL_RESET_TOKEN_EXPIRE_HOURS,
|
|
@@ -171,6 +248,43 @@ async def recover_password(email:str):
|
|
|
return {"msg": "Password recovery email sent"}
|
|
|
|
|
|
|
|
|
+from pydantic import BaseModel
|
|
|
+
|
|
|
+
|
|
|
+class Msg(BaseModel):
|
|
|
+ msg: str
|
|
|
+@users.post("/reset-password/", response_model=Msg)
|
|
|
+async def reset_password(
|
|
|
+ token: str = Body(...),
|
|
|
+ new_password: str = Body(...),
|
|
|
+ db: Session = Depends(deps.get_db),
|
|
|
+) -> Any:
|
|
|
+ """
|
|
|
+ Reset password
|
|
|
+ """
|
|
|
+ email = verify_password_reset_token(token)
|
|
|
+ print(email)
|
|
|
+ if not email:
|
|
|
+ raise HTTPException(status_code=400, detail="Invalid token")
|
|
|
+ # user = await query_user(email)
|
|
|
+ user = await User.filter(email=email).first()
|
|
|
+
|
|
|
+ if not user:
|
|
|
+ raise HTTPException(
|
|
|
+ status_code=404,
|
|
|
+ detail="The user with this username does not exist in the system.",
|
|
|
+ )
|
|
|
+ # elif not crud.user.is_active(user):
|
|
|
+ # raise HTTPException(status_code=400, detail="Inactive user")
|
|
|
+ hashed_password = bcrypt.hashpw(new_password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
|
|
|
+ user.password = hashed_password
|
|
|
+ # db.add(user)
|
|
|
+ db.commit()
|
|
|
+ print(user.password)
|
|
|
+ db.close()
|
|
|
+ return {"msg": "Password updated successfully"}
|
|
|
+
|
|
|
+
|
|
|
|
|
|
@users.get("/delete_user/{id}")
|
|
|
async def delete(id: int):
|
|
@@ -178,4 +292,6 @@ async def delete(id: int):
|
|
|
await User.filter(id=id).delete()
|
|
|
return {"msg": "success", "code": 200}
|
|
|
|
|
|
- return {"msg": "failed", "code": 400}
|
|
|
+ return {"msg": "failed", "code": 400}
|
|
|
+
|
|
|
+print('12334')
|