audit_service.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import db
  2. import json
  3. import redis
  4. import config
  5. from typing import Optional, Any
  6. class AuditService:
  7. def __init__(self):
  8. # Redis connection for telegram queue
  9. try:
  10. self.redis_client = redis.Redis(host='localhost', port=6379, decode_responses=True)
  11. except:
  12. self.redis_client = None
  13. def _format_details(self, details: Any) -> str:
  14. if not details:
  15. return ""
  16. if isinstance(details, dict):
  17. lines = []
  18. for k, v in details.items():
  19. lines.append(f"• <b>{k}</b>: {v}")
  20. return "\n" + "\n".join(lines)
  21. return str(details)
  22. def _get_readable_action(self, action: str) -> str:
  23. # Simple mapping for better readability
  24. mapping = {
  25. "warehouse_add_item": "📦 Добавление на склад",
  26. "warehouse_update_item": "📝 Обновление склада",
  27. "warehouse_delete_item": "🗑 Удаление со склада",
  28. "order_status_update": "🔔 Статус заказа изменен",
  29. "user_role_update": "👤 Смена роли пользователя",
  30. "user_register": "🆕 Новая регистрация",
  31. "user_login": "🔑 Вход в систему",
  32. "order_created": "🛒 Новый заказ оформлен",
  33. "order_review": "⭐ Оставлен отзыв",
  34. "update_order": "✏️ Заказ отредактирован",
  35. "delete_order_entirely": "🔥 Заказ полностью удален",
  36. "admin_create_user": "👤 Пользователь создан админом",
  37. "admin_update_user": "✏️ Пользователь отредактирован админом",
  38. "password_reset_success": "🔐 Пароль успешно сброшен",
  39. "upload_order_photo": "📸 Загружено фото заказа",
  40. "update_photo_visibility": "👁️ Изменена видимость фото",
  41. "delete_photo": "🗑️ Удалено фото из портфолио",
  42. "create_material": "🏗️ Создан новый материал",
  43. "update_material": "📝 Изменен материал",
  44. "delete_material": "❌ Удален материал",
  45. "create_service": "🛠️ Создана новая услуга",
  46. "update_service": "📝 Изменена услуга",
  47. "delete_service": "❌ Удалена услуга"
  48. }
  49. return mapping.get(action, action)
  50. async def log(
  51. self,
  52. user_id: int,
  53. action: str,
  54. target_type: Optional[str] = None,
  55. target_id: Optional[int] = None,
  56. details: Optional[Any] = None
  57. ):
  58. details_str = None
  59. if details:
  60. if isinstance(details, (dict, list)):
  61. def decimal_default(obj):
  62. from decimal import Decimal
  63. if isinstance(obj, Decimal):
  64. return float(obj)
  65. return str(obj)
  66. details_str = json.dumps(details, ensure_ascii=False, default=decimal_default)
  67. else:
  68. details_str = str(details)
  69. # 1. Save to DB
  70. query = """
  71. INSERT INTO audit_logs (user_id, action, target_type, target_id, details)
  72. VALUES (%s, %s, %s, %s, %s)
  73. """
  74. db.execute_commit(query, (user_id, action, target_type, target_id, details_str))
  75. # 2. Push to Telegram Queue if CHAT_ID is configured
  76. if config.TELEGRAM_CHAT_ID and self.redis_client:
  77. try:
  78. readable_action = self._get_readable_action(action)
  79. formatted_details = self._format_details(details)
  80. message = f"<b>Audit Log:</b> {readable_action}\n"
  81. if target_type:
  82. message += f"<b>Target:</b> {target_type} (ID: {target_id})\n"
  83. if formatted_details:
  84. message += f"<b>Details:</b>{formatted_details}"
  85. payload = {
  86. "id": config.TELEGRAM_CHAT_ID,
  87. "message": message
  88. }
  89. self.redis_client.rpush("messages_queue", json.dumps(payload, ensure_ascii=False))
  90. except Exception as e:
  91. print(f"FAILED TO PUSH TO TELEGRAM QUEUE: {e}")
  92. audit_service = AuditService()