Spaces:
Sleeping
Sleeping
File size: 10,513 Bytes
8275526 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 |
import os
import datetime
from pymongo import MongoClient
from bson.objectid import ObjectId
import logging
from dotenv import load_dotenv
# Cấu hình logging
logger = logging.getLogger(__name__)
# Tải biến môi trường
load_dotenv()
# Kết nối MongoDB
MONGO_URI = os.getenv("MONGO_URI", "mongodb://localhost:27017/")
DATABASE_NAME = os.getenv("MONGO_DB_NAME", "nutribot_db")
# Singleton pattern cho kết nối MongoDB
_mongo_client = None
_db = None
def get_db():
"""Trả về instance của MongoDB database (singleton pattern)"""
global _mongo_client, _db
if _mongo_client is None:
try:
_mongo_client = MongoClient(MONGO_URI)
_db = _mongo_client[DATABASE_NAME]
logger.info(f"Đã kết nối đến database: {DATABASE_NAME}")
except Exception as e:
logger.error(f"Lỗi kết nối MongoDB: {e}")
raise
return _db
def ensure_indexes():
"""Tạo các index cần thiết cho feedback collection"""
try:
db = get_db()
feedback_collection = db.feedback
# Index cho user_id
feedback_collection.create_index("user_id")
# Index cho status
feedback_collection.create_index("status")
# Index cho category
feedback_collection.create_index("category")
# Index cho created_at (để sắp xếp)
feedback_collection.create_index([("created_at", -1)])
logger.info("Đã tạo indexes cho feedback collection")
except Exception as e:
logger.error(f"Lỗi tạo indexes: {e}")
class Feedback:
def __init__(self, user_id=None, rating=5, category='', title='', content='',
status='pending', admin_response='', created_at=None, updated_at=None,
feedback_id=None):
self.feedback_id = feedback_id
self.user_id = user_id
self.rating = rating
self.category = category
self.title = title
self.content = content
self.status = status # pending, reviewed, resolved
self.admin_response = admin_response
self.created_at = created_at or datetime.datetime.now()
self.updated_at = updated_at or datetime.datetime.now()
def to_dict(self):
"""Chuyển đổi thông tin feedback thành dictionary"""
feedback_dict = {
"user_id": self.user_id,
"rating": self.rating,
"category": self.category,
"title": self.title,
"content": self.content,
"status": self.status,
"admin_response": self.admin_response,
"created_at": self.created_at,
"updated_at": self.updated_at
}
if self.feedback_id:
feedback_dict["_id"] = self.feedback_id
return feedback_dict
@classmethod
def from_dict(cls, feedback_dict):
"""Tạo đối tượng Feedback từ dictionary"""
if not feedback_dict:
return None
return cls(
feedback_id=feedback_dict.get("_id"),
user_id=feedback_dict.get("user_id"),
rating=feedback_dict.get("rating", 5),
category=feedback_dict.get("category", ""),
title=feedback_dict.get("title", ""),
content=feedback_dict.get("content", ""),
status=feedback_dict.get("status", "pending"),
admin_response=feedback_dict.get("admin_response", ""),
created_at=feedback_dict.get("created_at"),
updated_at=feedback_dict.get("updated_at")
)
def save(self):
"""Lưu thông tin feedback vào database"""
try:
db = get_db()
feedback_collection = db.feedback
self.updated_at = datetime.datetime.now()
if not self.feedback_id:
insert_result = feedback_collection.insert_one(self.to_dict())
self.feedback_id = insert_result.inserted_id
logger.info(f"Đã tạo feedback mới với ID: {self.feedback_id}")
return self.feedback_id
else:
feedback_collection.update_one(
{"_id": self.feedback_id},
{"$set": self.to_dict()}
)
logger.info(f"Đã cập nhật feedback: {self.feedback_id}")
return self.feedback_id
except Exception as e:
logger.error(f"Lỗi khi lưu feedback: {e}")
raise
@classmethod
def find_by_id(cls, feedback_id):
"""Tìm feedback theo ID"""
try:
db = get_db()
feedback_collection = db.feedback
if isinstance(feedback_id, str):
feedback_id = ObjectId(feedback_id)
feedback_dict = feedback_collection.find_one({"_id": feedback_id})
if feedback_dict:
return cls.from_dict(feedback_dict)
return None
except Exception as e:
logger.error(f"Lỗi khi tìm feedback: {e}")
return None
@classmethod
def find_by_user(cls, user_id, limit=10, skip=0):
"""Tìm feedback theo user_id"""
try:
db = get_db()
feedback_collection = db.feedback
if isinstance(user_id, str):
user_id = ObjectId(user_id)
feedbacks_cursor = feedback_collection.find({"user_id": user_id})\
.sort("created_at", -1)\
.skip(skip)\
.limit(limit)
result = []
for feedback_dict in feedbacks_cursor:
feedback_obj = cls.from_dict(feedback_dict)
if feedback_obj:
result.append(feedback_obj)
return result
except Exception as e:
logger.error(f"Lỗi tìm feedback theo user: {e}")
return []
@classmethod
def get_all_for_admin(cls, limit=20, skip=0, status_filter=None):
"""Lấy tất cả feedback cho admin với join user info"""
try:
db = get_db()
feedback_collection = db.feedback
# Tạo query filter
query_filter = {}
if status_filter:
query_filter["status"] = status_filter
# Aggregate để join với user collection
pipeline = [
{"$match": query_filter},
{
"$lookup": {
"from": "users",
"localField": "user_id",
"foreignField": "_id",
"as": "user_info"
}
},
{"$sort": {"created_at": -1}},
{"$skip": skip},
{"$limit": limit}
]
result = []
for feedback_doc in feedback_collection.aggregate(pipeline):
feedback = cls.from_dict(feedback_doc)
# Thêm thông tin user nếu có
if feedback and feedback_doc.get("user_info"):
user_info = feedback_doc["user_info"][0]
feedback.user_name = user_info.get("name", "Ẩn danh")
feedback.user_email = user_info.get("email", "")
else:
feedback.user_name = "Ẩn danh"
feedback.user_email = ""
result.append(feedback)
return result
except Exception as e:
logger.error(f"Lỗi lấy feedback cho admin: {e}")
return []
def update_admin_response(self, response, status):
"""Cập nhật phản hồi từ admin"""
try:
self.admin_response = response
self.status = status
self.save()
return True
except Exception as e:
logger.error(f"Lỗi cập nhật admin response: {e}")
return False
@staticmethod
def get_stats():
"""Lấy thống kê về feedback"""
try:
db = get_db()
feedback_collection = db.feedback
# Tổng số feedback
total_feedback = feedback_collection.count_documents({})
# Feedback pending
pending_feedback = feedback_collection.count_documents({"status": "pending"})
# Feedback trong tháng này
now = datetime.datetime.now()
month_start = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
this_month_feedback = feedback_collection.count_documents({
"created_at": {"$gte": month_start}
})
# Đánh giá trung bình
pipeline = [
{"$group": {"_id": None, "avg_rating": {"$avg": "$rating"}}}
]
rating_result = list(feedback_collection.aggregate(pipeline))
average_rating = rating_result[0]["avg_rating"] if rating_result else 0
return {
"total_feedback": total_feedback,
"pending_feedback": pending_feedback,
"this_month_feedback": this_month_feedback,
"average_rating": average_rating
}
except Exception as e:
logger.error(f"Lỗi lấy thống kê feedback: {e}")
return {
"total_feedback": 0,
"pending_feedback": 0,
"this_month_feedback": 0,
"average_rating": 0
}
@staticmethod
def create_feedback(user_id, rating, category, title, content):
"""Tạo feedback mới"""
try:
feedback = Feedback(
user_id=ObjectId(user_id) if isinstance(user_id, str) else user_id,
rating=rating,
category=category,
title=title,
content=content
)
feedback_id = feedback.save()
return True, {"feedback_id": str(feedback_id)}
except Exception as e:
logger.error(f"Lỗi tạo feedback: {e}")
return False, str(e) |