diff --git a/users/views.py b/users/views.py index 6549698..d8b64a6 100644 --- a/users/views.py +++ b/users/views.py @@ -279,19 +279,49 @@ class UserUpdateView(generics.RetrieveUpdateDestroyAPIView): instance = self.get_object() target_email = instance.email - # is_active만 수정 가능 + update_fields = [] + actions = [] + + # is_active 수정 is_active = request.data.get('is_active') if is_active is not None: instance.is_active = is_active - instance.save(update_fields=['is_active']) + update_fields.append('is_active') + actions.append("activated" if is_active else "deactivated") - action = "activated" if is_active else "deactivated" + # grade 수정 (관리자만 admin 등급 부여 가능) + grade = request.data.get('grade') + if grade is not None: + valid_grades = ['admin', 'manager', 'user'] + if grade not in valid_grades: + return Response( + {"error": f"유효하지 않은 등급입니다. 가능한 값: {valid_grades}"}, + status=status.HTTP_400_BAD_REQUEST + ) + # admin 등급 부여는 admin만 가능 (manager는 불가) + if grade == 'admin' and request.user.grade != 'admin': + return Response( + {"error": "admin 등급 부여는 admin만 가능합니다."}, + status=status.HTTP_403_FORBIDDEN + ) + # 자기 자신의 등급 하향 방지 (실수로 관리자 권한 잃는 것 방지) + if request.user.id == instance.id and instance.grade == 'admin' and grade != 'admin': + return Response( + {"error": "자신의 admin 등급을 변경할 수 없습니다."}, + status=status.HTTP_400_BAD_REQUEST + ) + instance.grade = grade + update_fields.append('grade') + actions.append(f"grade_changed_to_{grade}") + + if update_fields: + instance.save(update_fields=update_fields) logger.info( - f"[USER UPDATE] admin={admin_email} | target={target_email} | action={action} | IP={ip} | UA={ua}" + f"[USER UPDATE] admin={admin_email} | target={target_email} | actions={actions} | IP={ip} | UA={ua}" ) span.add_event( - f"User {action}", - attributes={"admin": admin_email, "target": target_email} + "User updated", + attributes={"admin": admin_email, "target": target_email, "actions": str(actions)} ) serializer = self.get_serializer(instance) @@ -1162,12 +1192,23 @@ class GoogleLoginView(APIView): social_provider="google", social_id=google_id, profile_image=picture, - is_active=True, # 소셜 로그인은 이메일 인증 불필요 + is_active=False, # 관리자 승인 필요 ) # 비밀번호 없이 사용 불가하게 설정 user.set_unusable_password() user.save() - logger.info(f"[GOOGLE LOGIN] user={email} | status=new_user_created | IP={ip} | UA={ua}") + logger.info(f"[GOOGLE LOGIN] user={email} | status=new_user_created_pending | IP={ip} | UA={ua}") + + # 승인 대기 응답 반환 + span.add_event("Google login - pending approval", attributes={"email": email}) + return Response( + { + "error": "회원가입이 완료되었습니다. 관리자 승인 후 로그인할 수 있습니다.", + "code": "PENDING_APPROVAL", + "message": "관리자 승인 대기 중입니다.", + }, + status=status.HTTP_403_FORBIDDEN + ) # 사용자 활성 상태 확인 if not user.is_active: diff --git a/version b/version index dc16803..5d60b2e 100644 --- a/version +++ b/version @@ -1 +1 @@ -v0.0.29 \ No newline at end of file +v0.0.30