Compare commits

...

10 Commits

Author SHA1 Message Date
Peter Zignego 3823aee4cf Revert oauth endpoint change and query params fix (#207)
* Fix extracting query parameters from request

* downgrade oauth access path

Co-authored-by: David Jennes <david.jennes@gmail.com>
2022-01-23 20:20:59 -05:00
Peter Zignego b95391b03b Revert oauth endpoint change and query params fix (#207)
* Fix extracting query parameters from request

* downgrade oauth access path

Co-authored-by: David Jennes <david.jennes@gmail.com>
2022-01-23 20:01:37 -05:00
Peter Zignego 56be11a950 Revert oauth endpoint change and query params fix (#207)
* Fix extracting query parameters from request

* downgrade oauth access path

Co-authored-by: David Jennes <david.jennes@gmail.com>
2022-01-23 20:01:24 -05:00
Peter Zignego f6f4252075 Update podspec 2021-12-29 10:00:18 -05:00
Peter Zignego a16a78d322 Update pipelines (#205)
* Update pipelines
2021-12-28 10:56:58 -05:00
Peter Zignego ab751a0304 Remove deprecated rtmStart 2021-12-28 09:49:53 -05:00
Arkadiusz Adamski 8e46cbb105 Add conversations.[open|create|archive] (#202) 2021-10-19 19:15:23 -04:00
Atakan Dulker e178c3748a WebAPI: Passes access token as Bearer Token (#200)
* Added passing access token as a Bearer token.

* Removed superfluous code
2021-10-04 21:35:27 -04:00
Roman Podymov a19f6b3088 Codable vol.3 - Attachment (#193)
* Add Attachment.CodingKeys

* testAttachmentCodable

* Create attachment.json

* Update XCTestManifests.swift

* extension Action: Equatable

* extension AttachmentField: Equatable

* Update project.pbxproj

* Update attachment.json

* Update SKCoreTests.swift

* Refactoring
2021-07-10 11:33:31 -04:00
Peter Zignego 6b385bd29c Fix carthage CI (#196) 2021-02-28 20:51:27 -05:00
21 changed files with 548 additions and 355 deletions
+2 -1
View File
@@ -40,4 +40,5 @@ Carthage/Build
# Swift Package Manager
.swiftpm/
*.resolved
*.resolved
.vscode
+1 -1
View File
@@ -1 +1 @@
5.2.4
5.5.2
+2
View File
@@ -44,6 +44,8 @@ Add `SlackKit` to your `Cartfile`:
github "pvzig/SlackKit"
```
**SlackKit is now using .xcframeworks. When building your dependencies with carthage, please specify a platform: `carthage bootstrap --use-xcframeworks --platform macos`**
#### CocoaPods
Add `SlackKit` to your `Podfile`:
+4
View File
@@ -220,6 +220,10 @@ extension Action.Option: Codable {
extension Action.Option.CodingKeys: CodingKey { }
extension Action: Equatable { }
extension Action.Confirm: Equatable { }
extension Action.Option: Equatable { }
public enum ActionStyle: String, Codable {
case defaultStyle = "default"
case primary = "primary"
+98 -26
View File
@@ -22,6 +22,28 @@
// THE SOFTWARE.
public struct Attachment {
fileprivate enum CodingKeys: String {
case fallback
case callbackID = "callback_id"
case type = "attachment_type"
case color
case pretext
case authorName = "author_name"
case authorLink = "author_link"
case authorIcon = "author_icon"
case title
case titleLink = "title_link"
case text
case fields
case actions
case imageURL = "image_url"
case thumbURL = "thumb_url"
case footer
case footerIcon = "footer_icon"
case ts
case markdownEnabledFields = "mrkdwn_in"
}
public let fallback: String?
public let callbackID: String?
public let type: String?
@@ -43,25 +65,25 @@ public struct Attachment {
public let markdownEnabledFields: Set<AttachmentTextField>?
public init(attachment: [String: Any]?) {
fallback = attachment?["fallback"] as? String
callbackID = attachment?["callback_id"] as? String
type = attachment?["attachment_type"] as? String
color = attachment?["color"] as? String
pretext = attachment?["pretext"] as? String
authorName = attachment?["author_name"] as? String
authorLink = attachment?["author_link"] as? String
authorIcon = attachment?["author_icon"] as? String
title = attachment?["title"] as? String
titleLink = attachment?["title_link"] as? String
text = attachment?["text"] as? String
imageURL = attachment?["image_url"] as? String
thumbURL = attachment?["thumb_url"] as? String
footer = attachment?["footer"] as? String
footerIcon = attachment?["footer_icon"] as? String
ts = attachment?["ts"] as? Int
fields = (attachment?["fields"] as? [[String: Any]])?.map { AttachmentField(field: $0) }
actions = (attachment?["actions"] as? [[String: Any]])?.map { Action(action: $0) }
markdownEnabledFields = (attachment?["mrkdwn_in"] as? [String]).map { Set($0.compactMap(AttachmentTextField.init)) }
fallback = attachment?[CodingKeys.fallback] as? String
callbackID = attachment?[CodingKeys.callbackID] as? String
type = attachment?[CodingKeys.type] as? String
color = attachment?[CodingKeys.color] as? String
pretext = attachment?[CodingKeys.pretext] as? String
authorName = attachment?[CodingKeys.authorName] as? String
authorLink = attachment?[CodingKeys.authorLink] as? String
authorIcon = attachment?[CodingKeys.authorIcon] as? String
title = attachment?[CodingKeys.title] as? String
titleLink = attachment?[CodingKeys.titleLink] as? String
text = attachment?[CodingKeys.text] as? String
fields = (attachment?[CodingKeys.fields] as? [[String: Any]])?.map { AttachmentField(field: $0) }
actions = (attachment?[CodingKeys.actions] as? [[String: Any]])?.map { Action(action: $0) }
imageURL = attachment?[CodingKeys.imageURL] as? String
thumbURL = attachment?[CodingKeys.thumbURL] as? String
footer = attachment?[CodingKeys.footer] as? String
footerIcon = attachment?[CodingKeys.footerIcon] as? String
ts = attachment?[CodingKeys.ts] as? Int
markdownEnabledFields = (attachment?[CodingKeys.markdownEnabledFields] as? [String]).map { Set($0.compactMap(AttachmentTextField.init)) }
}
public init(
@@ -135,12 +157,62 @@ public enum AttachmentColor: String {
case good, warning, danger
}
public enum AttachmentTextField: String {
case fallback = "fallback"
case pretext = "pretext"
public enum AttachmentTextField: String, Codable {
case fallback
case pretext
case authorName = "author_name"
case title = "title"
case text = "text"
case fields = "fields"
case footer = "footer"
case title
case text
case fields
case footer
}
extension Attachment: Codable {
public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
fallback = try values.decodeIfPresent(String.self, forKey: .fallback)
callbackID = try values.decodeIfPresent(String.self, forKey: .callbackID)
type = try values.decodeIfPresent(String.self, forKey: .type)
color = try values.decodeIfPresent(String.self, forKey: .color)
pretext = try values.decodeIfPresent(String.self, forKey: .pretext)
authorName = try values.decodeIfPresent(String.self, forKey: .authorName)
authorLink = try values.decodeIfPresent(String.self, forKey: .authorLink)
authorIcon = try values.decodeIfPresent(String.self, forKey: .authorIcon)
title = try values.decodeIfPresent(String.self, forKey: .title)
titleLink = try values.decodeIfPresent(String.self, forKey: .titleLink)
text = try values.decodeIfPresent(String.self, forKey: .text)
fields = try values.decodeIfPresent([AttachmentField].self, forKey: .fields)
actions = try values.decodeIfPresent([Action].self, forKey: .actions)
imageURL = try values.decodeIfPresent(String.self, forKey: .imageURL)
thumbURL = try values.decodeIfPresent(String.self, forKey: .thumbURL)
footer = try values.decodeIfPresent(String.self, forKey: .footer)
footerIcon = try values.decodeIfPresent(String.self, forKey: .footerIcon)
ts = try values.decodeIfPresent(Int.self, forKey: .ts)
markdownEnabledFields = (try values.decodeIfPresent([AttachmentTextField].self, forKey: .markdownEnabledFields)).map { Set($0) }
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(fallback, forKey: .fallback)
try container.encode(callbackID, forKey: .callbackID)
try container.encode(type, forKey: .type)
try container.encode(color, forKey: .color)
try container.encode(pretext, forKey: .pretext)
try container.encode(authorName, forKey: .authorName)
try container.encode(authorLink, forKey: .authorLink)
try container.encode(authorIcon, forKey: .authorIcon)
try container.encode(title, forKey: .title)
try container.encode(titleLink, forKey: .titleLink)
try container.encode(text, forKey: .text)
try container.encode(fields, forKey: .fields)
try container.encode(actions, forKey: .actions)
try container.encode(imageURL, forKey: .imageURL)
try container.encode(thumbURL, forKey: .thumbURL)
try container.encode(footer, forKey: .footer)
try container.encode(footerIcon, forKey: .footerIcon)
try container.encode(ts, forKey: .ts)
try container.encode(markdownEnabledFields, forKey: .markdownEnabledFields)
}
}
extension Attachment.CodingKeys: CodingKey { }
+2
View File
@@ -70,3 +70,5 @@ extension AttachmentField: Codable {
}
extension AttachmentField.CodingKeys: CodingKey { }
extension AttachmentField: Equatable { }
+13 -30
View File
@@ -38,13 +38,13 @@ public protocol RTMWebSocket {
func sendMessage(_ message: String) throws
}
public protocol RTMAdapter: class {
public protocol RTMAdapter: AnyObject {
func initialSetup(json: [String: Any], instance: SKRTMAPI)
func notificationForEvent(_ event: Event, type: EventType, instance: SKRTMAPI)
func connectionClosed(with error: Error, instance: SKRTMAPI)
}
public protocol RTMDelegate: class {
public protocol RTMDelegate: AnyObject {
func didConnect()
func disconnected()
func receivedMessage(_ message: String)
@@ -76,34 +76,17 @@ public final class SKRTMAPI: RTMDelegate {
self.rtm.delegate = self
}
public func connect(withInfo: Bool = true) {
if withInfo {
WebAPI.rtmStart(
token: token,
batchPresenceAware: options.noUnreads,
mpimAware: options.mpimAware,
noLatest: options.noLatest,
noUnreads: options.noUnreads,
presenceSub: options.presenceSub,
simpleLatest: options.simpleLatest,
success: {(response) in
self.connectWithResponse(response)
}, failure: { (error) in
self.adapter?.connectionClosed(with: error, instance: self)
}
)
} else {
WebAPI.rtmConnect(
token: token,
batchPresenceAware: options.batchPresenceAware,
presenceSub: options.presenceSub,
success: {(response) in
self.connectWithResponse(response)
}, failure: { (error) in
self.adapter?.connectionClosed(with: error, instance: self)
}
)
}
public func connect() {
WebAPI.rtmConnect(
token: token,
batchPresenceAware: options.batchPresenceAware,
presenceSub: options.presenceSub,
success: {(response) in
self.connectWithResponse(response)
}, failure: { (error) in
self.adapter?.connectionClosed(with: error, instance: self)
}
)
}
public func disconnect() {
@@ -58,6 +58,7 @@ extension HttpRequest {
return try! Request(
method: HTTPMethod.custom(named: method),
path: path,
queryPairs: queryParams,
body: String(bytes: body, encoding: .utf8) ?? "",
headers: HTTPHeaders(headers: headers.map ({ Header(name: $0.key, value: $0.value) }))
)
@@ -17,8 +17,10 @@ import Foundation
public protocol RequestType {
/// The HTTP request body.
var body: Data { get }
/// The HTTP request path, including query string and any fragments.
/// The HTTP request path
var path: String { get }
/// The HTTP request query pairs
var queryPairs: [(String, String)] { get }
/// The HTTP request method.
var method: HTTPMethod { get }
/// The HTTP request headers.
@@ -30,14 +32,16 @@ public struct Request: RequestType {
public var method: HTTPMethod
public var path: String
public var queryPairs: [(String, String)]
public var body: Data
public var headers: HTTPHeaders
/// Create a Request
/// Throws an error if the body parameter cannot be converted to Data
public init(method: HTTPMethod, path: String, body: String, headers: HTTPHeaders) throws {
public init(method: HTTPMethod, path: String, queryPairs: [(String, String)], body: String, headers: HTTPHeaders) throws {
self.method = method
self.path = path
self.queryPairs = queryPairs
guard let data = body.data(using: .utf8) else {
throw TitanError.dataConversion
}
@@ -46,9 +50,10 @@ public struct Request: RequestType {
}
/// Create a Request
public init(method: HTTPMethod, path: String, body: Data, headers: HTTPHeaders) {
public init(method: HTTPMethod, path: String, queryPairs: [(String, String)], body: Data, headers: HTTPHeaders) {
self.method = method
self.path = path
self.queryPairs = queryPairs
self.body = body
self.headers = headers
}
@@ -57,7 +62,7 @@ public struct Request: RequestType {
extension Request {
/// Create a Request from a RequestType
public init(request: RequestType) {
self.init(method: request.method, path: request.path, body: request.body, headers: request.headers)
self.init(method: request.method, path: request.path, queryPairs: request.queryPairs, body: request.body, headers: request.headers)
}
}
@@ -14,43 +14,6 @@
import Foundation
public extension RequestType {
/// The pairs of keys and values in the query string of the `RequestType`s path.
/// Complexity: 0(n) on all invocations.
var queryPairs: [(key: String, value: String)] {
// Ensure there is a query string, otherwise return
guard let indexOfQuery = self.path.firstIndex(of: "?") else {
return []
}
let query = self.path.suffix(from: indexOfQuery).dropFirst()
// Create an array of the individual query pairs, e.g. ["foo=bar", "baz=qux"]
let pairs = query.split(separator: "&")
// Decode `foo=bar` -> `(key: "foo", value: "bar")`, percent decoding any values along the way
return pairs.map { pair -> (key: String, value: String) in
// Separate the query pair into an array, e.g. "foo=bar" -> ["foo", "bar"]
let comps = pair.split(separator: "=")
// Split returns an array of subsequences which should conform to StringProtocol, however on Linux StringProtocol is out of date.
// Workaround for https://bugs.swift.org/browse/SR-5727 by converting to a String directly
.map(String.init)
.map {
// Percent encoding mandates that "%20" = <space>"
// however, many applications use "+" to mean space as well, so decode those (before we decode any percent-encoded plus signs!)
return $0.replacingOccurrences(of: "+", with: " ")
}.map {
return $0.removingPercentEncoding ?? ""
}
switch comps.count {
case 1: // "?foo="
return (key: String(comps[0]), value: "")
case 2: // "?foo=bar"
return (key: String(comps[0]), value: String(comps[1]))
default: // "?"
return (key: "", value: "")
}
}
}
/// Access the query string as a dictionary, with case sensitive keys.
/// Complexity: 0(n) on all invocations.
var query: [String: String] {
@@ -14,8 +14,8 @@
import Foundation
extension Request {
public init(_ method: HTTPMethod = .get, _ path: String = "/", _ body: String = "", _ headers: HTTPHeaders = HTTPHeaders()) {
self.init(method: method, path: path, body: body.data(using: .utf8) ?? Data(), headers: headers)
public init(_ method: HTTPMethod = .get, _ path: String = "/", _ queryPairs: [(String, String)] = [], _ body: String = "", _ headers: HTTPHeaders = HTTPHeaders()) {
self.init(method: method, path: path, queryPairs: queryPairs, body: body.data(using: .utf8) ?? Data(), headers: headers)
}
}
+1 -1
View File
@@ -134,7 +134,7 @@ SlackKit currently supports the a subset of the Slack Web API that is available
| `reactions.get`|
| `reactions.list`|
| `reactions.remove`|
| `rtm.start`|
| `rtm.connect`|
| `stars.add`|
| `stars.remove`|
| `team.info`|
+27 -23
View File
@@ -26,34 +26,30 @@ public enum Endpoint: String {
case authRevoke = "auth.revoke"
case authTest = "auth.test"
case channelsHistory = "channels.history"
case channelsInfo = "channels.info"
case channelsList = "channels.list"
case channelsMark = "channels.mark"
case channelsCreate = "channels.create"
case channelsInvite = "channels.invite"
case channelsJoin = "channels.join"
case channelsLeave = "channels.leave"
case channelsArchive = "channels.archive"
case channelsUnarchive = "channels.unarchive"
case channelsRename = "channels.rename"
case channelsKick = "channels.kick"
case channelsLeave = "channels.leave"
case channelsRename = "channels.rename"
case channelsSetPurpose = "channels.setPurpose"
case channelsSetTopic = "channels.setTopic"
case channelsUnarchive = "channels.unarchive"
case chatDelete = "chat.delete"
case chatPostMessage = "chat.postMessage"
case chatPostEphemeral = "chat.postEphemeral"
case chatMeMessage = "chat.meMessage"
case chatPostEphemeral = "chat.postEphemeral"
case chatPostMessage = "chat.postMessage"
case chatUpdate = "chat.update"
case conversationsList = "conversations.list"
case conversationsReplies = "conversations.replies"
case conversationsMembers = "conversations.members"
case conversationsArchive = "conversations.archive"
case conversationsCreate = "conversations.create"
case conversationsHistory = "conversations.history"
case conversationsList = "conversations.list"
case conversationsMembers = "conversations.members"
case conversationsOpen = "conversations.open"
case conversationsReplies = "conversations.replies"
case dndInfo = "dnd.info"
case dndTeamInfo = "dnd.teamInfo"
case emojiList = "emoji.list"
case filesCommentsAdd = "files.comments.add"
case filesCommentsEdit = "files.comments.edit"
case filesCommentsDelete = "files.comments.delete"
case filesCommentsEdit = "files.comments.edit"
case filesDelete = "files.delete"
case filesInfo = "files.info"
case filesUpload = "files.upload"
@@ -69,34 +65,42 @@ public enum Endpoint: String {
case imHistory = "im.history"
case imList = "im.list"
case imMark = "im.mark"
case imOpen = "im.open"
case mpimClose = "mpim.close"
case mpimHistory = "mpim.history"
case mpimList = "mpim.list"
case mpimMark = "mpim.mark"
case mpimOpen = "mpim.open"
case oauthAccess = "oauth.access"
case pinsList = "pins.list"
case pinsAdd = "pins.add"
case pinsList = "pins.list"
case pinsRemove = "pins.remove"
case reactionsAdd = "reactions.add"
case reactionsGet = "reactions.get"
case reactionsList = "reactions.list"
case reactionsRemove = "reactions.remove"
case rtmStart = "rtm.start"
case rtmConnect = "rtm.connect"
case searchAll = "search.all"
case searchFiles = "search.files"
case searchMessages = "search.messages"
case starsAdd = "stars.add"
case starsRemove = "stars.remove"
case teamInfo = "team.info"
case usersConversations = "users.conversations"
case usersGetPresence = "users.getPresence"
case usersInfo = "users.info"
case usersList = "users.list"
case usersConversations = "users.conversations"
case usersLookupByEmail = "users.lookupByEmail"
case usersProfileSet = "users.profile.set"
case usersSetActive = "users.setActive"
case usersSetPresence = "users.setPresence"
case searchAll = "search.all"
case searchFiles = "search.files"
case searchMessages = "search.messages"
// MARK: - Deprecated endpoints
case channelsArchive = "channels.archive"
case channelsCreate = "channels.create"
case channelsInfo = "channels.info"
case channelsInvite = "channels.invite"
case channelsJoin = "channels.join"
case channelsList = "channels.list"
case channelsMark = "channels.mark"
case imOpen = "im.open"
}
+15 -3
View File
@@ -47,15 +47,23 @@ public struct NetworkInterface {
internal func request(
_ endpoint: Endpoint,
accessToken: String,
parameters: [String: Any?],
successClosure: @escaping ([String: Any]) -> Void,
errorClosure: @escaping (SlackError) -> Void
) {
guard !accessToken.isEmpty else {
errorClosure(.invalidAuth)
return
}
guard let url = requestURL(for: endpoint, parameters: parameters) else {
errorClosure(SlackError.clientNetworkError)
return
}
let request = URLRequest(url: url)
var request = URLRequest(url: url)
request.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
session.dataTask(with: request) {(data, response, publicError) in
do {
@@ -89,6 +97,7 @@ public struct NetworkInterface {
internal func customRequest(
_ url: String,
token: String,
data: Data,
success: @escaping (Bool) -> Void,
errorClosure: @escaping (SlackError) -> Void
@@ -99,11 +108,12 @@ public struct NetworkInterface {
}
var request = URLRequest(url:url)
request.httpMethod = "POST"
let contentType = "application/json"
let contentType = "application/json; charset: utf-8"
request.setValue(contentType, forHTTPHeaderField: "Content-Type")
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
request.httpBody = data
session.dataTask(with: request) {(_, _, publicError) in
session.dataTask(with: request) {(data, response, publicError) in
if publicError == nil {
success(true)
} else {
@@ -114,6 +124,7 @@ public struct NetworkInterface {
internal func uploadRequest(
data: Data,
accessToken: String,
parameters: [String: Any?],
successClosure: @escaping ([String: Any]) -> Void, errorClosure: @escaping (SlackError) -> Void
) {
@@ -130,6 +141,7 @@ public struct NetworkInterface {
let boundaryConstant = randomBoundary()
let contentType = "multipart/form-data; boundary=" + boundaryConstant
request.setValue(contentType, forHTTPHeaderField: "Content-Type")
request.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
request.httpBody = requestBodyData(data: data, boundaryConstant: boundaryConstant, filename: filename, filetype: filetype)
session.dataTask(with: request) {(data, response, publicError) in
+204 -202
View File
@@ -71,34 +71,6 @@ public final class WebAPI {
// MARK: - RTM
extension WebAPI {
public static func rtmStart(
token: String,
batchPresenceAware: Bool = false,
mpimAware: Bool? = nil,
noLatest: Bool = false,
noUnreads: Bool? = nil,
presenceSub: Bool = false,
simpleLatest: Bool? = nil,
success: ((_ response: [String: Any]) -> Void)?,
failure: FailureClosure?
) {
let parameters: [String: Any?] =
[
"token": token,
"batch_presence_aware": batchPresenceAware,
"mpim_aware": mpimAware,
"no_latest": noLatest,
"no_unreads": noUnreads,
"presence_sub": presenceSub,
"simple_latest": simpleLatest
]
NetworkInterface().request(.rtmStart, parameters: parameters, successClosure: {(response) in
success?(response)
}) {(error) in
failure?(error)
}
}
public static func rtmConnect(
token: String,
batchPresenceAware: Bool = false,
@@ -108,11 +80,10 @@ extension WebAPI {
) {
let parameters: [String: Any?] =
[
"token": token,
"batch_presence_aware": batchPresenceAware,
"presence_sub": presenceSub
]
NetworkInterface().request(.rtmConnect, parameters: parameters, successClosure: {(response) in
NetworkInterface().request(.rtmConnect, accessToken: token, parameters: parameters, successClosure: {(response) in
success?(response)
}) {(error) in
failure?(error)
@@ -124,7 +95,7 @@ extension WebAPI {
// MARK: - Auth
extension WebAPI {
public func authenticationTest(success: AuthTestClosure?, failure: FailureClosure?) {
networkInterface.request(.authTest, parameters: ["token": token], successClosure: { (response) in
networkInterface.request(.authTest, accessToken: token, parameters: [:], successClosure: { (response) in
success?(response["user_id"] as? String, response["team_id"] as? String)
}) {(error) in
failure?(error)
@@ -142,8 +113,8 @@ extension WebAPI {
success: SuccessClosure?,
failure: FailureClosure?
) {
let parameters: [String: Any?] = ["token": token, "test": test]
NetworkInterface().request(.authRevoke, parameters: parameters, successClosure: { _ in
let parameters: [String: Any?] = ["test": test]
NetworkInterface().request(.authRevoke, accessToken: token, parameters: parameters, successClosure: { _ in
success?(true)
}) {(error) in
failure?(error)
@@ -174,56 +145,11 @@ extension WebAPI {
failure?(error)
}
}
public func channelInfo(id: String, success: ChannelClosure?, failure: FailureClosure?) {
info(.channelsInfo, type:.channel, id: id, success: {(channel) in
success?(channel)
}) {(error) in
failure?(error)
}
}
public func channelsList(
excludeArchived: Bool = false,
excludeMembers: Bool = false,
success: ((_ channels: [[String: Any]]?) -> Void)?,
failure: FailureClosure?
) {
list(.channelsList, type:.channel, excludeArchived: excludeArchived, excludeMembers: excludeMembers, success: {(channels) in
success?(channels)
}) {(error) in
failure?(error)
}
}
public func markChannel(channel: String, timestamp: String, success: ((_ ts: String) -> Void)?, failure: FailureClosure?) {
mark(.channelsMark, channel: channel, timestamp: timestamp, success: {(ts) in
success?(ts)
}) {(error) in
failure?(error)
}
}
public func createChannel(channel: String, success: ChannelClosure?, failure: FailureClosure?) {
create(.channelsCreate, name: channel, success: success, failure: failure)
}
public func inviteToChannel(_ channel: String, user: String, success: SuccessClosure?, failure: FailureClosure?) {
invite(.channelsInvite, channel: channel, user: user, success: success, failure: failure)
}
public func channelsJoin(_ name: String, validate: Bool, success: ChannelClosure?, failure: FailureClosure?) {
join(.channelsJoin, name: name, validate: validate, success: success, failure: failure)
}
public func channelsLeave(_ channel: String, success: SuccessClosure?, failure: FailureClosure?) {
leave(.channelsLeave, channel: channel, success: success, failure: failure)
}
public func channelsArchive(_ channel: String, success: SuccessClosure?, failure: FailureClosure?) {
archive(.channelsArchive, channel: channel, success: success, failure: failure)
}
public func channelsUnarchive(_ channel: String, success: SuccessClosure?, failure: FailureClosure?) {
unarchive(.channelsUnarchive, channel: channel, success: success, failure: failure)
}
@@ -256,8 +182,8 @@ extension WebAPI {
// MARK: - Messaging
extension WebAPI {
public func deleteMessage(channel: String, ts: String, success: SuccessClosure?, failure: FailureClosure?) {
let parameters: [String: Any] = ["token": token, "channel": channel, "ts": ts]
networkInterface.request(.chatDelete, parameters: parameters, successClosure: { _ in
let parameters: [String: Any] = ["channel": channel, "ts": ts]
networkInterface.request(.chatDelete, accessToken: token, parameters: parameters, successClosure: { _ in
success?(true)
}) {(error) in
failure?(error)
@@ -281,7 +207,6 @@ extension WebAPI {
failure: FailureClosure?
) {
let parameters: [String: Any?] = [
"token": token,
"channel": channel,
"text": text,
"as_user": asUser,
@@ -295,7 +220,7 @@ extension WebAPI {
"attachments": encodeAttachments(attachments),
"blocks": encodeBlocks(blocks)
]
networkInterface.request(.chatPostMessage, parameters: parameters, successClosure: {(response) in
networkInterface.request(.chatPostMessage, accessToken: token, parameters: parameters, successClosure: {(response) in
success?((ts: response["ts"] as? String, response["channel"] as? String))
}) {(error) in
failure?(error)
@@ -320,7 +245,6 @@ extension WebAPI {
failure: FailureClosure?
) {
let parameters: [String: Any?] = [
"token": token,
"channel": channel,
"thread_ts": thread,
"text": text,
@@ -335,7 +259,7 @@ extension WebAPI {
"icon_emoji": iconEmoji,
"attachments": encodeAttachments(attachments)
]
networkInterface.request(.chatPostMessage, parameters: parameters, successClosure: {(response) in
networkInterface.request(.chatPostMessage, accessToken: token, parameters: parameters, successClosure: {(response) in
success?((ts: response["ts"] as? String, response["channel"] as? String))
}) {(error) in
failure?(error)
@@ -356,7 +280,6 @@ extension WebAPI {
failure: FailureClosure?
) {
let parameters: [String: Any?] = [
"token": token,
"channel": channel,
"text": text,
"user": user,
@@ -367,7 +290,7 @@ extension WebAPI {
"link_names": linkNames,
"parse": parse?.rawValue,
]
networkInterface.request(.chatPostEphemeral, parameters: parameters, successClosure: {(response) in
networkInterface.request(.chatPostEphemeral, accessToken: token, parameters: parameters, successClosure: {(response) in
success?((ts: response["message_ts"] as? String, response["channel"] as? String))
}) {(error) in
failure?(error)
@@ -380,8 +303,8 @@ extension WebAPI {
success: (((ts: String?, channel: String?)) -> Void)?,
failure: FailureClosure?
) {
let parameters: [String: Any?] = ["token": token, "channel": channel, "text": text]
networkInterface.request(.chatMeMessage, parameters: parameters, successClosure: {(response) in
let parameters: [String: Any?] = ["channel": channel, "text": text]
networkInterface.request(.chatMeMessage, accessToken: token, parameters: parameters, successClosure: {(response) in
success?((ts: response["ts"] as? String, response["channel"] as? String))
}) {(error) in
failure?(error)
@@ -399,7 +322,6 @@ extension WebAPI {
failure: FailureClosure?
) {
let parameters: [String: Any?] = [
"token": token,
"channel": channel,
"ts": ts,
"text": message,
@@ -407,7 +329,7 @@ extension WebAPI {
"link_names": linkNames,
"attachments": encodeAttachments(attachments)
]
networkInterface.request(.chatUpdate, parameters: parameters, successClosure: { _ in
networkInterface.request(.chatUpdate, accessToken: token, parameters: parameters, successClosure: { _ in
success?(true)
}) {(error) in
failure?(error)
@@ -418,8 +340,8 @@ extension WebAPI {
// MARK: - Do Not Disturb
extension WebAPI {
public func dndInfo(user: String? = nil, success: ((_ status: DoNotDisturbStatus) -> Void)?, failure: FailureClosure?) {
let parameters: [String: Any?] = ["token": token, "user": user]
networkInterface.request(.dndInfo, parameters: parameters, successClosure: {(response) in
let parameters: [String: Any?] = ["user": user]
networkInterface.request(.dndInfo, accessToken: token, parameters: parameters, successClosure: {(response) in
success?(DoNotDisturbStatus(status: response))
}) {(error) in
failure?(error)
@@ -431,8 +353,8 @@ extension WebAPI {
success: ((_ statuses: [String: DoNotDisturbStatus]) -> Void)?,
failure: FailureClosure?
) {
let parameters: [String: Any?] = ["token": token, "users": users?.joined(separator: ",")]
networkInterface.request(.dndTeamInfo, parameters: parameters, successClosure: {(response) in
let parameters: [String: Any?] = ["users": users?.joined(separator: ",")]
networkInterface.request(.dndTeamInfo, accessToken: token, parameters: parameters, successClosure: {(response) in
guard let usersDictionary = response["users"] as? [String: Any] else {
success?([:])
return
@@ -447,7 +369,7 @@ extension WebAPI {
// MARK: - Emoji
extension WebAPI {
public func emojiList(success: ((_ emojiList: [String: Any]?) -> Void)?, failure: FailureClosure?) {
networkInterface.request(.emojiList, parameters: ["token": token], successClosure: {(response) in
networkInterface.request(.emojiList, accessToken: token, parameters: [:], successClosure: {(response) in
success?(response["emoji"] as? [String: Any])
}) {(error) in
failure?(error)
@@ -458,8 +380,8 @@ extension WebAPI {
// MARK: - Files
extension WebAPI {
public func deleteFile(fileID: String, success: SuccessClosure?, failure: FailureClosure?) {
let parameters = ["token": token, "file": fileID]
networkInterface.request(.filesDelete, parameters: parameters, successClosure: { _ in
let parameters = ["file": fileID]
networkInterface.request(.filesDelete, accessToken: token, parameters: parameters, successClosure: { _ in
success?(true)
}) {(error) in
failure?(error)
@@ -473,8 +395,8 @@ extension WebAPI {
success: FileClosure?,
failure: FailureClosure?
) {
let parameters: [String: Any] = ["token": token, "file": fileID, "count": count, "page": page]
networkInterface.request(.filesInfo, parameters: parameters, successClosure: {(response) in
let parameters: [String: Any] = ["file": fileID, "count": count, "page": page]
networkInterface.request(.filesInfo, accessToken: token, parameters: parameters, successClosure: {(response) in
var file = File(file: response["file"] as? [String: Any])
(response["comments"] as? [[String: Any]])?.forEach { comment in
let comment = Comment(comment: comment)
@@ -500,7 +422,6 @@ extension WebAPI {
failure: FailureClosure?
) {
let parameters: [String: Any?] = [
"token": token,
"filename": filename,
"filetype": filetype,
"title": title,
@@ -508,7 +429,7 @@ extension WebAPI {
"channels": channels?.joined(separator: ","),
"thread_ts": ts
]
networkInterface.uploadRequest(data: file, parameters: parameters, successClosure: {(response) in
networkInterface.uploadRequest(data: file, accessToken: token, parameters: parameters, successClosure: {(response) in
success?(File(file: response["file"] as? [String: Any]))
}) {(error) in
failure?(error)
@@ -519,8 +440,8 @@ extension WebAPI {
// MARK: - File Comments
extension WebAPI {
public func addFileComment(fileID: String, comment: String, success: CommentClosure?, failure: FailureClosure?) {
let parameters: [String: Any] = ["token": token, "file": fileID, "comment": comment]
networkInterface.request(.filesCommentsAdd, parameters: parameters, successClosure: {(response) in
let parameters: [String: Any] = ["file": fileID, "comment": comment]
networkInterface.request(.filesCommentsAdd, accessToken: token, parameters: parameters, successClosure: {(response) in
success?(Comment(comment: response["comment"] as? [String: Any]))
}) {(error) in
failure?(error)
@@ -528,8 +449,8 @@ extension WebAPI {
}
public func editFileComment(fileID: String, commentID: String, comment: String, success: CommentClosure?, failure: FailureClosure?) {
let parameters: [String: Any] = ["token": token, "file": fileID, "id": commentID, "comment": comment]
networkInterface.request(.filesCommentsEdit, parameters: parameters, successClosure: {(response) in
let parameters: [String: Any] = ["file": fileID, "id": commentID, "comment": comment]
networkInterface.request(.filesCommentsEdit, accessToken: token, parameters: parameters, successClosure: {(response) in
success?(Comment(comment: response["comment"] as? [String: Any]))
}) {(error) in
failure?(error)
@@ -537,8 +458,8 @@ extension WebAPI {
}
public func deleteFileComment(fileID: String, commentID: String, success: SuccessClosure?, failure: FailureClosure?) {
let parameters: [String: Any] = ["token": token, "file": fileID, "id": commentID]
networkInterface.request(.filesCommentsDelete, parameters: parameters, successClosure: { _ in
let parameters: [String: Any] = ["file": fileID, "id": commentID]
networkInterface.request(.filesCommentsDelete, accessToken: token, parameters: parameters, successClosure: { _ in
success?(true)
}) {(error) in
failure?(error)
@@ -610,8 +531,8 @@ extension WebAPI {
}
public func openGroup(channel: String, success: SuccessClosure?, failure: FailureClosure?) {
let parameters = ["token": token, "channel": channel]
networkInterface.request(.groupsOpen, parameters: parameters, successClosure: { _ in
let parameters = ["channel": channel]
networkInterface.request(.groupsOpen, accessToken: token, parameters: parameters, successClosure: { _ in
success?(true)
}) {(error) in
failure?(error)
@@ -689,16 +610,6 @@ extension WebAPI {
failure?(error)
}
}
public func openIM(userID: String, success: ((_ imID: String?) -> Void)?, failure: FailureClosure?) {
let parameters = ["token": token, "user": userID]
networkInterface.request(.imOpen, parameters: parameters, successClosure: {(response) in
let group = response["channel"] as? [String: Any]
success?(group?["id"] as? String)
}) {(error) in
failure?(error)
}
}
}
// MARK: - MPIM
@@ -757,8 +668,8 @@ extension WebAPI {
}
public func openMPIM(userIDs: [String], success: ((_ mpimID: String?) -> Void)?, failure: FailureClosure?) {
let parameters = ["token": token, "users": userIDs.joined(separator: ",")]
networkInterface.request(.mpimOpen, parameters: parameters, successClosure: {(response) in
let parameters = ["users": userIDs.joined(separator: ",")]
networkInterface.request(.mpimOpen, accessToken: token, parameters: parameters, successClosure: {(response) in
let group = response["group"] as? [String: Any]
success?(group?["id"] as? String)
}) {(error) in
@@ -775,10 +686,9 @@ extension WebAPI {
failure: FailureClosure?
) {
let parameters: [String: Any?] = [
"token": token,
"channel": channel
]
networkInterface.request(.pinsList, parameters: parameters, successClosure: { response in
networkInterface.request(.pinsList, accessToken: token, parameters: parameters, successClosure: { response in
let items = response["items"] as? [[String: Any]]
success?(items?.map({ Item(item: $0) }))
}) {(error) in
@@ -826,13 +736,12 @@ extension WebAPI {
failure: FailureClosure?
) {
let parameters: [String: Any?] = [
"token": token,
"channel": channel,
"file": file,
"file_comment": fileComment,
"timestamp": timestamp
]
networkInterface.request(endpoint, parameters: parameters, successClosure: { _ in
networkInterface.request(endpoint, accessToken: token, parameters: parameters, successClosure: { _ in
success?(true)
}) {(error) in
failure?(error)
@@ -915,14 +824,13 @@ extension WebAPI {
failure: FailureClosure?
) {
let parameters: [String: Any?] = [
"token": token,
"name": name,
"file": file,
"file_comment": fileComment,
"channel": channel,
"timestamp": timestamp
]
networkInterface.request(endpoint, parameters: parameters, successClosure: { _ in
networkInterface.request(endpoint, accessToken: token, parameters: parameters, successClosure: { _ in
success?(true)
}) {(error) in
failure?(error)
@@ -962,14 +870,13 @@ extension WebAPI {
failure: FailureClosure?
) {
let parameters: [String: Any?] = [
"token": token,
"file": file,
"file_comment": comment,
"channel": channel,
"timestamp": timestamp,
"full": full
]
networkInterface.request(.reactionsGet, parameters: parameters, successClosure: {(response) in
networkInterface.request(.reactionsGet, accessToken: token, parameters: parameters, successClosure: {(response) in
guard let item = response[type.rawValue] as? [String: Any] else {
reactions?([])
return
@@ -999,13 +906,12 @@ extension WebAPI {
failure: FailureClosure?
) {
let parameters: [String: Any?] = [
"token": token,
"user": user,
"full": full,
"count": count,
"page": page
]
networkInterface.request(.reactionsList, parameters: parameters, successClosure: {(response) in
networkInterface.request(.reactionsList, accessToken: token, parameters: parameters, successClosure: {(response) in
let items = response["items"] as? [[String: Any]]
success?(items?.map({ Item(item: $0) }))
}) {(error) in
@@ -1088,13 +994,12 @@ extension WebAPI {
failure: FailureClosure?
) {
let parameters: [String: Any?] = [
"token": token,
"file": file,
"file_comment": fileComment,
"channel": channel,
"timestamp": timestamp
]
networkInterface.request(endpoint, parameters: parameters, successClosure: { _ in
networkInterface.request(endpoint, accessToken: token, parameters: parameters, successClosure: { _ in
success?(true)
}) {(error) in
failure?(error)
@@ -1105,7 +1010,7 @@ extension WebAPI {
// MARK: - Team
extension WebAPI {
public func teamInfo(success: ((_ info: [String: Any]?) -> Void)?, failure: FailureClosure?) {
networkInterface.request(.teamInfo, parameters: ["token": token], successClosure: {(response) in
networkInterface.request(.teamInfo, accessToken: token, parameters: [:], successClosure: {(response) in
success?(response["team"] as? [String: Any])
}) {(error) in
failure?(error)
@@ -1125,14 +1030,13 @@ extension WebAPI {
failure: FailureClosure?
) {
let parameters: [String: Any?] = [
"token": token,
"cursor": cursor,
"exclude_archived": excludeArchived,
"limit": limit,
"types": types?.map({ $0.rawValue }).joined(separator: ","),
"user": userID
]
networkInterface.request(.usersConversations, parameters: parameters, successClosure: {(response) in
networkInterface.request(.usersConversations, accessToken: token, parameters: parameters, successClosure: {(response) in
let channels: [Channel] = (response["channels"] as? [[String: Any]])?.map{Channel(channel: $0)} ?? []
success?(channels, (response["response_metadata"] as? [String: Any])?["next_cursor"] as? String)
}) {(error) in
@@ -1141,8 +1045,8 @@ extension WebAPI {
}
public func userPresence(user: String, success: ((_ presence: String?) -> Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["token": token, "user": user]
networkInterface.request(.usersGetPresence, parameters: parameters, successClosure: {(response) in
let parameters: [String: Any] = ["user": user]
networkInterface.request(.usersGetPresence, accessToken: token, parameters: parameters, successClosure: {(response) in
success?(response["presence"] as? String)
}) {(error) in
failure?(error)
@@ -1150,8 +1054,8 @@ extension WebAPI {
}
public func userInfo(id: String, success: ((_ user: User) -> Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["token": token, "user": id]
networkInterface.request(.usersInfo, parameters: parameters, successClosure: {(response) in
let parameters: [String: Any] = ["user": id]
networkInterface.request(.usersInfo, accessToken: token, parameters: parameters, successClosure: {(response) in
success?(User(user: response["user"] as? [String: Any]))
}) {(error) in
failure?(error)
@@ -1163,7 +1067,7 @@ extension WebAPI {
includePresence: Bool = false,
success: ((_ userList: [[String: Any]]?, _ nextCursor: String?) -> Void)?,
failure: FailureClosure?) {
var parameters: [String: Any] = ["token": token, "presence": includePresence]
var parameters: [String: Any] = ["presence": includePresence]
if let cursor = cursor {
parameters["cursor"] = cursor
}
@@ -1171,7 +1075,7 @@ extension WebAPI {
parameters["limit"] = limit
}
networkInterface.request(.usersList, parameters: parameters, successClosure: {(response) in
networkInterface.request(.usersList, accessToken: token, parameters: parameters, successClosure: {(response) in
success?(response["members"] as? [[String: Any]], (response["response_metadata"] as? [String: Any])?["next_cursor"] as? String)
}) {(error) in
failure?(error)
@@ -1179,8 +1083,8 @@ extension WebAPI {
}
public func usersLookupByEmail(_ email: String, success: ((_ user: User) -> Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["token": token, "email": email]
networkInterface.request(.usersLookupByEmail, parameters: parameters, successClosure: { response in
let parameters: [String: Any] = ["email": email]
networkInterface.request(.usersLookupByEmail, accessToken: token, parameters: parameters, successClosure: { response in
success?(User(user: response["user"] as? [String: Any]))
}) { error in
failure?(error)
@@ -1196,28 +1100,19 @@ extension WebAPI {
"phone": profile.phone,
"status_text": profile.statusText,
"status_emoji": profile.statusEmoji,
"status_expiration": profile.statusExpiration,
"status_expiration": profile.statusExpiration
] as [String: Any?])
.filter { $0.value != nil }
.mapValues { $0! }
do {
let data = try JSONSerialization.data(withJSONObject: profileValues)
let json = String(data: data, encoding: .utf8)
guard let encodedJSON = json?.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {
throw SlackError.clientJSONError
}
var urlComponents = URLComponents(string: "https://slack.com/api/users.profile.set")
urlComponents?.queryItems = [
URLQueryItem(name: "token", value: token),
URLQueryItem(name: "profile", value: encodedJSON)
]
let data = try JSONSerialization.data(withJSONObject: ["profile": profileValues])
let urlComponents = URLComponents(string: "https://slack.com/api/users.profile.set")
guard let requestString = urlComponents?.url?.absoluteString else {
throw SlackError.clientNetworkError
}
networkInterface.customRequest(requestString, data: Data(), success: { _ in
networkInterface.customRequest(requestString, token: token, data: data, success: { _ in
success?(true)
}) {(error) in
failure?(error)
@@ -1228,7 +1123,7 @@ extension WebAPI {
}
public func setUserActive(success: SuccessClosure?, failure: FailureClosure?) {
networkInterface.request(.usersSetActive, parameters: ["token": token], successClosure: { _ in
networkInterface.request(.usersSetActive, accessToken: token, parameters: [:], successClosure: { _ in
success?(true)
}) {(error) in
failure?(error)
@@ -1236,8 +1131,8 @@ extension WebAPI {
}
public func setUserPresence(presence: Presence, success: SuccessClosure?, failure: FailureClosure?) {
let parameters: [String: Any] = ["token": token, "presence": presence.rawValue]
networkInterface.request(.usersSetPresence, parameters: parameters, successClosure: { _ in
let parameters: [String: Any] = ["presence": presence.rawValue]
networkInterface.request(.usersSetPresence, accessToken: token, parameters: parameters, successClosure: { _ in
success?(true)
}) {(error) in
failure?(error)
@@ -1247,6 +1142,35 @@ extension WebAPI {
// MARK: - Conversations
extension WebAPI {
public func conversationsArchive(channel: String, success: (() -> Void)?, failure: FailureClosure?) {
let parameters = ["channel": channel]
networkInterface.request(.conversationsArchive, accessToken: token, parameters: parameters, successClosure: {_ in }) {(error) in
failure?(error)
}
}
public func conversationsCreate(
name: String,
isPrivate: Bool = false,
success: ((_ id: String?, _ name: String?, _ creator: String?) -> Void)?,
failure: FailureClosure?
) {
let parameters = [
"name": name,
"is_private": isPrivate
] as [String : Any]
networkInterface.request(.conversationsOpen, accessToken: token, parameters: parameters, successClosure: {(response) in
let group = response["channel"] as? [String: Any]
success?(
group?["id"] as? String,
group?["name"] as? String,
group?["creator"] as? String
)
}) {(error) in
failure?(error)
}
}
public func conversationsList(
excludeArchived: Bool = false,
cursor: String? = nil,
@@ -1255,7 +1179,7 @@ extension WebAPI {
success: ((_ channels: [[String: Any]]?, _ nextCursor: String?) -> Void)?,
failure: FailureClosure?
) {
var parameters: [String: Any] = ["token": token, "exclude_archived": excludeArchived]
var parameters: [String: Any] = ["exclude_archived": excludeArchived]
if let cursor = cursor {
parameters["cursor"] = cursor
}
@@ -1265,7 +1189,7 @@ extension WebAPI {
if let types = types {
parameters["types"] = types.map({ $0.rawValue }).joined(separator: ",")
}
networkInterface.request(.conversationsList, parameters: parameters, successClosure: {(response) in
networkInterface.request(.conversationsList, accessToken: token, parameters: parameters, successClosure: {(response) in
success?(response["channels"] as? [[String: Any]], (response["response_metadata"] as? [String: Any])?["next_cursor"] as? String)
}) {(error) in
failure?(error)
@@ -1284,7 +1208,6 @@ extension WebAPI {
failure: FailureClosure?
) {
var parameters: [String: Any] = [
"token": token,
"channel": id,
"ts": ts,
"inclusive": inclusive,
@@ -1295,7 +1218,7 @@ extension WebAPI {
if let cursor = cursor {
parameters["cursor"] = cursor
}
networkInterface.request(.conversationsReplies, parameters: parameters, successClosure: {(response) in
networkInterface.request(.conversationsReplies, accessToken: token, parameters: parameters, successClosure: {(response) in
success?(response["messages"] as? [[String: Any]], (response["response_metadata"] as? [String: Any])?["next_cursor"] as? String)
}) {(error) in
failure?(error)
@@ -1310,7 +1233,6 @@ extension WebAPI {
failure: FailureClosure?
) {
var parameters: [String: Any] = [
"token": token,
"channel": id
]
if let cursor = cursor {
@@ -1319,7 +1241,7 @@ extension WebAPI {
if let limit = limit {
parameters["limit"] = limit
}
networkInterface.request(.conversationsMembers, parameters: parameters, successClosure: {(response) in
networkInterface.request(.conversationsMembers, accessToken: token, parameters: parameters, successClosure: {(response) in
success?(response["members"] as? [String], (response["response_metadata"] as? [String: Any])?["next_cursor"] as? String)
}) {(error) in
failure?(error)
@@ -1337,7 +1259,6 @@ extension WebAPI {
failure: FailureClosure?
) {
var parameters: [String: Any] = [
"token": token,
"channel": id,
"inclusive": inclusive,
"limit": limit,
@@ -1347,12 +1268,28 @@ extension WebAPI {
if let cursor = cursor {
parameters["cursor"] = cursor
}
networkInterface.request(.conversationsHistory, parameters: parameters, successClosure: {(response) in
networkInterface.request(.conversationsHistory, accessToken: token, parameters: parameters, successClosure: {(response) in
success?(response["messages"] as? [[String: Any]], (response["response_metadata"] as? [String: Any])?["next_cursor"] as? String)
}) {(error) in
failure?(error)
}
}
public func conversationsOpen(
userIDs: [String],
success: ((_ imID: String?) -> Void)?,
failure: FailureClosure?
) {
let parameters = [
"users": userIDs.joined(separator: ",")
]
networkInterface.request(.conversationsOpen, accessToken: token, parameters: parameters, successClosure: {(response) in
let group = response["channel"] as? [String: Any]
success?(group?["id"] as? String)
}) {(error) in
failure?(error)
}
}
}
// MARK: - Search
@@ -1377,7 +1314,6 @@ extension WebAPI {
failure: FailureClosure?
) {
let parameters: [String: Any] = [
"token": token,
"query": query,
"count": count,
"highlight": highlight,
@@ -1385,7 +1321,7 @@ extension WebAPI {
"sort": sort.rawValue,
"sort_dir": sortDir.rawValue,
]
networkInterface.request(.searchAll, parameters: parameters, successClosure: { (response) in
networkInterface.request(.searchAll, accessToken: token, parameters: parameters, successClosure: { (response) in
success?(
(response["files"] as? [String : Any])?["matches"] as? [[String : Any]],
(response["messages"] as? [String : Any])?["matches"] as? [[String : Any]]
@@ -1406,7 +1342,6 @@ extension WebAPI {
failure: FailureClosure?
) {
let parameters: [String: Any] = [
"token": token,
"query": query,
"count": count,
"highlight": highlight,
@@ -1414,7 +1349,7 @@ extension WebAPI {
"sort": sort.rawValue,
"sort_dir": sortDir.rawValue,
]
networkInterface.request(.searchFiles, parameters: parameters, successClosure: { (response) in
networkInterface.request(.searchFiles, accessToken: token, parameters: parameters, successClosure: { (response) in
success?(
(response["files"] as? [String : Any])?["matches"] as? [[String : Any]]
)
@@ -1434,7 +1369,6 @@ extension WebAPI {
failure: FailureClosure?
) {
let parameters: [String: Any] = [
"token": token,
"query": query,
"count": count,
"highlight": highlight,
@@ -1442,7 +1376,7 @@ extension WebAPI {
"sort": sort.rawValue,
"sort_dir": sortDir.rawValue,
]
networkInterface.request(.searchMessages, parameters: parameters, successClosure: { (response) in
networkInterface.request(.searchMessages, accessToken: token, parameters: parameters, successClosure: { (response) in
success?(
(response["messages"] as? [String : Any])?["matches"] as? [[String : Any]]
)
@@ -1494,8 +1428,8 @@ extension WebAPI {
}
fileprivate func close(_ endpoint: Endpoint, channelID: String, success: SuccessClosure?, failure: FailureClosure?) {
let parameters: [String: Any] = ["token": token, "channel": channelID]
networkInterface.request(endpoint, parameters: parameters, successClosure: { _ in
let parameters: [String: Any] = ["channel": channelID]
networkInterface.request(endpoint, accessToken: token, parameters: parameters, successClosure: { _ in
success?(true)
}) {(error) in
failure?(error)
@@ -1514,7 +1448,6 @@ extension WebAPI {
failure: FailureClosure?
) {
let parameters: [String: Any] = [
"token": token,
"channel": id,
"latest": latest,
"oldest": oldest,
@@ -1522,7 +1455,7 @@ extension WebAPI {
"count": count,
"unreads": unreads
]
networkInterface.request(endpoint, parameters: parameters, successClosure: {(response) in
networkInterface.request(endpoint, accessToken: token, parameters: parameters, successClosure: {(response) in
success?(History(history: response))
}) {(error) in
failure?(error)
@@ -1536,8 +1469,8 @@ extension WebAPI {
success: ChannelClosure?,
failure: FailureClosure?
) {
let parameters: [String: Any] = ["token": token, "channel": id]
networkInterface.request(endpoint, parameters: parameters, successClosure: {(response) in
let parameters: [String: Any] = ["channel": id]
networkInterface.request(endpoint, accessToken: token, parameters: parameters, successClosure: {(response) in
success?(Channel(channel: response[type.rawValue] as? [String: Any]))
}) {(error) in
failure?(error)
@@ -1552,8 +1485,8 @@ extension WebAPI {
success: ((_ channels: [[String: Any]]?) -> Void)?,
failure: FailureClosure?
) {
let parameters: [String: Any] = ["token": token, "exclude_archived": excludeArchived, "exclude_members": excludeMembers]
networkInterface.request(endpoint, parameters: parameters, successClosure: {(response) in
let parameters: [String: Any] = ["exclude_archived": excludeArchived, "exclude_members": excludeMembers]
networkInterface.request(endpoint, accessToken: token, parameters: parameters, successClosure: {(response) in
success?(response[type.rawValue+"s"] as? [[String: Any]])
}) {(error) in
failure?(error)
@@ -1567,8 +1500,8 @@ extension WebAPI {
success: ((_ ts: String) -> Void)?,
failure: FailureClosure?
) {
let parameters: [String: Any] = ["token": token, "channel": channel, "ts": timestamp]
networkInterface.request(endpoint, parameters: parameters, successClosure: { _ in
let parameters: [String: Any] = ["channel": channel, "ts": timestamp]
networkInterface.request(endpoint, accessToken: token, parameters: parameters, successClosure: { _ in
success?(timestamp)
}) {(error) in
failure?(error)
@@ -1583,8 +1516,8 @@ extension WebAPI {
success: SuccessClosure?,
failure: FailureClosure?
) {
let parameters: [String: Any] = ["token": token, "channel": channel, type.rawValue: text]
networkInterface.request(endpoint, parameters: parameters, successClosure: { _ in
let parameters: [String: Any] = ["channel": channel, type.rawValue: text]
networkInterface.request(endpoint, accessToken: token, parameters: parameters, successClosure: { _ in
success?(true)
}) {(error) in
failure?(error)
@@ -1597,8 +1530,8 @@ extension WebAPI {
success: ChannelClosure?,
failure: FailureClosure?
) {
let parameters: [String: Any] = ["token": token, "name": name]
networkInterface.request(endpoint, parameters: parameters, successClosure: {(response) in
let parameters: [String: Any] = ["name": name]
networkInterface.request(endpoint, accessToken: token, parameters: parameters, successClosure: {(response) in
success?(Channel(channel: response["channel"] as? [String: Any]))
}) {(error) in
failure?(error)
@@ -1612,8 +1545,8 @@ extension WebAPI {
success: SuccessClosure?,
failure: FailureClosure?
) {
let parameters: [String: Any] = ["token": token, "channel": channel, "user": user]
networkInterface.request(endpoint, parameters: parameters, successClosure: { _ in
let parameters: [String: Any] = ["channel": channel, "user": user]
networkInterface.request(endpoint, accessToken: token, parameters: parameters, successClosure: { _ in
success?(true)
}) {(error) in
failure?(error)
@@ -1627,8 +1560,8 @@ extension WebAPI {
success: ChannelClosure?,
failure: FailureClosure?
) {
let parameters: [String: Any] = ["token": token, "name": name, "validate": validate]
networkInterface.request(endpoint, parameters: parameters, successClosure: { response in
let parameters: [String: Any] = ["name": name, "validate": validate]
networkInterface.request(endpoint, accessToken: token, parameters: parameters, successClosure: { response in
success?(Channel(channel: response["channel"] as? [String: Any]))
}) {(error) in
failure?(error)
@@ -1641,8 +1574,8 @@ extension WebAPI {
success: SuccessClosure?,
failure: FailureClosure?
) {
let parameters: [String: Any] = ["token": token, "channel": channel]
networkInterface.request(endpoint, parameters: parameters,successClosure: { _ in
let parameters: [String: Any] = ["channel": channel]
networkInterface.request(endpoint, accessToken: token, parameters: parameters,successClosure: { _ in
success?(true)
}) {(error) in
failure?(error)
@@ -1655,8 +1588,8 @@ extension WebAPI {
success: SuccessClosure?,
failure: FailureClosure?
) {
let parameters: [String: Any] = ["token": token, "channel": channel]
networkInterface.request(endpoint, parameters: parameters,successClosure: { _ in
let parameters: [String: Any] = ["channel": channel]
networkInterface.request(endpoint, accessToken: token, parameters: parameters,successClosure: { _ in
success?(true)
}) {(error) in
failure?(error)
@@ -1669,8 +1602,8 @@ extension WebAPI {
success: SuccessClosure?,
failure: FailureClosure?
) {
let parameters: [String: Any] = ["token": token, "channel": channel]
networkInterface.request(endpoint, parameters: parameters,successClosure: { _ in
let parameters: [String: Any] = ["channel": channel]
networkInterface.request(endpoint, accessToken: token, parameters: parameters,successClosure: { _ in
success?(true)
}) {(error) in
failure?(error)
@@ -1685,8 +1618,8 @@ extension WebAPI {
success: ChannelClosure?,
failure: FailureClosure?
) {
let parameters: [String: Any] = ["token": token, "channel": channel, "name": name, "validate": validate ]
networkInterface.request(endpoint, parameters: parameters,successClosure: { response in
let parameters: [String: Any] = ["channel": channel, "name": name, "validate": validate ]
networkInterface.request(endpoint, accessToken: token, parameters: parameters,successClosure: { response in
success?(Channel(channel: response["channel"] as? [String: Any]))
}) {(error) in
failure?(error)
@@ -1700,11 +1633,80 @@ extension WebAPI {
success: SuccessClosure?,
failure: FailureClosure?
) {
let parameters: [String: Any] = ["token": token, "channel": channel, "user": user]
networkInterface.request(endpoint, parameters: parameters,successClosure: { _ in
let parameters: [String: Any] = ["channel": channel, "user": user]
networkInterface.request(endpoint, accessToken: token, parameters: parameters,successClosure: { _ in
success?(true)
}) {(error) in
failure?(error)
}
}
}
// MARK: - Deprecated
extension WebAPI {
// MARK: channels.*
@available(*, deprecated, message: "Use conversationsArchive instead.")
public func channelsArchive(_ channel: String, success: SuccessClosure?, failure: FailureClosure?) {
archive(.channelsArchive, channel: channel, success: success, failure: failure)
}
@available(*, deprecated, message: "Use conversationsCreate instead.")
public func createChannel(channel: String, success: ChannelClosure?, failure: FailureClosure?) {
create(.channelsCreate, name: channel, success: success, failure: failure)
}
@available(*, deprecated)
public func channelInfo(id: String, success: ChannelClosure?, failure: FailureClosure?) {
info(.channelsInfo, type:.channel, id: id, success: {(channel) in
success?(channel)
}) {(error) in
failure?(error)
}
}
@available(*, deprecated)
public func inviteToChannel(_ channel: String, user: String, success: SuccessClosure?, failure: FailureClosure?) {
invite(.channelsInvite, channel: channel, user: user, success: success, failure: failure)
}
@available(*, deprecated)
public func channelsJoin(_ name: String, validate: Bool, success: ChannelClosure?, failure: FailureClosure?) {
join(.channelsJoin, name: name, validate: validate, success: success, failure: failure)
}
@available(*, deprecated)
public func channelsList(
excludeArchived: Bool = false,
excludeMembers: Bool = false,
success: ((_ channels: [[String: Any]]?) -> Void)?,
failure: FailureClosure?
) {
list(.channelsList, type:.channel, excludeArchived: excludeArchived, excludeMembers: excludeMembers, success: {(channels) in
success?(channels)
}) {(error) in
failure?(error)
}
}
@available(*, deprecated)
public func markChannel(channel: String, timestamp: String, success: ((_ ts: String) -> Void)?, failure: FailureClosure?) {
mark(.channelsMark, channel: channel, timestamp: timestamp, success: {(ts) in
success?(ts)
}) {(error) in
failure?(error)
}
}
// MARK: im.*
@available(*, deprecated, message: "Use conversationsOpen instead.")
public func openIM(userID: String, success: ((_ imID: String?) -> Void)?, failure: FailureClosure?) {
let parameters = ["user": userID]
networkInterface.request(.imOpen, accessToken: token, parameters: parameters, successClosure: {(response) in
let group = response["channel"] as? [String: Any]
success?(group?["id"] as? String)
}) {(error) in
failure?(error)
}
}
}
+2 -2
View File
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "SlackKit"
s.version = "4.6.0"
s.version = "4.7.0"
s.summary = "Write Slack apps in Swift"
s.homepage = "https://github.com/pvzig/SlackKit"
s.license = "MIT"
@@ -8,7 +8,7 @@ Pod::Spec.new do |s|
s.source = { :git => "https://github.com/pvzig/SlackKit.git", :tag => s.version.to_s }
s.social_media_url = "https://twitter.com/pvzig"
s.platforms = { :ios => '10.0', :osx => '10.11', :tvos => '10.0' }
s.swift_version = '5.2.4'
s.swift_version = '5.5.2'
s.cocoapods_version = '>= 1.4.0'
s.default_subspec = "SlackKit"
+4
View File
@@ -126,6 +126,7 @@
A20D15EC22DE158000044CFC /* BlockLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = A20D15E922DE158000044CFC /* BlockLayout.swift */; };
AD39B504252DFF0B000CF632 /* Swifter.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = AD39B503252DFF0A000CF632 /* Swifter.xcframework */; };
AD39B508252DFF1A000CF632 /* Starscream.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = AD39B507252DFF1A000CF632 /* Starscream.xcframework */; };
DBA0851E258F83DB000F4381 /* attachment.json in Resources */ = {isa = PBXBuildFile; fileRef = DBA0851D258F83DB000F4381 /* attachment.json */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -312,6 +313,7 @@
A20D15E922DE158000044CFC /* BlockLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlockLayout.swift; sourceTree = "<group>"; };
AD39B503252DFF0A000CF632 /* Swifter.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = Swifter.xcframework; sourceTree = "<group>"; };
AD39B507252DFF1A000CF632 /* Starscream.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = Starscream.xcframework; sourceTree = "<group>"; };
DBA0851D258F83DB000F4381 /* attachment.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = attachment.json; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -789,6 +791,7 @@
isa = PBXGroup;
children = (
9EA45FB822C01290006A6D36 /* action.json */,
DBA0851D258F83DB000F4381 /* attachment.json */,
9EEC459722BE789600206AC3 /* attachmentfield.json */,
26D4E6282220731800A67B67 /* channel.json */,
26D4E6222220731700A67B67 /* conversation.json */,
@@ -1135,6 +1138,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
DBA0851E258F83DB000F4381 /* attachment.json in Resources */,
2601B6CD2223038A00F197AB /* channel.json in Resources */,
9EA45FB922C01290006A6D36 /* action.json in Resources */,
2601B710222F766D00F197AB /* member_left_channel.json in Resources */,
+85
View File
@@ -0,0 +1,85 @@
{
"fallback": "any fallback",
"callback_id": "any callback_id",
"attachment_type": "any attachment_type",
"color": "any color",
"pretext": "any pretext",
"author_name": "any author_name",
"author_link": "any author_link",
"author_icon": "any author_icon",
"title": "any title",
"title_link": "any title_link",
"text": "any text",
"image_url": "any image_url",
"thumb_url": "any thumb_url",
"footer": "any footer",
"footer_icon": "any footer_icon",
"ts": 100,
"fields": [
{
"title": "any title",
"value": "any value",
"short": true
},
{
"title": "another title",
"value": "another value",
"short": false
}
],
"actions": [
{
"name": "any name",
"text": "any text",
"type": "any type",
"value": "any value",
"url": "any url",
"style": "primary",
"confirm":
{
"title": "any title",
"text": "any text",
"ok_text": "any ok text",
"dismiss_text": "any dismiss text"
},
"options":
[
{
"text": "any text 1",
"value": "any value 1"
},
{
"text": "any text 2",
"value": "any value 2"
}
],
"data_source": "channels"
},
{
"name": "another name",
"text": "another text",
"type": "another type",
"value": "another value",
"url": "another url",
"style": "default",
"confirm":
{
"title": "another title",
"text": "another text",
"ok_text": "another ok text",
"dismiss_text": "another dismiss text"
},
"options":
[
{
"text": "another text 1",
"value": "another value 1"
}
],
"data_source": "channels"
}
],
"mrkdwn_in": [
"fallback", "fields", "title", "fallback", "fields"
]
}
+53
View File
@@ -45,6 +45,7 @@ final class SKCoreTests: XCTestCase {
static let usergroup = try! Data(contentsOf: URL(fileURLWithPath: "\(rootPath)/usergroup.json"))
static let events = try! Data(contentsOf: URL(fileURLWithPath: "\(rootPath)/events.json"))
static let action = try! Data(contentsOf: URL(fileURLWithPath: "\(rootPath)/action.json"))
static let attachment = try! Data(contentsOf: URL(fileURLWithPath: "\(rootPath)/attachment.json"))
static let attachmentfield = try! Data(contentsOf: URL(fileURLWithPath: "\(rootPath)/attachmentfield.json"))
static let customprofilefield = try! Data(contentsOf: URL(fileURLWithPath: "\(rootPath)/customprofilefield.json"))
static let donotdisturbstatus = try! Data(contentsOf: URL(fileURLWithPath: "\(rootPath)/donotdisturbstatus.json"))
@@ -65,6 +66,7 @@ final class SKCoreTests: XCTestCase {
("testUserGroup", testUserGroup),
("testEvents", testEvents),
("testActionCodable", testActionCodable),
("testAttachmentCodable", testAttachmentCodable),
("testAttachmentFieldCodable", testAttachmentFieldCodable),
("testCustomProfileFieldCodable", testCustomProfileFieldCodable),
("testDoNotDisturbStatusCodable", testDoNotDisturbStatusCodable),
@@ -193,6 +195,57 @@ final class SKCoreTests: XCTestCase {
XCTAssertEqual(actionBySerialization.dataSource, actionByDecoder!.dataSource)
}
func testAttachmentCodable() {
let data = JSONData.attachment
let decoder = JSONDecoder()
let attachmentByDecoder = try? decoder.decode(Attachment.self, from: data)
XCTAssertNotNil(attachmentByDecoder)
XCTAssertNotNil(attachmentByDecoder!.fallback)
XCTAssertNotNil(attachmentByDecoder!.callbackID)
XCTAssertNotNil(attachmentByDecoder!.type)
XCTAssertNotNil(attachmentByDecoder!.color)
XCTAssertNotNil(attachmentByDecoder!.pretext)
XCTAssertNotNil(attachmentByDecoder!.authorName)
XCTAssertNotNil(attachmentByDecoder!.authorLink)
XCTAssertNotNil(attachmentByDecoder!.authorIcon)
XCTAssertNotNil(attachmentByDecoder!.title)
XCTAssertNotNil(attachmentByDecoder!.titleLink)
XCTAssertNotNil(attachmentByDecoder!.text)
XCTAssertNotNil(attachmentByDecoder!.fields)
XCTAssertNotNil(attachmentByDecoder!.actions)
XCTAssertNotNil(attachmentByDecoder!.imageURL)
XCTAssertNotNil(attachmentByDecoder!.thumbURL)
XCTAssertNotNil(attachmentByDecoder!.footer)
XCTAssertNotNil(attachmentByDecoder!.footerIcon)
XCTAssertNotNil(attachmentByDecoder!.ts)
XCTAssertNotNil(attachmentByDecoder!.markdownEnabledFields)
let encoder = JSONEncoder()
let jsonData = try? encoder.encode(attachmentByDecoder!)
XCTAssertNotNil(jsonData)
let attachment = try? JSONSerialization.jsonObject(with: jsonData!, options: []) as? [String: Any]
XCTAssertNotNil(attachment)
let attachmentBySerialization = Attachment(attachment: attachment)
XCTAssertEqual(attachmentBySerialization.fallback, attachmentByDecoder!.fallback)
XCTAssertEqual(attachmentBySerialization.callbackID, attachmentByDecoder!.callbackID)
XCTAssertEqual(attachmentBySerialization.type, attachmentByDecoder!.type)
XCTAssertEqual(attachmentBySerialization.color, attachmentByDecoder!.color)
XCTAssertEqual(attachmentBySerialization.pretext, attachmentByDecoder!.pretext)
XCTAssertEqual(attachmentBySerialization.authorName, attachmentByDecoder!.authorName)
XCTAssertEqual(attachmentBySerialization.authorLink, attachmentByDecoder!.authorLink)
XCTAssertEqual(attachmentBySerialization.authorIcon, attachmentByDecoder!.authorIcon)
XCTAssertEqual(attachmentBySerialization.title, attachmentByDecoder!.title)
XCTAssertEqual(attachmentBySerialization.titleLink, attachmentByDecoder!.titleLink)
XCTAssertEqual(attachmentBySerialization.text, attachmentByDecoder!.text)
XCTAssertEqual(attachmentBySerialization.fields, attachmentByDecoder!.fields)
XCTAssertEqual(attachmentBySerialization.actions, attachmentByDecoder!.actions)
XCTAssertEqual(attachmentBySerialization.imageURL, attachmentByDecoder!.imageURL)
XCTAssertEqual(attachmentBySerialization.thumbURL, attachmentByDecoder!.thumbURL)
XCTAssertEqual(attachmentBySerialization.footer, attachmentByDecoder!.footer)
XCTAssertEqual(attachmentBySerialization.footerIcon, attachmentByDecoder!.footerIcon)
XCTAssertEqual(attachmentBySerialization.ts, attachmentByDecoder!.ts)
XCTAssertEqual(attachmentBySerialization.markdownEnabledFields, attachmentByDecoder!.markdownEnabledFields)
}
func testAttachmentFieldCodable() {
let data = JSONData.attachmentfield
let decoder = JSONDecoder()
+1
View File
@@ -19,6 +19,7 @@ extension SKCoreTests {
("testUser", testUser),
("testUserGroup", testUserGroup),
("testActionCodable", testActionCodable),
("testAttachmentCodable", testAttachmentCodable),
("testAttachmentFieldCodable", testAttachmentFieldCodable),
("testCustomProfileFieldCodable", testCustomProfileFieldCodable),
("testDoNotDisturbStatusCodable", testDoNotDisturbStatusCodable),
+22 -23
View File
@@ -10,7 +10,7 @@ jobs:
# Builds
- job: macOS
pool:
vmImage: 'macOS-10.15'
vmImage: 'macOS-11'
steps:
- task: Xcode@5
inputs:
@@ -20,7 +20,7 @@ jobs:
configuration: 'Release'
xcWorkspacePath: 'SlackKit.xcodeproj/project.xcworkspace'
xcodeVersion: specifyPath
xcodeDeveloperDir: '/Applications/Xcode_12.4.app/Contents/Developer'
xcodeDeveloperDir: '/Applications/Xcode_13.0.app/Contents/Developer'
- task: Xcode@5
inputs:
actions: 'test'
@@ -29,10 +29,10 @@ jobs:
configuration: 'Debug'
xcWorkspacePath: 'SlackKit.xcodeproj/project.xcworkspace'
xcodeVersion: specifyPath
xcodeDeveloperDir: '/Applications/Xcode_12.4.app/Contents/Developer'
xcodeDeveloperDir: '/Applications/Xcode_13.0.app/Contents/Developer'
- job: iOS
pool:
vmImage: 'macOS-10.15'
vmImage: 'macOS-11'
steps:
- task: Xcode@5
inputs:
@@ -42,7 +42,7 @@ jobs:
configuration: 'Release'
xcWorkspacePath: 'SlackKit.xcodeproj/project.xcworkspace'
xcodeVersion: specifyPath
xcodeDeveloperDir: '/Applications/Xcode_12.4.app/Contents/Developer'
xcodeDeveloperDir: '/Applications/Xcode_13.0.app/Contents/Developer'
- task: Xcode@5
inputs:
actions: 'test'
@@ -51,15 +51,15 @@ jobs:
configuration: 'Debug'
xcWorkspacePath: 'SlackKit.xcodeproj/project.xcworkspace'
xcodeVersion: specifyPath
xcodeDeveloperDir: '/Applications/Xcode_12.4.app/Contents/Developer'
xcodeDeveloperDir: '/Applications/Xcode_13.0.app/Contents/Developer'
destinationPlatformOption: 'custom'
destinationPlatform: 'iOS'
destinationTypeOption: 'simulators'
destinationSimulators: 'iPhone 12 Pro,OS=14.4'
destinationSimulators: 'iPhone 13 Pro,OS=15.0'
- job: tvOS
pool:
vmImage: 'macOS-10.15'
vmImage: 'macOS-11'
steps:
- task: Xcode@5
inputs:
@@ -69,7 +69,7 @@ jobs:
configuration: 'Release'
xcWorkspacePath: 'SlackKit.xcodeproj/project.xcworkspace'
xcodeVersion: specifyPath
xcodeDeveloperDir: '/Applications/Xcode_12.4.app/Contents/Developer'
xcodeDeveloperDir: '/Applications/Xcode_13.0.app/Contents/Developer'
- task: Xcode@5
inputs:
actions: 'test'
@@ -78,29 +78,29 @@ jobs:
configuration: 'Debug'
xcWorkspacePath: 'SlackKit.xcodeproj/project.xcworkspace'
xcodeVersion: specifyPath
xcodeDeveloperDir: '/Applications/Xcode_12.4.app/Contents/Developer'
xcodeDeveloperDir: '/Applications/Xcode_13.0.app/Contents/Developer'
destinationPlatformOption: 'custom'
destinationPlatform: 'tvOS'
destinationTypeOption: 'simulators'
destinationSimulators: 'Apple TV 4K,OS=14.3'
destinationSimulators: 'Apple TV 4K,OS=15.0'
- job: Linux
pool:
vmImage: 'ubuntu-16.04'
vmImage: 'ubuntu-18.04'
steps:
- script: |
# Install Swift dependencies
sudo apt-get install clang libicu-dev
# Install Swift 5.3.3
curl https://swift.org/builds/swift-5.3.3-release/ubuntu1604/swift-5.3.3-RELEASE/swift-5.3.3-RELEASE-ubuntu16.04.tar.gz > $(Build.SourcesDirectory)/swift-5.3.3-RELEASE-ubuntu16.04.tar.gz
tar xzf swift-5.3.3-RELEASE-ubuntu16.04.tar.gz -C $(Build.SourcesDirectory)
# Install Swift 5.5.2
curl https://download.swift.org/swift-5.5.2-release/ubuntu1804/swift-5.5.2-RELEASE/swift-5.5.2-RELEASE-ubuntu18.04.tar.gz > $(Build.SourcesDirectory)/swift-5.5.2-RELEASE-ubuntu18.04.tar.gz
tar xzf swift-5.5.2-RELEASE-ubuntu18.04.tar.gz -C $(Build.SourcesDirectory)
# Swift build
$(Build.SourcesDirectory)/swift-5.3.3-RELEASE-ubuntu16.04/usr/bin/swift build
$(Build.SourcesDirectory)/swift-5.5.2-RELEASE-ubuntu18.04/usr/bin/swift build
# Swift test
$(Build.SourcesDirectory)/swift-5.3.3-RELEASE-ubuntu16.04/usr/bin/swift test
$(Build.SourcesDirectory)/swift-5.5.2-RELEASE-ubuntu18.04/usr/bin/swift test
# Examples
- job: 'Swift_Package_Manager'
pool:
vmImage: 'macOS-10.15'
vmImage: 'macOS-11'
steps:
- script: |
brew update
@@ -109,15 +109,14 @@ jobs:
swift build --package-path Examples/Leaderboard/
- job: 'Carthage'
pool:
vmImage: 'macOS-10.15'
vmImage: 'macOS-11'
steps:
- script: |
carthage bootstrap --use-xcframeworks
- script: carthage bootstrap --use-xcframeworks --platform macos
workingDirectory: 'Examples/Leaderboard'
- job: 'CocoaPods'
pool:
vmImage: 'macOS-10.15'
vmImage: 'macOS-11'
steps:
- task: CocoaPods@0
inputs:
@@ -130,6 +129,6 @@ jobs:
configuration: 'Release'
xcWorkspacePath: 'Examples/Leaderboard/Leaderboard.xcworkspace'
xcodeVersion: specifyPath
xcodeDeveloperDir: '/Applications/Xcode_12.4.app/Contents/Developer'
xcodeDeveloperDir: '/Applications/Xcode_13.0.app/Contents/Developer'