Skip to content

Commit 61f7084

Browse files
authored
[Merge] #215 - 프로필 이미지 등록 API 연결
2 parents 3c41830 + cec5d24 commit 61f7084

12 files changed

Lines changed: 207 additions & 6 deletions

File tree

CERTI-iOS/Application/DIContainer/AppDIContainer.swift

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,14 @@ extension AppDIContainer {
269269
func makeEditPreCertificationUseCase() -> EditPreCertificationUseCase {
270270
return DefaultEditPreCertificationUseCase(repository: homeRepository)
271271
}
272+
273+
func makeGetPresignedURLUseCase() -> GetPresignedURLUseCase {
274+
return DefaultGetPresignedURLUseCase(repository: userRepository)
275+
}
276+
277+
func makeUploadImageToPresignedURLUseCase() -> UploadImageToPresignedURLUseCase {
278+
return DefaultUploadImageToPresignedURLUseCase()
279+
}
272280
}
273281

274282

@@ -352,7 +360,9 @@ extension AppDIContainer {
352360
deleteAcquisitionUseCase: makeDeleteAcquisitionUseCase(),
353361
deletePreCertificationUseCase: makeDeletePreCertificationUseCase(),
354362
editAcquisitionUseCase: makeEditAcquisitionUseCase(),
355-
editPreCertificationUseCase: makeEditPreCertificationUseCase()
363+
editPreCertificationUseCase: makeEditPreCertificationUseCase(),
364+
getPresignedURLUseCase: makeGetPresignedURLUseCase(),
365+
uploadImageToPresignedURLUseCase: makeUploadImageToPresignedURLUseCase()
356366
)
357367
}
358368

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//
2+
// PresignedURLResponseDTO.swift
3+
// CERTI-iOS
4+
//
5+
// Created by nayeon on 2/14/26.
6+
//
7+
8+
typealias PresignedURLResponseDTO = BaseResponseDTO<PresignedURLResponseData>
9+
10+
struct PresignedURLResponseData: Decodable {
11+
let preSignedURL: String
12+
let publicURL: String
13+
14+
func toPresignedURLEntity() -> PresignedURLEntity {
15+
return PresignedURLEntity(
16+
preSignedURL: preSignedURL,
17+
publicURL: publicURL
18+
)
19+
}
20+
}

CERTI-iOS/Data/Network/User/UserAPI.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ enum UserAPI {
2323
case togglePrivacySetting(agree: EditNotificationSettingRequestDTO)
2424
case getNotificationSetting
2525
case getTrack
26+
case getPresignedURL
2627
}
2728

2829
extension UserAPI: BaseTargetType {
@@ -65,6 +66,8 @@ extension UserAPI: BaseTargetType {
6566
return "user/privacy-agreement"
6667
case .getTrack:
6768
return "user/track"
69+
case .getPresignedURL:
70+
return "user/presigned-url"
6871
}
6972
}
7073

@@ -96,6 +99,8 @@ extension UserAPI: BaseTargetType {
9699
return .patch
97100
case .getTrack:
98101
return .get
102+
case .getPresignedURL:
103+
return .get
99104
}
100105
}
101106

@@ -138,6 +143,9 @@ extension UserAPI: BaseTargetType {
138143

139144
case .getTrack:
140145
return .requestPlain
146+
147+
case .getPresignedURL:
148+
return .requestPlain
141149
}
142150
}
143151

CERTI-iOS/Data/Network/User/UserService.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ protocol UserServiceProtocol {
2323
func toggleMarketingSetting(agree: EditNotificationSettingRequestDTO) async -> Result<BaseResponseDTO<EmptyData>, NetworkError>
2424
func togglePrivacySetting(agree: EditNotificationSettingRequestDTO) async -> Result<BaseResponseDTO<EmptyData>, NetworkError>
2525
func getTrack() async -> Result<TrackResponseDTO, NetworkError>
26+
func getPresignedURL() async -> Result<PresignedURLResponseDTO, NetworkError>
2627

2728
}
2829

@@ -81,4 +82,8 @@ final class UserService: BaseService, UserServiceProtocol {
8182
func getTrack() async -> Result<TrackResponseDTO, NetworkError> {
8283
return await requestDecodable(provider, .getTrack)
8384
}
85+
86+
func getPresignedURL() async -> Result<PresignedURLResponseDTO, NetworkError> {
87+
return await requestDecodable(provider, .getPresignedURL)
88+
}
8489
}

CERTI-iOS/Data/Repositories/DefaultUserRepository.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,4 +182,16 @@ final class DefaultUserRepository: UserRepository {
182182
return .failure(error)
183183
}
184184
}
185+
186+
func getPresignedURL() async -> Result<PresignedURLEntity, NetworkError> {
187+
let result = await service.getPresignedURL()
188+
189+
switch result {
190+
case .success(let success):
191+
guard let data = success.data else { return .failure(.decodingError) }
192+
return .success(data.toPresignedURLEntity())
193+
case .failure(let error):
194+
return .failure(error)
195+
}
196+
}
185197
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//
2+
// PresignedURLEntity.swift
3+
// CERTI-iOS
4+
//
5+
// Created by nayeon on 2/14/26.
6+
//
7+
8+
struct PresignedURLEntity {
9+
let preSignedURL: String
10+
let publicURL: String
11+
}

CERTI-iOS/Domain/Interfaces/Repositories/UserRepository.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,5 @@ protocol UserRepository {
2323
func toggleMarketingSetting(agree: Bool) async -> Result<Void, NetworkError>
2424
func togglePrivacySetting(agree: Bool) async -> Result<Void, NetworkError>
2525
func getTrack() async -> Result<String, NetworkError>
26+
func getPresignedURL() async -> Result<PresignedURLEntity, NetworkError>
2627
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//
2+
// UploadImageToPresignedURLUseCase.swift
3+
// CERTI-iOS
4+
//
5+
// Created by nayeon on 2/14/26.
6+
//
7+
8+
import Foundation
9+
10+
protocol UploadImageToPresignedURLUseCase {
11+
func execute(preSignedURL: String, data: Data, contentType: String) async -> Result<Void, NetworkError>
12+
}
13+
14+
final class DefaultUploadImageToPresignedURLUseCase: UploadImageToPresignedURLUseCase {
15+
func execute(preSignedURL: String, data: Data, contentType: String) async -> Result<Void, NetworkError> {
16+
guard let url = URL(string: preSignedURL) else { return .failure(.apiError(message: "Invalid URL")) }
17+
18+
var request = URLRequest(url: url)
19+
request.httpMethod = "PUT"
20+
request.setValue(contentType, forHTTPHeaderField: "Content-Type")
21+
request.httpBody = data
22+
23+
do {
24+
let (_, response) = try await URLSession.shared.data(for: request)
25+
guard let http = response as? HTTPURLResponse else { return .failure(.decodingError) }
26+
guard (200...299).contains(http.statusCode) else {
27+
return .failure(.apiError(message: "Upload failed. status=\(http.statusCode)"))
28+
}
29+
return .success(())
30+
} catch {
31+
return .failure(.apiError(message: "Upload error: \(error.localizedDescription)"))
32+
}
33+
}
34+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//
2+
// GetPresignedURLUseCase.swift
3+
// CERTI-iOS
4+
//
5+
// Created by nayeon on 2/14/26.
6+
//
7+
8+
protocol GetPresignedURLUseCase {
9+
func execute() async -> Result<PresignedURLEntity, NetworkError>
10+
}
11+
12+
final class DefaultGetPresignedURLUseCase: GetPresignedURLUseCase {
13+
14+
private let repository: UserRepository
15+
16+
init(repository: UserRepository) {
17+
self.repository = repository
18+
}
19+
20+
func execute() async -> Result<PresignedURLEntity, NetworkError> {
21+
return await repository.getPresignedURL()
22+
}
23+
}

CERTI-iOS/Presentation/MyPage/Factory/MyPageFactory.swift

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ final class DefaultMyPageFactory: MyPageFactory {
3333
private let deletePreCertificationUseCase: DeletePreCertificationUseCase
3434
private let editAcquisitionUseCase: EditAcquisitionUseCase
3535
private let editPreCertificationUseCase: EditPreCertificationUseCase
36+
private let getPresignedURLUseCase: GetPresignedURLUseCase
37+
private let uploadImageToPresignedURLUseCase: UploadImageToPresignedURLUseCase
3638

3739
init(
3840
fetchMyPageInfoUseCase: FetchMyPageInfoUseCase,
@@ -56,6 +58,8 @@ final class DefaultMyPageFactory: MyPageFactory {
5658
deletePreCertificationUseCase: DeletePreCertificationUseCase,
5759
editAcquisitionUseCase: EditAcquisitionUseCase,
5860
editPreCertificationUseCase: EditPreCertificationUseCase,
61+
getPresignedURLUseCase: GetPresignedURLUseCase,
62+
uploadImageToPresignedURLUseCase: UploadImageToPresignedURLUseCase
5963
) {
6064
self.fetchMyPageInfoUseCase = fetchMyPageInfoUseCase
6165
self.fetchEditProfileInfoUseCase = fetchEditProfileInfoUseCase
@@ -78,6 +82,8 @@ final class DefaultMyPageFactory: MyPageFactory {
7882
self.deletePreCertificationUseCase = deletePreCertificationUseCase
7983
self.editAcquisitionUseCase = editAcquisitionUseCase
8084
self.editPreCertificationUseCase = editPreCertificationUseCase
85+
self.getPresignedURLUseCase = getPresignedURLUseCase
86+
self.uploadImageToPresignedURLUseCase = uploadImageToPresignedURLUseCase
8187
}
8288

8389
@MainActor
@@ -103,7 +109,9 @@ final class DefaultMyPageFactory: MyPageFactory {
103109
deleteAcquisitionUseCase: deleteAcquisitionUseCase,
104110
deletePreCertificationUseCase: deletePreCertificationUseCase,
105111
editAcquisitionUseCase: editAcquisitionUseCase,
106-
editPreCertificationUseCase: editPreCertificationUseCase
112+
editPreCertificationUseCase: editPreCertificationUseCase,
113+
getPresignedURLUseCase: getPresignedURLUseCase,
114+
uploadImageToPresignedURLUseCase: uploadImageToPresignedURLUseCase
107115
)
108116
}
109117
}

0 commit comments

Comments
 (0)