Skip to content

Commit

Permalink
[GWL-268] 로그인 회원가입 연결 및 서버통신 (#297)
Browse files Browse the repository at this point in the history
* fix: CircularDepedency 현상 개선

* chore: 중복 Mutipart제거

* docs: 주석 제거

* chore: MultiPart-Trinet 재결합

* feat: Trinet No Interceptor Upload

* rename: userBit -> newUserInformation

* rename: userBit-newUserInformation

* fix: SignUp넘어갈 때, mainThread 에러 수정

* fix: ImageForm데이터 전달 안되는 현상 개선 및 회원가입 완료 시 받아온 토큰값 저장하는 로직 작성

* chore: Lint 정상화

* fix: SignUpGenderBirth에서 SignUpProfile까지 성별벌스 데이터 이동안되는 현상 개선

* Login, SignUp, TabBar Coordinator 연결

* add: Auth모듈 추가

* add: Auth모듈에 Token Entity

* add: Auth모듈에 AuthProvider추가

* chore: Token접근제어자 수정

* feat: 로그인 완료 시, 분기처리

* fix: Encoder로 인해 액세스토큰이 키체인에 쌍따옴표가 붙어서 저장되는 현상 개선

* chore: lint 복구

* fix: merge conflict

* fix: form-Data 이미지 그린아이에서 튕기는 현상 개선 이유 : fileName

* chore: 피드백 반영

---------

Co-authored-by: SeungHyun Hong <[email protected]>
  • Loading branch information
JongPyoAhn and WhiteHyun authored Dec 9, 2023
1 parent 9482966 commit a22a7b5
Show file tree
Hide file tree
Showing 40 changed files with 386 additions and 444 deletions.
14 changes: 7 additions & 7 deletions iOS/.swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ only_rules:
- unowned_variable_capture
- custom_rules
- trailing_comma
# - line_length
- line_length

excluded:
- Carthage
Expand All @@ -29,7 +29,7 @@ indentation: 2

trailing_comma:
mandatory_comma: true

line_length:
warning: 150

Expand All @@ -43,28 +43,28 @@ custom_rules:
name: "Writing log messages directly to standard out is disallowed"
regex: "(\\bprint|\\bdebugPrint|\\bdump|Swift\\.print|Swift\\.debugPrint|Swift\\.dump)\\s*\\("
match_kinds:
- identifier
- identifier
message: "Don't commit `print(…)`, `debugPrint(…)`, or `dump(…)` as they write to standard out in release. Either log to a dedicated logging system or silence this warning in debug-only scenarios explicitly using `// swiftlint:disable:next no_direct_standard_out_logs`"
severity: error
no_file_literal:
name: "#file is disallowed"
regex: "(\\b#file\\b)"
match_kinds:
- identifier
- identifier
message: "Instead of #file, use #fileID"
severity: error
no_filepath_literal:
name: "#filePath is disallowed"
regex: "(\\b#filePath\\b)"
match_kinds:
- identifier
- identifier
message: "Instead of #filePath, use #fileID."
severity: error
no_unchecked_sendable:
name: "`@unchecked Sendable` is discouraged."
regex: "@unchecked Sendable"
match_kinds:
- attribute.builtin
- typeidentifier
- attribute.builtin
- typeidentifier
message: "Instead of using `@unchecked Sendable`, consider a safe alternative like a standard `Sendable` conformance or using `@preconcurrency import`. If you really must use `@unchecked Sendable`, you can add a `// swiftlint:disable:next no_unchecked_sendable` annotation with an explanation for how we know the type is thread-safe, and why we have to use @unchecked Sendable instead of Sendable. More explanation and suggested safe alternatives are available at https://github.com/airbnb/swift#unchecked-sendable."
severity: error
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public extension TargetDependency {
static let keychain: TargetDependency = .project(target: "Keychain", path: .relativeToCore("Keychain"))
static let cacher: TargetDependency = .project(target: "Cacher", path: .relativeToCore("Cacher"))
static let userInformationManager: TargetDependency = .project(target: "UserInformationManager", path: .relativeToShared("UserInformationManager"))
static let auth: TargetDependency = .project(target: "Auth", path: .relativeToShared("Auth"))

static func feature(_ feature: Feature) -> TargetDependency {
return .project(
Expand Down
5 changes: 0 additions & 5 deletions iOS/Projects/App/WeTri/Sources/Application/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,6 @@ final class AppDelegate: UIResponder, UIApplicationDelegate {
didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil
)
-> Bool {
let accessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkNWNkN2I2Ni03ZWU2LTQ0NTMtYTczZS0wMjYxMjY4NjFlOTYiLCJ0eXBlIjoiYWNjZXNzIiwiaWF0IjoxNzAxOTYyNzM5LCJleHAiOjE3MDIwNDkxMzl9.Wu-xloayJ2T_sWaL6FCeml7j6UBQZlA7A0vUms3aK9Q".data(using: .utf8)!
Keychain.shared.save(key: Tokens.accessToken, data: accessToken)

let refreshToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkNWNkN2I2Ni03ZWU2LTQ0NTMtYTczZS0wMjYxMjY4NjFlOTYiLCJ0eXBlIjoicmVmcmVzaCIsImlhdCI6MTcwMTk2MjczOSwiZXhwIjoxNzAyMDQ5MTM5fQ.8_R9fb67KO7z5Yu3AGPvD1DIdySDur285JU8C7UEjpg".data(using: .utf8)!
Keychain.shared.save(key: Tokens.refreshToken, data: refreshToken)
return true
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
// Copyright © 2023 kr.codesquad.boostcamp8. All rights reserved.
//

import Auth
import Coordinator
import LoginFeature
import SignUpFeature
import SplashFeature
import UIKit

Expand Down Expand Up @@ -49,16 +51,27 @@ final class AppCoordinator: AppCoordinating {
}

func showLoginFlow() {
// TODO: LoginCoordinator 연결

let loginCoordinator = LoginCoordinator(
let coordinator = LoginFeatureCoordinator(
navigationController: navigationController,
isMockEnvironment: true,
isMockEnvironment: false,
isMockFirst: true
)
childCoordinators.append(coordinator)
coordinator.finishDelegate = self
coordinator.loginFeatureFinishDelegate = self
coordinator.start()
}

childCoordinators.append(loginCoordinator)
loginCoordinator.start()
func showSignUpFlow(newUserInformation: NewUserInformation) {
let coordinator = SignUpFeatureCoordinator(
navigationController: navigationController,
newUserInformation: newUserInformation,
isMockEnvironment: false
)
childCoordinators.append(coordinator)
coordinator.finishDelegate = self
coordinator.signUpFeatureFinishDelegate = self
coordinator.start()
}

func showTabBarFlow() {
Expand Down Expand Up @@ -90,3 +103,30 @@ extension AppCoordinator: SplashCoordinatorFinishDelegate {
}
}
}

// MARK: SignUpFeatureCoordinatorFinishDelegate

extension AppCoordinator: SignUpFeatureCoordinatorFinishDelegate {
func signUpFeatureCooridnatorDidFinished() {
showTabBarFlow()
}
}

// MARK: LoginFeatureFinishDelegate

extension AppCoordinator: LoginFeatureFinishDelegate {
func loginFeatureCoordinatorDidFinished(initialUser: InitialUser?, token: Token?) {
if let initialUser {
showSignUpFlow(
newUserInformation: NewUserInformation(
mappedUserID: initialUser.mappedUserID,
provider: initialUser.provider
)
)
}

if token != nil {
showTabBarFlow()
}
}
}
11 changes: 11 additions & 0 deletions iOS/Projects/Core/Network/Sources/Foundation/TNEndPoint.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,17 @@ public extension TNEndPoint {
request.httpBody = body?.data
return request
}

func requestFormData() throws -> URLRequest {
guard let targetURL = URL(string: baseURL)?.appending(path: path).appending(query: query)
else {
throw TNError.invalidURL
}
var request = URLRequest(url: targetURL)
request.httpMethod = method.rawValue
request.allHTTPHeaderFields = headers.dictionary
return request
}
}

private extension URL {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,24 @@ import Foundation

public struct MultipartFormData {
private let boundary: String
private let imageDataList: [Data]

public let multipartItems: [MultipartItem]

public init(multipartItems: [MultipartItem]) {
boundary = UUID().uuidString
public init(
uuid: UUID,
mimeType _: String = "image/png",
imageDataList: [Data]
) {
boundary = "\(uuid.uuidString)"
multipartItems = imageDataList.map { MultipartItem(data: $0, mimeType: .imagePNG) }
self.imageDataList = imageDataList
}

public init(uuid: UUID, multipartItems: [MultipartItem]) {
boundary = uuid.uuidString
self.multipartItems = multipartItems
imageDataList = []
}

public func makeBody() -> Data {
Expand All @@ -27,7 +40,7 @@ public struct MultipartFormData {

for item in multipartItems {
let imageFieldName = "images"
let filename = "image\(UUID().uuidString)"
let filename = "image\(UUID().uuidString)\(item.fileExtension.rawValue)"

body.append(boundaryPrefix)
body.append(#"Content-Disposition: form-data; name="\#(imageFieldName)"; filename="\#(filename)"\#(lineBreak)"#)
Expand All @@ -38,7 +51,6 @@ public struct MultipartFormData {

// insert final boundary
body.append("--\(boundary)--\(lineBreak)")

return body
}
}
Expand Down
14 changes: 13 additions & 1 deletion iOS/Projects/Core/Network/Sources/Multipart/MultipartItem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,28 @@

import Foundation

// MARK: - MultipartItem

public struct MultipartItem {
let data: Data
let mimeType: MimeType
let fileExtension: FileExtension

public init(data: Data, mimeType: MimeType) {
public init(data: Data, mimeType: MimeType, fileExtension: FileExtension = .png) {
self.data = data
self.mimeType = mimeType
self.fileExtension = fileExtension
}

public enum MimeType: String {
case imagePNG = "image/png"
}
}

// MARK: - FileExtension

public enum FileExtension: String {
case png = ".png"
case jpg = ".jpg"
case jpeg = ".jpeg"
}
13 changes: 13 additions & 0 deletions iOS/Projects/Core/Network/Sources/Provider/TNProvidable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ public struct TNProvider<T: TNEndPoint>: TNProvidable {
return retriedData
}

public func uploadRequest(_ service: T, successStatusCodeRange range: Range<Int> = 200 ..< 300) async throws -> Data {
guard let multipart = service.multipart else { throw TNError.unknownError }
let (data, response) = try await session.upload(for: service.requestFormData(), from: multipart.makeBody())
try checkStatusCode(response, successStatusCodeRange: range)
return data
}

public func request(_ service: T, completion: @escaping (Data?, URLResponse?, Error?) -> Void) throws {
try session.dataTask(with: service.request(), completionHandler: completion).resume()
}
Expand All @@ -45,6 +52,12 @@ public struct TNProvider<T: TNEndPoint>: TNProvidable {
return data
}

public func requestResponse(_ service: T, successStatusCodeRange range: Range<Int> = 200 ..< 300) async throws -> (Data, URLResponse) {
let (data, response) = try await session.data(for: service.request(), delegate: nil)
try checkStatusCode(response, successStatusCodeRange: range)
return (data, response)
}

public func request(_ service: T, successStatusCodeRange range: Range<Int> = 200 ..< 300, interceptor: TNRequestInterceptor) async throws -> Data {
let request = try interceptor.adapt(service.request(), session: session)

Expand Down
2 changes: 1 addition & 1 deletion iOS/Projects/Features/Login/Project.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ let project = Project.makeModule(
targets: .feature(
.login,
testingOptions: [.unitTest],
dependencies: [.trinet, .keychain, .combineCocoa, .log, TargetDependency.feature(.signUp)],
dependencies: [.trinet, .keychain, .combineCocoa, .log, .auth],
testDependencies: [],
resources: "Resources/**"
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
"mappedUserID": "1233498sdafksdjhfk...",
"provider": "apple"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
// Copyright © 2023 kr.codesquad.boostcamp8. All rights reserved.
//

import Auth
import Combine
import Foundation
import Log
Expand All @@ -16,6 +17,7 @@ import Trinet
enum AuthorizationRepositoryError: Error {
case invalidData
case failureDecode
case resonseDecodingError
}

// MARK: - AuthorizationRepository
Expand All @@ -32,19 +34,16 @@ struct AuthorizationRepository: AuthorizationRepositoryRepresentable {
return Future<LoginResponse, Never> { promise in
Task {
do {
guard let token = String(data: authorizationInfo.identityToken, encoding: .utf8),
let authorizationCode = String(data: authorizationInfo.authorizationCode, encoding: .utf8)
else {
return
}
let authorizationInfoRequestDTO = AuthorizationInfoRequestDTO(identityToken: token, authorizationCode: authorizationCode)
let token = String(decoding: authorizationInfo.identityToken, as: UTF8.self)
let authorizationCode = String(decoding: authorizationInfo.authorizationCode, as: UTF8.self)

let data = try await provider.request(.signIn(authorizationInfoRequestDTO))

guard let responseCode = try decoder.decode(Response.self, from: data).code else {
return
let authorizationInfoRequestDTO = AuthorizationInfoRequestDTO(identityToken: token, authorizationCode: authorizationCode)
let (data, response) = try await provider.requestResponse(.signIn(authorizationInfoRequestDTO))
guard let urlResponse = response as? HTTPURLResponse else {
throw AuthorizationRepositoryError.resonseDecodingError
}
switch responseCode {
let statusCode = urlResponse.statusCode
switch statusCode {
case AuthorizationRepositoryResponseCode.token.code:
let token = try decoder.decode(GWResponse<Token>.self, from: data).data
promise(.success((token, nil)))
Expand All @@ -71,7 +70,7 @@ enum AuthorizationRepositoryEndPoint: TNEndPoint {
var path: String {
switch self {
case .signIn:
return "auth/apple/signin"
return "/api/v1/auth/apple/signin"
}
}

Expand All @@ -94,9 +93,7 @@ enum AuthorizationRepositoryEndPoint: TNEndPoint {
}

var headers: TNHeaders {
return .init(headers: [
// TODO: 헤더 설정
])
return .default
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,33 @@
// Copyright © 2023 kr.codesquad.boostcamp8. All rights reserved.
//

import Auth
import Foundation

// MARK: - InitialUser

/// 처음 로그인 하는 유저의 Response를 담을 Entity
public struct InitialUser {
/// 처음 로그인 하는지 아닌지
let isFirstLogined: Bool
public let isFirstLogined: Bool

///
let mappedUserID: String
public let mappedUserID: String

/// OAuth 로그인 종류
let provider: AuthProvider
public let provider: AuthProvider

public init(
isFirstLogined: Bool,
mappedUserID: String,
provider: AuthProvider
) {
self.isFirstLogined = isFirstLogined
self.mappedUserID = mappedUserID
self.provider = provider
}
}

// MARK: Codable

extension InitialUser: Codable {}

// MARK: - AuthProvider

enum AuthProvider: String, Codable {
case apple
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
// Copyright © 2023 kr.codesquad.boostcamp8. All rights reserved.
//

import Auth
import Combine
import Foundation

Expand Down
Loading

0 comments on commit a22a7b5

Please sign in to comment.