Skip to content
This repository has been archived by the owner on Dec 7, 2024. It is now read-only.

Commit

Permalink
πŸ› :: [#198] 좩돌 ν•΄κ²°
Browse files Browse the repository at this point in the history
  • Loading branch information
shwaaaa committed Apr 6, 2024
2 parents 1763921 + 1ca9c70 commit c9a5c78
Show file tree
Hide file tree
Showing 23 changed files with 438 additions and 7 deletions.
4 changes: 4 additions & 0 deletions Service/Sources/DI/DataSourceAssembly.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,9 @@ public final class DataSourceAssembly: Assembly {
container.register(UserRemoteProtocol.self) { r in
UserRemote(keychainLocal: r.resolve(KeychainLocalProtocol.self)!)
}

container.register(ClubAttendRemoteProtocol.self) { r in
ClubAttendRemote(keychainLocal: r.resolve(KeychainLocalProtocol.self)!)
}
}
}
3 changes: 3 additions & 0 deletions Service/Sources/DI/RepositoryAssembly.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,8 @@ public final class RepositoryAssembly: Assembly {
container.register(ClubMemberRepository.self) { r in
DefaultClubMemberRepository(clubMemberRemote: r.resolve(ClubMemberRemoteProtocol.self)!)
}
container.register(ClubAttendRepository.self) { r in
DefaultClubAttendRepository(clubAttendRemote: r.resolve(ClubAttendRemoteProtocol.self)!)
}
}
}
20 changes: 20 additions & 0 deletions Service/Sources/DI/UseCaseAssembly.swift
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,26 @@ public final class UseCaseAssembly: Assembly {
clubMemberRepository: r.resolve(ClubMemberRepository.self)!
)
}
container.register(FetchClubAttendListUseCase.self) { r in
FetchClubAttendListUseCase(
clubAttendRepository: r.resolve(ClubAttendRepository.self)!
)
}
container.register(CreateAttendanceUseCase.self) { r in
CreateAttendanceUseCase(
clubAttendRepository: r.resolve(ClubAttendRepository.self)!
)
}
container.register(ChangeAllAttendStatusUseCase.self) { r in
ChangeAllAttendStatusUseCase(
clubAttendRepository: r.resolve(ClubAttendRepository.self)!
)
}
container.register(StatusAllApplyUseCase.self) { r in
StatusAllApplyUseCase(
clubAttendRepository: r.resolve(ClubAttendRepository.self)!
)
}

// MARK: - User
container.register(FetchProfileUseCase.self) { r in
Expand Down
97 changes: 97 additions & 0 deletions Service/Sources/Data/DataSource/Remote/API/ClubAttendAPI.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import Moya
import Foundation

enum ClubAttendAPI {
case fetchAttendList(clubID: Int, date: String?, period: Period?)
case createAttendance(clubID: Int, name: String, date: String, period: [Period])
case changeAllAttendStatus(attendanceID: String, attendanceStatus: AttendanceStatus)
case statusAllApply(attendanceIDs: [String], attendanceStatus: AttendanceStatus)
}

extension ClubAttendAPI: GCMSAPI {
var domain: GCMSDomain {
return .attend
}

var urlPath: String {
switch self {
case let .fetchAttendList(clubID, _, _):
return "/\(clubID)"

case let .createAttendance(clubID, _, _, _):
return "/\(clubID)/club"

case .changeAllAttendStatus(_, _):
return ""

case .statusAllApply(_, _):
return "/batch"
}
}

var method: Moya.Method {
switch self {
case .fetchAttendList:
return .get

case .changeAllAttendStatus, .statusAllApply:
return .patch

case .createAttendance:
return .post
}
}

var task: Task {
switch self {
case let .fetchAttendList(_, date, period):
return .requestParameters(parameters: [
"date": date,
"period": period
], encoding: URLEncoding.queryString)

case let .createAttendance(_, name, date, period):
return .requestPlain

case .changeAllAttendStatus(_, _):
return .requestPlain

case .statusAllApply(_, _):
return .requestPlain
}
}

var jwtTokenType: JWTTokenType? {
switch self {
default:
return .accessToken
}
}

typealias ErrorType = ClubAttendError
var errorMapper: [Int: ClubAttendError]? {
switch self {
case .fetchAttendList:
return [
401: .unauthorized,
403: .notClubMember,
404: .notFoundClub,
500: .serverError
]

case .statusAllApply:
return [
401: .unauthorized,
403: .notClubHeadOrClubTeacher,
404: .notFoundClub,
500: .serverError
]

case .createAttendance:
return [:]

case .changeAllAttendStatus:
return [:]
}
}
}
1 change: 1 addition & 0 deletions Service/Sources/Data/DataSource/Remote/API/GCMSAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ enum GCMSDomain: String {
case club
case clubMember = "club-member"
case applicant
case attend
}

extension GCMSDomain {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import Foundation

public struct FetchClubAttendListResponse: Decodable {
let date: String?
let period: String?
let users: [UsersResponse]

public struct UsersResponse: Decodable {
public let uuid: UUID
public let attendanceID: String
public let name: String
public let grade: Int
public let classNum: Int
public let number: Int
public let attendanceStatus: AttendanceStatus

enum CodingKeys: String, CodingKey, Decodable {
case uuid
case attendanceID = "attendanceId"
case name
case grade
case classNum
case number
case attendanceStatus
}
}
}

extension FetchClubAttendListResponse.UsersResponse {
func toDomain() -> ClubAttend {
ClubAttend(
uuid: uuid,
attendanceID: attendanceID,
name: name,
grade: grade,
classNum: classNum,
number: number,
attendanceStatus: attendanceStatus
)
}
}

extension FetchClubAttendListResponse {
func toDomain() -> [ClubAttend] {
self.users.map { $0.toDomain() }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import RxSwift
import Foundation

protocol ClubAttendRemoteProtocol {
func fetchAttendList(clubID: Int, date: String?, period: Period?) -> Single<[ClubAttend]>
func createAttendance(clubID: Int, name: String, date: String, period: [Period]) -> Completable
func changeAllAttendStatus(attendanceID: String, attendanceStatus: AttendanceStatus) -> Completable
func statusAllApply(attendanceIDs: [String], attendanceStatus: AttendanceStatus) -> Completable
}

final class ClubAttendRemote: BaseRemote<ClubAttendAPI>, ClubAttendRemoteProtocol {
func fetchAttendList(clubID: Int, date: String?, period: Period?) -> Single<[ClubAttend]> {
self.request(.fetchAttendList(clubID: clubID, date: date, period: period))
.map(FetchClubAttendListResponse.self)
.map { $0.toDomain() }
}

func createAttendance(clubID: Int, name: String, date: String, period: [Period]) -> Completable {
self.request(.createAttendance(clubID: clubID, name: name, date: date, period: period))
.asCompletable()
}

func changeAllAttendStatus(attendanceID: String, attendanceStatus: AttendanceStatus) -> Completable {
self.request(.changeAllAttendStatus(attendanceID: attendanceID, attendanceStatus: attendanceStatus))
.asCompletable()
}

func statusAllApply(attendanceIDs: [String], attendanceStatus: AttendanceStatus) -> Completable {
self.request(.statusAllApply(attendanceIDs: attendanceIDs, attendanceStatus: attendanceStatus))
.asCompletable()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import Foundation
import RxSwift

final class DefaultClubAttendRepository: ClubAttendRepository {
private let clubAttendRemote: any ClubAttendRemoteProtocol

init(clubAttendRemote: any ClubAttendRemoteProtocol) {
self.clubAttendRemote = clubAttendRemote
}

func fetchAttendList(clubID: Int, date: String?, period: Period?) -> Single<[ClubAttend]> {
clubAttendRemote.fetchAttendList(clubID: clubID, date: date, period: period)
}

func createAttendance(clubID: Int, name: String, date: String, period: [Period]) -> Completable {
clubAttendRemote.createAttendance(clubID: clubID, name: name, date: date, period: period)
}

func changeAllAttendStatus(attendanceID: String, attendanceStatus: AttendanceStatus) -> Completable {
clubAttendRemote.changeAllAttendStatus(attendanceID: attendanceID, attendanceStatus: attendanceStatus)
}

func statusAllApply(attendanceIDs: [String], attendanceStatus: AttendanceStatus) -> Completable {
clubAttendRemote.statusAllApply(attendanceIDs: attendanceIDs, attendanceStatus: attendanceStatus)
}
}
29 changes: 29 additions & 0 deletions Service/Sources/Domain/Entities/ClubAttend.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import Foundation

public struct ClubAttend: Equatable {
public let uuid: UUID
public let attendanceID: String
public let name: String
public let grade: Int
public let classNum: Int
public let number: Int
public let attendanceStatus: AttendanceStatus

public init(
uuid: UUID,
attendanceID: String,
name: String,
grade: Int,
classNum: Int,
number: Int,
attendanceStatus: AttendanceStatus
) {
self.uuid = uuid
self.attendanceID = attendanceID
self.name = name
self.grade = grade
self.classNum = classNum
self.number = number
self.attendanceStatus = attendanceStatus
}
}
5 changes: 4 additions & 1 deletion Service/Sources/Domain/Entities/MiniProfile.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ public struct MiniProfile: Equatable {
public let name: String
public let profileImg: String

public init(name: String, profileImg: String) {
public init(
name: String,
profileImg: String
) {
self.name = name
self.profileImg = profileImg
}
Expand Down
10 changes: 9 additions & 1 deletion Service/Sources/Domain/Entities/User.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import Foundation

public struct User: Equatable {
public init(uuid: UUID, email: String, name: String, grade: Int, classNum: Int, number: Int, profileImg: String?) {
public init(
uuid: UUID,
email: String,
name: String,
grade: Int,
classNum: Int,
number: Int,
profileImg: String?
) {
self.uuid = uuid
self.email = email
self.name = name
Expand Down
11 changes: 10 additions & 1 deletion Service/Sources/Domain/Entities/UserProfile.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import Foundation

public struct UserProfile: Equatable {
public init(uuid: UUID, email: String, name: String, grade: Int, classNum: Int, number: Int, profileImg: String?, clubs: [ClubList]) {
public init(
uuid: UUID,
email: String,
name: String,
grade: Int,
classNum: Int,
number: Int,
profileImg: String?,
clubs: [ClubList]
) {
self.uuid = uuid
self.email = email
self.name = name
Expand Down
6 changes: 6 additions & 0 deletions Service/Sources/Domain/Enums/AttendanceStatus.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
public enum AttendanceStatus: String, Codable {
case attendance = "ATTENDANCE"
case late = "LATE"
case reasonableAbsent = "REASONABLE_ABSENT"
case absent = "ABSENT"
}
13 changes: 13 additions & 0 deletions Service/Sources/Domain/Enums/Period.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
public enum Period: String, Codable, CaseIterable {
case first = "FIRST"
case second = "SECOND"
case third = "THIRD"
case fourth = "FOURTH"
case fifth = "FIFTH"
case sixth = "SIXTH"
case seventh = "SEVENTH"
case eighth = "EIGHTH"
case ninth = "NINTH"
case tenth = "TENTH"
case eleventh = "ELEVENTH"
}
3 changes: 2 additions & 1 deletion Service/Sources/Domain/Error/ClubApplicantError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,15 @@ extension ClubApplicantError: LocalizedError {
switch self {
case let .error(message, _):
return message

case .notClubMember:
return "동아리 ꡬ성원이 μ•„λ‹ˆλ©΄ μ‚¬μš©ν•  수 μ—†μŠ΅λ‹ˆλ‹€."

case .bodyIsNull:
return "μš”μ²­μ΄ 잘λͺ»λ˜μ—ˆμŠ΅λ‹ˆλ‹€"

case .unauthorized, .serverError:
return "μ•Œμˆ˜μ—†λŠ” μ—λŸ¬κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€. μž μ‹œ ν›„ λ‹€μ‹œ μ‹œλ„ν•΄ μ£Όμ„Έμš”."
return "μ•Œ 수 μ—†λŠ” μ—λŸ¬κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€. μž μ‹œ ν›„ λ‹€μ‹œ μ‹œλ„ν•΄ μ£Όμ„Έμš”."

case .alreadyClubMemberOrSameTypeClub:
return "이미 같은 동아리 μ†Œμ†μ΄κ±°λ‚˜ 같은 νƒ€μž…μ˜ 동아리λ₯Ό 이미 μ‹ μ²­ν–ˆμŠ΅λ‹ˆλ‹€."
Expand Down
Loading

0 comments on commit c9a5c78

Please sign in to comment.