중복 이메일과 가계정은 어떻게 해결할까? - SMTP 활용

7과11사이·2023년 11월 27일
0
post-custom-banner

첫 기능 업데이트를 드디어 시도해보게 된다!
시간이 조금 걸렸지만 출시한 어플을 그대로 두는 것보다 지속적으로 관리를 해보고 싶다. 어플의 인기도가 낮거나 높아도 새로운 기능을 시도하고 직접 적용하는 도전을 해보고 싶은 마음이 큰 만큼, 이번에 구현하고 있는 SMTP 기능 관련해서 내용을 적어보고자 한다!

[1206]
들어가기 전, SMTP 기능을 적용하고자 한 이유를 간단히 정리해본다.

SMTP를 적용하고자 했던 의도
firebase 자체적으로 유효성 검사를 한다.
심지어 존재하는 이메일인지 인증 확인 이메일도 보낼 수 있다.
하지만 유효성 검사는 말그대로 이메일 형식인지만 확인할 뿐, 큰 효과가 없다. 인증 이메일은 어플에 들어가고자 하는 사용자들에게 안내문이 들어간 이메일을 발송한다. 별도로 인터렉션을 제공하지 않는 모습을 보면서 인증번호라도 심어서 사용자들이 이메일을 봐야하는 이유를 하나라도 만들고 싶었다.


[오류] - "이미 존재하는 이메일입니다."

[찐] 어플은 사용자의 회원가입을 받는다.
맛집 어플이면서 회원가입을 받지 않아야 오히려 더 많은 사용자를 받아들일 수 있을 것 같다는 의견도 있었다. 하지만 궁극적인 이유는 사용자가 직접 리뷰를 작성해야했다. 각 사용자가 어떤 리뷰를 작성했는지, 해당 리뷰에 대한 권한을 가지고 있어야 하는 상황이었기에 이메일을 활용해서 사용자의 회원가입을 받았다.

회원가입 코드는 아래와 같이 구성했다.

func registerNewUser(with credentials: AuthCredentials, completion: @escaping (Bool, Error?) -> Void) {
        Auth.auth().createUser(withEmail: credentials.email, password: credentials.password) { result, error in
            if let error = error {
                print("에러가 발생했습니다. \(error.localizedDescription)")
                completion(false, error)
                return
            }
            
            guard let uid = result?.user.uid else {
                completion(false, nil)
                return
            }
            
            let data: [String: Any] = ["email": credentials.email,
                                       "uid": uid,
                                       "userName": credentials.userName,
                                       "description": credentials.description,
                                       "pid": credentials.pid,
                                       "rid": credentials.rid,
                                       "profileImg": credentials.profileImage
            ]
            FireStoreManager.shared.db.collection("users").document(uid).setData(data) { firestoreError in
                if let error = firestoreError {
                    print("데이터 저장 에러가 발생했습니다.", error.localizedDescription)
                    completion(false, error)
                    return
                } else {
                    print("유저 생성 완료")
                    completion(true, nil)
                }
            }
        }
    }

하지만 Firebase 덕분에 쉽게 생성하는 코드를 만들 수 있었다.
개별 사용자를 생성할 때는 이슈가 없었는데, 의외의 곳에서 오류가 발생하기 시작했다. 처음 가입하는 이메일임에도 '이미 존재하는 이메일'에 오류가 걸리기 시작했다는 점이다!!

@objc func confirmButtonTapped() {
        print("회원가입 버튼이 눌렸습니다.")
        
        guard let nickname = registrationView.nicknameTfView.textfield.text, !nickname.isEmpty else {
            registrationView.nicknameTfView.showInvalidMessage()
            showAlert(type: .doubleCheck)
            return
        }
        
        guard let id = registrationView.emailTfView.textfield.text, !id.isEmpty else {
            registrationView.emailTfView.showInvalidMessage()
            showAlert(type: .doubleCheck)
            return
        }
        
        guard checkIdPattern(id) else {
            registrationView.emailTfView.showInvalidMessage()
            showAlert(type: .idError)
            return
        }
        
        guard let pw = registrationView.pwTfView.textfield.text, !pw.isEmpty else {
            registrationView.pwTfView.showInvalidMessage()
            showAlert(type: .doubleCheck)
            return
        }
        
        guard validPasswordPattern(pw) else {
            registrationView.pwTfView.showInvalidMessage()
            showAlert(type: .passwordBlank)
            return
        }
        
        guard registrationView.pwTfView.textfield.text == registrationView.doublecheckPwView.textfield.text else {
            showAlert(type: .equalPassword)
            return
        }
        
        guard noticeButtonToggle else {
            showAlert(type: .agreement)
            return
        }
        
        let credentials = AuthCredentials(email: id, password: pw, userName: nickname, description: "", profileImage: "profiles/default_profile.png", pid: [], rid: [])
        AuthManager.shared.registerNewUser(with: credentials) { success, error in
            
            if success {
                print("유저가 생성되었습니다.")
                DispatchQueue.main.async {
                    let mainVC = TabBarViewController()
                    let testVC = CardController()
                    testVC.modalPresentationStyle = .fullScreen
                    self.navigationController?.pushViewController(mainVC, animated: true)
                    self.present(testVC, animated: true)
                }
            } else {
                print("========== 어떤 오류인가요??",error?.localizedDescription)
                self.registrationView.emailTfView.showInvalidMessage()
                self.showAlert(type: .alreadyExists)
            }
        }

위 코드에서 마지막 단계에서 .alreadyExists alert가 뜨는 것으로 보인다.
이메일이 잘 데이터베이스 내로 들어가는 것을 보면 계정 생성은 잘되는 것으로 보인다. 하지만 완료되지 않은 회원가입하는 과정에서 이미 이메일이 있다고 오류 메시지가 뜨는 점은 어디서 잘못된 걸까?

예상 1. 타이밍 문제

registerNewUser 코드가 escaping인 점에서 아직 코드가 실행되고 있는 상황에서 이미 데이터가 DB에 올라간 상황

타 팀이나 이전 에러 상황들을 보면, 간혹 이미지 로드에 있어서 10개 중에 한 두개가 로드 안되는 현상이 발생했다. 이때 듣기로 이미지 데이터가 아직 받아지고 있는 상황에서 화면을 그리다보니, 부족한 이미지 데이터는 빈칸으로 보여지고 무사히 로드할 수 있던 이미지들은 잘 보였다. 다른 페이지를 방문했다가 다시 돌아오면 모든 이미지가 보여지는 현상처럼, 회원가입 메서드에서도 데이터가 이미 올라갔지만 아직 인가 절차를 거치는 중에서 발생하는 data collision이 아닐까 싶다.

post-custom-banner

0개의 댓글