From c6969d7afae19761edd8bead792c9b132e9b0c4a Mon Sep 17 00:00:00 2001 From: hayano Date: Sat, 2 Nov 2024 23:53:34 +0000 Subject: [PATCH] =?UTF-8?q?Finish=20supervisor=20,=20=E6=AE=8B=E3=82=8A?= =?UTF-8?q?=E3=81=AFExcel=E3=81=A8=E3=82=BB=E3=82=AD=E3=83=A5=E3=83=AA?= =?UTF-8?q?=E3=83=86=E3=82=A3.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.swp | Bin 12288 -> 0 bytes rog/.models.py.swp | Bin 16384 -> 0 bytes rog/models.py | 8 +- rog/urls.py | 3 + rog/views.py | 278 ++++++++++++++++- supervisor/html/.index.html.swp | Bin 77824 -> 0 bytes supervisor/html/index.html | 535 +++++++++++++++++++++++++++----- 7 files changed, 742 insertions(+), 82 deletions(-) delete mode 100644 .env.swp delete mode 100644 rog/.models.py.swp delete mode 100644 supervisor/html/.index.html.swp diff --git a/.env.swp b/.env.swp deleted file mode 100644 index 0115a92dd2da3733224a755622cf11eb5dbe6a7a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 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 TVOPSrxEX44_f}%Ndt(0qG}}#t diff --git a/rog/models.py b/rog/models.py index d418fea..f7be855 100644 --- a/rog/models.py +++ b/rog/models.py @@ -522,6 +522,11 @@ class GoalImages(models.Model): team_name = models.CharField(_("Team name"), max_length=255) event_code = models.CharField(_("event code"), max_length=255) cp_number = models.IntegerField(_("CP numner")) + zekken_number = models.TextField( + null=True, # False にする + blank=True, # False にする + help_text="ゼッケン番号" + ) class CheckinImages(models.Model): user=models.ForeignKey(CustomUser, on_delete=models.DO_NOTHING) @@ -532,6 +537,7 @@ class CheckinImages(models.Model): cp_number = models.IntegerField(_("CP numner")) class GpsCheckin(models.Model): + id = models.AutoField(primary_key=True) # 明示的にidフィールドを追加 path_order = models.IntegerField( null=False, help_text="チェックポイントの順序番号" @@ -637,7 +643,7 @@ class GpsCheckin(models.Model): ] def __str__(self): - return f"{self.event_code}-{self.zekken_number}-{self.path_order}" + return f"{self.event_code}-{self.zekken_number}-{self.path_order}-buy:{self.buy_flag}-valid:{self.validate_location}-point:{self.points}" def save(self, *args, **kwargs): # 作成時・更新時のタイムスタンプを自動設定 diff --git a/rog/urls.py b/rog/urls.py index 863d91d..a123986 100644 --- a/rog/urls.py +++ b/rog/urls.py @@ -124,6 +124,9 @@ urlpatterns += [ path('export_excel///', views.export_excel, name='export_excel'), # for Supervisor Web app path('test/', views.test_api, name='test_api'), + path('update-goal-time/', views.update_goal_time, name='update-goal-time'), + path('get-goalimage/', views.get_goalimage, name='get-goalimage'), + ] if settings.DEBUG: diff --git a/rog/views.py b/rog/views.py index ddf7b18..c686b88 100644 --- a/rog/views.py +++ b/rog/views.py @@ -89,6 +89,7 @@ from io import BytesIO from django.urls import get_resolver import os +import json logger = logging.getLogger(__name__) @@ -227,6 +228,43 @@ class LocationViewSet(viewsets.ModelViewSet): serializer_class=LocationSerializer filter_fields=["prefecture", "location_name"] + 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) + raise class Location_lineViewSet(viewsets.ModelViewSet): queryset=Location_line.objects.all() @@ -2374,12 +2412,32 @@ def get_team_info(request, zekken_number): event_code=entry.event.event_name ).order_by('-goaltime').first() + # Nullチェックを追加してからログ出力 + goalimage_url = None + goaltime = None + + if goal_record: + try: + goaltime = goal_record.goaltime + if goal_record.goalimage and hasattr(goal_record.goalimage, 'url'): + goalimage_url = request.build_absolute_uri(goal_record.goalimage.url) + logger.info(f"get_team_info record.goalimage_url={goalimage_url}") + else: + logger.info("Goal record exists but no image found") + + except ValueError as e: + logger.warning(f"Error accessing goal image: {str(e)}") + else: + logger.info("No goal record found for team") + + return Response({ 'team_name': entry.team.team_name, 'members': ', '.join([f"{m.lastname} {m.firstname}" for m in members]), 'event_code': entry.event.event_name, 'start_datetime': entry.event.start_datetime, - 'end_datetime': goal_record.goaltime if goal_record else None, + 'end_datetime': goaltime, #goal_record.goaltime if goal_record else None, + 'goal_photo': goalimage_url, #goal_record.goalimage if goal_record else None, 'duration': entry.category.duration.total_seconds() }) @@ -2475,20 +2533,80 @@ def get_checkins(request, *args, **kwargs): status=status.HTTP_500_INTERNAL_SERVER_ERROR ) + @api_view(['POST']) def update_checkins(request): - with transaction.atomic(): - for update in request.data: - checkin = GpsCheckin.objects.get(id=update['id']) - checkin.path_order = update['path_order'] - checkin.validate_location = update['validate_location'] - checkin.save() - return Response({'status': 'success'}) + try: + with transaction.atomic(): + update_base = request.data + logger.info(f"Processing update data: {update_base}") + zekken_number = update_base['zekken_number'] + event_code = update_base['event_code'] + + for update in update_base['checkins']: + if 'id' in update and int(update['id'])>0: + # 既存レコードの更新 + logger.info(f"Updating existing checkin : {update}") + try: + checkin = GpsCheckin.objects.get(id=update['id']) + logger.info(f"Updating existing checkin: {checkin}") + + # 既存レコードの更新 + checkin.path_order = update['order'] + checkin.buy_flag = update.get('buy_flag', False) + checkin.validate_location = update.get('validation', False) + checkin.points = update.get('points', 0) + checkin.save() + logger.info(f"Updated existing checkin result: {checkin}") + + except GpsCheckin.DoesNotExist: + logger.error(f"Checkin with id {update['id']} not found") + return Response( + {"error": f"Checkin with id {update['id']} not found"}, + status=status.HTTP_404_NOT_FOUND + ) + for update in update_base['checkins']: + if 'id' in update and int(update['id'])==0: + # 新規レコードの作成 + logger.info("Creating new checkin:{update}") + try: + checkin = GpsCheckin.objects.create( + zekken_number=update_base['zekken_number'], + event_code=update_base['event_code'], + + path_order=update['order'], + cp_number=update['cp_number'], + validate_location=update.get('validation', False), + buy_flag=update.get('buy_flag', False), + points=update.get('points', 0), + create_at=timezone.now(), + update_at=timezone.now(), + create_user=request.user.email if request.user.is_authenticated else None, + update_user=request.user.email if request.user.is_authenticated else None + ) + logger.info(f"Updated existing checkin result: {checkin}") + + except KeyError as e: + logger.error(f"Missing required field: {str(e)}") + return Response( + {"error": f"Missing required field: {str(e)}"}, + status=status.HTTP_400_BAD_REQUEST + ) + + return Response({'status': 'success', 'message': 'Checkins updated successfully'}) + + except Exception as e: + logger.error(f"Error in update_checkins: {str(e)}", exc_info=True) + return Response( + {"error": "Failed to update checkins", "detail": str(e)}, + status=status.HTTP_500_INTERNAL_SERVER_ERROR + ) + @api_view(['GET']) def export_excel(request, zekken_number): # エントリー情報の取得 - entry = Entry.objects.select_related('team').get(zekken_number=zekken_number) + entry = Entry.objects.select_related('team','event').get(zekken_number=zekken_number) checkins = GpsCheckin.objects.filter(zekken_number=zekken_number).order_by('path_order') # Excelファイルの生成 @@ -2539,3 +2657,145 @@ def test_api(request): logger.debug("Test API endpoint called") return JsonResponse({"status": "API is working"}) +@api_view(['GET']) +#@authentication_classes([TokenAuthentication]) +#@permission_classes([IsAuthenticated]) +def get_goalimage(request): + """ + ゼッケン番号とイベントコードに基づいてゴール画像情報を取得するエンドポイント + + Parameters: + zekken_number (str): ゼッケン番号 + event_code (str): イベントコード + + Returns: + Response: ゴール画像情報を含むJSONレスポンス + """ + try: + logger.debug(f"get_goalimage called with params: {request.GET}") + + # リクエストパラメータを取得 + zekken_number = request.GET.get('zekken_number') + event_code = request.GET.get('event_code') + + logger.debug(f"Searching for goal records with zekken_number={zekken_number}, event_code={event_code}") + + # パラメータの検証 + if not zekken_number or not event_code: + return Response( + {"error": "zekken_number and event_code are required"}, + status=status.HTTP_400_BAD_REQUEST + ) + + # ゴール画像レコードを検索(最も早いゴール時間のレコードを取得) + goal_records = GoalImages.objects.filter( + zekken_number=zekken_number, + event_code=event_code + ).order_by('goaltime') + + logger.debug(f"Found {goal_records.count()} goal records") + + if not goal_records.exists(): + return Response( + {"message": "No goal records found"}, + status=status.HTTP_404_NOT_FOUND + ) + + # 最も早いゴール時間のレコード(cp_number = 0)を探す + valid_goal = goal_records.filter(cp_number=0).first() + + if not valid_goal: + return Response( + {"message": "No valid goal record found"}, + status=status.HTTP_404_NOT_FOUND + ) + + # シリアライザでデータを整形 + serializer = GolaImageSerializer(valid_goal) + + # レスポンスデータの構築 + response_data = { + "goal_record": serializer.data, + "total_records": goal_records.count(), + "has_multiple_records": goal_records.count() > 1 + } + + logger.info(f"Retrieved goal record for zekken_number {zekken_number} in event {event_code}") + return Response(response_data) + + except Exception as e: + logger.error(f"Error retrieving goal record: {str(e)}", exc_info=True) + return Response( + {"error": f"Failed to retrieve goal record: {str(e)}"}, + status=status.HTTP_500_INTERNAL_SERVER_ERROR + ) + + +@api_view(['POST']) +#@authentication_classes([TokenAuthentication]) +#@permission_classes([IsAuthenticated]) +def update_goal_time(request): + try: + logger.info(f"update_goal_time:{request}") + # リクエストからデータを取得 + zekken_number = request.data.get('zekken_number') + event_code = request.data.get('event_code') + team_name = request.data.get('team_name') + goal_time_str = request.data.get('goaltime') + + logger.info(f"zekken_number={zekken_number},event_code={event_code},team_name={team_name},goal_time={goal_time_str}") + + # 入力バリデーション + #if not all([zekken_number, event_code, team_name, goal_time_str]): + # return Response( + # {"error": "Missing required fields"}, + # status=status.HTTP_400_BAD_REQUEST + # ) + + try: + # 文字列からdatetimeオブジェクトに変換 + goal_time = datetime.strptime(goal_time_str, '%Y-%m-%dT%H:%M:%S') + except ValueError: + return Response( + {"error": "Invalid goal time format"}, + status=status.HTTP_400_BAD_REQUEST + ) + + # 既存のゴール記録を探す + goal_record = GoalImages.objects.filter( + team_name=team_name, + event_code=event_code + ).first() + + if goal_record: + # 既存の記録を更新 + goal_record.goaltime = goal_time + goal_record.save() + logger.info(f"Updated goal time for team {team_name} in event {event_code}") + else: + # 新しい記録を作成 + entry = Entry.objects.get(zekken_number=zekken_number, event__event_name=event_code) + GoalImages.objects.create( + user=entry.owner, + goaltime=goal_time, + team_name=team_name, + event_code=event_code, + cp_number=0 # ゴール地点を表すCP番号 + ) + logger.info(f"Created new goal time record for team {team_name} in event {event_code}") + + return Response({"message": "Goal time updated successfully"}) + + except Entry.DoesNotExist: + logger.error(f"Entry not found for zekken_number {zekken_number} in event {event_code}") + return Response( + {"error": "Entry not found"}, + status=status.HTTP_404_NOT_FOUND + ) + except Exception as e: + logger.error(f"Error updating goal time: {str(e)}") + return Response( + {"error": f"Failed to update goal time: {str(e)}"}, + status=status.HTTP_500_INTERNAL_SERVER_ERROR + ) + diff --git a/supervisor/html/.index.html.swp b/supervisor/html/.index.html.swp deleted file mode 100644 index bbe3145d2e4284e3a51f38abe868d529907fa967..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 77824 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 G;`~2gO|}yN diff --git a/supervisor/html/index.html b/supervisor/html/index.html index e9ddc9b..6b795d6 100755 --- a/supervisor/html/index.html +++ b/supervisor/html/index.html @@ -94,6 +94,7 @@ 買物申請 通過審査 獲得点数 + @@ -104,7 +105,7 @@
-