forked from zelo72/mastodon-ios
feat: add OAuth API endpoint unit test
This commit is contained in:
parent
fe83c02e03
commit
71de1ed9be
|
@ -11,6 +11,12 @@
|
|||
5D526FE225BE9AC400460CB9 /* MastodonSDK in Frameworks */ = {isa = PBXBuildFile; productRef = 5D526FE125BE9AC400460CB9 /* MastodonSDK */; };
|
||||
5E44BF88AD33646E64727BCF /* Pods_MastodonTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD92E0F10BDE4FE7C4B999F2 /* Pods_MastodonTests.framework */; };
|
||||
7A9135D4559750AF07CA9BE4 /* Pods_Mastodon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 602D783BEC22881EBAD84419 /* Pods_Mastodon.framework */; };
|
||||
DB01409625C40B6700F9F3CF /* AuthenticationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB01409525C40B6700F9F3CF /* AuthenticationViewController.swift */; };
|
||||
DB0140A125C40C0600F9F3CF /* MastodonPinBasedAuthenticationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0140A025C40C0600F9F3CF /* MastodonPinBasedAuthenticationViewController.swift */; };
|
||||
DB0140A825C40C1500F9F3CF /* MastodonPinBasedAuthenticationViewModelNavigationDelegateShim.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0140A725C40C1500F9F3CF /* MastodonPinBasedAuthenticationViewModelNavigationDelegateShim.swift */; };
|
||||
DB0140AE25C40C7300F9F3CF /* MastodonPinBasedAuthenticationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0140AD25C40C7300F9F3CF /* MastodonPinBasedAuthenticationViewModel.swift */; };
|
||||
DB0140BD25C40D7500F9F3CF /* CommonOSLog in Frameworks */ = {isa = PBXBuildFile; productRef = DB0140BC25C40D7500F9F3CF /* CommonOSLog */; };
|
||||
DB0140CF25C42AEE00F9F3CF /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0140CE25C42AEE00F9F3CF /* OSLog.swift */; };
|
||||
DB3D0FF325BAA61700EAA174 /* AlamofireImage in Frameworks */ = {isa = PBXBuildFile; productRef = DB3D0FF225BAA61700EAA174 /* AlamofireImage */; };
|
||||
DB3D100D25BAA75E00EAA174 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = DB3D100F25BAA75E00EAA174 /* Localizable.strings */; };
|
||||
DB3D102425BAA7B400EAA174 /* Assets.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3D102225BAA7B400EAA174 /* Assets.swift */; };
|
||||
|
@ -108,6 +114,11 @@
|
|||
A1B4523A7981F1044DE89C21 /* Pods_Mastodon_MastodonUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Mastodon_MastodonUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
BB482D32A7B9825BF5327C4F /* Pods-Mastodon-MastodonUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-MastodonUITests.release.xcconfig"; path = "Target Support Files/Pods-Mastodon-MastodonUITests/Pods-Mastodon-MastodonUITests.release.xcconfig"; sourceTree = "<group>"; };
|
||||
CD92E0F10BDE4FE7C4B999F2 /* Pods_MastodonTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MastodonTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
DB01409525C40B6700F9F3CF /* AuthenticationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationViewController.swift; sourceTree = "<group>"; };
|
||||
DB0140A025C40C0600F9F3CF /* MastodonPinBasedAuthenticationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonPinBasedAuthenticationViewController.swift; sourceTree = "<group>"; };
|
||||
DB0140A725C40C1500F9F3CF /* MastodonPinBasedAuthenticationViewModelNavigationDelegateShim.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MastodonPinBasedAuthenticationViewModelNavigationDelegateShim.swift; sourceTree = "<group>"; };
|
||||
DB0140AD25C40C7300F9F3CF /* MastodonPinBasedAuthenticationViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonPinBasedAuthenticationViewModel.swift; sourceTree = "<group>"; };
|
||||
DB0140CE25C42AEE00F9F3CF /* OSLog.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OSLog.swift; sourceTree = "<group>"; };
|
||||
DB3D0FED25BAA42200EAA174 /* MastodonSDK */ = {isa = PBXFileReference; lastKnownFileType = folder; path = MastodonSDK; sourceTree = "<group>"; };
|
||||
DB3D100E25BAA75E00EAA174 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
DB3D102225BAA7B400EAA174 /* Assets.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Assets.swift; sourceTree = "<group>"; };
|
||||
|
@ -160,6 +171,7 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
DB0140BD25C40D7500F9F3CF /* CommonOSLog in Frameworks */,
|
||||
DB89BA0325C10FD0008580ED /* CoreDataStack.framework in Frameworks */,
|
||||
5D526FE225BE9AC400460CB9 /* MastodonSDK in Frameworks */,
|
||||
7A9135D4559750AF07CA9BE4 /* Pods_Mastodon.framework in Frameworks */,
|
||||
|
@ -224,6 +236,25 @@
|
|||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DB01409B25C40BB600F9F3CF /* Authentication */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DB0140A625C40C0900F9F3CF /* PinBased */,
|
||||
DB01409525C40B6700F9F3CF /* AuthenticationViewController.swift */,
|
||||
);
|
||||
path = Authentication;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DB0140A625C40C0900F9F3CF /* PinBased */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DB0140A025C40C0600F9F3CF /* MastodonPinBasedAuthenticationViewController.swift */,
|
||||
DB0140AD25C40C7300F9F3CF /* MastodonPinBasedAuthenticationViewModel.swift */,
|
||||
DB0140A725C40C1500F9F3CF /* MastodonPinBasedAuthenticationViewModelNavigationDelegateShim.swift */,
|
||||
);
|
||||
path = PinBased;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DB3D0FF725BAA68500EAA174 /* Supporting Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -400,6 +431,7 @@
|
|||
children = (
|
||||
DB8AF54E25C13703002E6C99 /* MainTab */,
|
||||
DB8AF55625C137A8002E6C99 /* HomeViewController.swift */,
|
||||
DB01409B25C40BB600F9F3CF /* Authentication */,
|
||||
);
|
||||
path = Scene;
|
||||
sourceTree = "<group>";
|
||||
|
@ -407,6 +439,7 @@
|
|||
DB8AF56225C138BC002E6C99 /* Extension */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DB0140CE25C42AEE00F9F3CF /* OSLog.swift */,
|
||||
DB8AF55C25C138B7002E6C99 /* UIViewController.swift */,
|
||||
);
|
||||
path = Extension;
|
||||
|
@ -447,6 +480,7 @@
|
|||
packageProductDependencies = (
|
||||
DB3D0FF225BAA61700EAA174 /* AlamofireImage */,
|
||||
5D526FE125BE9AC400460CB9 /* MastodonSDK */,
|
||||
DB0140BC25C40D7500F9F3CF /* CommonOSLog */,
|
||||
);
|
||||
productName = Mastodon;
|
||||
productReference = DB427DD225BAA00100D1B89D /* Mastodon.app */;
|
||||
|
@ -569,6 +603,7 @@
|
|||
mainGroup = DB427DC925BAA00100D1B89D;
|
||||
packageReferences = (
|
||||
DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */,
|
||||
DB0140BB25C40D7500F9F3CF /* XCRemoteSwiftPackageReference "CommonOSLog" */,
|
||||
);
|
||||
productRefGroup = DB427DD325BAA00100D1B89D /* Products */;
|
||||
projectDirPath = "";
|
||||
|
@ -753,15 +788,20 @@
|
|||
DB8AF53025C13561002E6C99 /* AppContext.swift in Sources */,
|
||||
DB8AF52F25C13561002E6C99 /* DocumentStore.swift in Sources */,
|
||||
DB8AF55D25C138B7002E6C99 /* UIViewController.swift in Sources */,
|
||||
DB0140A125C40C0600F9F3CF /* MastodonPinBasedAuthenticationViewController.swift in Sources */,
|
||||
DB8AF55025C13703002E6C99 /* MainTabBarController.swift in Sources */,
|
||||
DB8AF54525C13647002E6C99 /* NeedsDependency.swift in Sources */,
|
||||
DB0140CF25C42AEE00F9F3CF /* OSLog.swift in Sources */,
|
||||
DB0140A825C40C1500F9F3CF /* MastodonPinBasedAuthenticationViewModelNavigationDelegateShim.swift in Sources */,
|
||||
DB427DD625BAA00100D1B89D /* AppDelegate.swift in Sources */,
|
||||
DB8AF54425C13647002E6C99 /* SceneCoordinator.swift in Sources */,
|
||||
DB8AF52E25C13561002E6C99 /* ViewStateStore.swift in Sources */,
|
||||
DB8AF55725C137A8002E6C99 /* HomeViewController.swift in Sources */,
|
||||
DB3D102525BAA7B400EAA174 /* Strings.swift in Sources */,
|
||||
DB01409625C40B6700F9F3CF /* AuthenticationViewController.swift in Sources */,
|
||||
DB3D102425BAA7B400EAA174 /* Assets.swift in Sources */,
|
||||
DB427DD825BAA00100D1B89D /* SceneDelegate.swift in Sources */,
|
||||
DB0140AE25C40C7300F9F3CF /* MastodonPinBasedAuthenticationViewModel.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -1263,6 +1303,14 @@
|
|||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCRemoteSwiftPackageReference section */
|
||||
DB0140BB25C40D7500F9F3CF /* XCRemoteSwiftPackageReference "CommonOSLog" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/MainasuK/CommonOSLog";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 0.1.1;
|
||||
};
|
||||
};
|
||||
DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/Alamofire/AlamofireImage.git";
|
||||
|
@ -1278,6 +1326,11 @@
|
|||
isa = XCSwiftPackageProductDependency;
|
||||
productName = MastodonSDK;
|
||||
};
|
||||
DB0140BC25C40D7500F9F3CF /* CommonOSLog */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = DB0140BB25C40D7500F9F3CF /* XCRemoteSwiftPackageReference "CommonOSLog" */;
|
||||
productName = CommonOSLog;
|
||||
};
|
||||
DB3D0FF225BAA61700EAA174 /* AlamofireImage */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */;
|
||||
|
|
|
@ -19,6 +19,15 @@
|
|||
"version": "4.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "CommonOSLog",
|
||||
"repositoryURL": "https://github.com/MainasuK/CommonOSLog",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "c121624a30698e9886efe38aebb36ff51c01b6c2",
|
||||
"version": "0.1.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "swift-nio",
|
||||
"repositoryURL": "https://github.com/apple/swift-nio.git",
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// OSLog.swift
|
||||
// Mastodon
|
||||
//
|
||||
// Created by Cirno MainasuK on 2021/1/29
|
||||
//
|
||||
|
||||
import os
|
||||
import Foundation
|
||||
import CommonOSLog
|
||||
|
||||
extension OSLog {
|
||||
static let api: OSLog = {
|
||||
#if DEBUG
|
||||
return OSLog(subsystem: OSLog.subsystem + ".api", category: "api")
|
||||
#else
|
||||
return OSLog.disabled
|
||||
#endif
|
||||
}()
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
//
|
||||
// AuthenticationViewController.swift
|
||||
// Mastodon
|
||||
//
|
||||
// Created by MainasuK Cirno on 2021/1/29.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// MastodonPinBasedAuthenticationViewController.swift
|
||||
// Mastodon
|
||||
//
|
||||
// Created by MainasuK Cirno on 2021/1/29.
|
||||
//
|
||||
|
||||
import os.log
|
||||
import Foundation
|
||||
import WebKit
|
||||
|
||||
final class MastodonPinBasedAuthenticationViewController: NSObject {
|
||||
|
||||
|
||||
weak var viewModel: MastodonPinBasedAuthenticationViewModel?
|
||||
|
||||
init(viewModel: MastodonPinBasedAuthenticationViewModel) {
|
||||
self.viewModel = viewModel
|
||||
}
|
||||
|
||||
deinit {
|
||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
//
|
||||
// MastodonPinBasedAuthenticationViewModel.swift
|
||||
// Mastodon
|
||||
//
|
||||
// Created by MainasuK Cirno on 2021/1/29.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
final class MastodonPinBasedAuthenticationViewModel {
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// MastodonPinBasedAuthenticationViewModelNavigationDelegateShim.swift
|
||||
// Mastodon
|
||||
//
|
||||
// Created by Cirno MainasuK on 2021/1/29.
|
||||
//
|
||||
|
||||
import os.log
|
||||
import Foundation
|
||||
import WebKit
|
||||
|
||||
final class MastodonPinBasedAuthenticationViewModelNavigationDelegateShim: NSObject {
|
||||
|
||||
weak var viewModel: MastodonPinBasedAuthenticationViewModel?
|
||||
|
||||
init(viewModel: MastodonPinBasedAuthenticationViewModel) {
|
||||
self.viewModel = viewModel
|
||||
}
|
||||
|
||||
deinit {
|
||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - WKNavigationDelegate
|
||||
extension MastodonPinBasedAuthenticationViewModelNavigationDelegateShim: WKNavigationDelegate {
|
||||
|
||||
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
|
||||
// TODO:
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -2,9 +2,26 @@
|
|||
"configurations" : [
|
||||
{
|
||||
"id" : "5119353D-C795-4264-89FD-8376D9B144F8",
|
||||
"name" : "Configuration 1",
|
||||
"name" : "mstdn.jp",
|
||||
"options" : {
|
||||
|
||||
"environmentVariableEntries" : [
|
||||
{
|
||||
"key" : "domain",
|
||||
"value" : "mstdn.jp"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id" : "C5184AF3-B83B-4A7E-949C-6B1AA3ABE7D1",
|
||||
"name" : "pawoo.net",
|
||||
"options" : {
|
||||
"environmentVariableEntries" : [
|
||||
{
|
||||
"key" : "domain",
|
||||
"value" : "pawoo.net"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -13,6 +30,10 @@
|
|||
},
|
||||
"testTargets" : [
|
||||
{
|
||||
"skippedTests" : [
|
||||
"MastodonSDKTests\/testCreateAnAnpplication()",
|
||||
"MastodonSDKTests\/testVerifyAppCredentials()"
|
||||
],
|
||||
"target" : {
|
||||
"containerPath" : "container:MastodonSDK",
|
||||
"identifier" : "MastodonSDKTests",
|
||||
|
|
|
@ -14,12 +14,31 @@ extension Mastodon.API.App {
|
|||
return Mastodon.API.endpointURL(domain: domain).appendingPathComponent("apps")
|
||||
}
|
||||
|
||||
static func verifyCredentialsEndpointURL(domain: String) -> URL {
|
||||
return Mastodon.API.endpointURL(domain: domain).appendingPathComponent("apps/verify_credentials")
|
||||
}
|
||||
|
||||
/// Create an application
|
||||
///
|
||||
/// Using this endpoint to obtain `client_id` and `client_secret` for later OAuth token exchange
|
||||
///
|
||||
/// - Since: 0.0.0
|
||||
/// - Version: 3.3.0
|
||||
/// # Last Update
|
||||
/// 2021/1/29
|
||||
/// # Reference
|
||||
/// [Document](https://docs.joinmastodon.org/methods/apps/)
|
||||
/// - Parameters:
|
||||
/// - session: `URLSession`
|
||||
/// - domain: Mastodon instance domain. e.g. "example.com"
|
||||
/// - query: `CreateQuery`
|
||||
/// - Returns: `AnyPublisher` contains `Application` nested in the response
|
||||
public static func create(
|
||||
session: URLSession,
|
||||
domain: String,
|
||||
query: CreateQuery
|
||||
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Application>, Error> {
|
||||
let request = Mastodon.API.request(
|
||||
let request = Mastodon.API.post(
|
||||
url: appEndpointURL(domain: domain),
|
||||
query: query,
|
||||
authorization: nil
|
||||
|
@ -32,6 +51,39 @@ extension Mastodon.API.App {
|
|||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
/// Verify application token
|
||||
///
|
||||
/// Using this endpoint to verify App token
|
||||
///
|
||||
/// - Since: 2.0.0
|
||||
/// - Version: 3.3.0
|
||||
/// # Last Update
|
||||
/// 2021/1/29
|
||||
/// # Reference
|
||||
/// [Document](https://docs.joinmastodon.org/methods/apps/)
|
||||
/// - Parameters:
|
||||
/// - session: `URLSession`
|
||||
/// - domain: Mastodon instance domain. e.g. "example.com"
|
||||
/// - authorization: App token
|
||||
/// - Returns: `AnyPublisher` contains `Application` nested in the response
|
||||
public static func verifyCredentials(
|
||||
session: URLSession,
|
||||
domain: String,
|
||||
authorization: Mastodon.API.OAuth.Authorization
|
||||
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Application>, Error> {
|
||||
let request = Mastodon.API.get(
|
||||
url: verifyCredentialsEndpointURL(domain: domain),
|
||||
query: nil,
|
||||
authorization: authorization
|
||||
)
|
||||
return session.dataTaskPublisher(for: request)
|
||||
.tryMap { data, response in
|
||||
let value = try Mastodon.API.decode(type: Mastodon.Entity.Application.self, from: data, response: response)
|
||||
return Mastodon.Response.Content(value: value, response: response)
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension Mastodon.API.App {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
|
||||
extension Mastodon.API.OAuth {
|
||||
|
||||
|
@ -16,3 +17,101 @@ extension Mastodon.API.OAuth {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
extension Mastodon.API.OAuth {
|
||||
|
||||
static func authorizeEndpointURL(domain: String) -> URL {
|
||||
return Mastodon.API.oauthEndpointURL(domain: domain).appendingPathComponent("authorize")
|
||||
}
|
||||
|
||||
/// Construct user authorize endpoint URL
|
||||
///
|
||||
/// This method construct a URL for user authorize
|
||||
///
|
||||
/// - Since: 0.1.0
|
||||
/// - Version: 3.3.0
|
||||
/// # Last Update
|
||||
/// 2021/1/29
|
||||
/// # Reference
|
||||
/// [Document](https://docs.joinmastodon.org/methods/apps/oauth/)
|
||||
/// - Parameters:
|
||||
/// - session: `URLSession`
|
||||
/// - domain: Mastodon instance domain. e.g. "example.com"
|
||||
/// - query: `AuthorizeQuery`
|
||||
static func authorizeURL(
|
||||
domain: String,
|
||||
query: AuthorizeQuery
|
||||
) -> URL {
|
||||
let request = Mastodon.API.get(
|
||||
url: authorizeEndpointURL(domain: domain),
|
||||
query: query,
|
||||
authorization: nil
|
||||
)
|
||||
let url = request.url!
|
||||
return url
|
||||
}
|
||||
|
||||
// static func authorize(
|
||||
// session: URLSession,
|
||||
// domain: String,
|
||||
// query: AuthorizeQuery
|
||||
// ) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Token>, Error> {
|
||||
// let request = Mastodon.API.post(
|
||||
// url: authorizeEndpointURL(domain: domain),
|
||||
// query: query,
|
||||
// authorization: nil
|
||||
// )
|
||||
// return session.dataTaskPublisher(for: request)
|
||||
// .tryMap { data, response in
|
||||
// let value = try Mastodon.API.decode(type: Mastodon.Entity.Token.self, from: data, response: response)
|
||||
// return Mastodon.Response.Content(value: value, response: response)
|
||||
// }
|
||||
// .eraseToAnyPublisher()
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
extension Mastodon.API.OAuth {
|
||||
public struct AuthorizeQuery: GetQuery {
|
||||
|
||||
public let forceLogin: String?
|
||||
public let responseType: String
|
||||
public let clientID: String
|
||||
public let redirectURI: String
|
||||
public let scope: String?
|
||||
|
||||
public init(
|
||||
forceLogin: String? = nil,
|
||||
responseType: String = "code",
|
||||
clientID: String,
|
||||
redirectURI: String = "urn:ietf:wg:oauth:2.0:oob",
|
||||
scope: String? = "read write follow push"
|
||||
) {
|
||||
self.forceLogin = forceLogin
|
||||
self.responseType = responseType
|
||||
self.clientID = clientID
|
||||
self.redirectURI = redirectURI
|
||||
self.scope = scope
|
||||
}
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case forceLogin = "force_login"
|
||||
case responseType = "response_type"
|
||||
case clientID
|
||||
case redirectURI = "redirect_uri"
|
||||
case scope
|
||||
}
|
||||
|
||||
var queryItems: [URLQueryItem]? {
|
||||
var items: [URLQueryItem] = []
|
||||
forceLogin.flatMap { items.append(URLQueryItem(name: "force_login", value: $0)) }
|
||||
items.append(URLQueryItem(name: "response_type", value: responseType))
|
||||
items.append(URLQueryItem(name: "clientID", value: clientID))
|
||||
items.append(URLQueryItem(name: "redirect_uri", value: redirectURI))
|
||||
scope.flatMap { items.append(URLQueryItem(name: "scope", value: $0)) }
|
||||
guard !items.isEmpty else { return nil }
|
||||
return items
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ extension Mastodon.API.Timeline {
|
|||
domain: String,
|
||||
query: PublicTimelineQuery
|
||||
) -> AnyPublisher<Mastodon.Response.Content<[Mastodon.Entity.Toot]>, Error> {
|
||||
let request = Mastodon.API.request(
|
||||
let request = Mastodon.API.get(
|
||||
url: publicTimelineEndpointURL(domain: domain),
|
||||
query: query,
|
||||
authorization: nil
|
||||
|
@ -65,27 +65,13 @@ extension Mastodon.API.Timeline {
|
|||
|
||||
var queryItems: [URLQueryItem]? {
|
||||
var items: [URLQueryItem] = []
|
||||
local.flatMap {
|
||||
items.append(URLQueryItem(name: "local", value: $0.queryItemValue))
|
||||
}
|
||||
remote.flatMap {
|
||||
items.append(URLQueryItem(name: "remote", value: $0.queryItemValue))
|
||||
}
|
||||
onlyMedia.flatMap {
|
||||
items.append(URLQueryItem(name: "only_media", value: $0.queryItemValue))
|
||||
}
|
||||
maxID.flatMap {
|
||||
items.append(URLQueryItem(name: "max_id", value: $0))
|
||||
}
|
||||
sinceID.flatMap {
|
||||
items.append(URLQueryItem(name: "since_id", value: $0))
|
||||
}
|
||||
minID.flatMap {
|
||||
items.append(URLQueryItem(name: "min_id", value: $0))
|
||||
}
|
||||
limit.flatMap {
|
||||
items.append(URLQueryItem(name: "limit", value: String($0)))
|
||||
}
|
||||
local.flatMap { items.append(URLQueryItem(name: "local", value: $0.queryItemValue)) }
|
||||
remote.flatMap { items.append(URLQueryItem(name: "remote", value: $0.queryItemValue)) }
|
||||
onlyMedia.flatMap { items.append(URLQueryItem(name: "only_media", value: $0.queryItemValue)) }
|
||||
maxID.flatMap { items.append(URLQueryItem(name: "max_id", value: $0)) }
|
||||
sinceID.flatMap { items.append(URLQueryItem(name: "since_id", value: $0)) }
|
||||
minID.flatMap { items.append(URLQueryItem(name: "min_id", value: $0)) }
|
||||
limit.flatMap { items.append(URLQueryItem(name: "limit", value: String($0))) }
|
||||
guard !items.isEmpty else { return nil }
|
||||
return items
|
||||
}
|
||||
|
|
|
@ -53,9 +53,15 @@ extension Mastodon.API {
|
|||
return decoder
|
||||
}()
|
||||
|
||||
static func oauthEndpointURL(domain: String) -> URL {
|
||||
return URL(string: "https://" + domain + "/oauth/")!
|
||||
}
|
||||
static func endpointURL(domain: String) -> URL {
|
||||
return URL(string: "https://" + domain + "/api/v1/")!
|
||||
}
|
||||
static func endpointV2URL(domain: String) -> URL {
|
||||
return URL(string: "https://" + domain + "/api/v2/")!
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -67,13 +73,15 @@ extension Mastodon.API {
|
|||
|
||||
extension Mastodon.API {
|
||||
|
||||
static func request(
|
||||
static func get(
|
||||
url: URL,
|
||||
query: GetQuery,
|
||||
query: GetQuery?,
|
||||
authorization: OAuth.Authorization?
|
||||
) -> URLRequest {
|
||||
var components = URLComponents(string: url.absoluteString)!
|
||||
if let query = query {
|
||||
components.queryItems = query.queryItems
|
||||
}
|
||||
|
||||
let requestURL = components.url!
|
||||
var request = URLRequest(
|
||||
|
@ -91,9 +99,9 @@ extension Mastodon.API {
|
|||
return request
|
||||
}
|
||||
|
||||
static func request(
|
||||
static func post(
|
||||
url: URL,
|
||||
query: PostQuery,
|
||||
query: PostQuery?,
|
||||
authorization: OAuth.Authorization?
|
||||
) -> URLRequest {
|
||||
let components = URLComponents(string: url.absoluteString)!
|
||||
|
@ -104,7 +112,9 @@ extension Mastodon.API {
|
|||
timeoutInterval: Mastodon.API.timeoutInterval
|
||||
)
|
||||
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
|
||||
if let query = query {
|
||||
request.httpBody = query.body
|
||||
}
|
||||
if let authorization = authorization {
|
||||
request.setValue(
|
||||
"Bearer \(authorization.accessToken)",
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
//
|
||||
// MastodonSDK+API+AppTests.swift
|
||||
//
|
||||
//
|
||||
// Created by MainasuK Cirno on 2021/1/29.
|
||||
//
|
||||
|
||||
import os.log
|
||||
import XCTest
|
||||
import Combine
|
||||
@testable import MastodonSDK
|
||||
|
||||
extension MastodonSDKTests {
|
||||
|
||||
func testCreateAnAnpplication() throws {
|
||||
try _testCreateAnAnpplication(domain: domain)
|
||||
}
|
||||
|
||||
func _testCreateAnAnpplication(domain: String) throws {
|
||||
let theExpectation = expectation(description: "Create An Application")
|
||||
|
||||
let query = Mastodon.API.App.CreateQuery(
|
||||
clientName: "XCTest",
|
||||
website: nil
|
||||
)
|
||||
Mastodon.API.App.create(session: session, domain: domain, query: query)
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { completion in
|
||||
switch completion {
|
||||
case .failure(let error):
|
||||
XCTFail(error.localizedDescription)
|
||||
case .finished:
|
||||
break
|
||||
}
|
||||
} receiveValue: { response in
|
||||
XCTAssertEqual(response.value.name, "XCTest")
|
||||
XCTAssertEqual(response.value.website, nil)
|
||||
XCTAssertEqual(response.value.redirectURI, "urn:ietf:wg:oauth:2.0:oob")
|
||||
os_log("%{public}s[%{public}ld], %{public}s: (%s) clientID %s", ((#file as NSString).lastPathComponent), #line, #function, domain, response.value.clientID ?? "nil")
|
||||
os_log("%{public}s[%{public}ld], %{public}s: (%s) clientSecret %s", ((#file as NSString).lastPathComponent), #line, #function, domain, response.value.clientSecret ?? "nil")
|
||||
theExpectation.fulfill()
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
wait(for: [theExpectation], timeout: 5.0)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension MastodonSDKTests {
|
||||
|
||||
func testVerifyAppCredentials() throws {
|
||||
try _testVerifyAppCredentials(domain: domain, accessToken: "")
|
||||
}
|
||||
|
||||
func _testVerifyAppCredentials(domain: String, accessToken: String) throws {
|
||||
let theExpectation = expectation(description: "Verify App Credentials")
|
||||
|
||||
let authorization = Mastodon.API.OAuth.Authorization(accessToken: accessToken)
|
||||
Mastodon.API.App.verifyCredentials(
|
||||
session: session,
|
||||
domain: domain,
|
||||
authorization: authorization
|
||||
)
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { completion in
|
||||
switch completion {
|
||||
case .failure(let error):
|
||||
XCTFail(error.localizedDescription)
|
||||
case .finished:
|
||||
break
|
||||
}
|
||||
} receiveValue: { response in
|
||||
XCTAssertEqual(response.value.name, "XCTest")
|
||||
XCTAssertEqual(response.value.website, nil)
|
||||
theExpectation.fulfill()
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
wait(for: [theExpectation], timeout: 5.0)
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
//
|
||||
// MastodonSDK+API+OAuthTests.swift
|
||||
//
|
||||
//
|
||||
// Created by MainasuK Cirno on 2021/1/29.
|
||||
//
|
||||
|
||||
import os.log
|
||||
import XCTest
|
||||
import Combine
|
||||
@testable import MastodonSDK
|
||||
|
||||
extension MastodonSDKTests {
|
||||
|
||||
func testOAuthAuthorize() throws {
|
||||
try _testOAuthAuthorize(domain: domain)
|
||||
}
|
||||
|
||||
func _testOAuthAuthorize(domain: String) throws {
|
||||
let query = Mastodon.API.OAuth.AuthorizeQuery(clientID: "StubClientID")
|
||||
let authorizeURL = Mastodon.API.OAuth.authorizeURL(domain: domain, query: query)
|
||||
os_log("%{public}s[%{public}ld], %{public}s: (%s) authorizeURL %s", ((#file as NSString).lastPathComponent), #line, #function, domain, authorizeURL.absoluteString)
|
||||
XCTAssertEqual(
|
||||
authorizeURL.absoluteString,
|
||||
"https://\(domain)/oauth/authorize?response_type=code&clientID=StubClientID&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope=read%20write%20follow%20push"
|
||||
)
|
||||
}
|
||||
|
||||
}
|
|
@ -6,58 +6,19 @@ final class MastodonSDKTests: XCTestCase {
|
|||
|
||||
var disposeBag = Set<AnyCancellable>()
|
||||
|
||||
let mstdnDomain = "mstdn.jp"
|
||||
let pawooDomain = "pawoo.net"
|
||||
let session = URLSession(configuration: .ephemeral)
|
||||
var domain: String { MastodonSDKTests.environmentVariable(key: "domain") }
|
||||
|
||||
static func environmentVariable(key: String) -> String {
|
||||
return ProcessInfo.processInfo.environment[key]!
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension MastodonSDKTests {
|
||||
|
||||
func testCreateAnAnpplication_mstdn() throws {
|
||||
try _testCreateAnAnpplication(domain: pawooDomain)
|
||||
}
|
||||
|
||||
func testCreateAnAnpplication_pawoo() throws {
|
||||
try _testCreateAnAnpplication(domain: pawooDomain)
|
||||
}
|
||||
|
||||
func _testCreateAnAnpplication(domain: String) throws {
|
||||
let theExpectation = expectation(description: "Create An Application")
|
||||
|
||||
let query = Mastodon.API.App.CreateQuery(
|
||||
clientName: "XCTest",
|
||||
website: nil
|
||||
)
|
||||
Mastodon.API.App.create(session: session, domain: domain, query: query)
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { completion in
|
||||
switch completion {
|
||||
case .failure(let error):
|
||||
XCTFail(error.localizedDescription)
|
||||
case .finished:
|
||||
break
|
||||
}
|
||||
} receiveValue: { response in
|
||||
XCTAssertEqual(response.value.name, "XCTest")
|
||||
XCTAssertEqual(response.value.website, nil)
|
||||
XCTAssertEqual(response.value.redirectURI, "urn:ietf:wg:oauth:2.0:oob")
|
||||
theExpectation.fulfill()
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
wait(for: [theExpectation], timeout: 10.0)
|
||||
}
|
||||
}
|
||||
|
||||
extension MastodonSDKTests {
|
||||
|
||||
func testPublicTimeline_mstdn() throws {
|
||||
try _testPublicTimeline(domain: mstdnDomain)
|
||||
}
|
||||
|
||||
func testPublicTimeline_pawoo() throws {
|
||||
try _testPublicTimeline(domain: pawooDomain)
|
||||
func testPublicTimeline() throws {
|
||||
try _testPublicTimeline(domain: domain)
|
||||
}
|
||||
|
||||
private func _testPublicTimeline(domain: String) throws {
|
||||
|
|
Loading…
Reference in New Issue