Skip to content

Commit

Permalink
πŸ”€ :: (#558) 사진 μ—…λ‘œλ“œ 둜직 λ³€κ²½
Browse files Browse the repository at this point in the history
  • Loading branch information
BJCHO0501 authored Sep 4, 2023
2 parents 657d3af + 6033fb7 commit 248e602
Show file tree
Hide file tree
Showing 18 changed files with 275 additions and 64 deletions.
6 changes: 4 additions & 2 deletions Application/Sources/Router/XQUARE/XquareRouterFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,8 @@ class XquareRouterFactory: RouterFactory {
let myPageViewModel = MyPageViewModel(
fetchProfileUseCase: userServiceDependency.fetchProfileUseCase,
editProfileImageUseCase: userServiceDependency.editProfileImageUseCase,
uploadImageUseCase: attachmentServiceDependency.uploadImageUseCase,
requestPresignedUrlUseCase: attachmentServiceDependency.requestPresignedUrlUseCase,
uploadImageToS3UseCase: attachmentServiceDependency.uploadImageToS3UseCase,
logoutUseCase: authServiceDependency.logoutUseCase,
registerGithubIDUseCase: githubServiceDependency.registerGithubIDUseCase,
checkGithubConnectingUseCase: githubServiceDependency.checkGithubConnecting
Expand All @@ -144,7 +145,8 @@ class XquareRouterFactory: RouterFactory {

let bugReportViewModel = BugReportViewModel(
postBugReportUseCase: reportServiceDependency.postBugReportUseCase,
uploadImageUseCase: attachmentServiceDependency.uploadImageUseCase
requestPresignedUrlUseCase: attachmentServiceDependency.requestPresignedUrlUseCase,
uploadImageToS3UseCase: attachmentServiceDependency.uploadImageToS3UseCase
)
self.bugReportView = BugReportView(viewModel: bugReportViewModel)

Expand Down
5 changes: 4 additions & 1 deletion Application/Sources/Scene/BugReport/BugReportView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,12 @@ struct BugReportView: View {
isPresented: $viewModel.xPhotosIsPresented,
selection: $viewModel.bugImage
)
.sdOkayAlert(isPresented: $viewModel.networking, sdAlert: {
.sdOkayAlert(isPresented: $viewModel.isSuccess, sdAlert: {
SDOkayAlert(title: "λ²„κ·Έμ œλ³΄", message: "제보 κ°μ‚¬ν•©λ‹ˆλ‹€! μ‚¬μš©μžλ‹˜λ“€μ˜ 제보둜 더 λ‚˜μ€ μŠ€ν€˜μ–΄λ₯Ό λ§Œλ“€μ–΄κ°‘λ‹ˆλ‹€!")
})
.sdOkayAlert(isPresented: $viewModel.isOverStorage, sdAlert: {
SDOkayAlert(title: "μ—…λ‘œλ“œ μ‹€νŒ¨", message: "파일의 μš©λŸ‰μ€ 10GBμ΄ν•˜μ—¬μ•Ό ν•©λ‹ˆλ‹€.")
})
.onAppear {viewModel.viewAppear()}
.onChange(of: viewModel.bugImage, perform: { _ in
viewModel.isLoading = true
Expand Down
80 changes: 65 additions & 15 deletions Application/Sources/Scene/BugReport/BugReportViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,42 +7,90 @@ class BugReportViewModel: ObservableObject {
@Published var bugPlace: String = "ν™ˆ"
@Published var content: String = ""
@Published var isDisabled: Bool = true
@Published var networking: Bool = false
@Published var bugImageUrl = [""]
@Published var bugImage: [UIImage] = [UIImage()]
@Published var isSuccess: Bool = false
@Published var isOverStorage: Bool = false
@Published var bugImageUrl: [String] = []
@Published var bugImage: [UIImage] = []
@Published var xPhotosIsPresented: Bool = false
@Published var isLoading: Bool = false
@Published var isEmpty: Bool = false
var catagory: BugCategory = .home

private let postBugReportUseCase: PostBugReportUseCase
private let uploadImageUseCase: UploadImageUseCase
private let requestPresignedUrlUseCase: RequestPresignedUrlUseCase
private let uploadImageToS3UseCase: UploadImageToS3UseCase

private var disposeBag = DisposeBag()

init(
postBugReportUseCase: PostBugReportUseCase,
uploadImageUseCase: UploadImageUseCase
requestPresignedUrlUseCase: RequestPresignedUrlUseCase,
uploadImageToS3UseCase: UploadImageToS3UseCase
) {
self.postBugReportUseCase = postBugReportUseCase
self.uploadImageUseCase = uploadImageUseCase
self.requestPresignedUrlUseCase = requestPresignedUrlUseCase
self.uploadImageToS3UseCase = uploadImageToS3UseCase
}

func checkBugPlaceAndContentIsEmpty() {
isDisabled = bugPlace.isEmpty || content.isEmpty
}

func uploadImage() {
self.uploadImageUseCase
.excute(files: self.bugImage.map { $0.jpegData(compressionQuality: 0.1) ?? Data() })
.subscribe(onSuccess: {
self.isLoading = false
self.bugImageUrl = $0
self.isEmpty = false
}, onFailure: { _ in
self.bugImage.forEach {
print($0.imageOrientation)
}
let imageDatas = self.bugImage.map { $0.jpegData(compressionQuality: 0.3) ?? Data() }
for image in imageDatas {
guard image.count / 1048576 < 10 else {
self.isLoading = false
self.bugImageUrl = [""]
self.isEmpty = true
}).disposed(by: disposeBag)
self.isOverStorage = true
return
}
}
guard !imageDatas.isEmpty else {
self.isLoading = false
self.isEmpty = true
return
}
debugPrint("call - uploadImage()")
self.requestPresignedUrlUseCase
.excute(files: imageDatas)
.subscribe(
with: self,
onSuccess: { owner, datas in
owner.uploadImageToS3(presignedDatas: datas, imageDatas: imageDatas)
}, onFailure: { owner, error in
debugPrint("⚠️Bugreport uploadImage Error: \(error.localizedDescription)")
owner.isLoading = false
owner.bugImageUrl = [""]
owner.isEmpty = true
}
).disposed(by: disposeBag)
}

private func uploadImageToS3(
presignedDatas: [PresigedUrlEntity],
imageDatas: [Data]
) {
uploadImageToS3UseCase
.excute(presigedDatas: presignedDatas, imageDatas: imageDatas)
.subscribe(
with: self,
onCompleted: { owner in
owner.isLoading = false
owner.bugImageUrl = presignedDatas.map { $0.url }
owner.isEmpty = false
}, onError: { owner, error in
debugPrint("⚠️Bugreport uploadImageToS3 Error: \(error.localizedDescription)")
owner.isLoading = false
owner.isEmpty = true
}
).disposed(by: disposeBag)
}

func postBug() {
checkBugPlace()
postBugReportUseCase.excute(
Expand All @@ -51,9 +99,10 @@ class BugReportViewModel: ObservableObject {
imageUrl: bugImageUrl
).subscribe(onCompleted: {
self.viewAppear()
self.networking = true
self.isSuccess = true
}).disposed(by: disposeBag)
}

func viewAppear() {
self.content = ""
self.isLoading = false
Expand All @@ -63,6 +112,7 @@ class BugReportViewModel: ObservableObject {
self.isEmpty = true
self.bugImageUrl = [""]
}

private func checkBugPlace() {
switch bugPlace {
case "μ‹ μ²­":
Expand Down
7 changes: 5 additions & 2 deletions Application/Sources/Scene/MyPage/MyPageView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,17 @@ struct MyPageView: View {
})
)
}
.sdOkayAlert(isPresented: $viewModel.isOverStorage, sdAlert: {
SDOkayAlert(title: "μ—…λ‘œλ“œ μ‹€νŒ¨", message: "파일의 μš©λŸ‰μ€ 10GBμ΄ν•˜μ—¬μ•Ό ν•©λ‹ˆλ‹€.")
})
.sdOkayAlert(isPresented: $viewModel.showLinkingErrorAlert) {
SDOkayAlert(title: "였λ₯˜", message: "연동에 μ‹€νŒ¨ν•˜μ˜€μŠ΅λ‹ˆλ‹€.")
}
.sdPhotoPicker(
isPresented: $viewModel.xPhotosIsPresented,
selection: $viewModel.profileImage
selection: $viewModel.selectProfileImage
)
.onChange(of: viewModel.profileImage, perform: { _ in
.onChange(of: viewModel.selectProfileImage, perform: { _ in
viewModel.uploadImage()
})
.setNavigationBackButton()
Expand Down
45 changes: 35 additions & 10 deletions Application/Sources/Scene/MyPage/MyPageViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,32 @@ class MyPageViewModel: ObservableObject {
@Published var xPhotosIsPresented: Bool = false
@Published var profileImageString: String = ""
@Published var showLogoutAlert: Bool = false
@Published var isOverStorage: Bool = false
@Published var isGithubLinking: Bool = false
@Published var showLinkingErrorAlert: Bool = false
var selectProfileImage = UIImage()

private let fetchProfileUseCase: FetchProfileUseCase
private let editProfileImageUseCase: EditProfileImageUseCase
private let uploadImageUseCase: UploadImageUseCase
private let requestPresignedUrlUseCase: RequestPresignedUrlUseCase
private let uploadImageToS3UseCase: UploadImageToS3UseCase
private let logoutUseCase: LogoutUseCase
private let registerGithubIDUseCase: RegisterGithubIDUseCase
private let checkGithubConnectingUseCase: CheckGithubConnectingUseCase

init(
fetchProfileUseCase: FetchProfileUseCase,
editProfileImageUseCase: EditProfileImageUseCase,
uploadImageUseCase: UploadImageUseCase,
requestPresignedUrlUseCase: RequestPresignedUrlUseCase,
uploadImageToS3UseCase: UploadImageToS3UseCase,
logoutUseCase: LogoutUseCase,
registerGithubIDUseCase: RegisterGithubIDUseCase,
checkGithubConnectingUseCase: CheckGithubConnectingUseCase
) {
self.fetchProfileUseCase = fetchProfileUseCase
self.editProfileImageUseCase = editProfileImageUseCase
self.uploadImageUseCase = uploadImageUseCase
self.requestPresignedUrlUseCase = requestPresignedUrlUseCase
self.uploadImageToS3UseCase = uploadImageToS3UseCase
self.logoutUseCase = logoutUseCase
self.registerGithubIDUseCase = registerGithubIDUseCase
self.checkGithubConnectingUseCase = checkGithubConnectingUseCase
Expand All @@ -59,18 +64,38 @@ class MyPageViewModel: ObservableObject {
}

func uploadImage() {
self.uploadImageUseCase
.excute(files: [self.profileImage.jpegData(compressionQuality: 0.5) ?? Data()])
.subscribe(onSuccess: {
self.editProfileImage(imageUrl: $0[0])
})
let imageData = self.selectProfileImage.jpegData(compressionQuality: 0.3) ?? Data()
guard imageData.count / 1048576 < 10 else {
self.isOverStorage = true
return
}
self.requestPresignedUrlUseCase
.excute(files: [imageData])
.subscribe(
with: self,
onSuccess: { owner, datas in
owner.uploadImageToS3(presignedDatas: datas, imageDatas: [imageData])
}
)
.disposed(by: disposeBag)
}

private func uploadImageToS3(presignedDatas: [PresigedUrlEntity], imageDatas: [Data]) {
self.uploadImageToS3UseCase
.excute(presigedDatas: presignedDatas, imageDatas: imageDatas)
.subscribe(
with: self,
onCompleted: { owner in
owner.editProfileImage(imageUrl: presignedDatas[0].url)
owner.profileImage = owner.selectProfileImage
}
)
.disposed(by: disposeBag)
}

private func editProfileImage(imageUrl: String) {
self.editProfileImageUseCase.excute(profileImage: imageUrl)
.subscribe(onCompleted: {
})
.subscribe(onCompleted: { })
.disposed(by: disposeBag)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,28 @@ import Foundation
public struct AttachmentServiceDependency {
public static let shared = resolve()

public let uploadImageUseCase: UploadImageUseCase
public let requestPresignedUrlUseCase: RequestPresignedUrlUseCase
public let uploadImageToS3UseCase: UploadImageToS3UseCase
}

public extension AttachmentServiceDependency {
extension AttachmentServiceDependency {

static func resolve() -> AttachmentServiceDependency {
let remoteDataSource: RemoteAttachmentDataSource = RemoteAttachmentDataSourceImpl()
let repository: AttachmentRepository = AttachmentRepositoryImpl(remoteDataSource: remoteDataSource)

let uploadImageUseCase = UploadImageUseCase(
let requestPresignedUrlUseCase = RequestPresignedUrlUseCase(
repository: repository
)

return .init(uploadImageUseCase: uploadImageUseCase)
let uploadImageToS3UseCase = UploadImageToS3UseCase(
repository: repository
)

return .init(
requestPresignedUrlUseCase: requestPresignedUrlUseCase,
uploadImageToS3UseCase: uploadImageToS3UseCase
)

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import RestApiModule
import AuthService

enum AttachmentAPI {
case uploadFiles(files: [Data])
case requestPresignedUrl(files: [Data])
}

extension AttachmentAPI: XquareAPI {

var domain: String {
"/attachment"
return "/attachment"
}

var urlPath: String {
Expand All @@ -28,17 +28,20 @@ extension AttachmentAPI: XquareAPI {

var task: Task {
switch self {
case .uploadFiles(let files):
var multiformData = [MultipartFormData]()
case .requestPresignedUrl(let files):
var imageParameters: [[String: Any]] = []
for file in files {
multiformData.append(.init(
provider: .data(file),
name: "files",
fileName: "files.jpg",
mimeType: "files/jpg"
))
imageParameters.append(
[
"original_filename": "image.jpg",
"content_type": "image/jpg",
"file_size": file.count
]
)
}
return .uploadCompositeMultipart(multiformData, urlParameters: ["bucketName": "xquare"])
return .requestParameters(parameters: [
"image_file_requests": imageParameters
], encoding: JSONEncoding.default)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import Moya
import Foundation

enum PresignedUrlAPI {
case uploadImageToS3(presignedURL: String, contentType: String, data: Data)
}

extension PresignedUrlAPI: TargetType {

var baseURL: URL {
switch self {
case .uploadImageToS3(let presignedURL, _, _):
return URL(string: presignedURL)!
}
}

var path: String {
return ""
}

var method: Moya.Method {
return .put
}

var task: Moya.Task {
switch self {
case .uploadImageToS3(_, _, let data):
return .requestData(data)
}
}

var headers: [String: String]? {
return ["Content-Type": "image/jpg"]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ import RestApiModule
import RxSwift

protocol RemoteAttachmentDataSource: RestApiRemoteDataSource<AttachmentAPI> {
func uploadFiles(files: [Data]) -> Single<[String]>
func requestPresignedUrl(files: [Data]) -> Single<[PresigedUrlEntity]>
func uploadImageToS3(presignedURL: String, contentType: String, data: Data) -> Completable
}
Loading

0 comments on commit 248e602

Please sign in to comment.