fix: fix delete email issue
This commit is contained in:
@@ -14,86 +14,6 @@ class EmailNotificationMiddleware(MiddlewareMixin):
|
|||||||
def __init__(self, get_response):
|
def __init__(self, get_response):
|
||||||
self.get_response = get_response
|
self.get_response = get_response
|
||||||
super().__init__(get_response)
|
super().__init__(get_response)
|
||||||
# 用于存储删除前的数据
|
|
||||||
self._delete_data_cache = {}
|
|
||||||
|
|
||||||
def process_request(self, request):
|
|
||||||
"""在处理请求前,如果是删除操作,先获取要删除的数据"""
|
|
||||||
try:
|
|
||||||
# 只处理DELETE操作
|
|
||||||
if request.method != 'DELETE':
|
|
||||||
return None
|
|
||||||
|
|
||||||
# 只处理API请求
|
|
||||||
if not request.path.startswith('/api/'):
|
|
||||||
return None
|
|
||||||
|
|
||||||
# 从URL路径中提取ID
|
|
||||||
path_parts = request.path.split('/')
|
|
||||||
record_id = None
|
|
||||||
for part in path_parts:
|
|
||||||
if part.isdigit():
|
|
||||||
record_id = part
|
|
||||||
break
|
|
||||||
|
|
||||||
if not record_id:
|
|
||||||
return None
|
|
||||||
|
|
||||||
# 根据路径类型获取对应的数据
|
|
||||||
if '/api/items/' in request.path:
|
|
||||||
data = self._get_item_data_before_delete(record_id)
|
|
||||||
if data:
|
|
||||||
self._delete_data_cache[f"item_{record_id}"] = data
|
|
||||||
elif '/api/records/' in request.path or '/api/finance/' in request.path:
|
|
||||||
data = self._get_finance_data_before_delete(record_id)
|
|
||||||
if data:
|
|
||||||
self._delete_data_cache[f"finance_{record_id}"] = data
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"获取删除前数据失败: {e}")
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def _get_item_data_before_delete(self, item_id):
|
|
||||||
"""获取物品删除前的数据"""
|
|
||||||
try:
|
|
||||||
from items.models import Item
|
|
||||||
item = Item.objects.get(id=item_id)
|
|
||||||
return {
|
|
||||||
'id': item.id,
|
|
||||||
'name': item.name,
|
|
||||||
'serial_number': item.serial_number,
|
|
||||||
'status': item.status,
|
|
||||||
'category': item.category,
|
|
||||||
'owner': item.owner,
|
|
||||||
'purchase_date': str(item.purchase_date) if item.purchase_date else '',
|
|
||||||
'purchase_price': str(item.purchase_price) if item.purchase_price else '',
|
|
||||||
'description': item.description,
|
|
||||||
'updated_at': str(item.updated_at) if hasattr(item, 'updated_at') else '',
|
|
||||||
}
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"获取物品数据失败: {e}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
def _get_finance_data_before_delete(self, record_id):
|
|
||||||
"""获取财务记录删除前的数据"""
|
|
||||||
try:
|
|
||||||
from finance.models import FinanceRecord
|
|
||||||
record = FinanceRecord.objects.get(id=record_id)
|
|
||||||
return {
|
|
||||||
'id': record.id,
|
|
||||||
'amount': str(record.amount),
|
|
||||||
'transaction_type': record.transaction_type,
|
|
||||||
'description': record.description,
|
|
||||||
'department': record.department.name if record.department else '',
|
|
||||||
'category': record.category.name if record.category else '',
|
|
||||||
'approver': record.approver,
|
|
||||||
'transaction_date': str(record.transaction_date),
|
|
||||||
'proof_images': [str(img.image) for img in record.proof_images.all()] if hasattr(record, 'proof_images') else []
|
|
||||||
}
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"获取财务记录数据失败: {e}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
def process_response(self, request, response):
|
def process_response(self, request, response):
|
||||||
"""处理响应,在数据修改操作成功后异步发送邮件通知"""
|
"""处理响应,在数据修改操作成功后异步发送邮件通知"""
|
||||||
@@ -102,8 +22,8 @@ class EmailNotificationMiddleware(MiddlewareMixin):
|
|||||||
if not request.path.startswith('/api/'):
|
if not request.path.startswith('/api/'):
|
||||||
return response
|
return response
|
||||||
|
|
||||||
# 只处理数据修改操作
|
# 只处理数据新增修改操作,但排除DELETE操作,毕竟删除操作已经另外重写
|
||||||
if request.method not in ['POST', 'PUT', 'PATCH', 'DELETE']:
|
if request.method not in ['POST', 'PUT', 'PATCH']:
|
||||||
return response
|
return response
|
||||||
|
|
||||||
# 只处理成功的响应
|
# 只处理成功的响应
|
||||||
@@ -149,34 +69,6 @@ class EmailNotificationMiddleware(MiddlewareMixin):
|
|||||||
try:
|
try:
|
||||||
operation_type = self._get_operation_type(request.method, request.path)
|
operation_type = self._get_operation_type(request.method, request.path)
|
||||||
|
|
||||||
# 对于DELETE操作,使用预先获取的数据
|
|
||||||
if request.method == 'DELETE':
|
|
||||||
# 从URL路径中提取ID
|
|
||||||
path_parts = request.path.split('/')
|
|
||||||
item_id = None
|
|
||||||
for part in path_parts:
|
|
||||||
if part.isdigit():
|
|
||||||
item_id = part
|
|
||||||
break
|
|
||||||
|
|
||||||
# 尝试从缓存中获取删除前的数据
|
|
||||||
cached_data = self._delete_data_cache.get(f"item_{item_id}")
|
|
||||||
if cached_data:
|
|
||||||
notification_data = {
|
|
||||||
'id': cached_data.get('id', item_id),
|
|
||||||
'name': f"[已删除] {cached_data.get('name', '未知物品')}",
|
|
||||||
'serial_number': cached_data.get('serial_number', ''),
|
|
||||||
'status': f"[删除前状态: {cached_data.get('status', '未知')}]",
|
|
||||||
'category': cached_data.get('category', ''),
|
|
||||||
'owner': cached_data.get('owner', ''),
|
|
||||||
'purchase_date': cached_data.get('purchase_date', ''),
|
|
||||||
'purchase_price': cached_data.get('purchase_price', ''),
|
|
||||||
'description': f"删除前描述: {cached_data.get('description', '')}",
|
|
||||||
'timestamp': cached_data.get('updated_at', ''),
|
|
||||||
'operation_path': request.path,
|
|
||||||
'operation_method': request.method
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
# 尝试从响应中获取数据
|
# 尝试从响应中获取数据
|
||||||
if hasattr(response, 'data'):
|
if hasattr(response, 'data'):
|
||||||
item_data = response.data
|
item_data = response.data
|
||||||
@@ -209,7 +101,7 @@ class EmailNotificationMiddleware(MiddlewareMixin):
|
|||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"异步处理物品操作通知失败: {e} 如果需要查看删除前的数据,请检查以前的邮件。")
|
logger.error(f"异步处理物品操作通知失败: {e}")
|
||||||
|
|
||||||
# 创建并启动后台线程
|
# 创建并启动后台线程
|
||||||
thread = threading.Thread(target=send_notification)
|
thread = threading.Thread(target=send_notification)
|
||||||
@@ -222,29 +114,6 @@ class EmailNotificationMiddleware(MiddlewareMixin):
|
|||||||
try:
|
try:
|
||||||
operation_type = self._get_operation_type(request.method, request.path)
|
operation_type = self._get_operation_type(request.method, request.path)
|
||||||
|
|
||||||
# 对于DELETE操作,响应通常不包含数据,需要从URL路径中提取ID
|
|
||||||
if request.method == 'DELETE':
|
|
||||||
# 从URL路径中提取ID
|
|
||||||
path_parts = request.path.split('/')
|
|
||||||
record_id = None
|
|
||||||
for part in path_parts:
|
|
||||||
if part.isdigit():
|
|
||||||
record_id = part
|
|
||||||
break
|
|
||||||
|
|
||||||
notification_data = {
|
|
||||||
'id': record_id or '未知',
|
|
||||||
'amount': '已删除记录',
|
|
||||||
'transaction_type': '已删除',
|
|
||||||
'description': '财务记录已被删除',
|
|
||||||
'department': '未知',
|
|
||||||
'category': '未知',
|
|
||||||
'approver': '未知',
|
|
||||||
'timestamp': '删除时间未知',
|
|
||||||
'operation_path': request.path,
|
|
||||||
'operation_method': request.method
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
# 尝试从响应中获取数据
|
# 尝试从响应中获取数据
|
||||||
if hasattr(response, 'data'):
|
if hasattr(response, 'data'):
|
||||||
finance_data = response.data
|
finance_data = response.data
|
||||||
@@ -278,7 +147,7 @@ class EmailNotificationMiddleware(MiddlewareMixin):
|
|||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"异步处理财务操作通知失败: {e} 如果需要查看删除前的数据,请检查以前的邮件。")
|
logger.error(f"异步处理财务操作通知失败: {e}")
|
||||||
|
|
||||||
# 创建并启动后台线程
|
# 创建并启动后台线程
|
||||||
thread = threading.Thread(target=send_notification)
|
thread = threading.Thread(target=send_notification)
|
||||||
@@ -291,7 +160,5 @@ class EmailNotificationMiddleware(MiddlewareMixin):
|
|||||||
return 'CREATE'
|
return 'CREATE'
|
||||||
elif method in ['PUT', 'PATCH']:
|
elif method in ['PUT', 'PATCH']:
|
||||||
return 'UPDATE'
|
return 'UPDATE'
|
||||||
elif method == 'DELETE':
|
|
||||||
return 'DELETE'
|
|
||||||
else:
|
else:
|
||||||
return 'UNKNOWN'
|
return 'UNKNOWN'
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import os
|
import os
|
||||||
|
import threading
|
||||||
from rest_framework import viewsets, status
|
from rest_framework import viewsets, status
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
from django.utils import timezone
|
||||||
from .models import FinancialRecord, Department, Category, ProofImage
|
from .models import FinancialRecord, Department, Category, ProofImage
|
||||||
from .serializers import (
|
from .serializers import (
|
||||||
FinancialRecordWriteSerializer,
|
FinancialRecordWriteSerializer,
|
||||||
@@ -23,6 +25,102 @@ class FinancialRecordViewSet(viewsets.ModelViewSet):
|
|||||||
return FinancialRecordReadSerializer
|
return FinancialRecordReadSerializer
|
||||||
return FinancialRecordWriteSerializer
|
return FinancialRecordWriteSerializer
|
||||||
|
|
||||||
|
def _get_user_info(self, request):
|
||||||
|
"""获取用户信息"""
|
||||||
|
try:
|
||||||
|
if hasattr(request, 'user') and request.user.is_authenticated:
|
||||||
|
return f"{request.user.username} ({request.user.email})"
|
||||||
|
else:
|
||||||
|
return f"匿名用户 (IP: {self._get_client_ip(request)})"
|
||||||
|
except:
|
||||||
|
return "未知用户"
|
||||||
|
|
||||||
|
def _get_client_ip(self, request):
|
||||||
|
"""获取客户端IP"""
|
||||||
|
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
|
||||||
|
if x_forwarded_for:
|
||||||
|
ip = x_forwarded_for.split(',')[0]
|
||||||
|
else:
|
||||||
|
ip = request.META.get('REMOTE_ADDR')
|
||||||
|
return ip
|
||||||
|
|
||||||
|
def destroy(self, request, *args, **kwargs):
|
||||||
|
"""删除方法,删除并发送邮件通知"""
|
||||||
|
instance = self.get_object()
|
||||||
|
|
||||||
|
# 获取记录信息用于邮件通知
|
||||||
|
record_id = instance.id
|
||||||
|
record_info = {
|
||||||
|
'title': instance.title,
|
||||||
|
'amount': str(instance.amount),
|
||||||
|
'description': instance.description,
|
||||||
|
'record_type': instance.record_type,
|
||||||
|
'transaction_date': str(instance.transaction_date),
|
||||||
|
'department': instance.department.name if instance.department else '',
|
||||||
|
'category': instance.category.name if instance.category else '',
|
||||||
|
'fund_manager': instance.fund_manager if hasattr(instance, 'fund_manager') else ''
|
||||||
|
}
|
||||||
|
|
||||||
|
# 删除关联的凭证图片文件
|
||||||
|
proof_images = ProofImage.objects.filter(financial_record=instance)
|
||||||
|
for proof_image in proof_images:
|
||||||
|
if proof_image.image:
|
||||||
|
try:
|
||||||
|
file_path = proof_image.image.path
|
||||||
|
if os.path.isfile(file_path):
|
||||||
|
os.remove(file_path)
|
||||||
|
print(f"成功删除凭证文件 {file_path}")
|
||||||
|
except (ValueError, AttributeError, OSError) as e:
|
||||||
|
print(f"删除凭证文件失败 {e}")
|
||||||
|
|
||||||
|
# 立即删除财务记录(会级联删除相关的凭证图片记录)
|
||||||
|
super().destroy(request, *args, **kwargs)
|
||||||
|
|
||||||
|
# 异步发送删除通知邮件
|
||||||
|
def send_delete_notification():
|
||||||
|
"""异步发送删除通知邮件"""
|
||||||
|
try:
|
||||||
|
from email_notice.services import EmailNotificationService
|
||||||
|
|
||||||
|
# 获取用户信息
|
||||||
|
user_info = self._get_user_info(request)
|
||||||
|
|
||||||
|
# 构建邮件通知数据
|
||||||
|
notification_data = {
|
||||||
|
'id': record_id,
|
||||||
|
'title': f"[已删除] {record_info['title']}",
|
||||||
|
'amount': record_info['amount'],
|
||||||
|
'record_type': record_info['record_type'],
|
||||||
|
'description': record_info['description'],
|
||||||
|
'department': record_info['department'],
|
||||||
|
'category': record_info['category'],
|
||||||
|
'fund_manager': record_info['fund_manager'],
|
||||||
|
'transaction_date': record_info['transaction_date'],
|
||||||
|
'deleted_at': timezone.now().isoformat(),
|
||||||
|
'operation_path': request.path,
|
||||||
|
'operation_method': request.method
|
||||||
|
}
|
||||||
|
|
||||||
|
# 发送删除通知邮件
|
||||||
|
EmailNotificationService.send_operation_notification(
|
||||||
|
'DELETE', '财务记录', notification_data, user_info
|
||||||
|
)
|
||||||
|
print(f"删除通知邮件已发送: 财务记录 ID:{record_id}, 标题:{record_info['title']}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"发送删除通知邮件失败: {e}")
|
||||||
|
|
||||||
|
# 启动异步邮件发送线程
|
||||||
|
email_thread = threading.Thread(target=send_delete_notification)
|
||||||
|
email_thread.daemon = True
|
||||||
|
email_thread.start()
|
||||||
|
|
||||||
|
# 返回删除成功响应
|
||||||
|
return Response({
|
||||||
|
'message': f'财务记录 "{record_info["title"]}" 已成功删除,删除通知邮件正在发送',
|
||||||
|
'deleted_record_info': record_info
|
||||||
|
}, status=status.HTTP_200_OK)
|
||||||
|
|
||||||
@action(detail=True, methods=['post'])
|
@action(detail=True, methods=['post'])
|
||||||
def upload_images(self, request, pk=None):
|
def upload_images(self, request, pk=None):
|
||||||
"""为财务记录上传多张凭证图片"""
|
"""为财务记录上传多张凭证图片"""
|
||||||
|
|||||||
Reference in New Issue
Block a user