import re from django import forms from django.contrib.auth.models import User from .models import Person from .peopleinfo import PEOPLE def format_phone_number(phone): """전화번호에서 대시 제거""" return re.sub(r'[^0-9]', '', phone) def format_phone_with_dash(phone): """전화번호에 대시 추가 (010-1234-5678 형식)""" phone = format_phone_number(phone) if len(phone) == 11: return f"{phone[:3]}-{phone[3:7]}-{phone[7:]}" return phone # peopleinfo.py에서 PEOPLE 데이터를 가져와서 허가된 사람들의 정보로 변환 ALLOWED_PEOPLE = [] for person in PEOPLE: # 전화번호에서 대시 제거 phone_without_dash = format_phone_number(person['연락처']) ALLOWED_PEOPLE.append({ '이름': person['이름'], '연락처': phone_without_dash }) def is_allowed_person(name, phone): """허가된 사람인지 확인""" formatted_phone = format_phone_number(phone) for person in ALLOWED_PEOPLE: if person['이름'] == name and person['연락처'] == formatted_phone: return True return False def is_already_registered(name, phone): """이미 가입한 사용자인지 확인""" # 전화번호 포맷팅 적용 formatted_phone = format_phone_number(phone) # 전화번호로 User 검색 (username이 전화번호이므로) existing_user = User.objects.filter(username=formatted_phone).first() if existing_user: # 해당 User와 연결된 Person이 있는 경우 (이미 회원가입한 상태) try: person = Person.objects.get(user=existing_user) return True except Person.DoesNotExist: pass # 이름과 전화번호로 Person 검색 (user가 있는 경우만 - 이미 회원가입한 상태) if Person.objects.filter( 이름=name, 연락처=formatted_phone, user__isnull=False ).exists(): return True return False def get_allowed_names(): """허가된 모든 이름 목록 반환""" return [person['이름'] for person in ALLOWED_PEOPLE] def get_phone_by_name(name): """이름으로 전화번호 찾기""" for person in ALLOWED_PEOPLE: if person['이름'] == name: return person['연락처'] return None class CustomFileInput(forms.FileInput): """"Currently:" 텍스트를 제거하는 커스텀 파일 입력 위젯""" def get_context(self, name, value, attrs): context = super().get_context(name, value, attrs) # "Currently:" 텍스트 제거 if 'help_text' in context: context['help_text'] = '' return context class Step1PhoneForm(forms.Form): name = forms.CharField( max_length=50, label='이름', widget=forms.TextInput(attrs={ 'class': 'w-full px-4 py-3 rounded-xl bg-gray-700 bg-opacity-80 text-white placeholder-gray-400 border border-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500 transition', 'placeholder': '이름' }) ) phone = forms.CharField( max_length=11, label='전화번호', widget=forms.TextInput(attrs={ 'class': 'w-full px-4 py-3 rounded-xl bg-gray-700 bg-opacity-80 text-white placeholder-gray-400 border border-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500 transition', 'placeholder': '01012345678' }) ) verification_code = forms.CharField( max_length=6, label='인증번호', required=False, widget=forms.TextInput(attrs={ 'class': 'w-full px-4 py-3 rounded-xl bg-gray-700 bg-opacity-80 text-white placeholder-gray-400 border border-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500 transition', 'placeholder': '6자리 인증번호' }) ) def clean(self): cleaned_data = super().clean() name = cleaned_data.get('name') phone = cleaned_data.get('phone') if name and phone: # 전화번호 포맷팅 적용 (대시 제거) formatted_phone = format_phone_number(phone) cleaned_data['phone'] = formatted_phone # 이미 가입한 사용자인지 먼저 확인 if is_already_registered(name, formatted_phone): raise forms.ValidationError('이미 가입한 유저입니다') # 허가되지 않은 사용자인지 확인 if not is_allowed_person(name, formatted_phone): raise forms.ValidationError('초대되지 않은 사용자입니다') return cleaned_data class Step2AccountForm(forms.Form): password1 = forms.CharField( label='Password', widget=forms.PasswordInput(attrs={ 'class': 'w-full px-4 py-3 rounded-xl bg-gray-700 bg-opacity-80 text-white placeholder-gray-400 border border-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500 transition', 'placeholder': 'Password' }) ) password2 = forms.CharField( label='Password (again)', widget=forms.PasswordInput(attrs={ 'class': 'w-full px-4 py-3 rounded-xl bg-gray-700 bg-opacity-80 text-white placeholder-gray-400 border border-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500 transition', 'placeholder': 'Password (again)' }) ) privacy_agreement = forms.BooleanField( required=True, label='정보공개 및 개인정보처리방침 동의', error_messages={ 'required': '회원가입을 계속하기 위해서 정보공개 등에 동의해주세요' }, widget=forms.CheckboxInput(attrs={ 'class': 'w-4 h-4 text-blue-600 bg-gray-700 border-gray-600 rounded focus:ring-blue-500 focus:ring-2' }) ) def clean(self): cleaned_data = super().clean() password1 = cleaned_data.get('password1') password2 = cleaned_data.get('password2') privacy_agreement = cleaned_data.get('privacy_agreement') if password1 and password2 and password1 != password2: raise forms.ValidationError('비밀번호가 일치하지 않습니다.') return cleaned_data def save(self, name, phone, request, commit=True): # 전화번호 포맷팅 적용 formatted_phone = format_phone_number(phone) # 기존 사용자가 있는지 확인 (전화번호로) existing_user = User.objects.filter(username=formatted_phone).first() if existing_user: # 해당 User와 연결된 Person이 있는 경우 (이미 회원가입한 상태) try: person = Person.objects.get(user=existing_user) print(f"[DEBUG] 기존 회원가입 사용자 발견: {existing_user.username}") return existing_user except Person.DoesNotExist: pass try: # 새 사용자 생성 (전화번호를 username으로 사용) user = User.objects.create_user( username=formatted_phone, email='', # 이메일은 빈 값으로 설정 password=self.cleaned_data['password1'], first_name=name ) # 기존 Person 정보가 있는지 확인 (user가 없는 상태) # 전화번호는 대시 제거하여 비교 existing_person = Person.objects.filter( 이름=name, user__isnull=True ).first() # 전화번호 비교 (대시 제거하여) if existing_person: person_phone_clean = re.sub(r'[^0-9]', '', existing_person.연락처) if person_phone_clean != formatted_phone: existing_person = None if existing_person: # 기존 미가입 Person이 있으면 user 연결하고 가입일시 설정 from django.utils import timezone existing_person.user = user existing_person.가입일시 = timezone.now() existing_person.save() print(f"[DEBUG] 기존 Person 업데이트: {name} (user 연결, 가입일시 기록)") return user else: # 기존 Person이 없으면 새로 생성하고 가입일시 설정 from django.utils import timezone Person.objects.create( user=user, 이름=name, 연락처=format_phone_with_dash(formatted_phone), # 대시 있는 전화번호로 저장 소속='', 직책='', 주소='', 사진='profile_photos/default_user.png', 가입일시=timezone.now() # 회원가입 완료 시점 기록 ) print(f"[DEBUG] 새 Person 생성: {name} (가입일시 기록)") return user except Exception as e: print(f"[DEBUG] 사용자 생성 중 오류: {e}") # 이미 존재하는 사용자인 경우 기존 사용자 반환 existing_user = User.objects.filter(username=formatted_phone).first() if existing_user: return existing_user raise e class PhoneVerificationForm(forms.Form): """전화번호 인증 폼""" name = forms.ChoiceField( choices=[('', '이름을 선택하세요')] + [(name, name) for name in get_allowed_names()], label='이름', widget=forms.Select(attrs={ 'class': 'w-full px-4 py-3 rounded-xl bg-gray-700 bg-opacity-80 text-white border border-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500 transition' }) ) phone = forms.CharField( max_length=11, label='전화번호', widget=forms.TextInput(attrs={ 'class': 'w-full px-4 py-3 rounded-xl bg-gray-700 bg-opacity-80 text-white placeholder-gray-400 border border-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500 transition', 'placeholder': '01012345678' }) ) verification_code = forms.CharField( max_length=6, label='인증번호', widget=forms.TextInput(attrs={ 'class': 'w-full px-4 py-3 rounded-xl bg-gray-700 bg-opacity-80 text-white placeholder-gray-400 border border-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500 transition', 'placeholder': '6자리 인증번호' }) ) def clean(self): cleaned_data = super().clean() name = cleaned_data.get('name') phone = cleaned_data.get('phone') if name and phone: # 전화번호 포맷팅 적용 (대시 제거) formatted_phone = format_phone_number(phone) cleaned_data['phone'] = formatted_phone if not is_allowed_person(name, formatted_phone): raise forms.ValidationError('이름과 전화번호가 일치하지 않습니다.') return cleaned_data class PersonForm(forms.ModelForm): """Person 모델 폼""" class Meta: model = Person fields = ['이름', '소속', '직책', '연락처', '주소', '생년월일', '사진', 'keyword1'] widgets = { '이름': forms.TextInput(attrs={ 'class': 'w-full px-4 py-3 rounded-xl bg-gray-200 bg-opacity-80 text-gray-500 border border-gray-300 focus:outline-none', 'readonly': True, 'tabindex': '-1', }), '소속': forms.TextInput(attrs={ 'class': 'w-full px-4 py-3 rounded-xl bg-gray-700 bg-opacity-80 text-white placeholder-gray-400 border border-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500 transition' }), '직책': forms.TextInput(attrs={ 'class': 'w-full px-4 py-3 rounded-xl bg-gray-700 bg-opacity-80 text-white placeholder-gray-400 border border-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500 transition' }), '연락처': forms.TextInput(attrs={ 'class': 'w-full px-4 py-3 rounded-xl bg-gray-200 bg-opacity-80 text-gray-500 border border-gray-300 focus:outline-none', 'readonly': True, 'tabindex': '-1', }), '주소': forms.TextInput(attrs={ 'class': 'w-full px-4 py-3 rounded-xl bg-gray-700 bg-opacity-80 text-white placeholder-gray-400 border border-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500 transition' }), '생년월일': forms.DateInput(attrs={ 'type': 'date', 'class': 'w-full px-4 py-3 rounded-xl bg-gray-700 bg-opacity-80 text-white border border-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500 transition' }), '사진': CustomFileInput(attrs={ 'class': 'w-full px-4 py-3 rounded-xl bg-gray-700 bg-opacity-80 text-white border border-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500 transition' }), 'keyword1': forms.TextInput(attrs={ 'class': 'w-full px-4 py-3 rounded-xl bg-gray-700 bg-opacity-80 text-white placeholder-gray-400 border border-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500 transition', 'placeholder': '검색 키워드 (예: 잘생김, 골프천재, 댄스머신 ...)' }), }