almost finish migrate new circumstances
This commit is contained in:
179
rog/views.py
179
rog/views.py
@ -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
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user