From 1c7a6a1f5ccae69b7b909a933ba9fc6df8d34b70 Mon Sep 17 00:00:00 2001 From: Akira Date: Sat, 20 Jul 2024 11:15:33 +0900 Subject: [PATCH] Added APIs for team and members --- .DS_Store | Bin 10244 -> 10244 bytes config/settings.py | 15 +- rog/management/commands/cleanup_temp_users.py | 16 ++ rog/models.py | 141 ++++++++++++-- rog/serializers.py | 57 +++++- rog/urls.py | 17 +- rog/views.py | 179 ++++++++++++++++-- 7 files changed, 395 insertions(+), 30 deletions(-) create mode 100644 rog/management/commands/cleanup_temp_users.py diff --git a/.DS_Store b/.DS_Store index fe9da2da1068b22d17d2fc15b1667067538b2769..8401b1e0ea83b7ed95cba3cd3bcc8b3ccf0a8dca 100644 GIT binary patch delta 44 zcmZn(XbG6$jIU^hRb_GTV|/ - 特定のチームの取得、更新、削除 +# /api/members/ - メンバーの一覧取得と作成 +# /api/members// - 特定のメンバーの取得、更新、削除 +# /api/entries/ - エントリーの一覧取得と作成 +# /api/entries// - 特定のエントリーの取得、更新、削除 +# +router.register(r'teams', TeamViewSet) +router.register(r'members', MemberViewSet) +router.register(r'entries', EntryViewSet) urlpatterns = router.urls @@ -48,5 +59,7 @@ urlpatterns += [ path('delete-account/', DeleteAccount, name="delete-account"), path('privacy/', PrivacyView, name='privacy-view'), path('register', RegistrationView.as_view(), name='register'), + path('verify-email//', VerifyEmailView.as_view(), name='verify_email'), + # path('goal-image/', GoalImageViewSet.as_view(), name='goal-image') -] \ No newline at end of file +] diff --git a/rog/views.py b/rog/views.py index 51e4783..aa14d96 100644 --- a/rog/views.py +++ b/rog/views.py @@ -1,15 +1,15 @@ from curses.ascii import NUL from django.core.serializers import serialize -from .models import GoalImages, Location, Location_line, Location_polygon, JpnAdminMainPerf, Useractions, GifuAreas, RogUser, CustomUser, UserTracks, GoalImages, CheckinImages -from rest_framework import viewsets -from .serializers import LocationSerializer, Location_lineSerializer, Location_polygonSerializer, JPN_main_perfSerializer, LocationCatSerializer, CreateUserSerializer, UserSerializer, LoginUserSerializer, UseractionsSerializer, UserDestinationSerializer, GifuAreaSerializer, LocationEventNameSerializer, RogUserSerializer, UserTracksSerializer, ChangePasswordSerializer, GolaImageSerializer, CheckinImageSerializer, RegistrationSerializer +from .models import GoalImages, Location, Location_line, Location_polygon, JpnAdminMainPerf, Useractions, GifuAreas, RogUser, CustomUser, UserTracks, GoalImages, CheckinImages, TempUser +from rest_framework import viewsets,status +from .serializers import LocationSerializer, Location_lineSerializer, Location_polygonSerializer, JPN_main_perfSerializer, LocationCatSerializer, CreateUserSerializer, UserSerializer, LoginUserSerializer, UseractionsSerializer, UserDestinationSerializer, GifuAreaSerializer, LocationEventNameSerializer, RogUserSerializer, UserTracksSerializer, ChangePasswordSerializer, GolaImageSerializer, CheckinImageSerializer, RegistrationSerializer, Team, Member, Entry, CustomUserSerializer from knox.models import AuthToken from rest_framework import viewsets, generics, status from rest_framework.decorators import action from rest_framework.response import Response from rest_framework.parsers import JSONParser, MultiPartParser -from .serializers import LocationSerializer +from .serializers import LocationSerializer, TeamSerializer, MemberSerializer, EntrySerializer from django.http import JsonResponse from rest_framework.permissions import IsAuthenticated from django.contrib.gis.db.models import Extent, Union @@ -29,8 +29,9 @@ from rest_framework.parsers import JSONParser, MultiPartParser from django.views.decorators.csrf import csrf_exempt import uuid from django.shortcuts import render +from django.utils import timezone - +from django.db import transaction class LocationViewSet(viewsets.ModelViewSet): queryset=Location.objects.all() @@ -55,6 +56,114 @@ class Jpn_Main_PerfViewSet(viewsets.ModelViewSet): +#===== AKira ここから + +class CustomUserViewSet(viewsets.ModelViewSet): + queryset = CustomUser.objects.all() + serializer_class = CustomUserSerializer + permission_classes = [IsAuthenticated] + + def get_queryset(self): + return CustomUser.objects.filter(id=self.request.user.id) + +class TeamViewSet(viewsets.ModelViewSet): + queryset = Team.objects.all() + serializer_class = TeamSerializer + + @transaction.atomic + def create(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + self.perform_create(serializer) + headers = self.get_success_headers(serializer.data) + + # チーム登録後にエントリー登録と外部APIコールを行う + self.register_entry_and_call_external_api(serializer.data) + + return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) + + def register_entry_and_call_external_api(self, team_data): + # エントリーの登録 + entry_data = { + 'zekken_number': team_data['zekken_number'], + 'event_code': request.data.get('event_code'), # エントリー用のevent_codeを取得 + 'date': request.data.get('date') # エントリー用の日付を取得 + } + entry_serializer = EntrySerializer(data=entry_data) + if entry_serializer.is_valid(): + entry_serializer.save() + + # 外部APIへのコール + self.call_external_api(team_data, entry_data) + else: + # エントリー登録に失敗した場合のエラーハンドリング + raise serializers.ValidationError(entry_serializer.errors) + + def call_external_api(self, team_data, entry_data): + external_api_url = "https://rogaining.sumasen.net/gifuroge/register_team" + + payload = { + 'zekken_number': team_data['zekken_number'], + 'event_code': entry_data['event_code'], + 'team_name': team_data['team_name'], + 'class_name': team_data.get('class_name', 'Default'), # class_nameがない場合はデフォルト値を設定 + 'password': team_data['password'] + } + + try: + response = requests.post(external_api_url, data=payload) + response.raise_for_status() # エラーレスポンスの場合は例外を発生させる + + # レスポンスの処理(必要に応じて) + print(f"External API response: {response.json()}") + except requests.RequestException as e: + # 外部APIコールに失敗した場合のエラーハンドリング + print(f"Failed to call external API: {str(e)}") + # ここでエラーをログに記録したり、管理者に通知したりすることができます + + + def get_queryset(self): + user = self.request.user + return Team.objects.filter(member__userid=user) + +class MemberViewSet(viewsets.ModelViewSet): + queryset = Member.objects.all() + serializer_class = MemberSerializer + permission_classes = [IsAuthenticated] + + def create(self, request): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + self.perform_create(serializer) + headers = self.get_success_headers(serializer.data) + return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) + + def get_queryset(self): + user = self.request.user + return Member.objects.filter(userid=user) + + + +class EntryViewSet(viewsets.ModelViewSet): + queryset = Entry.objects.all() + serializer_class = EntrySerializer + permission_classes = [IsAuthenticated] + + def create(self, request): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + self.perform_create(serializer) + headers = self.get_success_headers(serializer.data) + return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) + + def get_queryset(self): + user = self.request.user + return Entry.objects.filter(zekken_number__member__userid=user) + + + +#===== AKira ここまで + class UserTracksViewSet(viewsets.ModelViewSet): queryset = UserTracks.objects.all() serializer_class = UserTracksSerializer @@ -143,9 +252,10 @@ def LocationInBound(request): if(cat): if is_rog: if grp: - locs = Location.objects.filter(~Q(cp=0), geom__within=pl, category=cat, event_name__isnull=True, group__contains=grp) + #locs = Location.objects.filter(~Q(cp=0), geom__within=pl, category=cat, event_name__isnull=True, group__contains=grp) + locs = Location.objects.filter(geom__within=pl, category=cat, event_name__isnull=True, group__contains=grp) else: - locs = Location.objects.filter(~Q(cp=0), geom__within=pl, category=cat, event_name__isnull=True) + locs = Location.objects.filter(geom__within=pl, category=cat, event_name__isnull=True) else: if grp: locs = Location.objects.filter(geom__within=pl, category=cat, event_name__isnull=True, group__contains=grp, location_name__contains='観光') @@ -154,9 +264,9 @@ def LocationInBound(request): else: if is_rog: if grp: - locs = Location.objects.filter(~Q(cp=0), geom__within=pl, event_name__isnull=True, group__contains=grp) + locs = Location.objects.filter(geom__within=pl, event_name__isnull=True, group__contains=grp) else: - locs = Location.objects.filter(~Q(cp=0), geom__within=pl, event_name__isnull=True) + locs = Location.objects.filter(geom__within=pl, event_name__isnull=True) else: if grp: locs = Location.objects.filter(geom__within=pl, event_name__isnull=True, group__contains=grp, location_name__contains='観光') @@ -540,10 +650,57 @@ class TestActionViewSet(viewsets.ModelViewSet): def PrivacyView(request): return render(request, "rog/privacy.html") -class RegistrationView(APIView): +class RegistrationView_old(APIView): def post(self, request): serializer = RegistrationSerializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) \ No newline at end of file + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + +class RegistrationView(APIView): + def post(self, request): + serializer = RegistrationSerializer(data=request.data) + if serializer.is_valid(): + temp_user = serializer.save() + verification_url = request.build_absolute_uri( + reverse('verify_email', kwargs={'verification_code': temp_user.verification_code}) + ) + send_mail( + 'Verify your email', + f'Please click the link to verify your email: {verification_url}', + settings.DEFAULT_FROM_EMAIL, + [temp_user.email], + fail_silently=False, + ) + return Response({"message": "Please check your email to complete registration."}, status=status.HTTP_201_CREATED) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + +class VerifyEmailView(APIView): + def get(self, request, verification_code): + try: + temp_user = TempUser.objects.get(verification_code=verification_code) + if not temp_user.is_valid(): + temp_user.delete() + return Response({"error": "Verification link has expired. Please register again."}, status=status.HTTP_400_BAD_REQUEST) + + user = CustomUser.objects.create_user( + email=temp_user.email, + password=temp_user.password, + is_rogaining=temp_user.is_rogaining, + zekken_number=temp_user.zekken_number, + event_code=temp_user.event_code, + team_name=temp_user.team_name, + group=temp_user.group + ) + temp_user.delete() + return Response({"message": "Email verified. Registration complete."}, status=status.HTTP_200_OK) + except TempUser.DoesNotExist: + return Response({"error": "Invalid verification code."}, status=status.HTTP_400_BAD_REQUEST) + + + + + +