almost finish migrate new circumstances
This commit is contained in:
239
rog/views_apis/api_photos_fixed.py
Normal file
239
rog/views_apis/api_photos_fixed.py
Normal file
@ -0,0 +1,239 @@
|
||||
# 既存のインポート部分に追加
|
||||
from rest_framework.decorators import api_view
|
||||
from rest_framework.response import Response
|
||||
from rest_framework import status
|
||||
from rog.models import NewEvent2, Entry, GpsCheckin, Team
|
||||
import logging
|
||||
from django.db.models import F, Q
|
||||
from django.conf import settings
|
||||
import os
|
||||
from urllib.parse import urljoin
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
"""
|
||||
解説
|
||||
この実装では以下の処理を行っています:
|
||||
|
||||
1.2つのエンドポイントを提供しています:
|
||||
- /get_photo_list - 認証なしで写真とレポートURLを取得
|
||||
- /get_photo_list_prod - パスワード認証付きで同じ情報を取得
|
||||
2.共通のロジックは get_team_photos 関数に集約し、以下の情報を取得します:
|
||||
- チームの基本情報(名前、ゼッケン番号、クラス名)
|
||||
- チェックポイント通過時の写真(時間順、サービスチェック情報含む)
|
||||
- スタート写真とゴール写真(あれば)
|
||||
- チームレポートのURL(存在する場合)
|
||||
- スコアボードのURL(存在する場合)
|
||||
- チームのスコア(ゴール済みの場合)
|
||||
3.レポートとスコアボードのファイルパスを実際に確認し、存在する場合のみURLを提供します
|
||||
4.写真の表示順はスタート→チェックポイント(時間順)→ゴールとなっており、チェックポイントについてはそれぞれ番号、撮影時間、サービスチェック状態などの情報も含めています
|
||||
|
||||
この実装により、チームは自分たちの競技中の写真やレポートを簡単に確認できます。
|
||||
本番環境(_prod版)ではパスワード認証によりセキュリティを確保しています。
|
||||
"""
|
||||
|
||||
@api_view(['GET'])
|
||||
def get_photo_list(request):
|
||||
"""
|
||||
チームの写真とレポートURLを取得(認証なし版)
|
||||
|
||||
パラメータ:
|
||||
- zekken: ゼッケン番号
|
||||
- event: イベントコード
|
||||
"""
|
||||
logger.info("get_photo_list called")
|
||||
|
||||
# リクエストからパラメータを取得
|
||||
zekken_number = request.query_params.get('zekken')
|
||||
event_code = request.query_params.get('event')
|
||||
|
||||
logger.debug(f"Parameters: zekken={zekken_number}, event={event_code}")
|
||||
|
||||
# パラメータ検証
|
||||
if not all([zekken_number, event_code]):
|
||||
logger.warning("Missing required parameters")
|
||||
return Response({
|
||||
"status": "ERROR",
|
||||
"message": "ゼッケン番号とイベントコードが必要です"
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
return get_team_photos(zekken_number, event_code)
|
||||
|
||||
@api_view(['GET'])
|
||||
def get_photo_list_prod(request):
|
||||
"""
|
||||
チームの写真とレポートURLを取得(認証あり版)
|
||||
|
||||
パラメータ:
|
||||
- zekken: ゼッケン番号
|
||||
- pw: パスワード
|
||||
- event: イベントコード
|
||||
"""
|
||||
logger.info("get_photo_list_prod called")
|
||||
|
||||
# リクエストからパラメータを取得
|
||||
zekken_number = request.query_params.get('zekken')
|
||||
password = request.query_params.get('pw')
|
||||
event_code = request.query_params.get('event')
|
||||
|
||||
logger.debug(f"Parameters: zekken={zekken_number}, event={event_code}, has_password={bool(password)}")
|
||||
|
||||
# パラメータ検証
|
||||
if not all([zekken_number, password, event_code]):
|
||||
logger.warning("Missing required parameters")
|
||||
return Response({
|
||||
"status": "ERROR",
|
||||
"message": "ゼッケン番号、パスワード、イベントコードが必要です"
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
try:
|
||||
# イベントの存在確認
|
||||
event = NewEvent2.objects.filter(event_name=event_code).first()
|
||||
if not event:
|
||||
logger.warning(f"Event not found: {event_code}")
|
||||
return Response({
|
||||
"status": "ERROR",
|
||||
"message": "指定されたイベントが見つかりません"
|
||||
}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
# チームの存在確認とパスワード検証
|
||||
entry = Entry.objects.filter(
|
||||
event=event,
|
||||
zekken_number=zekken_number
|
||||
).first()
|
||||
|
||||
if not entry:
|
||||
logger.warning(f"Team with zekken number {zekken_number} not found in event: {event_code}")
|
||||
return Response({
|
||||
"status": "ERROR",
|
||||
"message": "指定されたゼッケン番号のチームが見つかりません"
|
||||
}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
# パスワード検証
|
||||
if not hasattr(entry, 'password') or entry.password != password:
|
||||
logger.warning(f"Invalid password for team: {entry.team.team_name if entry.team else 'Unknown'}")
|
||||
return Response({
|
||||
"status": "ERROR",
|
||||
"message": "パスワードが一致しません"
|
||||
}, status=status.HTTP_401_UNAUTHORIZED)
|
||||
|
||||
return get_team_photos(zekken_number, event_code)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error in get_photo_list_prod: {str(e)}")
|
||||
return Response({
|
||||
"status": "ERROR",
|
||||
"message": "サーバーエラーが発生しました"
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
|
||||
def get_team_photos(zekken_number, event_code):
|
||||
"""
|
||||
チームの写真とレポートURLを取得する共通関数
|
||||
"""
|
||||
try:
|
||||
logger.info(f"Getting photos for zekken: {zekken_number}, event: {event_code}")
|
||||
|
||||
# イベントの存在確認(event_codeで検索)
|
||||
event = NewEvent2.objects.filter(event_code=event_code).first()
|
||||
if not event:
|
||||
logger.warning(f"Event not found with event_code: {event_code}")
|
||||
# event_nameでも試してみる
|
||||
event = NewEvent2.objects.filter(event_name=event_code).first()
|
||||
if not event:
|
||||
logger.warning(f"Event not found with event_name: {event_code}")
|
||||
return Response({
|
||||
"status": "ERROR",
|
||||
"message": "指定されたイベントが見つかりません"
|
||||
}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
logger.info(f"Found event: {event.event_name} (ID: {event.id})")
|
||||
|
||||
# まずEntryテーブルを確認
|
||||
entry = Entry.objects.filter(
|
||||
event=event,
|
||||
zekken_number=zekken_number
|
||||
).first()
|
||||
|
||||
team_name = "Unknown Team"
|
||||
if entry and entry.team:
|
||||
team_name = entry.team.team_name
|
||||
logger.info(f"Found team in Entry: {team_name}")
|
||||
else:
|
||||
logger.info(f"No Entry found for zekken {zekken_number}, checking GpsCheckin for legacy data")
|
||||
|
||||
# GpsCheckinテーブルからチーム情報を取得(レガシーデータ対応)
|
||||
gps_checkin_sample = GpsCheckin.objects.filter(
|
||||
event_code=event_code,
|
||||
zekken_number=str(zekken_number)
|
||||
).first()
|
||||
|
||||
if gps_checkin_sample and gps_checkin_sample.team:
|
||||
team_name = gps_checkin_sample.team.team_name
|
||||
logger.info(f"Found team in GpsCheckin: {team_name}")
|
||||
else:
|
||||
team_name = f"Team {zekken_number}"
|
||||
logger.info(f"No team found, using default: {team_name}")
|
||||
|
||||
# GpsCheckinテーブルから写真データを取得
|
||||
gps_checkins = GpsCheckin.objects.filter(
|
||||
event_code=event_code,
|
||||
zekken_number=str(zekken_number),
|
||||
image_address__isnull=False
|
||||
).exclude(
|
||||
image_address=''
|
||||
).order_by('path_order', 'create_at')
|
||||
|
||||
logger.info(f"Found {gps_checkins.count()} GPS checkins with images")
|
||||
|
||||
# 写真リストを作成
|
||||
photos = []
|
||||
|
||||
for gps in gps_checkins:
|
||||
if gps.image_address:
|
||||
# 画像URLを構築
|
||||
if gps.image_address.startswith('http'):
|
||||
# 絶対URLの場合はそのまま使用
|
||||
image_url = gps.image_address
|
||||
else:
|
||||
# 相対パスの場合はベースURLと結合
|
||||
# settings.MEDIA_URLやstatic fileの設定に基づいて調整
|
||||
image_url = f"/media/{gps.image_address}" if not gps.image_address.startswith('/') else gps.image_address
|
||||
|
||||
photo_data = {
|
||||
"cp_number": gps.cp_number if gps.cp_number is not None else 0,
|
||||
"photo_url": image_url,
|
||||
"checkin_time": gps.create_at.strftime("%Y-%m-%d %H:%M:%S") if gps.create_at else None,
|
||||
"path_order": gps.path_order,
|
||||
"buy_flag": gps.buy_flag,
|
||||
"validate_location": gps.validate_location,
|
||||
"points": gps.points
|
||||
}
|
||||
|
||||
photos.append(photo_data)
|
||||
logger.debug(f"Added photo: CP {gps.cp_number}, URL: {image_url}")
|
||||
|
||||
# チームの基本情報
|
||||
team_info = {
|
||||
"team_name": team_name,
|
||||
"zekken_number": zekken_number,
|
||||
"event_name": event.event_name,
|
||||
"photo_count": len(photos)
|
||||
}
|
||||
|
||||
# レスポンス構築
|
||||
response_data = {
|
||||
"status": "SUCCESS",
|
||||
"message": f"写真を{len(photos)}枚取得しました",
|
||||
"team_info": team_info,
|
||||
"photo_list": photos
|
||||
}
|
||||
|
||||
logger.info(f"Successfully retrieved {len(photos)} photos for team {team_name}")
|
||||
return Response(response_data, status=status.HTTP_200_OK)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error in get_team_photos: {str(e)}")
|
||||
return Response({
|
||||
"status": "ERROR",
|
||||
"message": "サーバーエラーが発生しました"
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
Reference in New Issue
Block a user