import uuid from django.db import IntegrityError from django.core.mail import send_mail from django.conf import settings from django.urls import reverse from django.db import transaction from rest_framework import serializers from rest_framework_gis.serializers import GeoFeatureModelSerializer from sqlalchemy.sql.functions import mode from .models import Location, Location_line, Location_polygon, JpnAdminMainPerf, Useractions, GifuAreas, RogUser, UserTracks, GoalImages, CheckinImages,CustomUser,NewEvent,NewEvent2, Team, NewCategory, Category, Entry, Member, TempUser,EntryMember from drf_extra_fields.fields import Base64ImageField #from django.contrib.auth.models import User from .models import CustomUser from django.contrib.auth import authenticate from .utils import send_activation_email from .models import TestModel import logging logger = logging.getLogger(__name__) class LocationCatSerializer(serializers.ModelSerializer): class Meta: model=Location fields=['category',] class LocationSerializer(GeoFeatureModelSerializer): class Meta: model=Location geo_field='geom' fields="__all__" class Location_lineSerializer(GeoFeatureModelSerializer): class Meta: model=Location_line geo_field='geom' fields="__all__" class Location_polygonSerializer(GeoFeatureModelSerializer): class Meta: model=Location_polygon geo_field='geom' fields="__all__" class JPN_main_perfSerializer(serializers.ModelSerializer): class Meta: model=JpnAdminMainPerf fields=['id', 'adm0_en', 'adm0_ja', 'adm0_pcode', 'adm1_en', 'adm1_ja', 'adm1_pcode'] # class JPN_sub_perSerializer(serializers.ModelSerializer): # class Meta: # model=JpnSubPerf # fields=['id', 'adm0_en', 'adm0_ja', 'adm0_pcode', 'adm1_en', 'adm1_ja', 'adm1_pcode', 'adm2_ja', 'adm2_en', 'adm2_pcode'] # class JPN_perfSerializer(serializers.ModelSerializer): # class Meta: # model=JpnAdminPerf # fields=['id','et_id', 'et_right', 'et_left', 'adm2_l', 'adm1_l', 'adm0_l', 'adm0_r', 'adm1_r', 'adm2_r', 'admlevel'] class GifuAreaSerializer(serializers.ModelSerializer): class Meta: model= GifuAreas fields=['id', 'adm0_ja', 'adm0_pcode', 'adm1_en', 'adm1_ja', 'adm1_pcode', 'adm2_ja', 'adm2_en', 'adm2_pcode', 'area_nm'] class CreateUserSerializer(serializers.ModelSerializer): class Meta: model = CustomUser fields = ('email', 'password') extra_kwargs = {'password': {'write_only': True}} def create(self, validated_data): user = CustomUser.objects.create_user(validated_data['email'],validated_data['password'], '大垣-初心者','','') return user class UserSerializer(serializers.ModelSerializer): class Meta: model = CustomUser fields = ('id','email', 'is_rogaining' ,'group', 'zekken_number', 'event_code', 'team_name') class GolaImageSerializer(serializers.ModelSerializer): goalimage = Base64ImageField(max_length=None, use_url=True) class Meta: model = GoalImages fields="__all__" def get_goalimage_url(self, car): request = self.context.get('request') photo_url = GoalImages.goalimage.url return request.build_absolute_uri(photo_url) class CheckinImageSerializer(serializers.ModelSerializer): checkinimage = Base64ImageField(max_length=None, use_url=True) class Meta: model = CheckinImages fields="__all__" def get_checkinimage_url(self, car): request = self.context.get('request') photo_url = CheckinImages.checkinimage.url return request.build_absolute_uri(photo_url) class RogUserSerializer(serializers.ModelSerializer): class Meta: model = RogUser fields = ('id','user', 'paid',) class LoginUserSerializer(serializers.Serializer): email = serializers.CharField() password = serializers.CharField() def validate(self, data): user = authenticate(**data) if user and user.is_active: return user raise serializers.ValidationError("Invalid Details.") class UseractionsSerializer(serializers.ModelSerializer): user = UserSerializer(read_only=True) #location = LocationSerializer(read_only=True) location = serializers.RelatedField(source='Location', read_only=True) #location = serializers.PrimaryKeyRelatedField(many=True, read_only=True) class Meta: model = Useractions fields = ('id', 'user', 'location', 'wanttogo', 'like', 'checkin', 'order',) class UserDestinationSerializer(serializers.ModelSerializer): #user = UserSerializer(read_only=True) location = LocationSerializer(read_only=True) #location = serializers.RelatedField(source='Location', read_only=True) #location = serializers.PrimaryKeyRelatedField(many=True, read_only=True) class Meta: model = Useractions fields = ('id', 'user', 'location', 'wanttogo', 'like', 'checkin') class LocationEventNameSerializer(serializers.ModelSerializer): class Meta: model = Location fields = ('id', 'event_name',) class UserTracksSerializer(GeoFeatureModelSerializer): user_id = serializers.IntegerField() class Meta: model=UserTracks geo_field = 'geom' fields = ["user_id",] def create(self, validated_data): user_id = validated_data.pop("user_id", None) user = CustomUser.objects.get(id=user_id) return UserTracks.objects.create(user=user, **validated_data) class TestSerialiser(serializers.ModelSerializer): class Meta: model = TestModel fields = ('id', 'testbane', 'wanttogo', 'like', 'checkin') class ChangePasswordSerializer(serializers.Serializer): model = CustomUser """ Serializer for password change endpoint. """ old_password = serializers.CharField(required=True) new_password = serializers.CharField(required=True) class RegistrationSerializer(serializers.ModelSerializer): password2 = serializers.CharField(style={"input_type": "password"}, write_only=True) class Meta: model = CustomUser fields = ['email', 'is_rogaining', 'zekken_number', 'event_code', 'team_name', 'group', 'password', 'password2'] extra_kwargs = { 'password': {'write_only': True} } def save(self): user = CustomUser(email=self.validated_data['email'], is_rogaining=self.validated_data['is_rogaining'], zekken_number=self.validated_data['zekken_number'], event_code=self.validated_data['event_code'], team_name=self.validated_data['team_name'], group=self.validated_data['group']) password = self.validated_data['password'] password2 = self.validated_data['password2'] if password != password2: raise serializers.ValidationError({'password': 'Passwords must match.'}) user.set_password(password) user.save() return user class NewCategorySerializer(serializers.ModelSerializer): class Meta: model = NewCategory #fields = ['id','category_name', 'category_number', 'duration', 'num_of_member', 'family', 'female'] fields = ['id','category_name', 'category_number'] class NewEvent2Serializer(serializers.ModelSerializer): class Meta: model = NewEvent2 fields = ['id','event_name', 'start_datetime', 'end_datetime'] class NewEventSerializer(serializers.ModelSerializer): class Meta: model = NewEvent fields = ['event_name', 'start_datetime', 'end_datetime'] class TeamSerializer(serializers.ModelSerializer): #category = serializers.PrimaryKeyRelatedField(queryset=NewCategory.objects.all()) category = NewCategorySerializer(read_only=True) #category_id = serializers.PrimaryKeyRelatedField( # queryset=NewCategory.objects.all(), # source='category', # write_only=True #) owner = serializers.PrimaryKeyRelatedField(read_only=True) class Meta: model = Team fields = ['id','zekken_number', 'team_name', 'category', 'owner'] read_only_fields = ['id', 'owner', 'zekken_number'] def to_representation(self, instance): ret = super().to_representation(instance) ret['category'] = { 'id': instance.category.id, 'category_name': instance.category.category_name, 'category_number': instance.category.category_number } ret['owner'] = CustomUserSerializer(instance.owner).data return ret def validate_category(self, value): if not NewCategory.objects.filter(id=value.id).exists(): raise serializers.ValidationError("Invalid category ID.") return value def create(self, validated_data): category = validated_data.pop('category') team = Team.objects.create(category=category, **validated_data) return team #logger.debug(f"Creating team with data: {validated_data}") #validated_data['owner'] = self.context['request'].user #return super().create(validated_data) def update(self, instance, validated_data): if 'category' in validated_data: instance.category = validated_data.pop('category') return super().update(instance, validated_data) class CategorySerializer(serializers.ModelSerializer): class Meta: model = Category fields = ['category_name', 'category_number', 'duration', 'num_of_member', 'family', 'female'] class EntrySerializer(serializers.ModelSerializer): team = serializers.PrimaryKeyRelatedField(queryset=Team.objects.all()) event = serializers.PrimaryKeyRelatedField(queryset=NewEvent.objects.all()) category = serializers.PrimaryKeyRelatedField(queryset=NewCategory.objects.all()) owner = serializers.PrimaryKeyRelatedField(read_only=True) class Meta: model = Entry fields = ['id','team', 'event', 'category', 'date','owner'] def validate_team(self, value): if not value.members.exists(): raise serializers.ValidationError("チームにメンバーが登録されていません。") return value def to_representation(self, instance): ret = super().to_representation(instance) ret['team'] = instance.team.team_name ret['event'] = instance.event.event_name ret['category'] = instance.category.category_name ret['owner'] = instance.owner.email return ret class CustomUserSerializer(serializers.ModelSerializer): class Meta: model = CustomUser #fields = ['email', 'is_staff', 'is_active', 'is_rogaining', 'zekken_number', 'event_code', 'team_name', 'group', 'firstname', 'lastname', 'date_of_birth', 'female'] fields = ['id','email', 'firstname', 'lastname', 'date_of_birth', 'female'] read_only_fields = ['email'] class TeamDetailSerializer(serializers.ModelSerializer): category = NewCategorySerializer(read_only=True) class Meta: model = Team fields = ['id', 'zekken_number', 'team_name', 'category'] class UserSerializer(serializers.ModelSerializer): class Meta: model = CustomUser fields = ['id','email', 'firstname', 'lastname', 'date_of_birth', 'female', 'is_rogaining', 'zekken_number', 'event_code', 'team_name', 'group'] read_only_fields = ('id', 'email') class UserUpdateSerializer(serializers.ModelSerializer): class Meta: model = CustomUser fields = ['firstname', 'lastname', 'date_of_birth', 'female'] extra_kwargs = {'email': {'read_only': True}} def update(self, instance, validated_data): for attr, value in validated_data.items(): setattr(instance, attr, value) instance.save() return instance class MemberWithUserSerializer(serializers.ModelSerializer): user = UserSerializer(read_only=True) class Meta: model = Member fields = ['user', 'team'] class MemberSerializer(serializers.ModelSerializer): user = CustomUserSerializer() team = TeamDetailSerializer(read_only=True) #email = serializers.EmailField(write_only=True, required=False) #firstname = serializers.CharField(write_only=True, required=False) #lastname = serializers.CharField(write_only=True, required=False) #date_of_birth = serializers.DateField(write_only=True, required=False) #female = serializers.BooleanField(write_only=True, required=False) class Meta: model = Member fields = ['id','user','team'] # ,'email','firstname','lastname','date_of_birth','female'] #read_only_fields = ['id', 'team'] def create(self, validated_data): team = validated_data['team'] email = validated_data.get('email') if email: user, created = CustomUser.objects.get_or_create(email=email) if created: user.firstname = validated_data.get('firstname', '') user.lastname = validated_data.get('lastname', '') user.date_of_birth = validated_data.get('date_of_birth') user.female = validated_data.get('female', False) user.is_active = False user.activation_token = str(uuid.uuid4()) user.save() activation_link = self.context['request'].build_absolute_uri( reverse('user-activation', kwargs={'activation_token': user.activation_token}) ) try: send_activation_email(user, activation_link) except Exception as e: logger.error(f"アクティベーションメールの送信中にエラーが発生しました: {str(e)}") # メール送信に失敗しても、ユーザー作成は続行します else: dummy_email = f"dummy_{uuid.uuid4()}@example.com" user = CustomUser.objects.create( email=dummy_email, firstname=validated_data.get('firstname', ''), lastname=validated_data.get('lastname', ''), date_of_birth=validated_data.get('date_of_birth'), female=validated_data.get('female', False), is_active=True ) try: member = Member.objects.create(user=user, team=team) except IntegrityError: # ユーザーがすでにチームのメンバーの場合 raise serializers.ValidationError("このユーザーは既にチームのメンバーです。") return member def update(self, instance, validated_data): user_data = validated_data.pop('user', {}) user = instance.user if user.email.startswith('dummy_'): # dummy_ で始まるメールアドレスの場合のみ更新 for attr, value in user_data.items(): setattr(user, attr, value) user.save() else: raise serializers.ValidationError("このユーザーの情報は更新できません。") return super().update(instance, validated_data) class EntryMemberSerializer(serializers.ModelSerializer): class Meta: model = EntryMember fields = ['id', 'entry', 'member', 'is_temporary'] class TempUserSerializer(serializers.ModelSerializer): class Meta: model = TempUser fields = ['id','email', 'password', 'is_rogaining', 'zekken_number', 'event_code', 'team_name', 'group', 'firstname', 'lastname', 'date_of_birth', 'female', 'verification_code', 'created_at', 'expires_at'] class EntryCreationSerializer(serializers.Serializer): owner_email = serializers.EmailField() event_name = serializers.CharField() category_name = serializers.CharField() team_name = serializers.CharField() zekken_number = serializers.CharField() date = serializers.DateField() members = serializers.ListField(child=serializers.DictField()) def create(self, validated_data): owner = CustomUser.objects.get(email=validated_data['owner_email']) event = NewEvent2.objects.get(event_name=validated_data['event_name']) category = NewCategory.objects.get(category_name=validated_data['category_name']) # Create or get team team, _ = Team.objects.get_or_create( zekken_number=validated_data['zekken_number'], category=category, defaults={'team_name': validated_data['team_name'], 'owner': owner} ) # Create or update entry entry, _ = Entry.objects.update_or_create( owner=owner, team=team, event=event, date=validated_data['date'], defaults={'category': category} ) # Process members for member_data in validated_data['members']: user, created = CustomUser.objects.get_or_create( email=member_data.get('email'), defaults={ 'firstname': member_data['firstname'], 'lastname': member_data['lastname'], 'date_of_birth': member_data['date_of_birth'] } ) if created: TempUser.objects.create( email=user.email, firstname=user.firstname, lastname=user.lastname, date_of_birth=user.date_of_birth ) # Send invitation email here member, _ = NewMember.objects.get_or_create( user=user, team=team, defaults={'is_temporary': created} ) EntryMember.objects.get_or_create(entry=entry, member=member) return entry