Fix some APIs
This commit is contained in:
160
rog/views_apis/api_approval.py
Normal file
160
rog/views_apis/api_approval.py
Normal file
@ -0,0 +1,160 @@
|
||||
"""
|
||||
通過履歴承認API
|
||||
ユーザーが自分のチームの通過履歴を確認し、承認確定する処理を行う
|
||||
"""
|
||||
|
||||
import logging
|
||||
import uuid
|
||||
from django.http import JsonResponse
|
||||
from django.utils import timezone
|
||||
from django.db import transaction
|
||||
from rest_framework.decorators import api_view, permission_classes
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
from rest_framework import status
|
||||
from knox.auth import TokenAuthentication
|
||||
|
||||
from ..models import NewEvent2, Entry, GpsLog
|
||||
|
||||
# ログ設定
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@api_view(['POST'])
|
||||
@permission_classes([IsAuthenticated])
|
||||
def approve_checkin_history(request):
|
||||
"""
|
||||
ユーザーがアプリ上で通過履歴を確認し、承認確定する処理
|
||||
|
||||
パラメータ:
|
||||
- event_code: イベントコード (必須)
|
||||
- zekken_number: ゼッケン番号 (必須)
|
||||
- checkin_ids: 承認するチェックインIDのリスト (必須)
|
||||
- approval_comment: 承認コメント (任意)
|
||||
"""
|
||||
|
||||
# リクエストID生成(デバッグ用)
|
||||
request_id = str(uuid.uuid4())[:8]
|
||||
client_ip = request.META.get('HTTP_X_FORWARDED_FOR', request.META.get('REMOTE_ADDR', 'Unknown'))
|
||||
|
||||
logger.info(f"[APPROVE_CHECKIN] 🎯 API call started - ID: {request_id}, User: {request.user.email if request.user.is_authenticated else 'Anonymous'}, Client IP: {client_ip}")
|
||||
|
||||
try:
|
||||
# リクエストデータの取得
|
||||
data = request.data
|
||||
event_code = data.get('event_code')
|
||||
zekken_number = data.get('zekken_number')
|
||||
checkin_ids = data.get('checkin_ids', [])
|
||||
approval_comment = data.get('approval_comment', '')
|
||||
|
||||
logger.info(f"[APPROVE_CHECKIN] 📝 Request data - ID: {request_id}, event_code: '{event_code}', zekken_number: '{zekken_number}', checkin_ids: {checkin_ids}")
|
||||
|
||||
# 必須パラメータの検証
|
||||
if not all([event_code, zekken_number, checkin_ids]):
|
||||
logger.warning(f"[APPROVE_CHECKIN] ❌ Missing required parameters - ID: {request_id}")
|
||||
return Response({
|
||||
"status": "ERROR",
|
||||
"message": "イベントコード、ゼッケン番号、チェックインIDが必要です"
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
if not isinstance(checkin_ids, list) or len(checkin_ids) == 0:
|
||||
logger.warning(f"[APPROVE_CHECKIN] ❌ Invalid checkin_ids format - ID: {request_id}")
|
||||
return Response({
|
||||
"status": "ERROR",
|
||||
"message": "チェックインIDは空でない配列で指定してください"
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# イベントの存在確認
|
||||
event = NewEvent2.objects.filter(event_name=event_code).first()
|
||||
if not event:
|
||||
logger.warning(f"[APPROVE_CHECKIN] ❌ Event not found - ID: {request_id}, event_code: '{event_code}'")
|
||||
return Response({
|
||||
"status": "ERROR",
|
||||
"message": "指定されたイベントが見つかりません"
|
||||
}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
logger.info(f"[APPROVE_CHECKIN] ✅ Event found - ID: {request_id}, event: '{event_code}', event_id: {event.id}")
|
||||
|
||||
# チームの存在確認とオーナー権限の検証
|
||||
entry = Entry.objects.filter(
|
||||
event=event,
|
||||
team__zekken_number=zekken_number
|
||||
).first()
|
||||
|
||||
if not entry:
|
||||
logger.warning(f"[APPROVE_CHECKIN] ❌ Team not found - ID: {request_id}, zekken_number: '{zekken_number}', event_code: '{event_code}'")
|
||||
return Response({
|
||||
"status": "ERROR",
|
||||
"message": "指定されたゼッケン番号のチームが見つかりません"
|
||||
}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
logger.info(f"[APPROVE_CHECKIN] ✅ Team found - ID: {request_id}, team_name: '{entry.team.team_name}', zekken: {zekken_number}, entry_id: {entry.id}")
|
||||
|
||||
# オーナー権限の確認
|
||||
if entry.owner != request.user:
|
||||
logger.warning(f"[APPROVE_CHECKIN] ❌ Permission denied - ID: {request_id}, user: {request.user.email}, team_owner: {entry.owner.email}")
|
||||
return Response({
|
||||
"status": "ERROR",
|
||||
"message": "このチームの通過履歴を承認する権限がありません"
|
||||
}, status=status.HTTP_403_FORBIDDEN)
|
||||
|
||||
# 指定されたチェックインIDの存在確認
|
||||
existing_checkins = GpsLog.objects.filter(
|
||||
id__in=checkin_ids,
|
||||
zekken_number=zekken_number,
|
||||
event_code=event_code
|
||||
)
|
||||
|
||||
existing_ids = list(existing_checkins.values_list('id', flat=True))
|
||||
invalid_ids = [cid for cid in checkin_ids if cid not in existing_ids]
|
||||
|
||||
if invalid_ids:
|
||||
logger.warning(f"[APPROVE_CHECKIN] ⚠️ Invalid checkin IDs found - ID: {request_id}, invalid_ids: {invalid_ids}, valid_ids: {existing_ids}")
|
||||
return Response({
|
||||
"status": "ERROR",
|
||||
"message": "指定されたチェックイン記録が見つかりません",
|
||||
"error_details": {
|
||||
"invalid_checkin_ids": invalid_ids,
|
||||
"valid_checkin_ids": existing_ids
|
||||
}
|
||||
}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
logger.info(f"[APPROVE_CHECKIN] ✅ All checkin IDs validated - ID: {request_id}, count: {len(existing_ids)}")
|
||||
|
||||
# 承認処理(現時点ではACK応答のみ)
|
||||
# TODO: 実際のDB更新処理をここに実装
|
||||
# - validation_statusの更新
|
||||
# - approval_commentの保存
|
||||
# - approved_atタイムスタンプの設定
|
||||
# - approved_byユーザーの記録
|
||||
|
||||
approval_time = timezone.now()
|
||||
approved_checkins = []
|
||||
|
||||
for checkin in existing_checkins:
|
||||
approved_checkins.append({
|
||||
"checkin_id": checkin.id,
|
||||
"cp_number": checkin.cp_number,
|
||||
"approved_at": approval_time.strftime("%Y-%m-%d %H:%M:%S")
|
||||
})
|
||||
|
||||
logger.info(f"[APPROVE_CHECKIN] ✅ Approval completed - ID: {request_id}, approved_count: {len(approved_checkins)}, comment: '{approval_comment[:50]}...' if len(approval_comment) > 50 else approval_comment")
|
||||
|
||||
# 成功レスポンス
|
||||
return Response({
|
||||
"status": "OK",
|
||||
"message": "通過履歴の承認が完了しました",
|
||||
"approved_count": len(approved_checkins),
|
||||
"approved_checkins": approved_checkins,
|
||||
"team_info": {
|
||||
"team_name": entry.team.team_name,
|
||||
"zekken_number": zekken_number,
|
||||
"event_code": event_code
|
||||
}
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"[APPROVE_CHECKIN] 💥 Unexpected error - ID: {request_id}, error: {str(e)}", exc_info=True)
|
||||
return Response({
|
||||
"status": "ERROR",
|
||||
"message": "サーバーエラーが発生しました"
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
Reference in New Issue
Block a user