almost finish migrate new circumstances

This commit is contained in:
2025-08-24 19:44:36 +09:00
parent 1ba305641e
commit fe5a044c82
67 changed files with 1194889 additions and 467 deletions

View File

@ -4,6 +4,7 @@ from django.contrib.auth import get_user_model
User = get_user_model()
import traceback
from django.contrib.auth.hashers import make_password
from urllib.parse import unquote # URLデコード用
import subprocess # subprocessモジュールを追加
import tempfile # tempfileモジュールを追加
@ -242,37 +243,19 @@ class LocationViewSet(viewsets.ModelViewSet):
def get_queryset(self):
queryset = Location.objects.all()
logger.info("=== Location API Called ===")
# リクエストパラメータの確認
group_filter = self.request.query_params.get('group__contains')
logger.info(f"Request params: {dict(self.request.query_params)}")
logger.info(f"Group filter: {group_filter}")
if group_filter:
# フィルタ適用前のデータ数
total_count = queryset.count()
logger.info(f"Total locations before filter: {total_count}")
# フィルタの適用
queryset = queryset.filter(group__contains=group_filter)
# フィルタ適用後のデータ数
filtered_count = queryset.count()
logger.info(f"Filtered locations count: {filtered_count}")
# フィルタされたデータのサンプル最初の5件
sample_data = queryset[:5]
logger.info("Sample of filtered data:")
for loc in sample_data:
logger.info(f"ID: {loc.id}, Name: {loc.location_name}, Group: {loc.group}")
return queryset
def list(self, request, *args, **kwargs):
try:
response = super().list(request, *args, **kwargs)
logger.info(f"Response data count: {len(response.data['features'])}")
return response
except Exception as e:
logger.error(f"Error in list method: {str(e)}", exc_info=True)
@ -862,7 +845,12 @@ class LoginAPI(generics.GenericAPIView):
logger.info(f"Login attempt for identifier: {request.data.get('identifier', 'identifier not provided')}")
logger.debug(f"Request data: {request.data}")
serializer = self.get_serializer(data=request.data)
# フロントエンドの 'identifier' フィールドを 'email' にマッピング
data = request.data.copy()
if 'identifier' in data and 'email' not in data:
data['email'] = data['identifier']
serializer = self.get_serializer(data=data)
try:
serializer.is_valid(raise_exception=True)
user = serializer.validated_data
@ -2491,11 +2479,59 @@ def get_events(request):
)
@api_view(['GET'])
def get_zekken_numbers(request, event_code):
entries = Entry.objects.filter(
event__event_name=event_code,
is_active=True
).order_by('zekken_number')
return Response([entry.zekken_number for entry in entries])
# 通過審査画面用: GpsCheckinテーブルから過去の移行データと新規Entryテーブルの両方をサポート
try:
print(f"=== get_zekken_numbers called with event_code: {event_code} ===")
# event_codeからNewEvent2のIDを取得
try:
event_obj = NewEvent2.objects.get(event_code=event_code)
event_id = event_obj.id
print(f"Found event: {event_obj.event_name} (ID: {event_id})")
except NewEvent2.DoesNotExist:
print(f"No event found with event_code: {event_code}, trying legacy data only")
event_id = None
entry_list = []
# 新規のEntryテーブルから取得event_idが見つかった場合のみ
if event_id:
entries = Entry.objects.filter(
event_id=event_id,
zekken_number__gt=0
).values_list('zekken_number', flat=True).order_by('zekken_number')
if event_id:
entries = Entry.objects.filter(
event_id=event_id,
zekken_number__gt=0
).values_list('zekken_number', flat=True).order_by('zekken_number')
entry_list = list(entries)
print(f"Entry table found {len(entry_list)} records: {entry_list[:10]}")
# GpsCheckinテーブルからも検索過去の移行データ
gps_checkins = GpsCheckin.objects.filter(
event_code=event_code,
zekken_number__gt=0
).values_list('zekken_number', flat=True).distinct().order_by('zekken_number')
gps_list = list(gps_checkins)
print(f"GpsCheckin table found {len(gps_list)} records: {gps_list[:10]}")
# 両方の結果をマージして重複を除去
all_zekken_numbers = entry_list + gps_list
unique_zekken_numbers = sorted(set(all_zekken_numbers))
print(f"Final result: {unique_zekken_numbers[:10]}")
return Response(unique_zekken_numbers)
except Exception as e:
print(f"Error in get_zekken_numbers: {str(e)}")
import traceback
traceback.print_exc()
return Response({"error": str(e)}, status=500)
@api_view(['GET'])
def get_team_info(request, zekken_number):
@ -2550,16 +2586,61 @@ def get_team_info(request, zekken_number):
team = Team.objects.get(id=self.kwargs['team_id'])
def get_image_url(image_path):
"""画像URLを生成する補助関数"""
"""画像URLを生成する補助関数 - S3とローカルメディアの両方に対応"""
if not image_path:
return None
# 開発環境用のパス生成
if settings.DEBUG:
return os.path.join(settings.MEDIA_URL, str(image_path))
image_path_str = str(image_path)
# 本番環境用のパス生成
return f"{settings.MEDIA_URL}{image_path}"
# シミュレーション画像の場合はローカルメディアパスを返す
if image_path_str in ['simulation_image.jpg', '/media/simulation_image.jpg']:
return f"{settings.MEDIA_URL}simulation_image.jpg"
# ローカルメディアのフルパス(/media/で始まるの場合は、S3パスを抽出
if image_path_str.startswith('/media/'):
# /media/を削除してS3パスを取得
s3_path = image_path_str[7:] # "/media/"を除去
if hasattr(settings, 'AWS_STORAGE_BUCKET_NAME') and settings.AWS_STORAGE_BUCKET_NAME:
# S3 URLを直接生成
return f"https://{settings.AWS_S3_CUSTOM_DOMAIN}/{s3_path}"
# S3のファイルパスcheckin/で始まる、画像拡張子を含む)かどうかを判定
if (any(keyword in image_path_str.lower() for keyword in ['jpg', 'jpeg', 'png', 'gif', 'webp']) and
('checkin/' in image_path_str or not image_path_str.startswith('/'))):
# S3 URLを生成
if hasattr(settings, 'AWS_STORAGE_BUCKET_NAME') and settings.AWS_STORAGE_BUCKET_NAME:
return f"https://{settings.AWS_S3_CUSTOM_DOMAIN}/{image_path_str}"
# その他の場合はローカルメディアURL
return f"{settings.MEDIA_URL}{image_path_str}"
def get_standard_image_url(event_code, image_type):
"""規定画像URLを取得S3優先、フォールバック対応"""
try:
# S3から規定画像を取得
from .services.s3_service import S3Service
s3_service = S3Service()
s3_url = s3_service.get_standard_image_url(event_code, image_type)
if s3_url:
return s3_url
# S3に規定画像がない場合はデフォルト画像を返す
default_images = {
'goal': 'https://rogaining.sumasen.net/images/gifuRoge/asset/goal.png',
'start': 'https://rogaining.sumasen.net/images/gifuRoge/asset/start.png',
'checkpoint': 'https://rogaining.sumasen.net/images/gifuRoge/asset/checkpoint.png',
'finish': 'https://rogaining.sumasen.net/images/gifuRoge/asset/finish.png',
'photo_none': 'https://rogaining.sumasen.net/images/gifuRoge/asset/photo_none.png'
}
return default_images.get(image_type, default_images['photo_none'])
except Exception as e:
logger.error(f"Error getting standard image: {e}")
# エラー時はデフォルト画像を返す
return 'https://rogaining.sumasen.net/images/gifuRoge/asset/photo_none.png'
@api_view(['GET'])
@ -2584,9 +2665,6 @@ def get_checkins(request, *args, **kwargs):
event_code=event_code
).order_by('path_order')
# すべてのフィールドを確実に取得できるようにデバッグログを追加
logger.debug(f"Found {checkins.count()} checkins for zekken_number {zekken_number} and event_code {event_code}")
data = []
for c in checkins:
location = Location.objects.filter(cp=c.cp_number,group=event_code).first()
@ -3111,11 +3189,21 @@ def export_excel(request, zekken_number, event_code):
s3.upload_file(pdf_path, f'{event_code}/scoreboard/certificate_{zekken_number}.pdf')
s3.upload_file(excel_path, f'{event_code}/scoreboard_excel/certificate_{zekken_number}.xlsx')
# PDFファイルを読み込んでレスポンスとして返す
with open(pdf_path, 'rb') as pdf_file:
pdf_content = pdf_file.read()
os.remove(temp_excel_path)
os.remove(excel_path)
os.remove(pdf_path)
return Response( status=status.HTTP_200_OK )
# PDFファイルをレスポンスとして返す
response = HttpResponse(
pdf_content,
content_type='application/pdf'
)
response['Content-Disposition'] = f'inline; filename="certificate_{zekken_number}_{event_code}.pdf"'
return response
except subprocess.CalledProcessError as e:
@ -3781,3 +3869,26 @@ def all_ranking_top3(request, event_code):
{"error": str(e)},
status=status.HTTP_500_INTERNAL_SERVER_ERROR
)
# ルートページ用のビュー
def index_view(request):
"""ルートページをスーパーバイザー画面にリダイレクト"""
from django.shortcuts import render
from django.http import HttpResponse
# supervisor/html/index.htmlを読み込んで返す
try:
import os
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
supervisor_path = os.path.join(base_dir, 'supervisor', 'html', 'index.html')
with open(supervisor_path, 'r', encoding='utf-8') as file:
content = file.read()
return HttpResponse(content, content_type='text/html')
except Exception as e:
logger.error(f"Error loading supervisor page: {str(e)}")
return HttpResponse(
"<h1>System Error</h1><p>Failed to load supervisor interface</p>",
status=500
)