diff --git a/ByeBoo-iOS/ByeBoo-iOS.xcodeproj/xcshareddata/xcschemes/ByeBooTests.xcscheme b/ByeBoo-iOS/ByeBoo-iOS.xcodeproj/xcshareddata/xcschemes/ByeBooTests.xcscheme
new file mode 100644
index 00000000..059c58bd
--- /dev/null
+++ b/ByeBoo-iOS/ByeBoo-iOS.xcodeproj/xcshareddata/xcschemes/ByeBooTests.xcscheme
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ByeBoo-iOS/ByeBoo-iOS/Core/ByeBooError.swift b/ByeBoo-iOS/ByeBoo-iOS/Core/ByeBooError.swift
index 1f3f8642..03c1c6bb 100644
--- a/ByeBoo-iOS/ByeBoo-iOS/Core/ByeBooError.swift
+++ b/ByeBoo-iOS/ByeBoo-iOS/Core/ByeBooError.swift
@@ -25,6 +25,8 @@ enum ByeBooError: Error, LocalizedError, Equatable {
case appleLoginError
case endTimer
case configError
+ case fileNotFound
+ case nicknameViolation
var errorDescription: String? {
switch self {
@@ -62,6 +64,10 @@ enum ByeBooError: Error, LocalizedError, Equatable {
return nil
case .configError:
return "info에서 값을 찾을 수 없음"
+ case .fileNotFound:
+ return "파일을 찾을 수 없음"
+ case .nicknameViolation:
+ return nil
}
}
}
diff --git a/ByeBoo-iOS/ByeBoo-iOS/Data/DataDependencyAssembler.swift b/ByeBoo-iOS/ByeBoo-iOS/Data/DataDependencyAssembler.swift
index 8a4305d2..c81a75e4 100644
--- a/ByeBoo-iOS/ByeBoo-iOS/Data/DataDependencyAssembler.swift
+++ b/ByeBoo-iOS/ByeBoo-iOS/Data/DataDependencyAssembler.swift
@@ -44,12 +44,8 @@ struct DataDependencyAssembler: DependencyAssembler {
)
}
- DIContainer.shared.register(type: DefaultNotificationRepository.self) { _ in
- return DefaultNotificationRepository(
- network: networkService,
- userDefaultsService: userDefaultService,
- keychainService: keychainService
- )
+ DIContainer.shared.register(type: ForbiddenWordInterface.self) { _ in
+ return DefaultForbiddenWordRepository()
}
}
}
diff --git a/ByeBoo-iOS/ByeBoo-iOS/Data/ForbiddenWords.json b/ByeBoo-iOS/ByeBoo-iOS/Data/ForbiddenWords.json
new file mode 100644
index 00000000..528c9a12
--- /dev/null
+++ b/ByeBoo-iOS/ByeBoo-iOS/Data/ForbiddenWords.json
@@ -0,0 +1,1550 @@
+{
+ "words": [
+ "10새끼",
+ "10쎄끼",
+ "10알",
+ "10창",
+ "10탱",
+ "10탱아",
+ "10팔",
+ "10팔년",
+ "10팔놈",
+ "10팔연",
+ "10할년",
+ "10할연",
+ "18넘",
+ "18년",
+ "18놈",
+ "18눔",
+ "18늠",
+ "18세끼",
+ "18쉑끼",
+ "18쎄리",
+ "18쒜리",
+ "18쒝끼",
+ "18씨끼",
+ "2c8",
+ "2c팔",
+ "갈보",
+ "강간",
+ "개넘",
+ "개년",
+ "개놈",
+ "개뇬",
+ "개눔",
+ "개늠",
+ "개때꺄",
+ "개때끼",
+ "개또라이",
+ "개똥",
+ "개보지",
+ "개부랄",
+ "개부럴",
+ "개불알",
+ "개새",
+ "개새꺄",
+ "개새끼",
+ "개새리",
+ "개새야",
+ "개색",
+ "개색기",
+ "개색꺄",
+ "개색끼",
+ "개색히",
+ "개샥",
+ "개세",
+ "개세끼",
+ "개세이",
+ "개섹",
+ "개섺",
+ "개셃",
+ "개셋키",
+ "개셐",
+ "개소리",
+ "개쇄끼",
+ "개쇅",
+ "개쇅갸",
+ "개쇅기",
+ "개쇅꺄",
+ "개쇅끼",
+ "개쇅캬",
+ "개쇅키",
+ "개쇗",
+ "개쇗기",
+ "개쇠리",
+ "개쉐",
+ "개쉐끼",
+ "개쉐리",
+ "개쉐이",
+ "개쉑",
+ "개쉑갸",
+ "개쉑기",
+ "개쉑꺄",
+ "개쉑끼",
+ "개쉑이",
+ "개쉑캬",
+ "개쉑키",
+ "개쉑히",
+ "개쉢",
+ "개쉨",
+ "개쉬끼",
+ "개싀끼",
+ "개싘",
+ "개시퀴",
+ "개시키",
+ "개십팔",
+ "개싯끼",
+ "개싯키",
+ "개싴",
+ "개쌍넘",
+ "개쌍년",
+ "개쌍놈",
+ "개쌔",
+ "개쌔꺄",
+ "개쌔끼",
+ "개쌕",
+ "개쌕끼",
+ "개썅넘",
+ "개썅년",
+ "개썅놈",
+ "개썅늠",
+ "개썅연",
+ "개쎅",
+ "개쐐리",
+ "개쒜",
+ "개쒜끼",
+ "개쒜리",
+ "개쒝",
+ "개쒝갸",
+ "개쒝기",
+ "개쒝꺄",
+ "개쒝끼",
+ "개쒝키",
+ "개쒯",
+ "개쒸",
+ "개쒹기",
+ "개씌끼",
+ "개씨끼",
+ "개씨발",
+ "개씨팕",
+ "개씹",
+ "개씹창",
+ "개씹팔",
+ "개자슥",
+ "개자싁",
+ "개자식",
+ "개자지",
+ "개젓",
+ "개젖",
+ "개졋",
+ "개졎",
+ "개조또",
+ "개조옷",
+ "개족",
+ "개좆",
+ "개지랄",
+ "개후레",
+ "개후장",
+ "거시기",
+ "겁탈",
+ "게넘",
+ "게년",
+ "게놈",
+ "게뇬",
+ "게뇽",
+ "게눔",
+ "게새끼",
+ "게새리",
+ "게색",
+ "게색기",
+ "게색끼",
+ "게세",
+ "게세꺄",
+ "게세끼",
+ "게섹",
+ "게쉐",
+ "게쉐이",
+ "게시끼",
+ "게시퀴",
+ "고환",
+ "공짜버그",
+ "공짜캐쉬",
+ "그룹섹스",
+ "그지새끼",
+ "그지좃밥",
+ "그지좃빱",
+ "그지좆밥",
+ "근친",
+ "근친상간",
+ "기엉아",
+ "기형아",
+ "꼴려",
+ "꼴리는",
+ "꼴리다",
+ "난교",
+ "넣게벌려",
+ "넣고싸고",
+ "네에미",
+ "년놈",
+ "니미랄",
+ "니미럴",
+ "니미롤",
+ "니미를",
+ "니보지",
+ "니애미",
+ "니애비",
+ "니어미",
+ "니에미",
+ "니에비",
+ "니좆",
+ "대딸",
+ "딸딸이",
+ "떡치기",
+ "떡칠녀",
+ "룸섹스",
+ "마스터베이션",
+ "매춘",
+ "매춘부",
+ "몸안에사정",
+ "몸캠",
+ "몸켐",
+ "몸파는",
+ "뮈칀세끼",
+ "뮈칀세리",
+ "뮈칀섹끼",
+ "뮈친",
+ "뮈친세리",
+ "뮈친섹끼",
+ "뮈친섹이",
+ "미췬",
+ "미췬년",
+ "미췬세끼",
+ "미췬쉐리",
+ "미친",
+ "미친넘",
+ "미친년",
+ "미친놈",
+ "미친뇬",
+ "미친새끼",
+ "미친세리",
+ "미친섹이",
+ "미친자식",
+ "미튄",
+ "미틘",
+ "미틩",
+ "미틴",
+ "미틴뇬",
+ "밑구녕",
+ "밑구녕빨기",
+ "박고싶다",
+ "박고싶퍼",
+ "박아줄게",
+ "박아줄께",
+ "박을께",
+ "박을년",
+ "뱅쉰",
+ "뱅싄",
+ "뱅신",
+ "뱡신",
+ "버즤",
+ "버지",
+ "버지물",
+ "버짓물",
+ "번섹",
+ "번쌕",
+ "번쎅",
+ "벙어리",
+ "벼엉신",
+ "변섹",
+ "변태",
+ "변퇴",
+ "병쉰",
+ "병싀",
+ "병싄",
+ "병신",
+ "병씬",
+ "보오지",
+ "보쥐",
+ "보즤",
+ "보지",
+ "보지걸",
+ "보지구녕",
+ "보지구멍",
+ "보지나라",
+ "보지당",
+ "보지물",
+ "보지보지",
+ "보지털",
+ "보짓년",
+ "보짓물",
+ "보짖물",
+ "보G",
+ "봉알",
+ "뵤즤",
+ "뵤지",
+ "뵨태",
+ "뵹딱",
+ "뵹싄",
+ "뵹신",
+ "부랄",
+ "부부섹스",
+ "부카케",
+ "불륜",
+ "불알",
+ "붕딱",
+ "붕딲",
+ "붕뛴",
+ "붕싄",
+ "붕시나",
+ "붕신",
+ "붕알",
+ "붜지",
+ "붱신",
+ "뷍슨",
+ "뷍싄",
+ "뷍신",
+ "뷩쉬",
+ "뷩쉰",
+ "뷩싄",
+ "뷩신",
+ "뷰웅신",
+ "븅딱",
+ "븅쉰",
+ "븅싄",
+ "븅시",
+ "븅신",
+ "븅아",
+ "브랄",
+ "블알",
+ "븡딱",
+ "븡쉰",
+ "븡신",
+ "븽딱",
+ "븽쉬",
+ "븽슨",
+ "븽싄",
+ "븽시",
+ "븽신",
+ "비잉신",
+ "빙딱",
+ "빙쉬",
+ "빙쉰",
+ "빙싀",
+ "빙싄",
+ "빙시",
+ "빙신",
+ "빠걸",
+ "빠구리",
+ "빠굴",
+ "빠굴이",
+ "빠꾸리",
+ "빠도리",
+ "빠돌이",
+ "빠라",
+ "빠라조",
+ "빠라줘",
+ "빠러",
+ "빠수니",
+ "빠순이",
+ "빠큐",
+ "빡돌",
+ "빡촌",
+ "빡큐",
+ "빨어핥어박어",
+ "빨자좃",
+ "빨자좆",
+ "빽보지",
+ "빽자지",
+ "뺑신",
+ "뺑쒼",
+ "뺑씬",
+ "뺘큐",
+ "뻐어큐",
+ "뻐큐",
+ "뻐킹",
+ "뼝신",
+ "뽀개",
+ "뽀로노",
+ "뽀르나",
+ "뽀르너",
+ "뽀르노",
+ "뽀쥐",
+ "뽀지",
+ "뽀쮜",
+ "뽕알",
+ "뿅신",
+ "뿅씬",
+ "뿡알",
+ "쁑신",
+ "삐꾸",
+ "삥쉰",
+ "삥쒼",
+ "삥씬",
+ "사까시",
+ "사까치",
+ "사이버섹스",
+ "사창가",
+ "사카시",
+ "사카치",
+ "삽쥘",
+ "삿가시",
+ "삿까시",
+ "삿깟시",
+ "상년",
+ "상노무",
+ "상놈",
+ "새꺄",
+ "새뀌",
+ "새끠",
+ "새끼",
+ "새뤼",
+ "새에끼",
+ "새키",
+ "새X",
+ "색갸",
+ "색걸",
+ "색골",
+ "색광",
+ "색기",
+ "색꺄",
+ "색끼",
+ "색남",
+ "색녀",
+ "색마",
+ "색스",
+ "색쑤",
+ "색쓰",
+ "색캬",
+ "색키",
+ "색할",
+ "색햐",
+ "색히",
+ "샊꺄",
+ "샤불년",
+ "샤앙년",
+ "샵년",
+ "샹넘",
+ "샹년",
+ "샹놈",
+ "샹늠",
+ "성관계",
+ "성교",
+ "성매매",
+ "성섹스",
+ "성욕구",
+ "성인용품",
+ "성체위",
+ "성체험",
+ "성추행",
+ "성충동",
+ "성폭력",
+ "성폭행",
+ "성행위",
+ "세게빨아",
+ "세꺄",
+ "세뀌",
+ "세끠",
+ "세끼",
+ "세액스",
+ "세에끼",
+ "세에쓰",
+ "세엑",
+ "세퀴",
+ "세키",
+ "섹남",
+ "섹녀",
+ "섹마",
+ "섹보지",
+ "섹수",
+ "섹쉬",
+ "섹슈",
+ "섹스",
+ "섹시",
+ "섹파트너",
+ "섹하자",
+ "섹하장",
+ "섹할",
+ "섹해",
+ "섹히",
+ "섹s",
+ "수간",
+ "수음",
+ "쉑수",
+ "쉑스",
+ "쉑쑤",
+ "쉑쓰",
+ "쉑캬",
+ "스와핑",
+ "스트립쇼",
+ "스트립쑈",
+ "스펄",
+ "십8",
+ "십넘",
+ "십녀",
+ "십놈",
+ "십때꺄",
+ "십때끼",
+ "십떼끼",
+ "십밸",
+ "십새",
+ "십새꺄",
+ "십새끼",
+ "십새캬",
+ "십새키",
+ "십색",
+ "십색꺄",
+ "십색끼",
+ "십색히",
+ "십세",
+ "십세끼",
+ "십쇄리",
+ "십쉐",
+ "십쉐리",
+ "십쉐이",
+ "십쉑",
+ "십쉑히",
+ "십시끼",
+ "십쌔",
+ "십쌔꺄",
+ "십쎄끼",
+ "십씨키",
+ "십알",
+ "십질",
+ "십창",
+ "십탱",
+ "십탱구리",
+ "십팔",
+ "십팔년",
+ "십팔련",
+ "십팔연",
+ "십할",
+ "십할련",
+ "싯끼",
+ "싯빨",
+ "싯팔",
+ "싲팔",
+ "싴팔",
+ "싵팔",
+ "싶알",
+ "싶팔",
+ "싸발년",
+ "싸앙넘",
+ "싸앙녀",
+ "싸앙년",
+ "싸줄께",
+ "싹년",
+ "쌉년",
+ "쌍넌",
+ "쌍넘",
+ "쌍년",
+ "쌍념",
+ "쌍노무",
+ "쌍놈",
+ "쌍놈아",
+ "쌍뇨나",
+ "쌍뇬",
+ "쌍뇸",
+ "쌍뇽",
+ "쌍뉸",
+ "쌍연",
+ "쌔꺄",
+ "쌔끼",
+ "쌔리",
+ "쌔캬",
+ "쌔키",
+ "쌕",
+ "쌕갸",
+ "쌕걸",
+ "쌕꺄",
+ "쌕수",
+ "쌕스",
+ "쌕쑤",
+ "쌕쓰",
+ "쌩보지",
+ "쌩포르노",
+ "쌰앙넘",
+ "쌰앙녀",
+ "쌰앙년",
+ "쌰앙눔",
+ "쌰앙뉸",
+ "썁색",
+ "썅",
+ "썅넌",
+ "썅넘",
+ "썅녀",
+ "썅년",
+ "썅놈",
+ "썅뇬",
+ "썅연",
+ "썩을년",
+ "쎅스",
+ "쓰글넘",
+ "쓰글년",
+ "쓰글놈",
+ "쓰글늠",
+ "쓰발",
+ "쓰발넘",
+ "쓰벌",
+ "쓰불",
+ "쓰뷀",
+ "쓰블",
+ "씨댕",
+ "씨댕년",
+ "씨뎅",
+ "씨바",
+ "씨바라",
+ "씨박",
+ "씨발",
+ "씨발넘",
+ "씨발년",
+ "씨발놈",
+ "씨발놈아",
+ "씨방새",
+ "씨방세",
+ "씨뱔",
+ "씨벌",
+ "씨벌년",
+ "씨벧",
+ "씨벨년",
+ "씨벵",
+ "씨봉",
+ "씨봉알",
+ "씨부랄",
+ "씨부럴",
+ "씨불",
+ "씨불년",
+ "씨불얼",
+ "씨붕",
+ "씨뷀",
+ "씨브",
+ "씨브랄",
+ "씨브럴",
+ "씨블",
+ "씨블년",
+ "씨앙년",
+ "씨양년",
+ "씨이바",
+ "씨이발",
+ "씨이방",
+ "씨이밸",
+ "씨이벌",
+ "씨이빨",
+ "씨이팔",
+ "씨입년",
+ "씨입뇬",
+ "씨파",
+ "씨팍",
+ "씨팏",
+ "씨팔",
+ "씨팔년",
+ "씨펄",
+ "씹",
+ "씹8",
+ "씹넘",
+ "씹년",
+ "씹놈",
+ "씹뇬",
+ "씹딱꿍",
+ "씹때꺄",
+ "씹때끼",
+ "씹떼",
+ "씹떼끼",
+ "씹물",
+ "씹밸",
+ "씹벌",
+ "씹보지",
+ "씹보지년",
+ "씹블",
+ "씹빡",
+ "씹빨",
+ "씹뻘",
+ "씹새",
+ "씹새꺄",
+ "씹새끼",
+ "씹새캬",
+ "씹새키",
+ "씹색꺄",
+ "씹색끼",
+ "씹색히",
+ "씹샛길",
+ "씹생알",
+ "씹세",
+ "씹세끼",
+ "씹세이",
+ "씹쉐",
+ "씹쉐리",
+ "씹쉐이",
+ "씹쉑",
+ "씹쉑히",
+ "씹쌔",
+ "씹쌔기",
+ "씹쌔꺄",
+ "씹쌔끼",
+ "씹쌔키",
+ "씹쎄",
+ "씹쎄끼",
+ "씹쒜",
+ "씹씨키",
+ "씹알",
+ "씹연",
+ "씹질",
+ "씹창",
+ "씹탱",
+ "씹탱구리",
+ "씹팔",
+ "씹팔년",
+ "씹팔련",
+ "씹팔연",
+ "씹펄",
+ "씹풀",
+ "씹할",
+ "씹할련",
+ "씹할연",
+ "씻끼",
+ "씻발",
+ "씻벌",
+ "씻뻘",
+ "씻퐁",
+ "씾팔",
+ "앂년",
+ "앂팔",
+ "아이템매니아",
+ "아이템메니아",
+ "아이템베이",
+ "안에사정",
+ "알몸",
+ "알몸공개",
+ "알몸사진",
+ "알몸쇼",
+ "애액",
+ "앰병",
+ "앰창",
+ "야녀",
+ "야동",
+ "야설",
+ "엄창",
+ "에믜",
+ "에미",
+ "여자보지",
+ "염병",
+ "염병할",
+ "엿먹",
+ "엿먹어",
+ "옘병",
+ "오나니",
+ "오랄",
+ "오럴",
+ "오럴섹스",
+ "오르가즘",
+ "옹녀",
+ "왕보지",
+ "왕자지",
+ "우라질",
+ "원조교재",
+ "원조교제",
+ "원조알바",
+ "월경",
+ "유두",
+ "유방",
+ "육봉",
+ "육시랄",
+ "육시럴",
+ "윤간",
+ "윤락",
+ "음경",
+ "음담패설",
+ "음란",
+ "음순",
+ "음액",
+ "음욕",
+ "입사후장",
+ "입안사정",
+ "자위",
+ "자위기구",
+ "자위남",
+ "자위녀",
+ "자지",
+ "잡년",
+ "잡놈",
+ "잡뇬",
+ "젓가튼",
+ "젓같은",
+ "젓까",
+ "젓까는",
+ "젓나",
+ "젓나게",
+ "젓마난",
+ "젓만한",
+ "젓밥",
+ "젓빠지게",
+ "정박아",
+ "정자",
+ "젖",
+ "젖가튼",
+ "젖같은",
+ "젖까",
+ "젖까는",
+ "젖꼭지",
+ "젖나게",
+ "젖도",
+ "젖마난",
+ "젖만한",
+ "젖물",
+ "젖밥",
+ "젖빠지게",
+ "젖탱이",
+ "젖통",
+ "조가틍",
+ "조까",
+ "조까는",
+ "조까라",
+ "조까튼",
+ "조낸",
+ "조또",
+ "조루",
+ "조빠라",
+ "조빠지게",
+ "조빱",
+ "조옷나",
+ "조질래",
+ "조카툰",
+ "조털",
+ "족가튼",
+ "좀물",
+ "좃",
+ "좃가튼",
+ "좃같은",
+ "좃까",
+ "좃까는",
+ "좃까라",
+ "좃나",
+ "좃나게",
+ "좃도",
+ "좃물",
+ "좃밥",
+ "좃빠지게",
+ "좄까",
+ "좆",
+ "좆구녕",
+ "좆까",
+ "좆까는",
+ "좆나",
+ "좆대가리",
+ "좆도",
+ "좆물",
+ "좆밥",
+ "좇",
+ "좇까",
+ "죳",
+ "죶",
+ "죶가튼",
+ "죶빠지게",
+ "지랄",
+ "짬지",
+ "찌찌",
+ "창남",
+ "창녀",
+ "창녀촌",
+ "창년",
+ "창뇨",
+ "창뇬",
+ "챵녀",
+ "챵년",
+ "챵뇬",
+ "처녀막",
+ "최음제",
+ "카섹",
+ "카섹스",
+ "캐세끼",
+ "캐쉬버그",
+ "캐시버그",
+ "큰보지",
+ "큰자지",
+ "페니스",
+ "포르노",
+ "포르노사진",
+ "포르노섹스",
+ "폰색",
+ "폰세엑",
+ "폰섹",
+ "폰섹스",
+ "폰쉑",
+ "폰쌕",
+ "폰쎅",
+ "프리섹스",
+ "플레이보지",
+ "한번꽂자",
+ "한번주께",
+ "한번줄래",
+ "핥아주께",
+ "핧아줄께",
+ "함대주까",
+ "함대줄래",
+ "함빨자",
+ "항문",
+ "허벌",
+ "허벌창",
+ "호로년",
+ "호로새끼",
+ "호로새리",
+ "호로색",
+ "호로색끼",
+ "호로자슥",
+ "호로자식",
+ "호모섹기",
+ "호모쎄끼",
+ "호빠",
+ "호스트바",
+ "호스트빠",
+ "혼음",
+ "화냥",
+ "화냥년",
+ "화류",
+ "화양년",
+ "후레자식",
+ "후장",
+ "후장입사",
+ "ac발",
+ "x대가리",
+ "간나새끼",
+ "간나",
+ "개간나",
+ "쌍간나",
+ "종간나",
+ "좆간나",
+ "개판",
+ "개꼴통",
+ "개똥차",
+ "개쌍판",
+ "개꿈",
+ "개수작",
+ "개망나니",
+ "개돼지",
+ "개쓰레기",
+ "개족새",
+ "개차반",
+ "개초딩",
+ "걸레",
+ "고자",
+ "광녀",
+ "광년이",
+ "괴뢰",
+ "괴뢰군",
+ "그지깽깽이",
+ "급식충",
+ "김치녀",
+ "김치남",
+ "꺼벙이",
+ "꼬붕",
+ "꼰대",
+ "꼴통",
+ "남창",
+ "ㄴㄷㅆ",
+ "느개비",
+ "느금마",
+ "니미",
+ "니기미",
+ "닥쳐",
+ "따까리",
+ "또라이",
+ "똘추",
+ "렉카충",
+ "맘충",
+ "매국노",
+ "머저리",
+ "먹사",
+ "멍청도",
+ "메갈리아",
+ "워마드",
+ "보슬아치",
+ "무뇌",
+ "무뇌충",
+ "미친개",
+ "바보",
+ "버러지",
+ "변태새끼",
+ "벌레새끼",
+ "보전깨",
+ "보지년",
+ "보추",
+ "빠돼쌍",
+ "빨통",
+ "빡대가리",
+ "빨갱이",
+ "싸이코",
+ "사이코",
+ "상폐녀",
+ "상폐년",
+ "상폐놈",
+ "썩을놈",
+ "씨방놈",
+ "씨방년",
+ "시부랄",
+ "씹창년",
+ "씹덕",
+ "씹쓰레기",
+ "씹치남",
+ "씹치년",
+ "쌍노무새끼",
+ "아다",
+ "후다",
+ "애비충",
+ "애새끼",
+ "애자",
+ "양놈",
+ "앰흑",
+ "엠창",
+ "니미씨발",
+ "오유충",
+ "운지",
+ "육변기",
+ "응 니애미",
+ "인조새",
+ "일베충",
+ "저능아",
+ "정신병자",
+ "제기랄",
+ "제길",
+ "졸라",
+ "좆망",
+ "좆무위키",
+ "좆만이",
+ "존만이",
+ "좆집",
+ "좆심",
+ "좆병신",
+ "쥐새끼",
+ "쥐박이",
+ "짭새",
+ "짱깨",
+ "쪼다",
+ "쩌리",
+ "쪽발이",
+ "쪽바리",
+ "쫄보",
+ "찌랭이",
+ "찌질이",
+ "찐따",
+ "찐찌버거",
+ "창놈",
+ "촛불좀비",
+ "최순실",
+ "추남",
+ "추녀",
+ "트롤",
+ "틀딱충",
+ "피싸개",
+ "한남",
+ "한남충",
+ "한녀",
+ "한녀충",
+ "호구",
+ "호모",
+ "후빨",
+ "흑형",
+ "땅크",
+ "달창",
+ "네다홍",
+ "레이디가카",
+ "레이디 가카",
+ "민주화",
+ "ㅁㅈㅎ",
+ "전땅크",
+ "보빨",
+ "산업화",
+ "슨상",
+ "슨탄절",
+ "슨삭절",
+ "슨상그라드",
+ "ㅇㅂ",
+ "암베",
+ "앙망",
+ "엑윽",
+ "엑윽엑엑",
+ "엑엑윽엑",
+ "엘젤두환",
+ "엔두나",
+ "원조가카",
+ "가카",
+ "이시국충",
+ "일게이",
+ "일밍아웃",
+ "파오후",
+ "쿰척쿰척",
+ "허버허버",
+ "폭동절",
+ "혁명절",
+ "탕탕절",
+ "혼모노",
+ "MC무현",
+ "노무",
+ "노알라",
+ "노운지",
+ "노탄절",
+ "뇌물현",
+ "부엉이바위",
+ "이기야",
+ "중력절",
+ "운지절",
+ "달빛기사단",
+ "박사모",
+ "관잦",
+ "관좆",
+ "군무새",
+ "군쾅이",
+ "김아재",
+ "꽁치남",
+ "냄져",
+ "냄적냄",
+ "느갭",
+ "빠가남",
+ "소추",
+ "6.9",
+ "싸튀충",
+ "대디충",
+ "애호박남",
+ "와랄랄라",
+ "자댕이",
+ "자릉내",
+ "자들자들",
+ "자이루",
+ "자적자",
+ "자혐",
+ "조팔",
+ "좆들좆들",
+ "좆스플레인",
+ "줄쓰콘",
+ "팥죽남",
+ "후전깨",
+ "한남유충",
+ "함흥자지",
+ "운동권",
+ "꿘",
+ "방관충",
+ "박근혜",
+ "문재인",
+ "이명박",
+ "전두환",
+ "김대중",
+ "박정희",
+ "노태우",
+ "김영삼",
+ "노무현",
+ "번탈남",
+ "자르셋",
+ "자트릭스",
+ "좆의숙주",
+ "한남또",
+ "허수애비",
+ "투명애비",
+ "씹치",
+ "재기하다",
+ "명자",
+ "갓치",
+ "보지대장부",
+ "성님",
+ "탈코르셋",
+ "보력지원",
+ "흉자",
+ "가좆",
+ "기수짓",
+ "기안내",
+ "남리남리",
+ "똥냐",
+ "망혼",
+ "바용가",
+ "쓰까페미",
+ "앱친",
+ "앱티엠",
+ "정혈",
+ "젠신병자",
+ "하용가",
+ "혐애",
+ "힘조",
+ "힘죠",
+ "홍본자무죄",
+ "6작은따옴표9",
+ "66큰따옴표99",
+ "좆한민국",
+ "개저씨",
+ "페미니즘",
+ "페미나치",
+ "트페미",
+ "병신새끼",
+ "좆나게",
+ "존나게",
+ "전나게",
+ "졸라게",
+ "절라게",
+ "존나",
+ "젖나",
+ "전나",
+ "절라",
+ "좆만한",
+ "좃만한",
+ "존만한",
+ "좆마난",
+ "좃마난",
+ "존마난",
+ "좆같은",
+ "좆가튼",
+ "좃가튼,",
+ "저까튼",
+ "좆빠지게",
+ "저빠지게",
+ "좁밥",
+ "접밥",
+ "저빱",
+ "저까",
+ "씨이불",
+ "띠발",
+ "띠벌",
+ "띠불",
+ "띠방",
+ "띠바",
+ "띠붕",
+ "띠밸",
+ "띠팔",
+ "띠펄",
+ "시벌",
+ "시팔",
+ "시이발",
+ "시이벌",
+ "시이불",
+ "시이바",
+ "시이붕",
+ "시이부",
+ "시이밸",
+ "시이팔",
+ "시이펄",
+ "시이풀",
+ "시이빡",
+ "쒸발",
+ "쒸벌",
+ "쒸불",
+ "쒸방",
+ "쒸바",
+ "쒸빡",
+ "쒸이발",
+ "쒸이벌",
+ "쒸이불",
+ "쒸이방",
+ "쒸이바",
+ "쉬발",
+ "쉬벌",
+ "쉬불",
+ "쉬방",
+ "쉬바",
+ "쉬붕",
+ "쉬부",
+ "쉬밸",
+ "쉬팔",
+ "쉬풀",
+ "쉬빡",
+ "쓰방",
+ "쓰바",
+ "쓰붕",
+ "쓰부",
+ "쓰밸",
+ "쓰팔",
+ "쓰펄",
+ "쓰풀",
+ "쓰빡",
+ "쓰이발",
+ "쓰이벌",
+ "쓰이불",
+ "까대",
+ "까댄",
+ "니미룰",
+ "제기럴",
+ "제기롤",
+ "제기룰",
+ "닝기미",
+ "니주가리",
+ "개넌",
+ "지럴",
+ "지롤",
+ "쥐랄",
+ "쥐럴",
+ "쥐롤",
+ "등신",
+ "미췬놈",
+ "미췬넘",
+ "미친넌",
+ "미췬뇬",
+ "미췬넌",
+ "싸가지",
+ "싹아지",
+ "c팔",
+ "개같은년",
+ "c8",
+ "개같은놈",
+ "씝할",
+ "쉐끼",
+ "쇄끼",
+ "쇅끼",
+ "씨키",
+ "ㅅ ㅐ끼",
+ "ㅅ ㅐㄲ ㅣ",
+ "ㅅ ㅐ ㄲ ㅣ",
+ "시발",
+ "싀발",
+ "스발",
+ "스벌",
+ "쉬이발",
+ "쓰으방",
+ "쉬빨",
+ "쉬팍",
+ "씁알",
+ "씝알",
+ "씝탱",
+ "존니",
+ "죶나",
+ "죨라",
+ "죶니",
+ "죤니",
+ "죤나",
+ "죶마난",
+ "죶같은",
+ "즤랄",
+ "질알",
+ "ㅇㅐ자",
+ "니엠",
+ "믜친",
+ "ㅁl친",
+ "애쟈",
+ "떠라이",
+ "ㅆl팔",
+ "ㅆl발",
+ "ㄴ ㅣㅁ ㅣ",
+ "ㄴlㅁl",
+ "늬미",
+ "니믜",
+ "쓰팍",
+ "씌팔",
+ "씌발",
+ "싀팔",
+ "ㅆ1팔",
+ "ㅆ1발",
+ "계같은뇬",
+ "개같은뇬",
+ "죳나",
+ "니앰",
+ "애미",
+ "씹땡",
+ "씝년",
+ "ㄱH뇬",
+ "씌벌",
+ "싀방",
+ "싀봉",
+ "씌방",
+ "ㅆI발",
+ "ㅅ1발",
+ "ㄴ1ㅇH미",
+ "ㅈl랄",
+ "미칀",
+ "호로자슥애",
+ "젠장",
+ "젱장",
+ "제긜",
+ "젝일",
+ "바부",
+ "듕신",
+ "씨벨",
+ "시벵",
+ "시펄",
+ "등쉬",
+ "늬귀미",
+ "씨밝",
+ "개샛끼",
+ "개쓰렉기",
+ "쉬키",
+ "세캬",
+ "식키",
+ "시키",
+ "새캬",
+ "듕시나",
+ "똘아이",
+ "ㅁ1친",
+ "ㅁ1친년",
+ "뮈췬",
+ "뮈친년",
+ "미췐",
+ "미췐년",
+ "및친",
+ "벵신",
+ "병시나",
+ "병시",
+ "뷩시",
+ "색귀",
+ "셥새",
+ "쉽년",
+ "쉽새",
+ "시바라",
+ "쉽팔",
+ "시밝",
+ "시벨",
+ "십샹",
+ "ㅆ│발",
+ "쒸뱅",
+ "씌파",
+ "씌빨",
+ "씌밸",
+ "씌바",
+ "쒸박",
+ "씨뱅",
+ "c발",
+ "g랄",
+ "zl랄",
+ "凸,미워",
+ "뉘미",
+ "뉘귀미",
+ "^^ㅣ발",
+ "ㄱ ㅐ",
+ "ㅅ ㅐㄱㄱㅣ",
+ "ㄱH",
+ "ㅅ ㅔㄲ ㅣ",
+ "ㅅHㄲI",
+ "ㅅH끼",
+ "ㅅ ㅔㄲ",
+ "ㅅ1팔",
+ "ㅆ ㅣ불",
+ "ㅆㅂ",
+ "ㅅㅂ",
+ "씹발",
+ "개`",
+ "개쇄",
+ "씨`발",
+ "새'꺄",
+ "새'끼",
+ "섀캬",
+ "샹뇬",
+ "쇄키",
+ "섀끼",
+ "쌔기",
+ "ㅁ ㅣ친",
+ "망할",
+ "씨'발",
+ "씨빨",
+ "씹쌍",
+ "ㅈ1랄",
+ "ㅆ ㅣ발",
+ "ㅆ ㅣ방",
+ "ㅆ ㅣ팔",
+ "ㅆ ㅣ벌",
+ "ㅆ!발",
+ "쒸벨",
+ "등쉰",
+ "똘츄",
+ "ㄴ ㅣ미",
+ "ㄴ ㅣㄱ ㅣ",
+ "ㄴ1ㄱ1",
+ "ㄴ1ㅁ1",
+ "ㄴ1미",
+ "ㄴ1 ㅇ ㅐ",
+ "ㄴ1 애",
+ "니M창",
+ "니OH미",
+ "시팍",
+ "시빨",
+ "시파",
+ "시밸",
+ "쉽뇬",
+ "개련",
+ "ㅆ1밸",
+ "ㅆ1벨",
+ "씌벨",
+ "애좌",
+ "씻팔",
+ "ㅆ1바",
+ "개샛히애",
+ "색휘",
+ "섹키",
+ "쓉년",
+ "쓉창",
+ "호로자식애",
+ "씌뱅",
+ "씨팰",
+ "씌댕",
+ "씌뎅",
+ "엠병",
+ "후레자식애",
+ "후레자슥애",
+ "후레년",
+ "씹빠",
+ "뻑큐",
+ "ㅃr큐",
+ "개섀끼",
+ "개샹련",
+ "니뮈럴",
+ "늬기미",
+ "쓰박",
+ "씹샹",
+ "연병",
+ "시밟",
+ "뒤져",
+ "짜져",
+ "꺼져",
+ "뒤질래",
+ "디질래",
+ "아갈",
+ "허접",
+ "흐접",
+ "낙태아",
+ "다방년",
+ "애비자지",
+ "애미보지",
+ "잠지",
+ "공알",
+ "딸따리",
+ "섹쓰",
+ "쎅쓰",
+ "개싑창",
+ "죷",
+ "좇나",
+ "욧나",
+ "쟈지",
+ "죠또",
+ "죵나",
+ "자쥣",
+ "죠빠",
+ "쫓까",
+ "죡쳐",
+ "쟘쥐",
+ "꼬추",
+ "꼬츄",
+ "걸레년",
+ "곧휴",
+ "쟘지",
+ "ㅈ ㅏㅈ ㅣ",
+ "ㅈ ㅏ지",
+ "자쥐",
+ "잠쥐",
+ "보'지",
+ "섹'스",
+ "차앙년",
+ "창ㄴ ㅕ",
+ "촹년",
+ "촹뇬",
+ "ㅃr굴",
+ "고츄",
+ "죠까",
+ "sex",
+ "fuck",
+ "fuk",
+ "porno",
+ "dildo",
+ "pussy",
+ "shit",
+ "bitch",
+ "anal",
+ "fetish",
+ "gay",
+ "lesbien",
+ "bastard",
+ "cunt",
+ "damn",
+ "asshole",
+ "귀두"
+ ]
+}
diff --git a/ByeBoo-iOS/ByeBoo-iOS/Data/Model/ForbiddenWordList.swift b/ByeBoo-iOS/ByeBoo-iOS/Data/Model/ForbiddenWordList.swift
new file mode 100644
index 00000000..25aacb78
--- /dev/null
+++ b/ByeBoo-iOS/ByeBoo-iOS/Data/Model/ForbiddenWordList.swift
@@ -0,0 +1,19 @@
+//
+// ForbiddenWordList.swift
+// ByeBoo-iOS
+//
+// Created by APPLE on 2/27/26.
+//
+
+import Foundation
+
+struct ForbiddenWordList: Decodable {
+ let words: Set
+}
+
+extension ForbiddenWordList {
+
+ func toEntity() -> ForbiddenWordEntity {
+ .init(words: words)
+ }
+}
diff --git a/ByeBoo-iOS/ByeBoo-iOS/Data/Repository/ForbiddenWordRepository.swift b/ByeBoo-iOS/ByeBoo-iOS/Data/Repository/ForbiddenWordRepository.swift
new file mode 100644
index 00000000..d2b01955
--- /dev/null
+++ b/ByeBoo-iOS/ByeBoo-iOS/Data/Repository/ForbiddenWordRepository.swift
@@ -0,0 +1,51 @@
+//
+// ForbiddenWordRepository.swift
+// ByeBoo-iOS
+//
+// Created by APPLE on 2/27/26.
+//
+
+import Foundation
+
+final class DefaultForbiddenWordRepository: ForbiddenWordInterface {
+
+ private let resource = "ForbiddenWords"
+ private let fileExtension = "json"
+ private var cachedForbiddenWords: ForbiddenWordEntity?
+
+ func getForbiddenWords(_ word: String) -> ForbiddenWordEntity? {
+ if let cached = cachedForbiddenWords {
+ return cached
+ }
+
+ guard let url = fetchURL(),
+ let forbiddenWordList = decodeForbiddenWords(url: url) else {
+ return nil
+ }
+
+ let forbiddenWordEntity = forbiddenWordList.toEntity()
+ cachedForbiddenWords = forbiddenWordEntity
+ return forbiddenWordEntity
+ }
+
+ private func fetchURL() -> URL? {
+ guard let url = Bundle.main.url(forResource: resource, withExtension: fileExtension) else {
+ ByeBooLogger.error(ByeBooError.fileNotFound)
+ return nil
+ }
+
+ return url
+ }
+
+ private func decodeForbiddenWords(url: URL) -> ForbiddenWordList? {
+ do {
+ let data = try Data(contentsOf: url)
+ let decoder = JSONDecoder()
+ let decodedData = try decoder.decode(ForbiddenWordList.self, from: data)
+ return decodedData
+ } catch {
+ ByeBooLogger.error(ByeBooError.decodingError)
+ return nil
+ }
+ }
+}
diff --git a/ByeBoo-iOS/ByeBoo-iOS/Domain/DomainDependencyAssembler.swift b/ByeBoo-iOS/ByeBoo-iOS/Domain/DomainDependencyAssembler.swift
index 058335a9..ba2900d8 100644
--- a/ByeBoo-iOS/ByeBoo-iOS/Domain/DomainDependencyAssembler.swift
+++ b/ByeBoo-iOS/ByeBoo-iOS/Domain/DomainDependencyAssembler.swift
@@ -19,7 +19,9 @@ struct DomainDependencyAssembler: DependencyAssembler {
guard let userRepository = DIContainer.shared.resolve(type: UsersInterface.self),
let questRepository = DIContainer.shared.resolve(type: QuestsInterface.self),
- let authRepository = DIContainer.shared.resolve(type: AuthInterface.self) else {
+ let authRepository = DIContainer.shared.resolve(type: AuthInterface.self),
+ let forbiddenWordRepository = DIContainer.shared.resolve(type: ForbiddenWordInterface.self)
+ else {
ByeBooLogger.error(ByeBooError.DIFailedError)
return
}
@@ -163,5 +165,9 @@ struct DomainDependencyAssembler: DependencyAssembler {
DIContainer.shared.register(type: CheckAlarmEnabledUseCase.self) { _ in
return DefaultCheckAlarmEnabledUseCase(repository: userRepository)
}
+
+ DIContainer.shared.register(type: IsForbiddenWordUseCase.self) { _ in
+ return DefaultIsForbiddenWordUseCase(repository: forbiddenWordRepository)
+ }
}
}
diff --git a/ByeBoo-iOS/ByeBoo-iOS/Domain/Entity/ForbiddenWordEntity.swift b/ByeBoo-iOS/ByeBoo-iOS/Domain/Entity/ForbiddenWordEntity.swift
new file mode 100644
index 00000000..efcdd442
--- /dev/null
+++ b/ByeBoo-iOS/ByeBoo-iOS/Domain/Entity/ForbiddenWordEntity.swift
@@ -0,0 +1,16 @@
+//
+// ForbiddenWordEntity.swift
+// ByeBoo-iOS
+//
+// Created by APPLE on 2/27/26.
+//
+
+struct ForbiddenWordEntity {
+ let words: Set
+}
+
+extension ForbiddenWordEntity {
+ static func stub() -> Self {
+ .init(words: ["word1", "word2", "word3"])
+ }
+}
diff --git a/ByeBoo-iOS/ByeBoo-iOS/Domain/Entity/NicknameRule.swift b/ByeBoo-iOS/ByeBoo-iOS/Domain/Entity/NicknameRule.swift
index e0b30722..dfcd4650 100644
--- a/ByeBoo-iOS/ByeBoo-iOS/Domain/Entity/NicknameRule.swift
+++ b/ByeBoo-iOS/ByeBoo-iOS/Domain/Entity/NicknameRule.swift
@@ -10,4 +10,5 @@ import Foundation
enum NicknameRule {
private static let regularExpression = "(?=.{2,5}$)(?!.*[ㄱ-ㅎㅏ-ㅣ])[가-힣a-zA-Z0-9]+"
static let predicate = NSPredicate(format: "SELF MATCHES %@", regularExpression)
+ static let bannedWords: Set = ["admin", "master", "test", "운영자", "관리자"]
}
diff --git a/ByeBoo-iOS/ByeBoo-iOS/Domain/Interface/ForbiddenWordInterface.swift b/ByeBoo-iOS/ByeBoo-iOS/Domain/Interface/ForbiddenWordInterface.swift
new file mode 100644
index 00000000..55d49722
--- /dev/null
+++ b/ByeBoo-iOS/ByeBoo-iOS/Domain/Interface/ForbiddenWordInterface.swift
@@ -0,0 +1,10 @@
+//
+// ForbiddenWordInterface.swift
+// ByeBoo-iOS
+//
+// Created by APPLE on 2/27/26.
+//
+
+protocol ForbiddenWordInterface {
+ func getForbiddenWords(_ word: String) -> ForbiddenWordEntity?
+}
diff --git a/ByeBoo-iOS/ByeBoo-iOS/Domain/UseCase/CheckValidNicknameUseCase.swift b/ByeBoo-iOS/ByeBoo-iOS/Domain/UseCase/CheckValidNicknameUseCase.swift
index 83e010a5..17a295bc 100644
--- a/ByeBoo-iOS/ByeBoo-iOS/Domain/UseCase/CheckValidNicknameUseCase.swift
+++ b/ByeBoo-iOS/ByeBoo-iOS/Domain/UseCase/CheckValidNicknameUseCase.swift
@@ -6,12 +6,17 @@
//
protocol CheckValidNicknameUseCase {
- func execute(nickname: String) -> Bool
+ func isValidRegulation(nickname: String) -> Bool
+ func isPermitteed(nickname: String) -> Bool
}
struct DefaultCheckValidNicknameUseCase: CheckValidNicknameUseCase {
- func execute(nickname: String) -> Bool {
+ func isValidRegulation(nickname: String) -> Bool {
return NicknameRule.predicate.evaluate(with: nickname)
}
+
+ func isPermitteed(nickname: String) -> Bool {
+ return !NicknameRule.bannedWords.contains(nickname)
+ }
}
diff --git a/ByeBoo-iOS/ByeBoo-iOS/Domain/UseCase/IsForbiddenWordUseCase.swift b/ByeBoo-iOS/ByeBoo-iOS/Domain/UseCase/IsForbiddenWordUseCase.swift
new file mode 100644
index 00000000..87466347
--- /dev/null
+++ b/ByeBoo-iOS/ByeBoo-iOS/Domain/UseCase/IsForbiddenWordUseCase.swift
@@ -0,0 +1,29 @@
+//
+// IsForbiddenWordUseCase.swift
+// ByeBoo-iOS
+//
+// Created by APPLE on 2/27/26.
+//
+
+import Foundation
+
+protocol IsForbiddenWordUseCase {
+ func execute(word: String) -> Bool
+}
+
+struct DefaultIsForbiddenWordUseCase: IsForbiddenWordUseCase {
+
+ private let repository: ForbiddenWordInterface
+
+ init(repository: ForbiddenWordInterface) {
+ self.repository = repository
+ }
+
+ func execute(word: String) -> Bool {
+ guard let forbiddenWordEntity = repository.getForbiddenWords(word) else {
+ return true
+ }
+
+ return forbiddenWordEntity.words.contains { word.contains($0) }
+ }
+}
diff --git a/ByeBoo-iOS/ByeBoo-iOS/Domain/UseCase/isValidQuestAnswerUseCase.swift b/ByeBoo-iOS/ByeBoo-iOS/Domain/UseCase/IsValidQuestAnswerUseCase.swift
similarity index 97%
rename from ByeBoo-iOS/ByeBoo-iOS/Domain/UseCase/isValidQuestAnswerUseCase.swift
rename to ByeBoo-iOS/ByeBoo-iOS/Domain/UseCase/IsValidQuestAnswerUseCase.swift
index 9f31c5bd..cbd57801 100644
--- a/ByeBoo-iOS/ByeBoo-iOS/Domain/UseCase/isValidQuestAnswerUseCase.swift
+++ b/ByeBoo-iOS/ByeBoo-iOS/Domain/UseCase/IsValidQuestAnswerUseCase.swift
@@ -1,5 +1,5 @@
//
-// isValidQuestAnswerUseCase.swift
+// IsValidQuestAnswerUseCase.swift
// ByeBoo-iOS
//
// Created by 이나연 on 12/4/25.
diff --git a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Information/ViewController/InformationViewController.swift b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Information/ViewController/InformationViewController.swift
index 1e1621a4..b63dd098 100644
--- a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Information/ViewController/InformationViewController.swift
+++ b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Information/ViewController/InformationViewController.swift
@@ -91,7 +91,6 @@ extension InformationViewController {
viewModel.action(.nicknameButtonDidTap(nickname))
Mixpanel.mainInstance().track(event: CommonEvents.Name.nicknameComplete)
}
- move(view: selectQuestView, progress: .second)
}
private func saveQuest() {
@@ -140,6 +139,19 @@ extension InformationViewController: ToastPresentable, ToastErrorHandler {
self?.informationBaseView.updateButtonWhenBack(condition: result)
}
.store(in: &cancellables)
+
+ viewModel.output.isForbiddenWordPublisher
+ .sink { [weak self] result in
+ guard let self else { return }
+
+ switch result {
+ case .success:
+ move(view: selectQuestView, progress: .second)
+ case .failure(let error):
+ handleError(error)
+ }
+ }
+ .store(in: &cancellables)
}
private func bindName() {
diff --git a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Information/ViewModel/InformationViewModel.swift b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Information/ViewModel/InformationViewModel.swift
index b684c69c..e45cb786 100644
--- a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Information/ViewModel/InformationViewModel.swift
+++ b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Information/ViewModel/InformationViewModel.swift
@@ -11,6 +11,7 @@ final class InformationViewModel {
private var cancellables = Set()
private let nicknameValidationSubject = CurrentValueSubject(false)
+ private let isForbiddenWordSubject = PassthroughSubject, Never>()
private let userInformationSubject = PassthroughSubject, Never>()
private let userNameSubject = PassthroughSubject, Never>()
private(set) var output: Output
@@ -21,20 +22,24 @@ final class InformationViewModel {
private var user: UserEntity = UserEntity(id: 1, name: "")
private let checkValidNicknameUseCase: CheckValidNicknameUseCase
+ private let isForbiddenWordUseCase: IsForbiddenWordUseCase
private let sendUserUseCase: SendUserUseCase
private let getUserNameUseCase: GetUserNameUseCase
init(
checkValidNicknameUseCase: CheckValidNicknameUseCase,
+ isForbiddenWordUseCase: IsForbiddenWordUseCase,
sendUserUseCase: SendUserUseCase,
getUserNameUseCase: GetUserNameUseCase
) {
self.checkValidNicknameUseCase = checkValidNicknameUseCase
+ self.isForbiddenWordUseCase = isForbiddenWordUseCase
self.sendUserUseCase = sendUserUseCase
self.getUserNameUseCase = getUserNameUseCase
self.output = Output(
nicknameValidationPublisher: nicknameValidationSubject.eraseToAnyPublisher(),
+ isForbiddenWordPublisher: isForbiddenWordSubject.eraseToAnyPublisher(),
userInformationPublisher: userInformationSubject.eraseToAnyPublisher(),
userNamePublisher: userNameSubject.eraseToAnyPublisher()
)
@@ -80,6 +85,7 @@ extension InformationViewModel: ViewModelType {
struct Output {
let nicknameValidationPublisher: AnyPublisher
+ let isForbiddenWordPublisher: AnyPublisher, Never>
let userInformationPublisher: AnyPublisher, Never>
let userNamePublisher: AnyPublisher, Never>
}
@@ -87,12 +93,22 @@ extension InformationViewModel: ViewModelType {
func action(_ trigger: Input) {
switch trigger {
case .editingNickname(let nickname):
- let isValidNickname = checkValidNicknameUseCase.execute(nickname: nickname)
+ let isValidNickname = checkValidNicknameUseCase.isValidRegulation(nickname: nickname)
nicknameValidationSubject.send(isValidNickname)
+
case .nicknameButtonDidTap(let nickname):
+ guard checkValidNicknameUseCase.isPermitteed(nickname: nickname),
+ !isForbiddenWordUseCase.execute(word: nickname)
+ else {
+ isForbiddenWordSubject.send(.failure(.nicknameViolation))
+ return
+ }
currentNickname = nickname
+ isForbiddenWordSubject.send(.success(()))
+
case .feelingButtonDidTap(let feeling):
currentFeeling = feeling
+
case .questButtonDidTap(let questStyle):
currentQuestStyle = questStyle
createUserInformation(
diff --git a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/MyPage/ViewModel/ModifyNicknameViewModel.swift b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/MyPage/ViewModel/ModifyNicknameViewModel.swift
index b9cf43d0..5225b0c3 100644
--- a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/MyPage/ViewModel/ModifyNicknameViewModel.swift
+++ b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/MyPage/ViewModel/ModifyNicknameViewModel.swift
@@ -16,13 +16,16 @@ final class ModifyNicknameViewModel: ViewModelType {
private(set) var output: Output
private let checkValidNicknameUseCase: CheckValidNicknameUseCase
+ private let isForbiddenWordUseCase: IsForbiddenWordUseCase
private let modifyNicknameUseCase: ModifyNicknameUseCase
init(
checkValidNicknameUseCase: CheckValidNicknameUseCase,
+ isForbiddenWordUseCase: IsForbiddenWordUseCase,
modifyNicknameUseCase: ModifyNicknameUseCase
) {
self.checkValidNicknameUseCase = checkValidNicknameUseCase
+ self.isForbiddenWordUseCase = isForbiddenWordUseCase
self.modifyNicknameUseCase = modifyNicknameUseCase
output = Output(
@@ -34,7 +37,7 @@ final class ModifyNicknameViewModel: ViewModelType {
func action(_ trigger: Input) {
switch trigger {
case .editingNickname(let name):
- let isValidNickname = checkValidNicknameUseCase.execute(nickname: name)
+ let isValidNickname = checkValidNicknameUseCase.isValidRegulation(nickname: name)
checkValidNameSubject.send(isValidNickname)
case .modifyNameDidTap(let name):
modifyUserName(name: name)
@@ -58,6 +61,12 @@ extension ModifyNicknameViewModel {
extension ModifyNicknameViewModel {
private func modifyUserName(name: String) {
+ if isForbiddenWordUseCase.execute(word: name) ||
+ !checkValidNicknameUseCase.isPermitteed(nickname: name) {
+ userNameSubject.send(.failure(.nicknameViolation))
+ return
+ }
+
Task {
do {
let name = try await modifyNicknameUseCase.execute(name: name)
diff --git a/ByeBoo-iOS/ByeBoo-iOS/Presentation/PresentationDependencyAssembler.swift b/ByeBoo-iOS/ByeBoo-iOS/Presentation/PresentationDependencyAssembler.swift
index f1190d13..8b0522c3 100644
--- a/ByeBoo-iOS/ByeBoo-iOS/Presentation/PresentationDependencyAssembler.swift
+++ b/ByeBoo-iOS/ByeBoo-iOS/Presentation/PresentationDependencyAssembler.swift
@@ -18,7 +18,9 @@ struct PresentationDependencyAssembler: DependencyAssembler {
preAssembler.assemble()
guard let getUserNameUseCase = DIContainer.shared.resolve(type: GetUserNameUseCase.self),
- let fetchUserJourneyUseCase = DIContainer.shared.resolve(type: FetchUserJourneyUseCase.self) else {
+ let fetchUserJourneyUseCase = DIContainer.shared.resolve(type: FetchUserJourneyUseCase.self),
+ let isForbiddenWordUseCase = DIContainer.shared.resolve(type: IsForbiddenWordUseCase.self)
+ else {
ByeBooLogger.error(ByeBooError.DIFailedError)
return
}
@@ -66,13 +68,15 @@ struct PresentationDependencyAssembler: DependencyAssembler {
DIContainer.shared.register(type: InformationViewModel.self) { container in
guard let sendUserUseCase = container.resolve(type: SendUserUseCase.self),
- let checkValidNicknameUseCase = container.resolve(type: CheckValidNicknameUseCase.self) else {
+ let checkValidNicknameUseCase = container.resolve(type: CheckValidNicknameUseCase.self)
+ else {
ByeBooLogger.error(ByeBooError.DIFailedError)
return
}
return InformationViewModel(
checkValidNicknameUseCase: checkValidNicknameUseCase,
+ isForbiddenWordUseCase: isForbiddenWordUseCase,
sendUserUseCase: sendUserUseCase,
getUserNameUseCase: getUserNameUseCase
)
@@ -208,6 +212,7 @@ struct PresentationDependencyAssembler: DependencyAssembler {
return ModifyNicknameViewModel(
checkValidNicknameUseCase: checkValidNicknameUseCase,
+ isForbiddenWordUseCase: isForbiddenWordUseCase,
modifyNicknameUseCase: modifyNicknameUseCase
)
}
diff --git a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Protocol/ToastErrorHandler.swift b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Protocol/ToastErrorHandler.swift
index 89352e2b..e1fba882 100644
--- a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Protocol/ToastErrorHandler.swift
+++ b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Protocol/ToastErrorHandler.swift
@@ -15,6 +15,8 @@ extension ToastErrorHandler where Self: BaseViewController & ToastPresentable {
switch error {
case .networkConnect:
presentToastMessage(type: .connectServerError)
+ case .nicknameViolation:
+ presentToastMessage(type: .nicknameViolation)
default:
ByeBooLogger.error(error)
}
diff --git a/ByeBoo-iOS/ByeBooTests/Feature/ForbiddenWordTest.swift b/ByeBoo-iOS/ByeBooTests/Feature/ForbiddenWordTest.swift
new file mode 100644
index 00000000..7cd82703
--- /dev/null
+++ b/ByeBoo-iOS/ByeBooTests/Feature/ForbiddenWordTest.swift
@@ -0,0 +1,39 @@
+//
+// ForbiddenWordTest.swift
+// ByeBoo-iOS
+//
+// Created by APPLE on 2/28/26.
+//
+
+import Testing
+@testable import ByeBoo_iOS
+
+struct ForbiddenWordTest {
+
+ private let repository = DefaultForbiddenWordRepository()
+ private let isForbiddenWordUseCase: DefaultIsForbiddenWordUseCase
+
+ init() {
+ self.isForbiddenWordUseCase = DefaultIsForbiddenWordUseCase(repository: repository)
+ }
+
+ @Test(
+ "🏁 단어에 금칙어가 포함되어있는 경우 ✅ true",
+ arguments: ["10알", "10알아"]
+ )
+ func containsForbiddenWord__true(word: String) {
+ let isForbiddenWord = isForbiddenWordUseCase.execute(word: word)
+
+ #expect(isForbiddenWord == true)
+ }
+
+ @Test(
+ "🏁 단어에 금칙어가 포함되어있지 않은 경우 ✅ false",
+ arguments: ["주리", "승준", "나연"]
+ )
+ func containsForbiddenWord__false(word: String) {
+ let isForbiddenWord = isForbiddenWordUseCase.execute(word: word)
+
+ #expect(isForbiddenWord == false)
+ }
+}
diff --git a/ByeBoo-iOS/ByeBooTests/Feature/Information/NicknameTests.swift b/ByeBoo-iOS/ByeBooTests/Feature/Information/NicknameTests.swift
index 891aba6b..9eb9432e 100644
--- a/ByeBoo-iOS/ByeBooTests/Feature/Information/NicknameTests.swift
+++ b/ByeBoo-iOS/ByeBooTests/Feature/Information/NicknameTests.swift
@@ -17,7 +17,7 @@ struct NicknameTests {
arguments: ["a", "abcdef"]
)
func isNicknameLessThan2OrGreaterThan5__false(nickname: String) async {
- let result = checkValidNicknameUseCase.execute(nickname: nickname)
+ let result = checkValidNicknameUseCase.isValidRegulation(nickname: nickname)
#expect(result == false)
}
@@ -27,21 +27,21 @@ struct NicknameTests {
arguments: ["고ㅜ", "ㄱ우"]
)
func isNicknamUsingKoreanConsonantsOrVowelsAlone__false(nickname: String) async {
- let result = checkValidNicknameUseCase.execute(nickname: nickname)
+ let result = checkValidNicknameUseCase.isValidRegulation(nickname: nickname)
#expect(result == false)
}
@Test("🏁 한글 자음과 모음이 혼합되어있지만 불완전한 글자일 때 ✅ false")
func isNicknamUsingIncompleteKorean__false() async {
- let result = checkValidNicknameUseCase.execute(nickname: "ㄱㅗ우")
+ let result = checkValidNicknameUseCase.isValidRegulation(nickname: "ㄱㅗ우")
#expect(result == false)
}
@Test("🏁 닉네임에 특수문자가 포함되어있을 때 ✅ false")
func isNicknameContainsSpecialCharacter__false() async {
- let result = checkValidNicknameUseCase.execute(nickname: "가나디@")
+ let result = checkValidNicknameUseCase.isValidRegulation(nickname: "가나디@")
#expect(result == false)
}
@@ -51,7 +51,7 @@ struct NicknameTests {
arguments: [" 가나디", "가 나디", "가나디 "]
)
func isNicknamContainsSpace__false(nickname: String) async {
- let result = checkValidNicknameUseCase.execute(nickname: nickname)
+ let result = checkValidNicknameUseCase.isValidRegulation(nickname: nickname)
#expect(result == false)
}
@@ -61,8 +61,18 @@ struct NicknameTests {
arguments: ["허승준", "123", "Atom", "허1a"]
)
func isValidNickname__true(nickname: String) async {
- let result = checkValidNicknameUseCase.execute(nickname: nickname)
+ let result = checkValidNicknameUseCase.isValidRegulation(nickname: nickname)
#expect(result == true)
}
+
+ @Test(
+ "🏁 설정 불가한 닉네임을 입력한 경우 ✅ true",
+ arguments: ["admin", "master", "test", "운영자", "관리자"]
+ )
+ func isPermittedNickname__false(nickname: String) async {
+ let result = checkValidNicknameUseCase.isPermitteed(nickname: nickname)
+
+ #expect(result == false)
+ }
}