Spaces:
Runtime error
Runtime error
Commit
·
3e7b272
1
Parent(s):
0bf745a
new update
Browse files- db/mongoDB.py +74 -22
- dependencies.py +5 -4
- main.py +6 -0
- requirements.txt +2 -1
- routers/chat.py +4 -4
- routers/user.py +6 -6
- services/auth_service.py +10 -10
- services/chat_service.py +5 -5
- services/user_service.py +28 -28
- utils/utils.py +2 -2
db/mongoDB.py
CHANGED
@@ -1,31 +1,83 @@
|
|
1 |
-
|
2 |
-
|
3 |
import logging
|
|
|
|
|
|
|
|
|
|
|
4 |
logger = logging.getLogger(__name__)
|
5 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
|
7 |
-
|
8 |
-
|
9 |
-
|
|
|
|
|
10 |
|
11 |
-
|
12 |
-
|
|
|
|
|
|
|
|
|
|
|
13 |
|
14 |
-
|
15 |
-
user_collection = db["users"]
|
16 |
-
blacklist_collection = db["token_blacklist"]
|
17 |
-
conversations_collection = db["conversations"]
|
18 |
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
logger.
|
|
|
|
|
|
|
|
|
24 |
|
25 |
-
logger.info("🔸Đã kết nối tới MongoDB Cloud thành công!")
|
26 |
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
|
|
1 |
+
# db/mongoDB.py
|
2 |
+
|
3 |
import logging
|
4 |
+
from typing import Optional
|
5 |
+
from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorDatabase, AsyncIOMotorCollection
|
6 |
+
from pymongo.errors import ConnectionFailure, ConfigurationError
|
7 |
+
import config # Import từ file config tập trung
|
8 |
+
|
9 |
logger = logging.getLogger(__name__)
|
10 |
|
11 |
+
class MongoDatabase:
|
12 |
+
"""
|
13 |
+
Một lớp singleton để quản lý kết nối và các collection của MongoDB.
|
14 |
+
Điều này đảm bảo chúng ta chỉ có một kết nối duy nhất trong toàn bộ ứng dụng.
|
15 |
+
"""
|
16 |
+
client: Optional[AsyncIOMotorClient] = None
|
17 |
+
db: Optional[AsyncIOMotorDatabase] = None
|
18 |
+
|
19 |
+
# Khai báo các collection bạn sẽ sử dụng
|
20 |
+
users: Optional[AsyncIOMotorCollection] = None
|
21 |
+
token_blacklist: Optional[AsyncIOMotorCollection] = None
|
22 |
+
conversations: Optional[AsyncIOMotorCollection] = None
|
23 |
+
|
24 |
+
# Tạo một instance duy nhất để import và sử dụng trong toàn bộ ứng dụng
|
25 |
+
mongo_db = MongoDatabase()
|
26 |
+
|
27 |
+
async def connect_to_mongo():
|
28 |
+
"""
|
29 |
+
Hàm khởi tạo kết nối đến MongoDB Atlas và gán vào object mongo_db.
|
30 |
+
Hàm này sẽ được gọi từ lifespan của FastAPI.
|
31 |
+
"""
|
32 |
+
if mongo_db.client:
|
33 |
+
logger.info("MongoDB connection already established.")
|
34 |
+
return
|
35 |
+
|
36 |
+
logger.info(f"🔸 Connecting to MongoDB Atlas...")
|
37 |
+
|
38 |
+
if not config.MONGO_URI or not config.MONGO_DB_NAME:
|
39 |
+
logger.error("❌ MONGO_URI hoặc MONGO_DB_NAME chưa được thiết lập trong biến môi trường.")
|
40 |
+
raise ConfigurationError("MONGO_URI and MONGO_DB_NAME must be set.")
|
41 |
+
|
42 |
+
try:
|
43 |
+
# 1. Khởi tạo client bất đồng bộ
|
44 |
+
mongo_db.client = AsyncIOMotorClient(
|
45 |
+
config.MONGO_URI,
|
46 |
+
serverSelectionTimeoutMS=5000 # Thời gian chờ kết nối là 5 giây
|
47 |
+
)
|
48 |
+
|
49 |
+
# 2. Kiểm tra kết nối một cách rõ ràng
|
50 |
+
await mongo_db.client.admin.command('ping')
|
51 |
|
52 |
+
# 3. Gán các đối tượng database và collection
|
53 |
+
mongo_db.db = mongo_db.client[config.MONGO_DB_NAME]
|
54 |
+
mongo_db.user = mongo_db.db["users"]
|
55 |
+
mongo_db.token_blacklist = mongo_db.db["token_blacklist"]
|
56 |
+
mongo_db.conversations = mongo_db.db["conversations"]
|
57 |
|
58 |
+
# 4. Tạo TTL index một cách an toàn
|
59 |
+
# Lấy danh sách index hiện có
|
60 |
+
index_info = await mongo_db.token_blacklist.index_information()
|
61 |
+
if "expires_at_1" not in index_info:
|
62 |
+
# Chỉ tạo index nếu nó chưa tồn tại
|
63 |
+
await mongo_db.token_blacklist.create_index("expires_at", expireAfterSeconds=0)
|
64 |
+
logger.info("🔸 Successfully created TTL index for 'expires_at' in 'token_blacklist'.")
|
65 |
|
66 |
+
logger.info("✅ MongoDB connection successful and collections are ready.")
|
|
|
|
|
|
|
67 |
|
68 |
+
except ConnectionFailure as e:
|
69 |
+
logger.error(f"❌ Failed to connect to MongoDB: Connection Failure. Check your URI and network access rules in Atlas. Error: {e}", exc_info=True)
|
70 |
+
raise e
|
71 |
+
except ConfigurationError as e:
|
72 |
+
logger.error(f"❌ Failed to connect to MongoDB: Configuration Error. Check your connection string format. Error: {e}", exc_info=True)
|
73 |
+
raise e
|
74 |
+
except Exception as e:
|
75 |
+
logger.error(f"❌ An unexpected error occurred while connecting to MongoDB: {e}", exc_info=True)
|
76 |
+
raise e
|
77 |
|
|
|
78 |
|
79 |
+
async def close_mongo_connection():
|
80 |
+
"""Hàm đóng kết nối MongoDB khi ứng dụng tắt."""
|
81 |
+
if mongo_db.client:
|
82 |
+
mongo_db.client.close()
|
83 |
+
logger.info("✅ MongoDB connection closed.")
|
dependencies.py
CHANGED
@@ -3,7 +3,8 @@ from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
|
|
3 |
from jose import jwt, JWTError, ExpiredSignatureError
|
4 |
import os
|
5 |
from dotenv import load_dotenv
|
6 |
-
from db.mongoDB import user_collection, blacklist_collection
|
|
|
7 |
import torch
|
8 |
import rag_components
|
9 |
from schemas.chat import AppState
|
@@ -69,7 +70,7 @@ async def initialize_api_components(app_state: AppState):
|
|
69 |
app_state.dict = load_legal_dictionary(config.LEGAL_DIC_FOLDER+ "/legal_terms.json")
|
70 |
app_state.weaviateDB = connect_to_weaviate(run_diagnostics=False)
|
71 |
# --- Kiểm tra kết nối tới MongoDB ---
|
72 |
-
if
|
73 |
logger.error("🔸Lỗi kết nối tới MongoDB hoặc Weaviate.")
|
74 |
raise HTTPException(status_code=500, detail="Lỗi kết nối tới database.")
|
75 |
|
@@ -188,7 +189,7 @@ async def get_current_user(
|
|
188 |
# 1. Kiểm tra token trong blacklist
|
189 |
try:
|
190 |
logger.info("GET_CURRENT_USER: Đang kiểm tra blacklist...")
|
191 |
-
is_blacklisted =
|
192 |
if is_blacklisted:
|
193 |
logger.error(f"GET_CURRENT_USER: *** TOKEN TRONG BLACKLIST - RAISING 401 ***")
|
194 |
raise HTTPException( # Sử dụng credentials_exception hoặc một cái cụ thể hơn
|
@@ -265,7 +266,7 @@ async def get_current_user(
|
|
265 |
user_data: Optional[dict] = None # Khởi tạo để tránh UnboundLocalError
|
266 |
try:
|
267 |
logger.info(f"GET_CURRENT_USER: Đang tìm user trong DB: {email.lower()}") # email đã được validate là str
|
268 |
-
user_data =
|
269 |
# print(user_data) # Bỏ print trong production
|
270 |
|
271 |
if user_data is None:
|
|
|
3 |
from jose import jwt, JWTError, ExpiredSignatureError
|
4 |
import os
|
5 |
from dotenv import load_dotenv
|
6 |
+
# from db.mongoDB import user_collection, blacklist_collection
|
7 |
+
from db.mongoDB import mongo_db
|
8 |
import torch
|
9 |
import rag_components
|
10 |
from schemas.chat import AppState
|
|
|
70 |
app_state.dict = load_legal_dictionary(config.LEGAL_DIC_FOLDER+ "/legal_terms.json")
|
71 |
app_state.weaviateDB = connect_to_weaviate(run_diagnostics=False)
|
72 |
# --- Kiểm tra kết nối tới MongoDB ---
|
73 |
+
if mongo_db.users is None or app_state.weaviateDB is None:
|
74 |
logger.error("🔸Lỗi kết nối tới MongoDB hoặc Weaviate.")
|
75 |
raise HTTPException(status_code=500, detail="Lỗi kết nối tới database.")
|
76 |
|
|
|
189 |
# 1. Kiểm tra token trong blacklist
|
190 |
try:
|
191 |
logger.info("GET_CURRENT_USER: Đang kiểm tra blacklist...")
|
192 |
+
is_blacklisted = await mongo_db.token_blacklist.find_one({"token": token_to_verify})
|
193 |
if is_blacklisted:
|
194 |
logger.error(f"GET_CURRENT_USER: *** TOKEN TRONG BLACKLIST - RAISING 401 ***")
|
195 |
raise HTTPException( # Sử dụng credentials_exception hoặc một cái cụ thể hơn
|
|
|
266 |
user_data: Optional[dict] = None # Khởi tạo để tránh UnboundLocalError
|
267 |
try:
|
268 |
logger.info(f"GET_CURRENT_USER: Đang tìm user trong DB: {email.lower()}") # email đã được validate là str
|
269 |
+
user_data =await mongo_db.users.find_one({"email": email.lower()}, {"password": 0, "_id": 0})
|
270 |
# print(user_data) # Bỏ print trong production
|
271 |
|
272 |
if user_data is None:
|
main.py
CHANGED
@@ -15,6 +15,7 @@ import os
|
|
15 |
import traceback
|
16 |
from core.logging_config import setup_logging
|
17 |
setup_logging()
|
|
|
18 |
|
19 |
logger = logging.getLogger(__name__)
|
20 |
|
@@ -22,6 +23,10 @@ logger = logging.getLogger(__name__)
|
|
22 |
@asynccontextmanager
|
23 |
async def lifespan(app: FastAPI):
|
24 |
logger.info("✅ [Lifespan] STARTING UP...")
|
|
|
|
|
|
|
|
|
25 |
current_app_state_instance = AppState()
|
26 |
initialization_successful = False
|
27 |
try:
|
@@ -32,6 +37,7 @@ async def lifespan(app: FastAPI):
|
|
32 |
logger.info("✅ [Lifespan] SUCCESSFULLY set app.state.app_state.")
|
33 |
yield
|
34 |
logger.info("✅ [Lifespan] SHUTTING DOWN (after yield)...")
|
|
|
35 |
except Exception as e:
|
36 |
logger.error(f"❌ [Lifespan] FATAL ERROR DURING STARTUP: {type(e).__name__} - {e}")
|
37 |
logger.error(traceback.format_exc())
|
|
|
15 |
import traceback
|
16 |
from core.logging_config import setup_logging
|
17 |
setup_logging()
|
18 |
+
from db.mongoDB import connect_to_mongo, close_mongo_connection
|
19 |
|
20 |
logger = logging.getLogger(__name__)
|
21 |
|
|
|
23 |
@asynccontextmanager
|
24 |
async def lifespan(app: FastAPI):
|
25 |
logger.info("✅ [Lifespan] STARTING UP...")
|
26 |
+
|
27 |
+
await connect_to_mongo()
|
28 |
+
|
29 |
+
|
30 |
current_app_state_instance = AppState()
|
31 |
initialization_successful = False
|
32 |
try:
|
|
|
37 |
logger.info("✅ [Lifespan] SUCCESSFULLY set app.state.app_state.")
|
38 |
yield
|
39 |
logger.info("✅ [Lifespan] SHUTTING DOWN (after yield)...")
|
40 |
+
await close_mongo_connection()
|
41 |
except Exception as e:
|
42 |
logger.error(f"❌ [Lifespan] FATAL ERROR DURING STARTUP: {type(e).__name__} - {e}")
|
43 |
logger.error(traceback.format_exc())
|
requirements.txt
CHANGED
@@ -37,4 +37,5 @@ itsdangerous
|
|
37 |
Authlib[fastapi]
|
38 |
httpx
|
39 |
|
40 |
-
gunicorn
|
|
|
|
37 |
Authlib[fastapi]
|
38 |
httpx
|
39 |
|
40 |
+
gunicorn
|
41 |
+
motor
|
routers/chat.py
CHANGED
@@ -9,7 +9,7 @@ import logging
|
|
9 |
import uuid
|
10 |
from redis.asyncio import Redis
|
11 |
from datetime import datetime, timezone
|
12 |
-
from db.mongoDB import
|
13 |
from fastapi.responses import StreamingResponse
|
14 |
from schemas.chat import Message,ConversationResponse
|
15 |
from typing import List
|
@@ -135,7 +135,7 @@ async def delete_chat(chat_id: str, request: Request, user: UserOut = Depends(ge
|
|
135 |
# Xóa chat
|
136 |
delete_chat_from_redis(redis, chat_id)
|
137 |
# Xóa hội thoại trong MongoDB
|
138 |
-
result =
|
139 |
if result.deleted_count == 0:
|
140 |
raise HTTPException(status_code=404, detail="Chat not found in MongoDB")
|
141 |
|
@@ -147,7 +147,7 @@ async def delete_chat(chat_id: str, request: Request, user: UserOut = Depends(ge
|
|
147 |
async def get_conversations(user: UserOut = Depends(get_current_user)):
|
148 |
try:
|
149 |
logger.info(f"Attempting to get conversations for user: {user.email}")
|
150 |
-
db_conversations_cursor =
|
151 |
|
152 |
response_list = []
|
153 |
|
@@ -182,7 +182,7 @@ async def load_conversation_and_sync_redis(
|
|
182 |
|
183 |
# 1. Kiểm tra hội thoại trong MongoDB
|
184 |
try:
|
185 |
-
conversation_doc =
|
186 |
{"conversation_id": chat_id, "user_id": current_user.email}
|
187 |
)
|
188 |
if not conversation_doc:
|
|
|
9 |
import uuid
|
10 |
from redis.asyncio import Redis
|
11 |
from datetime import datetime, timezone
|
12 |
+
from db.mongoDB import mongo_db
|
13 |
from fastapi.responses import StreamingResponse
|
14 |
from schemas.chat import Message,ConversationResponse
|
15 |
from typing import List
|
|
|
135 |
# Xóa chat
|
136 |
delete_chat_from_redis(redis, chat_id)
|
137 |
# Xóa hội thoại trong MongoDB
|
138 |
+
result = await mongo_db.conversations.delete_one({"conversation_id": chat_id, "user_id": user.email})
|
139 |
if result.deleted_count == 0:
|
140 |
raise HTTPException(status_code=404, detail="Chat not found in MongoDB")
|
141 |
|
|
|
147 |
async def get_conversations(user: UserOut = Depends(get_current_user)):
|
148 |
try:
|
149 |
logger.info(f"Attempting to get conversations for user: {user.email}")
|
150 |
+
db_conversations_cursor = await mongo_db.conversations.find({"user_id": user.email})
|
151 |
|
152 |
response_list = []
|
153 |
|
|
|
182 |
|
183 |
# 1. Kiểm tra hội thoại trong MongoDB
|
184 |
try:
|
185 |
+
conversation_doc =await mongo_db.conversations.find_one(
|
186 |
{"conversation_id": chat_id, "user_id": current_user.email}
|
187 |
)
|
188 |
if not conversation_doc:
|
routers/user.py
CHANGED
@@ -12,7 +12,7 @@ from starlette.config import Config
|
|
12 |
from authlib.integrations.starlette_client import OAuth
|
13 |
import os
|
14 |
import config
|
15 |
-
from db.mongoDB import
|
16 |
import uuid
|
17 |
from passlib.context import CryptContext
|
18 |
from datetime import datetime, timedelta, timezone
|
@@ -304,7 +304,7 @@ async def auth_google_callback(request: Request):
|
|
304 |
|
305 |
|
306 |
# Kiểm tra xem user đã tồn tại trong DB chưa
|
307 |
-
db_user =
|
308 |
|
309 |
if not db_user:
|
310 |
placeholder_password = f"google-oauth2|{uuid.uuid4()}"
|
@@ -314,7 +314,7 @@ async def auth_google_callback(request: Request):
|
|
314 |
|
315 |
|
316 |
# Tạo user mới với thông tin từ Google
|
317 |
-
|
318 |
"email": user_email,
|
319 |
"username": username,
|
320 |
"password": hashed_password, # Mật khẩu tạm thời, sẽ không dùng đến
|
@@ -324,7 +324,7 @@ async def auth_google_callback(request: Request):
|
|
324 |
})
|
325 |
|
326 |
# Lấy lại user vừa tạo để đảm bảo có _id và các trường khác
|
327 |
-
db_user =
|
328 |
if not db_user: # Kiểm tra lại sau khi insert
|
329 |
raise HTTPException(status_code=500, detail="Could not create and retrieve new user account.")
|
330 |
|
@@ -362,7 +362,7 @@ async def exchange_google_code_for_token(request: Request,response: Response, co
|
|
362 |
redis_client.delete(redis_key) # Dùng một lần
|
363 |
user_email = user_email_bytes.decode()
|
364 |
|
365 |
-
|
366 |
"email": user_email
|
367 |
}, {
|
368 |
"$set": {
|
@@ -408,7 +408,7 @@ async def exchange_google_code_for_token(request: Request,response: Response, co
|
|
408 |
path="/api/user/refresh-token",
|
409 |
)
|
410 |
|
411 |
-
user_info =
|
412 |
user = {
|
413 |
"email": user_info.get("email"),
|
414 |
"username": user_info.get("username"),
|
|
|
12 |
from authlib.integrations.starlette_client import OAuth
|
13 |
import os
|
14 |
import config
|
15 |
+
from db.mongoDB import mongo_db
|
16 |
import uuid
|
17 |
from passlib.context import CryptContext
|
18 |
from datetime import datetime, timedelta, timezone
|
|
|
304 |
|
305 |
|
306 |
# Kiểm tra xem user đã tồn tại trong DB chưa
|
307 |
+
db_user = await mongo_db.users.find_one({"email": user_email})
|
308 |
|
309 |
if not db_user:
|
310 |
placeholder_password = f"google-oauth2|{uuid.uuid4()}"
|
|
|
314 |
|
315 |
|
316 |
# Tạo user mới với thông tin từ Google
|
317 |
+
await mongo_db.users.insert_one({
|
318 |
"email": user_email,
|
319 |
"username": username,
|
320 |
"password": hashed_password, # Mật khẩu tạm thời, sẽ không dùng đến
|
|
|
324 |
})
|
325 |
|
326 |
# Lấy lại user vừa tạo để đảm bảo có _id và các trường khác
|
327 |
+
db_user =await mongo_db.users.find_one({"email": user_email})
|
328 |
if not db_user: # Kiểm tra lại sau khi insert
|
329 |
raise HTTPException(status_code=500, detail="Could not create and retrieve new user account.")
|
330 |
|
|
|
362 |
redis_client.delete(redis_key) # Dùng một lần
|
363 |
user_email = user_email_bytes.decode()
|
364 |
|
365 |
+
await mongo_db.users.update_one({
|
366 |
"email": user_email
|
367 |
}, {
|
368 |
"$set": {
|
|
|
408 |
path="/api/user/refresh-token",
|
409 |
)
|
410 |
|
411 |
+
user_info =await mongo_db.users.find_one({"email": user_email})
|
412 |
user = {
|
413 |
"email": user_info.get("email"),
|
414 |
"username": user_info.get("username"),
|
services/auth_service.py
CHANGED
@@ -3,7 +3,7 @@ from jose import JWTError, jwt
|
|
3 |
from datetime import datetime, timedelta, timezone
|
4 |
from fastapi import HTTPException, Depends, Request, status
|
5 |
from schemas.user import RegisterRequest, LoginRequest
|
6 |
-
from db.mongoDB import
|
7 |
from utils.utils import verify_password
|
8 |
from config import SECRET_KEY, ALGORITHM, ACCESS_TOKEN_EXPIRE_MINUTES
|
9 |
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
|
@@ -31,7 +31,7 @@ async def register_user(user: RegisterRequest):
|
|
31 |
|
32 |
try:
|
33 |
# Kiểm tra username đã tồn tại chưa
|
34 |
-
existing_user =
|
35 |
if existing_user:
|
36 |
raise HTTPException(status_code=400, detail="Tài khoản đã tồn tại.")
|
37 |
|
@@ -40,7 +40,7 @@ async def register_user(user: RegisterRequest):
|
|
40 |
|
41 |
avatar = await get_random_unsplash_image()
|
42 |
# Lưu user mới
|
43 |
-
|
44 |
"username": user.username,
|
45 |
"password": hashed_password,
|
46 |
"email": user.email,
|
@@ -53,8 +53,8 @@ async def register_user(user: RegisterRequest):
|
|
53 |
except HTTPException as e:
|
54 |
raise HTTPException(status_code=e.status_code, detail=e.detail)
|
55 |
# Hàm xác thực đăng nhập
|
56 |
-
def authenticate_user(request: LoginRequest):
|
57 |
-
user =
|
58 |
if not user:
|
59 |
raise HTTPException(status_code=401, detail="Sai tài khoản hoặc mật khẩu")
|
60 |
|
@@ -64,8 +64,8 @@ def authenticate_user(request: LoginRequest):
|
|
64 |
return user
|
65 |
|
66 |
# Hàm tạo và trả về JWT token sau khi đăng nhập thành công
|
67 |
-
def login_user(request: LoginRequest):
|
68 |
-
user = authenticate_user(request)
|
69 |
|
70 |
accessToken = create_access_token(data={"sub": request.email})
|
71 |
|
@@ -101,7 +101,7 @@ async def logout_user(req: Request, credentials: HTTPAuthorizationCredentials =
|
|
101 |
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Access token không hợp lệ")
|
102 |
|
103 |
# Blacklist access token
|
104 |
-
await
|
105 |
"token": token,
|
106 |
"expires_at": datetime.fromtimestamp(exp, tz=timezone.utc)
|
107 |
})
|
@@ -110,9 +110,9 @@ async def logout_user(req: Request, credentials: HTTPAuthorizationCredentials =
|
|
110 |
refresh_token = req.cookies.get("refresh_token")
|
111 |
if refresh_token:
|
112 |
# Invalidate refresh token in database
|
113 |
-
user = await
|
114 |
if user:
|
115 |
-
await
|
116 |
{"_id": user["_id"]},
|
117 |
{"$set": {"refresh_token": None, "refresh_token_expiry": None, "revoked": True}}
|
118 |
)
|
|
|
3 |
from datetime import datetime, timedelta, timezone
|
4 |
from fastapi import HTTPException, Depends, Request, status
|
5 |
from schemas.user import RegisterRequest, LoginRequest
|
6 |
+
from db.mongoDB import mongo_db
|
7 |
from utils.utils import verify_password
|
8 |
from config import SECRET_KEY, ALGORITHM, ACCESS_TOKEN_EXPIRE_MINUTES
|
9 |
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
|
|
|
31 |
|
32 |
try:
|
33 |
# Kiểm tra username đã tồn tại chưa
|
34 |
+
existing_user =await mongo_db.users.find_one({"email": user.email})
|
35 |
if existing_user:
|
36 |
raise HTTPException(status_code=400, detail="Tài khoản đã tồn tại.")
|
37 |
|
|
|
40 |
|
41 |
avatar = await get_random_unsplash_image()
|
42 |
# Lưu user mới
|
43 |
+
await mongo_db.users.insert_one({
|
44 |
"username": user.username,
|
45 |
"password": hashed_password,
|
46 |
"email": user.email,
|
|
|
53 |
except HTTPException as e:
|
54 |
raise HTTPException(status_code=e.status_code, detail=e.detail)
|
55 |
# Hàm xác thực đăng nhập
|
56 |
+
async def authenticate_user(request: LoginRequest):
|
57 |
+
user =await mongo_db.users.find_one({"email": request.email})
|
58 |
if not user:
|
59 |
raise HTTPException(status_code=401, detail="Sai tài khoản hoặc mật khẩu")
|
60 |
|
|
|
64 |
return user
|
65 |
|
66 |
# Hàm tạo và trả về JWT token sau khi đăng nhập thành công
|
67 |
+
async def login_user(request: LoginRequest):
|
68 |
+
user = await authenticate_user(request)
|
69 |
|
70 |
accessToken = create_access_token(data={"sub": request.email})
|
71 |
|
|
|
101 |
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Access token không hợp lệ")
|
102 |
|
103 |
# Blacklist access token
|
104 |
+
await mongo_db.token_blacklist.insert_one({
|
105 |
"token": token,
|
106 |
"expires_at": datetime.fromtimestamp(exp, tz=timezone.utc)
|
107 |
})
|
|
|
110 |
refresh_token = req.cookies.get("refresh_token")
|
111 |
if refresh_token:
|
112 |
# Invalidate refresh token in database
|
113 |
+
user = await mongo_db.users.find_one({"refresh_token": refresh_token})
|
114 |
if user:
|
115 |
+
await mongo_db.users.update_one(
|
116 |
{"_id": user["_id"]},
|
117 |
{"$set": {"refresh_token": None, "refresh_token_expiry": None, "revoked": True}}
|
118 |
)
|
services/chat_service.py
CHANGED
@@ -7,7 +7,7 @@ import json
|
|
7 |
from utils.utils import save_chat_to_redis, search_term_in_dictionary, minimal_preprocess_for_llm, save_chat_to_mongo, get_langchain_chat_history
|
8 |
import os
|
9 |
import logging
|
10 |
-
from db.mongoDB import
|
11 |
from datetime import datetime, timezone
|
12 |
import asyncio
|
13 |
|
@@ -51,7 +51,7 @@ async def ask_question_service(app_state, request: QueryRequest, user: UserOut =
|
|
51 |
app_state.redis, chat_id, question_content, answer_def, current_utc_time, assistant_response_time
|
52 |
)
|
53 |
await save_chat_to_mongo(
|
54 |
-
|
55 |
)
|
56 |
friendly_answer = f"Xin chào! Về câu hỏi '{question_content}' của bạn, tôi đã tìm thấy thông tin sau:\n\n{answer_def}\n\nHy vọng thông tin này hữu ích cho bạn. Bạn có muốn tìm hiểu thêm về chủ đề này hoặc có câu hỏi nào khác không? 😊"
|
57 |
return AnswerResponse(
|
@@ -146,7 +146,7 @@ async def ask_question_service(app_state, request: QueryRequest, user: UserOut =
|
|
146 |
# Lưu vào MongoDB
|
147 |
# Chạy ngầm hoặc sau khi trả lời user để không làm chậm response (nếu có thể)
|
148 |
await save_chat_to_mongo(
|
149 |
-
|
150 |
)
|
151 |
|
152 |
end_time = time.time()
|
@@ -219,7 +219,7 @@ async def stream_chat_generator(
|
|
219 |
app_state.redis, chat_id, question_content, full_answer_for_saving, current_utc_time, assistant_response_time_dict
|
220 |
)
|
221 |
asyncio.create_task(save_chat_to_mongo( # Chạy nền
|
222 |
-
|
223 |
))
|
224 |
processing_time_dict = round(time.time() - start_time_total, 2)
|
225 |
logger.info(f"Stream: Dictionary answer for {chat_id} sent in {processing_time_dict:.2f}s.")
|
@@ -321,7 +321,7 @@ async def stream_chat_generator(
|
|
321 |
)
|
322 |
# Chạy lưu MongoDB ngầm để không block
|
323 |
asyncio.create_task(save_chat_to_mongo(
|
324 |
-
|
325 |
))
|
326 |
|
327 |
# Cập nhật Langchain history (nếu chain memory không tự làm)
|
|
|
7 |
from utils.utils import save_chat_to_redis, search_term_in_dictionary, minimal_preprocess_for_llm, save_chat_to_mongo, get_langchain_chat_history
|
8 |
import os
|
9 |
import logging
|
10 |
+
from db.mongoDB import mongo_db
|
11 |
from datetime import datetime, timezone
|
12 |
import asyncio
|
13 |
|
|
|
51 |
app_state.redis, chat_id, question_content, answer_def, current_utc_time, assistant_response_time
|
52 |
)
|
53 |
await save_chat_to_mongo(
|
54 |
+
mongo_db.conversations, chat_id, user.email, question_content, answer_def, current_utc_time, assistant_response_time
|
55 |
)
|
56 |
friendly_answer = f"Xin chào! Về câu hỏi '{question_content}' của bạn, tôi đã tìm thấy thông tin sau:\n\n{answer_def}\n\nHy vọng thông tin này hữu ích cho bạn. Bạn có muốn tìm hiểu thêm về chủ đề này hoặc có câu hỏi nào khác không? 😊"
|
57 |
return AnswerResponse(
|
|
|
146 |
# Lưu vào MongoDB
|
147 |
# Chạy ngầm hoặc sau khi trả lời user để không làm chậm response (nếu có thể)
|
148 |
await save_chat_to_mongo(
|
149 |
+
mongo_db.conversations, chat_id, user.email, question_content, assistant_response_content, current_utc_time, assistant_response_time
|
150 |
)
|
151 |
|
152 |
end_time = time.time()
|
|
|
219 |
app_state.redis, chat_id, question_content, full_answer_for_saving, current_utc_time, assistant_response_time_dict
|
220 |
)
|
221 |
asyncio.create_task(save_chat_to_mongo( # Chạy nền
|
222 |
+
mongo_db.conversations, chat_id, user_email, question_content, full_answer_for_saving, current_utc_time, assistant_response_time_dict
|
223 |
))
|
224 |
processing_time_dict = round(time.time() - start_time_total, 2)
|
225 |
logger.info(f"Stream: Dictionary answer for {chat_id} sent in {processing_time_dict:.2f}s.")
|
|
|
321 |
)
|
322 |
# Chạy lưu MongoDB ngầm để không block
|
323 |
asyncio.create_task(save_chat_to_mongo(
|
324 |
+
mongo_db.conversations, chat_id, user_email, question_content, full_answer_for_saving, current_utc_time, assistant_response_time
|
325 |
))
|
326 |
|
327 |
# Cập nhật Langchain history (nếu chain memory không tự làm)
|
services/user_service.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
from db.mongoDB import
|
2 |
from fastapi import HTTPException, Request, Response
|
3 |
import math
|
4 |
from datetime import datetime, timedelta, timezone
|
@@ -17,7 +17,7 @@ logger = logging.getLogger(__name__)
|
|
17 |
# Initialize password hashing context
|
18 |
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
19 |
|
20 |
-
def get_users(skip: int = 0, limit: int = 100, query: dict = None):
|
21 |
"""
|
22 |
Lấy danh sách người dùng với phân trang và tìm kiếm nâng cao
|
23 |
|
@@ -37,7 +37,7 @@ def get_users(skip: int = 0, limit: int = 100, query: dict = None):
|
|
37 |
search_query = query or {}
|
38 |
|
39 |
# Thực hiện truy vấn với phân trang
|
40 |
-
users_cursor =
|
41 |
search_query,
|
42 |
{"_id": 0, "password": 0} # Loại bỏ các trường nhạy cảm
|
43 |
).skip(skip).limit(limit)
|
@@ -56,7 +56,7 @@ def get_users(skip: int = 0, limit: int = 100, query: dict = None):
|
|
56 |
detail=f"Lỗi khi lấy danh sách người dùng: {str(e)}"
|
57 |
)
|
58 |
|
59 |
-
def count_users(query: dict = None):
|
60 |
"""
|
61 |
Đếm tổng số người dùng thỏa mãn điều kiện tìm kiếm
|
62 |
|
@@ -68,7 +68,7 @@ def count_users(query: dict = None):
|
|
68 |
"""
|
69 |
try:
|
70 |
search_query = query or {}
|
71 |
-
return
|
72 |
except Exception as e:
|
73 |
logger.error(f"Lỗi khi đếm người dùng: {str(e)}")
|
74 |
raise HTTPException(
|
@@ -112,7 +112,7 @@ async def get_paginated_users(
|
|
112 |
sort_criteria = [(sort_by, sort_order)]
|
113 |
|
114 |
# Thực hiện truy vấn
|
115 |
-
users_cursor =
|
116 |
query,
|
117 |
{"_id": 0, "password": 0} # Loại bỏ các trường nhạy cảm
|
118 |
).sort(sort_criteria).skip(skip).limit(limit)
|
@@ -121,7 +121,7 @@ async def get_paginated_users(
|
|
121 |
user_list = users_cursor.to_list(length=limit)
|
122 |
|
123 |
# Đếm tổng số bản ghi
|
124 |
-
total =
|
125 |
|
126 |
# Tính toán thông tin phân trang
|
127 |
total_pages = math.ceil(total / limit) if limit > 0 else 0
|
@@ -156,7 +156,7 @@ async def get_current_user_profile(email: str):
|
|
156 |
dict: Thông tin profile của người dùng
|
157 |
"""
|
158 |
try:
|
159 |
-
user =
|
160 |
logger.info(f"check user user_service: {user}")
|
161 |
if not user:
|
162 |
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Người dùng không tồn tại")
|
@@ -171,7 +171,7 @@ async def get_current_user_profile(email: str):
|
|
171 |
)
|
172 |
|
173 |
|
174 |
-
def delete_user(user_id: str):
|
175 |
"""
|
176 |
Xóa người dùng theo ID
|
177 |
|
@@ -182,7 +182,7 @@ def delete_user(user_id: str):
|
|
182 |
bool: True nếu xóa thành công, False nếu không tìm thấy người dùng
|
183 |
"""
|
184 |
try:
|
185 |
-
result =
|
186 |
return result.deleted_count > 0
|
187 |
except Exception as e:
|
188 |
logger.error(f"Lỗi khi xóa người dùng: {str(e)}")
|
@@ -191,7 +191,7 @@ def delete_user(user_id: str):
|
|
191 |
detail=f"Lỗi khi xóa người dùng: {str(e)}"
|
192 |
)
|
193 |
|
194 |
-
def change_password(email: str, current_password: str, new_password: str):
|
195 |
"""
|
196 |
Đổi mật khẩu của người dùng
|
197 |
|
@@ -204,7 +204,7 @@ def change_password(email: str, current_password: str, new_password: str):
|
|
204 |
bool: True nếu đổi mật khẩu thành công, False nếu không thành công
|
205 |
"""
|
206 |
try:
|
207 |
-
user =
|
208 |
if not user:
|
209 |
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Người dùng không tồn tại")
|
210 |
|
@@ -216,7 +216,7 @@ def change_password(email: str, current_password: str, new_password: str):
|
|
216 |
# Hash the new password
|
217 |
hashed_password = pwd_context.hash(new_password)
|
218 |
# Update the password in the database
|
219 |
-
result =
|
220 |
return result.modified_count > 0
|
221 |
except HTTPException as he:
|
222 |
raise he
|
@@ -242,13 +242,13 @@ async def reset_password_request(email: str) -> bool:
|
|
242 |
"""
|
243 |
try:
|
244 |
# Check if user exists
|
245 |
-
user =
|
246 |
if not user:
|
247 |
# Return True even if user not found to prevent email enumeration
|
248 |
return True
|
249 |
|
250 |
# Check for rate limiting (e.g., max 3 requests per hour)
|
251 |
-
reset_requests =
|
252 |
"email": email.lower(),
|
253 |
"reset_password_timestamp": {
|
254 |
"$gte": datetime.now(tz=timezone.utc) - timedelta(hours=1)
|
@@ -265,7 +265,7 @@ async def reset_password_request(email: str) -> bool:
|
|
265 |
expiry = datetime.now() + timedelta(minutes=10)
|
266 |
|
267 |
# Store reset token and timestamp in database
|
268 |
-
|
269 |
{"_id": ObjectId(user["_id"])},
|
270 |
{
|
271 |
"$set": {
|
@@ -312,7 +312,7 @@ async def reset_password(code: str, newPassword: str) -> bool:
|
|
312 |
"""
|
313 |
try:
|
314 |
# Find user by reset token
|
315 |
-
user =
|
316 |
if not user:
|
317 |
logger.warning(f"Code không hợp lệ: {code}")
|
318 |
return False
|
@@ -334,7 +334,7 @@ async def reset_password(code: str, newPassword: str) -> bool:
|
|
334 |
hashed_password = pwd_context.hash(newPassword)
|
335 |
|
336 |
# Update user's password and clear reset token
|
337 |
-
result =
|
338 |
{"_id": ObjectId(user["_id"])},
|
339 |
{
|
340 |
"$set": {"password": hashed_password},
|
@@ -380,7 +380,7 @@ async def generate_and_store_verification_code(email: str) -> bool:
|
|
380 |
expiry = datetime.now() + timedelta(minutes=10)
|
381 |
|
382 |
# Store code and expiry in database
|
383 |
-
result =
|
384 |
{"email": email.lower()},
|
385 |
{
|
386 |
"$set": {
|
@@ -425,12 +425,12 @@ async def verify_login_code(email: str, code: str, res: Response): # Bỏ kiểu
|
|
425 |
HTTPException: Nếu mã không hợp lệ, đã hết hạn hoặc có lỗi hệ thống.
|
426 |
"""
|
427 |
try:
|
428 |
-
user =
|
429 |
"email": email.lower(),
|
430 |
"login_verification_code": code
|
431 |
})
|
432 |
-
# Nếu
|
433 |
-
# user =
|
434 |
|
435 |
if not user:
|
436 |
logger.warning(f"Mã xác minh không hợp lệ: {code} cho email: {email}")
|
@@ -443,7 +443,7 @@ async def verify_login_code(email: str, code: str, res: Response): # Bỏ kiểu
|
|
443 |
if not expiry or expiry < datetime.now(expiry.tzinfo if expiry.tzinfo else None): # So sánh aware với aware, naive với naive
|
444 |
logger.warning(f"Mã xác minh đã hết hạn cho email: {email}")
|
445 |
# Xóa mã đã hết hạn để tránh sử dụng lại
|
446 |
-
|
447 |
{"_id": ObjectId(user["_id"])},
|
448 |
{
|
449 |
"$unset": {
|
@@ -509,7 +509,7 @@ async def verify_login_code(email: str, code: str, res: Response): # Bỏ kiểu
|
|
509 |
# --------------------
|
510 |
|
511 |
# Clear verification code và cập nhật last_login
|
512 |
-
|
513 |
{"_id": ObjectId(user["_id"])},
|
514 |
{
|
515 |
"$unset": {
|
@@ -567,7 +567,7 @@ async def authenticate_user(request: LoginRequest) -> dict:
|
|
567 |
Raises:
|
568 |
HTTPException: Nếu thông tin đăng nhập không hợp lệ.
|
569 |
"""
|
570 |
-
user =
|
571 |
if not user or not pwd_context.verify(request.password, user["password"]):
|
572 |
logger.warning(f"Xác thực thất bại cho email: {request.email}")
|
573 |
raise HTTPException(
|
@@ -603,7 +603,7 @@ async def refresh_access_token(req: Request , res: Response ) -> dict:
|
|
603 |
)
|
604 |
|
605 |
# Find user by refresh token in database
|
606 |
-
user =
|
607 |
|
608 |
|
609 |
if not user:
|
@@ -640,7 +640,7 @@ async def refresh_access_token(req: Request , res: Response ) -> dict:
|
|
640 |
new_refresh_token = await create_refresh_token(email)
|
641 |
|
642 |
# Update database with new refresh token
|
643 |
-
|
644 |
{"_id": user["_id"]},
|
645 |
{
|
646 |
"$set": {
|
@@ -702,7 +702,7 @@ async def verify_forgot_password_code(email: str, code: str) -> dict:
|
|
702 |
|
703 |
try:
|
704 |
# Find user by email and code
|
705 |
-
user =
|
706 |
"email": email.lower(),
|
707 |
"reset_password_code": code
|
708 |
})
|
|
|
1 |
+
from db.mongoDB import mongo_db
|
2 |
from fastapi import HTTPException, Request, Response
|
3 |
import math
|
4 |
from datetime import datetime, timedelta, timezone
|
|
|
17 |
# Initialize password hashing context
|
18 |
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
19 |
|
20 |
+
async def get_users(skip: int = 0, limit: int = 100, query: dict = None):
|
21 |
"""
|
22 |
Lấy danh sách người dùng với phân trang và tìm kiếm nâng cao
|
23 |
|
|
|
37 |
search_query = query or {}
|
38 |
|
39 |
# Thực hiện truy vấn với phân trang
|
40 |
+
users_cursor =await mongo_db.users.find(
|
41 |
search_query,
|
42 |
{"_id": 0, "password": 0} # Loại bỏ các trường nhạy cảm
|
43 |
).skip(skip).limit(limit)
|
|
|
56 |
detail=f"Lỗi khi lấy danh sách người dùng: {str(e)}"
|
57 |
)
|
58 |
|
59 |
+
async def count_users(query: dict = None):
|
60 |
"""
|
61 |
Đếm tổng số người dùng thỏa mãn điều kiện tìm kiếm
|
62 |
|
|
|
68 |
"""
|
69 |
try:
|
70 |
search_query = query or {}
|
71 |
+
return await mongo_db.users.count_documents(search_query)
|
72 |
except Exception as e:
|
73 |
logger.error(f"Lỗi khi đếm người dùng: {str(e)}")
|
74 |
raise HTTPException(
|
|
|
112 |
sort_criteria = [(sort_by, sort_order)]
|
113 |
|
114 |
# Thực hiện truy vấn
|
115 |
+
users_cursor =await mongo_db.users.find(
|
116 |
query,
|
117 |
{"_id": 0, "password": 0} # Loại bỏ các trường nhạy cảm
|
118 |
).sort(sort_criteria).skip(skip).limit(limit)
|
|
|
121 |
user_list = users_cursor.to_list(length=limit)
|
122 |
|
123 |
# Đếm tổng số bản ghi
|
124 |
+
total =await mongo_db.users.count_documents(query)
|
125 |
|
126 |
# Tính toán thông tin phân trang
|
127 |
total_pages = math.ceil(total / limit) if limit > 0 else 0
|
|
|
156 |
dict: Thông tin profile của người dùng
|
157 |
"""
|
158 |
try:
|
159 |
+
user =await mongo_db.users.find_one({"email": email}, {"_id": 0, "password": 0})
|
160 |
logger.info(f"check user user_service: {user}")
|
161 |
if not user:
|
162 |
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Người dùng không tồn tại")
|
|
|
171 |
)
|
172 |
|
173 |
|
174 |
+
async def delete_user(user_id: str):
|
175 |
"""
|
176 |
Xóa người dùng theo ID
|
177 |
|
|
|
182 |
bool: True nếu xóa thành công, False nếu không tìm thấy người dùng
|
183 |
"""
|
184 |
try:
|
185 |
+
result =await mongo_db.users.delete_one({"_id": user_id})
|
186 |
return result.deleted_count > 0
|
187 |
except Exception as e:
|
188 |
logger.error(f"Lỗi khi xóa người dùng: {str(e)}")
|
|
|
191 |
detail=f"Lỗi khi xóa người dùng: {str(e)}"
|
192 |
)
|
193 |
|
194 |
+
async def change_password(email: str, current_password: str, new_password: str):
|
195 |
"""
|
196 |
Đổi mật khẩu của người dùng
|
197 |
|
|
|
204 |
bool: True nếu đổi mật khẩu thành công, False nếu không thành công
|
205 |
"""
|
206 |
try:
|
207 |
+
user =await mongo_db.users.find_one({"email": email})
|
208 |
if not user:
|
209 |
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Người dùng không tồn tại")
|
210 |
|
|
|
216 |
# Hash the new password
|
217 |
hashed_password = pwd_context.hash(new_password)
|
218 |
# Update the password in the database
|
219 |
+
result =await mongo_db.users.update_one({"email": email}, {"$set": {"password": hashed_password}})
|
220 |
return result.modified_count > 0
|
221 |
except HTTPException as he:
|
222 |
raise he
|
|
|
242 |
"""
|
243 |
try:
|
244 |
# Check if user exists
|
245 |
+
user = await mongo_db.users.find_one({"email": email.lower()})
|
246 |
if not user:
|
247 |
# Return True even if user not found to prevent email enumeration
|
248 |
return True
|
249 |
|
250 |
# Check for rate limiting (e.g., max 3 requests per hour)
|
251 |
+
reset_requests = await mongo_db.users.count_documents({
|
252 |
"email": email.lower(),
|
253 |
"reset_password_timestamp": {
|
254 |
"$gte": datetime.now(tz=timezone.utc) - timedelta(hours=1)
|
|
|
265 |
expiry = datetime.now() + timedelta(minutes=10)
|
266 |
|
267 |
# Store reset token and timestamp in database
|
268 |
+
await mongo_db.users.update_one(
|
269 |
{"_id": ObjectId(user["_id"])},
|
270 |
{
|
271 |
"$set": {
|
|
|
312 |
"""
|
313 |
try:
|
314 |
# Find user by reset token
|
315 |
+
user =await mongo_db.users.find_one({"reset_password_code": code})
|
316 |
if not user:
|
317 |
logger.warning(f"Code không hợp lệ: {code}")
|
318 |
return False
|
|
|
334 |
hashed_password = pwd_context.hash(newPassword)
|
335 |
|
336 |
# Update user's password and clear reset token
|
337 |
+
result =await mongo_db.users.update_one(
|
338 |
{"_id": ObjectId(user["_id"])},
|
339 |
{
|
340 |
"$set": {"password": hashed_password},
|
|
|
380 |
expiry = datetime.now() + timedelta(minutes=10)
|
381 |
|
382 |
# Store code and expiry in database
|
383 |
+
result = await mongo_db.users.update_one(
|
384 |
{"email": email.lower()},
|
385 |
{
|
386 |
"$set": {
|
|
|
425 |
HTTPException: Nếu mã không hợp lệ, đã hết hạn hoặc có lỗi hệ thống.
|
426 |
"""
|
427 |
try:
|
428 |
+
user = await mongo_db.users.find_one({ # Sử dụng await nếu mongo_db.users là async (ví dụ Motor)
|
429 |
"email": email.lower(),
|
430 |
"login_verification_code": code
|
431 |
})
|
432 |
+
# Nếu mongo_db.users là đồng bộ (ví dụ PyMongo)
|
433 |
+
# user = mongo_db.users.find_one({ ... })
|
434 |
|
435 |
if not user:
|
436 |
logger.warning(f"Mã xác minh không hợp lệ: {code} cho email: {email}")
|
|
|
443 |
if not expiry or expiry < datetime.now(expiry.tzinfo if expiry.tzinfo else None): # So sánh aware với aware, naive với naive
|
444 |
logger.warning(f"Mã xác minh đã hết hạn cho email: {email}")
|
445 |
# Xóa mã đã hết hạn để tránh sử dụng lại
|
446 |
+
await mongo_db.users.update_one(
|
447 |
{"_id": ObjectId(user["_id"])},
|
448 |
{
|
449 |
"$unset": {
|
|
|
509 |
# --------------------
|
510 |
|
511 |
# Clear verification code và cập nhật last_login
|
512 |
+
await mongo_db.users.update_one( # Sử dụng await nếu là async
|
513 |
{"_id": ObjectId(user["_id"])},
|
514 |
{
|
515 |
"$unset": {
|
|
|
567 |
Raises:
|
568 |
HTTPException: Nếu thông tin đăng nhập không hợp lệ.
|
569 |
"""
|
570 |
+
user = await mongo_db.users.find_one({"email": request.email.lower()})
|
571 |
if not user or not pwd_context.verify(request.password, user["password"]):
|
572 |
logger.warning(f"Xác thực thất bại cho email: {request.email}")
|
573 |
raise HTTPException(
|
|
|
603 |
)
|
604 |
|
605 |
# Find user by refresh token in database
|
606 |
+
user = await mongo_db.users.find_one({"refresh_token": refresh_token})
|
607 |
|
608 |
|
609 |
if not user:
|
|
|
640 |
new_refresh_token = await create_refresh_token(email)
|
641 |
|
642 |
# Update database with new refresh token
|
643 |
+
await mongo_db.users.update_one(
|
644 |
{"_id": user["_id"]},
|
645 |
{
|
646 |
"$set": {
|
|
|
702 |
|
703 |
try:
|
704 |
# Find user by email and code
|
705 |
+
user =await mongo_db.users.find_one({
|
706 |
"email": email.lower(),
|
707 |
"reset_password_code": code
|
708 |
})
|
utils/utils.py
CHANGED
@@ -12,7 +12,7 @@ from jose import jwt
|
|
12 |
from config import SECRET_KEY, ALGORITHM, ACCESS_TOKEN_EXPIRE_MINUTES
|
13 |
from typing import List, Dict, Optional
|
14 |
from unidecode import unidecode
|
15 |
-
from db.mongoDB import
|
16 |
import secrets
|
17 |
from fastapi import HTTPException, status
|
18 |
from langchain_community.chat_message_histories import RedisChatMessageHistory
|
@@ -233,7 +233,7 @@ async def create_refresh_token(email: str) -> str:
|
|
233 |
|
234 |
|
235 |
# Store refresh token in database
|
236 |
-
result =
|
237 |
{"email": email.lower()},
|
238 |
{
|
239 |
"$set": {
|
|
|
12 |
from config import SECRET_KEY, ALGORITHM, ACCESS_TOKEN_EXPIRE_MINUTES
|
13 |
from typing import List, Dict, Optional
|
14 |
from unidecode import unidecode
|
15 |
+
from db.mongoDB import mongo_db
|
16 |
import secrets
|
17 |
from fastapi import HTTPException, status
|
18 |
from langchain_community.chat_message_histories import RedisChatMessageHistory
|
|
|
233 |
|
234 |
|
235 |
# Store refresh token in database
|
236 |
+
result = await mongo_db.users.update_one(
|
237 |
{"email": email.lower()},
|
238 |
{
|
239 |
"$set": {
|