diff --git a/Projects/App/Sources/Application/DI/Files/AppComponent+Files.swift b/Projects/App/Sources/Application/DI/Files/AppComponent+Files.swift new file mode 100644 index 00000000..61f36644 --- /dev/null +++ b/Projects/App/Sources/Application/DI/Files/AppComponent+Files.swift @@ -0,0 +1,16 @@ +import DomainModule +import DataModule +import NetworkModule + +public extension AppComponent { + var remoteFilesDataSource: any RemoteFilesDataSource { + RemoteFilesDataSourceStub() +// RemoteFilesDataSourceImpl(keychain: keychain) + } + var filesRepository: any FilesRepository { + FilesRepositoryImpl(remoteFilesDataSource: remoteFilesDataSource) + } + var uploadFileUseCase: any UploadFileUseCase { + UploadFileUseCaseImpl(filesRepository: filesRepository) + } +} diff --git a/Projects/App/Sources/Application/NeedleGenerated.swift b/Projects/App/Sources/Application/NeedleGenerated.swift index 0bf8da76..6f394c9c 100644 --- a/Projects/App/Sources/Application/NeedleGenerated.swift +++ b/Projects/App/Sources/Application/NeedleGenerated.swift @@ -157,6 +157,9 @@ extension AppComponent: Registration { localTable["remoteMealDataSource-any RemoteMealDataSource"] = { self.remoteMealDataSource as Any } localTable["mealRepository-any MealRepository"] = { self.mealRepository as Any } localTable["fetchMealListUseCase-any FetchMealListUseCase"] = { self.fetchMealListUseCase as Any } + localTable["remoteFilesDataSource-any RemoteFilesDataSource"] = { self.remoteFilesDataSource as Any } + localTable["filesRepository-any FilesRepository"] = { self.filesRepository as Any } + localTable["uploadFileUseCase-any UploadFileUseCase"] = { self.uploadFileUseCase as Any } localTable["remoteSchoolDataSource-any RemoteSchoolDataSource"] = { self.remoteSchoolDataSource as Any } localTable["schoolRepository-any SchoolRepository"] = { self.schoolRepository as Any } localTable["fetchSchoolListUseCase-any FetchSchoolListUseCase"] = { self.fetchSchoolListUseCase as Any } diff --git a/Projects/Services/APIKit/Sources/DmsAPI.swift b/Projects/Services/APIKit/Sources/DmsAPI.swift index 1fc9be4b..09f14ddc 100644 --- a/Projects/Services/APIKit/Sources/DmsAPI.swift +++ b/Projects/Services/APIKit/Sources/DmsAPI.swift @@ -28,7 +28,7 @@ public enum DmsDomain: String { case losts case notices case meals - case images + case files case schools } diff --git a/Projects/Services/APIKit/Sources/FilesAPI.swift b/Projects/Services/APIKit/Sources/FilesAPI.swift new file mode 100644 index 00000000..eb2a6786 --- /dev/null +++ b/Projects/Services/APIKit/Sources/FilesAPI.swift @@ -0,0 +1,44 @@ +import Foundation +import ErrorModule +import Moya + +public enum FilesAPI { + case uploadFile(data: Data) +} + +extension FilesAPI: DmsAPI { + public var domain: DmsDomain { + .files + } + + public var urlPath: String { + return "" + } + + public var method: Moya.Method { + return .post + } + + public var task: Moya.Task { + switch self { + case let .uploadFile(data): + return .uploadMultipart([ + .init( + provider: .data(data), + name: "file" + ) + ]) + } + } + + public var jwtTokenType: JwtTokenType { + .none + } + + public var errorMap: [Int: DmsError] { + [ + 400: .badRequest, + 500: .internalServerError + ] + } +} diff --git a/Projects/Services/DataMappingModule/Sources/Files/Response/UploadFileResponseDTO.swift b/Projects/Services/DataMappingModule/Sources/Files/Response/UploadFileResponseDTO.swift new file mode 100644 index 00000000..c0dc08e8 --- /dev/null +++ b/Projects/Services/DataMappingModule/Sources/Files/Response/UploadFileResponseDTO.swift @@ -0,0 +1,9 @@ +import Foundation + +public struct UploadFileResponseDTO: Decodable { + public let fileURL: String + + enum CodingKeys: String, CodingKey { + case fileURL = "file_url" + } +} diff --git a/Projects/Services/DataModule/Sources/Files/Repositories/FilesRepositoryImpl.swift b/Projects/Services/DataModule/Sources/Files/Repositories/FilesRepositoryImpl.swift new file mode 100644 index 00000000..a5aa851b --- /dev/null +++ b/Projects/Services/DataModule/Sources/Files/Repositories/FilesRepositoryImpl.swift @@ -0,0 +1,17 @@ +import Combine +import DomainModule +import ErrorModule +import Foundation +import NetworkModule + +public struct FilesRepositoryImpl: FilesRepository { + private let remoteFilesDataSource: any RemoteFilesDataSource + + public init(remoteFilesDataSource: any RemoteFilesDataSource) { + self.remoteFilesDataSource = remoteFilesDataSource + } + + public func uploadFile(data: Data) -> AnyPublisher { + remoteFilesDataSource.uploadFile(data: data) + } +} diff --git a/Projects/Services/DataModule/Sources/Files/UseCases/UploadFileUseCaseImpl.swift b/Projects/Services/DataModule/Sources/Files/UseCases/UploadFileUseCaseImpl.swift new file mode 100644 index 00000000..838c0ea3 --- /dev/null +++ b/Projects/Services/DataModule/Sources/Files/UseCases/UploadFileUseCaseImpl.swift @@ -0,0 +1,16 @@ +import Combine +import DomainModule +import ErrorModule +import Foundation + +public struct UploadFileUseCaseImpl: UploadFileUseCase { + private let filesRepository: any FilesRepository + + public init(filesRepository: any FilesRepository) { + self.filesRepository = filesRepository + } + + public func execute(data: Data) -> AnyPublisher { + filesRepository.uploadFile(data: data) + } +} diff --git a/Projects/Services/DomainModule/Sources/Files/Repository/FilesRepository.swift b/Projects/Services/DomainModule/Sources/Files/Repository/FilesRepository.swift new file mode 100644 index 00000000..b6080fc6 --- /dev/null +++ b/Projects/Services/DomainModule/Sources/Files/Repository/FilesRepository.swift @@ -0,0 +1,7 @@ +import Combine +import ErrorModule +import Foundation + +public protocol FilesRepository { + func uploadFile(data: Data) -> AnyPublisher +} diff --git a/Projects/Services/DomainModule/Sources/Files/UseCases/UploadFileUseCase.swift b/Projects/Services/DomainModule/Sources/Files/UseCases/UploadFileUseCase.swift new file mode 100644 index 00000000..cad32304 --- /dev/null +++ b/Projects/Services/DomainModule/Sources/Files/UseCases/UploadFileUseCase.swift @@ -0,0 +1,7 @@ +import Combine +import ErrorModule +import Foundation + +public protocol UploadFileUseCase { + func execute(data: Data) -> AnyPublisher +} diff --git a/Projects/Services/NetworkModule/Sources/Files/Remote/Impl/RemoteFilesDataSourceImpl.swift b/Projects/Services/NetworkModule/Sources/Files/Remote/Impl/RemoteFilesDataSourceImpl.swift new file mode 100644 index 00000000..fe1b4409 --- /dev/null +++ b/Projects/Services/NetworkModule/Sources/Files/Remote/Impl/RemoteFilesDataSourceImpl.swift @@ -0,0 +1,13 @@ +import APIKit +import Combine +import DataMappingModule +import ErrorModule +import Foundation + +public final class RemoteFilesDataSourceImpl: BaseRemoteDataSource, RemoteFilesDataSource { + public func uploadFile(data: Data) -> AnyPublisher { + request(.uploadFile(data: data), dto: UploadFileResponseDTO.self) + .map(\.fileURL) + .eraseToAnyPublisher() + } +} diff --git a/Projects/Services/NetworkModule/Sources/Files/Remote/RemoteFilesDataSource.swift b/Projects/Services/NetworkModule/Sources/Files/Remote/RemoteFilesDataSource.swift new file mode 100644 index 00000000..34d7a401 --- /dev/null +++ b/Projects/Services/NetworkModule/Sources/Files/Remote/RemoteFilesDataSource.swift @@ -0,0 +1,8 @@ +import Combine +import DataMappingModule +import ErrorModule +import Foundation + +public protocol RemoteFilesDataSource { + func uploadFile(data: Data) -> AnyPublisher +} diff --git a/Projects/Services/NetworkModule/Sources/Files/Remote/Stub/RemoteFilesDataSourceStub.swift b/Projects/Services/NetworkModule/Sources/Files/Remote/Stub/RemoteFilesDataSourceStub.swift new file mode 100644 index 00000000..0f8d033d --- /dev/null +++ b/Projects/Services/NetworkModule/Sources/Files/Remote/Stub/RemoteFilesDataSourceStub.swift @@ -0,0 +1,14 @@ +import Combine +import DataMappingModule +import ErrorModule +import Foundation + +public struct RemoteFilesDataSourceStub: RemoteFilesDataSource { + public init() {} + + public func uploadFile(data: Data) -> AnyPublisher { + Just("https://avatars.githubusercontent.com/u/74440939?v=4") + .setFailureType(to: DmsError.self) + .eraseToAnyPublisher() + } +}