Skip to content

Commit 8c7abc5

Browse files
committed
Change StudyplusError
1 parent d3d90b8 commit 8c7abc5

File tree

4 files changed

+67
-180
lines changed

4 files changed

+67
-180
lines changed

Lib/StudyplusSDK/Studyplus.swift

Lines changed: 19 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import UIKit
2929
/**
3030
The class for using Studyplus.
3131
For example, you can authenticate in Studyplus account, de-authentication, and post study record.
32-
32+
3333
Studyplusの各機能を使うためのクラスです。
3434
Studyplusアカウントとの連携、連携解除、勉強記録の投稿ができます。
3535
*/
@@ -151,29 +151,21 @@ final public class Studyplus {
151151

152152
/// Studyplusに学習記録を投稿
153153
///
154-
/// - Parameter
155-
/// - studyRecord: 学習記録
156-
/// - success: 投稿成功時のコールバック
157-
/// - failure: 投稿失敗時のコールバック
158-
public func post(_ record: StudyplusRecord,
159-
success: @escaping () -> Void,
160-
failure: @escaping (_ error: StudyplusError) -> Void) {
161-
guard record.isValidDuration else {
162-
// TODO: change error type
163-
failure(.postRecordFailed)
154+
/// - Parameters:
155+
/// - record: 学習記録
156+
/// - completion: 投稿完了後のコールバック
157+
public func post(_ record: StudyplusRecord, completion: @escaping (Result<Void, StudyplusPostError>) -> Void) {
158+
guard let accessToken = self.accessToken() else {
159+
completion(.failure(.needLogin))
164160
return
165161
}
166162

167-
guard let accessToken = self.accessToken() else {
168-
failure(.notConnected)
163+
guard record.isValidDuration else {
164+
completion(.failure(.invalidDuration))
169165
return
170166
}
171167

172-
StudyplusAPIRequest(accessToken: accessToken).post(record, success: {
173-
success()
174-
}, failure: { error in
175-
failure(error)
176-
})
168+
StudyplusAPIRequest(accessToken: accessToken).post(record, completion: completion)
177169
}
178170

179171
/// It is responsible for processing custom URL scheme
@@ -193,20 +185,19 @@ final public class Studyplus {
193185
/// The valid URL has a __[studyplus-{consumerKey}]__ scheme, and right pathComponents and host.
194186
/// 渡されたurlがStudyplusSDKで対応すべきURLであれば true、それ以外は false を返します。
195187
/// __[studyplus-{consumerKey}]__と正しいpathComponentsを持つことを確認してください。
196-
public func handle(appDelegateUrl: URL) -> Bool {
197-
198-
guard isAcceptableURL(url: appDelegateUrl) else {
199-
delegate?.studyplusDidFailToLogin(error: .unknownUrl(appDelegateUrl))
188+
public func handle(_ url: URL) -> Bool {
189+
guard isAcceptableURL(url: url) else {
190+
delegate?.studyplusDidFailToLogin(error: .unknownUrl(url))
200191
return false
201192
}
202193

203-
switch appDelegateUrl.pathComponents[1] {
194+
switch url.pathComponents[1] {
204195
case "success":
205-
let accessToken: Data = appDelegateUrl
196+
let accessToken: Data = url
206197
.pathComponents[2]
207198
.trimmingCharacters(in: .whitespacesAndNewlines)
208199
.data(using: .utf8, allowLossyConversion: false)!
209-
let username: Data = appDelegateUrl
200+
let username: Data = url
210201
.pathComponents[3]
211202
.trimmingCharacters(in: .whitespacesAndNewlines)
212203
.data(using: .utf8, allowLossyConversion: false)!
@@ -230,24 +221,13 @@ final public class Studyplus {
230221
if statusAccessToken == noErr && statusUsername == noErr {
231222
delegate?.studyplusDidSuccessToLogin()
232223
} else {
233-
delegate?.studyplusDidFailToLogin(error: .unknownReason("Could not access Keychain."))
224+
delegate?.studyplusDidFailToLogin(error: .keychainError)
234225
}
235226
case "fail":
236-
237-
if let errorCode: Int = Int(appDelegateUrl.pathComponents[2]) {
238-
delegate?.studyplusDidFailToLogin(error: StudyplusError(errorCode))
239-
} else {
240-
delegate?.studyplusDidFailToLogin(error: .unknownReason("ErrorCode is nil"))
241-
}
242-
227+
delegate?.studyplusDidFailToLogin(error: .fail)
243228
case "cancel":
244-
245-
delegate?.studyplusDidCancelToLogin()
246-
229+
delegate?.studyplusDidFailToLogin(error: .cancel)
247230
default:
248-
#if DEBUG
249-
print("StudyplusSDK: Unknown format: \(appDelegateUrl.absoluteString)")
250-
#endif
251231
return false
252232
}
253233

@@ -271,7 +251,6 @@ final public class Studyplus {
271251
/// - consumerKey: consumer key
272252
/// - consumerSecret: consumer secret
273253
public func change(consumerKey: String, consumerSecret: String) {
274-
275254
self.consumerKey = consumerKey
276255
self.consumerSecret = consumerSecret
277256
}
@@ -332,7 +311,6 @@ final public class Studyplus {
332311
}
333312

334313
private func isAcceptableURL(url: URL) -> Bool {
335-
336314
guard let host = url.host else { return false }
337315
guard host == "auth-result" || host == "login-result" else { return false }
338316

Lib/StudyplusSDK/StudyplusAPIRequest.swift

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ import Foundation
2828

2929
internal struct StudyplusAPIRequest {
3030

31-
private static let endPoint: String = "https://external-api.studyplus.jp"
32-
private static let path: String = "/v1/study_record"
33-
private let studyRecordUrl: URL = URL(string: endPoint + path)!
31+
private static let base: String = "https://external-api.studyplus.jp"
32+
private static let path: String = "/v1/study_records"
33+
private let studyRecordUrl: URL = URL(string: base + path)!
3434

3535
private let accessToken: String
3636
private var encoder: JSONEncoder {
@@ -45,41 +45,46 @@ internal struct StudyplusAPIRequest {
4545
self.accessToken = accessToken
4646
}
4747

48-
internal func post(_ record: StudyplusRecord,
49-
success: @escaping () -> Void,
50-
failure: @escaping (_ error: StudyplusError) -> Void) {
51-
studyRecord(record, success: {
48+
internal func post(_ record: StudyplusRecord, completion: @escaping (Result<Void, StudyplusPostError>) -> Void) {
49+
exec(record, completion: { result in
5250
DispatchQueue.main.async {
53-
success()
54-
}
55-
}, failure: { error in
56-
DispatchQueue.main.async {
57-
failure(error)
51+
completion(result)
5852
}
5953
})
6054
}
6155

62-
private func studyRecord(_ record: StudyplusRecord,
63-
success: @escaping () -> Void,
64-
failure: @escaping (_ error: StudyplusError) -> Void) {
56+
private func exec(_ record: StudyplusRecord, completion: @escaping (Result<Void, StudyplusPostError>) -> Void) {
6557
var request = URLRequest(url: studyRecordUrl)
6658
request.httpMethod = "POST"
6759
request.addValue("application/json; charaset=utf-8", forHTTPHeaderField: "Content-Type")
68-
request.addValue("OAuth " + accessToken, forHTTPHeaderField: "Authorization")
60+
request.addValue("OAuth \(accessToken)", forHTTPHeaderField: "Authorization")
6961
request.httpBody = try? encoder.encode(record)
7062

7163
let task = URLSession.shared.dataTask(with: request) { data, response, error in
72-
guard data != nil, error == nil, let response = response as? HTTPURLResponse else {
73-
failure(.postRecordFailed)
64+
if let error = error {
65+
if let error = error as NSError?,
66+
error.domain == NSURLErrorDomain,
67+
error.code == NSURLErrorNotConnectedToInternet {
68+
completion(.failure(.offline))
69+
return
70+
}
71+
72+
completion(.failure(.badRequest))
73+
return
74+
}
75+
76+
guard data != nil, let response = response as? HTTPURLResponse else {
77+
completion(.failure(.badRequest))
7478
return
7579
}
7680

7781
guard (200...204).contains(response.statusCode) else {
78-
failure(StudyplusError(response.statusCode, ""))
82+
let studyplusError = StudyplusPostError.responseError(response.statusCode)
83+
completion(.failure(studyplusError))
7984
return
8085
}
8186

82-
success()
87+
completion(.success(Void()))
8388
}
8489

8590
task.resume()

Lib/StudyplusSDK/StudyplusError.swift

Lines changed: 20 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
//
55
// The MIT License (MIT)
66
//
7-
// Copyright (c) 2017 Studyplus inc.
7+
// Copyright (c) 2021 Studyplus inc.
88
//
99
// Permission is hereby granted, free of charge, to any person obtaining a copy
1010
// of this software and associated documentation files (the "Software"), to deal
@@ -26,115 +26,32 @@
2626

2727
import Foundation
2828

29-
public enum StudyplusError {
30-
31-
case getAppDescription
32-
case authFailed
33-
case loginFailed
34-
case studyplusInMaintenance
35-
case invalidStudyplusSession
36-
case networkUnavailable
29+
public enum StudyplusPostError: Error {
30+
case invalidDuration
31+
case needLogin
32+
case offline
33+
case badRequest
34+
case invalidAccessToken
3735
case serverError
38-
case postRecordFailed
39-
case notConnected
40-
case unknownUrl(URL)
41-
case unknownReason(String)
42-
43-
internal init(_ code: Int) {
36+
case unknown(_ message: String)
4437

38+
static func responseError(_ code: Int) -> StudyplusPostError {
4539
switch code {
46-
case 1000:
47-
self = .getAppDescription
48-
case 2000:
49-
self = .authFailed
50-
case 3000:
51-
self = .loginFailed
52-
case 4000:
53-
self = .studyplusInMaintenance
54-
case 5000:
55-
self = .invalidStudyplusSession
56-
case 6000:
57-
self = .networkUnavailable
58-
case 7000:
59-
self = .serverError
60-
case 8000:
61-
self = .postRecordFailed
62-
case 9000:
63-
self = .notConnected
64-
default:
65-
self = .unknownReason("Unexpected Error errorCode: \(code).")
66-
}
67-
}
68-
69-
internal init(_ httpStatusCode: Int, _ message: String) {
70-
71-
switch httpStatusCode {
7240
case 400:
73-
self = .postRecordFailed
41+
return .badRequest
7442
case 401:
75-
self = .invalidStudyplusSession
76-
case 500:
77-
self = .serverError
78-
case 503:
79-
self = .studyplusInMaintenance
43+
return .invalidAccessToken
44+
case 500...599:
45+
return .serverError
8046
default:
81-
self = .unknownReason("Unexpected http status: \(httpStatusCode), message: \(message).")
47+
return .unknown("Unexpected http status: \(code)")
8248
}
8349
}
50+
}
8451

85-
public func code() -> Int {
86-
87-
switch self {
88-
case .getAppDescription:
89-
return 1000
90-
case .authFailed:
91-
return 2000
92-
case .loginFailed:
93-
return 3000
94-
case .studyplusInMaintenance:
95-
return 4000
96-
case .invalidStudyplusSession:
97-
return 5000
98-
case .networkUnavailable:
99-
return 6000
100-
case .serverError:
101-
return 7000
102-
case .postRecordFailed:
103-
return 8000
104-
case .notConnected:
105-
return 9000
106-
case .unknownUrl:
107-
return 10000
108-
case .unknownReason:
109-
return 90000
110-
}
111-
}
112-
113-
public func message() -> String {
114-
115-
switch self {
116-
case .getAppDescription:
117-
return "Failed to get information about application. (400 bad request)"
118-
case .authFailed:
119-
return "Failed to authorize Studyplus user. (400 bad request)"
120-
case .loginFailed:
121-
return "Failed to login to Studyplus. (400 bad request)"
122-
case .studyplusInMaintenance:
123-
return "Maybe Studyplus is in temporary maintenance."
124-
case .invalidStudyplusSession:
125-
return "Studyplus session is invalid."
126-
case .networkUnavailable:
127-
return "Network is not available."
128-
case .serverError:
129-
return "Some error(s) occurred in Studyplus server."
130-
case .postRecordFailed:
131-
return "Failed to post study record. (400 bad request)"
132-
case .notConnected:
133-
return "Not Connected, so accessToken is nill"
134-
case let .unknownUrl(url):
135-
return "Unknown Url: \(url.absoluteString)."
136-
case let .unknownReason(reason):
137-
return "Unknown Error: \(reason)."
138-
}
139-
}
52+
public enum StudyplusLoginError: Error {
53+
case unknownUrl(_ url: URL)
54+
case keychainError
55+
case fail
56+
case cancel
14057
}

Lib/StudyplusSDK/StudyplusLoginDelegate.swift

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
//
55
// The MIT License (MIT)
66
//
7-
// Copyright (c) 2017 Studyplus inc.
7+
// Copyright (c) 2021 Studyplus inc.
88
//
99
// Permission is hereby granted, free of charge, to any person obtaining a copy
1010
// of this software and associated documentation files (the "Software"), to deal
@@ -28,7 +28,7 @@ import Foundation
2828

2929
/**
3030
The delegate to receive callbacks from Studyplus.
31-
31+
3232
Studyplusオブジェクトに対する各種操作後のコールバックを受けるdelegateです。
3333
*/
3434
public protocol StudyplusLoginDelegate: class {
@@ -43,18 +43,5 @@ public protocol StudyplusLoginDelegate: class {
4343
/// Studyplus#login が失敗した後に呼ばれます。
4444
///
4545
/// - Parameter error: failure reason, see StudyplusError. 失敗の理由です。詳細は StudyplusError を参照してください。
46-
func studyplusDidFailToLogin(error: StudyplusError)
47-
48-
// MARK: - optional
49-
50-
/// Will be called after the Studyplus#login was cancelled.
51-
///
52-
/// Studyplus#login がキャンセルされた後に呼ばれます。
53-
func studyplusDidCancelToLogin()
54-
}
55-
56-
public extension StudyplusLoginDelegate {
57-
58-
func studyplusDidCancelToLogin() {
59-
}
46+
func studyplusDidFailToLogin(error: StudyplusLoginError)
6047
}

0 commit comments

Comments
 (0)