2025-08-03 10:28:43 +09:00
|
|
|
import re
|
|
|
|
|
from django import forms
|
|
|
|
|
from django.contrib.auth.models import User
|
|
|
|
|
from .models import Person
|
2025-08-03 12:30:21 +09:00
|
|
|
from .peopleinfo import PEOPLE
|
2025-08-03 10:28:43 +09:00
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
2025-08-03 12:30:21 +09:00
|
|
|
# peopleinfo.py에서 PEOPLE 데이터를 가져와서 허가된 사람들의 정보로 변환
|
|
|
|
|
ALLOWED_PEOPLE = []
|
|
|
|
|
for person in PEOPLE:
|
|
|
|
|
# 전화번호에서 대시 제거
|
|
|
|
|
phone_without_dash = format_phone_number(person['연락처'])
|
|
|
|
|
ALLOWED_PEOPLE.append({
|
|
|
|
|
'이름': person['이름'],
|
|
|
|
|
'연락처': phone_without_dash
|
|
|
|
|
})
|
2025-08-03 10:28:43 +09:00
|
|
|
|
|
|
|
|
def is_allowed_person(name, phone):
|
|
|
|
|
"""허가된 사람인지 확인"""
|
|
|
|
|
formatted_phone = format_phone_number(phone)
|
2025-08-03 12:30:21 +09:00
|
|
|
for person in ALLOWED_PEOPLE:
|
2025-08-03 10:28:43 +09:00
|
|
|
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():
|
|
|
|
|
"""허가된 모든 이름 목록 반환"""
|
2025-08-03 12:30:21 +09:00
|
|
|
return [person['이름'] for person in ALLOWED_PEOPLE]
|
2025-08-03 10:28:43 +09:00
|
|
|
|
|
|
|
|
def get_phone_by_name(name):
|
|
|
|
|
"""이름으로 전화번호 찾기"""
|
2025-08-03 12:30:21 +09:00
|
|
|
for person in ALLOWED_PEOPLE:
|
2025-08-03 10:28:43 +09:00
|
|
|
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,
|
2025-08-03 12:30:21 +09:00
|
|
|
label='정보공개 및 개인정보처리방침 동의',
|
2025-08-23 19:00:21 +09:00
|
|
|
error_messages={
|
|
|
|
|
'required': '회원가입을 계속하기 위해서 정보공개 등에 동의해주세요'
|
|
|
|
|
},
|
2025-08-03 10:28:43 +09:00
|
|
|
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')
|
2025-08-03 12:30:21 +09:00
|
|
|
privacy_agreement = cleaned_data.get('privacy_agreement')
|
2025-08-03 10:28:43 +09:00
|
|
|
|
|
|
|
|
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:
|
2025-08-23 19:00:21 +09:00
|
|
|
# 기존 미가입 Person이 있으면 user 연결하고 가입일시 설정
|
|
|
|
|
from django.utils import timezone
|
2025-08-03 10:28:43 +09:00
|
|
|
existing_person.user = user
|
2025-08-23 19:00:21 +09:00
|
|
|
existing_person.가입일시 = timezone.now()
|
2025-08-03 10:28:43 +09:00
|
|
|
existing_person.save()
|
2025-08-23 19:00:21 +09:00
|
|
|
print(f"[DEBUG] 기존 Person 업데이트: {name} (user 연결, 가입일시 기록)")
|
2025-08-03 10:28:43 +09:00
|
|
|
return user
|
|
|
|
|
else:
|
2025-08-23 19:00:21 +09:00
|
|
|
# 기존 Person이 없으면 새로 생성하고 가입일시 설정
|
|
|
|
|
from django.utils import timezone
|
2025-08-03 10:28:43 +09:00
|
|
|
Person.objects.create(
|
|
|
|
|
user=user,
|
|
|
|
|
이름=name,
|
|
|
|
|
연락처=format_phone_with_dash(formatted_phone), # 대시 있는 전화번호로 저장
|
|
|
|
|
소속='',
|
|
|
|
|
직책='',
|
|
|
|
|
주소='',
|
2025-08-23 19:00:21 +09:00
|
|
|
사진='profile_photos/default_user.png',
|
|
|
|
|
가입일시=timezone.now() # 회원가입 완료 시점 기록
|
2025-08-03 10:28:43 +09:00
|
|
|
)
|
2025-08-23 19:00:21 +09:00
|
|
|
print(f"[DEBUG] 새 Person 생성: {name} (가입일시 기록)")
|
2025-08-03 10:28:43 +09:00
|
|
|
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',
|
2025-08-24 18:31:27 +09:00
|
|
|
'placeholder': '검색 키워드 (예: 잘생김, 골프천재, 댄스머신 ...)'
|
2025-08-03 10:28:43 +09:00
|
|
|
}),
|
|
|
|
|
}
|