Files
iDRAC_Info/backend/forms/auth_forms.py
2025-10-05 17:37:51 +09:00

116 lines
4.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# backend/forms/auth_forms.py (refactor)
from __future__ import annotations
import re
import unicodedata
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField, BooleanField
from wtforms.validators import (
DataRequired, Length, Email, EqualTo, ValidationError, Regexp
)
from backend.models.user import User
# ─────────────────────────────────────────────────────────────
# 공통 필터/유틸
def strip_filter(x: str | None) -> str | None:
return x.strip() if isinstance(x, str) else x
def lower_strip(x: str | None) -> str | None:
return x.strip().lower() if isinstance(x, str) else x
def nfc_korean(x: str | None) -> str | None:
if not isinstance(x, str):
return x
# 한글 이름 등 유니코드 정규화 (NFC)
return unicodedata.normalize("NFC", x.strip())
# 비밀번호 정책: 8~64자, 대문자/소문자/숫자/특수문자 각 1개 이상
password_policy_validators = [
Length(min=8, max=64, message="비밀번호는 8~64자여야 합니다."),
Regexp(r".*[A-Z].*", message="비밀번호에 대문자가 1자 이상 포함되어야 합니다."),
Regexp(r".*[a-z].*", message="비밀번호에 소문자가 1자 이상 포함되어야 합니다."),
Regexp(r".*\d.*", message="비밀번호에 숫자가 1자 이상 포함되어야 합니다."),
Regexp(r".*[^A-Za-z0-9].*", message="비밀번호에 특수문자가 1자 이상 포함되어야 합니다."),
]
# ─────────────────────────────────────────────────────────────
class RegistrationForm(FlaskForm):
username = StringField(
"이름",
filters=[nfc_korean],
validators=[
DataRequired(message="이름을 입력해주세요."),
Length(min=2, max=20, message="이름은 2~20자 사이여야 합니다."),
],
render_kw={
"placeholder": "이름 (한글만 허용)",
"autocomplete": "name",
"autocapitalize": "off",
"autocorrect": "off",
"spellcheck": "false",
},
)
email = StringField(
"이메일",
filters=[lower_strip],
validators=[
DataRequired(message="이메일을 입력해주세요."),
Email(message="유효한 이메일을 입력하세요."),
],
render_kw={
"placeholder": "예: user@example.com",
"autocomplete": "email",
"inputmode": "email",
},
)
password = PasswordField(
"비밀번호",
validators=[DataRequired(message="비밀번호를 입력해주세요."), *password_policy_validators],
render_kw={"placeholder": "비밀번호", "autocomplete": "new-password"},
)
confirm_password = PasswordField(
"비밀번호 확인",
validators=[
DataRequired(message="비밀번호 확인을 입력해주세요."),
EqualTo("password", message="비밀번호가 일치하지 않습니다."),
],
render_kw={"placeholder": "비밀번호 다시 입력", "autocomplete": "new-password"},
)
submit = SubmitField("회원가입")
def validate_username(self, field):
# 한글만 허용(2~20자) 기존 로직 유지
if not re.fullmatch(r"[가-힣]{2,20}", field.data or ""):
raise ValidationError("이름은 한글로만 2~20자 입력 가능합니다.")
# 중복 체크
user = User.query.filter_by(username=field.data).first()
if user:
raise ValidationError("이미 사용 중인 이름입니다.")
def validate_email(self, field):
# 이메일은 소문자 비교(필터로 이미 소문자화)
user = User.query.filter_by(email=field.data).first()
if user:
raise ValidationError("이미 등록된 이메일입니다.")
class LoginForm(FlaskForm):
email = StringField(
"이메일",
filters=[lower_strip],
validators=[DataRequired(message="이메일을 입력해주세요."), Email(message="유효한 이메일을 입력하세요.")],
render_kw={"placeholder": "이메일 주소", "autocomplete": "username", "inputmode": "email"},
)
password = PasswordField(
"비밀번호",
validators=[DataRequired(message="비밀번호를 입력해주세요.")],
render_kw={"placeholder": "비밀번호", "autocomplete": "current-password"},
)
remember = BooleanField("로그인 유지")
submit = SubmitField("로그인")