Skip to content

Commit

Permalink
Merge pull request #228 from OMZigak/refactor/#225-RemarkProvider
Browse files Browse the repository at this point in the history
[refactor] authtarget 통합
  • Loading branch information
hooni0918 authored Jul 18, 2024
2 parents 470d850 + f9eaa39 commit 74b7550
Show file tree
Hide file tree
Showing 5 changed files with 234 additions and 2 deletions.
16 changes: 16 additions & 0 deletions KkuMulKum.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@
785AE1BE2C2E878600677CA0 /* FirebaseStorageCombine-Community in Frameworks */ = {isa = PBXBuildFile; productRef = 785AE1BD2C2E878600677CA0 /* FirebaseStorageCombine-Community */; };
785AE1C02C2E878600677CA0 /* FirebaseVertexAI-Preview in Frameworks */ = {isa = PBXBuildFile; productRef = 785AE1BF2C2E878600677CA0 /* FirebaseVertexAI-Preview */; };
785AE1D12C3B07A600677CA0 /* PrivacyInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 785AE1D02C3B07A600677CA0 /* PrivacyInfo.plist */; };
789196362C492F8600FF8CDF /* AuthTargetType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 789196352C492F8600FF8CDF /* AuthTargetType.swift */; };
789196382C49697B00FF8CDF /* AuthError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 789196372C49697B00FF8CDF /* AuthError.swift */; };
789196342C486F6B00FF8CDF /* KeychainAccessible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 789196332C486F6B00FF8CDF /* KeychainAccessible.swift */; };
789873322C3D1A7B00435E96 /* LoginViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7898732F2C3D1A7B00435E96 /* LoginViewController.swift */; };
789873332C3D1A7B00435E96 /* LoginViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 789873302C3D1A7B00435E96 /* LoginViewModel.swift */; };
Expand Down Expand Up @@ -237,6 +239,8 @@
782B407E2C3E44B7008B0CA7 /* WelcomeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeViewModel.swift; sourceTree = "<group>"; };
782B40812C3E4925008B0CA7 /* NicknameViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NicknameViewModel.swift; sourceTree = "<group>"; };
785AE1D02C3B07A600677CA0 /* PrivacyInfo.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = PrivacyInfo.plist; sourceTree = "<group>"; };
789196352C492F8600FF8CDF /* AuthTargetType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthTargetType.swift; sourceTree = "<group>"; };
789196372C49697B00FF8CDF /* AuthError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthError.swift; sourceTree = "<group>"; };
789196332C486F6B00FF8CDF /* KeychainAccessible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainAccessible.swift; sourceTree = "<group>"; };
7898732F2C3D1A7B00435E96 /* LoginViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginViewController.swift; sourceTree = "<group>"; };
789873302C3D1A7B00435E96 /* LoginViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginViewModel.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -512,6 +516,15 @@
path = ViewModel;
sourceTree = "<group>";
};
789196392C49697F00FF8CDF /* Auth */ = {
isa = PBXGroup;
children = (
789196372C49697B00FF8CDF /* AuthError.swift */,
789196352C492F8600FF8CDF /* AuthTargetType.swift */,
);
path = Auth;
sourceTree = "<group>";
};
789873352C3D1B3000435E96 /* View */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -1120,6 +1133,7 @@
DDE7D2BE2C470A58005A921F /* TargetType */ = {
isa = PBXGroup;
children = (
789196392C49697F00FF8CDF /* Auth */,
DDE7D2BF2C470A58005A921F /* LoginTargetType.swift */,
DDE7D2C02C470A58005A921F /* ProfileTargetType.swift */,
DDE7D2C12C470A58005A921F /* NicknameTargetType.swift */,
Expand Down Expand Up @@ -1700,6 +1714,7 @@
DD8626622C4606A300E4F980 /* ReadyStatusViewModel.swift in Sources */,
DD3F9DC22C481ED5008E1FF7 /* MeetingService.swift in Sources */,
DE6D4D102C3F14D80005584B /* InvitationCodePopUpView.swift in Sources */,
789196382C49697B00FF8CDF /* AuthError.swift in Sources */,
A39F2B1B2C47C206008DA5F5 /* SetReadyCompletedViewController.swift in Sources */,
DDFA50812C4693BD000A62E2 /* ProfileSetupViewController.swift in Sources */,
DD30721A2C3C011600416D9F /* AddPromiseRequestModel.swift in Sources */,
Expand Down Expand Up @@ -1804,6 +1819,7 @@
DD3976862C41C2AD00E2A4C4 /* HomeView.swift in Sources */,
DD8626672C4606A300E4F980 /* SetReadyInfoView.swift in Sources */,
DD41BEFC2C41D54D0095A068 /* TardyPenaltyView.swift in Sources */,
789196362C492F8600FF8CDF /* AuthTargetType.swift in Sources */,
789873322C3D1A7B00435E96 /* LoginViewController.swift in Sources */,
78BD61342C45B4A7005752FD /* AuthService.swift in Sources */,
DE32D1D22C3BF703006848DF /* LoginUserResponseModel.swift in Sources */,
Expand Down
57 changes: 56 additions & 1 deletion KkuMulKum/Network/Service/AuthService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,26 @@
//
// Created by 이지훈 on 7/14/24.
//

import Foundation
import Moya

protocol AuthServiceType {
func saveAccessToken(_ token: String) -> Bool
func saveRefreshToken(_ token: String) -> Bool
func getAccessToken() -> String?
func getRefreshToken() -> String?
func clearTokens() -> Bool
func performRequest<T: ResponseModelType>(
_ target: AuthTargetType,
completion: @escaping (
Result<T, NetworkError>
) -> Void
)
}

class AuthService: AuthServiceType {
private var keychainService: KeychainService
private let provider = MoyaProvider<AuthTargetType>()

init(keychainService: KeychainService = DefaultKeychainService.shared) {
self.keychainService = keychainService
Expand Down Expand Up @@ -45,4 +52,52 @@ class AuthService: AuthServiceType {
keychainService.refreshToken = nil
return keychainService.accessToken == nil && keychainService.refreshToken == nil
}

func performRequest<T: ResponseModelType>(
_ target: AuthTargetType,
completion: @escaping (Result<T, NetworkError>) -> Void
) {
provider.request(target) { result in
switch result {
case .success(let response):
do {
let decodedResponse = try JSONDecoder().decode(
ResponseBodyDTO<T>.self,
from: response.data
)
if decodedResponse.success {
if let data = decodedResponse.data {
completion(.success(data))
} else {
completion(.failure(.decodingError))
}
} else {
let networkError = self.handleErrorResponse(decodedResponse.error)
completion(.failure(networkError))
}
} catch {
completion(.failure(.decodingError))
}
case .failure:
completion(.failure(.networkError))
}
}
}

private func handleErrorResponse(_ error: ErrorResponse?) -> NetworkError {
guard let error = error else {
return .unknownError("Unknown error occurred")
}

switch error.code {
case 40080:
return .invalidImageFormat
case 40081:
return .imageSizeExceeded
case 40420:
return .userNotFound
default:
return .unknownError(error.message)
}
}
}
34 changes: 34 additions & 0 deletions KkuMulKum/Network/TargetType/Auth/AuthError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// AuthError.swift
// KkuMulKum
//
// Created by 이지훈 on 7/19/24.
//

import Foundation

enum NetworkError: Error {
case invalidImageFormat
case imageSizeExceeded
case userNotFound
case decodingError
case networkError
case unknownError(String)

var message: String {
switch self {
case .invalidImageFormat:
return "이미지 확장자는 jpg, png, webp만 가능합니다."
case .imageSizeExceeded:
return "이미지 사이즈는 5MB를 넘을 수 없습니다."
case .userNotFound:
return "유저를 찾을 수 없습니다."
case .decodingError:
return "데이터 디코딩 중 오류가 발생했습니다."
case .networkError:
return "네트워크 오류가 발생했습니다."
case .unknownError(let message):
return message
}
}
}
104 changes: 104 additions & 0 deletions KkuMulKum/Network/TargetType/Auth/AuthTargetType.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
//
// AuthTargetType.swift
// KkuMulKum
//
// Created by 이지훈 on 7/18/24.
//

import Foundation

import Moya

enum AuthTargetType {
case appleLogin(identityToken: String, fcmToken: String)
case kakaoLogin(accessToken: String, fcmToken: String)
case refreshToken(refreshToken: String)
case updateProfileImage(image: Data, fileName: String, mimeType: String)
case updateName(name: String)
}

extension AuthTargetType: TargetType {
var baseURL: URL {
guard let privacyInfo = Bundle.main.privacyInfo,
let urlString = privacyInfo["BASE_URL"] as? String,
let url = URL(string: urlString) else {
fatalError("Invalid BASE_URL in PrivacyInfo.plist")
}
return url
}

var path: String {
switch self {
case .appleLogin, .kakaoLogin:
return "/api/v1/auth/signin"
case .refreshToken:
return "/api/v1/auth/reissue"
case .updateProfileImage:
return "/api/v1/users/me/image"
case .updateName:
return "/api/v1/users/me/name"
}
}

var method: Moya.Method {
switch self {
case .appleLogin, .kakaoLogin, .refreshToken:
return .post
case .updateProfileImage, .updateName:
return .patch
}
}

var task: Task {
switch self {
case let .appleLogin(_, fcmToken):
return .requestJSONEncodable(SocialLoginRequestModel(provider: "APPLE", fcmToken: fcmToken))
case let .kakaoLogin(_, fcmToken):
return .requestJSONEncodable(SocialLoginRequestModel(provider: "KAKAO", fcmToken: fcmToken))
case .refreshToken:
return .requestPlain
case let .updateProfileImage(imageData, fileName, mimeType):
let formData: [MultipartFormData] = [
MultipartFormData(
provider: .data(imageData),
name: "image",
fileName: fileName,
mimeType: mimeType
)
]
return .uploadMultipart(formData)
case let .updateName(name):
return .requestParameters(
parameters: ["name": name],
encoding: JSONEncoding.default
)
}
}

var headers: [String : String]? {
switch self {
case .appleLogin(let identityToken, _):
return ["Authorization": identityToken, "Content-Type": "application/json"]
case .kakaoLogin(let accessToken, _):
return ["Authorization": accessToken, "Content-Type": "application/json"]
case .refreshToken(let refreshToken):
return ["Authorization": refreshToken, "Content-Type": "application/json"]
case .updateProfileImage:
guard let token = DefaultKeychainService.shared.accessToken else {
return ["Content-Type": "multipart/form-data"]
}
return [
"Authorization": "Bearer \(token)",
"Content-Type": "multipart/form-data"
]
case .updateName:
guard let token = DefaultKeychainService.shared.accessToken else {
fatalError("No access token available")
}
return [
"Content-Type": "application/json",
"Authorization": "Bearer \(token)"
]
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Created by 이지훈 on 7/10/24.
//


import UIKit

import RxSwift
Expand All @@ -25,8 +26,30 @@ class ProfileSetupViewModel {
private let disposeBag = DisposeBag()
private let provider = MoyaProvider<ProfileTargetType>()

init(nickname: String) {
init(nickname: String, authService: AuthServiceType = AuthService()) {
self.nickname = nickname
self.authService = authService
}

func updateProfileImage(_ image: UIImage?) {
profileImage.value = image
isConfirmButtonEnabled.value = image != nil
}

func uploadProfileImage(completion: @escaping (Bool) -> Void) {
print("uploadProfileImage 함수 호출됨")
guard let image = profileImage.value,
let imageData = image.jpegData(compressionQuality: 0.8) else {
print("이미지 변환 실패")
serverResponse.value = "이미지 변환 중 오류가 발생했습니다."
completion(false)
return
}

print("이미지 데이터 크기: \(imageData.count) bytes")

let fileName = "profile_image.jpg"
let mimeType = "image/jpeg"

updateProfileImageTrigger
.withLatestFrom(profileImage)
Expand Down

0 comments on commit 74b7550

Please sign in to comment.