-
Notifications
You must be signed in to change notification settings - Fork 1
Design/#18 home #24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Design/#18 home #24
Changes from all commits
b928577
6d87048
f3f34fa
ffe834f
cb4270a
6484a03
90fbc90
24b21fe
1cb99e7
cdc04ff
4a19bc2
1b0f08a
97cf0aa
777b41e
1a0e32e
c2727fb
abba511
b5c9c32
f981fb0
9af5995
46cc298
7670fc4
39d6928
ee416c6
c8a331b
19dd8aa
e5c1cfc
8498de8
a32080b
ca13615
1c31756
d73fd16
b6324e8
9ad4d99
c3e3bcd
d4fd2bd
1e5c079
d80fbe8
ccc4049
a305883
657ea4f
8871919
1140041
8dcfcfb
7546a19
ea28b57
fa1e35b
7612920
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| // | ||
| // String+.swift | ||
| // Core | ||
| // | ||
| // Created by ์ต์์ฉ on 1/31/26. | ||
| // Copyright ยฉ 2026 NDGL-iOS. All rights reserved. | ||
| // | ||
|
|
||
| import Foundation | ||
|
|
||
| public extension String { | ||
| func toFlag() -> String { | ||
| guard self.count == 2 else { return "๐ณ๏ธ" } | ||
|
|
||
| let base: UInt32 = 127397 | ||
| var flagString = "" | ||
|
|
||
| for uni in self.uppercased().unicodeScalars { | ||
| if let scalar = UnicodeScalar(base + uni.value) { | ||
| flagString.append(String(scalar)) | ||
| } else { | ||
| return "๐ณ๏ธ" | ||
| } | ||
| } | ||
| return flagString | ||
| } | ||
|
|
||
| func toKoreanCountryName() -> String { | ||
| guard self.count == 2 else { return "์ ์ ์์" } | ||
|
|
||
| let locale = Locale(identifier: "ko_KR") | ||
| return locale.localizedString(forRegionCode: self) ?? "์ ์ ์์" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| // | ||
| // UICollectionReusableView+.swift | ||
| // Core | ||
| // | ||
| // Created by ์ต์์ฉ on 2/3/26. | ||
| // Copyright ยฉ 2026 NDGL-iOS. All rights reserved. | ||
| // | ||
|
|
||
| import UIKit | ||
|
|
||
| public extension UICollectionReusableView { | ||
| static var reusableViewIdentifier : String { | ||
| return String(describing: self) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| // | ||
| // UICollectionViewCell+.swift | ||
| // Core | ||
| // | ||
| // Created by ์ต์์ฉ on 1/30/26. | ||
| // Copyright ยฉ 2026 NDGL-iOS. All rights reserved. | ||
| // | ||
|
|
||
| import UIKit | ||
|
|
||
| public extension UICollectionViewCell { | ||
| static var cellIdentifier : String { | ||
| return String(describing: self) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| // | ||
| // UITableViewCell+.swift | ||
| // Core | ||
| // | ||
| // Created by ์ต์์ฉ on 2/10/26. | ||
| // Copyright ยฉ 2026 NDGL-iOS. All rights reserved. | ||
| // | ||
|
|
||
| import UIKit | ||
|
|
||
| public extension UITableViewCell { | ||
| static var cellIdentifier: String { | ||
| return String(describing: self) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -18,6 +18,7 @@ public final class TokenProviderAdapter: TokenProviding, @unchecked Sendable { | |||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| public func accessToken() -> String? { | ||||||||||||||||||
| tokenRepository.get(.accessToken) | ||||||||||||||||||
| // tokenRepository.get(.accessToken) | ||||||||||||||||||
| "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJiYmE3ODIwYS0wMDUzLTQxZDctODdhYi00Zjk2ZWM3ZDI1MTMiLCJpYXQiOjE3NzA5NjQzMDUsImV4cCI6MTc3MTA1MDcwNX0.Sn8wNhZ1Ac-ETZDsOiSMMHHaALJNXxNKrbN_-4xD5REcVa2tJ0NiafhTKlbIuYafL1Acd9dDMIHjx3H33c5w8w" | ||||||||||||||||||
| } | ||||||||||||||||||
|
Comment on lines
20
to
23
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ํ๋์ฝ๋ฉ๋ JWT ํ ํฐ์ ๋ณด์ ์ํ์ ๋๋ค. ํ
์คํธ ๋ชฉ์ ์ด๋ผ ํ๋๋ผ๋, ์ปค๋ฐ๋ JWT๋ Git ํ์คํ ๋ฆฌ์ ์๊ตฌ์ ์ผ๋ก ๋จ๊ฒ ๋ฉ๋๋ค. ํด๋น ํ ํฐ์ ์ฆ์ ๋ฌดํจํ(revoke)ํ๊ณ , ์ค์ ํ ํฐ ์กฐํ ๋ก์ง์ ๋ณต์ํด ์ฃผ์ธ์. ํ
์คํธ ์์๋ ํ๊ฒฝ ๋ณ์๋ ๋ณ๋ ์ค์ ํ์ผ( ๐ ์ ์: ์๋ ๋ก์ง ๋ณต์ public func accessToken() -> String? {
-// tokenRepository.get(.accessToken)
- "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJiYmE3ODIwYS0wMDUzLTQxZDctODdhYi00Zjk2ZWM3ZDI1MTMiLCJpYXQiOjE3NzA3OTUwMjYsImV4cCI6MTc3MDg4MTQyNn0.oNCkotV0uA-3kCtTwGhTUwA9fUUhuO85p1k3952oTfRaULOw2Ix3RpXq_ta82ynmUK7F3i8F0Jb1d4_Rl-zcgA"
+ tokenRepository.get(.accessToken)
}๐ Committable suggestion
Suggested change
๐งฐ Tools๐ช Gitleaks (8.30.0)[high] 22-22: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data. (jwt) ๐ค Prompt for AI Agents
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ์ด๋ถ๋ถ์ ์ฝ๋์ ์๋๊ฒ ์๋๋ผ ์์๋ก ํ๋๋ผ๋ฉด xcconfig์์ ๊ฐ์ ธ์์ผ๋ฉด ๋ ์ข์ ๊ฒ ๊ฐ์ต๋๋ค. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
PR description image: none provided. ์๊ฒฌ ๊ฐ์ฌํฉ๋๋ค. ๋ง์ ์ฃผ์ ๋๋ก ์ฝ๋๋ ์ฆ์ ์๋ณตํ๊ณ , ๋ก์ปฌ ์์ ํ ํฐ์ด ํ์ํ๋ฉด xcconfig๋ฅผ ํตํด ์ฃผ์ ํ๋ ํ๋ฆ์ผ๋ก ์ฒ๋ฆฌํ๊ฒ ์ต๋๋ค.
public func accessToken() -> String? {
tokenRepository.get(.accessToken)
}
์์(Adapter์ DEBUG ์ ์ฉ fallback ์ถ๊ฐ): public func accessToken() -> String? {
if let token = tokenRepository.get(.accessToken) {
return token
}
`#if` DEBUG
if let token = Bundle.main.object(forInfoDictionaryKey: "ACCESS_TOKEN") as? String, !token.isEmpty {
return token
}
`#endif`
return nil
}์ค์ ๋ฐฉ๋ฒ
๋ฐ๋ก ์๋ณต(1๋ฒ)๋ง ์ด PR์ ๋ฐ์ํ๊ณ , DEBUG fallback(2๋ฒ)์ ์ํ์๋ฉด ์ด๋ฒ PR์ ํฌํจํ๊ฑฐ๋ ๋ณ๋ PR๋ก ์งํํ๊ฒ ์ต๋๋ค. ์ด๋ค ๋ฐฉ์์ผ๋ก ์งํํ ์ง ์๋ ค์ฃผ์ธ์! โ๏ธ Learnings added
|
||||||||||||||||||
| } | ||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| // | ||
| // HomeServiceFactory.swift | ||
| // Data | ||
| // | ||
| // Created by ์ต์์ฉ on 2/10/26. | ||
| // Copyright ยฉ 2026 NDGL-iOS. All rights reserved. | ||
| // | ||
|
|
||
| import Domain | ||
| import Networks | ||
|
|
||
| import Moya | ||
|
|
||
| public func makeHomeService(tokenProvider: TokenProviding) -> HomeServiceProtocol { | ||
| let provider: MoyaProvider<HomeAPI> = NetworkProviderFactory.makeAuthenticatedProvider(tokenProvider: tokenProvider) | ||
| return HomeService(provider: provider) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| // | ||
| // HomeRepository.swift | ||
| // Data | ||
| // | ||
| // Created by ์ต์์ฉ on 2/4/26. | ||
| // Copyright ยฉ 2026 NDGL-iOS. All rights reserved. | ||
| // | ||
|
|
||
| import Foundation | ||
|
|
||
| import Domain | ||
| import Networks | ||
|
|
||
| public final class HomeRepository: HomeRepositoryInterface { | ||
| private let homeService: HomeServiceProtocol | ||
|
|
||
| public init(homeService: HomeServiceProtocol) { | ||
| self.homeService = homeService | ||
| } | ||
|
|
||
| public func fetchMyTripInfo() async throws -> MyTripSummary { | ||
| do { | ||
| return try await homeService.getUpcoming().toDomain() | ||
| } catch { | ||
| throw error.toNDGLError() | ||
| } | ||
| } | ||
|
|
||
| public func fetchCategoryList() async throws -> [TripCategory] { | ||
| do { | ||
| return try await homeService.getCategoryList().map { $0.toDomain() } | ||
| } catch { | ||
| throw error.toNDGLError() | ||
| } | ||
| } | ||
|
|
||
| public func fetchPopularTripList(id: Int?, page: Int?, size: Int?) async throws -> [TripInfo] { | ||
| do { | ||
| return try await homeService.getPopularTripList(id: id, page: page, size: size).toDomain() | ||
| } catch { | ||
| throw error.toNDGLError() | ||
| } | ||
| } | ||
|
|
||
| public func fetchRecommendTripList(page: Int?, size: Int?) async throws -> [TripInfo] { | ||
| do { | ||
| return try await homeService.getRecommendTripList(page: page, size: size).toDomain() | ||
| } catch { | ||
| throw error.toNDGLError() | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| // | ||
| // Error+.swift | ||
| // Data | ||
| // | ||
| // Created by ์ต์์ฉ on 2/13/26. | ||
| // Copyright ยฉ 2026 NDGL-iOS. All rights reserved. | ||
| // | ||
|
|
||
| import Foundation | ||
|
|
||
| import Domain | ||
| import Networks | ||
|
|
||
| extension Error { | ||
| func toNDGLError() -> NDGLError { | ||
| if let networkError = self as? NetworkError { | ||
| switch networkError { | ||
| case .connectionFailed, .decodingFailed, .noData: | ||
| return .unknown("\(networkError.message)") | ||
| case .unknown(let string): | ||
| return .serverError(string) | ||
| case .serverError(let errorResponse): | ||
| return .serverError(errorResponse.message ?? "์ ์ ์๋ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค.") | ||
| } | ||
| } | ||
|
|
||
| return .unknown("์ ์ ์๋ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค.") | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| // | ||
| // ProgramResponse+.swift | ||
| // Data | ||
| // | ||
| // Created by ์ต์์ฉ on 2/10/26. | ||
| // Copyright ยฉ 2026 NDGL-iOS. All rights reserved. | ||
| // | ||
|
|
||
| import Foundation | ||
|
|
||
| import Domain | ||
| import Networks | ||
|
|
||
| extension ProgramResponse { | ||
| func toDomain() -> TripCategory { | ||
| .init(id: self.id, creator: self.name, viedoType: VideoType(rawValue: self.type)) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| // | ||
| // TripResponse+.swift | ||
| // Data | ||
| // | ||
| // Created by ์ต์์ฉ on 2/10/26. | ||
| // Copyright ยฉ 2026 NDGL-iOS. All rights reserved. | ||
| // | ||
|
|
||
| import Foundation | ||
|
|
||
| import Domain | ||
| import Networks | ||
|
|
||
| extension TripResponse { | ||
| func toDomain() -> [TripInfo] { | ||
| self.content.map { | ||
| .init( | ||
| id: $0.travelId, | ||
| title: $0.title, | ||
| thumbnailUrl: $0.thumbnail ?? "", | ||
| creator: $0.programName, | ||
| country: $0.country, | ||
| city: $0.city, | ||
| nights: $0.nights, | ||
| days: $0.days | ||
| ) | ||
| } | ||
| } | ||
|
Comment on lines
+14
to
+28
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ๐งฉ Analysis chain๐ Script executed: # First, find the TripResponse model definition
find . -name "*.swift" -type f | xargs grep -l "struct TripResponse" | head -5Repository: YAPP-Github/27th-App-Team-1-iOS Length of output: 138 ๐ Script executed: # Search for countryCode and country-related fields in Swift files
rg -n "countryCode|country_code|countryIso" --type=swift -C 3Repository: YAPP-Github/27th-App-Team-1-iOS Length of output: 1146 ๐ Script executed: # Look at the TripResponse structure to understand the available fields
rg -n "struct TripResponse|class TripResponse" --type=swift -A 20 | head -100Repository: YAPP-Github/27th-App-Team-1-iOS Length of output: 1554 ๐ Script executed: # Search for country code conversion or mapping logic
rg -n "countryCode|country.*code|CountryCode|Country.*Code" --type=swift -B2 -A2 | head -80Repository: YAPP-Github/27th-App-Team-1-iOS Length of output: 844 ๐ Script executed: # Check if there are any utility functions for country code conversion
rg -n "func.*country|country.*func" --type=swift -i -B1 -A3 | head -60Repository: YAPP-Github/27th-App-Team-1-iOS Length of output: 544 ๐ Script executed: # Look for any test files related to TripResponse transformation
find . -name "*TripResponse*Test*" -o -name "*Test*TripResponse*" | head -5Repository: YAPP-Github/27th-App-Team-1-iOS Length of output: 57 ๐ Script executed: # Read the complete String+.swift file to see all country-related extensions
cat Projects/Core/Sources/Extensions/Foundation+/String+.swiftRepository: YAPP-Github/27th-App-Team-1-iOS Length of output: 912 ๐ Script executed: # Search for any reverse conversion (name to code) or country code mapping
rg -n "country.*Code|countryCode.*=|country_code" --type=swift -B3 -A3Repository: YAPP-Github/27th-App-Team-1-iOS Length of output: 1146 ๐ Script executed: # Search for test files, mocks, or sample data that shows what the country field contains
find . -type f \( -name "*Mock*" -o -name "*Test*" -o -name "*Stub*" \) -exec grep -l "country\|TripResponse\|TripContent" {} \; | head -10Repository: YAPP-Github/27th-App-Team-1-iOS Length of output: 151 ๐ Script executed: # Look for JSON files or API response examples
find . -type f \( -name "*.json" -o -name "*.txt" \) -exec grep -l "country\|travelId\|programName" {} \; | head -10Repository: YAPP-Github/27th-App-Team-1-iOS Length of output: 57 ๐ Script executed: # Check the mock file to see what data it uses
cat Projects/Features/FollowFeature/Sources/Mock/MockFollowDetailService.swift | head -100Repository: YAPP-Github/27th-App-Team-1-iOS Length of output: 3961 ๐ Script executed: # Look for any API documentation, comments, or README that describes the response format
find . -type f \( -name "README*" -o -name "*.md" \) -exec grep -l "country\|API\|response" {} \; | head -10Repository: YAPP-Github/27th-App-Team-1-iOS Length of output: 57 ๐ Script executed: # Search for any comments near the TripResponse or TripContentResponse definition
rg -n "TripContentResponse|TripResponse" --type=swift -B5 -A30 | grep -A30 "struct TripContentResponse"Repository: YAPP-Github/27th-App-Team-1-iOS Length of output: 2506
Line 26์์
๐ค Prompt for AI Agents |
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| // | ||
| // UpcomingResponse+.swift | ||
| // Data | ||
| // | ||
| // Created by ์ต์์ฉ on 2/13/26. | ||
| // Copyright ยฉ 2026 NDGL-iOS. All rights reserved. | ||
| // | ||
|
|
||
| import Foundation | ||
|
|
||
| import Domain | ||
| import Networks | ||
|
|
||
| extension UpcomingResponse { | ||
| func toDomain() -> MyTripSummary { | ||
| return .init( | ||
| id: self.userTravelId, | ||
| title: self.title, | ||
| startDay: self.startDate.toDate() ?? .now, | ||
| endDay: self.endDate.toDate() ?? .now, | ||
|
Comment on lines
+19
to
+20
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ๋ ์ง ํ์ฑ ์คํจ ์
๐ค Prompt for AI Agents |
||
| tripSchedule: .init( | ||
| id: self.upcomingUserTravelPlace.id, | ||
| day: 1, // ์๋ฒ์์ ์ฒซ ์ผ์ ๋ง ๋ณด๋ด์ฃผ๊ณ ์์ | ||
| placeName: self.upcomingUserTravelPlace.place.name, | ||
| thumbnailUrl: self.upcomingUserTravelPlace.place.thumbnail ?? "", | ||
| transport: self.upcomingUserTravelPlace.place.category, | ||
| estimatedDuration: self.upcomingUserTravelPlace.estimatedDuration | ||
| ) | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| extension String { | ||
| func toDate() -> Date? { | ||
| let formatter = DateFormatter() | ||
| formatter.locale = Locale(identifier: "en_US_POSIX") | ||
| formatter.dateFormat = "yyyy-MM-dd" | ||
| return formatter.date(from: self) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| // | ||
| // NDGLError.swift | ||
| // Domain | ||
| // | ||
| // Created by ์ต์์ฉ on 2/13/26. | ||
| // Copyright ยฉ 2026 NDGL-iOS. All rights reserved. | ||
| // | ||
|
|
||
| import Foundation | ||
|
|
||
| public enum NDGLError: Error { | ||
| case serverError(String) | ||
| case unknown(String) | ||
| case authenticationFailed | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
๋งค๋ฒ idenifier ์ถ๊ฐ๋ก ๋ง๋ค์ด์คฌ๋๋ฐ ์ด ๋ถ๋ถ ์๋ ๊ฒ ์ข์ต๋๋ค. (์๊ฐ๋ง ํ๊ณ ์์๋๋ฐ ๐ )