Skip to content

Commit 45a6017

Browse files
authored
Merge pull request #20 from YAPP-Github/feat/#19-Travel_Follow_Contents_API
Feat/#19 travel follow contents api
2 parents 95d2fd6 + 67798d3 commit 45a6017

58 files changed

Lines changed: 1421 additions & 504 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Projects/App/Sources/Application/AppComponent.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,17 @@
66
// Copyright © 2026 NDGL-iOS. All rights reserved.
77
//
88

9+
import Data
10+
import Domain
911
import RIBs
10-
1112
import RootFeature
1213

1314
final class AppComponent: Component<EmptyDependency>, RootDependency {
15+
16+
var tokenProvider: TokenProviding {
17+
shared { TokenRepositoryFactory.makeTokenProvider() }
18+
}
19+
1420
init() {
1521
super.init(dependency: EmptyComponent())
1622
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
//
2+
// KeychainStorage.swift
3+
// Core
4+
//
5+
// Created by NDGL on 2026-02-06.
6+
// Copyright © 2026 NDGL-iOS. All rights reserved.
7+
//
8+
9+
import Foundation
10+
import Security
11+
12+
public protocol KeychainStorageProtocol {
13+
func save(_ value: String, forKey key: String) -> Bool
14+
func load(forKey key: String) -> String?
15+
func delete(forKey key: String) -> Bool
16+
func clear() -> Bool
17+
}
18+
19+
public final class KeychainStorage: KeychainStorageProtocol {
20+
21+
private let service: String
22+
23+
public init(service: String = Bundle.main.bundleIdentifier ?? "com.ndgl.app") {
24+
self.service = service
25+
}
26+
27+
@discardableResult
28+
public func save(_ value: String, forKey key: String) -> Bool {
29+
guard let data = value.data(using: .utf8) else { return false }
30+
31+
// 기존 항목 삭제
32+
delete(forKey: key)
33+
34+
let query: [String: Any] = [
35+
kSecClass as String: kSecClassGenericPassword,
36+
kSecAttrService as String: service,
37+
kSecAttrAccount as String: key,
38+
kSecValueData as String: data,
39+
kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
40+
]
41+
42+
let status = SecItemAdd(query as CFDictionary, nil)
43+
return status == errSecSuccess
44+
}
45+
46+
public func load(forKey key: String) -> String? {
47+
let query: [String: Any] = [
48+
kSecClass as String: kSecClassGenericPassword,
49+
kSecAttrService as String: service,
50+
kSecAttrAccount as String: key,
51+
kSecReturnData as String: true,
52+
kSecMatchLimit as String: kSecMatchLimitOne
53+
]
54+
55+
var result: AnyObject?
56+
let status = SecItemCopyMatching(query as CFDictionary, &result)
57+
58+
guard status == errSecSuccess,
59+
let data = result as? Data,
60+
let value = String(data: data, encoding: .utf8) else {
61+
return nil
62+
}
63+
64+
return value
65+
}
66+
67+
@discardableResult
68+
public func delete(forKey key: String) -> Bool {
69+
let query: [String: Any] = [
70+
kSecClass as String: kSecClassGenericPassword,
71+
kSecAttrService as String: service,
72+
kSecAttrAccount as String: key
73+
]
74+
75+
let status = SecItemDelete(query as CFDictionary)
76+
return status == errSecSuccess || status == errSecItemNotFound
77+
}
78+
79+
@discardableResult
80+
public func clear() -> Bool {
81+
let query: [String: Any] = [
82+
kSecClass as String: kSecClassGenericPassword,
83+
kSecAttrService as String: service
84+
]
85+
86+
let status = SecItemDelete(query as CFDictionary)
87+
return status == errSecSuccess || status == errSecItemNotFound
88+
}
89+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//
2+
// TokenProviderAdapter.swift
3+
// Data
4+
//
5+
// Created by NDGL on 2026-02-06.
6+
// Copyright © 2026 NDGL-iOS. All rights reserved.
7+
//
8+
9+
import Domain
10+
import Foundation
11+
12+
public final class TokenProviderAdapter: TokenProviding, @unchecked Sendable {
13+
14+
private let tokenRepository: TokenRepositoryProtocol
15+
16+
public init(tokenRepository: TokenRepositoryProtocol) {
17+
self.tokenRepository = tokenRepository
18+
}
19+
20+
public func accessToken() -> String? {
21+
tokenRepository.get(.accessToken)
22+
}
23+
}

Projects/Data/Sources/DI/AuthRepositoryFactory.swift renamed to Projects/Data/Sources/DI/AuthServiceFactory.swift

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// AuthRepositoryFactory.swift
2+
// AuthServiceFactory.swift
33
// Data
44
//
55
// Created by kimnahun on 1/21/26.
@@ -13,7 +13,3 @@ import Networks
1313
public func makeAuthService() -> AuthServiceProtocol {
1414
AuthService()
1515
}
16-
17-
public func makeAuthRepository(authService: AuthServiceProtocol) -> AuthRepositoryProtocol {
18-
AuthRepository(authService: authService)
19-
}

Projects/Data/Sources/DI/FollowRepositoryFactory.swift

Lines changed: 0 additions & 19 deletions
This file was deleted.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//
2+
// FollowServiceFactory.swift
3+
// Data
4+
//
5+
// Created by NDGL on 2026-02-06.
6+
// Copyright © 2026 NDGL-iOS. All rights reserved.
7+
//
8+
9+
import Domain
10+
import Foundation
11+
import Networks
12+
13+
public func makeFollowService() -> FollowServiceProtocol {
14+
FollowService()
15+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//
2+
// TokenRepositoryFactory.swift
3+
// Data
4+
//
5+
// Created by NDGL on 2026-02-06.
6+
// Copyright © 2026 NDGL-iOS. All rights reserved.
7+
//
8+
9+
import Core
10+
import Domain
11+
import Foundation
12+
13+
public enum TokenRepositoryFactory {
14+
15+
public static func make() -> TokenRepositoryProtocol {
16+
let keychainStorage = KeychainStorage()
17+
return TokenRepository(keychainStorage: keychainStorage)
18+
}
19+
20+
public static func makeTokenProvider() -> TokenProviding {
21+
let tokenRepository = make()
22+
return TokenProviderAdapter(tokenRepository: tokenRepository)
23+
}
24+
25+
public static func makeTokenProvider(with repository: TokenRepositoryProtocol) -> TokenProviding {
26+
TokenProviderAdapter(tokenRepository: repository)
27+
}
28+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//
2+
// TravelServiceFactory.swift
3+
// Data
4+
//
5+
// Created by NDGL on 2026-02-06.
6+
// Copyright © 2026 NDGL-iOS. All rights reserved.
7+
//
8+
9+
import Domain
10+
import Foundation
11+
import Moya
12+
import Networks
13+
14+
public func makeTravelService(tokenProvider: TokenProviding) -> TravelServiceProtocol {
15+
let provider: MoyaProvider<TravelAPI> = NetworkProviderFactory.makeAuthenticatedProvider(
16+
tokenProvider: tokenProvider
17+
)
18+
return TravelService(provider: provider)
19+
}

Projects/Data/Sources/Repository/Auth/AuthRepository.swift

Lines changed: 0 additions & 40 deletions
This file was deleted.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//
2+
// TokenRepository.swift
3+
// Data
4+
//
5+
// Created by NDGL on 2026-02-06.
6+
// Copyright © 2026 NDGL-iOS. All rights reserved.
7+
//
8+
9+
import Core
10+
import Domain
11+
import Foundation
12+
13+
public final class TokenRepository: TokenRepositoryProtocol {
14+
15+
// MARK: - Properties
16+
17+
private let keychainStorage: KeychainStorageProtocol
18+
19+
// MARK: - Initialization
20+
21+
public init(keychainStorage: KeychainStorageProtocol) {
22+
self.keychainStorage = keychainStorage
23+
}
24+
25+
// MARK: - TokenRepositoryProtocol
26+
27+
public func save(_ value: String, for type: TokenType) {
28+
keychainStorage.save(value, forKey: type.rawValue)
29+
}
30+
31+
public func get(_ type: TokenType) -> String? {
32+
keychainStorage.load(forKey: type.rawValue)
33+
}
34+
35+
public func delete(_ type: TokenType) {
36+
keychainStorage.delete(forKey: type.rawValue)
37+
}
38+
}

0 commit comments

Comments
 (0)