Compare commits

..

144 Commits

Author SHA1 Message Date
Peter Zignego 29739dba74 Merge pull request #65 from pvzig/minor-updates
Code styling
2017-01-03 21:20:00 -05:00
Peter Zignego d60a7094a4 Readme 2017-01-03 21:18:58 -05:00
Peter Zignego 7edd4210f6 Code quality improvements 2017-01-02 22:41:03 -05:00
Peter Zignego 2abaecbd14 Lowercase enums 2017-01-02 22:39:56 -05:00
Peter Zignego 346499e03b Update podspec version 2016-11-25 12:46:48 -05:00
Peter Zignego bc72a52bf5 Update readme 2016-11-24 12:37:48 -05:00
Peter Zignego 0ebd3cb0e7 Merge pull request #60 from pvzig/ios-fix
Fix iOS crash + Swift 3 style changes
2016-11-24 12:19:39 -05:00
Peter Zignego 5d7064ee13 Podfile + versioning 2016-11-24 12:16:53 -05:00
Peter Zignego d02768ddad Bump starscream version 2016-11-24 12:01:54 -05:00
Peter Zignego dbc7b361c8 Merge branch 'master' into ios-fix 2016-11-24 11:59:50 -05:00
Peter Zignego a0de46e3c7 Code quality improvements 2016-11-20 22:10:44 -05:00
Peter Zignego 2d6e19baee Bump starscream version 2016-11-20 22:07:06 -05:00
Peter Zignego 21ec3cb2a1 Fix iOS crash 2016-11-20 22:04:50 -05:00
Peter Zignego cb542da068 Merge pull request #59 from MarcusSmith/master
Fix File Upload Bug
2016-11-18 14:16:18 -05:00
Marcus Smith 788b4e4f7a Remove File data from upload's query parameters, which was preventing a proper URL from being created from the request string 2016-11-18 14:14:02 -05:00
Peter Zignego 24b2292cba Request string bugfix 2016-11-17 16:48:00 -05:00
Peter Zignego 72866262d2 Fix request string bug 2016-11-17 16:30:28 -05:00
Peter Zignego acabbb6c03 Update README.md 2016-11-17 15:04:18 -05:00
Peter Zignego fff0f0befc Merge branch 'master' of https://github.com/pvzig/SlackKit into ios-fix
# Conflicts:
#	SlackKit/Sources/WebAPI.swift
2016-11-17 14:44:35 -05:00
Peter Zignego cf0675dac2 Merge pull request #58 from stucarney/master
Added missing support for chat.meMessage endpoint
2016-11-17 09:08:54 -05:00
Stu Carney 1cffa0ba74 Added missing support for chat.meMessage endpoint 2016-11-16 20:00:22 -06:00
Peter Zignego 9ebd8182a6 Lowercase enums 2016-11-13 17:26:32 -05:00
Peter Zignego 63a8ae7f08 Lowercase enums 2016-11-13 15:34:27 -05:00
Peter Zignego 992f94e870 Lowercase error enums 2016-11-13 15:32:50 -05:00
Peter Zignego 1c476c77ad Lowercase enums 2016-11-11 14:59:43 -05:00
Peter Zignego 28bd612ca0 Carthage search paths 2016-10-11 21:18:34 -04:00
Peter Zignego 45cf2a7ac0 Add back links for carthage 2016-10-11 21:12:31 -04:00
Peter Zignego f7c986c65c Update dependency managers 2016-10-11 21:01:17 -04:00
Peter Zignego ca43df4475 Update project file 2016-10-11 19:43:14 -04:00
Peter Zignego ef71b6abf0 Swifter compatability 2016-10-11 19:41:36 -04:00
Peter Zignego 3ff922a2c0 Project file update 2016-10-11 19:41:28 -04:00
Peter Zignego 646c371bd3 SPM compatability 2016-10-01 12:37:13 -04:00
Peter Zignego 36401009f8 Version bump 2016-09-26 00:05:13 -04:00
Peter Zignego b837554dcf Delete Package.swift until SPM compatability is restored 2016-09-25 23:54:25 -04:00
Peter Zignego 0ba0e019ae Update README.md 2016-09-25 23:52:53 -04:00
Peter Zignego 8771ef3f0a Update readme 2016-09-25 23:51:32 -04:00
Peter Zignego 71e7238483 Merge branch 'swift3'
# Conflicts:
#	README.md
#	SlackKit/Sources/Action.swift
#	SlackKit/Sources/Response.swift
#	SlackKit/Sources/SlackKit.swift
2016-09-25 20:35:45 -04:00
Peter Zignego b75c10fca6 Merge pull request #53 from pvzig/swift3-GM
Swift 3
2016-09-25 20:31:44 -04:00
Peter Zignego 50f85ac103 Carthage 2016-09-20 00:23:26 -04:00
Peter Zignego a7cbb84b34 Update starscream delegate 2016-09-20 00:23:08 -04:00
Peter Zignego ed6789c9a5 Swift 3 update 2016-09-19 23:59:10 -04:00
Peter Zignego ca444930a4 GM 2016-09-14 21:39:32 -04:00
Peter Zignego 21051864ec Add badges 2016-09-13 00:10:55 -04:00
Peter Zignego 36d1553072 Update README.md 2016-09-12 23:42:17 -04:00
Peter Zignego eb14758846 Add badges 2016-09-12 23:40:48 -04:00
Peter Zignego bf3a5c2422 Merge pull request #47 from hiragram/add-missing-scope
Add MissingScope
2016-08-21 22:40:59 -04:00
Yuya 98fd1342e7 Add MissingScope 2016-08-21 13:38:49 +09:00
Peter Zignego 183ed91cb8 Merge branch 'xcode8b4' into swift3 2016-08-03 22:47:16 -04:00
Peter Zignego c241dcf1df Xcode 8 beta 4 2016-08-03 22:47:03 -04:00
Peter Zignego 8007fa6f0f Include style in Action JSON dictionary 2016-08-02 23:24:12 -04:00
Peter Zignego 7ab973a03b Include style in Action JSON dictionary 2016-08-02 23:21:16 -04:00
Peter Zignego 1889ffeeee Fix callback bug when authing via a provided token 2016-07-26 19:11:26 -04:00
Peter Zignego 987be40c91 Fix callback bug when authing via a token 2016-07-26 19:07:53 -04:00
Peter Zignego 2e71ac6876 Bug fix 2016-07-23 11:12:14 -04:00
Peter Zignego df661762a9 Bug fix 2016-07-23 11:09:54 -04:00
Peter Zignego c428cac537 Update readme 2016-07-20 21:44:30 -04:00
Peter Zignego 18c6516df9 Remove Cocoapods 2016-07-20 21:32:57 -04:00
Peter Zignego fe450a7db2 Set swift version 2016-07-20 21:32:41 -04:00
Peter Zignego bb57f59553 Swift 3 support 2016-07-20 18:31:03 -04:00
Peter Zignego e5a4a67bdb Fix imports for SPM 2016-07-18 00:07:03 -04:00
Peter Zignego 1e304f1f6d Update podfile.lock 2016-07-17 23:29:06 -04:00
Peter Zignego 81ebf86abd Update podfile and podspec 2016-07-17 23:04:03 -04:00
Peter Zignego afa16e98b3 Update podspec 2016-07-17 22:50:13 -04:00
Peter Zignego 6596bb2861 SlackKit 2.0.0 2016-07-17 22:20:15 -04:00
Peter Zignego fd12ab0600 Readme updates 2016-07-17 21:49:27 -04:00
Peter Zignego 31508e44dc Merge branch 'feature/message-buttons'
# Conflicts:
#	README.md
#	SlackKit.xcodeproj/project.pbxproj
#	SlackKit/Sources/MessageActionResponder.swift
#	SlackKit/Supporting Files/Info-iOS.plist
#	SlackKit/Supporting Files/Info-tvOS.plist
#	SlackKit/Supporting Files/Info.plist
2016-07-17 21:39:14 -04:00
Peter Zignego b980f371f6 SlackKit 2.0.0 2016-07-17 21:30:56 -04:00
Peter Zignego 9526d739e1 Oauth 2016-07-07 20:22:44 -04:00
Peter Zignego c3af5c33be Increment version 2016-07-04 14:35:51 -04:00
Peter Zignego c6258c57a0 Merge pull request #43 from pvzig/spm-fix
SPM fix
2016-07-04 14:32:31 -04:00
Peter Zignego 45e075aca2 Update readme 2016-07-04 14:30:52 -04:00
Peter Zignego 5ebe40a389 Remove example 2016-07-04 13:15:32 -04:00
Peter Zignego 0a5a8f83f7 Remove example target 2016-07-04 13:14:03 -04:00
Peter Zignego 8f4a287ad0 Fix Package.swift 2016-07-04 13:13:28 -04:00
Peter Zignego deadc8855a Webhook and server 2016-07-04 12:38:06 -04:00
Peter Zignego 98155f00b7 Remove bundled sample 2016-07-02 16:42:36 -04:00
Peter Zignego a55d3be65b Message buttons 2016-06-26 14:39:12 -04:00
Peter Zignego 3b8f1834f0 Code improvements 2016-06-25 18:52:53 -04:00
Peter Zignego 34972eb8af Types get their own .swift files 2016-06-25 18:51:48 -04:00
Peter Zignego f21179f567 Model type organization 2016-06-23 00:13:52 -04:00
Peter Zignego e1bf5a160f Merge pull request #41 from hamin/make-some-channel-setters-public
Make the following Chanel setters public 'unreadCountDisplay', 'unrea…
2016-06-19 22:00:07 -04:00
Haris Amin c66a5fe0db Make the following Chanel setters public 'unreadCountDisplay', 'unread', and 'lastRead' 2016-06-19 17:48:31 -04:00
Peter Zignego f03908bcc7 Merge pull request #38 from natestedman/master
Remove curly quotes from Carthage instructions
2016-06-04 11:13:55 -04:00
Nate Stedman 591b0d9d55 Remove curly quotes from Carthage instructions. 2016-06-04 08:55:23 -04:00
Peter Zignego 6e83fb93d8 Merge pull request #36 from pvzig/feature/additional-footer-fields
1.1.1
2016-06-01 17:22:02 -04:00
Peter Zignego c1d202f433 Increment version 2016-06-01 17:21:23 -04:00
Peter Zignego c7db8ac578 Add new Attachment footer fields
https://api.slack.com/docs/attachments
2016-06-01 17:17:27 -04:00
Peter Zignego d2e430e5bf Merge pull request #35 from pvzig/feature/model-object-improvements
1.1.0
2016-05-22 22:33:12 -04:00
Peter Zignego ebe169bf2a Update podspec 2016-05-22 22:30:29 -04:00
Peter Zignego ca36653dc4 Update readme 2016-05-22 22:30:21 -04:00
Peter Zignego 94895edfac Bump version 2016-05-22 22:27:34 -04:00
Peter Zignego 3ea13ac6c4 Multiple target naming clean up 2016-05-22 22:27:25 -04:00
Peter Zignego e94adfc019 Make timestamp non-optional 2016-05-22 21:59:51 -04:00
Peter Zignego 1291323c5a Remove unused variable 2016-05-22 21:30:41 -04:00
Peter Zignego 4ceb452e6b File reordering 2016-05-22 21:30:27 -04:00
Peter Zignego 457504e786 Code quality 2016-05-22 18:38:00 -04:00
Peter Zignego 6d9a939575 Files only come as an ID via RTM (API change)
https://medium.com/slack-developer-blog/changes-to-file-events-in-the-real-time-messaging-api-5fa75c8c4d99#.1f3k421tz
2016-05-22 18:12:46 -04:00
Peter Zignego efc3847a20 Merge remote-tracking branch 'michallaskowski/remove-unneded-optionals' into feature/model-object-improvements
# Conflicts:
#	SlackKit/Sources/Message.swift
#	SlackKit/Sources/SlackWebAPI.swift
2016-05-21 15:28:28 -04:00
Peter Zignego 3ed139b503 Merge pull request #33 from hamin/fix-message-reactions-parsing
Fixes parsing of Reaction from Message response. It now properly adds…
2016-05-21 12:26:51 -04:00
Peter Zignego a4d9083f72 Merge pull request #34 from muratayusuke/feature/handle_http_error
Hanlde HTTP error
2016-05-21 12:25:18 -04:00
muratayusuke 67b2fa95b3 Hanlde HTTP error 2016-05-21 15:06:57 +09:00
Haris Amin e031f85447 Fixes parsing of Reaction from Message response. It now properly adds users to a parsed Reaction 2016-05-21 01:16:34 -04:00
Peter Zignego 0b1dc6068e Merge remote-tracking branch 'michallaskowski/slack-web-api-without-client' 2016-05-17 20:21:20 -04:00
Peter Zignego b027b5b779 Readme styling 2016-05-15 21:16:09 -04:00
Peter Zignego e507c85ca2 Update readme with note about slow carthage build times 2016-05-15 21:14:43 -04:00
michallaskowski 145dfccfae Remove unneeded Array extension 2016-05-15 23:16:55 +02:00
michallaskowski b4ca2bcc07 Delete optionals from EventDelegate where possible, fix reactionRemoved 2016-05-15 23:16:55 +02:00
michallaskowski 85b2d920ad Gardening Client.swift 2016-05-15 23:16:55 +02:00
michallaskowski 6415a113ed Remove failable initializers 2016-05-15 23:16:55 +02:00
Peter Zignego 3a2324b279 Fix readme 2016-05-15 16:29:40 -04:00
Peter Zignego d647a6b0c9 Update podspec 2016-05-15 16:27:47 -04:00
Peter Zignego 4230d7841c Merge pull request #32 from pvzig/feature/carthage-support
Feature/carthage support
2016-05-15 16:22:18 -04:00
Peter Zignego 8995a54d15 Fix project file and schemes after merge 2016-05-15 16:16:26 -04:00
Peter Zignego ba43a123ea Merge branch 'master' into feature/carthage-support
# Conflicts:
#	SlackKit.podspec
#	SlackKit.xcodeproj/project.pbxproj
#	SlackKit.xcodeproj/xcshareddata/xcschemes/SlackKit.xcscheme
2016-05-15 15:57:27 -04:00
Peter Zignego d00419dc18 Framework build details 2016-05-15 15:41:42 -04:00
Peter Zignego 15f3a30ba9 Framework build details 2016-05-15 15:39:47 -04:00
Peter Zignego befa53e3a9 Update ignore 2016-05-15 15:28:43 -04:00
Peter Zignego 35dfa840e8 Revert "Use submodule to handle core dependency"
This reverts commit edf56e1678.
2016-05-15 15:25:36 -04:00
Peter Zignego edf56e1678 Use submodule to handle core dependency 2016-05-15 15:21:47 -04:00
Peter Zignego 3eab323564 Ignore Cartfile.resolved 2016-05-15 15:04:34 -04:00
Peter Zignego 0b2ee1d10e Clean up project file 2016-05-15 14:51:15 -04:00
michallaskowski 5444948940 Do not hold Client instance in SlackWebAPI 2016-05-15 20:40:05 +02:00
Peter Zignego 13335b5de1 Add additional shared schemes 2016-05-15 14:09:21 -04:00
Peter Zignego c8d8e18db6 Move AttachmentColor enum 2016-05-14 20:11:14 -04:00
Peter Zignego c11321c116 File name comment fixes 2016-05-14 20:08:54 -04:00
Michal Laskowski 0041a118a7 Fix circular dependencies (#30)
* Remove EventDispatcher, EventHandler classes; extend Client

* Make delegates weak

* Remove unneded 'if let delegate = '

* Move files around
2016-05-14 19:51:08 -04:00
Michal Laskowski 6cb5280cf5 Add tvOS target to podspec 2016-05-11 10:12:15 -05:00
Peter Zignego 9cad043957 Add shared scheme 2016-05-06 15:02:39 -04:00
Peter Zignego fa15ed8751 Merge pull request #28 from hamin/add-larger-thumbs-to-file
Adding support for larger size File thumbs
2016-05-04 12:02:42 -04:00
Haris Amin 0c9c146d58 Adding support for larger size File thumbs 2016-05-04 01:58:43 -04:00
Peter Zignego 109a20fac2 Readme update 2016-04-27 23:18:19 -04:00
Peter Zignego a6cf1e3cb6 Revert "Delete and add Cartfile.resolved to ignore"
This reverts commit d3c16bed5f.
2016-04-27 23:17:41 -04:00
Peter Zignego d3c16bed5f Delete and add Cartfile.resolved to ignore 2016-04-27 23:07:55 -04:00
Peter Zignego 797d95ab75 Update readme 2016-04-27 22:54:30 -04:00
Nate Stedman efb7bc9458 Use Carthage for resolving dependencies. 2016-04-27 22:34:28 -04:00
Peter Zignego 79e59f23fb Bump version number 2016-04-27 19:33:48 -04:00
Peter Zignego 01e199659e Update readme 2016-04-27 19:30:48 -04:00
Peter Zignego 851b2f5e14 Merge pull request #27 from pvzig/1.0.2
v1.0.2
2016-04-27 19:26:26 -04:00
Peter Zignego c506512800 Add files.info 2016-04-27 19:18:12 -04:00
Peter Zignego 20fa05605b Merge branch 'master' of https://github.com/pvzig/SlackRTMKit 2016-04-27 17:44:55 -04:00
Peter Zignego 30baf1f76c Add clientConnectionFailed delegate 2016-04-27 17:44:51 -04:00
Peter Zignego 1c3f01f861 Fix typo in example 2016-04-27 17:39:23 -04:00
Peter Zignego 47dc9b3d9f Merge pull request #25 from muratayusuke/feature/make_token_public
Make token public
2016-04-25 10:28:45 -04:00
muratayusuke b9e828ef3d Make token public 2016-04-24 18:44:40 +09:00
51 changed files with 3021 additions and 1059 deletions
+6 -5
View File
@@ -16,11 +16,12 @@ DerivedData
*.hmap
*.ipa
*.xcuserstate
.build
Packages/
*.xcodeproj/
*.DS_Store
# SwiftPM
Packages/
.build
# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
@@ -28,10 +29,10 @@ Packages/
# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
#
Pods/
SlackKit.xcworkspace
# Carthage
#
# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts
Carthage/Checkouts
Carthage/Build
+1 -1
View File
@@ -1 +1 @@
3.0.2
3.0
+2
View File
@@ -0,0 +1,2 @@
github "https://github.com/daltoniam/Starscream" == 2.0.2
github "https://github.com/pvzig/swifter.git" == 3.0.4
+2
View File
@@ -0,0 +1,2 @@
github "daltoniam/Starscream" "2.0.2"
github "pvzig/swifter" "3.0.4"
-9
View File
@@ -1,9 +0,0 @@
import PackageDescription
let package = Package(
name: "echobot",
targets: [],
dependencies: [
.Package(url: "https://github.com/pvzig/SlackKit.git", majorVersion: 0, minor: 0),
]
)
-35
View File
@@ -1,35 +0,0 @@
import Foundation
import SlackKit
class Echobot: MessageEventsDelegate {
let client: SlackClient
init(token: String) {
client = SlackClient(apiToken: token)
client.messageEventsDelegate = self
}
// MARK: MessageEventsDelegate
func sent(_ message: Message, client: SlackClient) {}
func changed(_ message: Message, client: SlackClient) {}
func deleted(_ message: Message?, client: SlackClient) {}
func received(_ message: Message, client: SlackClient) {
listen(message: message)
}
// MARK: Echobot Internal Logic
private func listen(message: Message) {
if let channel = message.channel, let text = message.text, let id = client.authenticatedUser?.id {
if id != message.user && message.user != nil {
client.webAPI.sendMessage(channel:channel, text: text, linkNames: true, success: {(response) in
}, failure: { (error) in
print("Echobot failed to reply due to error:\(error)")
})
}
}
}
}
let echobot = Echobot(token: "xoxb-SLACK_API_TOKEN")
echobot.client.connect()
-8
View File
@@ -1,8 +0,0 @@
import PackageDescription
let package = Package(
name: "leaderboard",
dependencies: [
.Package(url: "https://github.com/pvzig/SlackKit.git", majorVersion: 0, minor: 0),
]
)
-141
View File
@@ -1,141 +0,0 @@
import Foundation
import SlackKit
class Leaderboard: MessageEventsDelegate {
var leaderboard: [String: Int] = [String: Int]()
let atSet = CharacterSet(charactersIn: "@")
let client: SlackClient
init(token: String) {
client = SlackClient(apiToken: token)
client.messageEventsDelegate = self
}
enum Command: String {
case leaderboard = "leaderboard"
}
enum Trigger: String {
case plusPlus = "++"
case minusMinus = "--"
}
// MARK: MessageEventsDelegate
func sent(_ message: Message, client: SlackClient) {}
func changed(_ message: Message, client: SlackClient) {}
func deleted(_ message: Message?, client: SlackClient) {}
func received(_ message: Message, client: SlackClient) {
listen(message: message)
}
// MARK: Leaderboard Internal Logic
private func listen(message: Message) {
if let id = client.authenticatedUser?.id, let text = message.text {
if text.lowercased().contains(Command.leaderboard.rawValue) && text.contains(id) {
handleCommand(command: .leaderboard, channel: message.channel)
}
}
if message.text?.contains(Trigger.plusPlus.rawValue) == true {
handleMessageWithTrigger(message: message, trigger: .plusPlus)
}
if message.text?.contains(Trigger.minusMinus.rawValue) == true {
handleMessageWithTrigger(message: message, trigger: .minusMinus)
}
}
private func handleMessageWithTrigger(message: Message, trigger: Trigger) {
if let text = message.text, let start = text.range(of: "@")?.lowerBound, let end = text.range(of: trigger.rawValue)?.lowerBound {
let string = String(text.characters[start...end].dropLast().dropFirst())
let users = client.users.values.filter{$0.id == self.userID(string: string)}
if users.count > 0 {
let idString = userID(string: string)
initalizationForValue(dictionary: &leaderboard, value: idString)
scoringForValue(dictionary: &leaderboard, value: idString, trigger: trigger)
} else {
initalizationForValue(dictionary: &leaderboard, value: string)
scoringForValue(dictionary: &leaderboard, value: string, trigger: trigger)
}
}
}
private func handleCommand(command: Command, channel:String?) {
switch command {
case .leaderboard:
if let id = channel {
client.webAPI.sendMessage(channel:id, text: "Leaderboard", linkNames: true, attachments: [constructLeaderboardAttachment()], success: {(response) in
print(response)
}, failure: { (error) in
print("Leaderboard failed to post due to error:\(error)")
})
}
}
}
private func initalizationForValue( dictionary: inout [String: Int], value: String) {
if dictionary[value] == nil {
dictionary[value] = 0
}
}
private func scoringForValue( dictionary: inout [String: Int], value: String, trigger: Trigger) {
switch trigger {
case .plusPlus:
dictionary[value]?+=1
case .minusMinus:
dictionary[value]?-=1
}
}
// MARK: Leaderboard Interface
private func constructLeaderboardAttachment() -> Attachment? {
let 💯 = AttachmentField(title: "💯", value: swapIDsForNames(string: topItems(dictionary: &leaderboard)), short: true)
let 💩 = AttachmentField(title: "💩", value: swapIDsForNames(string: bottomItems(dictionary: &leaderboard)), short: true)
return Attachment(fallback: "Leaderboard", title: "Leaderboard", colorHex: AttachmentColor.good.rawValue, text: "", fields: [💯, 💩])
}
private func topItems(dictionary: inout [String: Int]) -> String {
let sortedKeys = dictionary.keys.sorted(by: { (k1: String, k2: String) -> Bool in
return dictionary[k1]! > dictionary[k2]!
}).filter({ dictionary[$0]! > 0})
let sortedValues = dictionary.values.sorted(by: {$0 > $1}).filter({$0 > 0})
return leaderboardString(keys: sortedKeys, values: sortedValues)
}
private func bottomItems( dictionary: inout [String: Int]) -> String {
let sortedKeys = dictionary.keys.sorted(by: { (k1: String, k2: String) -> Bool in
return dictionary[k1]! < dictionary[k2]!
}).filter({ dictionary[$0]! < 0})
let sortedValues = dictionary.values.sorted(by: {$0 < $1}).filter({$0 < 0})
return leaderboardString(keys: sortedKeys, values: sortedValues)
}
private func leaderboardString(keys: [String], values: [Int]) -> String {
var returnValue = ""
for i in 0..<values.count {
returnValue += keys[i] + " (" + "\(values[i])" + ")\n"
}
return returnValue
}
// MARK: - Utilities
private func swapIDsForNames(string: String) -> String {
var returnString = string
for key in client.users.keys {
if let name = client.users[key]?.name {
if returnString.contains(key) {
returnString = returnString.replacingOccurrences(of: key, with: "@"+name)
}
}
}
return returnString
}
private func userID(string: String) -> String {
return string.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
}
}
let leaderboard = Leaderboard(token: "xoxb-SLACK_API_TOKEN")
leaderboard.client.connect()
-9
View File
@@ -1,9 +0,0 @@
import PackageDescription
let package = Package(
name: "robot-or-not-bot",
targets: [],
dependencies: [
.Package(url: "https://github.com/pvzig/SlackKit.git", majorVersion: 0, minor: 0),
]
)
@@ -1,117 +0,0 @@
import Foundation
import SlackKit
class RobotOrNotBot: MessageEventsDelegate {
let verdicts: [String:Bool] = [
"Mr. Roboto" : false,
"Service Kiosks": false,
"Darth Vader": false,
"K-9": true,
"Emotions": false,
"Self-Driving Cars": false,
"Telepresence Robots": false,
"Roomba": true,
"Assembly-Line Robot": false,
"ASIMO": false,
"KITT": false,
"USS Enterprise": false,
"Transformers": true,
"Jaegers": false,
"The Major": false,
"Siri": false,
"The Terminator": true,
"Commander Data": false,
"Marvin the Paranoid Android": true,
"Pinocchio": false,
"Droids": true,
"Hitchbot": false,
"Mars Rovers": false,
"Space Probes": false,
"Sasquatch": false,
"Toaster": false,
"Toaster Oven": false,
"Cylons": false,
"V'ger": true,
"Ilia Robot": false,
"The TARDIS": false,
"Johnny 5": true,
"Twiki": true,
"Dr. Theopolis": false,
"robots.txt": false,
"Lobot": false,
"Vicki": true,
"GlaDOS": false,
"Turrets": true,
"Wheatley": true,
"Herbie the Love Bug": false,
"Iron Man": false,
"Ultron": false,
"The Vision": false,
"Clockwork Droids": false,
"Podcasts": false,
"Cars": false,
"Swimming Pool Cleaners": false,
"Burritos": false,
"Prince Robot IV": false,
"Daleks": false,
"Cybermen": false,
"The Internet of Things": false,
"Nanobots": true,
"Two Intermeshed Gears": false,
"Crow T. Robot": true,
"Tom Servo": true,
"Thomas and Friends": false,
"Replicants": false,
"Chatbots": false,
"Agents": false,
"Lego Simulated Worm Toy": true,
"Ghosts": false,
"Exos": true,
"Rasputin": false,
"Tamagotchi": false,
"T-1000": true,
"The Tin Woodman": false,
"Mic N. The Robot": true,
"Robot Or Not Bot": false
]
let client: SlackClient
init(token: String) {
client = SlackClient(apiToken: token)
client.messageEventsDelegate = self
}
// MARK: MessageEventsDelegate
func received(_ message: Message, client: SlackClient) {
if let id = client.authenticatedUser?.id {
if message.text?.contains(id) == true {
handleMessage(message: message)
}
}
}
func changed(_ message: Message, client: SlackClient) {}
func deleted(_ message: Message?, client: SlackClient) {}
func sent(_ message: Message, client: SlackClient) {}
private func handleMessage(message: Message) {
if let text = message.text?.lowercased(), let channel = message.channel {
for (robot, verdict) in verdicts {
let lowerbot = robot.lowercased()
if text.contains(lowerbot) {
if verdict == true {
client.webAPI.addReaction(name: "robot_face", channel: channel, timestamp: message.ts, success: nil, failure: nil)
} else {
client.webAPI.addReaction(name: "no_entry_sign", channel: channel, timestamp: message.ts, success: nil, failure: nil)
}
return
}
}
client.webAPI.addReaction(name: "question", channel: channel, timestamp: message.ts, success: nil, failure: nil)
}
}
}
let slackbot = RobotOrNotBot(token: "xoxb-SLACK_API_TOKEN")
slackbot.client.connect()
+4 -27
View File
@@ -1,34 +1,11 @@
//
// Package.swift
//
// Copyright © 2016 Peter Zignego. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import PackageDescription
let package = Package(
name: "SlackKit",
targets: [],
dependencies: [
.Package(url: "https://github.com/Zewo/WebSocketClient", majorVersion: 0, minor: 14),
.Package(url: "https://github.com/Zewo/HTTPClient.git", majorVersion: 0, minor: 14)
],
exclude: ["Examples"]
.Package(url: "https://github.com/pvzig/swifter.git",
majorVersion: 3, minor: 0),
.Package(url: "https://github.com/daltoniam/Starscream", majorVersion: 2, minor: 0)
]
)
+18
View File
@@ -0,0 +1,18 @@
source 'https://github.com/CocoaPods/Specs.git'
use_frameworks!
target 'SlackKit OS X' do
pod 'Starscream', '~> 2.0.2'
pod 'Swifter', :git => 'https://github.com/pvzig/swifter.git', :tag => '3.0.4'
end
target 'SlackKit iOS' do
pod 'Starscream', '~> 2.0.2'
pod 'Swifter', :git => 'https://github.com/pvzig/swifter.git', :tag => '3.0.4'
end
target 'SlackKit tvOS' do
pod 'Starscream', '~> 2.0.2'
pod 'Swifter', :git => 'https://github.com/pvzig/swifter.git', :tag => '3.0.4'
end
+25
View File
@@ -0,0 +1,25 @@
PODS:
- Starscream (2.0.2)
- Swifter (1.3.2)
DEPENDENCIES:
- Starscream (~> 2.0.2)
- Swifter (from `https://github.com/pvzig/swifter.git`, tag `3.0.4`)
EXTERNAL SOURCES:
Swifter:
:git: https://github.com/pvzig/swifter.git
:tag: 3.0.4
CHECKOUT OPTIONS:
Swifter:
:git: https://github.com/pvzig/swifter.git
:tag: 3.0.4
SPEC CHECKSUMS:
Starscream: 6c135a34e0a6e60cedaa0b30db67a4c05cf7cd38
Swifter: dd1800ba8eb3e28b22b8bd20f91a8561a0110fac
PODFILE CHECKSUM: cd86ea0f8422027c9d5fa3c40243ae7a816fb79a
COCOAPODS: 1.1.0.rc.3
+220 -134
View File
@@ -1,72 +1,146 @@
![SlackKit](https://cloud.githubusercontent.com/assets/8311605/10260893/5ec60f96-694e-11e5-91fd-da6845942201.png)
![Swift Version](https://img.shields.io/badge/Swift-DEVELOPMENT--SNAPSHOT--2016--05--09--a-orange.svg) ![Plaforms](https://img.shields.io/badge/Platforms-macOS,linux-lightgrey.svg) ![License MIT](https://img.shields.io/badge/License-MIT-lightgrey.svg) [![SwiftPM compatible](https://img.shields.io/badge/SwiftPM-compatible-brightgreen.svg)](https://github.com/apple/swift-package-manager)
##Alpha Linux Slack Client Library
###Description
This is a Slack client library for Linux written in Swift. It's intended to expose all of the functionality of Slack's [Real Time Messaging API](https://api.slack.com/rtm) as well as the [web APIs](https://api.slack.com/web) that are accessible by [bot users](https://api.slack.com/bot-users).
![Swift Version](https://img.shields.io/badge/Swift-3.0-orange.svg) ![Plaforms](https://img.shields.io/badge/Platforms-macOS,iOS,tvOS-lightgrey.svg) ![License MIT](https://img.shields.io/badge/License-MIT-lightgrey.svg) [![CocoaPods compatible](https://img.shields.io/badge/CocoaPods-compatible-brightgreen.svg)](https://cocoapods.org) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-brightgreen.svg)](https://github.com/Carthage/Carthage) [![SwiftPM compatible](https://img.shields.io/badge/SwiftPM-compatible-brightgreen.svg)](https://github.com/apple/swift-package-manager)
## SlackKit: A Swift Slack Client Library
### Description
###Disclaimer: The linux version of SlackKit is a pre-release alpha. Feel free to report issues you come across.
This is a Slack client library for OS X, iOS, and tvOS written in Swift. It's intended to expose all of the functionality of Slack's [Real Time Messaging API](https://api.slack.com/rtm) as well as the [web APIs](https://api.slack.com/web) that are accessible to [bot users](https://api.slack.com/bot-users). SlackKit also supports Slacks [OAuth 2.0](https://api.slack.com/docs/oauth) flow including the [Add to Slack](https://api.slack.com/docs/slack-button) and [Sign in with Slack](https://api.slack.com/docs/sign-in-with-slack) buttons, [incoming webhooks](https://api.slack.com/incoming-webhooks), [slash commands](https://api.slack.com/slash-commands), and [message buttons](https://api.slack.com/docs/message-buttons).
###Installation
This is the **Swift 3** branch of SlackKit. SlackKit also has support for [Swift 2.3](https://github.com/pvzig/SlackKit/tree/swift2.3) and [Linux](https://github.com/pvzig/SlackKit/tree/linux).
#### Building the SlackKit Framework
To build the SlackKit project directly, first build the dependencies using Carthage or CocoaPods. To use the framework in your application, install it in one of the following ways:
### Installation
#### CocoaPods
Add SlackKit to your pod file:
```
use_frameworks!
pod 'SlackKit', '~> 3.1.5'
```
and run
```
# Use CocoaPods version >= 1.1.0
pod install
```
#### Carthage
Add SlackKit to your Cartfile:
```
github "https://github.com/pvzig/slackkit.git"
```
and run
```
carthage bootstrap
```
**Note:** If youre seeing long compile times with optimizations turned on, try updating to the latest version of Xcode, 8.2.1.
Drag the built `SlackKit.framework` into your Xcode project.
#### Swift Package Manager
####Swift Package Manager
Add SlackKit to your Package.swift
```swift
import PackageDescription
let package = Package(
dependencies: [
.Package(url: "https://github.com/pvzig/SlackKit.git", majorVersion: 0, minor: 0)
]
dependencies: [
.Package(url: "https://github.com/pvzig/SlackKit.git", majorVersion: 3)
]
)
```
####Development
1. Install Homebrew: `/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"`
2. Install `swiftenv`: `brew install kylef/formulae/swiftenv`
3. Configure your shell: `echo 'if which swiftenv > /dev/null; then eval "$(swiftenv init -)"; fi' >> ~/.bash_profile`
4. Download and install the latest Zewo compatible snapshot:
```
swiftenv install DEVELOPMENT-SNAPSHOT-2016-05-09-a
swiftenv local DEVELOPMENT-SNAPSHOT-2016-05-09-a
```
5. Install and Link OpenSSL: `brew install openssl`, `brew link openssl --force`
To build an application that uses SlackKit in Xcode, simply use SwiftPM. (For the 05-03 snapshot you must run `swift build` before generating an Xcode project:
```
swift build
swift build -Xlinker -L$(pwd)/.build/debug/ -Xswiftc -I/usr/local/include -Xlinker -L/usr/local/lib -X
```
Run `swift build` on your applications main directory.
To use the library in your project import it:
```
import SlackKit
```
####Deployment
Deploy your application to Heroku using [this buildpack](https://github.com/pvzig/heroku-buildpack-swift). For more detailed instructions please see [this post](https://medium.com/@pvzig/building-slack-bots-in-swift-b99e243e444c).
### Usage
###Usage
To use SlackKit you'll need a bearer token which identifies a single user. You can generate a [full access token or create one using OAuth 2](https://api.slack.com/web).
#### OAuth
Slack has [many different oauth scopes](https://api.slack.com/docs/oauth-scopes) that can be combined in different ways. If your application does not request the proper OAuth scopes, your API calls will fail.
Once you have a token, initialize a client instance using it:
If you authenticate using OAuth and the Add to Slack or Sign in with Slack buttons this is handled for you.
If you wish to make OAuth requests yourself, you can generate them using the `authorizeRequest` function on `SlackKit`s `oauth` property:
```swift
let client = Client(apiToken: "YOUR_SLACK_API_TOKEN")
func authorizeRequest(scope:[Scope], redirectURI: String, state: String = "slackkit", team: String? = nil)
```
If you want to receive messages from the Slack RTM API, connect to it.
For local development of things like OAuth, slash commands, and message buttons that require connecting over `https`, you may want to use a tool like [ngrok](https://ngrok.com) or [localtunnel](http://localtunnel.me).
#### Incoming Webhooks
After [configuring your incoming webhook in Slack](https://my.slack.com/services/new/incoming-webhook/), initialize IncomingWebhook with the provided URL and use `postMessage` to send messages.
```swift
client.connect()
let incoming = IncomingWebhook(url: "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX")
let message = Response(text: "Hello, World!")
incoming.postMessage(message)
```
#### Slash Commands
After [configuring your slash command in Slack](https://my.slack.com/services/new/slash-commands) (you can also provide slash commands as part of a [Slack App](https://api.slack.com/slack-apps)), initialize a webhook server with the token for the slash command, a configured route, and a response.
```swift
let response = Response(text: "Hello, World!", responseType: .inChannel)
let webhook = WebhookServer(token: "SLASH-COMMAND-TOKEN", route: "hello_world", response: response)
webhook.start()
```
When a user enters that slash command, it will hit your configured route and return the response you specified.
To add additional routes and responses, you can use WebhookServers addRoute function:
```swift
func addRoute(route: String, response: Response)
```
#### Message Buttons
If you are developing a Slack App and are authorizing using OAuth, you can use [message buttons](https://api.slack.com/docs/message-buttons).
To send messages with actions, add them to an attachment:
```swift
let helloAction = Action(name: "hello_world", text: "Hello, World!")
let attachment = Attachment(fallback: "Hello World Attachment", title: "Attachment with an Action Button", callbackID: "helloworld", actions: [helloAction])
```
To act on message actions, initialize an instance of the `MessageActionServer` using your apps verification token, your specified interactive messages request URL route, and a `MessageActionResponder`:
```swift
let action = Action(name: "hello_world", text: "Hello, World!")
let response = Response(text: "Hello, 🌎!", responseType: .inChannel)
let responder = MessageActionResponder(responses: [(action, response)])
let server = MessageActionServer(token: "SLACK-APP-VERIFICATION-TOKEN", route: "actions", responder: responder)
server.start()
```
#### Bot Users
To deploy a bot user using SlackKit you'll need a bearer token which identifies a single user. You can generate a [full access token or create one using OAuth 2](https://api.slack.com/web).
Initialize a SlackKit instance using your [applications Client ID and Client Secret](https://api.slack.com/apps) to set up SlackKit for OAuth authorization:
```swift
let bot = SlackKit(clientID: "CLIENT_ID", clientSecret: "CLIENT_SECRET")
```
or use a manually acquired token:
```swift
let bot = SlackKit(withAPIToken: "xoxp-YOUR-SLACK-API-TOKEN")
```
#### Client Connection Options
You can also set options for a ping/pong interval, timeout interval, and automatic reconnection:
```swift
let options = ClientOptions(pingInterval: 2, timeout: 10, reconnect: false)
let bot = SlackKit(clientID: "CLIENT_ID", clientSecret: "CLIENT_SECRET", clientOptions: options)
```
Once connected, the client will begin to consume any messages sent by the Slack RTM API.
####Web API Methods
#### Web API Methods
SlackKit currently supports the a subset of the Slack Web APIs that are available to bot users:
- api.test
- auth.revoke
- auth.test
- channels.history
- channels.info
@@ -75,6 +149,7 @@ SlackKit currently supports the a subset of the Slack Web APIs that are availabl
- channels.setPurpose
- channels.setTopic
- chat.delete
- chat.meMessage
- chat.postMessage
- chat.update
- emoji.list
@@ -82,6 +157,7 @@ SlackKit currently supports the a subset of the Slack Web APIs that are availabl
- files.comments.edit
- files.comments.delete
- files.delete
- files.info
- files.upload
- groups.close
- groups.history
@@ -101,6 +177,7 @@ SlackKit currently supports the a subset of the Slack Web APIs that are availabl
- mpim.list
- mpim.mark
- mpim.open
- oauth.access
- pins.add
- pins.list
- pins.remove
@@ -120,112 +197,121 @@ SlackKit currently supports the a subset of the Slack Web APIs that are availabl
They can be accessed through a Client objects `webAPI` property:
```swift
client.webAPI.authenticationTest({
(authenticated) -> Void in
print(authenticated)
}){(error) -> Void in
print(error)
client.webAPI.authenticationTest({(auth) in
print(auth)
}, failure: {(error) in
print(error)
})
```
#### Delegate methods
To receive delegate callbacks for events, register an object as the delegate for those events using the `onClientInitalization` block:
```swift
let bot = SlackKit(clientID: clientID, clientSecret: clientSecret)
bot.onClientInitalization = { (client: Client) in
DispatchQueue.main.async(execute: {
client.messageEventsDelegate = self
})
}
```
####Delegate methods
To receive delegate callbacks for certain events, register an object as the delegate for those events:
```swift
client.slackEventsDelegate = self
```
Delegate callbacks contain a reference to the Client where the event occurred.
There are a number of delegates that you can set to receive callbacks for certain events.
#####SlackEventsDelegate
##### ConnectionEventsDelegate
```swift
func clientConnected()
func clientDisconnected()
func preferenceChanged(preference: String, value: AnyObject)
func userChanged(user: User)
func presenceChanged(user: User?, presence: String?)
func manualPresenceChanged(user: User?, presence: String?)
func botEvent(bot: Bot)
connected(_ client: Client)
disconnected(_ client: Client)
connectionFailed(_ client: Client, error: SlackError)
```
##### MessageEventsDelegate
```swift
sent(_ message: Message, client: Client)
received(_ message: Message, client: Client)
changed(_ message: Message, client: Client)
deleted(_ message: Message?, client: Client)
```
##### ChannelEventsDelegate
```swift
userTypingIn(_ channel: Channel, user: User, client: Client)
marked(_ channel: Channel, timestamp: String, client: Client)
created(_ channel: Channel, client: Client)
deleted(_ channel: Channel, client: Client)
renamed(_ channel: Channel, client: Client)
archived(_ channel: Channel, client: Client)
historyChanged(_ channel: Channel, client: Client)
joined(_ channel: Channel, client: Client)
left(_ channel: Channel, client: Client)
```
##### DoNotDisturbEventsDelegate
```swift
updated(_ status: DoNotDisturbStatus, client: Client)
userUpdated(_ status: DoNotDisturbStatus, user: User, client: Client)
```
##### GroupEventsDelegate
```swift
opened(_ group: Channel, client: Client)
```
##### FileEventsDelegate
```swift
processed(_ file: File, client: Client)
madePrivate(_ file: File, client: Client)
deleted(_ file: File, client: Client)
commentAdded(_ file: File, comment: Comment, client: Client)
commentEdited(_ file: File, comment: Comment, client: Client)
commentDeleted(_ file: File, comment: Comment, client: Client)
```
##### PinEventsDelegate
```swift
pinned(_ item: Item, channel: Channel?, client: Client)
unpinned(_ item: Item, channel: Channel?, client: Client)
```
##### StarEventsDelegate
```swift
starred(_ item: Item, starred: Bool, _ client: Client)
```
##### ReactionEventsDelegate
```swift
added(_ reaction: String, item: Item, itemUser: String, client: Client)
removed(_ reaction: String, item: Item, itemUser: String, client: Client)
```
##### SlackEventsDelegate
```swift
preferenceChanged(_ preference: String, value: Any?, client: Client)
userChanged(_ user: User, client: Client)
presenceChanged(_ user: User, presence: String, client: Client)
manualPresenceChanged(_ user: User, presence: String, client: Client)
botEvent(_ bot: Bot, client: Client)
```
##### TeamEventsDelegate
```swift
userJoined(_ user: User, client: Client)
planChanged(_ plan: String, client: Client)
preferencesChanged(_ preference: String, value: Any?, client: Client)
nameChanged(_ name: String, client: Client)
domainChanged(_ domain: String, client: Client)
emailDomainChanged(_ domain: String, client: Client)
emojiChanged(_ client: Client)
```
##### SubteamEventsDelegate
```swift
event(_ userGroup: UserGroup, client: Client)
selfAdded(_ subteamID: String, client: Client)
selfRemoved(_ subteamID: String, client: Client)
```
##### TeamProfileEventsDelegate
```swift
changed(_ profile: CustomProfile, client: Client)
deleted(_ profile: CustomProfile, client: Client)
reordered(_ profile: CustomProfile, client: Client)
```
#####MessageEventsDelegate
```swift
func messageSent(message: Message)
func messageReceived(message: Message)
func messageChanged(message: Message)
func messageDeleted(message: Message?)
```
### Examples
[Check out example applications here.](https://github.com/pvzig/SlackKit-examples)
#####ChannelEventsDelegate
```swift
func userTyping(channel: Channel?, user: User?)
func channelMarked(channel: Channel, timestamp: String?)
func channelCreated(channel: Channel)
func channelDeleted(channel: Channel)
func channelRenamed(channel: Channel)
func channelArchived(channel: Channel)
func channelHistoryChanged(channel: Channel)
func channelJoined(channel: Channel)
func channelLeft(channel: Channel)
```
#####DoNotDisturbEventsDelegate
```swift
doNotDisturbUpdated(dndStatus: DoNotDisturbStatus)
doNotDisturbUserUpdated(dndStatus: DoNotDisturbStatus, user: User?)
```
#####GroupEventsDelegate
```swift
func groupOpened(group: Channel)
```
#####FileEventsDelegate
```swift
func fileProcessed(file: File)
func fileMadePrivate(file: File)
func fileDeleted(file: File)
func fileCommentAdded(file: File, comment: Comment)
func fileCommentEdited(file: File, comment: Comment)
func fileCommentDeleted(file: File, comment: Comment)
```
#####PinEventsDelegate
```swift
func itemPinned(item: Item?, channel: Channel?)
func itemUnpinned(item: Item?, channel: Channel?)
```
#####StarEventsDelegate
```swift
func itemStarred(item: Item, star: Bool)
```
#####ReactionEventsDelegate
```swift
func reactionAdded(reaction: String?, item: Item?, itemUser: String?)
func reactionRemoved(reaction: String?, item: Item?, itemUser: String?)
```
#####TeamEventsDelegate
```swift
func teamJoined(user: User)
func teamPlanChanged(plan: String)
func teamPreferencesChanged(preference: String, value: AnyObject)
func teamNameChanged(name: String)
func teamDomainChanged(domain: String)
func teamEmailDomainChanged(domain: String)
func teamEmojiChanged()
```
#####SubteamEventsDelegate
```swift
func subteamEvent(userGroup: UserGroup)
func subteamSelfAdded(subteamID: String)
func subteamSelfRemoved(subteamID: String)
```
###Get In Touch
### Get In Touch
[@pvzig](https://twitter.com/pvzig)
<peter@launchsoft.co>
+18
View File
@@ -0,0 +1,18 @@
Pod::Spec.new do |s|
s.name = "SlackKit"
s.version = "3.1.5"
s.summary = "a Slack client library for OS X, iOS, and tvOS written in Swift"
s.homepage = "https://github.com/pvzig/SlackKit"
s.license = 'MIT'
s.author = { "Peter Zignego" => "peter@launchsoft.co" }
s.source = { :git => "https://github.com/pvzig/SlackKit.git", :tag => s.version.to_s }
s.social_media_url = 'https://twitter.com/pvzig'
s.ios.deployment_target = '8.0'
s.osx.deployment_target = '10.10'
s.tvos.deployment_target = '9.0'
s.requires_arc = true
s.source_files = 'SlackKit/Sources/*.swift'
s.frameworks = 'Foundation'
s.dependency 'Starscream'
s.dependency 'Swifter'
end
+980
View File
@@ -0,0 +1,980 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
2601D61B1C7646B80012BF22 /* SlackError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2601D61A1C7646B80012BF22 /* SlackError.swift */; };
260EC2331C4DC61D0093B253 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 260EC2301C4DC61D0093B253 /* Extensions.swift */; };
260EC2341C4DC61D0093B253 /* NetworkInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 260EC2311C4DC61D0093B253 /* NetworkInterface.swift */; };
260EC2351C4DC61D0093B253 /* WebAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 260EC2321C4DC61D0093B253 /* WebAPI.swift */; };
263993901CE90C87004A6E93 /* SlackKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 2661A6A41BBF62FF0026F67B /* SlackKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
263993971CE90EE0004A6E93 /* Client+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C16C98791CE7D3DD00692776 /* Client+Utilities.swift */; };
263993981CE90EE0004A6E93 /* Channel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1881C398E3C00BF7225 /* Channel.swift */; };
263993991CE90EE0004A6E93 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1921C398E3C00BF7225 /* User.swift */; };
2639939B1CE90EE0004A6E93 /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1891C398E3C00BF7225 /* Client.swift */; };
2639939C1CE90EE0004A6E93 /* Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA18A1C398E3C00BF7225 /* Event.swift */; };
2639939D1CE90EE0004A6E93 /* Bot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1871C398E3C00BF7225 /* Bot.swift */; };
2639939E1CE90EE0004A6E93 /* Client+EventDispatching.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1A85FF71CE3BCEF00756C40 /* Client+EventDispatching.swift */; };
2639939F1CE90EE0004A6E93 /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA18E1C398E3C00BF7225 /* File.swift */; };
263993A01CE90EE0004A6E93 /* WebAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 260EC2321C4DC61D0093B253 /* WebAPI.swift */; };
263993A11CE90EE0004A6E93 /* Attachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26DF40341C7A0FA300E19241 /* Attachment.swift */; };
263993A21CE90EE0004A6E93 /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA18F1C398E3C00BF7225 /* Message.swift */; };
263993A31CE90EE0004A6E93 /* Team.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1901C398E3C00BF7225 /* Team.swift */; };
263993A41CE90EE0004A6E93 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 260EC2301C4DC61D0093B253 /* Extensions.swift */; };
263993A51CE90EE0004A6E93 /* UserGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1931C398E3C00BF7225 /* UserGroup.swift */; };
263993A61CE90EE0004A6E93 /* SlackError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2601D61A1C7646B80012BF22 /* SlackError.swift */; };
263993A71CE90EE0004A6E93 /* Client+EventHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1A85FF81CE3BCEF00756C40 /* Client+EventHandling.swift */; };
263993A81CE90EE0004A6E93 /* NetworkInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 260EC2311C4DC61D0093B253 /* NetworkInterface.swift */; };
263993A91CE90EE0004A6E93 /* EventDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA18B1C398E3C00BF7225 /* EventDelegate.swift */; };
263993AD1CE90EE0004A6E93 /* SlackKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 2661A6A41BBF62FF0026F67B /* SlackKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
263993B61CE90EED004A6E93 /* Client+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C16C98791CE7D3DD00692776 /* Client+Utilities.swift */; };
263993B71CE90EED004A6E93 /* Channel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1881C398E3C00BF7225 /* Channel.swift */; };
263993B81CE90EED004A6E93 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1921C398E3C00BF7225 /* User.swift */; };
263993BA1CE90EED004A6E93 /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1891C398E3C00BF7225 /* Client.swift */; };
263993BB1CE90EED004A6E93 /* Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA18A1C398E3C00BF7225 /* Event.swift */; };
263993BC1CE90EED004A6E93 /* Bot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1871C398E3C00BF7225 /* Bot.swift */; };
263993BD1CE90EED004A6E93 /* Client+EventDispatching.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1A85FF71CE3BCEF00756C40 /* Client+EventDispatching.swift */; };
263993BE1CE90EED004A6E93 /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA18E1C398E3C00BF7225 /* File.swift */; };
263993BF1CE90EED004A6E93 /* WebAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 260EC2321C4DC61D0093B253 /* WebAPI.swift */; };
263993C01CE90EED004A6E93 /* Attachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26DF40341C7A0FA300E19241 /* Attachment.swift */; };
263993C11CE90EED004A6E93 /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA18F1C398E3C00BF7225 /* Message.swift */; };
263993C21CE90EED004A6E93 /* Team.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1901C398E3C00BF7225 /* Team.swift */; };
263993C31CE90EED004A6E93 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 260EC2301C4DC61D0093B253 /* Extensions.swift */; };
263993C41CE90EED004A6E93 /* UserGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1931C398E3C00BF7225 /* UserGroup.swift */; };
263993C51CE90EED004A6E93 /* SlackError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2601D61A1C7646B80012BF22 /* SlackError.swift */; };
263993C61CE90EED004A6E93 /* Client+EventHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1A85FF81CE3BCEF00756C40 /* Client+EventHandling.swift */; };
263993C71CE90EED004A6E93 /* NetworkInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 260EC2311C4DC61D0093B253 /* NetworkInterface.swift */; };
263993C81CE90EED004A6E93 /* EventDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA18B1C398E3C00BF7225 /* EventDelegate.swift */; };
263993CC1CE90EED004A6E93 /* SlackKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 2661A6A41BBF62FF0026F67B /* SlackKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
2659FC1B1DADC4E0003F3930 /* Starscream.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4307A07F1CC6D0910011D5DE /* Starscream.framework */; };
2659FC1C1DADC4E0003F3930 /* Swifter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26B30B6B1D289FA0004D4AB5 /* Swifter.framework */; };
2659FC1D1DADC4F2003F3930 /* Swifter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26B30B6E1D289FB2004D4AB5 /* Swifter.framework */; };
2659FC1F1DADC4F2003F3930 /* Starscream.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2659FC1E1DADC4F2003F3930 /* Starscream.framework */; };
2659FC201DADC4FC003F3930 /* Swifter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 269B47CB1D3AE5670042D137 /* Swifter.framework */; };
2659FC221DADC4FC003F3930 /* Starscream.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2659FC211DADC4FC003F3930 /* Starscream.framework */; };
2678B5941D3151B900CE521A /* AuthorizeResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2678B5931D3151B900CE521A /* AuthorizeResponse.swift */; };
2678B5951D3151B900CE521A /* AuthorizeResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2678B5931D3151B900CE521A /* AuthorizeResponse.swift */; };
2678B5961D3151B900CE521A /* AuthorizeResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2678B5931D3151B900CE521A /* AuthorizeResponse.swift */; };
2678B5971D3151C600CE521A /* MessageActionRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26B30B871D297A98004D4AB5 /* MessageActionRequest.swift */; };
2678B5981D3151C900CE521A /* Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26B30B931D298E78004D4AB5 /* Response.swift */; };
2678B5991D3151CD00CE521A /* WebhookRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26B30B981D298F25004D4AB5 /* WebhookRequest.swift */; };
269B475A1D3493DE0042D137 /* OAuthResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 269B47591D3493DE0042D137 /* OAuthResponse.swift */; };
269B475B1D3493DE0042D137 /* OAuthResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 269B47591D3493DE0042D137 /* OAuthResponse.swift */; };
269B475C1D3493DE0042D137 /* OAuthResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 269B47591D3493DE0042D137 /* OAuthResponse.swift */; };
269B475E1D3538E90042D137 /* SlackKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 269B475D1D3538E90042D137 /* SlackKit.swift */; };
269B475F1D3538E90042D137 /* SlackKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 269B475D1D3538E90042D137 /* SlackKit.swift */; };
269B47601D3538E90042D137 /* SlackKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 269B475D1D3538E90042D137 /* SlackKit.swift */; };
269B47621D3544240042D137 /* IncomingWebhook.swift in Sources */ = {isa = PBXBuildFile; fileRef = 269B47611D3544240042D137 /* IncomingWebhook.swift */; };
269B47631D3544240042D137 /* IncomingWebhook.swift in Sources */ = {isa = PBXBuildFile; fileRef = 269B47611D3544240042D137 /* IncomingWebhook.swift */; };
269B47641D3544240042D137 /* IncomingWebhook.swift in Sources */ = {isa = PBXBuildFile; fileRef = 269B47611D3544240042D137 /* IncomingWebhook.swift */; };
269B47661D39AAA80042D137 /* MessageActionResponder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 269B47651D39AAA80042D137 /* MessageActionResponder.swift */; };
269B47671D39AAA80042D137 /* MessageActionResponder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 269B47651D39AAA80042D137 /* MessageActionResponder.swift */; };
269B47681D39AAA80042D137 /* MessageActionResponder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 269B47651D39AAA80042D137 /* MessageActionResponder.swift */; };
269B47C71D3AE25B0042D137 /* MessageActionServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26B30B8F1D298E08004D4AB5 /* MessageActionServer.swift */; };
269B47C81D3AE25B0042D137 /* MessageActionServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26B30B8F1D298E08004D4AB5 /* MessageActionServer.swift */; };
269B47C91D3AE2620042D137 /* Server.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26B30B911D298E12004D4AB5 /* Server.swift */; };
269B47CA1D3AE2670042D137 /* WebhookServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC15001D260B1000FD3A53 /* WebhookServer.swift */; };
269B47CE1D3C22FC0042D137 /* ClientOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 269B47CD1D3C22FC0042D137 /* ClientOptions.swift */; };
269B47CF1D3C22FC0042D137 /* ClientOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 269B47CD1D3C22FC0042D137 /* ClientOptions.swift */; };
269B47D01D3C22FC0042D137 /* ClientOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 269B47CD1D3C22FC0042D137 /* ClientOptions.swift */; };
26B30B881D297A98004D4AB5 /* MessageActionRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26B30B871D297A98004D4AB5 /* MessageActionRequest.swift */; };
26B30B901D298E08004D4AB5 /* MessageActionServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26B30B8F1D298E08004D4AB5 /* MessageActionServer.swift */; };
26B30B921D298E12004D4AB5 /* Server.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26B30B911D298E12004D4AB5 /* Server.swift */; };
26B30B941D298E78004D4AB5 /* Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26B30B931D298E78004D4AB5 /* Response.swift */; };
26B30B951D298E78004D4AB5 /* Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26B30B931D298E78004D4AB5 /* Response.swift */; };
26B30B961D298EE1004D4AB5 /* MessageActionRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26B30B871D297A98004D4AB5 /* MessageActionRequest.swift */; };
26B30B971D298EED004D4AB5 /* Server.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26B30B911D298E12004D4AB5 /* Server.swift */; };
26B30B991D298F25004D4AB5 /* WebhookRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26B30B981D298F25004D4AB5 /* WebhookRequest.swift */; };
26B30B9A1D298F25004D4AB5 /* WebhookRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26B30B981D298F25004D4AB5 /* WebhookRequest.swift */; };
26B30BB61D2BC2E4004D4AB5 /* Scope.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26B30BB51D2BC2E4004D4AB5 /* Scope.swift */; };
26B30BB71D2BC2E4004D4AB5 /* Scope.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26B30BB51D2BC2E4004D4AB5 /* Scope.swift */; };
26B30BB81D2BC2E4004D4AB5 /* Scope.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26B30BB51D2BC2E4004D4AB5 /* Scope.swift */; };
26B30BC31D2DFF0D004D4AB5 /* OAuthServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26B30BC21D2DFF0D004D4AB5 /* OAuthServer.swift */; };
26B30BC41D2DFF0D004D4AB5 /* OAuthServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26B30BC21D2DFF0D004D4AB5 /* OAuthServer.swift */; };
26B30BC51D2DFF0D004D4AB5 /* OAuthServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26B30BC21D2DFF0D004D4AB5 /* OAuthServer.swift */; };
26B30BC71D2DFF7D004D4AB5 /* AuthorizeRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26B30BC61D2DFF7D004D4AB5 /* AuthorizeRequest.swift */; };
26B30BC81D2DFF7D004D4AB5 /* AuthorizeRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26B30BC61D2DFF7D004D4AB5 /* AuthorizeRequest.swift */; };
26B30BC91D2DFF7D004D4AB5 /* AuthorizeRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26B30BC61D2DFF7D004D4AB5 /* AuthorizeRequest.swift */; };
26BBA1941C398E3C00BF7225 /* Bot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1871C398E3C00BF7225 /* Bot.swift */; };
26BBA1951C398E3C00BF7225 /* Channel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1881C398E3C00BF7225 /* Channel.swift */; };
26BBA1961C398E3C00BF7225 /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1891C398E3C00BF7225 /* Client.swift */; };
26BBA1971C398E3C00BF7225 /* Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA18A1C398E3C00BF7225 /* Event.swift */; };
26BBA1981C398E3C00BF7225 /* EventDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA18B1C398E3C00BF7225 /* EventDelegate.swift */; };
26BBA19B1C398E3C00BF7225 /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA18E1C398E3C00BF7225 /* File.swift */; };
26BBA19C1C398E3C00BF7225 /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA18F1C398E3C00BF7225 /* Message.swift */; };
26BBA19D1C398E3C00BF7225 /* Team.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1901C398E3C00BF7225 /* Team.swift */; };
26BBA19F1C398E3C00BF7225 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1921C398E3C00BF7225 /* User.swift */; };
26BBA1A01C398E3C00BF7225 /* UserGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1931C398E3C00BF7225 /* UserGroup.swift */; };
26DF40351C7A0FA300E19241 /* Attachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26DF40341C7A0FA300E19241 /* Attachment.swift */; };
26EC14C11D1EF16500FD3A53 /* AttachmentField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14C01D1EF16500FD3A53 /* AttachmentField.swift */; };
26EC14C21D1EF16500FD3A53 /* AttachmentField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14C01D1EF16500FD3A53 /* AttachmentField.swift */; };
26EC14C31D1EF16500FD3A53 /* AttachmentField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14C01D1EF16500FD3A53 /* AttachmentField.swift */; };
26EC14C91D1EF17400FD3A53 /* Comment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14C41D1EF17400FD3A53 /* Comment.swift */; };
26EC14CA1D1EF17400FD3A53 /* Comment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14C41D1EF17400FD3A53 /* Comment.swift */; };
26EC14CB1D1EF17400FD3A53 /* Comment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14C41D1EF17400FD3A53 /* Comment.swift */; };
26EC14CC1D1EF17400FD3A53 /* CustomProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14C51D1EF17400FD3A53 /* CustomProfile.swift */; };
26EC14CD1D1EF17400FD3A53 /* CustomProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14C51D1EF17400FD3A53 /* CustomProfile.swift */; };
26EC14CE1D1EF17400FD3A53 /* CustomProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14C51D1EF17400FD3A53 /* CustomProfile.swift */; };
26EC14CF1D1EF17400FD3A53 /* CustomProfileField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14C61D1EF17400FD3A53 /* CustomProfileField.swift */; };
26EC14D01D1EF17400FD3A53 /* CustomProfileField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14C61D1EF17400FD3A53 /* CustomProfileField.swift */; };
26EC14D11D1EF17400FD3A53 /* CustomProfileField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14C61D1EF17400FD3A53 /* CustomProfileField.swift */; };
26EC14D21D1EF17400FD3A53 /* DoNotDisturbStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14C71D1EF17400FD3A53 /* DoNotDisturbStatus.swift */; };
26EC14D31D1EF17400FD3A53 /* DoNotDisturbStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14C71D1EF17400FD3A53 /* DoNotDisturbStatus.swift */; };
26EC14D41D1EF17400FD3A53 /* DoNotDisturbStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14C71D1EF17400FD3A53 /* DoNotDisturbStatus.swift */; };
26EC14D51D1EF17400FD3A53 /* Edited.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14C81D1EF17400FD3A53 /* Edited.swift */; };
26EC14D61D1EF17400FD3A53 /* Edited.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14C81D1EF17400FD3A53 /* Edited.swift */; };
26EC14D71D1EF17400FD3A53 /* Edited.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14C81D1EF17400FD3A53 /* Edited.swift */; };
26EC14DA1D1EF17E00FD3A53 /* History.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14D81D1EF17E00FD3A53 /* History.swift */; };
26EC14DB1D1EF17E00FD3A53 /* History.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14D81D1EF17E00FD3A53 /* History.swift */; };
26EC14DC1D1EF17E00FD3A53 /* History.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14D81D1EF17E00FD3A53 /* History.swift */; };
26EC14DD1D1EF17E00FD3A53 /* Item.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14D91D1EF17E00FD3A53 /* Item.swift */; };
26EC14DE1D1EF17E00FD3A53 /* Item.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14D91D1EF17E00FD3A53 /* Item.swift */; };
26EC14DF1D1EF17E00FD3A53 /* Item.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14D91D1EF17E00FD3A53 /* Item.swift */; };
26EC14E11D1EF18700FD3A53 /* Reaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14E01D1EF18700FD3A53 /* Reaction.swift */; };
26EC14E21D1EF18700FD3A53 /* Reaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14E01D1EF18700FD3A53 /* Reaction.swift */; };
26EC14E31D1EF18700FD3A53 /* Reaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14E01D1EF18700FD3A53 /* Reaction.swift */; };
26EC14E61D1EF18F00FD3A53 /* TeamIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14E41D1EF18F00FD3A53 /* TeamIcon.swift */; };
26EC14E71D1EF18F00FD3A53 /* TeamIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14E41D1EF18F00FD3A53 /* TeamIcon.swift */; };
26EC14E81D1EF18F00FD3A53 /* TeamIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14E41D1EF18F00FD3A53 /* TeamIcon.swift */; };
26EC14E91D1EF18F00FD3A53 /* Topic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14E51D1EF18F00FD3A53 /* Topic.swift */; };
26EC14EA1D1EF18F00FD3A53 /* Topic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14E51D1EF18F00FD3A53 /* Topic.swift */; };
26EC14EB1D1EF18F00FD3A53 /* Topic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14E51D1EF18F00FD3A53 /* Topic.swift */; };
26EC14F91D1F355A00FD3A53 /* Action.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14F81D1F355A00FD3A53 /* Action.swift */; };
26EC14FA1D1F355A00FD3A53 /* Action.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14F81D1F355A00FD3A53 /* Action.swift */; };
26EC14FB1D1F355A00FD3A53 /* Action.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC14F81D1F355A00FD3A53 /* Action.swift */; };
26EC15011D260B1000FD3A53 /* WebhookServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC15001D260B1000FD3A53 /* WebhookServer.swift */; };
26EC15021D260B1000FD3A53 /* WebhookServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EC15001D260B1000FD3A53 /* WebhookServer.swift */; };
C16C987A1CE7D3DD00692776 /* Client+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C16C98791CE7D3DD00692776 /* Client+Utilities.swift */; };
C1A85FF91CE3BCEF00756C40 /* Client+EventDispatching.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1A85FF71CE3BCEF00756C40 /* Client+EventDispatching.swift */; };
C1A85FFA1CE3BCEF00756C40 /* Client+EventHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1A85FF81CE3BCEF00756C40 /* Client+EventHandling.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
2601D61A1C7646B80012BF22 /* SlackError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SlackError.swift; path = Sources/SlackError.swift; sourceTree = "<group>"; };
26072A341BB48B3A00CD650C /* SlackKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SlackKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
260EC2301C4DC61D0093B253 /* Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Extensions.swift; path = Sources/Extensions.swift; sourceTree = "<group>"; };
260EC2311C4DC61D0093B253 /* NetworkInterface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NetworkInterface.swift; path = Sources/NetworkInterface.swift; sourceTree = "<group>"; };
260EC2321C4DC61D0093B253 /* WebAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WebAPI.swift; path = Sources/WebAPI.swift; sourceTree = "<group>"; };
263993B21CE90EE0004A6E93 /* SlackKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SlackKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
263993D11CE90EED004A6E93 /* SlackKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SlackKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
2659FC1E1DADC4F2003F3930 /* Starscream.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Starscream.framework; path = Carthage/Build/iOS/Starscream.framework; sourceTree = "<group>"; };
2659FC211DADC4FC003F3930 /* Starscream.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Starscream.framework; path = Carthage/Build/tvOS/Starscream.framework; sourceTree = "<group>"; };
2661A6A41BBF62FF0026F67B /* SlackKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SlackKit.h; sourceTree = "<group>"; };
2678B5931D3151B900CE521A /* AuthorizeResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AuthorizeResponse.swift; path = Sources/AuthorizeResponse.swift; sourceTree = "<group>"; };
268E46131CE8F79D009F19CC /* Info-iOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Info-iOS.plist"; path = "Supporting Files/Info-iOS.plist"; sourceTree = "<group>"; };
268E46141CE8F79D009F19CC /* Info-tvOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Info-tvOS.plist"; path = "Supporting Files/Info-tvOS.plist"; sourceTree = "<group>"; };
268E46151CE8F79D009F19CC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = "Supporting Files/Info.plist"; sourceTree = "<group>"; };
269B47591D3493DE0042D137 /* OAuthResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OAuthResponse.swift; path = Sources/OAuthResponse.swift; sourceTree = "<group>"; };
269B475D1D3538E90042D137 /* SlackKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SlackKit.swift; path = Sources/SlackKit.swift; sourceTree = "<group>"; };
269B47611D3544240042D137 /* IncomingWebhook.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = IncomingWebhook.swift; path = Sources/IncomingWebhook.swift; sourceTree = "<group>"; };
269B47651D39AAA80042D137 /* MessageActionResponder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MessageActionResponder.swift; path = Sources/MessageActionResponder.swift; sourceTree = "<group>"; };
269B47CB1D3AE5670042D137 /* Swifter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Swifter.framework; path = Carthage/Build/tvOS/Swifter.framework; sourceTree = "<group>"; };
269B47CD1D3C22FC0042D137 /* ClientOptions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ClientOptions.swift; path = Sources/ClientOptions.swift; sourceTree = "<group>"; };
26B30B6B1D289FA0004D4AB5 /* Swifter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Swifter.framework; path = Carthage/Build/Mac/Swifter.framework; sourceTree = "<group>"; };
26B30B6E1D289FB2004D4AB5 /* Swifter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Swifter.framework; path = Carthage/Build/iOS/Swifter.framework; sourceTree = "<group>"; };
26B30B871D297A98004D4AB5 /* MessageActionRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MessageActionRequest.swift; path = Sources/MessageActionRequest.swift; sourceTree = "<group>"; };
26B30B8F1D298E08004D4AB5 /* MessageActionServer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MessageActionServer.swift; path = Sources/MessageActionServer.swift; sourceTree = "<group>"; };
26B30B911D298E12004D4AB5 /* Server.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Server.swift; path = Sources/Server.swift; sourceTree = "<group>"; };
26B30B931D298E78004D4AB5 /* Response.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Response.swift; path = Sources/Response.swift; sourceTree = "<group>"; };
26B30B981D298F25004D4AB5 /* WebhookRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WebhookRequest.swift; path = Sources/WebhookRequest.swift; sourceTree = "<group>"; };
26B30BB51D2BC2E4004D4AB5 /* Scope.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Scope.swift; path = Sources/Scope.swift; sourceTree = "<group>"; };
26B30BC21D2DFF0D004D4AB5 /* OAuthServer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OAuthServer.swift; path = Sources/OAuthServer.swift; sourceTree = "<group>"; };
26B30BC61D2DFF7D004D4AB5 /* AuthorizeRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AuthorizeRequest.swift; path = Sources/AuthorizeRequest.swift; sourceTree = "<group>"; };
26BBA1871C398E3C00BF7225 /* Bot.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Bot.swift; path = Sources/Bot.swift; sourceTree = "<group>"; };
26BBA1881C398E3C00BF7225 /* Channel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Channel.swift; path = Sources/Channel.swift; sourceTree = "<group>"; };
26BBA1891C398E3C00BF7225 /* Client.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Client.swift; path = Sources/Client.swift; sourceTree = "<group>"; };
26BBA18A1C398E3C00BF7225 /* Event.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Event.swift; path = Sources/Event.swift; sourceTree = "<group>"; };
26BBA18B1C398E3C00BF7225 /* EventDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = EventDelegate.swift; path = Sources/EventDelegate.swift; sourceTree = "<group>"; };
26BBA18E1C398E3C00BF7225 /* File.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = File.swift; path = Sources/File.swift; sourceTree = "<group>"; };
26BBA18F1C398E3C00BF7225 /* Message.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Message.swift; path = Sources/Message.swift; sourceTree = "<group>"; };
26BBA1901C398E3C00BF7225 /* Team.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Team.swift; path = Sources/Team.swift; sourceTree = "<group>"; };
26BBA1921C398E3C00BF7225 /* User.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = User.swift; path = Sources/User.swift; sourceTree = "<group>"; };
26BBA1931C398E3C00BF7225 /* UserGroup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = UserGroup.swift; path = Sources/UserGroup.swift; sourceTree = "<group>"; };
26DF40341C7A0FA300E19241 /* Attachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Attachment.swift; path = Sources/Attachment.swift; sourceTree = "<group>"; };
26EC14C01D1EF16500FD3A53 /* AttachmentField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentField.swift; path = Sources/AttachmentField.swift; sourceTree = "<group>"; };
26EC14C41D1EF17400FD3A53 /* Comment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Comment.swift; path = Sources/Comment.swift; sourceTree = "<group>"; };
26EC14C51D1EF17400FD3A53 /* CustomProfile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CustomProfile.swift; path = Sources/CustomProfile.swift; sourceTree = "<group>"; };
26EC14C61D1EF17400FD3A53 /* CustomProfileField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CustomProfileField.swift; path = Sources/CustomProfileField.swift; sourceTree = "<group>"; };
26EC14C71D1EF17400FD3A53 /* DoNotDisturbStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DoNotDisturbStatus.swift; path = Sources/DoNotDisturbStatus.swift; sourceTree = "<group>"; };
26EC14C81D1EF17400FD3A53 /* Edited.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Edited.swift; path = Sources/Edited.swift; sourceTree = "<group>"; };
26EC14D81D1EF17E00FD3A53 /* History.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = History.swift; path = Sources/History.swift; sourceTree = "<group>"; };
26EC14D91D1EF17E00FD3A53 /* Item.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Item.swift; path = Sources/Item.swift; sourceTree = "<group>"; };
26EC14E01D1EF18700FD3A53 /* Reaction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Reaction.swift; path = Sources/Reaction.swift; sourceTree = "<group>"; };
26EC14E41D1EF18F00FD3A53 /* TeamIcon.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TeamIcon.swift; path = Sources/TeamIcon.swift; sourceTree = "<group>"; };
26EC14E51D1EF18F00FD3A53 /* Topic.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Topic.swift; path = Sources/Topic.swift; sourceTree = "<group>"; };
26EC14F81D1F355A00FD3A53 /* Action.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Action.swift; path = Sources/Action.swift; sourceTree = "<group>"; };
26EC15001D260B1000FD3A53 /* WebhookServer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WebhookServer.swift; path = Sources/WebhookServer.swift; sourceTree = "<group>"; };
4307A07F1CC6D0910011D5DE /* Starscream.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Starscream.framework; path = Carthage/Build/Mac/Starscream.framework; sourceTree = "<group>"; };
C16C98791CE7D3DD00692776 /* Client+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Client+Utilities.swift"; path = "Sources/Client+Utilities.swift"; sourceTree = "<group>"; };
C1A85FF71CE3BCEF00756C40 /* Client+EventDispatching.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Client+EventDispatching.swift"; path = "Sources/Client+EventDispatching.swift"; sourceTree = "<group>"; };
C1A85FF81CE3BCEF00756C40 /* Client+EventHandling.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Client+EventHandling.swift"; path = "Sources/Client+EventHandling.swift"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
26072A301BB48B3A00CD650C /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
2659FC1B1DADC4E0003F3930 /* Starscream.framework in Frameworks */,
2659FC1C1DADC4E0003F3930 /* Swifter.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
263993AA1CE90EE0004A6E93 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
2659FC1F1DADC4F2003F3930 /* Starscream.framework in Frameworks */,
2659FC1D1DADC4F2003F3930 /* Swifter.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
263993C91CE90EED004A6E93 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
2659FC221DADC4FC003F3930 /* Starscream.framework in Frameworks */,
2659FC201DADC4FC003F3930 /* Swifter.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
26072A2A1BB48B3A00CD650C = {
isa = PBXGroup;
children = (
2661A6811BBF60E60026F67B /* SlackKit */,
26072A351BB48B3A00CD650C /* Products */,
CA70A3A1A9A1A259960DFBCF /* Frameworks */,
);
sourceTree = "<group>";
};
26072A351BB48B3A00CD650C /* Products */ = {
isa = PBXGroup;
children = (
26072A341BB48B3A00CD650C /* SlackKit.framework */,
263993B21CE90EE0004A6E93 /* SlackKit.framework */,
263993D11CE90EED004A6E93 /* SlackKit.framework */,
);
name = Products;
sourceTree = "<group>";
};
2661A6811BBF60E60026F67B /* SlackKit */ = {
isa = PBXGroup;
children = (
26BBA1891C398E3C00BF7225 /* Client.swift */,
C1A85FF71CE3BCEF00756C40 /* Client+EventDispatching.swift */,
C1A85FF81CE3BCEF00756C40 /* Client+EventHandling.swift */,
C16C98791CE7D3DD00692776 /* Client+Utilities.swift */,
26BBA18B1C398E3C00BF7225 /* EventDelegate.swift */,
260EC2301C4DC61D0093B253 /* Extensions.swift */,
269B47611D3544240042D137 /* IncomingWebhook.swift */,
260EC2311C4DC61D0093B253 /* NetworkInterface.swift */,
26B30B8F1D298E08004D4AB5 /* MessageActionServer.swift */,
269B47651D39AAA80042D137 /* MessageActionResponder.swift */,
26B30BC21D2DFF0D004D4AB5 /* OAuthServer.swift */,
26B30B911D298E12004D4AB5 /* Server.swift */,
269B475D1D3538E90042D137 /* SlackKit.swift */,
260EC2321C4DC61D0093B253 /* WebAPI.swift */,
26EC15001D260B1000FD3A53 /* WebhookServer.swift */,
26EC14B31D1B974500FD3A53 /* Models */,
268E46161CE8F7A2009F19CC /* Supporting Files */,
);
path = SlackKit;
sourceTree = "<group>";
};
268E46161CE8F7A2009F19CC /* Supporting Files */ = {
isa = PBXGroup;
children = (
2661A6A41BBF62FF0026F67B /* SlackKit.h */,
268E46151CE8F79D009F19CC /* Info.plist */,
268E46131CE8F79D009F19CC /* Info-iOS.plist */,
268E46141CE8F79D009F19CC /* Info-tvOS.plist */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
26B30B9B1D29AB1E004D4AB5 /* Server */ = {
isa = PBXGroup;
children = (
26B30B871D297A98004D4AB5 /* MessageActionRequest.swift */,
26B30B931D298E78004D4AB5 /* Response.swift */,
26B30B981D298F25004D4AB5 /* WebhookRequest.swift */,
);
name = Server;
sourceTree = "<group>";
};
26B30BB91D2BC2EA004D4AB5 /* Auth */ = {
isa = PBXGroup;
children = (
26B30BC61D2DFF7D004D4AB5 /* AuthorizeRequest.swift */,
2678B5931D3151B900CE521A /* AuthorizeResponse.swift */,
26B30BB51D2BC2E4004D4AB5 /* Scope.swift */,
269B47591D3493DE0042D137 /* OAuthResponse.swift */,
);
name = Auth;
sourceTree = "<group>";
};
26EC14B31D1B974500FD3A53 /* Models */ = {
isa = PBXGroup;
children = (
26EC14F81D1F355A00FD3A53 /* Action.swift */,
26DF40341C7A0FA300E19241 /* Attachment.swift */,
26EC14C01D1EF16500FD3A53 /* AttachmentField.swift */,
26BBA1871C398E3C00BF7225 /* Bot.swift */,
26BBA1881C398E3C00BF7225 /* Channel.swift */,
269B47CD1D3C22FC0042D137 /* ClientOptions.swift */,
26EC14C41D1EF17400FD3A53 /* Comment.swift */,
26EC14C51D1EF17400FD3A53 /* CustomProfile.swift */,
26EC14C61D1EF17400FD3A53 /* CustomProfileField.swift */,
26EC14C71D1EF17400FD3A53 /* DoNotDisturbStatus.swift */,
26EC14C81D1EF17400FD3A53 /* Edited.swift */,
26BBA18A1C398E3C00BF7225 /* Event.swift */,
26BBA18E1C398E3C00BF7225 /* File.swift */,
26EC14D81D1EF17E00FD3A53 /* History.swift */,
26EC14D91D1EF17E00FD3A53 /* Item.swift */,
26BBA18F1C398E3C00BF7225 /* Message.swift */,
26EC14E01D1EF18700FD3A53 /* Reaction.swift */,
2601D61A1C7646B80012BF22 /* SlackError.swift */,
26BBA1901C398E3C00BF7225 /* Team.swift */,
26EC14E41D1EF18F00FD3A53 /* TeamIcon.swift */,
26EC14E51D1EF18F00FD3A53 /* Topic.swift */,
26BBA1921C398E3C00BF7225 /* User.swift */,
26BBA1931C398E3C00BF7225 /* UserGroup.swift */,
26B30BB91D2BC2EA004D4AB5 /* Auth */,
26B30B9B1D29AB1E004D4AB5 /* Server */,
);
name = Models;
sourceTree = "<group>";
};
CA70A3A1A9A1A259960DFBCF /* Frameworks */ = {
isa = PBXGroup;
children = (
2659FC211DADC4FC003F3930 /* Starscream.framework */,
2659FC1E1DADC4F2003F3930 /* Starscream.framework */,
269B47CB1D3AE5670042D137 /* Swifter.framework */,
26B30B6E1D289FB2004D4AB5 /* Swifter.framework */,
26B30B6B1D289FA0004D4AB5 /* Swifter.framework */,
4307A07F1CC6D0910011D5DE /* Starscream.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
26072A311BB48B3A00CD650C /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
263993901CE90C87004A6E93 /* SlackKit.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
263993AC1CE90EE0004A6E93 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
263993AD1CE90EE0004A6E93 /* SlackKit.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
263993CB1CE90EED004A6E93 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
263993CC1CE90EED004A6E93 /* SlackKit.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
26072A331BB48B3A00CD650C /* SlackKit OS X */ = {
isa = PBXNativeTarget;
buildConfigurationList = 26072A3C1BB48B3B00CD650C /* Build configuration list for PBXNativeTarget "SlackKit OS X" */;
buildPhases = (
26072A2F1BB48B3A00CD650C /* Sources */,
26072A301BB48B3A00CD650C /* Frameworks */,
26072A311BB48B3A00CD650C /* Headers */,
26072A321BB48B3A00CD650C /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = "SlackKit OS X";
productName = SlackRTMKit;
productReference = 26072A341BB48B3A00CD650C /* SlackKit.framework */;
productType = "com.apple.product-type.framework";
};
263993951CE90EE0004A6E93 /* SlackKit iOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = 263993AF1CE90EE0004A6E93 /* Build configuration list for PBXNativeTarget "SlackKit iOS" */;
buildPhases = (
263993961CE90EE0004A6E93 /* Sources */,
263993AA1CE90EE0004A6E93 /* Frameworks */,
263993AC1CE90EE0004A6E93 /* Headers */,
263993AE1CE90EE0004A6E93 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = "SlackKit iOS";
productName = SlackRTMKit;
productReference = 263993B21CE90EE0004A6E93 /* SlackKit.framework */;
productType = "com.apple.product-type.framework";
};
263993B41CE90EED004A6E93 /* SlackKit tvOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = 263993CE1CE90EED004A6E93 /* Build configuration list for PBXNativeTarget "SlackKit tvOS" */;
buildPhases = (
263993B51CE90EED004A6E93 /* Sources */,
263993C91CE90EED004A6E93 /* Frameworks */,
263993CB1CE90EED004A6E93 /* Headers */,
263993CD1CE90EED004A6E93 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = "SlackKit tvOS";
productName = SlackRTMKit;
productReference = 263993D11CE90EED004A6E93 /* SlackKit.framework */;
productType = "com.apple.product-type.framework";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
26072A2B1BB48B3A00CD650C /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0730;
LastUpgradeCheck = 0800;
ORGANIZATIONNAME = "Launch Software LLC";
TargetAttributes = {
26072A331BB48B3A00CD650C = {
CreatedOnToolsVersion = 7.0;
LastSwiftMigration = 0800;
};
};
};
buildConfigurationList = 26072A2E1BB48B3A00CD650C /* Build configuration list for PBXProject "SlackKit" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 26072A2A1BB48B3A00CD650C;
productRefGroup = 26072A351BB48B3A00CD650C /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
26072A331BB48B3A00CD650C /* SlackKit OS X */,
263993951CE90EE0004A6E93 /* SlackKit iOS */,
263993B41CE90EED004A6E93 /* SlackKit tvOS */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
26072A321BB48B3A00CD650C /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
263993AE1CE90EE0004A6E93 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
263993CD1CE90EED004A6E93 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
26072A2F1BB48B3A00CD650C /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
2678B5941D3151B900CE521A /* AuthorizeResponse.swift in Sources */,
26B30B921D298E12004D4AB5 /* Server.swift in Sources */,
269B47CE1D3C22FC0042D137 /* ClientOptions.swift in Sources */,
269B47621D3544240042D137 /* IncomingWebhook.swift in Sources */,
C16C987A1CE7D3DD00692776 /* Client+Utilities.swift in Sources */,
26BBA1951C398E3C00BF7225 /* Channel.swift in Sources */,
26B30B901D298E08004D4AB5 /* MessageActionServer.swift in Sources */,
26B30B941D298E78004D4AB5 /* Response.swift in Sources */,
26EC14CF1D1EF17400FD3A53 /* CustomProfileField.swift in Sources */,
269B47661D39AAA80042D137 /* MessageActionResponder.swift in Sources */,
26BBA19F1C398E3C00BF7225 /* User.swift in Sources */,
26EC14DD1D1EF17E00FD3A53 /* Item.swift in Sources */,
26EC15011D260B1000FD3A53 /* WebhookServer.swift in Sources */,
26EC14CC1D1EF17400FD3A53 /* CustomProfile.swift in Sources */,
26BBA1961C398E3C00BF7225 /* Client.swift in Sources */,
26B30B881D297A98004D4AB5 /* MessageActionRequest.swift in Sources */,
269B475E1D3538E90042D137 /* SlackKit.swift in Sources */,
26B30BC71D2DFF7D004D4AB5 /* AuthorizeRequest.swift in Sources */,
26BBA1971C398E3C00BF7225 /* Event.swift in Sources */,
26EC14D21D1EF17400FD3A53 /* DoNotDisturbStatus.swift in Sources */,
26BBA1941C398E3C00BF7225 /* Bot.swift in Sources */,
26EC14E61D1EF18F00FD3A53 /* TeamIcon.swift in Sources */,
C1A85FF91CE3BCEF00756C40 /* Client+EventDispatching.swift in Sources */,
26BBA19B1C398E3C00BF7225 /* File.swift in Sources */,
26EC14F91D1F355A00FD3A53 /* Action.swift in Sources */,
26B30BC31D2DFF0D004D4AB5 /* OAuthServer.swift in Sources */,
26EC14D51D1EF17400FD3A53 /* Edited.swift in Sources */,
260EC2351C4DC61D0093B253 /* WebAPI.swift in Sources */,
26EC14E11D1EF18700FD3A53 /* Reaction.swift in Sources */,
26B30BB61D2BC2E4004D4AB5 /* Scope.swift in Sources */,
26EC14E91D1EF18F00FD3A53 /* Topic.swift in Sources */,
26DF40351C7A0FA300E19241 /* Attachment.swift in Sources */,
26BBA19C1C398E3C00BF7225 /* Message.swift in Sources */,
26BBA19D1C398E3C00BF7225 /* Team.swift in Sources */,
260EC2331C4DC61D0093B253 /* Extensions.swift in Sources */,
26BBA1A01C398E3C00BF7225 /* UserGroup.swift in Sources */,
2601D61B1C7646B80012BF22 /* SlackError.swift in Sources */,
26EC14DA1D1EF17E00FD3A53 /* History.swift in Sources */,
269B475A1D3493DE0042D137 /* OAuthResponse.swift in Sources */,
C1A85FFA1CE3BCEF00756C40 /* Client+EventHandling.swift in Sources */,
26B30B991D298F25004D4AB5 /* WebhookRequest.swift in Sources */,
26EC14C91D1EF17400FD3A53 /* Comment.swift in Sources */,
26EC14C11D1EF16500FD3A53 /* AttachmentField.swift in Sources */,
260EC2341C4DC61D0093B253 /* NetworkInterface.swift in Sources */,
26BBA1981C398E3C00BF7225 /* EventDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
263993961CE90EE0004A6E93 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
26B30B961D298EE1004D4AB5 /* MessageActionRequest.swift in Sources */,
263993971CE90EE0004A6E93 /* Client+Utilities.swift in Sources */,
269B47CF1D3C22FC0042D137 /* ClientOptions.swift in Sources */,
269B47C71D3AE25B0042D137 /* MessageActionServer.swift in Sources */,
263993981CE90EE0004A6E93 /* Channel.swift in Sources */,
26EC14D01D1EF17400FD3A53 /* CustomProfileField.swift in Sources */,
263993991CE90EE0004A6E93 /* User.swift in Sources */,
26EC14DE1D1EF17E00FD3A53 /* Item.swift in Sources */,
269B475B1D3493DE0042D137 /* OAuthResponse.swift in Sources */,
26EC15021D260B1000FD3A53 /* WebhookServer.swift in Sources */,
26B30BC41D2DFF0D004D4AB5 /* OAuthServer.swift in Sources */,
26EC14CD1D1EF17400FD3A53 /* CustomProfile.swift in Sources */,
2639939B1CE90EE0004A6E93 /* Client.swift in Sources */,
2639939C1CE90EE0004A6E93 /* Event.swift in Sources */,
26B30BC81D2DFF7D004D4AB5 /* AuthorizeRequest.swift in Sources */,
2678B5951D3151B900CE521A /* AuthorizeResponse.swift in Sources */,
26EC14D31D1EF17400FD3A53 /* DoNotDisturbStatus.swift in Sources */,
2639939D1CE90EE0004A6E93 /* Bot.swift in Sources */,
26EC14E71D1EF18F00FD3A53 /* TeamIcon.swift in Sources */,
2639939E1CE90EE0004A6E93 /* Client+EventDispatching.swift in Sources */,
26B30B971D298EED004D4AB5 /* Server.swift in Sources */,
2639939F1CE90EE0004A6E93 /* File.swift in Sources */,
26B30B951D298E78004D4AB5 /* Response.swift in Sources */,
26EC14FA1D1F355A00FD3A53 /* Action.swift in Sources */,
26EC14D61D1EF17400FD3A53 /* Edited.swift in Sources */,
263993A01CE90EE0004A6E93 /* WebAPI.swift in Sources */,
26B30B9A1D298F25004D4AB5 /* WebhookRequest.swift in Sources */,
26EC14E21D1EF18700FD3A53 /* Reaction.swift in Sources */,
26EC14EA1D1EF18F00FD3A53 /* Topic.swift in Sources */,
263993A11CE90EE0004A6E93 /* Attachment.swift in Sources */,
26B30BB71D2BC2E4004D4AB5 /* Scope.swift in Sources */,
263993A21CE90EE0004A6E93 /* Message.swift in Sources */,
263993A31CE90EE0004A6E93 /* Team.swift in Sources */,
263993A41CE90EE0004A6E93 /* Extensions.swift in Sources */,
263993A51CE90EE0004A6E93 /* UserGroup.swift in Sources */,
263993A61CE90EE0004A6E93 /* SlackError.swift in Sources */,
269B475F1D3538E90042D137 /* SlackKit.swift in Sources */,
26EC14DB1D1EF17E00FD3A53 /* History.swift in Sources */,
263993A71CE90EE0004A6E93 /* Client+EventHandling.swift in Sources */,
269B47631D3544240042D137 /* IncomingWebhook.swift in Sources */,
269B47671D39AAA80042D137 /* MessageActionResponder.swift in Sources */,
26EC14CA1D1EF17400FD3A53 /* Comment.swift in Sources */,
26EC14C21D1EF16500FD3A53 /* AttachmentField.swift in Sources */,
263993A81CE90EE0004A6E93 /* NetworkInterface.swift in Sources */,
263993A91CE90EE0004A6E93 /* EventDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
263993B51CE90EED004A6E93 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
263993B61CE90EED004A6E93 /* Client+Utilities.swift in Sources */,
263993B71CE90EED004A6E93 /* Channel.swift in Sources */,
269B47D01D3C22FC0042D137 /* ClientOptions.swift in Sources */,
26EC14D11D1EF17400FD3A53 /* CustomProfileField.swift in Sources */,
263993B81CE90EED004A6E93 /* User.swift in Sources */,
26EC14DF1D1EF17E00FD3A53 /* Item.swift in Sources */,
2678B5981D3151C900CE521A /* Response.swift in Sources */,
269B475C1D3493DE0042D137 /* OAuthResponse.swift in Sources */,
26EC14CE1D1EF17400FD3A53 /* CustomProfile.swift in Sources */,
269B47C91D3AE2620042D137 /* Server.swift in Sources */,
263993BA1CE90EED004A6E93 /* Client.swift in Sources */,
263993BB1CE90EED004A6E93 /* Event.swift in Sources */,
269B47CA1D3AE2670042D137 /* WebhookServer.swift in Sources */,
26EC14D41D1EF17400FD3A53 /* DoNotDisturbStatus.swift in Sources */,
263993BC1CE90EED004A6E93 /* Bot.swift in Sources */,
26EC14E81D1EF18F00FD3A53 /* TeamIcon.swift in Sources */,
263993BD1CE90EED004A6E93 /* Client+EventDispatching.swift in Sources */,
263993BE1CE90EED004A6E93 /* File.swift in Sources */,
26B30BB81D2BC2E4004D4AB5 /* Scope.swift in Sources */,
269B47601D3538E90042D137 /* SlackKit.swift in Sources */,
2678B5991D3151CD00CE521A /* WebhookRequest.swift in Sources */,
26EC14FB1D1F355A00FD3A53 /* Action.swift in Sources */,
26EC14D71D1EF17400FD3A53 /* Edited.swift in Sources */,
263993BF1CE90EED004A6E93 /* WebAPI.swift in Sources */,
2678B5961D3151B900CE521A /* AuthorizeResponse.swift in Sources */,
26EC14E31D1EF18700FD3A53 /* Reaction.swift in Sources */,
26EC14EB1D1EF18F00FD3A53 /* Topic.swift in Sources */,
26B30BC51D2DFF0D004D4AB5 /* OAuthServer.swift in Sources */,
263993C01CE90EED004A6E93 /* Attachment.swift in Sources */,
263993C11CE90EED004A6E93 /* Message.swift in Sources */,
263993C21CE90EED004A6E93 /* Team.swift in Sources */,
269B47681D39AAA80042D137 /* MessageActionResponder.swift in Sources */,
263993C31CE90EED004A6E93 /* Extensions.swift in Sources */,
2678B5971D3151C600CE521A /* MessageActionRequest.swift in Sources */,
263993C41CE90EED004A6E93 /* UserGroup.swift in Sources */,
269B47C81D3AE25B0042D137 /* MessageActionServer.swift in Sources */,
263993C51CE90EED004A6E93 /* SlackError.swift in Sources */,
26EC14DC1D1EF17E00FD3A53 /* History.swift in Sources */,
263993C61CE90EED004A6E93 /* Client+EventHandling.swift in Sources */,
26B30BC91D2DFF7D004D4AB5 /* AuthorizeRequest.swift in Sources */,
269B47641D3544240042D137 /* IncomingWebhook.swift in Sources */,
26EC14CB1D1EF17400FD3A53 /* Comment.swift in Sources */,
26EC14C31D1EF16500FD3A53 /* AttachmentField.swift in Sources */,
263993C71CE90EED004A6E93 /* NetworkInterface.swift in Sources */,
263993C81CE90EED004A6E93 /* EventDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
26072A3A1BB48B3B00CD650C /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
26072A3B1BB48B3B00CD650C /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
26072A3D1BB48B3B00CD650C /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
COMBINE_HIDPI_IMAGES = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Carthage/Build/Mac",
);
FRAMEWORK_VERSION = A;
INFOPLIST_FILE = "$(SRCROOT)/SlackKit/Supporting Files/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.10;
PRODUCT_BUNDLE_IDENTIFIER = com.launchsoft.SlackKit;
PRODUCT_NAME = SlackKit;
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0;
};
name = Debug;
};
26072A3E1BB48B3B00CD650C /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
COMBINE_HIDPI_IMAGES = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Carthage/Build/Mac",
);
FRAMEWORK_VERSION = A;
INFOPLIST_FILE = "$(SRCROOT)/SlackKit/Supporting Files/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.10;
PRODUCT_BUNDLE_IDENTIFIER = com.launchsoft.SlackKit;
PRODUCT_NAME = SlackKit;
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 3.0;
};
name = Release;
};
263993B01CE90EE0004A6E93 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
COMBINE_HIDPI_IMAGES = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Carthage/Build/iOS",
);
FRAMEWORK_VERSION = A;
INFOPLIST_FILE = "$(SRCROOT)/SlackKit/Supporting Files/Info-iOS.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.10;
PRODUCT_BUNDLE_IDENTIFIER = com.launchsoft.SlackKit;
PRODUCT_NAME = SlackKit;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0;
};
name = Debug;
};
263993B11CE90EE0004A6E93 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
COMBINE_HIDPI_IMAGES = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Carthage/Build/iOS",
);
FRAMEWORK_VERSION = A;
INFOPLIST_FILE = "$(SRCROOT)/SlackKit/Supporting Files/Info-iOS.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.10;
PRODUCT_BUNDLE_IDENTIFIER = com.launchsoft.SlackKit;
PRODUCT_NAME = SlackKit;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 3.0;
};
name = Release;
};
263993CF1CE90EED004A6E93 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
COMBINE_HIDPI_IMAGES = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Carthage/Build/tvOS",
);
FRAMEWORK_VERSION = A;
INFOPLIST_FILE = "$(SRCROOT)/SlackKit/Supporting Files/Info-tvOS.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.10;
PRODUCT_BUNDLE_IDENTIFIER = com.launchsoft.SlackKit;
PRODUCT_NAME = SlackKit;
SDKROOT = appletvos;
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "appletvsimulator appletvos";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0;
TVOS_DEPLOYMENT_TARGET = 9.0;
};
name = Debug;
};
263993D01CE90EED004A6E93 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
COMBINE_HIDPI_IMAGES = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Carthage/Build/tvOS",
);
FRAMEWORK_VERSION = A;
INFOPLIST_FILE = "$(SRCROOT)/SlackKit/Supporting Files/Info-tvOS.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.10;
PRODUCT_BUNDLE_IDENTIFIER = com.launchsoft.SlackKit;
PRODUCT_NAME = SlackKit;
SDKROOT = appletvos;
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "appletvsimulator appletvos";
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 3.0;
TVOS_DEPLOYMENT_TARGET = 9.0;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
26072A2E1BB48B3A00CD650C /* Build configuration list for PBXProject "SlackKit" */ = {
isa = XCConfigurationList;
buildConfigurations = (
26072A3A1BB48B3B00CD650C /* Debug */,
26072A3B1BB48B3B00CD650C /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
26072A3C1BB48B3B00CD650C /* Build configuration list for PBXNativeTarget "SlackKit OS X" */ = {
isa = XCConfigurationList;
buildConfigurations = (
26072A3D1BB48B3B00CD650C /* Debug */,
26072A3E1BB48B3B00CD650C /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
263993AF1CE90EE0004A6E93 /* Build configuration list for PBXNativeTarget "SlackKit iOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
263993B01CE90EE0004A6E93 /* Debug */,
263993B11CE90EE0004A6E93 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
263993CE1CE90EED004A6E93 /* Build configuration list for PBXNativeTarget "SlackKit tvOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
263993CF1CE90EED004A6E93 /* Debug */,
263993D01CE90EED004A6E93 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 26072A2B1BB48B3A00CD650C /* Project object */;
}
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:SlackRTMKit.xcodeproj">
</FileRef>
</Workspace>
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "26072A331BB48B3A00CD650C"
BuildableName = "SlackKit.framework"
BlueprintName = "SlackKit OS X"
ReferencedContainer = "container:SlackKit.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "26072A331BB48B3A00CD650C"
BuildableName = "SlackKit.framework"
BlueprintName = "SlackKit OS X"
ReferencedContainer = "container:SlackKit.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "26072A331BB48B3A00CD650C"
BuildableName = "SlackKit.framework"
BlueprintName = "SlackKit OS X"
ReferencedContainer = "container:SlackKit.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "263993951CE90EE0004A6E93"
BuildableName = "SlackKit.framework"
BlueprintName = "SlackKit iOS"
ReferencedContainer = "container:SlackKit.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "263993951CE90EE0004A6E93"
BuildableName = "SlackKit.framework"
BlueprintName = "SlackKit iOS"
ReferencedContainer = "container:SlackKit.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "263993951CE90EE0004A6E93"
BuildableName = "SlackKit.framework"
BlueprintName = "SlackKit iOS"
ReferencedContainer = "container:SlackKit.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "263993B41CE90EED004A6E93"
BuildableName = "SlackKit.framework"
BlueprintName = "SlackKit tvOS"
ReferencedContainer = "container:SlackKit.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "263993B41CE90EED004A6E93"
BuildableName = "SlackKit.framework"
BlueprintName = "SlackKit tvOS"
ReferencedContainer = "container:SlackKit.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "263993B41CE90EED004A6E93"
BuildableName = "SlackKit.framework"
BlueprintName = "SlackKit tvOS"
ReferencedContainer = "container:SlackKit.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
+30
View File
@@ -0,0 +1,30 @@
//
// SlackKit.h
//
// Copyright © 2016 Peter Zignego. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <Foundation/Foundation.h>
//! Project version number for SlackKit.
FOUNDATION_EXPORT double SlackKitVersionNumber;
//! Project version string for SlackKit.
FOUNDATION_EXPORT const unsigned char SlackKitVersionString[];
+1 -1
View File
@@ -41,7 +41,7 @@ public struct Attachment {
public let footer: String?
public let footerIcon: String?
public let ts: Int?
internal init(attachment: [String: Any]?) {
fallback = attachment?["fallback"] as? String
callbackID = attachment?["callback_id"] as? String
+47
View File
@@ -0,0 +1,47 @@
//
// AuthorizeRequest.swift
//
// Copyright © 2016 Peter Zignego. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
internal struct AuthorizeRequest {
let clientID: String
let scope: [Scope]
let redirectURI: String
let state: String
let team: String?
var parameters: [String: Any] {
var json = [String : Any]()
json["scope"] = scope.map({$0.rawValue}).joined(separator: ",")
json["state"] = state
json["team"] = team
return json
}
init(clientID: String, scope:[Scope], redirectURI: String, state: String = "slackkit", team: String? = nil) {
self.clientID = clientID
self.scope = scope
self.redirectURI = redirectURI
self.state = state
self.team = team
}
}
+36
View File
@@ -0,0 +1,36 @@
//
// AuthorizeResponse.swift
//
// Copyright © 2016 Peter Zignego. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
internal struct AuthorizeResponse {
let code: String
let state: String
init?(queryParameters: [(String, String)]) {
guard let code = queryParameters.first?.1, let state = queryParameters.last?.1 else {
return nil
}
self.code = code
self.state = state
}
}
+1 -1
View File
@@ -70,7 +70,7 @@ public struct Channel {
unreadCountDisplay = channel?["unread_count_display"] as? Int
hasPins = channel?["has_pins"] as? Bool
members = channel?["members"] as? [String]
if let latestMesssageDictionary = channel?["latest"] as? [String: Any] {
latest = Message(dictionary: latestMesssageDictionary)
} else {
+10 -11
View File
@@ -21,15 +21,14 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
internal extension SlackClient {
func dispatch(_ anEvent: [String: Any]) {
let event = Event(anEvent)
let type = event.type ?? .unknown
internal extension Client {
func dispatch(_ event: [String: Any]) {
let event = Event(event)
let type = event.type ?? .error
switch type {
case .hello:
connected = true
pingRTMServer()
connectionEventsDelegate?.connected(self)
case .ok:
messageSent(event)
@@ -114,8 +113,8 @@ internal extension SlackClient {
case .emojiChanged:
emojiChanged(event)
case .commandsChanged:
// This functionality is only used by our web client.
// The other APIs required to support slash command metadata are currently unstable.
// This functionality is only used by our web client.
// The other APIs required to support slash command metadata are currently unstable.
// Until they are released other clients should ignore this event.
break
case .teamPlanChange:
@@ -143,7 +142,7 @@ internal extension SlackClient {
// Other clients should ignore this event.
break
case .teamMigrationStarted:
connect(pingInterval: pingInterval, timeout: timeout, reconnect: reconnect)
connect(options: options ?? ClientOptions())
case .reconnectURL:
// The reconnect_url event is currently unsupported and experimental.
break
@@ -153,8 +152,8 @@ internal extension SlackClient {
subteamAddedSelf(event)
case .subteamSelfRemoved:
subteamRemovedSelf(event)
case .unknown:
print("Unknown event of type: \(anEvent["type"] ?? "No Type Information")")
case .error:
print("Error: \(event)")
}
}
+20 -21
View File
@@ -22,10 +22,9 @@
// THE SOFTWARE.
import Foundation
import Dispatch
internal extension SlackClient {
internal extension Client {
//MARK: - Pong
func pong(_ event: Event) {
pong = event.replyTo
@@ -74,20 +73,20 @@ internal extension SlackClient {
func userTyping(_ event: Event) {
guard let channel = event.channel, let channelID = channel.id, let user = event.user, let userID = user.id ,
channels.index(forKey: channelID) != nil && !channels[channelID]!.usersTyping.contains(userID) else {
return
return
}
channels[channelID]?.usersTyping.append(userID)
channelEventsDelegate?.userTypingIn(channel, user: user, client: self)
let timeout = DispatchTime.now() + Double(Int64(5.0 * Double(CLOCKS_PER_SEC))) / Double(CLOCKS_PER_SEC)
let timeout = DispatchTime.now() + Double(Int64(5.0 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)
DispatchQueue.main.asyncAfter(deadline: timeout, execute: {
if let index = self.channels[channelID]?.usersTyping.index(of: userID) {
self.channels[channelID]?.usersTyping.remove(at: index)
}
})
}
func channelMarked(_ event: Event) {
guard let channel = event.channel, let id = channel.id, let timestamp = event.ts else {
return
@@ -199,7 +198,7 @@ internal extension SlackClient {
files[id]?.comments[commentID] = comment
}
}
files[id] = file
fileEventsDelegate?.processed(file, client: self)
}
@@ -265,13 +264,13 @@ internal extension SlackClient {
guard let id = event.channelID, let item = event.item else {
return
}
if let pins = channels[id]?.pinnedItems.filter({$0 != item}) {
channels[id]?.pinnedItems = pins
}
pinEventsDelegate?.unpinned(item, channel: channels[id], client: self)
}
//MARK: - Stars
func itemStarred(_ event: Event, star: Bool) {
guard let item = event.item, let type = item.type else {
@@ -287,7 +286,7 @@ internal extension SlackClient {
default:
break
}
starEventsDelegate?.starred(item, starred: star, self)
}
@@ -347,15 +346,15 @@ internal extension SlackClient {
default:
break
}
reactionEventsDelegate?.added(reaction, item: item, itemUser: itemUser, client: self)
}
func removedReaction(_ event: Event) {
guard let item = event.item, let type = item.type, let key = event.reaction, let userID = event.user?.id, let itemUser = event.itemUser else {
return
}
switch type {
case "message":
guard let channel = item.channel, let ts = item.ts, let message = channels[channel]?.messages[ts] else {
@@ -375,10 +374,10 @@ internal extension SlackClient {
default:
break
}
reactionEventsDelegate?.removed(key, item: item, itemUser: itemUser, client: self)
}
//MARK: - Preferences
func changePreference(_ event: Event) {
guard let name = event.name else {
@@ -513,7 +512,7 @@ internal extension SlackClient {
guard let profile = event.profile else {
return
}
for user in users {
for key in profile.fields.keys {
users[user.0]?.profile?.customProfile?.fields[key]?.updateProfileField(profile.fields[key])
@@ -527,7 +526,7 @@ internal extension SlackClient {
guard let profile = event.profile else {
return
}
for user in users {
if let id = profile.fields.first?.0 {
users[user.0]?.profile?.customProfile?.fields[id] = nil
@@ -541,13 +540,13 @@ internal extension SlackClient {
guard let profile = event.profile else {
return
}
for user in users {
for key in profile.fields.keys {
users[user.0]?.profile?.customProfile?.fields[key]?.ordering = profile.fields[key]?.ordering
}
}
teamProfileEventsDelegate?.reordered(profile, client: self)
}
+5 -5
View File
@@ -26,7 +26,7 @@ public enum ClientError: Error {
case userDoesNotExist
}
public extension SlackClient {
public extension Client {
//MARK: - User & Channel
public func getChannelIDWith(name: String) throws -> String {
@@ -35,24 +35,24 @@ public extension SlackClient {
}
return id
}
public func getUserIDWith(name: String) throws -> String {
guard let id = users.filter({$0.1.name == strip(string:name)}).first?.0 else {
throw ClientError.userDoesNotExist
}
return id
}
public func getImIDForUserWith(id: String, success: @escaping (_ imID: String?)->Void, failure: @escaping (SlackError)->Void) {
let ims = channels.filter{$0.1.isIM == true}
let channel = ims.filter{$0.1.user == id}.first
if let channel = channel {
success(channel.0)
} else {
webAPI.openIM(userID: id, success: success, failure: failure)
webAPI.openIM(id, success: success, failure: failure)
}
}
//MARK: - Utilities
internal func strip(string: String) -> String {
var strippedString = string
+103 -136
View File
@@ -22,13 +22,11 @@
// THE SOFTWARE.
import Foundation
import Venice
import WebSocketClient
import Starscream
public class SlackClient {
public final class Client: WebSocketDelegate {
internal(set) public var connected = false
internal(set) public var authenticated = false
internal(set) public var authenticatedUser: User?
internal(set) public var team: Team?
@@ -39,6 +37,18 @@ public class SlackClient {
internal(set) public var files = [String: File]()
internal(set) public var sentMessages = [String: Message]()
public var token = "xoxp-SLACK_AUTH_TOKEN"
public var webAPI: WebAPI {
return WebAPI(token: token)
}
internal var webSocket: WebSocket?
private let pingPongQueue = DispatchQueue(label: "com.launchsoft.SlackKit")
internal var ping: Double?
internal var pong: Double?
internal var options: ClientOptions?
//MARK: - Delegates
public weak var connectionEventsDelegate: ConnectionEventsDelegate?
public weak var slackEventsDelegate: SlackEventsDelegate?
@@ -53,81 +63,53 @@ public class SlackClient {
public weak var teamEventsDelegate: TeamEventsDelegate?
public weak var subteamEventsDelegate: SubteamEventsDelegate?
public weak var teamProfileEventsDelegate: TeamProfileEventsDelegate?
internal var token = "SLACK_AUTH_TOKEN"
public func setAuthToken(token: String) {
self.token = token
}
public var webAPI: SlackWebAPI {
return SlackWebAPI(token: token)
}
internal var client: WebSocketClient?
internal var socket: WebSocket?
internal var ping: Double?
internal var pong: Double?
internal var pingInterval: Double = 30
internal var timeout: Double = 300
internal var reconnect: Bool = false
required public init(apiToken: String) {
// If you already have an API token
internal init(apiToken: String) {
self.token = apiToken
}
public func connect(simpleLatest: Bool? = nil, noUnreads: Bool? = nil, mpimAware: Bool? = nil, pingInterval: Double = 30, timeout: Double = 300, reconnect: Bool = false) {
self.pingInterval = pingInterval
self.timeout = timeout
self.reconnect = reconnect
webAPI.rtmStart(simpleLatest: simpleLatest, noUnreads: noUnreads, mpimAware: mpimAware, success: { (response) in
self.initialSetup(JSON: response)
if let socketURL = response["url"] as? String, let url = URL(string: socketURL) {
do {
self.client = try WebSocketClient(url: url, didConnect: { (socket) in
self.setupSocket(socket)
})
try self.client?.connect()
} catch let error {
print("WebSocket client could not connect: \(error)")
}
public func setAuthToken(_ token: String) {
self.token = token
}
public func connect(options: ClientOptions = ClientOptions()) {
self.options = options
webAPI.rtmStart(options.simpleLatest, noUnreads: options.noUnreads, mpimAware: options.mpimAware, success: {(response) in
guard let socketURL = response["url"] as? String, let url = URL(string: socketURL) else {
return
}
self.initialSetup(JSON: response)
self.webSocket = WebSocket(url: url)
self.webSocket?.delegate = self
self.webSocket?.connect()
}, failure: {(error) in
print("rtm.start failed with error: \(error)")
self.connectionEventsDelegate?.connectionFailed(self, error: error)
})
}
public func disconnect() {
_ = try? socket?.close()
webSocket?.disconnect()
}
//MARK: - RTM message send
public func sendMessage(message: String, channelID: String) {
if connected {
if let data = formatMessageToSlackJsonString(message: message, channel: channelID) {
do {
try socket?.send(data.base64EncodedString())
} catch let error {
print("Message failed to send: \(error)")
}
}
//MARK: - RTM Message send
public func send(message: String, channelID: String) {
guard connected else { return }
if let data = try? format(message: message, channel: channelID), let string = String(data: data, encoding: String.Encoding.utf8) {
webSocket?.write(string: string)
}
}
private func formatMessageToSlackJsonString(message: String, channel: String) -> Data? {
private func format(message: String, channel: String) throws -> Data {
let json: [String: Any] = [
"id": Date().slackTimestamp,
"type": "message",
"channel": channel,
"text": message.slackFormatEscaping
]
do {
return try JSONSerialization.data(withJSONObject: json, options: [])
} catch {
return nil
}
addSentMessage(json)
return try JSONSerialization.data(withJSONObject: json, options: [])
}
private func addSentMessage(_ dictionary: [String: Any]) {
@@ -142,6 +124,49 @@ public class SlackClient {
sentMessages[ts] = Message(dictionary: message)
}
//MARK: - RTM Ping
private func pingRTMServerAt(interval: TimeInterval) {
let delay = DispatchTime.now() + Double(Int64(interval * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)
pingPongQueue.asyncAfter(deadline: delay, execute: {
guard self.connected && self.timeoutCheck() else {
self.disconnect()
return
}
self.sendRTMPing()
self.pingRTMServerAt(interval: interval)
})
}
private func sendRTMPing() {
guard connected else {
return
}
let json: [String: Any] = [
"id": Date().slackTimestamp,
"type": "ping"
]
guard let data = try? JSONSerialization.data(withJSONObject: json, options: []) else {
return
}
if let string = String(data: data, encoding: String.Encoding.utf8) {
ping = json["id"] as? Double
webSocket?.write(string: string)
}
}
private func timeoutCheck() -> Bool {
if let pong = pong, let ping = ping, let timeout = options?.timeout {
if pong - ping < timeout {
return true
} else {
return false
}
// Ping-pong or timeout not configured
} else {
return true
}
}
//MARK: - Client setup
private func initialSetup(JSON: [String: Any]) {
team = Team(team: JSON["team"] as? [String: Any])
@@ -207,90 +232,32 @@ public class SlackClient {
}
}
//MARK: - RTM Ping
internal func pingRTMServer() {
co {
self.sendRTMPing()
nap(for: self.pingInterval.seconds)
guard self.connected && self.isConnectionTimedOut else {
self.disconnect()
return
}
self.pingRTMServer()
// MARK: - WebSocketDelegate
public func websocketDidConnect(socket: WebSocket) {
if let pingInterval = options?.pingInterval {
pingRTMServerAt(interval: pingInterval)
}
}
private func sendRTMPing() {
guard connected else {
return
}
let json: [String: Any] = [
"id": Date().slackTimestamp,
"type": "ping"
]
guard let data = try? JSONSerialization.data(withJSONObject: json, options: []) else {
return
}
if let string = String(data: data, encoding: String.Encoding.utf8) {
ping = json["id"] as? Double
do {
try socket?.send(string)
} catch let error {
print("Failed to send ping with error: \(error)")
}
}
}
var isConnectionTimedOut: Bool {
if let pong = pong, let ping = ping {
if pong - ping < timeout {
return true
} else {
return false
}
} else {
return true
}
}
// MARK: - WebSocket
private func setupSocket(_ socket: WebSocket) {
socket.onText {(message) in
self.websocketDidReceive(message: message)
}
socket.onClose{ (code: CloseCode?, reason: String?) in
self.websocketDidDisconnect(closeCode: code, error: reason)
}
socket.onPing { (data) in try socket.pong() }
socket.onPong { (data) in try socket.ping() }
self.socket = socket
}
private func websocketDidReceive(message: String) {
do {
guard let message = message.data(using: .utf8) else {
print("Failed to decode message")
return
}
let json = try JSONSerialization.jsonObject(with: message, options: [])
if let event = json as? [String: Any] {
dispatch(event)
}
}
catch let error {
print("Failed to dispatch message: \(error)")
}
}
private func websocketDidDisconnect(closeCode: CloseCode?, error: String?) {
public func websocketDidDisconnect(socket: WebSocket, error: NSError?) {
connected = false
authenticated = false
client = nil
socket = nil
webSocket = nil
authenticatedUser = nil
connectionEventsDelegate?.disconnected(self)
if reconnect == true {
connect(pingInterval: pingInterval, timeout: timeout, reconnect: reconnect)
if let options = options, options.reconnect == true {
connect(options: options)
}
}
public func websocketDidReceiveMessage(socket: WebSocket, text: String) {
guard let data = text.data(using: String.Encoding.utf8) else {
return
}
if let json = (try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments)) as? [String: Any] {
dispatch(json)
}
}
public func websocketDidReceiveData(socket: WebSocket, data: Data) {}
}
+43
View File
@@ -0,0 +1,43 @@
//
// ClientOptions.swift
//
// Copyright © 2016 Peter Zignego. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
public struct ClientOptions {
let simpleLatest: Bool?
let noUnreads: Bool?
let mpimAware: Bool?
let pingInterval: TimeInterval?
let timeout: TimeInterval?
let reconnect: Bool?
public init(simpleLatest: Bool? = nil, noUnreads: Bool? = nil, mpimAware: Bool? = nil, pingInterval: TimeInterval? = nil, timeout: TimeInterval? = nil, reconnect: Bool? = nil) {
self.simpleLatest = simpleLatest
self.noUnreads = noUnreads
self.mpimAware = mpimAware
self.pingInterval = pingInterval
self.timeout = timeout
self.reconnect = reconnect
}
}
+4 -4
View File
@@ -93,7 +93,7 @@ internal enum EventType: String {
case subteamSelfAdded = "subteam_self_added"
case subteamSelfRemoved = "subteam_self_removed"
case ok = "ok"
case unknown = "unknown"
case error = "error"
}
internal enum MessageSubtype: String {
@@ -195,20 +195,20 @@ internal class Event {
nestedMessage = Message(dictionary: event["message"] as? [String: Any])
profile = CustomProfile(profile: event["profile"] as? [String: Any])
file = File(id: event["file"] as? String)
// Comment, Channel, and User can come across as Strings or Dictionaries
if let commentDictionary = event["comment"] as? [String: Any] {
comment = Comment(comment: commentDictionary)
} else {
comment = Comment(id: event["comment"] as? String)
}
if let userDictionary = event["user"] as? [String: Any] {
user = User(user: userDictionary)
} else {
user = User(id: event["user"] as? String)
}
if let channelDictionary = event["channel"] as? [String: Any] {
channel = Channel(channel: channelDictionary)
} else {
+48 -48
View File
@@ -22,88 +22,88 @@
// THE SOFTWARE.
public protocol ConnectionEventsDelegate: class {
func connected(_ client: SlackClient)
func disconnected(_ client: SlackClient)
func connectionFailed(_ client: SlackClient, error: SlackError)
func connected(_ client: Client)
func disconnected(_ client: Client)
func connectionFailed(_ client: Client, error: SlackError)
}
public protocol MessageEventsDelegate: class {
func sent(_ message: Message, client: SlackClient)
func received(_ message: Message, client: SlackClient)
func changed(_ message: Message, client: SlackClient)
func deleted(_ message: Message?, client: SlackClient)
func sent(_ message: Message, client: Client)
func received(_ message: Message, client: Client)
func changed(_ message: Message, client: Client)
func deleted(_ message: Message?, client: Client)
}
public protocol ChannelEventsDelegate: class {
func userTypingIn(_ channel: Channel, user: User, client: SlackClient)
func marked(_ channel: Channel, timestamp: String, client: SlackClient)
func created(_ channel: Channel, client: SlackClient)
func deleted(_ channel: Channel, client: SlackClient)
func renamed(_ channel: Channel, client: SlackClient)
func archived(_ channel: Channel, client: SlackClient)
func historyChanged(_ channel: Channel, client: SlackClient)
func joined(_ channel: Channel, client: SlackClient)
func left(_ channel: Channel, client: SlackClient)
func userTypingIn(_ channel: Channel, user: User, client: Client)
func marked(_ channel: Channel, timestamp: String, client: Client)
func created(_ channel: Channel, client: Client)
func deleted(_ channel: Channel, client: Client)
func renamed(_ channel: Channel, client: Client)
func archived(_ channel: Channel, client: Client)
func historyChanged(_ channel: Channel, client: Client)
func joined(_ channel: Channel, client: Client)
func left(_ channel: Channel, client: Client)
}
public protocol DoNotDisturbEventsDelegate: class {
func updated(_ status: DoNotDisturbStatus, client: SlackClient)
func userUpdated(_ status: DoNotDisturbStatus, user: User, client: SlackClient)
func updated(_ status: DoNotDisturbStatus, client: Client)
func userUpdated(_ status: DoNotDisturbStatus, user: User, client: Client)
}
public protocol GroupEventsDelegate: class {
func opened(_ group: Channel, client: SlackClient)
func opened(_ group: Channel, client: Client)
}
public protocol FileEventsDelegate: class {
func processed(_ file: File, client: SlackClient)
func madePrivate(_ file: File, client: SlackClient)
func deleted(_ file: File, client: SlackClient)
func commentAdded(_ file: File, comment: Comment, client: SlackClient)
func commentEdited(_ file: File, comment: Comment, client: SlackClient)
func commentDeleted(_ file: File, comment: Comment, client: SlackClient)
func processed(_ file: File, client: Client)
func madePrivate(_ file: File, client: Client)
func deleted(_ file: File, client: Client)
func commentAdded(_ file: File, comment: Comment, client: Client)
func commentEdited(_ file: File, comment: Comment, client: Client)
func commentDeleted(_ file: File, comment: Comment, client: Client)
}
public protocol PinEventsDelegate: class {
func pinned(_ item: Item, channel: Channel?, client: SlackClient)
func unpinned(_ item: Item, channel: Channel?, client: SlackClient)
func pinned(_ item: Item, channel: Channel?, client: Client)
func unpinned(_ item: Item, channel: Channel?, client: Client)
}
public protocol StarEventsDelegate: class {
func starred(_ item: Item, starred: Bool, _ client: SlackClient)
func starred(_ item: Item, starred: Bool, _ client: Client)
}
public protocol ReactionEventsDelegate: class {
func added(_ reaction: String, item: Item, itemUser: String, client: SlackClient)
func removed(_ reaction: String, item: Item, itemUser: String, client: SlackClient)
func added(_ reaction: String, item: Item, itemUser: String, client: Client)
func removed(_ reaction: String, item: Item, itemUser: String, client: Client)
}
public protocol SlackEventsDelegate: class {
func preferenceChanged(_ preference: String, value: Any?, client: SlackClient)
func userChanged(_ user: User, client: SlackClient)
func presenceChanged(_ user: User, presence: String, client: SlackClient)
func manualPresenceChanged(_ user: User, presence: String, client: SlackClient)
func botEvent(_ bot: Bot, client: SlackClient)
func preferenceChanged(_ preference: String, value: Any?, client: Client)
func userChanged(_ user: User, client: Client)
func presenceChanged(_ user: User, presence: String, client: Client)
func manualPresenceChanged(_ user: User, presence: String, client: Client)
func botEvent(_ bot: Bot, client: Client)
}
public protocol TeamEventsDelegate: class {
func userJoined(_ user: User, client: SlackClient)
func planChanged(_ plan: String, client: SlackClient)
func preferencesChanged(_ preference: String, value: Any?, client: SlackClient)
func nameChanged(_ name: String, client: SlackClient)
func domainChanged(_ domain: String, client: SlackClient)
func emailDomainChanged(_ domain: String, client: SlackClient)
func emojiChanged(_ client: SlackClient)
func userJoined(_ user: User, client: Client)
func planChanged(_ plan: String, client: Client)
func preferencesChanged(_ preference: String, value: Any?, client: Client)
func nameChanged(_ name: String, client: Client)
func domainChanged(_ domain: String, client: Client)
func emailDomainChanged(_ domain: String, client: Client)
func emojiChanged(_ client: Client)
}
public protocol SubteamEventsDelegate: class {
func event(_ userGroup: UserGroup, client: SlackClient)
func selfAdded(_ subteamID: String, client: SlackClient)
func selfRemoved(_ subteamID: String, client: SlackClient)
func event(_ userGroup: UserGroup, client: Client)
func selfAdded(_ subteamID: String, client: Client)
func selfRemoved(_ subteamID: String, client: Client)
}
public protocol TeamProfileEventsDelegate: class {
func changed(_ profile: CustomProfile, client: SlackClient)
func deleted(_ profile: CustomProfile, client: SlackClient)
func reordered(_ profile: CustomProfile, client: SlackClient)
func changed(_ profile: CustomProfile, client: Client)
func deleted(_ profile: CustomProfile, client: Client)
func reordered(_ profile: CustomProfile, client: Client)
}
+3 -2
View File
@@ -24,7 +24,7 @@
import Foundation
public extension Date {
var slackTimestamp: Double {
return NSNumber(value: timeIntervalSince1970).doubleValue
}
@@ -45,7 +45,7 @@ internal extension Dictionary where Key: ExpressibleByStringLiteral, Value: Any
var requestStringFromParameters: String {
var requestString = ""
for key in self.keys {
if let value = self[key] as? String, let encodedValue = value.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) {
if let value = self[key] as? String, let encodedValue = value.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlHostAllowed) {
requestString += "&\(key)=\(encodedValue)"
} else if let value = self[key] {
requestString += "&\(key)=\(value)"
@@ -54,3 +54,4 @@ internal extension Dictionary where Key: ExpressibleByStringLiteral, Value: Any
return requestString
}
}
+2 -2
View File
@@ -22,7 +22,7 @@
// THE SOFTWARE.
public struct File: Equatable {
public let id: String?
public let created: Int?
public let name: String?
@@ -131,7 +131,7 @@ public struct File: Equatable {
stars = file?["num_stars"] as? Int
isStarred = file?["is_starred"] as? Bool
pinnedTo = file?["pinned_to"] as? [String]
reactions = Reaction.reactionsFromArray(file?["reactions"] as? [[String: Any]])
reactions = Reaction.reactionsFromArray(file?["reactions"] as? [[String: Any]])
}
internal init(id:String?) {
+71
View File
@@ -0,0 +1,71 @@
//
// IncomingWebhook.swift
//
// Copyright © 2016 Peter Zignego. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
public struct IncomingWebhook {
public let url: String?
public let channel: String?
public let configurationURL: String?
public let username: String?
public let iconEmoji: String?
public let iconURL: String?
internal init(webhook: [String: Any]?) {
url = webhook?["url"] as? String
channel = webhook?["channel"] as? String
configurationURL = webhook?["configuration_url"] as? String
username = webhook?["username"] as? String
iconEmoji = webhook?["icon_emoji"] as? String
iconURL = webhook?["icon_url"] as? String
}
public init(url: String, channel: String? = nil, username: String? = nil, iconEmoji: String? = nil, iconURL: String? = nil) {
self.url = url
self.channel = channel
self.username = username
self.iconEmoji = iconEmoji
self.iconURL = iconURL
self.configurationURL = nil
}
public func postMessage(_ response: Response, success: ((Bool)->Void)? = nil, failure: ((SlackError)->Void)? = nil) {
if let url = self.url, let data = try? JSONSerialization.data(withJSONObject: jsonBody(response.json), options: []) {
NetworkInterface().customRequest(url, data: data, success: { _ in
success?(true)
}, errorClosure: {(error) in
failure?(error)
})
}
}
private func jsonBody(_ response: [String: Any]) -> [String: Any] {
var json = response
json["channel"] = channel
json["username"] = username
json["icon_emoji"] = iconEmoji
json["icon_url"] = iconURL
return json
}
}
@@ -0,0 +1,51 @@
//
// MessageActionRequest.swift
//
// Copyright © 2016 Peter Zignego. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
internal struct MessageActionRequest: Request {
let action: Action?
let callbackID: String?
let team: Team?
let channel: Channel?
let user: User?
let actionTS: String?
let messageTS: String?
let attachmentID: String?
let token: String?
let originalMessage: Message?
let responseURL: String
init(response: [String: Any]?) {
action = (response?["actions"] as? [[String:Any]])?.map({Action(action: $0)}).first
callbackID = response?["callback_id"] as? String
team = Team(team: response?["team"] as? [String: Any])
channel = Channel(channel: response?["channel"] as? [String: Any])
user = User(user: response?["channel"] as? [String: Any])
actionTS = response?["action_ts"] as? String
messageTS = response?["message_ts"] as? String
attachmentID = response?["attachment_id"] as? String
token = response?["token"] as? String
originalMessage = Message(dictionary: response?["original_message"] as? [String: Any])
responseURL = response?["response_url"] as? String ?? ""
}
}
@@ -0,0 +1,39 @@
//
// MessageActionResponder.swift
//
// Copyright © 2016 Peter Zignego. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
public struct MessageActionResponder {
public var responses:[(Action, Response)]
public init(responses:[(Action, Response)]) {
self.responses = responses
}
internal func responseForRequest(_ request:MessageActionRequest) -> Reply? {
if let response = responses.filter({$0.0.name == request.action?.name}).first?.1 {
return Reply.json(response: response)
} else {
return nil
}
}
}
@@ -0,0 +1,45 @@
//
// MessageActionServer.swift
//
// Copyright © 2016 Peter Zignego. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
open class MessageActionServer: Server {
internal let responder: MessageActionResponder
required public init(token: String, route: String, responder: MessageActionResponder) {
self.responder = responder
super.init(token: token)
addRoute(route)
}
internal func addRoute(_ route: String) {
http.POST["/\(route)"] = { request in
let payload = request.parseUrlencodedForm()
let actionRequest = MessageActionRequest(response: self.jsonFromRequest(payload[0].1))
if let reply = self.responder.responseForRequest(actionRequest), actionRequest.token == self.token {
return self.request(actionRequest, reply: reply)
} else {
return .badRequest(.text("Bad request."))
}
}
}
}
+89 -75
View File
@@ -22,113 +22,127 @@
// THE SOFTWARE.
import Foundation
import HTTPClient
import WebSocketClient
internal struct NetworkInterface {
private let apiUrl = "https://slack.com/api/"
private let client: HTTPClient.Client?
init() {
do {
self.client = try Client(url: URL(string: "https://slack.com")!)
} catch {
self.client = nil
internal func request(_ endpoint: Endpoint, token: String? = nil, parameters: [String: Any]?, successClosure: @escaping ([String: Any])->Void, errorClosure: @escaping (SlackError)->Void) {
var requestString = "\(apiUrl)\(endpoint.rawValue)?"
if let token = token {
requestString += "token=\(token)"
}
}
internal func request(_ endpoint: Endpoint, token: String, parameters: [String: Any]?, successClosure: ([String: Any])->Void, errorClosure: (SlackError)->Void) {
var requestString = "\(apiUrl)\(endpoint.rawValue)?token=\(token)"
if let params = parameters {
requestString += params.requestStringFromParameters
}
do {
let contentNegotiation = ContentNegotiationMiddleware(mediaTypes: [.json, .urlEncodedForm], mode: .client)
var response = try client?.get(requestString, middleware: [contentNegotiation])
if let buffer = try response?.body.becomeBuffer(deadline: 3.seconds.fromNow()) {
let data = Data(bytes: buffer.bytes)
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
if let result = json as? [String: Any] {
if (result["ok"] as? Bool == true) {
successClosure(result)
} else {
if let errorString = result["error"] as? String {
throw SlackError(rawValue: errorString) ?? SlackError.unknownError
} else {
throw SlackError.unknownError
}
}
}
}
} catch let error {
if let slackError = error as? SlackError {
errorClosure(slackError)
} else {
errorClosure(SlackError.unknownError)
}
guard let url = URL(string: requestString) else {
errorClosure(SlackError.clientNetworkError)
return
}
let request = URLRequest(url:url)
URLSession.shared.dataTask(with: request) {(data, response, internalError) in
do {
successClosure(try self.handleResponse(data, response: response, internalError: internalError))
} catch let error {
errorClosure(error as? SlackError ?? SlackError.unknownError)
}
}.resume()
}
internal func uploadRequest(token: String, data: Data, parameters: [String: Any]?, successClosure: ([String: Any])->Void, errorClosure: (SlackError)->Void) {
internal func customRequest(_ url: String, data: Data, success: @escaping (Bool)->Void, errorClosure: @escaping (SlackError)->Void) {
guard let url = URL(string: url.removePercentEncoding()) else {
errorClosure(SlackError.clientNetworkError)
return
}
var request = URLRequest(url:url)
request.httpMethod = "POST"
let contentType = "application/json"
request.setValue(contentType, forHTTPHeaderField: "Content-Type")
request.httpBody = data
URLSession.shared.dataTask(with: request) {(data, response, internalError) in
if internalError == nil {
success(true)
} else {
errorClosure(SlackError.clientNetworkError)
}
}.resume()
}
internal func uploadRequest(_ token: String, data: Data, parameters: [String: Any]?, successClosure: @escaping ([String: Any])->Void, errorClosure: @escaping (SlackError)->Void) {
var requestString = "\(apiUrl)\(Endpoint.filesUpload.rawValue)?token=\(token)"
if let params = parameters {
requestString = requestString + params.requestStringFromParameters
}
let boundaryConstant = randomBoundary()
let boundaryStart = "--\(boundaryConstant)\r\n"
let boundaryEnd = "\r\n--\(boundaryConstant)--\r\n"
let contentDispositionString = "Content-Disposition: form-data; name=\"file\"; filename=\"\(parameters!["filename"])\"\r\n"
let contentTypeString = "Content-Type: \(parameters!["filetype"])\r\n\r\n"
guard let boundaryStartData = boundaryStart.data(using: .utf8), let dispositionData = contentDispositionString.data(using: .utf8), let contentTypeData = contentTypeString.data(using: .utf8), let boundaryEndData = boundaryEnd.data(using: .utf8) else {
guard let url = URL(string: requestString) else {
errorClosure(SlackError.clientNetworkError)
return
}
var requestBodyData = Data()
requestBodyData.append(contentsOf: boundaryStartData)
requestBodyData.append(contentsOf: dispositionData)
requestBodyData.append(contentsOf: contentTypeData)
requestBodyData.append(contentsOf: data)
requestBodyData.append(contentsOf: boundaryEndData)
let header: Headers = ["Content-Type":"multipart/form-data; boundary=\(boundaryConstant)"]
var request = URLRequest(url:url)
request.httpMethod = "POST"
let boundaryConstant = randomBoundary()
let contentType = "multipart/form-data; boundary=" + boundaryConstant
let boundaryStart = "--\(boundaryConstant)\r\n"
let boundaryEnd = "--\(boundaryConstant)--\r\n"
let contentDispositionString = "Content-Disposition: form-data; name=\"file\"; filename=\"\(parameters!["filename"])\"\r\n"
let contentTypeString = "Content-Type: \(parameters!["filetype"])\r\n\r\n"
var requestBodyData: Data = Data()
requestBodyData.append(boundaryStart.data(using: String.Encoding.utf8)!)
requestBodyData.append(contentDispositionString.data(using: String.Encoding.utf8)!)
requestBodyData.append(contentTypeString.data(using: String.Encoding.utf8)!)
requestBodyData.append(data)
requestBodyData.append("\r\n".data(using: String.Encoding.utf8)!)
requestBodyData.append(boundaryEnd.data(using: String.Encoding.utf8)!)
request.setValue(contentType, forHTTPHeaderField: "Content-Type")
request.httpBody = requestBodyData as Data
URLSession.shared.dataTask(with: request) {(data, response, internalError) in
do {
successClosure(try self.handleResponse(data, response: response, internalError: internalError))
} catch let error {
errorClosure(error as? SlackError ?? SlackError.unknownError)
}
}.resume()
}
private func handleResponse(_ data: Data?, response:URLResponse?, internalError:Error?) throws -> [String: Any] {
guard let data = data, let response = response as? HTTPURLResponse else {
throw SlackError.clientNetworkError
}
do {
let body = Buffer([UInt8](requestBodyData))
var response = try client?.post(requestString, headers: header, body: body)
if let buffer = try response?.body.becomeBuffer(deadline: 3.seconds.fromNow()) {
let data = Data(bytes: buffer.bytes)
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
if let result = json as? [String: Any] {
if (result["ok"] as? Bool == true) {
successClosure(result)
guard let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else {
throw SlackError.clientJSONError
}
switch response.statusCode {
case 200:
if (json["ok"] as! Bool == true) {
return json
} else {
if let errorString = json["error"] as? String {
throw SlackError(rawValue: errorString) ?? .unknownError
} else {
if let errorString = result["error"] as? String {
throw SlackError(rawValue: errorString) ?? SlackError.unknownError
} else {
throw SlackError.unknownError
}
throw SlackError.unknownError
}
}
case 429:
throw SlackError.tooManyRequests
default:
throw SlackError.clientNetworkError
}
} catch let error {
if let slackError = error as? SlackError {
errorClosure(slackError)
throw slackError
} else {
errorClosure(SlackError.unknownError)
throw SlackError.unknownError
}
}
}
private func randomBoundary() -> String {
#if os(Linux)
return "slackkit.boundary.\(Int(random()))\(Int(random()))"
#else
return "slackkit.boundary.\(arc4random())\(arc4random())"
#endif
return String(format: "slackkit.boundary.%08x%08x", arc4random(), arc4random())
}
}
+44
View File
@@ -0,0 +1,44 @@
//
// OAuthResponse.swift
//
// Copyright © 2016 Peter Zignego. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
internal struct OAuthResponse {
let accessToken: String?
let scope: [Scope]?
let userID: String?
let teamName: String?
let teamID: String?
let incomingWebhook: IncomingWebhook?
let bot: Bot?
init(response: [String: Any]?) {
accessToken = response?["access_token"] as? String
scope = (response?["scope"] as? String)?.components(separatedBy: ",").flatMap{Scope(rawValue:$0)}
userID = response?["user_id"] as? String
teamName = response?["team_name"] as? String
teamID = response?["team_id"] as? String
incomingWebhook = IncomingWebhook(webhook: response?["incoming_webhook"] as? [String: Any])
bot = Bot(botUser: response?["bot"] as? [String: Any])
}
}
+94
View File
@@ -0,0 +1,94 @@
//
// OAuthServer.swift
//
// Copyright © 2016 Peter Zignego. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
import Swifter
internal protocol OAuthDelegate {
func userAuthed(_ response: OAuthResponse)
}
public struct OAuthServer {
private let oauthURL = "https://slack.com/oauth/authorize"
private let http = HttpServer()
private let clientID: String
private let clientSecret: String
private let state: String?
private let redirectURI: String?
private var delegate: OAuthDelegate?
internal init(clientID: String, clientSecret: String, state: String? = nil, redirectURI: String? = nil, port:in_port_t = 8080, forceIPV4: Bool = false, delegate: OAuthDelegate? = nil) throws {
self.clientID = clientID
self.clientSecret = clientSecret
self.state = state ?? "state"
self.redirectURI = redirectURI
self.delegate = delegate
oauthRoute()
start(port, forceIPV4: forceIPV4)
}
public func start(_ port: in_port_t = 8080, forceIPV4: Bool = false) {
do {
try http.start(port, forceIPv4: forceIPV4)
} catch let error as NSError {
print("Server failed to start with error: \(error)")
}
}
public func stop() {
http.stop()
}
private func oauthRoute() {
http["/oauth"] = { request in
guard let response = AuthorizeResponse(queryParameters: request.queryParams), response.state == self.state else {
return .badRequest(.text("Bad request."))
}
WebAPI.oauthAccess(self.clientID, clientSecret: self.clientSecret, code: response.code, redirectURI: self.redirectURI, success: {(response) in
self.delegate?.userAuthed(OAuthResponse(response: response))
}, failure: {(error) in
print("Authorization failed")
})
if let redirect = self.redirectURI {
return .movedPermanently(redirect)
}
return .ok(.text("Authentication successful."))
}
}
private func oauthURLRequest(_ authorize: AuthorizeRequest) -> URLRequest? {
var requestString = "\(oauthURL)?client_id=\(authorize.clientID)"
requestString += authorize.parameters.requestStringFromParameters
guard let url = URL(string: requestString) else {
return nil
}
return URLRequest(url:url)
}
public func authorizeRequest(_ scope:[Scope], redirectURI: String, state: String = "slackkit", team: String? = nil) -> URLRequest? {
let request = AuthorizeRequest(clientID: clientID, scope: scope, redirectURI: redirectURI, state: state, team: team)
return oauthURLRequest(request)
}
}
+43
View File
@@ -0,0 +1,43 @@
//
// Response.swift
//
// Copyright © 2016 Peter Zignego. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
public struct Response {
let text: String
let responseType: ResponseType?
let attachments: [Attachment]?
public init(text: String, responseType: ResponseType? = nil, attachments: [Attachment]? = nil) {
self.responseType = responseType
self.text = text
self.attachments = attachments
}
internal var json: [String: Any] {
var json = [String : Any]()
json["text"] = text
json["response_type"] = responseType?.rawValue
json["attachments"] = attachments?.map({$0.dictionary})
return json
}
}
+71
View File
@@ -0,0 +1,71 @@
//
// Scope.swift
//
// Copyright © 2016 Peter Zignego. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
public enum Scope: String {
case ChannelsHistory = "channels:history"
case ChannelsRead = "channels:read"
case ChannelsWrite = "channels:write"
case ChatWriteBot = "chat:write:bot"
case ChatWriteUser = "chat:write:user"
case DNDRead = "dnd:read"
case DNDWrite = "dnd:write"
case EmojiRead = "emoji:read"
case FilesRead = "files:read"
case FilesWriteUser = "files:write:user"
case GroupsHistory = "groups:history"
case GroupsRead = "groups:read"
case GroupsWrite = "groups:write"
case IdentityBasic = "identity.basic"
case IMHistory = "im:history"
case IMRead = "im:read"
case IMWrite = "im:write"
case MPIMHistory = "mpim:history"
case MPIMRead = "mpim:read"
case MPIMWrite = "mpim:write"
case PinsRead = "pins:read"
case PinsWrite = "pins:write"
case ReactionsRead = "reactions:read"
case ReactionsWrite = "reactions:write"
case RemindersRead = "reminders:read"
case RemindersWrite = "reminders:write"
case SearchRead = "search:read"
case StarsRead = "stars:read"
case StarsWrite = "stars:write"
case TeamRead = "team:read"
case UserGroupsRead = "usergroups:read"
case UserGroupsWrite = "usergroups:write"
case UserProfilesRead = "user.profiles:read"
case UserProfilesWrite = "user.profiles:write"
case UsersRead = "users:read"
case UsersWrite = "users:write"
case IncomingWebhook = "incoming-webhook"
case Commands = "commands"
case Bot = "bot"
case Identify = "identify"
case Client = "client"
case Admin = "admin"
//Deprecated
case Read = "read"
case Post = "post"
}
+90
View File
@@ -0,0 +1,90 @@
//
// Server.swift
//
// Copyright © 2016 Peter Zignego. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
import Swifter
internal enum Reply {
case json(response: Response)
case text(body: String)
case badRequest
}
internal protocol Request {
var responseURL: String { get }
}
open class Server {
internal let http = HttpServer()
internal let token: String
internal init(token: String) {
self.token = token
}
open func start(_ port: in_port_t = 8080, forceIPV4: Bool = false) {
do {
try http.start(port, forceIPv4: forceIPV4)
} catch let error as NSError {
print("Server failed to start with error: \(error)")
}
}
open func stop() {
http.stop()
}
internal func request(_ request:Request, reply: Reply) -> HttpResponse {
switch reply {
case .text(let body):
return .ok(.text(body))
case .json(let response):
return .ok(.json(response.json as AnyObject))
case .badRequest:
return .badRequest(.text("Bad request."))
}
}
internal func dictionaryFromRequest(_ body: [UInt8]) -> [String: Any]? {
let string = String(data: Data(bytes: UnsafePointer<UInt8>(body), count: body.count), encoding: String.Encoding.utf8)
if let body = string?.components(separatedBy: "&") {
var dict: [String: Any] = [:]
for argument in body {
let kv = argument.components(separatedBy: "=")
if let key = kv.first, let value = kv.last {
dict[key] = value as Any?
}
}
return dict
}
return nil
}
internal func jsonFromRequest(_ string: String) -> [String: Any]? {
guard let data = string.data(using: String.Encoding.utf8) else {
return nil
}
return (try? JSONSerialization.jsonObject(with: data, options: [])) as? [String: Any] ?? nil
}
}
+66
View File
@@ -0,0 +1,66 @@
//
// SlackKit.swift
//
// Copyright © 2016 Peter Zignego. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
public final class SlackKit: OAuthDelegate {
internal(set) public var oauth: OAuthServer?
internal(set) public var clients: [String: Client] = [:]
private let clientOptions: ClientOptions
// Initalization block
public var onClientInitalization: ((Client) -> Void)?
// If you already have an API token
public init(withAPIToken token: String, clientOptions: ClientOptions = ClientOptions()) {
self.clientOptions = clientOptions
let client = Client(apiToken: token)
DispatchQueue.main.async(execute: {
self.onClientInitalization?(client)
})
clients[token] = client
client.connect(options: self.clientOptions)
}
// If you're going to be receiving and/or initiating OAuth requests, provide a client ID and secret
public init(clientID: String, clientSecret: String, state: String? = nil, redirectURI: String? = nil, port:in_port_t = 8080, forceIPV4: Bool = false, clientOptions: ClientOptions = ClientOptions()) {
self.clientOptions = clientOptions
oauth = try? OAuthServer(clientID: clientID, clientSecret: clientSecret, state: state, redirectURI: redirectURI, port: port, forceIPV4: forceIPV4, delegate: self)
}
internal func userAuthed(_ response: OAuthResponse) {
// User auth
if let token = response.accessToken {
let client = Client(apiToken: token)
self.onClientInitalization?(client)
clients[token] = client
}
// Bot User
if let token = response.bot?.botToken {
let client = Client(apiToken: token)
self.onClientInitalization?(client)
clients[token] = client
client.connect(options: self.clientOptions)
}
}
}
@@ -1,5 +1,5 @@
//
// SlackWebAPI.swift
// WebAPI.swift
//
// Copyright © 2016 Peter Zignego. All rights reserved.
//
@@ -24,7 +24,9 @@
import Foundation
internal enum Endpoint: String {
case apiTest = "api.test"
case authRevoke = "auth.revoke"
case authTest = "auth.test"
case channelsHistory = "channels.history"
case channelsInfo = "channels.info"
@@ -33,8 +35,8 @@ internal enum Endpoint: String {
case channelsSetPurpose = "channels.setPurpose"
case channelsSetTopic = "channels.setTopic"
case chatDelete = "chat.delete"
case chatMeMessage = "chat.meMessage"
case chatPostMessage = "chat.postMessage"
case chatMeMessage = "chat.meMessage"
case chatUpdate = "chat.update"
case dndInfo = "dnd.info"
case dndTeamInfo = "dnd.teamInfo"
@@ -63,6 +65,7 @@ internal enum Endpoint: String {
case mpimList = "mpim.list"
case mpimMark = "mpim.mark"
case mpimOpen = "mpim.open"
case oauthAccess = "oauth.access"
case pinsAdd = "pins.add"
case pinsRemove = "pins.remove"
case reactionsAdd = "reactions.add"
@@ -80,7 +83,7 @@ internal enum Endpoint: String {
case usersSetPresence = "users.setPresence"
}
public class SlackWebAPI {
public final class WebAPI {
public typealias FailureClosure = (_ error: SlackError)->Void
@@ -107,156 +110,174 @@ public class SlackWebAPI {
private let networkInterface: NetworkInterface
private let token: String
public init(token: String) {
self.networkInterface = NetworkInterface()
self.token = token
}
//MARK: - RTM
public func rtmStart(simpleLatest: Bool? = nil, noUnreads: Bool? = nil, mpimAware: Bool? = nil, success: ((_ response: [String: Any])->Void)?, failure: FailureClosure?) {
public func rtmStart(_ simpleLatest: Bool? = nil, noUnreads: Bool? = nil, mpimAware: Bool? = nil, success: ((_ response: [String: Any])->Void)?, failure: FailureClosure?) {
let parameters: [String: Any?] = ["simple_latest": simpleLatest, "no_unreads": noUnreads, "mpim_aware": mpimAware]
networkInterface.request(.rtmStart, token: token, parameters: filterNilParameters(parameters), successClosure: {(response) in
success?(response)
}) {(error) in
failure?(error)
}
networkInterface.request(.rtmStart, token: token, parameters: WebAPI.filterNilParameters(parameters), successClosure: {(response) in
success?(response)
}) {(error) in
failure?(error)
}
}
//MARK: - Auth Test
public func authenticationTest(success: ((_ authenticated: Bool)->Void)?, failure: FailureClosure?) {
//MARK: - Auth
public func authenticationTest(_ success: ((_ authenticated: Bool)->Void)?, failure: FailureClosure?) {
networkInterface.request(.authTest, token: token, parameters: nil, successClosure: {(response) in
success?(true)
}) {(error) in
failure?(error)
success?(true)
}) {(error) in
failure?(error)
}
}
public static func oauthAccess(_ clientID: String, clientSecret: String, code: String, redirectURI: String? = nil, success: ((_ response: [String: Any])->Void)?, failure: ((SlackError)->Void)?) {
let parameters: [String: Any?] = ["client_id": clientID, "client_secret": clientSecret, "code": code, "redirect_uri": redirectURI]
NetworkInterface().request(.oauthAccess, parameters: filterNilParameters(parameters), successClosure: {(response) in
success?(response)
}) {(error) in
failure?(error)
}
}
public static func oauthRevoke(_ token: String, test: Bool? = nil, success: ((_ revoked:Bool)->Void)?, failure: ((SlackError)->Void)?) {
let parameters: [String: Any?] = ["token": token, "test": test]
NetworkInterface().request(.authRevoke, parameters: filterNilParameters(parameters), successClosure: {(response) in
success?(true)
}) {(error) in
failure?(error)
}
}
//MARK: - Channels
public func channelHistory(id: String, latest: String = "\(Date().slackTimestamp)", oldest: String = "0", inclusive: Bool = false, count: Int = 100, unreads: Bool = false, success: ((_ history: History?)->Void)?, failure: FailureClosure?) {
public func channelHistory(_ id: String, latest: String = "\(Date().timeIntervalSince1970)", oldest: String = "0", inclusive: Bool = false, count: Int = 100, unreads: Bool = false, success: ((_ history: History)->Void)?, failure: FailureClosure?) {
history(.channelsHistory, id: id, latest: latest, oldest: oldest, inclusive: inclusive, count: count, unreads: unreads, success: {(history) in
success?(history)
}) {(error) in
failure?(error)
success?(history)
}) {(error) in
failure?(error)
}
}
public func channelInfo(id: String, success: ((_ channel: Channel)->Void)?, failure: FailureClosure?) {
public func channelInfo(_ id: String, success: ((_ channel: Channel)->Void)?, failure: FailureClosure?) {
info(.channelsInfo, type:.channel, id: id, success: {(channel) in
success?(channel)
}) {(error) in
failure?(error)
success?(channel)
}) {(error) in
failure?(error)
}
}
public func channelsList(excludeArchived: Bool = false, success: ((_ channels: [[String: Any]]?)->Void)?, failure: FailureClosure?) {
public func channelsList(_ excludeArchived: Bool = false, success: ((_ channels: [[String: Any]]?)->Void)?, failure: FailureClosure?) {
list(.channelsList, type:.channel, excludeArchived: excludeArchived, success: {(channels) in
success?(channels)
}) {(error) in
failure?(error)
success?(channels)
}) {(error) in
failure?(error)
}
}
public func markChannel(channel: String, timestamp: String, success: ((_ ts: String)->Void)?, failure: FailureClosure?) {
public func markChannel(_ channel: String, timestamp: String, success: ((_ ts: String)->Void)?, failure: FailureClosure?) {
mark(.channelsMark, channel: channel, timestamp: timestamp, success: {(ts) in
success?(timestamp)
}) {(error) in
failure?(error)
success?(timestamp)
}) {(error) in
failure?(error)
}
}
public func setChannelPurpose(channel: String, purpose: String, success: ((_ purposeSet: Bool)->Void)?, failure: FailureClosure?) {
public func setChannelPurpose(_ channel: String, purpose: String, success: ((_ purposeSet: Bool)->Void)?, failure: FailureClosure?) {
setInfo(.channelsSetPurpose, type: .purpose, channel: channel, text: purpose, success: {(purposeSet) in
success?(purposeSet)
}) { (error) in
failure?(error)
success?(purposeSet)
}) {(error) in
failure?(error)
}
}
public func setChannelTopic(channel: String, topic: String, success: ((_ topicSet: Bool)->Void)?, failure: FailureClosure?) {
public func setChannelTopic(_ channel: String, topic: String, success: ((_ topicSet: Bool)->Void)?, failure: FailureClosure?) {
setInfo(.channelsSetTopic, type: .topic, channel: channel, text: topic, success: {(topicSet) in
success?(topicSet)
}) {(error) in
failure?(error)
success?(topicSet)
}) {(error) in
failure?(error)
}
}
//MARK: - Messaging
public func deleteMessage(channel: String, ts: String, success: ((_ deleted: Bool)->Void)?, failure: FailureClosure?) {
public func deleteMessage(_ channel: String, ts: String, success: ((_ deleted: Bool)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["channel": channel, "ts": ts]
networkInterface.request(.chatDelete, token: token, parameters: parameters, successClosure: {(response) in
success?(true)
}) {(error) in
failure?(error)
success?(true)
}) {(error) in
failure?(error)
}
}
public func sendMessage(channel: String, text: String, username: String? = nil, asUser: Bool? = nil, parse: ParseMode? = nil, linkNames: Bool? = nil, attachments: [Attachment?]? = nil, unfurlLinks: Bool? = nil, unfurlMedia: Bool? = nil, iconURL: String? = nil, iconEmoji: String? = nil, success: (((ts: String?, channel: String?))->Void)?, failure: FailureClosure?) {
let parameters: [String: Any?] = ["channel":channel, "text":text.slackFormatEscaping, "as_user":asUser, "parse":parse?.rawValue, "link_names":linkNames, "unfurl_links":unfurlLinks, "unfurlMedia":unfurlMedia, "username":username, "attachments":encodeAttachments(attachments), "icon_url":iconURL, "icon_emoji":iconEmoji]
networkInterface.request(.chatPostMessage, token: token, parameters: filterNilParameters(parameters), successClosure: {(response) in
success?((ts: response["ts"] as? String, response["channel"] as? String))
}) {(error) in
failure?(error)
}
}
public func sendMeMessage(_ channel: String, text: String, success: (((ts: String?, channel: String?))->Void)?, failure: FailureClosure?) {
let parameters: [String: Any?] = ["channel": channel, "text": text.slackFormatEscaping]
networkInterface.request(.chatMeMessage, token: token, parameters: filterNilParameters(parameters), successClosure: {(response) in
public func sendMessage(_ channel: String, text: String, username: String? = nil, asUser: Bool? = nil, parse: ParseMode? = nil, linkNames: Bool? = nil, attachments: [Attachment?]? = nil, unfurlLinks: Bool? = nil, unfurlMedia: Bool? = nil, iconURL: String? = nil, iconEmoji: String? = nil, success: (((ts: String?, channel: String?))->Void)?, failure: FailureClosure?) {
let parameters: [String: Any?] = ["channel": channel, "text": text.slackFormatEscaping, "as_user": asUser, "parse": parse?.rawValue, "link_names": linkNames, "unfurl_links": unfurlLinks, "unfurlMedia": unfurlMedia, "username": username, "icon_url": iconURL, "icon_emoji": iconEmoji, "attachments": encodeAttachments(attachments)]
networkInterface.request(.chatPostMessage, token: token, parameters: WebAPI.filterNilParameters(parameters), successClosure: {(response) in
success?((ts: response["ts"] as? String, response["channel"] as? String))
}) {(error) in
failure?(error)
}
}
public func updateMessage(channel: String, ts: String, message: String, attachments: [Attachment?]? = nil, parse:ParseMode = .none, linkNames: Bool = false, success: ((_ updated: Bool)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any?] = ["channel": channel, "ts": ts, "text": message.slackFormatEscaping, "parse": parse.rawValue, "link_names": linkNames, "attachments":encodeAttachments(attachments)]
networkInterface.request(.chatUpdate, token: token, parameters: filterNilParameters(parameters), successClosure: {(response) in
success?(true)
}) {(error) in
failure?(error)
public func sendMeMessage(_ channel: String, text: String, success: (((ts: String?, channel: String?))->Void)?, failure: FailureClosure?) {
let parameters: [String: Any?] = ["channel": channel, "text": text.slackFormatEscaping]
networkInterface.request(.chatMeMessage, token: token, parameters: WebAPI.filterNilParameters(parameters), successClosure: {(response) in
success?((ts: response["ts"] as? String, response["channel"] as? String))
}) {(error) in
failure?(error)
}
}
public func updateMessage(_ channel: String, ts: String, message: String, attachments: [Attachment?]? = nil, parse:ParseMode = .none, linkNames: Bool = false, success: ((_ updated: Bool)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any?] = ["channel": channel, "ts": ts, "text": message.slackFormatEscaping, "parse": parse.rawValue, "link_names": linkNames, "attachments": encodeAttachments(attachments)]
networkInterface.request(.chatUpdate, token: token, parameters: WebAPI.filterNilParameters(parameters), successClosure: {(response) in
success?(true)
}) {(error) in
failure?(error)
}
}
//MARK: - Do Not Disturb
public func dndInfo(user: String? = nil, success: ((_ status: DoNotDisturbStatus)->Void)?, failure: FailureClosure?) {
public func dndInfo(_ user: String? = nil, success: ((_ status: DoNotDisturbStatus)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any?] = ["user": user]
networkInterface.request(.dndInfo, token: token, parameters: filterNilParameters(parameters), successClosure: {(response) in
success?(DoNotDisturbStatus(status: response))
}) {(error) in
failure?(error)
networkInterface.request(.dndInfo, token: token, parameters: WebAPI.filterNilParameters(parameters), successClosure: {(response) in
success?(DoNotDisturbStatus(status: response))
}) {(error) in
failure?(error)
}
}
public func dndTeamInfo(users: [String]? = nil, success: ((_ statuses: [String: DoNotDisturbStatus])->Void)?, failure: FailureClosure?) {
let parameters: [String: Any?] = ["users":users?.joined(separator: ",")]
networkInterface.request(.dndTeamInfo, token: token, parameters: filterNilParameters(parameters), successClosure: {(response) in
public func dndTeamInfo(_ users: [String]? = nil, success: ((_ statuses: [String: DoNotDisturbStatus])->Void)?, failure: FailureClosure?) {
let parameters: [String: Any?] = ["users": users?.joined(separator: ",")]
networkInterface.request(.dndTeamInfo, token: token, parameters: WebAPI.filterNilParameters(parameters), successClosure: {(response) in
guard let usersDictionary = response["users"] as? [String: Any] else {
success?([:])
return
}
success?(self.enumerateDNDStatuses(usersDictionary))
}) {(error) in
failure?(error)
}) {(error) in
failure?(error)
}
}
//MARK: - Emoji
public func emojiList(success: ((_ emojiList: [String: Any]?)->Void)?, failure: FailureClosure?) {
public func emojiList(_ success: ((_ emojiList: [String: Any]?)->Void)?, failure: FailureClosure?) {
networkInterface.request(.emojiList, token: token, parameters: nil, successClosure: {(response) in
success?(response["emoji"] as? [String: Any])
}) {(error) in
failure?(error)
success?(response["emoji"] as? [String: Any])
}) {(error) in
failure?(error)
}
}
//MARK: - Files
public func deleteFile(fileID: String, success: ((_ deleted: Bool)->Void)?, failure: FailureClosure?) {
let parameters = ["file":fileID]
networkInterface.request(.filesDelete, token: token, parameters: parameters, successClosure: {(response) in
success?(true)
}) {(error) in
failure?(error)
public func deleteFile(_ fileID: String, success: ((_ deleted: Bool)->Void)?, failure: FailureClosure?) {
let parameters = ["file": fileID]
networkInterface.request(.filesDelete, token: token, parameters: parameters as [String : Any]?, successClosure: {(response) in
success?(true)
}) {(error) in
failure?(error)
}
}
@@ -278,7 +299,7 @@ public class SlackWebAPI {
public func uploadFile(_ file: Data, filename: String, filetype: String = "auto", title: String? = nil, initialComment: String? = nil, channels: [String]? = nil, success: ((_ file: File)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any?] = ["filename": filename, "filetype": filetype, "title": title, "initial_comment": initialComment, "channels": channels?.joined(separator: ",")]
networkInterface.uploadRequest(token: token, data: file, parameters: filterNilParameters(parameters), successClosure: {(response) in
networkInterface.uploadRequest(token, data: file, parameters: WebAPI.filterNilParameters(parameters), successClosure: {(response) in
success?(File(file: response["file"] as? [String: Any]))
}) {(error) in
failure?(error)
@@ -286,374 +307,374 @@ public class SlackWebAPI {
}
//MARK: - File Comments
public func addFileComment(fileID: String, comment: String, success: ((_ comment: Comment)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["file":fileID, "comment":comment.slackFormatEscaping]
public func addFileComment(_ fileID: String, comment: String, success: ((_ comment: Comment)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["file": fileID, "comment": comment.slackFormatEscaping]
networkInterface.request(.filesCommentsAdd, token: token, parameters: parameters, successClosure: {(response) in
success?(Comment(comment: response["comment"] as? [String: Any]))
}) {(error) in
failure?(error)
success?(Comment(comment: response["comment"] as? [String: Any]))
}) {(error) in
failure?(error)
}
}
public func editFileComment(fileID: String, commentID: String, comment: String, success: ((_ comment: Comment)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["file":fileID, "id":commentID, "comment":comment.slackFormatEscaping]
public func editFileComment(_ fileID: String, commentID: String, comment: String, success: ((_ comment: Comment)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["file": fileID, "id": commentID, "comment": comment.slackFormatEscaping]
networkInterface.request(.filesCommentsEdit, token: token, parameters: parameters, successClosure: {(response) in
success?(Comment(comment: response["comment"] as? [String: Any]))
}) {(error) in
failure?(error)
}) {(error) in
failure?(error)
}
}
public func deleteFileComment(fileID: String, commentID: String, success: ((_ deleted: Bool?)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["file":fileID, "id": commentID]
public func deleteFileComment(_ fileID: String, commentID: String, success: ((_ deleted: Bool?)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["file": fileID, "id": commentID]
networkInterface.request(.filesCommentsDelete, token: token, parameters: parameters, successClosure: {(response) in
success?(true)
}) {(error) in
failure?(error)
success?(true)
}) {(error) in
failure?(error)
}
}
//MARK: - Groups
public func closeGroup(groupID: String, success: ((_ closed: Bool)->Void)?, failure: FailureClosure?) {
public func closeGroup(_ groupID: String, success: ((_ closed: Bool)->Void)?, failure: FailureClosure?) {
close(.groupsClose, channelID: groupID, success: {(closed) in
success?(closed)
}) {(error) in
failure?(error)
success?(closed)
}) {(error) in
failure?(error)
}
}
public func groupHistory(id: String, latest: String = "\(Date().slackTimestamp)", oldest: String = "0", inclusive: Bool = false, count: Int = 100, unreads: Bool = false, success: ((_ history: History?)->Void)?, failure: FailureClosure?) {
public func groupHistory(_ id: String, latest: String = "\(Date().timeIntervalSince1970)", oldest: String = "0", inclusive: Bool = false, count: Int = 100, unreads: Bool = false, success: ((_ history: History)->Void)?, failure: FailureClosure?) {
history(.groupsHistory, id: id, latest: latest, oldest: oldest, inclusive: inclusive, count: count, unreads: unreads, success: {(history) in
success?(history)
}) {(error) in
failure?(error)
success?(history)
}) {(error) in
failure?(error)
}
}
public func groupInfo(id: String, success: ((_ channel: Channel?)->Void)?, failure: FailureClosure?) {
public func groupInfo(_ id: String, success: ((_ channel: Channel)->Void)?, failure: FailureClosure?) {
info(.groupsInfo, type:.group, id: id, success: {(channel) in
success?(channel)
}) {(error) in
failure?(error)
success?(channel)
}) {(error) in
failure?(error)
}
}
public func groupsList(excludeArchived: Bool = false, success: ((_ channels: [[String: Any]]?)->Void)?, failure: FailureClosure?) {
public func groupsList(_ excludeArchived: Bool = false, success: ((_ channels: [[String: Any]]?)->Void)?, failure: FailureClosure?) {
list(.groupsList, type:.group, excludeArchived: excludeArchived, success: {(channels) in
success?(channels)
}) {(error) in
failure?(error)
success?(channels)
}) {(error) in
failure?(error)
}
}
public func markGroup(channel: String, timestamp: String, success: ((_ ts: String)->Void)?, failure: FailureClosure?) {
public func markGroup(_ channel: String, timestamp: String, success: ((_ ts: String)->Void)?, failure: FailureClosure?) {
mark(.groupsMark, channel: channel, timestamp: timestamp, success: {(ts) in
success?(timestamp)
}) {(error) in
failure?(error)
success?(timestamp)
}) {(error) in
failure?(error)
}
}
public func openGroup(channel: String, success: ((_ opened: Bool)->Void)?, failure: FailureClosure?) {
public func openGroup(_ channel: String, success: ((_ opened: Bool)->Void)?, failure: FailureClosure?) {
let parameters = ["channel":channel]
networkInterface.request(.groupsOpen, token: token, parameters: parameters, successClosure: {(response) in
success?(true)
}) {(error) in
failure?(error)
networkInterface.request(.groupsOpen, token: token, parameters: parameters as [String: Any]?, successClosure: {(response) in
success?(true)
}) {(error) in
failure?(error)
}
}
public func setGroupPurpose(channel: String, purpose: String, success: ((_ purposeSet: Bool)->Void)?, failure: FailureClosure?) {
public func setGroupPurpose(_ channel: String, purpose: String, success: ((_ purposeSet: Bool)->Void)?, failure: FailureClosure?) {
setInfo(.groupsSetPurpose, type: .purpose, channel: channel, text: purpose, success: {(purposeSet) in
success?(purposeSet)
}) {(error) in
failure?(error)
success?(purposeSet)
}) {(error) in
failure?(error)
}
}
public func setGroupTopic(channel: String, topic: String, success: ((_ topicSet: Bool)->Void)?, failure: FailureClosure?) {
public func setGroupTopic(_ channel: String, topic: String, success: ((_ topicSet: Bool)->Void)?, failure: FailureClosure?) {
setInfo(.groupsSetTopic, type: .topic, channel: channel, text: topic, success: {(topicSet) in
success?(topicSet)
}) {(error) in
failure?(error)
success?(topicSet)
}) {(error) in
failure?(error)
}
}
//MARK: - IM
public func closeIM(channel: String, success: ((_ closed: Bool)->Void)?, failure: FailureClosure?) {
public func closeIM(_ channel: String, success: ((_ closed: Bool)->Void)?, failure: FailureClosure?) {
close(.imClose, channelID: channel, success: {(closed) in
success?(closed)
}) {(error) in
failure?(error)
success?(closed)
}) {(error) in
failure?(error)
}
}
public func imHistory(id: String, latest: String = "\(Date().slackTimestamp)", oldest: String = "0", inclusive: Bool = false, count: Int = 100, unreads: Bool = false, success: ((_ history: History?)->Void)?, failure: FailureClosure?) {
public func imHistory(_ id: String, latest: String = "\(Date().timeIntervalSince1970)", oldest: String = "0", inclusive: Bool = false, count: Int = 100, unreads: Bool = false, success: ((_ history: History)->Void)?, failure: FailureClosure?) {
history(.imHistory, id: id, latest: latest, oldest: oldest, inclusive: inclusive, count: count, unreads: unreads, success: {(history) in
success?(history)
}) {(error) in
failure?(error)
success?(history)
}) {(error) in
failure?(error)
}
}
public func imsList(excludeArchived: Bool = false, success: ((_ channels: [[String: Any]]?)->Void)?, failure: FailureClosure?) {
public func imsList(_ excludeArchived: Bool = false, success: ((_ channels: [[String: Any]]?)->Void)?, failure: FailureClosure?) {
list(.imList, type:.im, excludeArchived: excludeArchived, success: {(channels) in
success?(channels)
}) {(error) in
failure?(error)
success?(channels)
}) {(error) in
failure?(error)
}
}
public func markIM(channel: String, timestamp: String, success: ((_ ts: String)->Void)?, failure: FailureClosure?) {
public func markIM(_ channel: String, timestamp: String, success: ((_ ts: String)->Void)?, failure: FailureClosure?) {
mark(.imMark, channel: channel, timestamp: timestamp, success: {(ts) in
success?(timestamp)
}) {(error) in
failure?(error)
success?(timestamp)
}) {(error) in
failure?(error)
}
}
public func openIM(userID: String, success: ((_ imID: String?)->Void)?, failure: FailureClosure?) {
let parameters = ["user":userID]
networkInterface.request(.imOpen, token: token, parameters: parameters, successClosure: {(response) in
let group = response["channel"] as? [String: Any]
success?(group?["id"] as? String)
}) {(error) in
failure?(error)
public func openIM(_ userID: String, success: ((_ imID: String?)->Void)?, failure: FailureClosure?) {
let parameters = ["user": userID]
networkInterface.request(.imOpen, token: token, parameters: parameters as [String: Any]?, successClosure: {(response) in
let group = response["channel"] as? [String: Any]
success?(group?["id"] as? String)
}) {(error) in
failure?(error)
}
}
//MARK: - MPIM
public func closeMPIM(channel: String, success: ((_ closed: Bool)->Void)?, failure: FailureClosure?) {
public func closeMPIM(_ channel: String, success: ((_ closed: Bool)->Void)?, failure: FailureClosure?) {
close(.mpimClose, channelID: channel, success: {(closed) in
success?(closed)
}) {(error) in
failure?(error)
success?(closed)
}) {(error) in
failure?(error)
}
}
public func mpimHistory(id: String, latest: String = "\(Date().slackTimestamp)", oldest: String = "0", inclusive: Bool = false, count: Int = 100, unreads: Bool = false, success: ((_ history: History?)->Void)?, failure: FailureClosure?) {
public func mpimHistory(_ id: String, latest: String = "\(Date().timeIntervalSince1970)", oldest: String = "0", inclusive: Bool = false, count: Int = 100, unreads: Bool = false, success: ((_ history: History)->Void)?, failure: FailureClosure?) {
history(.mpimHistory, id: id, latest: latest, oldest: oldest, inclusive: inclusive, count: count, unreads: unreads, success: {(history) in
success?(history)
}) {(error) in
failure?(error)
success?(history)
}) {(error) in
failure?(error)
}
}
public func mpimsList(excludeArchived: Bool = false, success: ((_ channels: [[String: Any]]?)->Void)?, failure: FailureClosure?) {
public func mpimsList(_ excludeArchived: Bool = false, success: ((_ channels: [[String: Any]]?)->Void)?, failure: FailureClosure?) {
list(.mpimList, type:.group, excludeArchived: excludeArchived, success: {(channels) in
success?(channels)
}) {(error) in
failure?(error)
success?(channels)
}) {(error) in
failure?(error)
}
}
public func markMPIM(channel: String, timestamp: String, success: ((_ ts: String)->Void)?, failure: FailureClosure?) {
public func markMPIM(_ channel: String, timestamp: String, success: ((_ ts: String)->Void)?, failure: FailureClosure?) {
mark(.mpimMark, channel: channel, timestamp: timestamp, success: {(ts) in
success?(timestamp)
}) {(error) in
failure?(error)
success?(timestamp)
}) {(error) in
failure?(error)
}
}
public func openMPIM(userIDs: [String], success: ((_ mpimID: String?)->Void)?, failure: FailureClosure?) {
let parameters = ["users":userIDs.joined(separator: ",")]
networkInterface.request(.mpimOpen, token: token, parameters: parameters, successClosure: {(response) in
let group = response["group"] as? [String: Any]
success?(group?["id"] as? String)
}) {(error) in
failure?(error)
public func openMPIM(_ userIDs: [String], success: ((_ mpimID: String?)->Void)?, failure: FailureClosure?) {
let parameters = ["users": userIDs.joined(separator: ",")]
networkInterface.request(.mpimOpen, token: token, parameters: parameters as [String: Any]?, successClosure: {(response) in
let group = response["group"] as? [String: Any]
success?(group?["id"] as? String)
}) {(error) in
failure?(error)
}
}
//MARK: - Pins
public func pinItem(channel: String, file: String? = nil, fileComment: String? = nil, timestamp: String? = nil, success: ((_ pinned: Bool)->Void)?, failure: FailureClosure?) {
public func pinItem(_ channel: String, file: String? = nil, fileComment: String? = nil, timestamp: String? = nil, success: ((_ pinned: Bool)->Void)?, failure: FailureClosure?) {
pin(.pinsAdd, channel: channel, file: file, fileComment: fileComment, timestamp: timestamp, success: {(ok) in
success?(ok)
}) {(error) in
failure?(error)
success?(ok)
}) {(error) in
failure?(error)
}
}
public func unpinItem(channel: String, file: String? = nil, fileComment: String? = nil, timestamp: String? = nil, success: ((_ unpinned: Bool)->Void)?, failure: FailureClosure?) {
public func unpinItem(_ channel: String, file: String? = nil, fileComment: String? = nil, timestamp: String? = nil, success: ((_ unpinned: Bool)->Void)?, failure: FailureClosure?) {
pin(.pinsRemove, channel: channel, file: file, fileComment: fileComment, timestamp: timestamp, success: {(ok) in
success?(ok)
}) {(error) in
failure?(error)
success?(ok)
}) {(error) in
failure?(error)
}
}
private func pin(_ endpoint: Endpoint, channel: String, file: String? = nil, fileComment: String? = nil, timestamp: String? = nil, success: ((_ ok: Bool)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any?] = ["channel":channel, "file":file, "file_comment":fileComment, "timestamp":timestamp]
networkInterface.request(endpoint, token: token, parameters: filterNilParameters(parameters), successClosure: {(response) in
success?(true)
}) {(error) in
failure?(error)
let parameters: [String: Any?] = ["channel": channel, "file": file, "file_comment": fileComment, "timestamp": timestamp]
networkInterface.request(endpoint, token: token, parameters: WebAPI.filterNilParameters(parameters), successClosure: {(response) in
success?(true)
}) {(error) in
failure?(error)
}
}
//MARK: - Reactions
// One of file, file_comment, or the combination of channel and timestamp must be specified.
public func addReaction(name: String, file: String? = nil, fileComment: String? = nil, channel: String? = nil, timestamp: String? = nil, success: ((_ reacted: Bool)->Void)?, failure: FailureClosure?) {
public func addReaction(_ name: String, file: String? = nil, fileComment: String? = nil, channel: String? = nil, timestamp: String? = nil, success: ((_ reacted: Bool)->Void)?, failure: FailureClosure?) {
react(.reactionsAdd, name: name, file: file, fileComment: fileComment, channel: channel, timestamp: timestamp, success: {(ok) in
success?(ok)
}) {(error) in
failure?(error)
success?(ok)
}) {(error) in
failure?(error)
}
}
// One of file, file_comment, or the combination of channel and timestamp must be specified.
public func removeReaction(name: String, file: String? = nil, fileComment: String? = nil, channel: String? = nil, timestamp: String? = nil, success: ((_ unreacted: Bool)->Void)?, failure: FailureClosure?) {
public func removeReaction(_ name: String, file: String? = nil, fileComment: String? = nil, channel: String? = nil, timestamp: String? = nil, success: ((_ unreacted: Bool)->Void)?, failure: FailureClosure?) {
react(.reactionsRemove, name: name, file: file, fileComment: fileComment, channel: channel, timestamp: timestamp, success: {(ok) in
success?(ok)
}) {(error) in
failure?(error)
success?(ok)
}) {(error) in
failure?(error)
}
}
private func react(_ endpoint: Endpoint, name: String, file: String? = nil, fileComment: String? = nil, channel: String? = nil, timestamp: String? = nil, success: ((_ ok: Bool)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any?] = ["name":name, "file":file, "file_comment":fileComment, "channel":channel, "timestamp":timestamp]
networkInterface.request(endpoint, token: token, parameters: filterNilParameters(parameters), successClosure: {(response) in
success?(true)
}) {(error) in
failure?(error)
let parameters: [String: Any?] = ["name": name, "file": file, "file_comment": fileComment, "channel": channel, "timestamp": timestamp]
networkInterface.request(endpoint, token: token, parameters: WebAPI.filterNilParameters(parameters), successClosure: {(response) in
success?(true)
}) {(error) in
failure?(error)
}
}
//MARK: - Stars
// One of file, file_comment, channel, or the combination of channel and timestamp must be specified.
public func addStar(file: String? = nil, fileComment: String? = nil, channel: String? = nil, timestamp: String? = nil, success: ((_ starred: Bool)->Void)?, failure: FailureClosure?) {
public func addStar(_ file: String? = nil, fileComment: String? = nil, channel: String? = nil, timestamp: String? = nil, success: ((_ starred: Bool)->Void)?, failure: FailureClosure?) {
star(.starsAdd, file: file, fileComment: fileComment, channel: channel, timestamp: timestamp, success: {(ok) in
success?(ok)
}) {(error) in
failure?(error)
success?(ok)
}) {(error) in
failure?(error)
}
}
// One of file, file_comment, channel, or the combination of channel and timestamp must be specified.
public func removeStar(file: String? = nil, fileComment: String? = nil, channel: String? = nil, timestamp: String? = nil, success: ((_ unstarred: Bool)->Void)?, failure: FailureClosure?) {
public func removeStar(_ file: String? = nil, fileComment: String? = nil, channel: String? = nil, timestamp: String? = nil, success: ((_ unstarred: Bool)->Void)?, failure: FailureClosure?) {
star(.starsRemove, file: file, fileComment: fileComment, channel: channel, timestamp: timestamp, success: {(ok) in
success?(ok)
}) {(error) in
failure?(error)
success?(ok)
}) {(error) in
failure?(error)
}
}
private func star(_ endpoint: Endpoint, file: String?, fileComment: String?, channel: String?, timestamp: String?, success: ((_ ok: Bool)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any?] = ["file":file, "file_comment":fileComment, "channel":channel, "timestamp":timestamp]
networkInterface.request(endpoint, token: token, parameters: filterNilParameters(parameters), successClosure: {(response) in
success?(true)
}) {(error) in
failure?(error)
let parameters: [String: Any?] = ["file": file, "file_comment": fileComment, "channel": channel, "timestamp": timestamp]
networkInterface.request(endpoint, token: token, parameters: WebAPI.filterNilParameters(parameters), successClosure: {(response) in
success?(true)
}) {(error) in
failure?(error)
}
}
//MARK: - Team
public func teamInfo(success: ((_ info: [String: Any]?)->Void)?, failure: FailureClosure?) {
public func teamInfo(_ success: ((_ info: [String: Any]?)->Void)?, failure: FailureClosure?) {
networkInterface.request(.teamInfo, token: token, parameters: nil, successClosure: {(response) in
success?(response["team"] as? [String: Any])
}) {(error) in
failure?(error)
success?(response["team"] as? [String: Any])
}) {(error) in
failure?(error)
}
}
//MARK: - Users
public func userPresence(user: String, success: ((_ presence: String?)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["user":user]
public func userPresence(_ user: String, success: ((_ presence: String?)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["user": user]
networkInterface.request(.usersGetPresence, token: token, parameters: parameters, successClosure: {(response) in
success?(response["presence"] as? String)
}) {(error) in
failure?(error)
success?(response["presence"] as? String)
}) {(error) in
failure?(error)
}
}
public func userInfo(id: String, success: ((_ user: User)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["user":id]
public func userInfo(_ id: String, success: ((_ user: User)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["user": id]
networkInterface.request(.usersInfo, token: token, parameters: parameters, successClosure: {(response) in
success?(User(user: response["user"] as? [String: Any]))
}) {(error) in
failure?(error)
success?(User(user: response["user"] as? [String: Any]))
}) {(error) in
failure?(error)
}
}
public func usersList(includePresence: Bool = false, success: ((_ userList: [[String: Any]]?)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["presence":includePresence]
public func usersList(_ includePresence: Bool = false, success: ((_ userList: [[String: Any]]?)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["presence": includePresence]
networkInterface.request(.usersList, token: token, parameters: parameters, successClosure: {(response) in
success?(response["members"] as? [[String: Any]])
}) {(error) in
failure?(error)
success?(response["members"] as? [[String: Any]])
}) {(error) in
failure?(error)
}
}
public func setUserActive(success: ((_ success: Bool)->Void)?, failure: FailureClosure?) {
public func setUserActive(_ success: ((_ success: Bool)->Void)?, failure: FailureClosure?) {
networkInterface.request(.usersSetActive, token: token, parameters: nil, successClosure: {(response) in
success?(true)
}) {(error) in
failure?(error)
success?(true)
}) {(error) in
failure?(error)
}
}
public func setUserPresence(presence: Presence, success: ((_ success: Bool)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["presence":presence.rawValue]
public func setUserPresence(_ presence: Presence, success: ((_ success: Bool)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["presence": presence.rawValue]
networkInterface.request(.usersSetPresence, token: token, parameters: parameters, successClosure: {(response) in
success?(true)
}) {(error) in
failure?(error)
success?(true)
}) {(error) in
failure?(error)
}
}
//MARK: - Channel Utilities
private func close(_ endpoint: Endpoint, channelID: String, success: ((_ closed: Bool)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["channel":channelID]
let parameters: [String: Any] = ["channel": channelID]
networkInterface.request(endpoint, token: token, parameters: parameters, successClosure: {(response) in
success?(true)
}) {(error) in
failure?(error)
success?(true)
}) {(error) in
failure?(error)
}
}
private func history(_ endpoint: Endpoint, id: String, latest: String = "\(Date().slackTimestamp)", oldest: String = "0", inclusive: Bool = false, count: Int = 100, unreads: Bool = false, success: ((_ history: History)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["channel": id, "latest": latest, "oldest": oldest, "inclusive":inclusive, "count":count, "unreads":unreads]
private func history(_ endpoint: Endpoint, id: String, latest: String = "\(Date().timeIntervalSince1970)", oldest: String = "0", inclusive: Bool = false, count: Int = 100, unreads: Bool = false, success: ((_ history: History)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["channel": id, "latest": latest, "oldest": oldest, "inclusive": inclusive, "count": count, "unreads": unreads]
networkInterface.request(endpoint, token: token, parameters: parameters, successClosure: {(response) in
success?(History(history: response))
}) {(error) in
failure?(error)
success?(History(history: response))
}) {(error) in
failure?(error)
}
}
private func info(_ endpoint: Endpoint, type: ChannelType, id: String, success: ((_ channel: Channel)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["channel": id]
networkInterface.request(endpoint, token: token, parameters: parameters, successClosure: {(response) in
success?(Channel(channel: response[type.rawValue] as? [String: Any]))
}) {(error) in
failure?(error)
success?(Channel(channel: response[type.rawValue] as? [String: Any]))
}) {(error) in
failure?(error)
}
}
private func list(_ endpoint: Endpoint, type: ChannelType, excludeArchived: Bool = false, success: ((_ channels: [[String: Any]]?)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["exclude_archived": excludeArchived]
networkInterface.request(endpoint, token: token, parameters: parameters, successClosure: {(response) in
success?(response[type.rawValue+"s"] as? [[String: Any]])
}) {(error) in
failure?(error)
success?(response[type.rawValue+"s"] as? [[String: Any]])
}) {(error) in
failure?(error)
}
}
private func mark(_ endpoint: Endpoint, channel: String, timestamp: String, success: ((_ ts: String)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["channel": channel, "ts": timestamp]
networkInterface.request(endpoint, token: token, parameters: parameters, successClosure: {(response) in
success?(timestamp)
}) {(error) in
failure?(error)
success?(timestamp)
}) {(error) in
failure?(error)
}
}
private func setInfo(_ endpoint: Endpoint, type: InfoType, channel: String, text: String, success: ((_ success: Bool)->Void)?, failure: FailureClosure?) {
fileprivate func setInfo(_ endpoint: Endpoint, type: InfoType, channel: String, text: String, success: ((_ success: Bool)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["channel": channel, type.rawValue: text]
networkInterface.request(endpoint, token: token, parameters: parameters, successClosure: {(response) in
success?(true)
}) {(error) in
failure?(error)
success?(true)
}) {(error) in
failure?(error)
}
}
@@ -670,14 +691,14 @@ public class SlackWebAPI {
let data = try JSONSerialization.data(withJSONObject: attachmentArray, options: [])
return String(data: data, encoding: String.Encoding.utf8)
} catch _ {
print("Error encoding attachments")
}
}
return nil
}
//MARK: - Filter Nil Parameters
internal func filterNilParameters(_ parameters: [String: Any?]) -> [String: Any] {
internal static func filterNilParameters(_ parameters: [String: Any?]) -> [String: Any] {
var finalParameters = [String: Any]()
for (key, value) in parameters {
if let unwrapped = value {
+49
View File
@@ -0,0 +1,49 @@
//
// WebhookRequest.swift
//
// Copyright © 2016 Peter Zignego. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
internal struct WebhookRequest: Request {
let token: String?
let teamID: String
let teamDomain: String
let channelID: String
let channelName: String
let userID: String
let userName: String
let command: String
let text: String
let responseURL: String
init(request: [String: Any]?) {
token = request?["token"] as? String
teamID = request?["team_id"] as? String ?? ""
teamDomain = request?["team_domain"] as? String ?? ""
channelID = request?["channel_id"] as? String ?? ""
channelName = request?["channel_name"] as? String ?? ""
userID = request?["user_id"] as? String ?? ""
userName = request?["user_name"] as? String ?? ""
command = request?["command"] as? String ?? ""
text = request?["text"] as? String ?? ""
responseURL = request?["response_url"] as? String ?? ""
}
}
+49
View File
@@ -0,0 +1,49 @@
//
// WebhookServer.swift
//
// Copyright © 2016 Peter Zignego. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
open class WebhookServer: Server {
public init(token: String, route: String, response: Response) {
super.init(token: token)
addRoute(route, response: response)
}
open func addRoute(_ route: String, response: Response) {
http["/\(route)"] = { request in
let webhookRequest = WebhookRequest(request: self.dictionaryFromRequest(request.body))
if webhookRequest.token == self.token {
return self.request(webhookRequest, reply: self.replyForResponse(response))
} else {
return .badRequest(.text("Bad request."))
}
}
}
private func replyForResponse(_ response: Response) -> Reply {
if response.attachments == nil && response.responseType == nil {
return Reply.text(body: response.text)
} else {
return Reply.json(response: response)
}
}
}
+28
View File
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>3.1.5</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2016 Peter Zignego. All rights reserved.</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
+28
View File
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>3.1.5</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2016 Peter Zignego. All rights reserved.</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0.1</string>
<string>3.1.5</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>