278 lines
10 KiB
Python
278 lines
10 KiB
Python
|
|
"""
|
||
|
|
회원탈퇴 처리를 위한 유틸리티 함수들
|
||
|
|
"""
|
||
|
|
from django.contrib.auth.models import User
|
||
|
|
from django.utils import timezone
|
||
|
|
from .models import Person, WithdrawalRequest
|
||
|
|
from .peopleinfo import PEOPLE
|
||
|
|
|
||
|
|
from .log_utils import log_user_activity
|
||
|
|
from datetime import datetime
|
||
|
|
|
||
|
|
|
||
|
|
def find_original_person_data(person_name, phone_number):
|
||
|
|
"""
|
||
|
|
peopleinfo.py에서 원본 Person 데이터 찾기
|
||
|
|
|
||
|
|
Args:
|
||
|
|
person_name: 사람 이름
|
||
|
|
phone_number: 전화번호 (대시 포함 또는 미포함)
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
dict: 원본 Person 데이터 또는 None
|
||
|
|
"""
|
||
|
|
# 전화번호 정규화 (대시 제거)
|
||
|
|
clean_phone = phone_number.replace('-', '').replace(' ', '')
|
||
|
|
|
||
|
|
for person_data in PEOPLE:
|
||
|
|
original_name = person_data.get('이름', '')
|
||
|
|
original_phone = person_data.get('연락처', '').replace('-', '').replace(' ', '')
|
||
|
|
|
||
|
|
if original_name == person_name and original_phone == clean_phone:
|
||
|
|
return person_data
|
||
|
|
|
||
|
|
return None
|
||
|
|
|
||
|
|
|
||
|
|
def backup_user_data(withdrawal_request):
|
||
|
|
"""
|
||
|
|
탈퇴 전 사용자 데이터 백업
|
||
|
|
|
||
|
|
Args:
|
||
|
|
withdrawal_request: WithdrawalRequest 객체
|
||
|
|
"""
|
||
|
|
try:
|
||
|
|
person = withdrawal_request.person
|
||
|
|
user = withdrawal_request.user
|
||
|
|
|
||
|
|
backup_data = {
|
||
|
|
'user_info': {
|
||
|
|
'username': user.username,
|
||
|
|
'email': user.email,
|
||
|
|
'date_joined': user.date_joined.isoformat() if user.date_joined else None,
|
||
|
|
'last_login': user.last_login.isoformat() if user.last_login else None,
|
||
|
|
},
|
||
|
|
'person_info': {
|
||
|
|
'이름': person.이름,
|
||
|
|
'소속': person.소속,
|
||
|
|
'생년월일': person.생년월일.isoformat() if person.생년월일 else None,
|
||
|
|
'직책': person.직책,
|
||
|
|
'연락처': person.연락처,
|
||
|
|
'주소': person.주소,
|
||
|
|
'사진': person.사진.name if person.사진 else None,
|
||
|
|
'TITLE': person.TITLE,
|
||
|
|
'SEQUENCE': person.SEQUENCE,
|
||
|
|
'keyword1': person.keyword1,
|
||
|
|
'소개글': person.소개글,
|
||
|
|
'모든사람보기권한': person.모든사람보기권한,
|
||
|
|
'비밀번호설정필요': person.비밀번호설정필요,
|
||
|
|
'가입일시': person.가입일시.isoformat() if person.가입일시 else None,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
withdrawal_request.backup_data = backup_data
|
||
|
|
withdrawal_request.save()
|
||
|
|
|
||
|
|
print(f"[WITHDRAWAL] 사용자 데이터 백업 완료: {person.이름}")
|
||
|
|
return True
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
print(f"[WITHDRAWAL_ERROR] 사용자 데이터 백업 실패: {e}")
|
||
|
|
return False
|
||
|
|
|
||
|
|
|
||
|
|
def restore_person_to_original(person):
|
||
|
|
"""
|
||
|
|
Person 데이터를 peopleinfo.py의 원본으로 복원
|
||
|
|
|
||
|
|
Args:
|
||
|
|
person: Person 객체
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
bool: 성공 여부
|
||
|
|
"""
|
||
|
|
try:
|
||
|
|
original_data = find_original_person_data(person.이름, person.연락처)
|
||
|
|
|
||
|
|
if not original_data:
|
||
|
|
print(f"[WITHDRAWAL_ERROR] 원본 데이터를 찾을 수 없음: {person.이름} ({person.연락처})")
|
||
|
|
return False
|
||
|
|
|
||
|
|
# 원본 데이터로 복원
|
||
|
|
person.소속 = original_data.get('소속', '')
|
||
|
|
|
||
|
|
# 생년월일 파싱
|
||
|
|
birth_str = original_data.get('생년월일', '')
|
||
|
|
if birth_str:
|
||
|
|
try:
|
||
|
|
if '.' in birth_str:
|
||
|
|
person.생년월일 = datetime.strptime(birth_str, '%Y.%m.%d').date()
|
||
|
|
elif len(birth_str) == 4:
|
||
|
|
person.생년월일 = datetime.strptime(f"{birth_str}.01.01", '%Y.%m.%d').date()
|
||
|
|
else:
|
||
|
|
person.생년월일 = None
|
||
|
|
except ValueError:
|
||
|
|
person.생년월일 = None
|
||
|
|
else:
|
||
|
|
person.생년월일 = None
|
||
|
|
|
||
|
|
person.직책 = original_data.get('직책', '')
|
||
|
|
person.주소 = original_data.get('주소', '')
|
||
|
|
|
||
|
|
# 사진 경로 처리
|
||
|
|
photo = original_data.get('사진', 'profile_photos/default_user.png')
|
||
|
|
if photo.startswith('media/'):
|
||
|
|
photo = photo[6:]
|
||
|
|
person.사진 = photo
|
||
|
|
|
||
|
|
person.TITLE = original_data.get('TITLE', '')
|
||
|
|
|
||
|
|
# SEQUENCE 처리
|
||
|
|
sequence = original_data.get('SEQUENCE', None)
|
||
|
|
if sequence and sequence != '':
|
||
|
|
try:
|
||
|
|
person.SEQUENCE = int(sequence)
|
||
|
|
except ValueError:
|
||
|
|
person.SEQUENCE = None
|
||
|
|
else:
|
||
|
|
person.SEQUENCE = None
|
||
|
|
|
||
|
|
# 회원가입 시 추가된 정보들 초기화
|
||
|
|
person.user = None # User 연결 해제
|
||
|
|
person.keyword1 = None
|
||
|
|
person.소개글 = None
|
||
|
|
person.모든사람보기권한 = False
|
||
|
|
person.비밀번호설정필요 = False
|
||
|
|
person.가입일시 = None
|
||
|
|
|
||
|
|
person.save()
|
||
|
|
|
||
|
|
print(f"[WITHDRAWAL] Person 데이터 원본 복원 완료: {person.이름}")
|
||
|
|
return True
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
print(f"[WITHDRAWAL_ERROR] Person 데이터 복원 실패: {e}")
|
||
|
|
return False
|
||
|
|
|
||
|
|
|
||
|
|
def process_withdrawal_approval(withdrawal_request, approved_by, admin_notes=None):
|
||
|
|
"""
|
||
|
|
회원탈퇴 승인 처리
|
||
|
|
|
||
|
|
Args:
|
||
|
|
withdrawal_request: WithdrawalRequest 객체
|
||
|
|
approved_by: 승인자 (User 객체)
|
||
|
|
admin_notes: 관리자 메모 (선택사항)
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
bool: 성공 여부
|
||
|
|
"""
|
||
|
|
try:
|
||
|
|
# 1. 사용자 데이터 백업
|
||
|
|
if not backup_user_data(withdrawal_request):
|
||
|
|
return False
|
||
|
|
|
||
|
|
# 2. Person 데이터를 원본으로 복원
|
||
|
|
if not restore_person_to_original(withdrawal_request.person):
|
||
|
|
return False
|
||
|
|
|
||
|
|
# 3. WithdrawalRequest 상태 업데이트 (User 삭제 전에)
|
||
|
|
withdrawal_request.status = 'APPROVED'
|
||
|
|
withdrawal_request.approved_by = approved_by
|
||
|
|
withdrawal_request.approved_date = timezone.now()
|
||
|
|
withdrawal_request.admin_notes = admin_notes
|
||
|
|
withdrawal_request.save()
|
||
|
|
|
||
|
|
# 4. SMS 발송 (User 삭제 전에)
|
||
|
|
try:
|
||
|
|
from A_core.sms_utils import send_withdrawal_approval_sms
|
||
|
|
phone_number = withdrawal_request.user.username # username이 전화번호
|
||
|
|
name = withdrawal_request.person.이름
|
||
|
|
sms_result = send_withdrawal_approval_sms(phone_number, name)
|
||
|
|
if sms_result.get('success'):
|
||
|
|
print(f"[SMS] 탈퇴 승인 SMS 발송 성공: {name} ({phone_number})")
|
||
|
|
else:
|
||
|
|
print(f"[SMS_ERROR] 탈퇴 승인 SMS 발송 실패: {sms_result.get('error', 'Unknown error')}")
|
||
|
|
except Exception as e:
|
||
|
|
print(f"[SMS_ERROR] 탈퇴 승인 SMS 발송 중 오류: {e}")
|
||
|
|
|
||
|
|
# 5. 탈퇴 로그 기록 (User 삭제 전에)
|
||
|
|
try:
|
||
|
|
from .log_utils import log_withdrawal_approval
|
||
|
|
# 간단한 request 객체 모방 (로그 기록용)
|
||
|
|
class SimpleRequest:
|
||
|
|
def __init__(self):
|
||
|
|
self.path = '/admin/withdrawal_approval/'
|
||
|
|
self.method = 'POST'
|
||
|
|
self.META = {'HTTP_REFERER': '', 'HTTP_USER_AGENT': 'Admin System'}
|
||
|
|
self.session = {'session_key': 'admin_session'}
|
||
|
|
def session_key(self):
|
||
|
|
return 'admin_session'
|
||
|
|
|
||
|
|
fake_request = SimpleRequest()
|
||
|
|
log_withdrawal_approval(
|
||
|
|
fake_request,
|
||
|
|
approved_by,
|
||
|
|
withdrawal_request.user.username,
|
||
|
|
withdrawal_request.person.이름,
|
||
|
|
withdrawal_request.id
|
||
|
|
)
|
||
|
|
except Exception as e:
|
||
|
|
print(f"[WITHDRAWAL_WARNING] 탈퇴 로그 기록 실패: {e}")
|
||
|
|
|
||
|
|
# 6. User 삭제
|
||
|
|
user_to_delete = withdrawal_request.user
|
||
|
|
user_username = user_to_delete.username
|
||
|
|
user_to_delete.delete()
|
||
|
|
|
||
|
|
# 7. WithdrawalRequest의 user 필드를 None으로 설정 (이미 SET_NULL이므로 자동 처리됨)
|
||
|
|
|
||
|
|
print(f"[WITHDRAWAL] 회원탈퇴 승인 처리 완료: {user_username}")
|
||
|
|
return True
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
print(f"[WITHDRAWAL_ERROR] 회원탈퇴 승인 처리 실패: {e}")
|
||
|
|
return False
|
||
|
|
|
||
|
|
|
||
|
|
def reject_withdrawal_request(withdrawal_request, approved_by, admin_notes=None):
|
||
|
|
"""
|
||
|
|
회원탈퇴 요청 거부
|
||
|
|
|
||
|
|
Args:
|
||
|
|
withdrawal_request: WithdrawalRequest 객체
|
||
|
|
approved_by: 처리자 (User 객체)
|
||
|
|
admin_notes: 관리자 메모 (선택사항)
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
bool: 성공 여부
|
||
|
|
"""
|
||
|
|
try:
|
||
|
|
# 1. SMS 발송 (상태 변경 전에)
|
||
|
|
try:
|
||
|
|
from A_core.sms_utils import send_withdrawal_rejection_sms
|
||
|
|
phone_number = withdrawal_request.user.username # username이 전화번호
|
||
|
|
name = withdrawal_request.person.이름
|
||
|
|
reason = admin_notes # 관리자 메모를 거부 사유로 사용
|
||
|
|
sms_result = send_withdrawal_rejection_sms(phone_number, name, reason)
|
||
|
|
if sms_result.get('success'):
|
||
|
|
print(f"[SMS] 탈퇴 거부 SMS 발송 성공: {name} ({phone_number})")
|
||
|
|
else:
|
||
|
|
print(f"[SMS_ERROR] 탈퇴 거부 SMS 발송 실패: {sms_result.get('error', 'Unknown error')}")
|
||
|
|
except Exception as e:
|
||
|
|
print(f"[SMS_ERROR] 탈퇴 거부 SMS 발송 중 오류: {e}")
|
||
|
|
|
||
|
|
# 2. 상태 변경
|
||
|
|
withdrawal_request.status = 'REJECTED'
|
||
|
|
withdrawal_request.approved_by = approved_by
|
||
|
|
withdrawal_request.approved_date = timezone.now()
|
||
|
|
withdrawal_request.admin_notes = admin_notes
|
||
|
|
withdrawal_request.save()
|
||
|
|
|
||
|
|
print(f"[WITHDRAWAL] 회원탈퇴 요청 거부: {withdrawal_request.person.이름}")
|
||
|
|
return True
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
print(f"[WITHDRAWAL_ERROR] 회원탈퇴 요청 거부 실패: {e}")
|
||
|
|
return False
|