from .models import JpnSubPerf # このインポート文をファイルの先頭に追加 from django.contrib.auth import get_user_model User = get_user_model() import traceback from django.contrib.auth.hashers import make_password from django.contrib.auth.tokens import default_token_generator from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode from django.utils.encoding import force_bytes, force_str import requests from rest_framework import serializers from django.db import IntegrityError from django.urls import reverse from .utils import send_verification_email,send_invitation_email,send_team_join_email,send_reset_password_email from django.conf import settings import uuid from rest_framework.exceptions import ValidationError as DRFValidationError from django.db import transaction from django.db.models import F from rest_framework import viewsets, permissions, status from rest_framework.decorators import action from rest_framework.response import Response from django.shortcuts import get_object_or_404 from .models import Team, Member, CustomUser, NewCategory from .serializers import TeamSerializer, MemberSerializer, CustomUserSerializer, TeamDetailSerializer,UserUpdateSerializer,UserRegistrationSerializer from .permissions import IsTeamOwner 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, NewEvent,NewEvent2, Team, Category, NewCategory,Entry, Member, TempUser,EntryMember from rest_framework import viewsets from .serializers import LocationSerializer, Location_lineSerializer, Location_polygonSerializer, JPN_main_perfSerializer, LocationCatSerializer, UserSerializer, LoginUserSerializer, UseractionsSerializer, UserDestinationSerializer, GifuAreaSerializer, LocationEventNameSerializer, RogUserSerializer, UserTracksSerializer, ChangePasswordSerializer, GolaImageSerializer, CheckinImageSerializer, RegistrationSerializer, MemberWithUserSerializer,TempUserRegistrationSerializer, PasswordResetRequestSerializer, PasswordResetConfirmSerializer from knox.models import AuthToken from rest_framework import viewsets, generics, status from rest_framework.response import Response from rest_framework.parsers import JSONParser, MultiPartParser from .serializers import LocationSerializer from django.http import JsonResponse from rest_framework.permissions import IsAuthenticated from django.contrib.gis.db.models import Extent, Union from .serializers import TestSerialiser,NewEventSerializer,NewEvent2Serializer, TeamSerializer, NewCategorySerializer,CategorySerializer, EntrySerializer, MemberSerializer, TempUserSerializer, CustomUserSerializer,EntryMemberSerializer,MemberCreationSerializer,EntryCreationSerializer from .models import TestModel from django.shortcuts import get_object_or_404 from django.db.models import F from django.contrib.gis import geos from django.db.models import Q from rest_framework import permissions from rest_framework.views import APIView from rest_framework.decorators import api_view from rest_framework.decorators import api_view, permission_classes from rest_framework.parsers import JSONParser, MultiPartParser from django.views.decorators.csrf import csrf_exempt from django.shortcuts import render from .permissions import IsMemberOrTeamOwner from django.utils.decorators import method_decorator from django.utils.encoding import force_str import logging from datetime import datetime from django.utils.dateparse import parse_date logger = logging.getLogger(__name__) class LocationViewSet(viewsets.ModelViewSet): queryset=Location.objects.all() serializer_class=LocationSerializer filter_fields=["prefecture", "location_name"] class Location_lineViewSet(viewsets.ModelViewSet): queryset=Location_line.objects.all() serializer_class=Location_lineSerializer class Location_polygonViewSet(viewsets.ModelViewSet): queryset=Location_polygon.objects.all() serializer_class=Location_polygonSerializer class Jpn_Main_PerfViewSet(viewsets.ModelViewSet): queryset=JpnAdminMainPerf.objects.filter(id=9) serializer_class=JPN_main_perfSerializer filter_fields = ["adm1_ja"] class UserTracksViewSet(viewsets.ModelViewSet): queryset = UserTracks.objects.all() serializer_class = UserTracksSerializer @api_view(['PUT']) @permission_classes([IsAuthenticated]) def update_user_info(request, user_id): try: user = CustomUser.objects.get(id=user_id) except CustomUser.DoesNotExist: return Response({"error": "User not found"}, status=status.HTTP_404_NOT_FOUND) if request.user.id != user_id: return Response({"error": "You don't have permission to update this user's information"}, status=status.HTTP_403_FORBIDDEN) data = request.data logger.debug(f"Received data for update: {data}") # CustomUserの更新可能なフィールドを指定 updateable_fields = ['zekken_number', 'event_code', 'team_name', 'group'] #for field in updateable_fields: # if field in data: # setattr(user, field, data[field]) updated_fields = [] for field in updateable_fields: if field in data: old_value = getattr(user, field) setattr(user, field, data[field]) new_value = getattr(user, field) if old_value != new_value: updated_fields.append(f"{field}: {old_value} -> {new_value}") logger.debug(f"Fields to be updated: {updated_fields}") try: user.save() logger.info(f"User {user_id} updated. Changed fields: {', '.join(updated_fields)}") serializer = CustomUserSerializer(user) return Response(serializer.data, status=status.HTTP_200_OK) except Exception as e: logger.error(f"Error updating user {user_id}: {str(e)}") return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST) @api_view(['PUT']) @permission_classes([IsAuthenticated]) def update_user_detail(request, user_id): try: user = CustomUser.objects.get(id=user_id) except CustomUser.DoesNotExist: return Response({"error": "User not found"}, status=status.HTTP_404_NOT_FOUND) if request.user.id != user_id: return Response({"error": "You don't have permission to update this user's information"}, status=status.HTTP_403_FORBIDDEN) data = request.data logger.debug(f"Received data for update: {data}") # CustomUserの更新可能なフィールドを指定 updateable_fields = ['firstname', 'lastname', 'date_of_birth', 'female'] #for field in updateable_fields: # if field in data: # setattr(user, field, data[field]) updated_fields = [] for field in updateable_fields: if field in data: old_value = getattr(user, field) setattr(user, field, data[field]) new_value = getattr(user, field) if old_value != new_value: logger.debug(f"{field}: {old_value} -> {new_value}") updated_fields.append(f"{field}: {old_value} -> {new_value}") logger.debug(f"Fields to be updated: {updated_fields}") try: user.save() logger.info(f"User {user_id} updated. Changed fields: {', '.join(updated_fields)}") # 更新されたUserデータを使用して関連するMemberのデータを更新 members = Member.objects.filter(user=user) for member in members: member.is_temporary = False member.save() serializer = CustomUserSerializer(user) return Response(serializer.data, status=status.HTTP_200_OK) except Exception as e: logger.error(f"Error updating user {user_id}: {str(e)}") return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST) def LocationsInPerf(request): perfecture = request.GET.get('perf') is_rog = request.GET.get('rog') cat = request.GET.get('cat') grp = request.GET.get('grp') perf_geom = JpnAdminMainPerf.objects.get(id=perfecture) if(cat): if is_rog: if grp: locs = Location.objects.filter(~Q(cp=0), geom__within=perf_geom.geom, category=cat, group__contains=grp) else: locs = Location.objects.filter(~Q(cp=0), geom__within=perf_geom.geom, category=cat) else: if grp: locs = Location.objects.filter(geom__within=perf_geom.geom, category=cat, group__contains=grp, location_name__contains='観光') else: locs = Location.objects.filter(geom__within=perf_geom.geom, category=cat, location_name__contains='観光') else: if is_rog: if grp: locs = Location.objects.filter(~Q(cp=0), geom__within=perf_geom.geom, group__contains=grp) else: locs = Location.objects.filter(~Q(cp=0), geom__within=perf_geom.geom) else: if grp: locs = Location.objects.filter(geom__within=perf_geom.geom, group__contains=grp, location_name__contains='観光') else: locs = Location.objects.filter(geom__within=perf_geom.geom, location_name__contains='観光') serializer = LocationSerializer(locs, many=True) return JsonResponse(serializer.data, safe=False) def LocationsInSubPerf(request): subperfecture = request.GET.get('subperf') is_rog = request.GET.get('rog') cat = request.GET.get('cat') grp = request.GET.get('grp') perf_geom = JpnSubPerf.objects.get(id=subperfecture) if(cat): if is_rog: if grp: locs = Location.objects.filter(~Q(cp=0), geom__within=perf_geom.geom, category=cat, group__contains=grp) else: locs = Location.objects.filter(~Q(cp=0), geom__within=perf_geom.geom, category=cat) else: if grp: locs = Location.objects.filter(geom__within=perf_geom.geom, category=cat, group__contains=grp, location_name__contains='観光') else: locs = Location.objects.filter(geom__within=perf_geom.geom, category=cat, location_name__contains='観光') else: if is_rog: if grp: locs = Location.objects.filter(~Q(cp=0), geom__within=perf_geom.geom, group__contains=grp) else: locs = Location.objects.filter(~Q(cp=0), geom__within=perf_geom.geom) else: locs = Location.objects.filter(geom__within=perf_geom.geom, location_name__contains='観光') serializer = LocationSerializer(locs, many=True) return JsonResponse(serializer.data, safe=False) # この関数LocationInBoundは、地理的な範囲内にある特定の条件を満たす位置情報を検索し、結果をJSON形式で返すものです。主なロジックは以下の通りです: # # 1.リクエストパラメータの取得: # 4つの緯度経度ペア(lat1/lon1からlat4/lon4) # カテゴリ(cat) # グループ(grp) # ROG(Region of Gaze)フラグ(is_rog) # # 2. 境界ポリゴンの作成: # 4つの緯度経度ペアが全て提供された場合、それらを使用してジオメトリポリゴンを作成します。 # # 3.位置情報のフィルタリング: # 基本的に、ポリゴン内(geom__within=pl)にある位置情報を検索します。 # イベント名がない(event_name__isnull=True)位置情報のみを対象とします。 # カテゴリ、グループ、ROGフラグの有無に応じて、さらにフィルタリングを行います: # カテゴリが指定された場合、そのカテゴリに一致する位置情報のみを検索します。 # ROGフラグがある場合、cp(おそらくcheck point)が0でない位置情報を検索します。 # ROGフラグがない場合、location_nameに'観光'を含む位置情報のみを検索します。 # グループが指定された場合、そのグループを含む位置情報のみを検索します。 # # 4.結果の返却: # 検索結果が120件を超える場合、"too_many_points"フラグを立てたJSONレスポンスを返します。 # それ以外の場合、LocationSerializerを使用して位置情報をシリアライズし、JSONレスポンスとして返します。 # # 5.エラーハンドリング: # 必要な緯度経度パラメータが不足している場合、空のJSONオブジェクトを返します。 # # この関数は、主に観光関連の位置情報を特定の地理的範囲内で検索し、様々な条件でフィルタリングすることができます。ROGフラグの有無によって検索条件が変わるのが特徴的です。 # def LocationInBound(request): logger.debug(f"Received request parameters: {request.GET}") lat1 = float(request.GET.get('la1')) lon1 = float(request.GET.get('ln1')) lat2 = float(request.GET.get('la2')) lon2 = float(request.GET.get('ln2')) lat3 = float(request.GET.get('la3')) lon3 = float(request.GET.get('ln3')) lat4 = float(request.GET.get('la4')) lon4 = float(request.GET.get('ln4')) cat = request.GET.get('cat') grp = request.GET.get('grp') is_rog = request.GET.get('rog') logger.debug(f"Parsed parameters: lat1={lat1}, lon1={lon1}, lat2={lat2}, lon2={lon2}, " f"lat3={lat3}, lon3={lon3}, lat4={lat4}, lon4={lon4}, " f"cat={cat}, grp={grp}, is_rog={is_rog}") if(lat1 != None and lon1 != None and lat2 != None and lon2 != None and lat3 != None and lon3 != None and lat4 != None and lon4 != None): pl = geos.Polygon(((lon1, lat1), (lon2, lat2), (lon3, lat3), (lon4, lat4), (lon1, lat1)), srid=4326) logger.debug(f"Created polygon: {pl}") base_query = Location.objects.filter(geom__within=pl, event_name__isnull=True) if cat: base_query = base_query.filter(category=cat) if is_rog: base_query = base_query.filter(~Q(cp=0)) else: base_query = base_query.filter(location_name__contains='観光') if grp: base_query = base_query.filter(group__contains=grp) logger.debug(f"Final query: {base_query.query}") locs = base_query logger.debug(f"Number of locations found: {len(locs)}") ''' 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) else: locs = Location.objects.filter(~Q(cp=0), 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='観光') else: locs = Location.objects.filter(geom__within=pl, category=cat, event_name__isnull=True, location_name__contains='観光') else: if is_rog: if grp: locs = Location.objects.filter(~Q(cp=0), 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) else: if grp: locs = Location.objects.filter(geom__within=pl, event_name__isnull=True, group__contains=grp, location_name__contains='観光') else: locs = Location.objects.filter(geom__within=pl, event_name__isnull=True, location_name__contains='観光') ''' if len(locs) > 200: return JsonResponse({"too_many_points": True}, safe=False, status=500) else: serializer = LocationSerializer(locs, many=True) return JsonResponse(serializer.data, safe=False) else: return JsonResponse({}, safe=False) def SubInPerf(request): prefecture = request.GET.get('perf') perf_geom = JpnAdminMainPerf.objects.get(id=prefecture) sub = JpnAdminPerf.objects.filter(geom__within=perf_geom.geom) serializer = JPN_perfSerializer(sub, many=True) return JsonResponse(serializer.data, safe=False) def SubPerfInMainPerf(request): area = request.GET.get('area') perf_geom = GifuAreas.objects.get(id=area) sub = JpnSubPerf.objects.filter(geom__contained=perf_geom.geom) #serializer = JPN_sub_perSerializer #sub = JpnAdminPerf.objects.filter(geom__within=perf_geom.geom) serializer = JPN_sub_perSerializer(sub, many=True) return JsonResponse(serializer.data, safe=False) def GetAllGifuAreas(request): prefecture = request.GET.get('perf') perf_geom = JpnAdminMainPerf.objects.get(id=prefecture) sub = GifuAreas.objects.filter(geom__contained=perf_geom.geom) serializer = GifuAreaSerializer(sub, many=True) return JsonResponse(serializer.data, safe=False) def ExtentForMainPerf(request): perf_id = request.GET.get('perf') perf = JpnAdminMainPerf.objects.get(id=perf_id) ext = perf.geom.extent # iata = serializers.serialize("json",ext) return JsonResponse(ext, safe=False) @api_view(['POST',]) @permission_classes((IsAuthenticated,)) @csrf_exempt def ExtentForLocations(request): user = request.user ec = user.event_code #print(user.event_code) locs = Location.objects.filter(group__contains=ec).aggregate(Extent('geom'), Union('geom')) return JsonResponse(locs['geom__extent'], safe=False) def ExtentForSubPerf_old(request): sub_perf_id = request.GET.get('sub_perf') sub_perf = JpnSubPerf.objects.get(id=sub_perf_id) ext = sub_perf.geom.extent # iata = serializers.serialize("json",ext) return JsonResponse(ext, safe=False) def ExtentForSubPerf(request): sub_perf_id = request.GET.get('sub_perf') if not sub_perf_id: return JsonResponse({"error": "sub_perf parameter is required"}, status=400) try: sub_perf = JpnSubPerf.objects.get(id=sub_perf_id) ext = sub_perf.geom.extent return JsonResponse(ext, safe=False) except ObjectDoesNotExist: return JsonResponse({"error": "Specified sub_perf does not exist"}, status=404) except Exception as e: return JsonResponse({"error": "Error on ExtentForSubPerf : {e}"}, status=404) def CatView(request): lat1 = float(request.GET.get('la1')) lon1 = float(request.GET.get('ln1')) lat2 = float(request.GET.get('la2')) lon2 = float(request.GET.get('ln2')) lat3 = float(request.GET.get('la3')) lon3 = float(request.GET.get('ln3')) lat4 = float(request.GET.get('la4')) lon4 = float(request.GET.get('ln4')) if(lat1 != None and lon1 != None and lat2 != None and lon2 != None and lat3 != None and lon3 != None and lat4 != None and lon4 != None): pl = geos.Polygon(((lon1, lat1), (lon2, lat2), (lon3, lat3), (lon4, lat4), (lon1, lat1)), srid=4326) #locs = Location.objects.filter(geom__within=pl) c = Location.objects.filter(geom__within=pl).values('category').distinct() serializer = LocationCatSerializer(c, many=True) return JsonResponse(serializer.data, safe=False) else: return null c = Location.objects.filter().values('category').distinct() serializer = LocationCatSerializer(c, many=True) return JsonResponse(serializer.data, safe=False) def CatByCity(request): city = request.GET.get('city') if(city != None): cilt_polygon = JpnSubPerf.objects.filter(adm1_ja=city) cats = Location.objects.filter(geom__within=cilt_polygon[0].geom).values('category').distinct() serializer = LocationCatSerializer(cats, many=True) return JsonResponse(serializer.data, safe=False) else: return None class RegistrationAPI(generics.GenericAPIView): #serializer_class = CreateUserSerializer serializer_class = UserRegistrationSerializer def post(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) user = serializer.save() return Response({ "user": UserSerializer(user, context=self.get_serializer_context()).data, "token": AuthToken.objects.create(user)[1] }) class LoginView(APIView): def post(self, request): email = request.data.get('email') password = request.data.get('password') # デバッグコード user = CustomUser.objects.filter(email=email).first() if user: stored_hash = user.password print(f"Stored hashed password: {stored_hash}") is_valid = check_password(raw_password, stored_hash) print(f"Password is valid during login: {is_valid}") user = authenticate(request, username=email, password=raw_password) if user: token, _ = Token.objects.get_or_create(user=user) return Response({'token': token.key}, status=status.HTTP_200_OK) else: return Response({'error': 'Invalid credentials'}, status=status.HTTP_400_BAD_REQUEST) #user = authenticate(request, username=email, password=password) #if user: # token, _ = Token.objects.get_or_create(user=user) # return Response({'token': token.key}, status=status.HTTP_200_OK) #else: # return Response({'error': 'Invalid credentials'}, status=status.HTTP_400_BAD_REQUEST) class PasswordResetView(APIView): def post(self, request): email = request.data.get('email') user = CustomUser.objects.filter(email=email).first() if user: token = default_token_generator.make_token(user) uid = urlsafe_base64_encode(force_bytes(user.pk)) reset_link = f"https://yourwebsite.com/reset-password/{uid}/{token}/" send_mail( 'Password Reset', f'Click here to reset your password: {reset_link}', 'noreply@yourwebsite.com', [email], fail_silently=False, ) return Response({'message': 'Password reset email sent'}, status=status.HTTP_200_OK) else: return Response({'error': 'User not found'}, status=status.HTTP_400_BAD_REQUEST) class LoginAPI(generics.GenericAPIView): serializer_class = LoginUserSerializer def post(self, request, *args, **kwargs): logger.info(f"Login attempt for user: {request.data.get('email', 'email not provided')}") logger.debug(f"Request data: {request.data}") serializer = self.get_serializer(data=request.data) try: serializer.is_valid(raise_exception=True) user = serializer.validated_data logger.info(f"User {user.email} logged in successfully") return Response({ "user": UserSerializer(user, context=self.get_serializer_context()).data, "token": AuthToken.objects.create(user)[1] }) except serializers.ValidationError as e: logger.error(f"Login failed for user {request.data.get('email', 'email not provided')}: {str(e)}") logger.error(f"Serializer errors: {serializer.errors}") error_msg = serializer.errors.get('non_field_errors', ['ログインに失敗しました。'])[0] return Response({ "error": error_msg, "details": serializer.errors }, status=status.HTTP_400_BAD_REQUEST) except Exception as e: logger.error(f"Unexpected error during login for user {request.data.get('email', 'email not provided')}: {str(e)}") logger.error(f"Traceback: {traceback.format_exc()}") return Response({ "error": "予期せぬエラーが発生しました。", "details": str(e) }, status=status.HTTP_500_INTERNAL_SERVER_ERROR) class UserUpdateAPI(generics.UpdateAPIView): permission_classes = [permissions.IsAuthenticated] serializer_class = UserUpdateSerializer def get_object(self): return self.request.user def update(self, request, *args, **kwargs): partial = kwargs.pop('partial', False) instance = self.get_object() serializer = self.get_serializer(instance, data=request.data, partial=partial) serializer.is_valid(raise_exception=True) self.perform_update(serializer) if getattr(instance, '_prefetched_objects_cache', None): instance._prefetched_objects_cache = {} return Response(serializer.data) # User 情報取得 class UserAPI(generics.RetrieveAPIView): permission_classes = [permissions.IsAuthenticated,] serializer_class = UserSerializer def get_object(self): return self.request.user # @api_view(['POST',]) # @permission_classes((IsAuthenticated,)) # @csrf_exempt # class GoalImageViewSet(APIView): # permissions_classes = [permissions.IsAuthenticated,] # # parser_classes = [MultiPartParser, JSONParser] # def post(self, request, format=None): # # print(request.data) # serializer = GolaImageSerializer(data=request.data) # if serializer.is_valid(): # serializer.save() # return Response(serializer.data, status=status.HttP_200_OK) # else: # return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) # return Response({"ok":"ok"}) class GoalImageViewSet(viewsets.ModelViewSet): queryset=GoalImages.objects.all() serializer_class=GolaImageSerializer # parser_classes = (MultiPartParser, JSONParser) def get_queryset(self): queryset = GoalImages.objects.all() # dist = self.request.GET.get('dist') # if dist != None : # queryset = Incident.objects.filter(entity=dist, is_approved=True) # else: # queryset = Incident.objects.filter(is_approved=True) return queryset class CheckinImageViewSet(viewsets.ModelViewSet): queryset=CheckinImages.objects.all() serializer_class=CheckinImageSerializer # parser_classes = (MultiPartParser, JSONParser) def get_queryset(self): queryset = CheckinImages.objects.all() # dist = self.request.GET.get('dist') # if dist != None : # queryset = Incident.objects.filter(entity=dist, is_approved=True) # else: # queryset = Incident.objects.filter(is_approved=True) return queryset class RetrieveUserView(generics.RetrieveAPIView): queryset = CustomUser.objects.all() serializer_class = UserSerializer permission_classes = [IsAuthenticated] def get_object(self): return self.request.user def userDetials(request): user_id = request.GET.get('user_id') user = CustomUser.objects.get(id=user_id) rogUser = RogUser.objects.filter(user=user) serializer = RogUserSerializer(rogUser, many=True) return JsonResponse(serializer.data, safe=False) @api_view(['GET']) @permission_classes((IsAuthenticated, )) def DeleteAccount(request): usr = request.user; #print("user is" + usr) if(usr): #usr.delete() usr.email = usr.email + "_res" + str(uuid.uuid4()) usr.save(); AuthToken.objects.filter(user=usr).delete() return Response({"result":"user deleted"}) return Response({"result":"user not found"}) ''' def send_verification_email(self, temp_user): subject = '仮登録の確認' message = f'以下のリンクをクリックして登録を完了してください:\n{settings.FRONTEND_URL}/verify/{temp_user.verification_code}' from_email = settings.DEFAULT_FROM_EMAIL recipient_list = [temp_user.email] try: send_mail(subject, message, from_email, recipient_list) logger.info(f"Verification email sent to {temp_user.email}") except Exception as e: logger.error(f"Failed to send verification email to {temp_user.email}. Error: {str(e)}") ''' def UserActionViewset(request): user_id = request.GET.get('user_id') location_id = request.GET.get('location_id') location = Location.objects.get(location_id=location_id) user = CustomUser.objects.get(id=user_id) action = Useractions.objects.filter(location=location, user=user) serializer = UseractionsSerializer(action, many=True) return JsonResponse(serializer.data, safe=False) def UserMakeActionViewset(request): user_id = request.GET.get('user_id') location_id = request.GET.get('location_id') wanttogo = True if request.GET.get('wanttogo') == "true" else False like = True if request.GET.get('like') == "true" else False checkin = True if request.GET.get('checkin') == "true" else False location = Location.objects.get(location_id=location_id) user = CustomUser.objects.get(id=user_id) #action = Useractions.objects.filter(location__id=location_id, user__id=user_id) rec = Useractions.objects.filter(user=user, location=location) if(rec): obj = rec.update(wanttogo=wanttogo, like=like, checkin=checkin) else: obj, created = Useractions.objects.update_or_create(user=user, location=location, wanttogo=wanttogo, like=like, checkin=checkin) serializer = UseractionsSerializer(obj, many=False) return JsonResponse(serializer.data, safe=False) def UserDestinations(request): user_id = request.GET.get('user_id') user = CustomUser.objects.get(id=user_id) #action = Useractions.objects.filter(location__id=location_id, user__id=user_id) rec = Useractions.objects.filter(user=user, wanttogo=True).order_by('order') serializer = UserDestinationSerializer(rec, many=True) return JsonResponse(serializer.data, safe=False) def UpdateOrder(request): dir = request.GET.get('dir') user_action_id = int(request.GET.get('user_action_id')) order = int(request.GET.get('order')) aorder = int(request.GET.get('order')) oorder = int(request.GET.get('order')) if(user_action_id): #updated = Useractions.objects.filter(order__gte=order).update(order = F('order')+1) #res = Useractions.objects.filter(id=user_action_id).update(order=order) index = 0 if dir == "up": for id in Useractions.objects.all().order_by('order').values_list('id', flat=True): print(id) print("----",user_action_id) if index == order : index += 1 print("index increated .....") if user_action_id == id: Useractions.objects.filter(id=id).update(order=order) print("updated .....") continue Useractions.objects.filter(id=id).update(order=index) index += 1 else : for id in Useractions.objects.all().order_by('order').values_list('id', flat=True): print(id) print("----",user_action_id) if index == order : index -= 1 print("index increated .....") if user_action_id == id: Useractions.objects.filter(id=id).update(order=order) print("updated .....") continue Useractions.objects.filter(id=id).update(order=index) index += 1 # for id in Useractions.objects.values_list('order', flat=True): # aorder -= 1 # Useractions.objects.filter(order__lt=id).update(order=aorder) # res = Useractions.objects.filter(id=user_action_id).update(order=oorder) return JsonResponse(1, safe=False) else: return JsonResponse({}, safe=False) def DeleteDestination(request): dest_id = int(request.GET.get('dest_id')) print("###### dest ") print(dest_id) if(dest_id != None): Useractions.objects.filter(id=dest_id).delete() return JsonResponse({"success":1}, safe=False) else: return JsonResponse({"success":0}, safe=False) def CustomAreaLocations(request): cat = request.GET.get('cat') name = request.GET.get('name') is_rog = request.GET.get('rog') grp = request.GET.get('grp') if(cat != None): if is_rog: if grp: locs = Location.objects.filter(~Q(cp=0), event_name__isnull=False, category=cat, event_name=name, group__contains=grp) else: locs = Location.objects.filter(~Q(cp=0), event_name__isnull=False, category=cat, event_name=name) else: if grp: locs = Location.objects.filter(event_name__isnull=False, category=cat, event_name=name, group__contains=grp, location_name__contains='観光') else: locs = Location.objects.filter(event_name__isnull=False, category=cat, event_name=name, location_name__contains='観光') else: if is_rog: if grp: locs = Location.objects.filter(~Q(cp=0), event_name__isnull=False, event_name=name, group__contains=grp) else: locs = Location.objects.filter(~Q(cp=0), event_name__isnull=False, event_name=name) else: if grp: locs = Location.objects.filter(event_name__isnull=False, event_name=name, group__contains=grp, location_name__contains='観光') else: locs = Location.objects.filter(event_name__isnull=False, event_name=name, location_name__contains='観光') serializer = LocationSerializer(locs, many=True) return JsonResponse(serializer.data, safe=False) def CustomAreaNames(request): locs = Location.objects.filter(event_name__isnull=False).values('event_name').distinct() serializer = LocationEventNameSerializer(locs, many=True) return JsonResponse(serializer.data, safe=False) class UserActivationView(APIView): def get(self, request, activation_token): try: temp_user = TempUser.objects.get(verification_code=activation_token) user = CustomUser.objects.create( email=temp_user.email, firstname=temp_user.firstname, lastname=temp_user.lastname, date_of_birth=temp_user.date_of_birth, female=temp_user.female, is_active=True ) # Here you might want to add the user to the team they were invited to temp_user.delete() return Response({"message": "アカウントが正常にアクティベートされました。"}, status=status.HTTP_200_OK) except TempUser.DoesNotExist: return Response({"error": "無効なアクティベーショントークンです。"}, status=status.HTTP_400_BAD_REQUEST) ''' def get(self, request, activation_token): try: user = CustomUser.objects.get(activation_token=activation_token, is_active=False) user.is_active = True user.activation_token = None user.save() return Response({"message": "アカウントが正常にアクティベートされました。"}, status=status.HTTP_200_OK) except CustomUser.DoesNotExist: return Response({"error": "無効なアクティベーショントークンです。"}, status=status.HTTP_400_BAD_REQUEST) ''' class ChangePasswordView(generics.UpdateAPIView): """ An endpoint for changing password. """ serializer_class = ChangePasswordSerializer model = CustomUser permission_classes = (IsAuthenticated,) def get_object(self, queryset=None): obj = self.request.user return obj def update(self, request, *args, **kwargs): self.object = self.get_object() serializer = self.get_serializer(data=request.data) if serializer.is_valid(): # Check old password if not self.object.check_password(serializer.data.get("old_password")): return Response({"old_password": ["Wrong password."]}, status=status.HTTP_400_BAD_REQUEST) # set_password also hashes the password that the user will get self.object.set_password(serializer.data.get("new_password")) self.object.save() response = { 'status': 'success', 'code': status.HTTP_200_OK, 'message': 'Password updated successfully', 'data': [] } return Response(response) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class TestActionViewSet(viewsets.ModelViewSet): serializer_class = TestSerialiser queryset = TestModel.objects.all() def PrivacyView(request): return render(request, "rog/privacy.html") class RegistrationView(APIView): @transaction.atomic def post(self, request): serializer = UserRegistrationSerializer(data=request.data) if serializer.is_valid(): try: user = serializer.save() logger.info(f"New user registered: {user.email}") # パスワードを取得 password = serializer.validated_data.pop('password') # ユーザーを作成するが、まだ保存しない user = serializer.save(commit=False) # パスワードを明示的に設定 user.set_password(password) # ユーザーを保存 user.save() logger.info(f"New user registered: {user.email}") return Response({"message": "ユーザー登録が完了しました。"}, status=status.HTTP_201_CREATED) except Exception as e: logger.error(f"Error during user registration: {str(e)}") return Response({"error": "ユーザー登録中にエラーが発生しました。"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) else: logger.warning(f"Invalid registration data: {serializer.errors}") return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) # Akira class NewEvent2ViewSet(viewsets.ModelViewSet): queryset = NewEvent2.objects.all() serializer_class = NewEvent2Serializer permission_classes = [IsAuthenticated] class NewEvent2ListView(generics.ListAPIView): queryset = NewEvent2.objects.all() serializer_class = NewEvent2Serializer permission_classes = [IsAuthenticated] class NewEventViewSet(viewsets.ModelViewSet): queryset = NewEvent.objects.all() serializer_class = NewEventSerializer permission_classes = [IsAuthenticated] class NewEventListView(generics.ListAPIView): queryset = NewEvent.objects.all() serializer_class = NewEventSerializer permission_classes = [IsAuthenticated] class TeamViewSet(viewsets.ModelViewSet): serializer_class = TeamSerializer permission_classes = [permissions.IsAuthenticated, IsTeamOwner] def get_queryset(self): return Team.objects.filter(owner=self.request.user) def perform_create(self, serializer): logger.info(f"Creating new team for user: {self.request.user.email}") team = serializer.save(owner=self.request.user) logger.info(f"Team created successfully: {team.id}") def update_related_entries(self, team): current_entries = Entry.objects.filter(team=team, is_active=True) for entry in current_entries: self.update_external_system(entry.zekken_number, team.owner.event_code, team.team_name) def update_external_system(self, zekken_number, event_code, team_name): api_url = f"{settings.FRONTEND_URL}/gifuroge/update_team_name" headers = {"Content-Type": "application/x-www-form-urlencoded"} data = { "zekken_number": zekken_number, "new_team_name": team_name, "event_code": event_code, } try: response = requests.post(api_url, headers=headers, data=data) response.raise_for_status() logger.info(f"External system updated for zekken_number: {zekken_number}") return True except requests.RequestException as e: logger.error(f"Failed to update external system. Error: {str(e)}") return False # with transaction.atomic(): # # category = serializer.validated_data['category'] # category = NewCategory.objects.select_for_update().get(id=category.id) # zekken_number = category.category_number # category.category_number = F('category_number') + 1 # category.save() # category.refresh_from_db() # F() 式の結果を評価 # # team = serializer.save(owner=self.request.user, zekken_number=zekken_number) # logger.info(f"Team created successfully: {team.id}") # # # 外部システムの更新 # success = self.register_team( # team.owner, # team.zekken_number, # team.owner.event_code, # team.team_name, # team.category.category_name, # team.owner.password # ) # if not success: # logger.error("Failed to register external system") # raise serializers.ValidationError("外部システムの更新に失敗しました。") # logger.info("External system register successfully") # # def register_team(self, owner,zekken_number,event_code,team_name,category_name,password): # logger.info(f"register_team ==> zekken_number={zekken_number},event_code={event_code},team_name={team_name},category_name={category_name},password={password}") # api_url = f"{settings.FRONTEND_URL}/gifuroge/register_team" # user = owner # # headers = { # "Content-Type": "application/x-www-form-urlencoded" # } # data = { # "zekken_number": zekken_number, # "event_code": event_code, # "team_name": team_name, # "class_name": category_name, # "password": password # パスワードの扱いに注意が必要です # } # # try: # response = requests.post(api_url,headers=headers,data=data) # response.raise_for_status() # logger.info(f"Team registered successfully for team {team_name}") # return True # # except requests.RequestException as e: # logger.error(f"Failed to register team for entry {entry.id}. Error: {str(e)}") # # エラーが発生しても、エントリー自体は作成されています # # 必要に応じて、ここでエラーハンドリングを追加できます # return False # # def destroy(self, request, *args, **kwargs): # team = self.get_object() # if team.members.exists(): # return Response( # { # "error": "チームにメンバーが残っているため削除できません。", # "error_code": "TEAM_HAS_MEMBERS" # }, # status=status.HTTP_400_BAD_REQUEST # ) # # #return Response({"error": "チームにメンバーが残っているため削除できません。"}, status=status.HTTP_400_BAD_REQUEST) # return super().destroy(request, *args, **kwargs) # # def update_external_system(zekken_number, event_code, team_name, class_name, password): # api_url = f"{settings.FRONTEND_URL}/gifuroge/update_team_name" # headers = { # "Content-Type": "application/x-www-form-urlencoded" # } # data = { # "zekken_number": zekken_number, # "new_team_name": team_name, # "event_code": event_code, # } # try: # response = requests.post(api_url,headers=headers, data=data) # response.raise_for_status() # # return True # except requests.RequestException as e: # logger.error(f"Failed to update external system. Error: {str(e)}") # return False # # def update(self, request, *args, **kwargs): # try: # partial = kwargs.pop('partial', False) # instance = self.get_object() # serializer = self.get_serializer(instance, data=request.data, partial=partial) # serializer.is_valid(raise_exception=True) # self.perform_update(serializer) # # if getattr(instance, '_prefetched_objects_cache', None): # instance._prefetched_objects_cache = {} # # return Response(serializer.data) # except Exception as e: # return Response({"error": "更新に失敗しました。競合が発生した可能性があります。"}, status=status.HTTP_409_CONFLICT) # # ## def update(self, request, *args, **kwargs): ## try: ## return super().update(request, *args, **kwargs) ## except Exception as e: ## return Response({"error": "更新に失敗しました。競合が発生した可能性があります。"}, status=status.HTTP_409_CONFLICT) # # def perform_update(self, serializer): # with transaction.atomic(): # team = serializer.save() # # # 外部システムの更新 # success = update_external_system( # team.zekken_number, # team.owner.event_code, # team.team_name, # team.category.category_name, # team.owner.password # ) # if not success: # raise serializers.ValidationError("外部システムの更新に失敗しました。") # else: # print("岐阜ロゲシステム更新に成功") # # @action(detail=True, methods=['post']) # def copy(self, request, pk=None): # original_team = self.get_object() # with transaction.atomic(): # category = NewCategory.objects.select_for_update().get(id=original_team.category.id) # new_zekken_number = category.category_number # category.category_number = F('category_number') + 1 # category.save() # category.refresh_from_db() # F() 式の結果を評価 # # new_team = Team.objects.create( # zekken_number=new_zekken_number, # team_name=f"{original_team.team_name} (コピー)", # category=category, # owner=request.user # ) # for member in original_team.members.all(): # Member.objects.create( # team=new_team, # user=member.user # ) # return Response(TeamSerializer(new_team).data, status=status.HTTP_201_CREATED) # class NewCategoryViewSet(viewsets.ModelViewSet): queryset = NewCategory.objects.all() serializer_class = NewCategorySerializer #permission_classes = [IsAuthenticated] @action(detail=True, methods=['POST']) def get_zekken_number(self, request, pk=None): try: with transaction.atomic(): category = NewCategory.objects.select_for_update().get(pk=pk) category.category_number += 1 category.save() serializer = self.get_serializer(category) return Response(serializer.data) except NewCategory.DoesNotExist: return Response({"error": "Category not found"}, status=status.HTTP_404_NOT_FOUND) except Exception as e: return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST) class NewCategoryListView(generics.ListAPIView): queryset = NewCategory.objects.all() serializer_class = NewCategorySerializer permission_classes = [IsAuthenticated] class CategoryViewSet(viewsets.ModelViewSet): queryset = Category.objects.all() serializer_class = CategorySerializer permission_classes = [IsAuthenticated] class CategoryListView(generics.ListAPIView): queryset = Category.objects.all() serializer_class = CategorySerializer permission_classes = [IsAuthenticated] ''' def get(self, request): categories = Category.objects.all() data = [] for category in categories: category_name = force_str(category.category_name) data.append({ 'category_name': category_name, # その他のフィールド }) return Response(data) ''' class EntryViewSet(viewsets.ModelViewSet): #queryset = Entry.objects.all() serializer_class = EntrySerializer permission_classes = [permissions.IsAuthenticated] #def perform_create(self, serializer): # team = Team.objects.get(owner=self.request.user) # serializer.save(team=team) def get_queryset(self): user = self.request.user # ユーザーが所有するチームのIDを取得 owned_team_ids = Team.objects.filter(owner=user).values_list('id', flat=True) # ユーザーがメンバーとして所属するチームのIDを取得 member_team_ids = Member.objects.filter(user=user).values_list('team_id', flat=True) # 両方のチームに関連するエントリーを取得 return Entry.objects.filter(Q(team__id__in=owned_team_ids) | Q(team__id__in=member_team_ids)) @transaction.atomic def perform_create(self, serializer): category = serializer.validated_data['category'] category = NewCategory.objects.select_for_update().get(id=category.id) zekken_number = category.category_number category.category_number = F('category_number') + 1 category.save() category.refresh_from_db() team = serializer.validated_data['team'] entry = serializer.save(owner=self.request.user, zekken_number=zekken_number) # 外部システムの更新 success = self.register_team( entry.zekken_number, team.owner.event_code, team.team_name, category.category_name, team.owner.password ) if not success: logger.error("Failed to register external system") raise serializers.ValidationError("外部システムの更新に失敗しました。") logger.info("External system registered successfully") def register_team(self, zekken_number, event_code, team_name, category_name, password): api_url = f"{settings.FRONTEND_URL}/gifuroge/register_team" headers = {"Content-Type": "application/x-www-form-urlencoded"} data = { "zekken_number": zekken_number, "event_code": event_code, "team_name": team_name, "class_name": category_name, "password": password } try: response = requests.post(api_url, headers=headers, data=data) response.raise_for_status() logger.info(f"Team registered successfully for zekken_number {zekken_number}") return True except requests.RequestException as e: logger.error(f"Failed to register team. Error: {str(e)}") return False # def create(self, request, *args, **kwargs): # serializer = self.get_serializer(data=request.data) # try: # 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) # except DRFValidationError as e: # return Response({'error': self.format_errors(e.detail)}, status=status.HTTP_400_BAD_REQUEST) # # except IntegrityError: # # return Response({'error': '既に登録済みです'}, status=status.HTTP_400_BAD_REQUEST) # except IntegrityError as e: # return Response({'error': f'データベースエラー: {str(e)}'}, status=status.HTTP_400_BAD_REQUEST) # # except Exception as e: # return Response({'error': f"予期せぬエラーが発生しました: {str(e),'type': str(type(e))}"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) # # def perform_create(self, serializer): # serializer.save(owner=self.request.user) # # # def update(self, request, *args, **kwargs): # logger.info(f"Update method called for Entry with ID: {kwargs.get('pk')}") # logger.debug(f"Request data: {request.data}") # # partial = kwargs.pop('partial', False) # instance = self.get_object() # serializer = self.get_serializer(instance, data=request.data, partial=partial) # # try: # serializer.is_valid(raise_exception=True) # logger.debug(f"Serializer validated data: {serializer.validated_data}") # except serializers.ValidationError as e: # logger.error(f"Validation error: {e.detail}") # return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST) # # try: # self.perform_update(serializer) # logger.info(f"Entry updated successfully: {serializer.data}") # except Exception as e: # logger.exception(f"Error updating Entry: {str(e)}") # return Response({"error": "An error occurred while updating the entry."}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) # # # return Response(serializer.data) # # def destroy(self, request, *args, **kwargs): # instance = self.get_object() # self.perform_destroy(instance) # return Response(status=status.HTTP_204_NO_CONTENT) # # def get_error_message(self, exception): # if hasattr(exception, 'detail'): # if isinstance(exception.detail, dict): # return '. '.join([f"{key}: {', '.join(value)}" for key, value in exception.detail.items()]) # elif isinstance(exception.detail, list): # return '. '.join(exception.detail) # return str(exception) # # def format_errors(self, errors): # if isinstance(errors, list): # return '. '.join(errors) # elif isinstance(errors, dict): # return '. '.join([f"{key}: {value}" if isinstance(value, str) else f"{key}: {', '.join(value)}" for key, value in errors.items()]) # else: # return str(errors) class MemberViewSet(viewsets.ModelViewSet): serializer_class = MemberSerializer permission_classes = [permissions.IsAuthenticated,IsTeamOwner] def get_serializer_class(self): if self.action == 'create': return MemberCreationSerializer return MemberSerializer def get_queryset(self): team_id = self.kwargs['team_id'] return Member.objects.filter(team_id=team_id) @action(detail=False, methods=['DELETE']) def destroy_all(self, request, team_id=None): team = Team.objects.get(id=team_id) # チームのオーナーかどうかを確認 if team.owner != request.user: return Response({"error": "チームのオーナーのみがメンバーを一括削除できます。"}, status=status.HTTP_403_FORBIDDEN) # 確認パラメータをチェック confirm = request.query_params.get('confirm', '').lower() if confirm != 'true': return Response({"error": "確認パラメータが必要です。'?confirm=true'を追加してください。"}, status=status.HTTP_400_BAD_REQUEST) try: with transaction.atomic(): # オーナー以外のすべてのメンバーを削除 #deleted_count = Member.objects.filter(team=team).exclude(user=team.owner).delete()[0] deleted_count = Member.objects.filter(team=team).delete()[0] return Response({ "message": f"{deleted_count}人のメンバーが削除されました。", "deleted_count": deleted_count }, status=status.HTTP_200_OK) except Exception as e: return Response({"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) def destroy(self, request, *args, **kwargs): instance = self.get_object() team = instance.team # チームのオーナーかどうかを確認 if team.owner != request.user: return Response({"error": "チームのオーナーのみがメンバーを削除できます。"}, status=status.HTTP_403_FORBIDDEN) # オーナー自身は削除できないようにする #if instance.user == team.owner: # return Response({"error": "チームのオーナーは削除できません。"}, status=status.HTTP_400_BAD_REQUEST) self.perform_destroy(instance) return Response(status=status.HTTP_204_NO_CONTENT) def create(self, request, *args, **kwargs): logger.info(f"Attempting to create new member for team: {self.kwargs['team_id']}") logger.debug(f"Received data: {request.data}") team = Team.objects.get(id=self.kwargs['team_id']) #serializer = self.get_serializer(data=request.data) serializer = self.get_serializer(data=request.data, context={'team': team}) try: serializer.is_valid(raise_exception=True) except serializers.ValidationError as e: logger.error(f"Validation error: {e.detail}") return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST) email = serializer.validated_data.get('email', '') logger.info(f"Processing member with email: {email}") user_data = { 'firstname': serializer.validated_data.get('firstname', ''), 'lastname': serializer.validated_data.get('lastname', ''), 'date_of_birth': serializer.validated_data.get('date_of_birth'), 'female': serializer.validated_data.get('female', False), } # 自分自身を登録する場合 if request.user.email == email: member, created = Member.objects.get_or_create(user=request.user, team=team) if created: return Response(MemberSerializer(member).data, status=status.HTTP_201_CREATED) else: return Response({"message": "You are already a member of this team."}, status=status.HTTP_200_OK) if not email or email.startswith('dummy_'): logger.info("Processing as direct registration") # 直接登録 try: if email: user, created = CustomUser.objects.get_or_create( email=email, defaults={**user_data, 'is_active':True} ) else: # emailが空の場合、一意のダミーメールアドレスを生成 dummy_email = f"dummy_{uuid.uuid4()}@example.com" user = CustomUser.objects.create(email=dummy_email, **user_data) member = Member.objects.create(user=user, team=team) logger.info(f"Member created successfully: {member.id}") return Response(MemberSerializer(member).data, status=status.HTTP_201_CREATED) except Exception as e: logger.error(f"Error creating member: {str(e)}") return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST) #member = serializer.save(team=team) #return Response(serializer.data, status=status.HTTP_201_CREATED) else: logger.info("Processing as temporary registration") # 仮登録 existing_user = CustomUser.objects.filter(email=email).first() if existing_user: logger.info(f"Existing user found: {existing_user.id}") # 既存ユーザーの場合、チーム招待メールを送信 send_team_join_email(request.user,existing_user, team) return Response({"message": "Invitation for your team sent to existing user."}, status=status.HTTP_200_OK) else: logger.info("Inviting new temporary user") try: print("新規ユーザー") #temp_user = TempUser.objects.create( # email=email, # **user_data, # verification_code=str(uuid.uuid4()) #) send_invitation_email(request.user,request,email, team) #仮登録済みでも確認メールを送る。 logger.info(f"Invitation email sent to: {email}") return Response({"message": "Invitation email sent to the user."}, status=status.HTTP_201_CREATED) except Exception as e: logger.info(f"Error on Invitation email sent to: {email} : {e}") return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST) ''' def create(self, request, *args, **kwargs): team = Team.objects.get(id=self.kwargs['team_id']) serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) try: self.perform_create(serializer) except DRFValidationError as e: return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST) #except ValidationError as e: # return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST) except IntegrityError: return Response({"error": "このユーザーは既にチームのメンバーです。"}, status=status.HTTP_400_BAD_REQUEST) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) ''' ''' def send_activation_email(self, temp_user, team): # アクティベーションメール送信のロジックをここに実装 # 注意: 'user-activation' URLパターンが存在しない場合は、適切なURLを生成する方法を検討する必要があります activation_url = "dummy url" #f"{settings.FRONTEND_URL}/activate/{temp_user.verification_code}" # ここでemailを送信するロジックを実装 print(f"Activation email would be sent to {temp_user.email} with URL: {activation_url}") def send_invitation_email(self, user, team): # チーム招待メール送信のロジック #invitation_url = self.request.build_absolute_uri( # reverse('team-invite', kwargs={'team_id': team.id, 'user_id': user.id}) #) #subject = f"Invitation to join {team.name}" #message = f"You have been invited to join the team {team.name}. Click here to accept: {invitation_url}" #from_email = settings.DEFAULT_FROM_EMAIL #recipient_list = [user.email] #send_mail(subject, message, from_email, recipient_list) # チーム招待メール送信のロジックをここに実装 # 注意: 'team-invitation' URLパターンが存在しない場合は、適切なURLを生成する方法を検討する必要があります # 例えば、フロントエンドのURLを直接指定する方法など invitation_url = "dummy url" #f"{settings.FRONTEND_URL}/team/{team.id}/invite" # ここでemailを送信するロジックを実装 print(f"Invitation email would be sent to {user.email} with URL: {invitation_url}") ''' def perform_create(self, serializer): team = Team.objects.get(id=self.kwargs['team_id']) serializer.save(team=team) @transaction.atomic def update(self, request, *args, **kwargs): #partial = kwargs.pop('partial', False) instance = self.get_object() user = instance.user logger.debug(f"Updating user: {user.email}") logger.debug(f"Received data: {request.data}") if user.email.startswith('dummy_'): logger.debug("User has dummy email, proceeding with update") # 直接データを更新 user.firstname = request.data.get('firstname', user.firstname) user.lastname = request.data.get('lastname', user.lastname) # 日付の処理 date_of_birth = request.data.get('date_of_birth') if date_of_birth: try: date_of_birth = date_of_birth.translate(str.maketrans("0123456789", "0123456789")) parsed_date = parse_date(date_of_birth) if parsed_date: user.date_of_birth = parsed_date else: raise ValueError("Invalid date format") except ValueError: logger.error(f"Invalid date format: {date_of_birth}") return Response({"error": "Invalid date format. Use YYYY-MM-DD."}, status=status.HTTP_400_BAD_REQUEST) user.female = request.data.get('female', user.female) user.save() logger.debug(f"User updated: firstname={user.firstname}, lastname={user.lastname}, date_of_birth={user.date_of_birth}, female={user.female}") # Memberインスタンスも更新 serializer = self.get_serializer(instance, data=request.data, partial=True) serializer.is_valid(raise_exception=True) self.perform_update(serializer) # 更新後のデータを取得 updated_instance = self.get_object() updated_serializer = self.get_serializer(updated_instance) logger.debug(f"Updated user data: {updated_serializer.data}") return Response(updated_serializer.data) else: logger.debug("User does not have dummy email, update not allowed") return Response({"error": "このユーザーの情報は更新できません。"}, status=status.HTTP_403_FORBIDDEN) def perform_update(self, serializer): serializer.save() logger.debug("perform_update called") def get_object(self): queryset = self.get_queryset() member_id = self.kwargs['pk'] obj = get_object_or_404(queryset, id=member_id) self.check_object_permissions(self.request, obj) return obj class ActivateMemberView(APIView): def get(self, request, user_id, team_id): user = get_object_or_404(CustomUser, id=user_id) team = get_object_or_404(Team, id=team_id) # メンバーオブジェクトを取得または作成 member, created = Member.objects.get_or_create(user=user, team=team) if member.lastname == "dummy": # userデータでmemberデータを更新 member.lastname = user.lastname member.firstname = user.firstname member.date_of_birth = user.date_of_birth member.female = user.female member.save() message = f"{team.team_name}に正常に参加し、メンバー情報が更新されました。アプリのチーム管理で確認できます。" else: message = f"{team.team_name}に正常に参加しました。" return render(request, 'activation_success.html', {'message': message}) class ActivateNewMemberView(APIView): def get(self, request, verification_code, team_id): try: team = Team.objects.get(id=team_id) member, created = Member.objects.get_or_create(team=team, user__email=email) if created: return Response({'message': 'Member activated successfully'}, status=status.HTTP_201_CREATED) else: return Response({'message': 'Member already exists'}, status=status.HTTP_200_OK) except Team.DoesNotExist: return Response({'message': 'Invalid team'}, status=status.HTTP_400_BAD_REQUEST) ''' temp_user = get_object_or_404(TempUser, verification_code=verification_code) team = get_object_or_404(Team, id=team_id) user = CustomUser.objects.create_user( email=temp_user.email, password=temp_user.password, # Ensure this is securely handled **{k: v for k, v in temp_user.__dict__.items() if k in ['firstname', 'lastname', 'date_of_birth', 'female']} ) Member.objects.create(user=user, team=team) temp_user.delete() message = f"アカウントが作成され、{team.team_name}に参加しました。アプリのチーム管理で確認できます。" return render(request, 'activation_success.html', {'message': message}) ''' class OwnerEntriesView(generics.ListAPIView): serializer_class = EntrySerializer permission_classes = [permissions.IsAuthenticated] def get_queryset(self): user = self.request.user return Entry.objects.filter(owner=user) class OwnerTeamsView(generics.ListAPIView): serializer_class = TeamSerializer permission_classes = [permissions.IsAuthenticated] def get_queryset(self): user = self.request.user return Team.objects.filter(owner=user) class OwnerMembersView(generics.ListAPIView): serializer_class = MemberSerializer permission_classes = [permissions.IsAuthenticated] def get_queryset(self): user = self.request.user return Member.objects.filter(team__owner=user) class MemberAddView(APIView): def post(self, request, team_id): logger.info(f"Received request to add member to team {team_id}") logger.debug(f"Request data: {request.data}") team = get_object_or_404(Team, id=team_id) logger.info(f"Found team: {team}") serializer = MemberSerializer(data=request.data) if serializer.is_valid(): logger.info("Serializer is valid") try: member = serializer.save(team=team) logger.info(f"Member added successfully: {member}") return Response(serializer.data, status=status.HTTP_201_CREATED) except Exception as e: logger.error(f"Error saving member: {str(e)}") return Response({"detail": str(e)}, status=status.HTTP_400_BAD_REQUEST) else: logger.error(f"Serializer errors: {serializer.errors}") return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class TempUserViewSet(viewsets.ModelViewSet): queryset = TempUser.objects.all() serializer_class = TempUserSerializer permission_classes = [IsAuthenticated] # CustomUserViewSetの修正 class CustomUserViewSet(viewsets.ModelViewSet): queryset = CustomUser.objects.all() serializer_class = CustomUserSerializer permission_classes = [IsAuthenticated] def get_queryset(self): user = self.request.user if user.is_staff: return CustomUser.objects.all() return CustomUser.objects.filter(id=user.id) class TeamMembersView(generics.ListAPIView): serializer_class = MemberSerializer permission_classes = [IsAuthenticated] def get_queryset(self): team_id = self.kwargs['team_id'] return Member.objects.filter(team_id=team_id) # ユーザーのエントリーを取得するビュー class UserEntriesView(generics.ListAPIView): serializer_class = EntrySerializer permission_classes = [IsAuthenticated] def get_queryset(self): user = self.request.user return Entry.objects.filter(team__owner=user) # イベントのカテゴリーを取得するビュー class EventCategoriesView(generics.ListAPIView): serializer_class = NewCategorySerializer permission_classes = [IsAuthenticated] def get_queryset(self): event_id = self.kwargs['event_id'] return NewCategory.objects.filter(entry__event_id=event_id).distinct() # ユーザー仮登録 class RegisterView(APIView): def post(self, request): serializer = TempUserSerializer(data=request.data) if serializer.is_valid(): temp_user = serializer.save() verification_code = uuid.uuid4() temp_user.verification_code = verification_code temp_user.save() verification_url = request.build_absolute_uri( reverse('verify-email', kwargs={'verification_code': verification_code}) ) send_verification_email(temp_user,verifiction_url) #send_mail( # 'Verify your email', # f'Click the link to verify your email: {verification_url}', # settings.DEFAULT_FROM_EMAIL, # [temp_user.email], # fail_silently=False, #) return Response({'message': 'Verification email sent'}, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class ResendInvitationEmailView(APIView): def post(self, request): email = request.data.get('email') if not email: return Response({"error": "メールアドレスを指定してください。"}, status=status.HTTP_400_BAD_REQUEST) try: temp_user = TempUser.objects.get(email=email) verification_url = request.build_absolute_uri( reverse('verify-email', kwargs={'verification_code': temp_user.verification_code}) ) send_verification_email(temp_user, verification_url) logger.info(f"招待メールを再送信しました。Email: {email}") return Response({"message": "招待メールを再送信しました。"}, status=status.HTTP_200_OK) except ObjectDoesNotExist: logger.warning(f"仮登録されていないメールアドレスに対して招待メールの再送信が試みられました。Email: {email}") return Response({"error": "指定されたメールアドレスは仮登録されていません。"}, status=status.HTTP_404_NOT_FOUND) class TempUserRegistrationView(APIView): def post(self, request): email = request.data.get('email') # 本登録済みのユーザーチェック if CustomUser.objects.filter(email=email).exists(): logger.warning(f"既に本登録されているメールアドレスでの仮登録が試みられました。Email: {email}") return Response({"error": "このメールアドレスは既に本登録されています。"}, status=status.HTTP_400_BAD_REQUEST) # 仮登録済みのユーザーチェック try: temp_user = TempUser.objects.get(email=email) verification_url = request.build_absolute_uri( reverse('verify-email', kwargs={'verification_code': temp_user.verification_code}) ) send_verification_email(temp_user, verification_url) logger.info(f"既に仮登録されているユーザーに招待メールを再送信しました。Email: {email}") return Response({"message": "既に仮登録は行われていますが、招待メールを再送信しました。"}, status=status.HTTP_200_OK) except TempUser.DoesNotExist: # 新規仮登録 serializer = TempUserRegistrationSerializer(data=request.data) if serializer.is_valid(): # シリアライザのvalidated_dataからパスワードを取得 password = serializer.validated_data.get('password') # パスワードをハッシュ化 hashed_password = make_password(password) # ハッシュ化されたパスワードでTempUserを作成 temp_user = serializer.save(password=hashed_password) verification_code = uuid.uuid4() temp_user.verification_code = verification_code temp_user.save() verification_url = request.build_absolute_uri( reverse('verify-email', kwargs={'verification_code': verification_code}) ) send_verification_email(temp_user, verification_url) logger.info(f"新規ユーザーを仮登録し、招待メールを送信しました。Email: {email}") return Response({"message": "仮登録が完了しました。招待メールを送信しました。"}, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) #serializer = TempUserRegistrationSerializer(data=request.data) #if serializer.is_valid(): # temp_user = serializer.save() # verification_code = uuid.uuid4() # temp_user.verification_code = verification_code # temp_user.save() # verification_url = request.build_absolute_uri( # reverse('verify-email', kwargs={'verification_code': verification_code}) # ) # send_verification_email(temp_user,verification_url) #招待メールを送る。 # return Response({"message": "仮登録が完了しました。招待メールを送信しました。"}, 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 temp_user.is_valid(): user_data = { 'email': temp_user.email, 'is_rogaining':True, # ここでis_rogainingをTrueに設定 '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, 'firstname': temp_user.firstname, 'lastname': temp_user.lastname, 'date_of_birth': temp_user.date_of_birth, 'female': temp_user.female, } # パスワードを安全にハッシュ化 #hashed_password = make_password(temp_user.password) try: # CustomUserを作成 user = CustomUser.objects.create(**user_data) #user = CustomUser.objects.create_user( # email=user_data['email'], # password=temp_user.password, # ハッシュ化されたパスワードを直接使用 # **{k: v for k, v in user_data.items() if k != 'email'} #) except ValidationError as e: # パスワードのバリデーションエラーなどの処理 return render(request, 'verification_error.html', {'message': str(e), 'title': 'エラー'}) # チームへの追加処理(もし必要なら) if hasattr(temp_user, 'team_id'): team = Team.objects.get(id=temp_user.team_id) Member.objects.create(user=user, team=team) message = f"メールアドレスが確認され、アカウントが作成されました。{team.team_name}のメンバーとして登録されています。アプリでログインして、必要な情報を入力してください。" else: message = "メールアドレスが確認され、アカウントが作成されました。アプリでログインして、必要な情報を入力してください。" temp_user.delete() return render(request, 'verification_success.html', {'message': message,'title':"認証成功"}) else: message = "確認リンクの有効期限が切れています。アプリから認証コードの再送信をしてください。" return render(request, 'verification_success.html', {'message': message,'title':'有効期限切れ'}) except TempUser.DoesNotExist: message = "無効な確認コードです。" return render(request, 'verification_success.html', {'message': message,'title':'無効な確認コードです'}) class MemberUserDetailView(generics.RetrieveAPIView): serializer_class = MemberWithUserSerializer permission_classes = [IsAuthenticated] def get_queryset(self): return Member.objects.select_related('user', 'team') class TeamMembersWithUserView(generics.ListAPIView): serializer_class = MemberWithUserSerializer permission_classes = [IsAuthenticated] def get_queryset(self): team_id = self.kwargs['team_id'] return Member.objects.filter(team_id=team_id).select_related('user', 'team') class PasswordResetRequestView(APIView): def post(self, request): serializer = PasswordResetRequestSerializer(data=request.data) if serializer.is_valid(): email = serializer.validated_data['email'] user = CustomUser.objects.filter(email=email).first() if user: token = default_token_generator.make_token(user) uid = urlsafe_base64_encode(force_bytes(user.pk)) reset_link = f"{settings.FRONTEND_URL}/api/reset-password/{uid}/{token}/" send_reset_password_email(email,reset_link) return Response({"message": "Password reset email sent"}, status=status.HTTP_200_OK) return Response({"message": "User not found"}, status=status.HTTP_404_NOT_FOUND) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class PasswordResetConfirmView(APIView): def get(self, request, uidb64, token): try: uid = force_str(urlsafe_base64_decode(uidb64)) user = CustomUser.objects.get(pk=uid) except (TypeError, ValueError, OverflowError, CustomUser.DoesNotExist): user = None if user is not None and default_token_generator.check_token(user, token): return render(request, 'password_reset.html', {'uid': uidb64, 'token': token}) else: return render(request, 'password_reset_invalid.html') if user is not None and default_token_generator.check_token(user, token): return Response({"message": "Token is valid"}, status=status.HTTP_200_OK) return Response({"message": "Invalid reset link"}, status=status.HTTP_400_BAD_REQUEST) def post(self, request, uidb64, token): try: uid = force_str(urlsafe_base64_decode(uidb64)) user = CustomUser.objects.get(pk=uid) except (TypeError, ValueError, OverflowError, CustomUser.DoesNotExist): return Response({"error": "Invalid reset link"}, status=status.HTTP_400_BAD_REQUEST) if default_token_generator.check_token(user, token): serializer = PasswordResetConfirmSerializer(data=request.data) if serializer.is_valid(): user.set_password(serializer.validated_data['new_password']) user.save() return Response({"message": "Password has been reset successfully"}, status=status.HTTP_200_OK) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) return Response({"error": "Invalid reset link"}, status=status.HTTP_400_BAD_REQUEST)