Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[team-07] Login - Home 화면 IssueCard 출력 흐름 구현 #267

Open
wants to merge 8 commits into
base: team-07
Choose a base branch
from
120 changes: 86 additions & 34 deletions iOS/IssueTracker/IssueTracker.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

53 changes: 42 additions & 11 deletions iOS/IssueTracker/IssueTracker/DataLayer/DTO/IssueCardDTO.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,48 @@

import Foundation

struct IssueCardDTO: Identifiable {
let id: Int
let title: String
let content: String
let isSelected: Bool
let mileStone: String?
let labels: [Label]
// MARK: - Empty
struct IssueCardArrayDTO: Codable {
let issues: [IssueCardDTO]
}
Comment on lines +11 to 13
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이런 네이밍에서는 Array와 같은 자료구조 이름을 직접 사용하기 보다는
복수형태로 사용해주는 게 더 자연스럽다는 생각입니다 :) (IssueCardsDTO)


struct Label: Identifiable {
let id: Int
let labelName: String
let labelColor: String
// MARK: - Issue
struct IssueCardDTO: Codable {
let issueID: Int
let title, content: String
let milestoneID: Int
let milestoneName: String
let labels: [LabelDTO]

enum CodingKeys: String, CodingKey {
case issueID = "issueId"
case title, content
case milestoneID = "milestoneId"
case milestoneName, labels
}
}

// MARK: - Label
struct LabelDTO: Codable {
let labelID: Int?
let labelName, labelColor: String

enum CodingKeys: String, CodingKey {
case labelID = "labelId"
case labelName, labelColor
}
}

extension IssueCardDTO {

func toDomain() -> IssueCardEntity {
return .init(id: issueID, title: title, content: content, isSelected: false, mileStone: milestoneName, labels: labels.map { $0.toDomain() })
}
}

extension LabelDTO {

func toDomain() -> LabelEntity {
return .init(id: labelID, labelName: labelName, labelColor: labelColor)
}
}
Comment on lines +42 to 54
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사소한 부분이긴 하지만 extension 작성 시엔
작성하는 타입의 선언부와 최대한 가까운 위치에 작성하면 더 직관적입니다 :)
그리고 아무래도 스코프가 달라지기 때문에, 사실 개수가 몇 개 안 되고 이 정도로 간단한 메소드들은 굳이 분리하지 않아도 될 수 있어요!
객체도 그렇고 뭐든지 분리하게 될 경우엔 나름의 장점도 있지만 복잡도와 트레이드오프가 발생한다는 점을 기억해주세요!

Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,12 @@ struct EndPoint: EndPointable, HTTPPackageable {
self.body = body
}

var queryItems: [URLQueryItem]? {
// TODO: Issue card 정보 불러올때 사용예정 [미구현]
return nil
}

var url: URL {
var components = URLComponents()
components.scheme = urlConfigure.scheme
components.host = urlConfigure.host
components.path = urlConfigure.path
components.queryItems = queryItems
components.queryItems = urlConfigure.queryItem
guard let url = components.url else {
preconditionFailure("Invalid URL components: \(components)"
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,5 @@
import Foundation

protocol EndPointable {
var queryItems: [URLQueryItem]? {get}
var url: URL {get}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// FetchIssueListURLConfiguration.swift
// IssueTracker
//
// Created by Kai Kim on 2022/06/30.
//

import Foundation

struct FetchOpenIssueListURLConfiguration: URLConfigurable {
var scheme: String = "https"
var host: String = "0e1f525b-4045-4a86-b2d7-b782850ccb9f.mock.pstmn.io"
var path: String = "/issue-tracker/api/issues"
Comment on lines +11 to +13
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이런 값들은 사실 상 변경될 일이 없지 않나요?
let으로 작성해도 될 것 같네요ㅎㅎ

var queryItem: [URLQueryItem]? = [URLQueryItem(name: "isOpened", value: "true")]
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
import Foundation

struct GitURLConfiguration: URLConfigurable {
var queryItem: [URLQueryItem]?
var path = "/login/code/github"
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
import Foundation

protocol URLConfigurable {
var scheme: String {get}
var host: String {get}
var path: String {get}
var queryItem: [URLQueryItem]? {get}
}

extension URLConfigurable {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
import Foundation

struct TokenURLConfiguration: URLConfigurable {
var queryItem: [URLQueryItem]?
var path: String = "/login/oauth/github"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// FetchIssueCardRepository.swift
// IssueTracker
//
// Created by Kai Kim on 2022/06/30.
//

import Foundation

final class ViewFilteredIssueCardRepository: ViewIssueCardRepository {

var endPoint: EndPoint

init(endPoint: EndPoint = EndPoint(urlConfigure: FetchOpenIssueListURLConfiguration(), method: .GET, body: nil)) {
self.endPoint = endPoint
}

func fetchIssueCard(completion: @escaping (IssueCardArrayDTO?) -> Void) {
NetworkService.request(endPoint: endPoint) { result in
switch result {
case .success(let data):
let decoder = Decoder<IssueCardArrayDTO>()
let issuecards = decoder.decode(data: data)
completion(issuecards)
case .failure(let error):
print(error)
}
}
}
Comment on lines +18 to +29
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이번 프로젝트의 Repository에서는 사실 상 데이터를 decode해주는 역할만 하고 있긴 하네요 :)
이 역할이 조금 아쉽지는 않으셨나요?
만약 Repository가 많은 쓸모를 가지려면 어떤 상황이 주어져야 할까요?
지금은 하나의 API를 통해 필요한 모든 걸 가지고 오지만, 만약 API가 여러개거나 또는 네트워크 서비스 이외의 곳 (로컬 저장소라든가)
에서 데이터를 가져올 수 있고 또 로컬과 리모트 데이터 간의 싱크업이 필요한 프로젝트라면 Repository가 훨씬 많은 역할을 할 수 있지 않을까 싶어요.


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// DefaultIssueCardRepository.swift
// IssueTracker
//
// Created by Kai Kim on 2022/06/30.
//

import Foundation

protocol ViewIssueCardRepository {
var endPoint: EndPoint {get}
func fetchIssueCard(completion: @escaping (IssueCardArrayDTO?) -> Void)
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@

import Foundation

final class UserInfoRepository: DefaultUserInfoRepository {
final class DefaultRequestTokenInfoRepository: RequestTokenInfoRepository {

var endPoint: EndPoint

init(endPoint: EndPoint) {
self.endPoint = endPoint
}

func fetchUserInfo(completion: @escaping (TokenInfo?) -> Void) {
func fetchTokenInfo(completion: @escaping (TokenInfo?) -> Void) {
NetworkService.request(endPoint: endPoint) { result in
switch result {
case .success(let data):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import Foundation

protocol DefaultUserInfoRepository {
protocol RequestTokenInfoRepository {
var endPoint: EndPoint {get}
func fetchUserInfo(completion: @escaping (TokenInfo?) -> Void)
func fetchTokenInfo(completion: @escaping (TokenInfo?) -> Void)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// IssueCardEntity.swift
// IssueTracker
//
// Created by Kai Kim on 2022/06/30.
//

import Foundation

struct IssueCardEntity: Identifiable {
let id: Int
let title: String
let content: String
let isSelected: Bool
let mileStone: String?
let labels: [LabelEntity]
}

struct LabelEntity: Identifiable {
let id: Int?
let labelName: String
let labelColor: String
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@

import AuthenticationServices

final class AppleAuthorizationUsecase: NSObject, DefaultLoginUsecase {
final class AppleLoginUsecase: NSObject, LoginUsecase {

// private(set) var endPoint: EndPoint
private var presentationAnchor: UIWindow?
private var authorizationController: ASAuthorizationController?
var requestUserInfoUsecase: DefaultRequestUserInfoUsecase?
var requestUserInfoUsecase: RequestTokenInfoUsecase?

init(presentationAnchor: UIWindow?) {
self.presentationAnchor = presentationAnchor
Expand All @@ -28,7 +28,7 @@ final class AppleAuthorizationUsecase: NSObject, DefaultLoginUsecase {

func setRequestUserInfo(_ grantResource: DefaultGrantResource) {
guard let resource = grantResource as? AppleGrantResource, let data = encodeModel(model: resource) else {return}
self.requestUserInfoUsecase = RequestUserInfoUsecase(userInfoRepository: UserInfoRepository(endPoint: EndPoint(urlConfigure: TokenURLConfiguration(), method: .POST, body: data)))
self.requestUserInfoUsecase = DefaultRequestTokenInfoUsecase(userInfoRepository: DefaultRequestTokenInfoRepository(endPoint: EndPoint(urlConfigure: TokenURLConfiguration(), method: .POST, body: data)))
}

func enquireForGrant(handler: @escaping (URL?) -> Void) {
Expand All @@ -38,7 +38,7 @@ final class AppleAuthorizationUsecase: NSObject, DefaultLoginUsecase {
}
}

private extension AppleAuthorizationUsecase {
private extension AppleLoginUsecase {

func prepareToRequest() {
let appleIDProvider = ASAuthorizationAppleIDProvider()
Expand All @@ -58,7 +58,7 @@ private extension AppleAuthorizationUsecase {

}

extension AppleAuthorizationUsecase: ASAuthorizationControllerDelegate {
extension AppleLoginUsecase: ASAuthorizationControllerDelegate {

func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
switch authorization.credential {
Expand All @@ -77,7 +77,7 @@ extension AppleAuthorizationUsecase: ASAuthorizationControllerDelegate {
}
}

extension AppleAuthorizationUsecase: ASAuthorizationControllerPresentationContextProviding {
extension AppleLoginUsecase: ASAuthorizationControllerPresentationContextProviding {

func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
guard let window = presentationAnchor else { return ASPresentationAnchor() }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@

import Foundation

final class GithubAuthorizationUsecase: DefaultLoginUsecase {
final class GithubLoginUsecase: LoginUsecase {

var requestUserInfoUsecase: DefaultRequestUserInfoUsecase?
var requestUserInfoUsecase: RequestTokenInfoUsecase?

func execute() {
NetworkService.requestURL(endPoint: EndPoint(urlConfigure: GitURLConfiguration(), method: .GET, body: nil)) { result in
Expand All @@ -24,29 +24,14 @@ final class GithubAuthorizationUsecase: DefaultLoginUsecase {

func setRequestUserInfo(_ grantResource: DefaultGrantResource) {
guard let resource = grantResource as? GitHubGrantResource, let data = encodeModel(model: resource) else {return}
self.requestUserInfoUsecase = RequestUserInfoUsecase(userInfoRepository: UserInfoRepository(endPoint: EndPoint(urlConfigure: TokenURLConfiguration(), method: .POST, body: data)))
self.requestUserInfoUsecase = DefaultRequestTokenInfoUsecase(userInfoRepository: DefaultRequestTokenInfoRepository(endPoint: EndPoint(urlConfigure: TokenURLConfiguration(), method: .POST, body: data)))
}
}

private extension GithubAuthorizationUsecase {
private extension GithubLoginUsecase {

func encodeModel(model: GitHubGrantResource) -> Data? {
let encoder = Encoder<GitHubGrantResource>()
return encoder.encode(model: model)
}

// func requestAPI(with endPoint: EndPoint) {
// self.responseHandler(true)
//// NetworkService.request(endPoint: endPoint, completion: { result in
//// switch result {
//// case .success(let data):
//// // TODO: Decode response data
//// print(data)
//// self.responseHandler?(true)
//// case .failure(let error):
//// print(error)
//// self.responseHandler?(false)
//// }
//// })
// }
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@

import Foundation

protocol DefaultLoginUsecase {
protocol LoginUsecase {

var requestUserInfoUsecase: DefaultRequestUserInfoUsecase? {get}
var requestUserInfoUsecase: RequestTokenInfoUsecase? {get}
func execute()
func setRequestUserInfo(_ grantResource: DefaultGrantResource)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// requestUserInfoUsecase.swift
// IssueTracker
//
// Created by Kai Kim on 2022/06/28.
//

import Foundation

final class DefaultRequestTokenInfoUsecase: RequestTokenInfoUsecase {

var tokenInfoRepository: RequestTokenInfoRepository?

init(userInfoRepository: RequestTokenInfoRepository? = DefaultRequestTokenInfoRepository(endPoint: EndPoint(urlConfigure: TokenURLConfiguration(), method: .POST, body: nil))) {
self.tokenInfoRepository = userInfoRepository
}

func execute(completion: @escaping (TokenInfo?) -> Void) {
tokenInfoRepository?.fetchTokenInfo(completion: { userInfo in
guard let userInfo = userInfo else {
completion(nil)
return
}
completion(userInfo)
})
Comment on lines +19 to +25
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

옵셔널을 전달할 수 있으니 guard문은 불필요해보이네요ㅎㅎ

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import Foundation

protocol DefaultRequestUserInfoUsecase {
var userInfoRepository: DefaultUserInfoRepository? {get}
protocol RequestTokenInfoUsecase {
var tokenInfoRepository: RequestTokenInfoRepository? {get}
func execute(completion: @escaping (TokenInfo?) -> Void)
}
Loading