add submit_qr_points

This commit is contained in:
2025-09-04 10:10:24 +09:00
parent 1698776589
commit 7abdfbe903
3 changed files with 306 additions and 0 deletions

View File

@ -17,6 +17,7 @@ from .views_apis.api_ranking import get_ranking,all_ranking_top3
from .views_apis.api_photos import get_photo_list, get_photo_list_prod, get_team_photos
from .views_apis.s3_views import upload_checkin_image, upload_standard_image, get_standard_image, list_event_images, delete_image
from .views_apis.api_scoreboard import get_scoreboard,download_scoreboard,reprint,make_all_scoreboard,make_cp_list_sheet
from .views_apis.api_qr_points import submit_qr_points, qr_points_status
from .views_apis.api_bulk_upload import bulk_upload_photos, confirm_checkin_validation
from .views_apis.api_admin_validation import get_event_participants_ranking, get_participant_validation_details, get_event_zekken_list
from .views_apis.api_simulator import rogaining_simulator
@ -271,6 +272,10 @@ urlpatterns += [
path('api/routes/gpx-test-data/', gpx_test_data, name='gpx_test_data'),
path('api/routes/available/', available_routes, name='available_routes'),
# QR Points API
path('api/submit_qr_points', submit_qr_points, name='submit_qr_points'),
path('api/qr_points_status', qr_points_status, name='qr_points_status'),
]
if settings.DEBUG:

View File

@ -488,6 +488,27 @@ def checkin_from_rogapp(request):
gps_coordinates = request.data.get('gps_coordinates', {})
camera_metadata = request.data.get('camera_metadata', {})
# 🔍 詳細なパラメータログQRコード問題調査用
logger.info(f"[CHECKIN] 🔍 DETAILED PARAMS - ID: {request_id}")
logger.info(f"[CHECKIN] 📊 Basic params: event_code='{event_code}', team_name='{team_name}', cp_number={cp_number}")
logger.info(f"[CHECKIN] 🖼️ Image params: has_image={bool(image_url)}, image_size={len(image_url) if image_url else 0}, image_type={type(image_url)}")
logger.info(f"[CHECKIN] 🛒 Purchase params: buy_flag={buy_flag} (type: {type(buy_flag)})")
logger.info(f"[CHECKIN] 📱 Client params: user_agent='{user_agent[:100]}...', client_ip='{client_ip}'")
logger.info(f"[CHECKIN] 🔐 Auth params: user_authenticated={request.user.is_authenticated}, user='{user_info}'")
# 全リクエストデータをダンプQRコード問題調査用
try:
import json
request_data_safe = {}
for key, value in request.data.items():
if key == 'image' and value:
request_data_safe[key] = f"[IMAGE_DATA:{len(str(value))}chars]"
else:
request_data_safe[key] = value
logger.info(f"[CHECKIN] 📥 FULL REQUEST DATA: {json.dumps(request_data_safe, ensure_ascii=False, indent=2)}")
except Exception as e:
logger.warning(f"[CHECKIN] Failed to log request data: {e}")
logger.info(f"[CHECKIN] Request parameters - ID: {request_id}, event_code: '{event_code}', team_name: '{team_name}', cp_number: {cp_number}, has_image: {bool(image_url)}, image_size: {len(image_url) if image_url else 0} chars, buy_flag: {buy_flag}, user_agent: '{user_agent[:100]}'")
# GPS座標情報をログに記録

View File

@ -0,0 +1,280 @@
"""
QRコードサービスポイント処理API
このモジュールは、QRコードを使用したサービスポイントの登録・処理を行います。
"""
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status
from rog.models import NewEvent2, Entry, Location2025, GpsCheckin
from django.db import transaction
from django.utils import timezone
from datetime import datetime
import logging
import json
import uuid
logger = logging.getLogger(__name__)
@api_view(['POST'])
def submit_qr_points(request):
"""
QRコードサービスポイント登録API
パラメータ:
- event_code: イベントコード
- team_name: チーム名
- qr_code_data: QRコードデータ
- latitude: 緯度(オプション)
- longitude: 経度(オプション)
- image: 画像データ(オプション)
- cp_number: チェックポイント番号(オプション)
"""
# リクエストIDを生成してログで追跡できるようにする
request_id = str(uuid.uuid4())[:8]
logger.info(f"[QR_SUBMIT] 🚀 Starting QR points submission - ID: {request_id}")
# クライアント情報を取得
user_agent = request.META.get('HTTP_USER_AGENT', 'Unknown')
client_ip = request.META.get('HTTP_X_FORWARDED_FOR') or request.META.get('REMOTE_ADDR', 'Unknown')
user_info = str(request.user) if request.user.is_authenticated else 'Anonymous'
# リクエストからパラメータを取得
event_code = request.data.get('event_code')
team_name = request.data.get('team_name')
qr_code_data = request.data.get('qr_code_data')
latitude = request.data.get('latitude')
longitude = request.data.get('longitude')
image_data = request.data.get('image')
cp_number = request.data.get('cp_number')
# 📊 詳細なパラメータログ
logger.info(f"[QR_SUBMIT] 📊 DETAILED PARAMS - ID: {request_id}")
logger.info(f"[QR_SUBMIT] 🏷️ Basic params: event_code='{event_code}', team_name='{team_name}'")
logger.info(f"[QR_SUBMIT] 📱 QR params: qr_code_data='{qr_code_data}', cp_number={cp_number}")
logger.info(f"[QR_SUBMIT] 🌍 Location params: lat={latitude}, lng={longitude}")
logger.info(f"[QR_SUBMIT] 🖼️ Image params: has_image={bool(image_data)}, image_size={len(str(image_data)) if image_data else 0}")
logger.info(f"[QR_SUBMIT] 📱 Client params: user_agent='{user_agent[:100]}...', client_ip='{client_ip}'")
logger.info(f"[QR_SUBMIT] 🔐 Auth params: user_authenticated={request.user.is_authenticated}, user='{user_info}'")
# 全リクエストデータをダンプ(デバッグ用)
try:
request_data_safe = {}
for key, value in request.data.items():
if key == 'image' and value:
request_data_safe[key] = f"[IMAGE_DATA:{len(str(value))}chars]"
else:
request_data_safe[key] = value
logger.info(f"[QR_SUBMIT] 📥 FULL REQUEST DATA: {json.dumps(request_data_safe, ensure_ascii=False, indent=2)}")
except Exception as e:
logger.warning(f"[QR_SUBMIT] Failed to log request data: {e}")
# パラメータ検証
if not all([event_code, team_name, qr_code_data]):
logger.warning(f"[QR_SUBMIT] ❌ Missing required parameters - ID: {request_id}")
return Response({
"status": "ERROR",
"message": "イベントコード、チーム名、QRコードデータが必要です",
"request_id": request_id
}, status=status.HTTP_400_BAD_REQUEST)
try:
with transaction.atomic():
# イベントの存在確認
event = NewEvent2.objects.filter(event_name=event_code).first()
if not event:
logger.warning(f"[QR_SUBMIT] ❌ Event not found: {event_code} - ID: {request_id}")
return Response({
"status": "ERROR",
"message": f"指定されたイベント '{event_code}' が見つかりません",
"request_id": request_id
}, status=status.HTTP_404_NOT_FOUND)
# チームの存在確認
entry = Entry.objects.filter(
event=event,
team__team_name=team_name
).first()
if not entry:
logger.warning(f"[QR_SUBMIT] ❌ Team not found: {team_name} in event: {event_code} - ID: {request_id}")
return Response({
"status": "ERROR",
"message": f"指定されたチーム '{team_name}' がイベント '{event_code}' に見つかりません",
"request_id": request_id
}, status=status.HTTP_404_NOT_FOUND)
# QRコードデータの解析
try:
if isinstance(qr_code_data, str):
# JSON文字列の場合はパース
if qr_code_data.startswith('{'):
qr_data = json.loads(qr_code_data)
else:
# 単純な文字列の場合
qr_data = {"code": qr_code_data}
else:
qr_data = qr_code_data
logger.info(f"[QR_SUBMIT] 📱 Parsed QR data: {qr_data} - ID: {request_id}")
except json.JSONDecodeError as e:
logger.warning(f"[QR_SUBMIT] ❌ Invalid QR code data format: {e} - ID: {request_id}")
return Response({
"status": "ERROR",
"message": "QRコードデータの形式が正しくありません",
"request_id": request_id
}, status=status.HTTP_400_BAD_REQUEST)
# チェックポイント情報の取得cp_numberが指定されている場合
location = None
if cp_number:
location = Location2025.objects.filter(
event_id=event.id,
cp_number=cp_number
).first()
if location:
logger.info(f"[QR_SUBMIT] 📍 Found location: CP{cp_number} - {location.cp_name} - ID: {request_id}")
else:
logger.warning(f"[QR_SUBMIT] ⚠️ Location not found for CP{cp_number} - ID: {request_id}")
# QRポイント登録処理
current_time = timezone.now()
# GpsCheckinレコードを作成QRコード情報を含む
checkin_data = {
'event': event,
'entry': entry,
'zekken_number': entry.zekken_number,
'cp_number': cp_number or 0, # cp_numberが指定されていない場合は0
'checkin_time': current_time,
'is_service_checked': True, # QRコードはサービスポイントとして扱う
}
# 位置情報が提供されている場合は追加
if latitude and longitude:
checkin_data['latitude'] = float(latitude)
checkin_data['longitude'] = float(longitude)
logger.info(f"[QR_SUBMIT] 🌍 GPS coordinates recorded: {latitude}, {longitude} - ID: {request_id}")
# QRコードデータを格納JSONフィールドがある場合
if hasattr(GpsCheckin, 'qr_code_data'):
checkin_data['qr_code_data'] = qr_data
# 画像データを格納URLまたはパスの場合
if image_data:
if hasattr(GpsCheckin, 'image_url'):
checkin_data['image_url'] = image_data
logger.info(f"[QR_SUBMIT] 🖼️ Image data recorded - ID: {request_id}")
# レコードを作成
gps_checkin = GpsCheckin.objects.create(**checkin_data)
# ポイント計算
point_value = 0
if location:
point_value = location.cp_point or 0
# 成功レスポンス
response_data = {
"status": "OK",
"message": "QRコードサービスポイントが正常に登録されました",
"request_id": request_id,
"data": {
"event_code": event_code,
"team_name": team_name,
"zekken_number": entry.zekken_number,
"cp_number": cp_number,
"point_value": point_value,
"checkin_time": current_time.isoformat(),
"qr_code_processed": True,
"has_location": bool(latitude and longitude),
"has_image": bool(image_data),
"checkin_id": gps_checkin.id if gps_checkin else None
}
}
logger.info(f"[QR_SUBMIT] ✅ SUCCESS - Team: {team_name}, Zekken: {entry.zekken_number}, CP: {cp_number}, Points: {point_value}, QR: {bool(qr_code_data)}, Client IP: {client_ip}, User: {user_info} - ID: {request_id}")
return Response(response_data, status=status.HTTP_200_OK)
except Exception as e:
logger.error(f"[QR_SUBMIT] ❌ EXCEPTION - ID: {request_id}, Error: {str(e)}", exc_info=True)
return Response({
"status": "ERROR",
"message": "QRコードサービスポイント処理中にエラーが発生しました",
"request_id": request_id,
"error_detail": str(e) if logger.getEffectiveLevel() <= logging.DEBUG else None
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
@api_view(['GET'])
def qr_points_status(request):
"""
QRポイント処理状況確認API
パラメータ:
- event_code: イベントコード
- team_name: チーム名(オプション)
"""
event_code = request.query_params.get('event_code')
team_name = request.query_params.get('team_name')
logger.info(f"[QR_STATUS] QR points status check - event: {event_code}, team: {team_name}")
if not event_code:
return Response({
"status": "ERROR",
"message": "イベントコードが必要です"
}, status=status.HTTP_400_BAD_REQUEST)
try:
# イベントの存在確認
event = NewEvent2.objects.filter(event_name=event_code).first()
if not event:
return Response({
"status": "ERROR",
"message": f"指定されたイベント '{event_code}' が見つかりません"
}, status=status.HTTP_404_NOT_FOUND)
# QRコード関連のチェックイン状況を取得
query = GpsCheckin.objects.filter(event=event, is_service_checked=True)
if team_name:
query = query.filter(entry__team__team_name=team_name)
qr_checkins = query.order_by('-checkin_time')[:50] # 最新50件
checkin_list = []
for checkin in qr_checkins:
checkin_list.append({
"checkin_id": checkin.id,
"team_name": checkin.entry.team.team_name,
"zekken_number": checkin.zekken_number,
"cp_number": checkin.cp_number,
"checkin_time": checkin.checkin_time.isoformat(),
"has_qr_data": hasattr(checkin, 'qr_code_data') and bool(checkin.qr_code_data),
"has_location": bool(checkin.latitude and checkin.longitude),
"is_service_checked": checkin.is_service_checked
})
return Response({
"status": "OK",
"message": "QRポイント状況を取得しました",
"data": {
"event_code": event_code,
"total_count": len(checkin_list),
"checkins": checkin_list
}
}, status=status.HTTP_200_OK)
except Exception as e:
logger.error(f"[QR_STATUS] Error getting QR points status: {str(e)}", exc_info=True)
return Response({
"status": "ERROR",
"message": "QRポイント状況取得中にエラーが発生しました",
"error_detail": str(e) if logger.getEffectiveLevel() <= logging.DEBUG else None
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)