Skip to content
16 changes: 16 additions & 0 deletions FLINT/Data/Sources/DTO/Auth/LogoutRequestDTO.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// LogoutRequestDTO.swift
// Data
//
// Created by 소은 on 6/19/26.
//

import Foundation

public struct LogoutRequestDTO: Encodable {
public let refreshToken: String

public init(refreshToken: String) {
self.refreshToken = refreshToken
}
}
14 changes: 14 additions & 0 deletions FLINT/Data/Sources/DTO/Auth/WithdrawRequestDTO.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// WithdrawRequestDTO.swift
// Data
//

import Foundation

public struct WithdrawRequestDTO: Encodable {
public let agreedTermsIds: [String]

public init(agreedTermsIds: [String]) {
self.agreedTermsIds = agreedTermsIds
}
}
16 changes: 16 additions & 0 deletions FLINT/Data/Sources/DTO/Collection/ReportRequestDTO.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// ReportRequestDTO.swift
// Data
//

import Foundation

public struct ReportRequestDTO: Encodable {
public let reasons: [String]
public let otherDetail: String?

public init(reasons: [String], otherDetail: String?) {
self.reasons = reasons
self.otherDetail = otherDetail
}
}
14 changes: 10 additions & 4 deletions FLINT/Data/Sources/Networking/API/AuthAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,22 @@ import Moya
import DTO

public enum AuthAPI {
case logout
case logout(refreshToken: String)
case logoutAll
case refresh
case signup(userInfo: SignupRequestDTO)
case socialVerify(socialAuthCredential: SocialVerifyRequestDTO)
case withdraw
case withdraw(agreedTermsIds: [String])
}

extension AuthAPI: TargetType {
public var path: String {
switch self {
case .signup:
return "/api/v1/auth/signup"
case .logout, .logoutAll, .refresh:
case .logout:
return "/api/v1/auth/logout"
case .logoutAll, .refresh:
#warning("TODO: - 나중에 구현할 것")
return "TODO"
case .socialVerify:
Expand All @@ -50,8 +52,12 @@ extension AuthAPI: TargetType {
return .requestJSONEncodable(userInfo)
case let .socialVerify(socialAuthCredential):
return .requestJSONEncodable(socialAuthCredential)
case .logout, .logoutAll, .refresh, .withdraw:
case let .logout(refreshToken):
return .requestJSONEncodable(LogoutRequestDTO(refreshToken: refreshToken))
case .logoutAll, .refresh:
return .requestPlain
case let .withdraw(agreedTermsIds):
return .requestJSONEncodable(WithdrawRequestDTO(agreedTermsIds: agreedTermsIds))
}
}
}
17 changes: 9 additions & 8 deletions FLINT/Data/Sources/Networking/API/CollectionAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Foundation
import Moya

import Domain
import DTO

public enum CollectionAPI {
case fetchCollections(cursor: Int64?, size: Int32)
Expand All @@ -18,6 +19,7 @@ public enum CollectionAPI {
case deleteCollection(collectionId: Int64)
case fetchCollectionDetail(collectionId: Int64)
case fetchRecentViewedCollections
case reportCollection(collectionId: Int64, reasons: [String], otherDetail: String?)
}

extension CollectionAPI: TargetType {
Expand All @@ -33,14 +35,16 @@ extension CollectionAPI: TargetType {
return "/api/v1/collections/\(collectionId)"
case .fetchRecentViewedCollections:
return "/api/v1/collections/recent"
case let .reportCollection(collectionId, _, _):
return "/api/v1/collections/\(collectionId)/reports"
}
}

public var method: Moya.Method {
switch self {
case .fetchCollections, .fetchCollectionDetail, .fetchRecentViewedCollections:
return .get
case .createCollection:
case .createCollection, .reportCollection:
return .post
case .updateCollection:
return .put
Expand All @@ -52,22 +56,19 @@ extension CollectionAPI: TargetType {
public var task: Moya.Task {
switch self {
case let .fetchCollections(cursor, size):
var parameters: [String: Any] = [
"size": size,
]
var parameters: [String: Any] = ["size": size]
if let cursor {
parameters["cursor"] = cursor
}
return .requestParameters(
parameters: parameters,
encoding: URLEncoding.queryString
)
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case let .createCollection(collectionInfo):
return .requestJSONEncodable(collectionInfo)
case let .updateCollection(_, collectionInfo):
return .requestJSONEncodable(collectionInfo)
case .deleteCollection, .fetchCollectionDetail, .fetchRecentViewedCollections:
return .requestPlain
case let .reportCollection(_, reasons, otherDetail):
return .requestJSONEncodable(ReportRequestDTO(reasons: reasons, otherDetail: otherDetail))
}
}
}
25 changes: 20 additions & 5 deletions FLINT/Data/Sources/Networking/Service/AuthService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import DTO
public protocol AuthService {
func signup(userInfo: SignupInfoEntity) -> AnyPublisher<SignupDTO, Error>
func socialVerify(socialAuthCredential: SocialVerifyRequestDTO) -> AnyPublisher<SocialVerifyResponseDTO, Error>
func withDraw() -> AnyPublisher<Void, Error>
func logout() -> AnyPublisher<Void, Error>
func withDraw(agreedTermsIds: [String]) -> AnyPublisher<Void, Error>
}

public final class DefaultAuthService: AuthService {
Expand Down Expand Up @@ -67,10 +68,24 @@ public final class DefaultAuthService: AuthService {
.eraseToAnyPublisher()
}

public func withDraw() -> AnyPublisher<Void, Error> {
authAPIProvider.requestPublisher(.withdraw)
.mapBaseResponseData(BlankData.self)
.map({ _ in })
public func logout() -> AnyPublisher<Void, Error> {
guard let refreshToken = tokenStorage.load(type: .refreshToken) else {
return Fail(error: TokenError.noToken).eraseToAnyPublisher()
}
return authAPIProvider.requestPublisher(.logout(refreshToken: refreshToken))
.logged()
.tryMap { [weak self] response in
guard (200..<300).contains(response.statusCode) else {
throw MoyaError.statusCode(response)
}
self?.tokenStorage.clearAll()
}
.eraseToAnyPublisher()
}

public func withDraw(agreedTermsIds: [String]) -> AnyPublisher<Void, Error> {
return authAPIProvider.requestPublisher(.withdraw(agreedTermsIds: agreedTermsIds))
.logged()
.mapBaseResponseEmpty()
}
}
8 changes: 8 additions & 0 deletions FLINT/Data/Sources/Networking/Service/CollectionService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public protocol CollectionService {
func deleteCollection(collectionId: Int64) -> AnyPublisher<Void, Error>
func fetchCollectionDetail(collectionId: Int64) -> AnyPublisher<CollectionDetailDTO, Error>
func fetchRecentViewedCollections() -> AnyPublisher<CollectionsDTO, Error>
func reportCollection(collectionId: Int64, reasons: [String], otherDetail: String?) -> AnyPublisher<Void, Error>
}

public final class DefaultCollectionService: CollectionService {
Expand Down Expand Up @@ -60,4 +61,11 @@ public final class DefaultCollectionService: CollectionService {
return collectionAPIProvider.requestPublisher(.fetchRecentViewedCollections)
.mapBaseResponseData(CollectionsDTO.self)
}

public func reportCollection(collectionId: Int64, reasons: [String], otherDetail: String?) -> AnyPublisher<Void, Error> {
return collectionAPIProvider.requestPublisher(.reportCollection(collectionId: collectionId, reasons: reasons, otherDetail: otherDetail))
.mapBaseResponseData(BlankData.self)
.map { _ in }
.eraseToAnyPublisher()
}
}
8 changes: 6 additions & 2 deletions FLINT/Data/Sources/RepositoryImpl/AuthRepositoryImpl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ public final class DefaultAuthRepository: AuthRepository {
.eraseToAnyPublisher()
}

public func withDraw() -> AnyPublisher<Void, Error> {
return authService.withDraw()
public func logout() -> AnyPublisher<Void, Error> {
return authService.logout()
}

public func withDraw(agreedTermsIds: [String]) -> AnyPublisher<Void, Error> {
return authService.withDraw(agreedTermsIds: agreedTermsIds)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,8 @@ public final class DefaultCollectionRepository: CollectionRepository {
.tryMap { try $0.entities }
.eraseToAnyPublisher()
}

public func reportCollection(collectionId: Int64, reasons: [String], otherDetail: String?) -> AnyPublisher<Void, Error> {
return collectionService.reportCollection(collectionId: collectionId, reasons: reasons, otherDetail: otherDetail)
}
}
3 changes: 2 additions & 1 deletion FLINT/Domain/Sources/Repository/AuthRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ import Entity
public protocol AuthRepository {
func signup(userInfo: SignupInfoEntity) -> AnyPublisher<String, Error>
func socialVerify(socialAuthCredential: SocialVerifyEntity) -> AnyPublisher<SocialVerifyResultEntity, Error>
func withDraw() -> AnyPublisher<Void, Error>
func logout() -> AnyPublisher<Void, Error>
func withDraw(agreedTermsIds: [String]) -> AnyPublisher<Void, Error>
}
1 change: 1 addition & 0 deletions FLINT/Domain/Sources/Repository/CollectionRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ public protocol CollectionRepository {
func deleteCollection(collectionId: Int64) -> AnyPublisher<Void, Error>
func fetchCollectionDetail(collectionId: Int64) -> AnyPublisher<CollectionDetailEntity, Error>
func fetchRecentViewedCollections() -> AnyPublisher<[CollectionEntity], Error>
func reportCollection(collectionId: Int64, reasons: [String], otherDetail: String?) -> AnyPublisher<Void, Error>
}
28 changes: 28 additions & 0 deletions FLINT/Domain/Sources/UseCase/Auth/LogoutUseCase.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// LogoutUseCase.swift
// Domain
//
// Created by 소은 on 6/19/26.
//

import Combine
import Foundation

import Repository

public protocol LogoutUseCase {
func callAsFunction() -> AnyPublisher<Void, Error>
}

public final class DefaultLogoutUseCase: LogoutUseCase {

private let authRepository: AuthRepository

public init(authRepository: AuthRepository) {
self.authRepository = authRepository
}

public func callAsFunction() -> AnyPublisher<Void, Error> {
return authRepository.logout()
}
}
6 changes: 3 additions & 3 deletions FLINT/Domain/Sources/UseCase/Auth/WithDrawUseCase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import Entity
import Repository

public protocol WithDrawUseCase {
func callAsFunction() -> AnyPublisher<Void, Error>
func callAsFunction(agreedTermsIds: [String]) -> AnyPublisher<Void, Error>
}

public final class DefaultWithDrawUseCase: WithDrawUseCase {
Expand All @@ -23,7 +23,7 @@ public final class DefaultWithDrawUseCase: WithDrawUseCase {
self.authRepository = authRepository
}

public func callAsFunction() -> AnyPublisher<Void, Error> {
return authRepository.withDraw()
public func callAsFunction(agreedTermsIds: [String]) -> AnyPublisher<Void, Error> {
return authRepository.withDraw(agreedTermsIds: agreedTermsIds)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// ReportCollectionUseCase.swift
// Domain
//
// Created by 소은 on 6/21/26.
//

import Combine
import Foundation

import Repository

public protocol ReportCollectionUseCase {
func callAsFunction(collectionId: Int64, reasons: [String], otherDetail: String?) -> AnyPublisher<Void, Error>
}

public final class DefaultReportCollectionUseCase: ReportCollectionUseCase {

private let collectionRepository: CollectionRepository

public init(collectionRepository: CollectionRepository) {
self.collectionRepository = collectionRepository
}

public func callAsFunction(collectionId: Int64, reasons: [String], otherDetail: String?) -> AnyPublisher<Void, Error> {
return collectionRepository.reportCollection(collectionId: collectionId, reasons: reasons, otherDetail: otherDetail)
}
}
3 changes: 3 additions & 0 deletions FLINT/FLINT/Dependency/DIContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ typealias DependencyFactory = ViewControllerFactory &
FetchOTTPlatformsForContentUseCaseFactory &
ExploreViewModelFactory &
ProfileViewModelFactory &

SettingViewModelFactory &
WithdrawViewModelFactory &

CreateCollectionViewModelFactory &
AddContentSelectViewModelFactory &
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// LogoutUseCaseFactory..swift
// FLINT
//
// Created by 소은 on 6/19/26.
//

import Foundation

import Domain

protocol LogoutUseCaseFactory: AuthRepositoryFactory {
func makeLogoutUseCase() -> LogoutUseCase
}

extension LogoutUseCaseFactory {
func makeLogoutUseCase() -> LogoutUseCase {
return DefaultLogoutUseCase(authRepository: makeAuthRepository())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// ReportCollectionUseCaseFactory.swift
// FLINT
//
// Created by 소은 on 6/21/26.
//

import Foundation

import Domain

protocol ReportCollectionUseCaseFactory: CollectionRepositoryFactory {
func makeReportCollectionUseCase() -> ReportCollectionUseCase
}

extension ReportCollectionUseCaseFactory {
func makeReportCollectionUseCase() -> ReportCollectionUseCase {
return DefaultReportCollectionUseCase(collectionRepository: makeCollectionRepository())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// ReportViewControllerFactory+.swift
// FLINT
//

import Foundation

import Presentation

extension ReportViewControllerFactory where Self: ReportViewModelFactory & ViewControllerFactory {
func makeReportViewController(collectionId: Int64) -> ReportViewController {
return ReportViewController(
viewModel: makeReportViewModel(collectionId: collectionId),
viewControllerFactory: self
)
}
}
Loading