diff --git a/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj b/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj index a8ffdaee..4aeb993e 100644 --- a/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj +++ b/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj @@ -31,6 +31,8 @@ CE0D9FD329648DA300CEB5CD /* CustomAlertVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE0D9FD229648DA300CEB5CD /* CustomAlertVC.swift */; }; CE10065529680F7000FD31FB /* DepartureSearchingResponseDto.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE10065429680F7000FD31FB /* DepartureSearchingResponseDto.swift */; }; CE1006572968230800FD31FB /* DepartureLocationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE1006562968230800FD31FB /* DepartureLocationModel.swift */; }; + CE102C4829DB1D6B00E23E69 /* GetNewTokenResponseDto.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE102C4729DB1D6B00E23E69 /* GetNewTokenResponseDto.swift */; }; + CE102C4A29DBAD3D00E23E69 /* AuthInterceptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE102C4929DBAD3D00E23E69 /* AuthInterceptor.swift */; }; CE146770296568DC00DCEA1B /* RunTrackingVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE14676F296568DC00DCEA1B /* RunTrackingVC.swift */; }; CE14677829658C7200DCEA1B /* Stopwatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE14677729658C7200DCEA1B /* Stopwatch.swift */; }; CE14677A2965A80700DCEA1B /* CustomBottomSheetVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE1467792965A80700DCEA1B /* CustomBottomSheetVC.swift */; }; @@ -130,6 +132,7 @@ CEC2A6902962B06C00160BF7 /* convertLocationObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC2A68F2962B06C00160BF7 /* convertLocationObject.swift */; }; CEC2A6922962BE2900160BF7 /* DepartureSearchVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC2A6912962BE2900160BF7 /* DepartureSearchVC.swift */; }; CECA695C296E61D6002AF05C /* PrivateCourseNotUploadedResponseDto.swift in Sources */ = {isa = PBXBuildFile; fileRef = CECA695B296E61D6002AF05C /* PrivateCourseNotUploadedResponseDto.swift */; }; + CEE59FDA29DD6F7D00C791F1 /* Providers.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEE59FD929DD6F7D00C791F1 /* Providers.swift */; }; CEEC6B3A2961C4F300D00E1E /* CourseDrawingHomeVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEEC6B392961C4F300D00E1E /* CourseDrawingHomeVC.swift */; }; CEEC6B3C2961C51A00D00E1E /* CourseStorageVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEEC6B3B2961C51A00D00E1E /* CourseStorageVC.swift */; }; CEEC6B3E2961C53700D00E1E /* CourseDiscoveryVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEEC6B3D2961C53700D00E1E /* CourseDiscoveryVC.swift */; }; @@ -180,6 +183,8 @@ CE10065229680D4400FD31FB /* .gitkeep */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitkeep; sourceTree = ""; }; CE10065429680F7000FD31FB /* DepartureSearchingResponseDto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DepartureSearchingResponseDto.swift; sourceTree = ""; }; CE1006562968230800FD31FB /* DepartureLocationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DepartureLocationModel.swift; sourceTree = ""; }; + CE102C4729DB1D6B00E23E69 /* GetNewTokenResponseDto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetNewTokenResponseDto.swift; sourceTree = ""; }; + CE102C4929DBAD3D00E23E69 /* AuthInterceptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthInterceptor.swift; sourceTree = ""; }; CE14676F296568DC00DCEA1B /* RunTrackingVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunTrackingVC.swift; sourceTree = ""; }; CE14677729658C7200DCEA1B /* Stopwatch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Stopwatch.swift; sourceTree = ""; }; CE1467792965A80700DCEA1B /* CustomBottomSheetVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomBottomSheetVC.swift; sourceTree = ""; }; @@ -283,6 +288,7 @@ CEC2A68F2962B06C00160BF7 /* convertLocationObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = convertLocationObject.swift; sourceTree = ""; }; CEC2A6912962BE2900160BF7 /* DepartureSearchVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DepartureSearchVC.swift; sourceTree = ""; }; CECA695B296E61D6002AF05C /* PrivateCourseNotUploadedResponseDto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivateCourseNotUploadedResponseDto.swift; sourceTree = ""; }; + CEE59FD929DD6F7D00C791F1 /* Providers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Providers.swift; sourceTree = ""; }; CEEC6B392961C4F300D00E1E /* CourseDrawingHomeVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseDrawingHomeVC.swift; sourceTree = ""; }; CEEC6B3B2961C51A00D00E1E /* CourseStorageVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseStorageVC.swift; sourceTree = ""; }; CEEC6B3D2961C53700D00E1E /* CourseDiscoveryVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseDiscoveryVC.swift; sourceTree = ""; }; @@ -373,6 +379,7 @@ isa = PBXGroup; children = ( A3D1A77D29CF09B600DD54EC /* SignInResponseDto.swift */, + CE102C4729DB1D6B00E23E69 /* GetNewTokenResponseDto.swift */, ); path = ResponseDto; sourceTree = ""; @@ -891,6 +898,8 @@ isa = PBXGroup; children = ( CE6655BE295D82E200C64E12 /* .gitkeep */, + CE102C4929DBAD3D00E23E69 /* AuthInterceptor.swift */, + CEE59FD929DD6F7D00C791F1 /* Providers.swift */, ); path = Service; sourceTree = ""; @@ -1313,6 +1322,7 @@ CE17F0382961BF8B00E1DED0 /* FontLiterals.swift in Sources */, CE6655E8295D889600C64E12 /* UISwitch+.swift in Sources */, CE0C23772966D64D00B45063 /* PageCVC.swift in Sources */, + CEE59FDA29DD6F7D00C791F1 /* Providers.swift in Sources */, CE5875A029601500005D967E /* Toast.swift in Sources */, CE40BB1E2968054F0030ABCA /* BaseResponse.swift in Sources */, CE14677C2965C1B100DCEA1B /* RunningRecordVC.swift in Sources */, @@ -1334,6 +1344,7 @@ CE6655FE295D912300C64E12 /* calculateTopInset.swift in Sources */, CEEC6B492961C5E200D00E1E /* SplashVC.swift in Sources */, CE6655D0295D85FF00C64E12 /* CancelBag.swift in Sources */, + CE102C4A29DBAD3D00E23E69 /* AuthInterceptor.swift in Sources */, A3BC2F432966A93100198261 /* CourseDetailVC.swift in Sources */, DAD5A3D8296C6D9600C8166B /* AdImageCollectionViewCell.swift in Sources */, CE18E890296C76C100FEB569 /* RNLocationModel.swift in Sources */, @@ -1391,6 +1402,7 @@ CE6655E6295D887F00C64E12 /* UIStackView+.swift in Sources */, A3BC2F34296303A600198261 /* GoalRewardInfoCVC.swift in Sources */, CEB8416E2962C45300BF8080 /* LocationSearchResultTVC.swift in Sources */, + CE102C4829DB1D6B00E23E69 /* GetNewTokenResponseDto.swift in Sources */, CE6655CA295D84DD00C64E12 /* UserDefaultKeyList.swift in Sources */, CE6655F2295D894D00C64E12 /* UIView+.swift in Sources */, CE9291252965C9FB0010959C /* CourseDetailInfoView.swift in Sources */, diff --git a/Runnect-iOS/Runnect-iOS/Global/Literal/ImageLiterals.swift b/Runnect-iOS/Runnect-iOS/Global/Literal/ImageLiterals.swift index b3bf5bc6..7e9eba31 100644 --- a/Runnect-iOS/Runnect-iOS/Global/Literal/ImageLiterals.swift +++ b/Runnect-iOS/Runnect-iOS/Global/Literal/ImageLiterals.swift @@ -67,6 +67,8 @@ enum ImageLiterals { static var imgSpaceship: UIImage { .load(named: "img_spaceship") } static var imgAppIcon: UIImage { .load(named: "img_app_icon") } static var imgAd: UIImage { .load(named: "img_ad") } + static var imgAppleLogin: UIImage { .load(named: "img_apple_login")} + static var imgKakaoLogin: UIImage { .load(named: "img_kakao_login")} } extension UIImage { diff --git a/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_apple_login.imageset/Contents.json b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_apple_login.imageset/Contents.json new file mode 100644 index 00000000..e04c2538 --- /dev/null +++ b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_apple_login.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Group 9514.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Group 9514@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Group 9514@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_apple_login.imageset/Group 9514.png b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_apple_login.imageset/Group 9514.png new file mode 100644 index 00000000..ed5b1897 Binary files /dev/null and b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_apple_login.imageset/Group 9514.png differ diff --git a/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_apple_login.imageset/Group 9514@2x.png b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_apple_login.imageset/Group 9514@2x.png new file mode 100644 index 00000000..6d331555 Binary files /dev/null and b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_apple_login.imageset/Group 9514@2x.png differ diff --git a/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_apple_login.imageset/Group 9514@3x.png b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_apple_login.imageset/Group 9514@3x.png new file mode 100644 index 00000000..b815b5b4 Binary files /dev/null and b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_apple_login.imageset/Group 9514@3x.png differ diff --git a/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_kakao_login.imageset/Contents.json b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_kakao_login.imageset/Contents.json new file mode 100644 index 00000000..e1897055 --- /dev/null +++ b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_kakao_login.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Kakao Login.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Kakao Login@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Kakao Login@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_kakao_login.imageset/Kakao Login.png b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_kakao_login.imageset/Kakao Login.png new file mode 100644 index 00000000..6e749e3a Binary files /dev/null and b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_kakao_login.imageset/Kakao Login.png differ diff --git a/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_kakao_login.imageset/Kakao Login@2x.png b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_kakao_login.imageset/Kakao Login@2x.png new file mode 100644 index 00000000..a87ee34f Binary files /dev/null and b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_kakao_login.imageset/Kakao Login@2x.png differ diff --git a/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_kakao_login.imageset/Kakao Login@3x.png b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_kakao_login.imageset/Kakao Login@3x.png new file mode 100644 index 00000000..177cc50e Binary files /dev/null and b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/img_kakao_login.imageset/Kakao Login@3x.png differ diff --git a/Runnect-iOS/Runnect-iOS/Global/Utils/RNUtils/UserManager.swift b/Runnect-iOS/Runnect-iOS/Global/Utils/RNUtils/UserManager.swift index 93811ba6..861e77d3 100644 --- a/Runnect-iOS/Runnect-iOS/Global/Utils/RNUtils/UserManager.swift +++ b/Runnect-iOS/Runnect-iOS/Global/Utils/RNUtils/UserManager.swift @@ -17,9 +17,7 @@ enum RNError: Error { final class UserManager { static let shared = UserManager() - private var signInProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private var authProvider = Providers.authProvider @UserDefaultWrapper(key: "accessToken") public var accessToken @UserDefaultWrapper(key: "refreshToken") public var refreshToken @@ -35,7 +33,7 @@ final class UserManager { } func signIn(token: String, provider: String, completion: @escaping(Result) -> Void) { - signInProvider.request(.signIn(token: token, provider: provider)) { [weak self] response in + authProvider.request(.signIn(token: token, provider: provider)) { [weak self] response in guard let self = self else { return } switch response { case .success(let result): @@ -47,7 +45,7 @@ final class UserManager { self.accessToken = data.accessToken self.refreshToken = data.refreshToken self.isKakao = provider == "KAKAO" ? true : false - completion(.success(data.nickname ?? "")) + completion(.success(data.type)) // 로그인인지 회원가입인지 전달 } catch { print(error.localizedDescription) completion(.failure(.networkFail)) @@ -64,23 +62,19 @@ final class UserManager { } } - func autoSignIn(completion: @escaping(Result) -> Void) { - guard let accessToken = self.accessToken else { return } - guard let isKakao = self.isKakao else { return } - let provider = isKakao ? "KAKAO" : "APPLE" - signInProvider.request(.signIn(token: accessToken, provider: provider)) { [weak self] response in + func getNewToken(completion: @escaping(Result) -> Void) { + authProvider.request(.getNewToken) { [weak self] response in guard let self = self else { return } switch response { case .success(let result): let status = result.statusCode if 200..<300 ~= status { do { - let responseDto = try result.map(BaseResponse.self) + let responseDto = try result.map(BaseResponse.self) guard let data = responseDto.data else { return } self.accessToken = data.accessToken self.refreshToken = data.refreshToken - self.isKakao = provider == "KAKAO" ? true : false - completion(.success(data.nickname ?? "")) + completion(.success(true)) } catch { print(error.localizedDescription) completion(.failure(.networkFail)) diff --git a/Runnect-iOS/Runnect-iOS/Network/Dto/SignInDto/ResponseDto/GetNewTokenResponseDto.swift b/Runnect-iOS/Runnect-iOS/Network/Dto/SignInDto/ResponseDto/GetNewTokenResponseDto.swift new file mode 100644 index 00000000..b30dcaf3 --- /dev/null +++ b/Runnect-iOS/Runnect-iOS/Network/Dto/SignInDto/ResponseDto/GetNewTokenResponseDto.swift @@ -0,0 +1,15 @@ +// +// GetNewTokenResponseDto.swift +// Runnect-iOS +// +// Created by sejin on 2023/04/03. +// + +import Foundation + +// MARK: - GetNewTokenResponseDto + +struct GetNewTokenResponseDto: Codable { + let accessToken: String + let refreshToken: String +} diff --git a/Runnect-iOS/Runnect-iOS/Network/Router/AuthRouter.swift b/Runnect-iOS/Runnect-iOS/Network/Router/AuthRouter.swift index 06cfc2a8..17254689 100644 --- a/Runnect-iOS/Runnect-iOS/Network/Router/AuthRouter.swift +++ b/Runnect-iOS/Runnect-iOS/Network/Router/AuthRouter.swift @@ -11,6 +11,7 @@ import Moya enum AuthRouter { case signIn(token: String, provider: String) + case getNewToken } extension AuthRouter: TargetType { @@ -26,6 +27,8 @@ extension AuthRouter: TargetType { switch self { case .signIn: return "/auth" + case .getNewToken: + return "/auth/getNewToken" } } @@ -33,6 +36,8 @@ extension AuthRouter: TargetType { switch self { case .signIn: return .post + case .getNewToken: + return .get } } @@ -40,13 +45,19 @@ extension AuthRouter: TargetType { switch self { case .signIn(let token, let provider): return .requestParameters(parameters: ["token": token, "provider": provider], encoding: JSONEncoding.default) + case .getNewToken: + return .requestPlain } } var headers: [String: String]? { switch self { - case .signIn: + case .signIn, .getNewToken: return Config.defaultHeader } } + + var validationType: ValidationType { + return .successCodes + } } diff --git a/Runnect-iOS/Runnect-iOS/Network/Router/CourseRouter.swift b/Runnect-iOS/Runnect-iOS/Network/Router/CourseRouter.swift index dd36f92a..ca17dfe5 100644 --- a/Runnect-iOS/Runnect-iOS/Network/Router/CourseRouter.swift +++ b/Runnect-iOS/Runnect-iOS/Network/Router/CourseRouter.swift @@ -89,11 +89,13 @@ extension CourseRouter: TargetType { var headers: [String: String]? { switch self { case .uploadCourseDrawing: - return ["Content-Type": "multipart/form-data", - "accessToken": Config.accessToken, - "refreshToken": Config.refreshToken] + return ["Content-Type": "multipart/form-data"] default: - return Config.headerWithAccessToken + return Config.defaultHeader } } + + var validationType: ValidationType { + return .successCodes + } } diff --git a/Runnect-iOS/Runnect-iOS/Network/Router/PublicCourseRouter.swift b/Runnect-iOS/Runnect-iOS/Network/Router/PublicCourseRouter.swift index 57b20f0b..57143719 100644 --- a/Runnect-iOS/Runnect-iOS/Network/Router/PublicCourseRouter.swift +++ b/Runnect-iOS/Runnect-iOS/Network/Router/PublicCourseRouter.swift @@ -7,6 +7,7 @@ import Foundation import Moya + enum PublicCourseRouter { case getCourseData case getCourseSearchData(keyword: String) @@ -16,12 +17,14 @@ enum PublicCourseRouter { } extension PublicCourseRouter: TargetType { + var baseURL: URL { guard let url = URL(string: Config.baseURL) else {fatalError("baseURL could not be configured") } return url } + var path: String { switch self { case .getCourseData, .courseUploadingData: @@ -34,6 +37,7 @@ extension PublicCourseRouter: TargetType { return "/public-course/user" } } + var method: Moya.Method { switch self { case .getCourseData, .getCourseSearchData, .getUploadedCourseDetail, .getUploadedCourseInfo: @@ -41,8 +45,8 @@ extension PublicCourseRouter: TargetType { case .courseUploadingData: return .post } - } + var task: Moya.Task { switch self { case .getCourseSearchData(let keyword): @@ -56,10 +60,15 @@ extension PublicCourseRouter: TargetType { return .requestPlain } } + var headers: [String: String]? { switch self { default: - return Config.headerWithAccessToken + return Config.defaultHeader } } + + var validationType: ValidationType { + return .successCodes + } } diff --git a/Runnect-iOS/Runnect-iOS/Network/Router/RecordRouter.swift b/Runnect-iOS/Runnect-iOS/Network/Router/RecordRouter.swift index 3f896268..c635164c 100644 --- a/Runnect-iOS/Runnect-iOS/Network/Router/RecordRouter.swift +++ b/Runnect-iOS/Runnect-iOS/Network/Router/RecordRouter.swift @@ -57,7 +57,11 @@ extension RecordRouter: TargetType { var headers: [String: String]? { switch self { case .recordRunning, .getActivityRecordInfo: - return Config.headerWithAccessToken + return Config.defaultHeader } } + + var validationType: ValidationType { + return .successCodes + } } diff --git a/Runnect-iOS/Runnect-iOS/Network/Router/ScrapRouter.swift b/Runnect-iOS/Runnect-iOS/Network/Router/ScrapRouter.swift index fc23a636..8f0ca82d 100644 --- a/Runnect-iOS/Runnect-iOS/Network/Router/ScrapRouter.swift +++ b/Runnect-iOS/Runnect-iOS/Network/Router/ScrapRouter.swift @@ -53,7 +53,11 @@ extension ScrapRouter: TargetType { var headers: [String: String]? { switch self { case .createAndDeleteScrap, .getScrapCourse: - return Config.headerWithAccessToken + return Config.defaultHeader } } + + var validationType: ValidationType { + return .successCodes + } } diff --git a/Runnect-iOS/Runnect-iOS/Network/Router/StampRouter.swift b/Runnect-iOS/Runnect-iOS/Network/Router/StampRouter.swift index 36b09646..cb25ae3f 100644 --- a/Runnect-iOS/Runnect-iOS/Network/Router/StampRouter.swift +++ b/Runnect-iOS/Runnect-iOS/Network/Router/StampRouter.swift @@ -46,7 +46,11 @@ extension StampRouter: TargetType { var headers: [String: String]? { switch self { case .getGoalRewardInfo: - return Config.headerWithAccessToken + return Config.defaultHeader } - } + } + + var validationType: ValidationType { + return .successCodes + } } diff --git a/Runnect-iOS/Runnect-iOS/Network/Router/UserRouter.swift b/Runnect-iOS/Runnect-iOS/Network/Router/UserRouter.swift index 9da8a5be..b3bcce38 100644 --- a/Runnect-iOS/Runnect-iOS/Network/Router/UserRouter.swift +++ b/Runnect-iOS/Runnect-iOS/Network/Router/UserRouter.swift @@ -49,6 +49,10 @@ extension UserRouter: TargetType { } var headers: [String: String]? { - return Config.headerWithAccessToken + return Config.defaultHeader + } + + var validationType: ValidationType { + return .successCodes } } diff --git a/Runnect-iOS/Runnect-iOS/Network/Service/AuthInterceptor.swift b/Runnect-iOS/Runnect-iOS/Network/Service/AuthInterceptor.swift new file mode 100644 index 00000000..32017703 --- /dev/null +++ b/Runnect-iOS/Runnect-iOS/Network/Service/AuthInterceptor.swift @@ -0,0 +1,55 @@ +// +// AuthInterceptor.swift +// Runnect-iOS +// +// Created by sejin on 2023/04/04. +// + +import Foundation + +import Alamofire +import Moya + +///// 토큰 만료 시 자동으로 refresh를 위한 서버 통신 +final class AuthInterceptor: RequestInterceptor { + + static let shared = AuthInterceptor() + + private init() {} + + func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result) -> Void) { + guard urlRequest.url?.absoluteString.hasPrefix(Config.baseURL) == true, + let accessToken = UserManager.shared.accessToken, + let refreshToken = UserManager.shared.refreshToken + else { + completion(.success(urlRequest)) + return + } + + var urlRequest = urlRequest + urlRequest.setValue(accessToken, forHTTPHeaderField: "accessToken") + urlRequest.setValue(refreshToken, forHTTPHeaderField: "refreshToken") + print("adator 적용 \(urlRequest.headers)") + completion(.success(urlRequest)) + } + + func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) { + print("retry 진입") + guard let response = request.task?.response as? HTTPURLResponse, response.statusCode == 401 + else { + completion(.doNotRetryWithError(error)) + return + } + + UserManager.shared.getNewToken { result in + switch result { + case .success: + print("Retry-토큰 재발급 성공") + completion(.retry) + case .failure(let error): + // 세션 만료 -> 로그인 화면으로 전환 + completion(.doNotRetryWithError(error)) + } + } + } +} diff --git a/Runnect-iOS/Runnect-iOS/Network/Service/Providers.swift b/Runnect-iOS/Runnect-iOS/Network/Service/Providers.swift new file mode 100644 index 00000000..eeb361cc --- /dev/null +++ b/Runnect-iOS/Runnect-iOS/Network/Service/Providers.swift @@ -0,0 +1,32 @@ +// +// Providers.swift +// Runnect-iOS +// +// Created by sejin on 2023/04/05. +// + +import Foundation + +import Moya + +struct Providers { + static let departureSearchingProvider = MoyaProvider(withAuth: false) + static let authProvider = MoyaProvider(withAuth: true) + static let userProvider = MoyaProvider(withAuth: true) + static let courseProvider = MoyaProvider(withAuth: true) + static let publicCourseProvider = MoyaProvider(withAuth: true) + static let recordProvider = MoyaProvider(withAuth: true) + static let scrapProvider = MoyaProvider(withAuth: true) + static let stampProvider = MoyaProvider(withAuth: true) +} + +extension MoyaProvider { + convenience init(withAuth: Bool) { + if withAuth { + self.init(session: Session(interceptor: AuthInterceptor.shared), + plugins: [NetworkLoggerPlugin(verbose: true)]) + } else { + self.init() + } + } +} diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift index ce70efcb..f7b51f86 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift @@ -16,17 +16,11 @@ final class CourseDetailVC: UIViewController { // MARK: - Properties - private let scrapProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private let scrapProvider = Providers.scrapProvider - private let PublicCourseProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private let PublicCourseProvider = Providers.publicCourseProvider - private let courseProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private let courseProvider = Providers.courseProvider private var courseModel: Course? diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseDiscoveryVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseDiscoveryVC.swift index 4686de86..e5e1eda2 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseDiscoveryVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseDiscoveryVC.swift @@ -15,13 +15,9 @@ import Moya final class CourseDiscoveryVC: UIViewController { // MARK: - Properties - private let PublicCourseProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private let PublicCourseProvider = Providers.publicCourseProvider - private let scrapProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private let scrapProvider = Providers.scrapProvider private var courseList = [PublicCourse]() @@ -32,8 +28,8 @@ final class CourseDiscoveryVC: UIViewController { $0.setImage(ImageLiterals.icSearch, for: .normal) $0.tintColor = .g1 } - private let plusButton = UIButton(type: .system).then { - $0.setImage(ImageLiterals.icPlus, for: .normal) + private let uploadButton = CustomButton(title: "업로드하기").then { + $0.layer.cornerRadius = 20 } // MARK: - collectionview @@ -88,10 +84,8 @@ extension CourseDiscoveryVC { } private func setAddTarget() { - self.searchButton.addTarget(self, action: #selector(pushToSearchVC), for: .touchUpInside) - self.plusButton.addTarget(self, action: #selector(pushToDiscoveryVC), for: .touchUpInside) - + self.uploadButton.addTarget(self, action: #selector(pushToDiscoveryVC), for: .touchUpInside) } } @@ -128,17 +122,19 @@ extension CourseDiscoveryVC { private func layout() { view.backgroundColor = .w1 mapCollectionView.backgroundColor = .w1 - view.addSubviews(plusButton, mapCollectionView) - view.bringSubviewToFront(plusButton) + view.addSubviews(uploadButton, mapCollectionView) + view.bringSubviewToFront(uploadButton) mapCollectionView.snp.makeConstraints { $0.top.equalTo(self.navibar.snp.bottom) $0.leading.bottom.trailing.equalTo(view.safeAreaLayoutGuide) } - plusButton.snp.makeConstraints { make in + uploadButton.snp.makeConstraints { make in make.trailing.equalTo(self.view.safeAreaLayoutGuide).inset(16) make.bottom.equalTo(self.view.safeAreaLayoutGuide).inset(20) + make.height.equalTo(40) + make.width.equalTo(136) } } } diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseSearchVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseSearchVC.swift index 9146e531..5d3d7fa4 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseSearchVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseSearchVC.swift @@ -15,13 +15,9 @@ final class CourseSearchVC: UIViewController { // MARK: - Properties - private let PublicCourseRouter = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private let PublicCourseRouter = Providers.publicCourseProvider - private let scrapProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private let scrapProvider = Providers.scrapProvider private var courseList = [PublicCourse]() private var keyword: String? diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseUploadVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseUploadVC.swift index 4d5eaf5f..75a4b26e 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseUploadVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/CourseUploadVC.swift @@ -15,9 +15,8 @@ class CourseUploadVC: UIViewController { // MARK: - Properties // private var runningModel: RunningModel? - private let PublicCourseProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private let PublicCourseProvider = Providers.publicCourseProvider + private var courseModel: Course? private let courseTitleMaxLength = 20 diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/MyCourseSelectVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/MyCourseSelectVC.swift index 902e38ca..d397bd9e 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/MyCourseSelectVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/MyCourseSelectVC.swift @@ -14,9 +14,7 @@ class MyCourseSelectVC: UIViewController { // MARK: - Properties - private let courseProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private let courseProvider = Providers.courseProvider private var courseList = [Course]() diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/CourseDrawingVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/CourseDrawingVC.swift index 417e95ef..a6e2456c 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/CourseDrawingVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/CourseDrawingVC.swift @@ -14,9 +14,7 @@ final class CourseDrawingVC: UIViewController { // MARK: - Properties - private let courseProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private let courseProvider = Providers.courseProvider private var departureLocationModel: DepartureLocationModel? diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/DepartureSearchVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/DepartureSearchVC.swift index 1ff6f618..d135000a 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/DepartureSearchVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/DepartureSearchVC.swift @@ -13,9 +13,7 @@ final class DepartureSearchVC: UIViewController { // MARK: - Properties - private let departureSearchingProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private let departureSearchingProvider = Providers.departureSearchingProvider private var addressList = [KakaoAddressResult]() diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseStorage/VC/CourseStorageVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseStorage/VC/CourseStorageVC.swift index 85de924e..e72b546b 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseStorage/VC/CourseStorageVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseStorage/VC/CourseStorageVC.swift @@ -14,13 +14,9 @@ final class CourseStorageVC: UIViewController { // MARK: - Properties - private let courseProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private let courseProvider = Providers.courseProvider - private let scrapProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private let scrapProvider = Providers.scrapProvider private let cancelBag = CancelBag() diff --git a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/ActivityRecordInfoVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/ActivityRecordInfoVC.swift index 5dc24c5c..eab49a64 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/ActivityRecordInfoVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/ActivityRecordInfoVC.swift @@ -15,9 +15,7 @@ final class ActivityRecordInfoVC: UIViewController { // MARK: - Properties - private var recordProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private var recordProvider = Providers.recordProvider private var activityRecordList = [ActivityRecord]() diff --git a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/GoalRewardInfoVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/GoalRewardInfoVC.swift index caed83c7..ecd9e045 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/GoalRewardInfoVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/GoalRewardInfoVC.swift @@ -14,9 +14,7 @@ import Moya final class GoalRewardInfoVC: UIViewController { // MARK: - Properties - private var stampProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private var stampProvider = Providers.stampProvider var stampNameList: [GoalRewardInfoModel] = GoalRewardInfoModel.stampNameList diff --git a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/UploadedCourseInfoVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/UploadedCourseInfoVC.swift index 4dea323a..2a13d3d7 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/UploadedCourseInfoVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/UploadedCourseInfoVC.swift @@ -15,9 +15,7 @@ final class UploadedCourseInfoVC: UIViewController { // MARK: - Properties - private var uploadedCourseProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private var uploadedCourseProvider = Providers.publicCourseProvider private var uploadedCourseList = [PublicCourse]() diff --git a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/MyPageVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/MyPageVC.swift index d66fb775..e969717c 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/MyPageVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/MyPageVC.swift @@ -15,9 +15,7 @@ final class MyPageVC: UIViewController { // MARK: - Properties - private var userProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private var userProvider = Providers.userProvider let stampNameImageDictionary: [String: UIImage] = GoalRewardInfoModel.stampNameImageDictionary diff --git a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/NicknameEditorVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/NicknameEditorVC.swift index 5bd10471..d01a8c34 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/NicknameEditorVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/NicknameEditorVC.swift @@ -19,9 +19,7 @@ final class NicknameEditorVC: UIViewController { // MARK: - Properties - private var userProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private var userProvider = Providers.userProvider weak var delegate: NicknameEditorVCDelegate? diff --git a/Runnect-iOS/Runnect-iOS/Presentation/Running/VC/RunningRecordVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/Running/VC/RunningRecordVC.swift index c0ee546f..108df439 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/Running/VC/RunningRecordVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/Running/VC/RunningRecordVC.swift @@ -15,9 +15,7 @@ final class RunningRecordVC: UIViewController { private var runningModel: RunningModel? - private let recordProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private let recordProvider = Providers.recordProvider private let courseTitleMaxLength = 20 diff --git a/Runnect-iOS/Runnect-iOS/Presentation/Running/VC/RunningWaitingVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/Running/VC/RunningWaitingVC.swift index 7bfa5151..c5f95be7 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/Running/VC/RunningWaitingVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/Running/VC/RunningWaitingVC.swift @@ -18,13 +18,9 @@ final class RunningWaitingVC: UIViewController { private var publicCourseId: Int? private var courseModel: Course? - private let courseProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private let courseProvider = Providers.courseProvider - private let recordProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private let recordProvider = Providers.recordProvider // MARK: - UI Components diff --git a/Runnect-iOS/Runnect-iOS/Presentation/SignIn/VC/NickNameSetUpVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/SignIn/VC/NickNameSetUpVC.swift index 6006e1e7..78d08a3b 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/SignIn/VC/NickNameSetUpVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/SignIn/VC/NickNameSetUpVC.swift @@ -13,9 +13,7 @@ final class NickNameSetUpVC: UIViewController { // MARK: - Properties - private var userProvider = MoyaProvider( - plugins: [NetworkLoggerPlugin(verbose: true)] - ) + private var userProvider = Providers.userProvider private let nicknameMaxLength = 7 diff --git a/Runnect-iOS/Runnect-iOS/Presentation/SignIn/VC/SignInSocialLoginVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/SignIn/VC/SignInSocialLoginVC.swift index 2d73d8ef..5509f4c9 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/SignIn/VC/SignInSocialLoginVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/SignIn/VC/SignInSocialLoginVC.swift @@ -33,18 +33,15 @@ final class SignInSocialLoginVC: UIViewController { $0.contentMode = .scaleAspectFill } - private lazy var kakaoLoginButton = UIButton(type: .system).then { - $0.setTitle("카카오로 로그인", for: .normal) - $0.titleLabel?.font = .b3 - $0.setTitleColor(.black, for: .normal) - $0.setBackgroundColor(UIColor(hex: "FEE500"), for: .normal) - $0.layer.cornerRadius = 7 - $0.setImage(ImageLiterals.icKakao, for: .normal) - $0.imageEdgeInsets = .init(top: 0, left: 0, bottom: 0, right: self.screenWidth * 0.5) - $0.tintColor = .black + private let appleLoginButton = UIButton(type: .custom).then { + $0.layer.cornerRadius = 8 + $0.setImage(ImageLiterals.imgAppleLogin, for: .normal) } - private let appleLoginButton = ASAuthorizationAppleIDButton() + private let kakaoLoginButton = UIButton(type: .custom).then { + $0.layer.cornerRadius = 8 + $0.setImage(ImageLiterals.imgKakaoLogin, for: .normal) + } override func viewDidLoad() { super.viewDidLoad() @@ -85,9 +82,8 @@ extension SignInSocialLoginVC { guard let oauthToken = oauthToken else { return } UserManager.shared.signIn(token: oauthToken.accessToken, provider: "KAKAO") { [weak self] result in switch result { - case .success(let nickname): - print(nickname) - self?.pushToNickNameSetUpVC() + case .success(let type): + type == "Signup" ? self?.pushToNickNameSetUpVC() : self?.pushToTabBarController() case .failure(let error): print(error) self?.showNetworkFailureToast() @@ -105,9 +101,8 @@ extension SignInSocialLoginVC { guard let oauthToken = oauthToken else { return } UserManager.shared.signIn(token: oauthToken.accessToken, provider: "KAKAO") { [weak self] result in switch result { - case .success(let nickname): - print(nickname) - self?.pushToNickNameSetUpVC() + case .success(let type): + type == "Signup" ? self?.pushToNickNameSetUpVC() : self?.pushToTabBarController() case .failure(let error): print(error) self?.showNetworkFailureToast() @@ -131,6 +126,12 @@ extension SignInSocialLoginVC { let nicknameSetUpVC = NickNameSetUpVC() self.navigationController?.pushViewController(nicknameSetUpVC, animated: true) } + + private func pushToTabBarController() { + let tabBarController = TabBarController() + guard let window = self.view.window else { return } + ViewControllerUtils.setRootViewController(window: window, viewController: tabBarController, withAnimation: true) + } } // MARK: - UI & Layout @@ -192,9 +193,8 @@ extension SignInSocialLoginVC: ASAuthorizationControllerPresentationContextProvi UserManager.shared.signIn(token: tokeStr, provider: "APPLE") { [weak self] result in switch result { - case .success(let nickname): - print(nickname) - self?.pushToNickNameSetUpVC() + case .success(let type): + type == "Signup" ? self?.pushToNickNameSetUpVC() : self?.pushToTabBarController() case .failure(let error): print(error) self?.showNetworkFailureToast() diff --git a/Runnect-iOS/Runnect-iOS/Presentation/Splash/VC/SplashVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/Splash/VC/SplashVC.swift index b8dc1c89..621e5052 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/Splash/VC/SplashVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/Splash/VC/SplashVC.swift @@ -11,7 +11,7 @@ import SnapKit import Then final class SplashVC: UIViewController { - + // MARK: - UI Components private let backgroundImageView = UIImageView().then { @@ -41,8 +41,16 @@ extension SplashVC { private func checkDidSignIn() { DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { if UserManager.shared.hasAccessToken { - // accessToken 재발급 - self.pushToTabBarController() + UserManager.shared.getNewToken { [weak self] result in + switch result { + case .success: + print("SplashVC-토큰 재발급 성공") + self?.pushToTabBarController() + case .failure(let error): + print(error) + self?.pushToSignInView() + } + } } else { self.pushToSignInView() }