Skip to content
This repository was archived by the owner on Mar 5, 2025. It is now read-only.

Commit b2cd611

Browse files
author
Leonard-happy
committed
인증 API, Issues API, Model (Issue, User) 추가.
1 parent 52b78ad commit b2cd611

File tree

12 files changed

+668
-0
lines changed

12 files changed

+668
-0
lines changed

.gitignore

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
2+
## OS X files
3+
.DS_Store
4+
.DS_Store?
5+
.Trashes
6+
.Spotlight-V100
7+
*.swp
8+
9+
## Xcode build files
10+
DerivedData/
11+
build/
12+
13+
## Xcode private settings
14+
*.pbxuser
15+
!default.pbxuser
16+
*.mode1v3
17+
!default.mode1v3
18+
*.mode2v3
19+
!default.mode2v3
20+
*.perspectivev3
21+
!default.perspectivev3
22+
23+
xcuserdata/
24+
25+
## Other
26+
*.xccheckout
27+
*.moved-aside
28+
*.xcuserstate
29+
*.xcscmblueprint
30+
31+
## Obj-C/Swift specific
32+
*.hmap
33+
*.ipa
34+
*.dSYM.zip
35+
*.dSYM
36+
37+
## Swift Package Manager
38+
.build/
39+
40+
Pods/
41+
Podfile.lock

GithubIssues.xcodeproj/project.pbxproj

Lines changed: 252 additions & 0 deletions
Large diffs are not rendered by default.

GithubIssues.xcodeproj/xcuserdata/leonard.xcuserdatad/xcschemes/GithubIssues.xcscheme

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,59 @@
55
<BuildAction
66
parallelizeBuildables = "YES"
77
buildImplicitDependencies = "YES">
8+
<BuildActionEntries>
9+
<BuildActionEntry
10+
buildForTesting = "YES"
11+
buildForRunning = "YES"
12+
buildForProfiling = "YES"
13+
buildForArchiving = "YES"
14+
buildForAnalyzing = "YES">
15+
<BuildableReference
16+
BuildableIdentifier = "primary"
17+
BlueprintIdentifier = "D7CE58D91F64118400380CEE"
18+
BuildableName = "GithubIssues.app"
19+
BlueprintName = "GithubIssues"
20+
ReferencedContainer = "container:GithubIssues.xcodeproj">
21+
</BuildableReference>
22+
</BuildActionEntry>
23+
</BuildActionEntries>
824
</BuildAction>
925
<TestAction
1026
buildConfiguration = "Debug"
1127
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
1228
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
1329
shouldUseLaunchSchemeArgsEnv = "YES">
1430
<Testables>
31+
<TestableReference
32+
skipped = "NO">
33+
<BuildableReference
34+
BuildableIdentifier = "primary"
35+
BlueprintIdentifier = "D7CE58ED1F64118400380CEE"
36+
BuildableName = "GithubIssuesTests.xctest"
37+
BlueprintName = "GithubIssuesTests"
38+
ReferencedContainer = "container:GithubIssues.xcodeproj">
39+
</BuildableReference>
40+
</TestableReference>
41+
<TestableReference
42+
skipped = "NO">
43+
<BuildableReference
44+
BuildableIdentifier = "primary"
45+
BlueprintIdentifier = "D7CE58F81F64118400380CEE"
46+
BuildableName = "GithubIssuesUITests.xctest"
47+
BlueprintName = "GithubIssuesUITests"
48+
ReferencedContainer = "container:GithubIssues.xcodeproj">
49+
</BuildableReference>
50+
</TestableReference>
1551
</Testables>
52+
<MacroExpansion>
53+
<BuildableReference
54+
BuildableIdentifier = "primary"
55+
BlueprintIdentifier = "D7CE58D91F64118400380CEE"
56+
BuildableName = "GithubIssues.app"
57+
BlueprintName = "GithubIssues"
58+
ReferencedContainer = "container:GithubIssues.xcodeproj">
59+
</BuildableReference>
60+
</MacroExpansion>
1661
<AdditionalOptions>
1762
</AdditionalOptions>
1863
</TestAction>
@@ -26,6 +71,16 @@
2671
debugDocumentVersioning = "YES"
2772
debugServiceExtension = "internal"
2873
allowLocationSimulation = "YES">
74+
<BuildableProductRunnable
75+
runnableDebuggingMode = "0">
76+
<BuildableReference
77+
BuildableIdentifier = "primary"
78+
BlueprintIdentifier = "D7CE58D91F64118400380CEE"
79+
BuildableName = "GithubIssues.app"
80+
BlueprintName = "GithubIssues"
81+
ReferencedContainer = "container:GithubIssues.xcodeproj">
82+
</BuildableReference>
83+
</BuildableProductRunnable>
2984
<AdditionalOptions>
3085
</AdditionalOptions>
3186
</LaunchAction>
@@ -35,6 +90,16 @@
3590
savedToolIdentifier = ""
3691
useCustomWorkingDirectory = "NO"
3792
debugDocumentVersioning = "YES">
93+
<BuildableProductRunnable
94+
runnableDebuggingMode = "0">
95+
<BuildableReference
96+
BuildableIdentifier = "primary"
97+
BlueprintIdentifier = "D7CE58D91F64118400380CEE"
98+
BuildableName = "GithubIssues.app"
99+
BlueprintName = "GithubIssues"
100+
ReferencedContainer = "container:GithubIssues.xcodeproj">
101+
</BuildableReference>
102+
</BuildableProductRunnable>
38103
</ProfileAction>
39104
<AnalyzeAction
40105
buildConfiguration = "Debug">

GithubIssues.xcworkspace/contents.xcworkspacedata

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

GithubIssues/API.swift

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//
2+
// API.swift
3+
// GithubIssues
4+
//
5+
// Created by Leonard on 2017. 9. 10..
6+
// Copyright © 2017년 intmain. All rights reserved.
7+
//
8+
9+
import Foundation
10+
import Alamofire
11+
import SwiftyJSON
12+
13+
14+
struct API {
15+
static func getOauthKey(user: String, password: String, completionHandler: @escaping (DataResponse<JSON>) -> Void) {
16+
var headers: HTTPHeaders = [:]
17+
if let authorizationHeader = Request.authorizationHeader(user: user, password: password) {
18+
headers[authorizationHeader.key] = authorizationHeader.value
19+
}
20+
let parameters: Parameters = ["client_secret": Router.clientSecret , "scopes": ["public_repo"], "note": "admin script" ]
21+
Alamofire.request(Router.authKey(parameters, headers))
22+
.responseSwiftyJSON { json in
23+
print(json)
24+
completionHandler(json)
25+
}
26+
}
27+
28+
static func repoIssues(owner: String, repo: String, completionHandler: @escaping (DataResponse<[Model.Issue]>) -> Void) {
29+
Alamofire.request(Router.repoIssues(owner: owner, repo: repo)).responseSwiftyJSON { (dataResponse: DataResponse<JSON>) in
30+
let result = dataResponse.map({ (json: JSON) -> [Model.Issue] in
31+
return json.arrayValue.map{
32+
Model.Issue(json: $0)
33+
}
34+
})
35+
completionHandler(result)
36+
}
37+
}
38+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//
2+
// DataRequest+extension.swift
3+
// GithubIssues
4+
//
5+
// Created by Leonard on 2017. 9. 10..
6+
// Copyright © 2017년 intmain. All rights reserved.
7+
//
8+
9+
import Foundation
10+
import Alamofire
11+
import SwiftyJSON
12+
13+
enum BackendError: Error {
14+
case network(error: Error)
15+
case dataSerialization(reason: String)
16+
case jsonSerialization(error: Error)
17+
case objectSerialization(reason: String)
18+
case xmlSerialization(error: Error)
19+
}
20+
21+
extension DataRequest {
22+
@discardableResult
23+
public func responseSwiftyJSON(_ completionHandler: @escaping (DataResponse<JSON>) -> Void) -> Self {
24+
let responseSerializer = DataResponseSerializer<JSON> { request, response, data, error in
25+
guard error == nil else {
26+
DataRequest.errorMessage(response, error: error, data: data)
27+
return .failure(error!)
28+
}
29+
30+
let result = DataRequest
31+
.jsonResponseSerializer(options: .allowFragments)
32+
.serializeResponse(request, response, data, error)
33+
34+
switch result {
35+
case .success(let value):
36+
if let _ = response {
37+
return .success(JSON(value))
38+
} else {
39+
let failureReason = "JSON could not be serialized into response object: \(value)"
40+
let error = BackendError.objectSerialization(reason: failureReason)
41+
DataRequest.errorMessage(response, error: error, data: data)
42+
return .failure(error)
43+
}
44+
case .failure(let error):
45+
DataRequest.errorMessage(response, error: error, data: data)
46+
return .failure(error)
47+
}
48+
}
49+
return response(responseSerializer: responseSerializer, completionHandler: completionHandler)
50+
}
51+
52+
static func errorMessage(_ response: HTTPURLResponse?, error: Error?, data: Data?) {
53+
debugPrint("status: \(response?.statusCode ?? -1), error message:\(error.debugDescription)")
54+
}
55+
}

GithubIssues/Issue.swift

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//
2+
// Issue.swift
3+
// GithubIssues
4+
//
5+
// Created by Leonard on 2017. 9. 10..
6+
// Copyright © 2017년 intmain. All rights reserved.
7+
//
8+
9+
import Foundation
10+
import SwiftyJSON
11+
12+
extension Model {
13+
public struct Issue {
14+
let id: Int
15+
let number: Int
16+
let title: String
17+
let user: Model.User
18+
let state: State
19+
let comments: Int
20+
let body: String
21+
let createdAt: Date?
22+
let updatedAt: Date?
23+
let closedAt: Date?
24+
25+
public init(json: JSON) {
26+
id = json["id"].intValue
27+
number = json["number"].intValue
28+
title = json["title"].stringValue
29+
user = Model.User(json: json["user"])
30+
state = State(rawValue: json["state"].stringValue) ?? .none
31+
comments = json["comments"].intValue
32+
body = json["body"].stringValue
33+
34+
let format = DateFormatter()
35+
format.dateFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'"
36+
createdAt = format.date(from: json["created_at"].stringValue)
37+
updatedAt = format.date(from: json["updated_at"].stringValue)
38+
closedAt = format.date(from: json["closed_at"].stringValue)
39+
}
40+
}
41+
}
42+
43+
extension Model.Issue {
44+
enum State: String {
45+
case open = "open", close = "close", none = "none"
46+
47+
var display: String {
48+
switch self {
49+
case .open: return "opened"
50+
case .close: return "closed"
51+
default: return "-"
52+
}
53+
}
54+
}
55+
}
56+
57+
58+
extension Model.Issue: Equatable {
59+
public static func ==(lhs: Model.Issue, rhs: Model.Issue) -> Bool {
60+
return lhs.id == rhs.id
61+
}
62+
}

GithubIssues/Model.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//
2+
// Model.swift
3+
// GithubIssues
4+
//
5+
// Created by Leonard on 2017. 9. 10..
6+
// Copyright © 2017년 intmain. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
public struct Model {
12+
13+
}

GithubIssues/Router.swift

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
//
2+
// Router.swift
3+
// GithubIssues
4+
//
5+
// Created by Leonard on 2017. 9. 9..
6+
// Copyright © 2017년 intmain. All rights reserved.
7+
//
8+
9+
import Foundation
10+
import Alamofire
11+
import SwiftyJSON
12+
13+
enum Router {
14+
case authKey(Parameters, HTTPHeaders)
15+
case repoIssues(owner: String, repo: String)
16+
17+
}
18+
19+
extension Router: URLRequestConvertible {
20+
21+
static let baseURLString = "https://api.github.com"
22+
static let clientID = "36c48adc3d1433fbd286"
23+
static let clientSecret = "a911bfd178a79f25d14c858a1199cd76d9e92f3b"
24+
25+
var method: HTTPMethod {
26+
switch self {
27+
case .authKey:
28+
return .put
29+
case .repoIssues:
30+
return .get
31+
}
32+
}
33+
34+
var path: String {
35+
switch self {
36+
case .authKey:
37+
return "/authorizations/clients/\(Router.clientID)/\(Date().timeIntervalSince1970)"
38+
case let .repoIssues(owner, repo):
39+
return "/repos/\(owner)/\(repo)/issues"
40+
}
41+
}
42+
43+
func asURLRequest() throws -> URLRequest {
44+
let url = try Router.baseURLString.asURL()
45+
46+
var urlRequest = URLRequest(url: url.appendingPathComponent(path))
47+
urlRequest.httpMethod = method.rawValue
48+
if let token = UserDefaults.standard.string(forKey: "token") {
49+
urlRequest.setValue("token \(token)", forHTTPHeaderField: "Authorization")
50+
}
51+
52+
switch self {
53+
case let .authKey(parameters, headers):
54+
headers.forEach{ (key, value) in urlRequest.addValue(value, forHTTPHeaderField: key) }
55+
urlRequest = try JSONEncoding.default.encode(urlRequest, with: parameters)
56+
// urlRequest = try URLEncoding.default.encode(urlRequest, with: parameters)
57+
case let .repoIssues(_, _):
58+
urlRequest = try URLEncoding.default.encode(urlRequest, with: nil)
59+
}
60+
61+
return urlRequest
62+
}
63+
}
64+
65+
66+

0 commit comments

Comments
 (0)