Update new API..

This commit is contained in:
2025-09-02 20:06:58 +09:00
parent 0acaa6ea1f
commit a8dc2ba3b1
6 changed files with 500 additions and 15 deletions

0
.env.local_akira Normal file
View File

View File

@ -2,7 +2,7 @@ POSTGRES_USER=admin
POSTGRES_PASS=admin123456 POSTGRES_PASS=admin123456
POSTGRES_DBNAME=rogdb POSTGRES_DBNAME=rogdb
DATABASE=postgres DATABASE=postgres
PG_HOST=172.31.25.76 PG_HOST=postgres-db
PG_PORT=5432 PG_PORT=5432
GS_VERSION=2.20.0 GS_VERSION=2.20.0
GEOSERVER_PORT=8600 GEOSERVER_PORT=8600

View File

@ -1,7 +1,7 @@
from sys import prefix from sys import prefix
from rest_framework import urlpatterns from rest_framework import urlpatterns
from rest_framework.routers import DefaultRouter from rest_framework.routers import DefaultRouter
from .views import CategoryByNameView, LocationViewSet, Location_lineViewSet, Location_polygonViewSet, Jpn_Main_PerfViewSet, LocationsInPerf, ExtentForSubPerf, SubPerfInMainPerf, ExtentForMainPerf, LocationsInSubPerf, CatView, RegistrationAPI, LoginAPI, UserAPI, UserActionViewset, UserMakeActionViewset, UserDestinations, UpdateOrder, LocationInBound, DeleteDestination, CustomAreaLocations, GetAllGifuAreas, CustomAreaNames, userDetials, UserTracksViewSet, CatByCity, ChangePasswordView, GoalImageViewSet, CheckinImageViewSet, ExtentForLocations, DeleteAccount, PrivacyView, RegistrationView, TeamViewSet,MemberViewSet,EntryViewSet,RegisterView, VerifyEmailView, NewEventListView,NewEvent2ListView,NewCategoryListView,CategoryListView, MemberUserDetailView, TeamMembersWithUserView,MemberAddView,UserActivationView,RegistrationView,TempUserRegistrationView,ResendInvitationEmailView,update_user_info,update_user_detail,ActivateMemberView, ActivateNewMemberView, PasswordResetRequestView, PasswordResetConfirmView, NewCategoryViewSet,LocationInBound2,UserLastGoalTimeView,TeamEntriesView,update_entry_status,get_events,get_zekken_numbers,get_team_info,get_checkins,update_checkins,export_excel,debug_urls,get_ranking, all_ranking_top3 from .views import CategoryByNameView, LocationViewSet, Location_lineViewSet, Location_polygonViewSet, Jpn_Main_PerfViewSet, LocationsInPerf, ExtentForSubPerf, SubPerfInMainPerf, ExtentForMainPerf, LocationsInSubPerf, CatView, RegistrationAPI, LoginAPI, UserAPI, UserActionViewset, UserMakeActionViewset, UserDestinations, UpdateOrder, LocationInBound, DeleteDestination, CustomAreaLocations, GetAllGifuAreas, CustomAreaNames, userDetials, UserTracksViewSet, CatByCity, ChangePasswordView, GoalImageViewSet, CheckinImageViewSet, ExtentForLocations, DeleteAccount, PrivacyView, RegistrationView, TeamViewSet,MemberViewSet,EntryViewSet,RegisterView, VerifyEmailView, NewEventListView,NewEvent2ListView,NewCategoryListView,CategoryListView, MemberUserDetailView, TeamMembersWithUserView,MemberAddView,UserActivationView,RegistrationView,TempUserRegistrationView,ResendInvitationEmailView,update_user_info,update_user_detail,ActivateMemberView, ActivateNewMemberView, PasswordResetRequestView, PasswordResetConfirmView, NewCategoryViewSet,LocationInBound2,UserLastGoalTimeView,TeamEntriesView,update_entry_status,get_events,get_zekken_numbers,get_team_info,get_checkins,update_checkins,export_excel,debug_urls,get_ranking, all_ranking_top3, current_entry_info
from .views_apis.api_auth import check_event_code from .views_apis.api_auth import check_event_code
from .views_apis.api_teams import register_team,update_team_name,team_class_changer,team_register,zekken_max_num,zekken_double_check,get_team_list,get_zekken_list from .views_apis.api_teams import register_team,update_team_name,team_class_changer,team_register,zekken_max_num,zekken_double_check,get_team_list,get_zekken_list
@ -140,6 +140,7 @@ urlpatterns += [
#path('admin/', admin.site.urls), #path('admin/', admin.site.urls),
path('entries/<int:entry_id>/update-status/', update_entry_status, name='update-entry-status'), path('entries/<int:entry_id>/update-status/', update_entry_status, name='update-entry-status'),
path('user/current-entry-info/', views.current_entry_info, name='current-entry-info'),
# for Supervisor Web app # for Supervisor Web app

View File

@ -120,15 +120,23 @@ def update_entry_status(request, entry_id):
if entry.owner != request.user and not entry.team.members.filter(user=request.user).exists(): if entry.owner != request.user and not entry.team.members.filter(user=request.user).exists():
return Response({"error": "You don't have permission to update this entry"}, status=status.HTTP_403_FORBIDDEN) return Response({"error": "You don't have permission to update this entry"}, status=status.HTTP_403_FORBIDDEN)
hasParticipated = request.data.get('hasParticipated') # フィールド名の両方のパターンを受け入れる
hasGoaled = request.data.get('hasGoaled') hasParticipated = request.data.get('hasParticipated') or request.data.get('has_participated')
hasGoaled = request.data.get('hasGoaled') or request.data.get('has_goaled')
if hasParticipated is not None: if hasParticipated is not None:
entry.hasParticipated = hasParticipated entry.hasParticipated = hasParticipated
if hasGoaled is not None: if hasGoaled is not None:
entry.hasGoaled = hasGoaled entry.hasGoaled = hasGoaled
entry.save() # update()を使用してバリデーションをスキップ
Entry.objects.filter(id=entry_id).update(
hasParticipated=entry.hasParticipated,
hasGoaled=entry.hasGoaled
)
# 更新後のオブジェクトを再取得
entry.refresh_from_db()
serializer = EntrySerializer(entry) serializer = EntrySerializer(entry)
return Response(serializer.data) return Response(serializer.data)
@ -4085,3 +4093,64 @@ def location_checkin_test(request):
"""ロケーションチェックインのテストページ""" """ロケーションチェックインのテストページ"""
from django.shortcuts import render from django.shortcuts import render
return render(request, 'location_checkin_test.html') return render(request, 'location_checkin_test.html')
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def current_entry_info(request):
"""
ユーザーの最新エントリー情報取得API
GET /api/user/current-entry-info/
"""
user = request.user
# ユーザーの最新エントリーを取得IDの降順でソート
latest_entry = Entry.objects.filter(
team__owner=user
).select_related('team', 'event', 'category', 'team__category').order_by('-id').first()
if not latest_entry:
return Response({
'error': 'No active entry found for user',
'detail': 'User has no current entries'
}, status=status.HTTP_404_NOT_FOUND)
# ユーザーの全エントリー数を取得
entries_count = Entry.objects.filter(team__owner=user).count()
# レスポンスデータを構築
response_data = {
'user': {
'id': user.id,
'email': user.email,
'firstname': user.firstname,
'lastname': user.lastname,
'is_staff': user.is_staff,
'event_code': latest_entry.event.event_name # 最新エントリーのイベント名
},
'current_entry': {
'id': latest_entry.id,
'team': {
'id': latest_entry.team.id,
'team_name': latest_entry.team.team_name,
'category': {
'id': latest_entry.category.id,
'category_name': latest_entry.category.category_name
}
},
'event': {
'id': latest_entry.event.id,
'event_name': latest_entry.event.event_name,
'start_datetime': latest_entry.event.start_datetime,
'end_datetime': latest_entry.event.end_datetime
},
'date': latest_entry.date.strftime('%Y-%m-%d') if latest_entry.date else None,
'has_participated': latest_entry.hasParticipated,
'has_goaled': latest_entry.hasGoaled
},
'entries_count': entries_count,
'latest_entry_date': latest_entry.date # created_atがないのでdateフィールドを使用
}
return Response(response_data)

View File

@ -0,0 +1,258 @@
# サーバーAPI変更要求書
**文書番号:** API-REQ-20250901
**作成日:** 2025年9月1日
**作成者:** アプリ開発チーム
**対象システム:** 岐阜ロゲイニングアプリ サーバーAPI
## 概要
岐阜ロゲイニングアプリにおいて、ユーザーのエントリー参加後にアプリ側とサーバー側のデータ同期に問題が発生しています。具体的には、ユーザー情報に含まれる`event_code`とEntryControllerで管理されている実際のエントリー情報が一致しないため、競技開始時にValidationErrorが発生している状況です。
## 問題の詳細
### 現在の問題
1. **データ同期の不整合**
- ユーザー情報: `event_code: "TestEvent"` (Event ID: 140)
- 実際のエントリー: `event: "揖斐川"` (Event ID: 128, Entry ID: 747)
2. **競技開始時のエラー**
- API: `PATCH /api/entries/747/update-status/`
- エラー: `ValidationError at /api/entries/747/update-status/`
- ステータス: HTTP 500
3. **ユーザー情報の未更新**
- エントリー参加後にユーザー情報(`currentUser`)が最新のエントリー情報で更新されない
## 要求される変更
### 1. 新規API追加
#### API 1: ユーザーの最新エントリー情報取得API
**エンドポイント:** `GET /api/user/current-entry-info/`
**目的:** ユーザーの最新エントリー情報を取得し、アプリ側とサーバー側のデータ同期を確保
**認証:** Token認証必須
**リクエスト**
```http
GET /api/user/current-entry-info/
Authorization: Token <user_token>
Content-Type: application/json; charset=UTF-8
```
**成功レスポンス (HTTP 200)**
```json
{
"user": {
"id": 1765,
"email": "akira.miyata@gifuai.net",
"firstname": "明",
"lastname": "宮田",
"is_staff": true,
"event_code": "揖斐川"
},
"current_entry": {
"id": 747,
"team": {
"id": 155,
"team_name": "狸の宮家_v2",
"category": {
"id": 1,
"category_name": "一般-5時間"
}
},
"event": {
"id": 128,
"event_name": "揖斐川",
"start_datetime": "2025-01-25T10:00:00+09:00",
"end_datetime": "2025-01-25T16:00:00+09:00"
},
"date": "2025-01-25",
"has_participated": false,
"has_goaled": false
},
"entries_count": 6,
"latest_entry_date": "2025-01-25T10:00:00+09:00"
}
```
**エラーレスポンス (HTTP 404)**
```json
{
"error": "No active entry found for user",
"detail": "User has no current entries"
}
```
**実装要件:**
- ユーザーの最新エントリーを`team__owner`で検索
- エントリーは`created_at`の降順でソート
- ユーザー情報の`event_code`は最新エントリーのイベント名を反映
- Team, Event, Category情報を含む完全な情報を返却
### 2. 既存API修正
#### API 2: エントリーステータス更新API修正
**エンドポイント:** `PATCH /api/entries/{entry_id}/update-status/`
**問題:** 現在ValidationErrorが発生
**現在のリクエストボディ:**
```json
{
"hasParticipated": true,
"hasGoaled": false
}
```
**期待されるフィールド名 (要確認):**
```json
{
"has_participated": true,
"has_goaled": false
}
```
**対応要求:**
1. フィールド名の整合性確認
2. バリデーションエラーの原因調査
3. 適切なエラーレスポンスの実装
## 実装方針
### Django REST Framework実装例
```python
# views.py
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from django.contrib.auth.decorators import login_required
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def current_entry_info(request):
user = request.user
# ユーザーの最新エントリーを取得
latest_entry = Entry.objects.filter(
team__owner=user
).order_by('-created_at').first()
if not latest_entry:
return Response({
'error': 'No active entry found for user',
'detail': 'User has no current entries'
}, status=404)
# レスポンスデータを構築
response_data = {
'user': {
'id': user.id,
'email': user.email,
'firstname': user.first_name,
'lastname': user.last_name,
'is_staff': user.is_staff,
'event_code': latest_entry.event.event_name # 最新エントリーのイベント名
},
'current_entry': {
'id': latest_entry.id,
'team': {
'id': latest_entry.team.id,
'team_name': latest_entry.team.team_name,
'category': {
'id': latest_entry.category.id,
'category_name': latest_entry.category.category_name
}
},
'event': {
'id': latest_entry.event.id,
'event_name': latest_entry.event.event_name,
'start_datetime': latest_entry.event.start_datetime,
'end_datetime': latest_entry.event.end_datetime
},
'date': latest_entry.date,
'has_participated': latest_entry.has_participated,
'has_goaled': latest_entry.has_goaled
},
'entries_count': Entry.objects.filter(team__owner=user).count(),
'latest_entry_date': latest_entry.created_at
}
return Response(response_data)
```
```python
# urls.py
urlpatterns = [
path('api/user/current-entry-info/', views.current_entry_info, name='current_entry_info'),
# ... 他のURL
]
```
## 期待される効果
1. **データ整合性の確保**
- アプリ側とサーバー側のエントリー情報が常に同期
- 正しいentry_idとevent_codeを使用した通信
2. **エラーの解消**
- 競技開始時のValidationErrorの解決
- 適切なAPI呼び出しの実現
3. **ユーザビリティの向上**
- 競技開始がスムーズに行える
- データの不整合によるアプリクラッシュの防止
## 実装スケジュール
| 項目 | 期限 | 担当 |
|------|------|------|
| API設計レビュー | 2025年9月3日 | サーバーチーム |
| 新規API実装 | 2025年9月5日 | サーバーチーム |
| 既存API修正 | 2025年9月5日 | サーバーチーム |
| 結合テスト | 2025年9月6日 | 全チーム |
| 本番環境デプロイ | 2025年9月8日 | インフラチーム |
## テスト要件
### 1. 単体テスト
- [ ] 新規API: 正常系レスポンス確認
- [ ] 新規API: エラーケース確認
- [ ] 既存API: バリデーションエラー修正確認
### 2. 結合テスト
- [ ] アプリからの新規API呼び出し
- [ ] データ同期確認
- [ ] 競技開始フロー確認
### 3. 性能テスト
- [ ] 新規APIのレスポンス時間測定
- [ ] 同時アクセス時の動作確認
## リスク評価
| リスク | 影響度 | 対策 |
|--------|--------|------|
| 既存API変更による影響 | 中 | 下位互換性の維持 |
| データ移行の必要性 | 低 | 新規APIのため影響なし |
| 性能劣化 | 低 | インデックス最適化 |
## 承認
| 役割 | 氏名 | 承認日 | 署名 |
|------|------|--------|------|
| アプリ開発リーダー | | | |
| サーバー開発リーダー | | | |
| プロジェクトマネージャー | | | |
---
**注意事項:**
- 本変更要求は岐阜ロゲイニングアプリの安定運用のために必要な修正です
- 実装前に必ずステージング環境での検証を行ってください
- 本番環境デプロイ時はユーザーへの事前通知を行ってください

View File

@ -623,6 +623,133 @@ zekken_number=101&event_code=岐阜ロゲイニング2025
--- ---
## 10. エントリー管理API
### 10.1 現在のエントリー情報取得
ユーザーの最新のエントリー情報を取得します。アプリとサーバー間のデータ同期に使用されます。
**エンドポイント**: `GET /user/current-entry-info/`
**認証**: 必須Token認証
**レスポンス(成功時)**:
```json
{
"id": 123,
"team": {
"id": 45,
"team_name": "サンプルチーム",
"owner": 67
},
"event": {
"id": 12,
"event_name": "岐阜ロゲイニング2025",
"start_datetime": "2025-09-15T10:00:00Z",
"end_datetime": "2025-09-15T16:00:00Z"
},
"category": {
"id": 1,
"category_name": "一般男子",
"duration": 180,
"num_of_member": 4
},
"zekken_number": 101,
"date": "2025-09-15T10:00:00Z",
"hasParticipated": false,
"hasGoaled": false
}
```
**レスポンス(エントリーなし)**:
```json
{
"message": "エントリー情報が見つかりません"
}
```
**レスポンス(認証エラー)**:
```json
{
"detail": "認証情報が提供されていません。"
}
```
### 10.2 エントリーステータス更新
エントリーの参加状況とゴール状況を更新します。後方互換性のため、新旧フィールド名の両方をサポートしています。
**エンドポイント**: `PUT /entry/{entry_id}/update-status/`
**認証**: 必須Token認証
**リクエストパラメータ(新フィールド名)**:
```json
{
"hasParticipated": true,
"hasGoaled": false
}
```
**リクエストパラメータ(旧フィールド名・後方互換性)**:
```json
{
"has_participated": true,
"has_goaled": false
}
```
**レスポンス(成功時)**:
```json
{
"id": 123,
"team": {
"id": 45,
"team_name": "サンプルチーム"
},
"event": {
"id": 12,
"event_name": "岐阜ロゲイニング2025"
},
"zekken_number": 101,
"hasParticipated": true,
"hasGoaled": false,
"updated_at": "2025-09-15T11:30:00Z"
}
```
**レスポンス(エラー時)**:
```json
{
"detail": "エントリーが見つかりません。"
}
```
**使用例**:
**現在のエントリー情報取得**:
```bash
curl -X GET "/user/current-entry-info/" \
-H "Authorization: Token <your_token>" \
-H "Content-Type: application/json"
```
**ステータス更新(参加開始)**:
```bash
curl -X PUT "/entry/123/update-status/" \
-H "Authorization: Token <your_token>" \
-H "Content-Type: application/json" \
-d '{"hasParticipated": true, "hasGoaled": false}'
```
**ステータス更新(ゴール完了)**:
```bash
curl -X PUT "/entry/123/update-status/" \
-H "Authorization: Token <your_token>" \
-H "Content-Type: application/json" \
-d '{"hasParticipated": true, "hasGoaled": true}'
```
---
## エラーコード一覧 ## エラーコード一覧
| ステータスコード | 説明 | | ステータスコード | 説明 |
@ -682,22 +809,37 @@ zekken_number=101&event_code=岐阜ロゲイニング2025
curl -X POST "/entry/" -H "Authorization: Token <token>" -d '{"team":1,"event":1,"category":1}' curl -X POST "/entry/" -H "Authorization: Token <token>" -d '{"team":1,"event":1,"category":1}'
``` ```
7. **スタート** 7. **エントリー情報確認**
```bash
curl -X GET "/user/current-entry-info/" -H "Authorization: Token <token>"
```
8. **スタート前ステータス更新**
```bash
curl -X PUT "/entry/123/update-status/" -H "Authorization: Token <token>" -d '{"hasParticipated": true, "hasGoaled": false}'
```
9. **スタート**
```bash ```bash
curl -X POST "/start_from_rogapp" -d '{"event_code":"岐阜ロゲイニング2025","team_name":"サンプルチーム"}' curl -X POST "/start_from_rogapp" -d '{"event_code":"岐阜ロゲイニング2025","team_name":"サンプルチーム"}'
``` ```
8. **チェックイン** 10. **チェックイン**
```bash ```bash
curl -X POST "/checkin_from_rogapp" -d '{"event_code":"岐阜ロゲイニング2025","team_name":"サンプルチーム","cp_number":1,"image":"https://example.com/photo1.jpg"}' curl -X POST "/checkin_from_rogapp" -d '{"event_code":"岐阜ロゲイニング2025","team_name":"サンプルチーム","cp_number":1,"image":"https://example.com/photo1.jpg"}'
``` ```
9. **ゴール** 11. **ゴール**
```bash ```bash
curl -X POST "/goal_from_rogapp" -d '{"event_code":"岐阜ロゲイニング2025","team_name":"サンプルチーム","image":"https://example.com/goal.jpg"}' curl -X POST "/goal_from_rogapp" -d '{"event_code":"岐阜ロゲイニング2025","team_name":"サンプルチーム","image":"https://example.com/goal.jpg"}'
``` ```
10. **証明書取得** 12. **ゴール後ステータス更新**
```bash
curl -X PUT "/entry/123/update-status/" -H "Authorization: Token <token>" -d '{"hasParticipated": true, "hasGoaled": true}'
```
13. **証明書取得**
```bash ```bash
curl "/download_scoreboard?zekken_number=101&event_code=岐阜ロゲイニング2025" curl "/download_scoreboard?zekken_number=101&event_code=岐阜ロゲイニング2025"
``` ```
@ -725,6 +867,8 @@ zekken_number=101&event_code=岐阜ロゲイニング2025
3. **画像アップロード**: 画像ファイルは事前に適切なストレージにアップロードし、URLを指定してください 3. **画像アップロード**: 画像ファイルは事前に適切なストレージにアップロードし、URLを指定してください
4. **時刻形式**: すべての時刻は ISO 8601 形式YYYY-MM-DDTHH:MM:SSZで指定してください 4. **時刻形式**: すべての時刻は ISO 8601 形式YYYY-MM-DDTHH:MM:SSZで指定してください
5. **エラーハンドリング**: APIからのエラーレスポンスを適切に処理してください 5. **エラーハンドリング**: APIからのエラーレスポンスを適切に処理してください
6. **エントリー情報同期**: アプリ起動時は `/user/current-entry-info/` でエントリー情報を同期してください
7. **ステータス更新**: エントリーステータス更新API は後方互換性のため新旧フィールド名をサポートしています
--- ---
@ -804,6 +948,19 @@ zekken_number=101&event_code=岐阜ロゲイニング2025
- **参照**: `rog_entry` (チーム情報取得) - **参照**: `rog_entry` (チーム情報取得)
- **参照**: `rog_gpslog` (チェックイン画像URL) - **参照**: `rog_gpslog` (チェックイン画像URL)
#### 9. エントリー管理系API
**`/user/current-entry-info/` (現在のエントリー情報取得)**
- **参照**: `rog_entry` (ユーザーの最新エントリー情報)
- **参照**: `rog_team` (チーム基本情報)
- **参照**: `rog_newevent2` (イベント情報)
- **参照**: `rog_newcategory` (カテゴリ詳細情報)
- **参照**: `knox_authtoken` (ユーザー認証)
**`/entry/{entry_id}/update-status/` (エントリーステータス更新)**
- **参照**: `rog_entry` (対象エントリー検索)
- **更新**: `rog_entry` (hasParticipated/hasGoaled更新)
- **参照**: `knox_authtoken` (ユーザー認証・権限確認)
--- ---
## テーブル別API使用一覧表 ## テーブル別API使用一覧表