Skip to content
This repository was archived by the owner on Dec 2, 2022. It is now read-only.

Commit 9e93806

Browse files
committed
Merge pull request #10 from pvzig/web-api
Add bot accessible Slack Web API endpoints
2 parents e9fc66a + 572e363 commit 9e93806

File tree

11 files changed

+1261
-75
lines changed

11 files changed

+1261
-75
lines changed

README.md

Lines changed: 77 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
![SlackKit](https://cloud.githubusercontent.com/assets/8311605/10260893/5ec60f96-694e-11e5-91fd-da6845942201.png)
22
##iOS/OS X Slack Client Library
33
###Description
4-
This is a Slack client library for iOS and OS X written in Swift. It's intended to expose all of the functionality of Slack's [Real Time Messaging API](https://api.slack.com/rtm).
4+
This is a Slack client library for iOS and OS X 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).
55

66
###Installation
7-
####Swift Package Manager (Swift 2.2 and up)
7+
####Swift Package Manager
88
Add SlackKit to your Package.swift
99

1010
```swift
@@ -37,17 +37,88 @@ import SlackKit
3737
###Usage
3838
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).
3939

40-
Once you have a token, give it to the Client:
40+
Once you have a token, initialize a client instance using it:
4141
```swift
42-
Client.sharedInstance.setAuthToken("YOUR_SLACK_AUTH_TOKEN")
42+
let client = Client(apiToken: "YOUR_SLACK_API_TOKEN")
43+
4344
```
44-
and connect:
45+
46+
If you want to receive messages from the Slack RTM API, connect to it.
4547
```swift
46-
Client.sharedInstance.connect()
48+
client.connect()
4749
```
50+
4851
Once connected, the client will begin to consume any messages sent by the Slack RTM API.
4952

53+
####Web API Methods
54+
SlackKit currently supports the a subset of the Slack Web APIs that are available to bot users:
55+
56+
- api.test
57+
- auth.test
58+
- channels.history
59+
- channels.info
60+
- channels.list
61+
- channels.mark
62+
- channels.setPurpose
63+
- channels.setTopic
64+
- chat.delete
65+
- chat.postMessage
66+
- chat.update
67+
- emoji.list
68+
- files.delete
69+
- files.upload
70+
- groups.close
71+
- groups.history
72+
- groups.info
73+
- groups.list
74+
- groups.mark
75+
- groups.open
76+
- groups.setPurpose
77+
- groups.setTopic
78+
- im.close
79+
- im.history
80+
- im.list
81+
- im.mark
82+
- im.open
83+
- mpim.close
84+
- mpim.history
85+
- mpim.list
86+
- mpim.mark
87+
- mpim.open
88+
- pins.add
89+
- pins.list
90+
- pins.remove
91+
- reactions.add
92+
- reactions.get
93+
- reactions.list
94+
- reactions.remove
95+
- rtm.start
96+
- stars.add
97+
- stars.remove
98+
- team.info
99+
- users.getPresence
100+
- users.info
101+
- users.list
102+
- users.setActive
103+
- users.setPresence
104+
105+
They can be accessed through a Client object’s `webAPI` property:
106+
```swift
107+
client.webAPI.authenticationTest({
108+
(authenticated) -> Void in
109+
print(authenticated)
110+
}){(error) -> Void in
111+
print(error)
112+
}
113+
```
114+
50115
####Delegate methods
116+
117+
To receive delegate callbacks for certain events, register an object as the delegate for those events:
118+
```swift
119+
client.slackEventsDelegate = self
120+
```
121+
51122
There are a number of delegates that you can set to receive callbacks for certain events.
52123

53124
#####SlackEventsDelegate
@@ -138,18 +209,6 @@ func subteamSelfAdded(subteamID: String)
138209
func subteamSelfRemoved(subteamID: String)
139210
```
140211

141-
###Examples
142-
####Sending a Message:
143-
```swift
144-
Client.sharedInstance.sendMessage(message: "Hello, world!", channelID: "CHANNEL_ID")
145-
```
146-
147-
####Print a List of Users in a Channel:
148-
```swift
149-
let users = Client.sharedInstance.channels?["CHANNEL_ID"]?.members
150-
print(users)
151-
```
152-
153212
###Get In Touch
154213
[@pvzig](https://twitter.com/pvzig)
155214

SlackKit.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |s|
22
s.name = "SlackKit"
3-
s.version = "0.9.7"
3+
s.version = "0.9.6"
44
s.summary = "a Slack client library for iOS and OS X written in Swift"
55
s.homepage = "https://github.com/pvzig/SlackKit"
66
s.license = 'MIT'

SlackKit.xcodeproj/project.pbxproj

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
260EC2331C4DC61D0093B253 /* ClientExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 260EC2301C4DC61D0093B253 /* ClientExtensions.swift */; };
11+
260EC2341C4DC61D0093B253 /* NetworkInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 260EC2311C4DC61D0093B253 /* NetworkInterface.swift */; };
12+
260EC2351C4DC61D0093B253 /* SlackWebAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 260EC2321C4DC61D0093B253 /* SlackWebAPI.swift */; };
1013
26BBA1941C398E3C00BF7225 /* Bot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1871C398E3C00BF7225 /* Bot.swift */; };
1114
26BBA1951C398E3C00BF7225 /* Channel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1881C398E3C00BF7225 /* Channel.swift */; };
1215
26BBA1961C398E3C00BF7225 /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1891C398E3C00BF7225 /* Client.swift */; };
@@ -25,6 +28,9 @@
2528

2629
/* Begin PBXFileReference section */
2730
26072A341BB48B3A00CD650C /* SlackKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SlackKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
31+
260EC2301C4DC61D0093B253 /* ClientExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ClientExtensions.swift; path = Sources/ClientExtensions.swift; sourceTree = "<group>"; };
32+
260EC2311C4DC61D0093B253 /* NetworkInterface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NetworkInterface.swift; path = Sources/NetworkInterface.swift; sourceTree = "<group>"; };
33+
260EC2321C4DC61D0093B253 /* SlackWebAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SlackWebAPI.swift; path = Sources/SlackWebAPI.swift; sourceTree = "<group>"; };
2834
2661A6A41BBF62FF0026F67B /* SlackKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SlackKit.h; sourceTree = "<group>"; };
2935
266E05F01BBF780C00840D76 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
3036
26BBA1871C398E3C00BF7225 /* Bot.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Bot.swift; path = Sources/Bot.swift; sourceTree = "<group>"; };
@@ -90,16 +96,19 @@
9096
26BBA1871C398E3C00BF7225 /* Bot.swift */,
9197
26BBA1881C398E3C00BF7225 /* Channel.swift */,
9298
26BBA1891C398E3C00BF7225 /* Client.swift */,
99+
260EC2301C4DC61D0093B253 /* ClientExtensions.swift */,
93100
26BBA18A1C398E3C00BF7225 /* Event.swift */,
94101
26BBA18B1C398E3C00BF7225 /* EventDelegate.swift */,
95102
26BBA18C1C398E3C00BF7225 /* EventDispatcher.swift */,
96103
26BBA18D1C398E3C00BF7225 /* EventHandler.swift */,
97104
26BBA18E1C398E3C00BF7225 /* File.swift */,
98105
26BBA18F1C398E3C00BF7225 /* Message.swift */,
106+
260EC2311C4DC61D0093B253 /* NetworkInterface.swift */,
99107
26BBA1901C398E3C00BF7225 /* Team.swift */,
100108
26BBA1911C398E3C00BF7225 /* Types.swift */,
101109
26BBA1921C398E3C00BF7225 /* User.swift */,
102110
26BBA1931C398E3C00BF7225 /* UserGroup.swift */,
111+
260EC2321C4DC61D0093B253 /* SlackWebAPI.swift */,
103112
2661A6A41BBF62FF0026F67B /* SlackKit.h */,
104113
266E05F01BBF780C00840D76 /* Info.plist */,
105114
);
@@ -236,9 +245,12 @@
236245
26BBA1971C398E3C00BF7225 /* Event.swift in Sources */,
237246
26BBA1941C398E3C00BF7225 /* Bot.swift in Sources */,
238247
26BBA19B1C398E3C00BF7225 /* File.swift in Sources */,
248+
260EC2351C4DC61D0093B253 /* SlackWebAPI.swift in Sources */,
239249
26BBA19C1C398E3C00BF7225 /* Message.swift in Sources */,
240250
26BBA19D1C398E3C00BF7225 /* Team.swift in Sources */,
251+
260EC2331C4DC61D0093B253 /* ClientExtensions.swift in Sources */,
241252
26BBA1A01C398E3C00BF7225 /* UserGroup.swift in Sources */,
253+
260EC2341C4DC61D0093B253 /* NetworkInterface.swift in Sources */,
242254
26BBA1981C398E3C00BF7225 /* EventDelegate.swift in Sources */,
243255
);
244256
runOnlyForDeploymentPostprocessing = 0;

SlackKit/Sources/Client.swift

Lines changed: 33 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -50,50 +50,46 @@ public class Client: WebSocketDelegate {
5050
public var reactionEventsDelegate: ReactionEventsDelegate?
5151
public var teamEventsDelegate: TeamEventsDelegate?
5252
public var subteamEventsDelegate: SubteamEventsDelegate?
53+
54+
internal var token = "SLACK_AUTH_TOKEN"
5355

54-
private var token = "SLACK_AUTH_TOKEN"
5556
public func setAuthToken(token: String) {
5657
self.token = token
5758
}
5859

59-
private var webSocket: WebSocket?
60-
private var dispatcher: EventDispatcher?
61-
62-
required public init() {
60+
public var webAPI: SlackWebAPI {
61+
return SlackWebAPI(client: self)
6362
}
63+
64+
internal var webSocket: WebSocket?
65+
private var dispatcher: EventDispatcher?
66+
67+
internal let api = NetworkInterface()
6468

65-
public static let sharedInstance = Client()
69+
required public init(apiToken: String) {
70+
self.token = apiToken
71+
}
6672

67-
//MARK: - Connection
6873
public func connect() {
6974
dispatcher = EventDispatcher(client: self)
70-
let request = NSURLRequest(URL: NSURL(string:"https://slack.com/api/rtm.start?token="+token)!)
71-
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.currentQueue()!) {
72-
(response, data, error) -> Void in
73-
guard let data = data else {
74-
return
75+
webAPI.rtmStart(success: {
76+
(response) -> Void in
77+
self.initialSetup(response)
78+
if let socketURL = response["url"] as? String {
79+
let url = NSURL(string: socketURL)
80+
self.webSocket = WebSocket(url: url!)
81+
self.webSocket?.delegate = self
82+
self.webSocket?.connect()
7583
}
76-
do {
77-
let result = try NSJSONSerialization.JSONObjectWithData(data, options: []) as! [String: AnyObject]
78-
if (result["ok"] as! Bool == true) {
79-
self.initialSetup(result)
80-
let socketURL = NSURL(string: result["url"] as! String)
81-
self.webSocket = WebSocket(url: socketURL!)
82-
self.webSocket?.delegate = self
83-
self.webSocket?.connect()
84-
}
85-
} catch _ {
86-
print(error)
87-
}
88-
}
84+
}, failure:nil)
8985
}
9086

9187
//MARK: - Message send
9288
public func sendMessage(message: String, channelID: String) {
9389
if (connected) {
9490
if let data = formatMessageToSlackJsonString(msg: message, channel: channelID) {
9591
let string = NSString(data: data, encoding: NSUTF8StringEncoding)
96-
self.webSocket?.writeString(string as! String)
92+
webSocket?.writeString(string as! String)
9793
}
9894
}
9995
}
@@ -103,7 +99,7 @@ public class Client: WebSocketDelegate {
10399
"id": NSDate().timeIntervalSince1970,
104100
"type": "message",
105101
"channel": message.channel,
106-
"text": slackFormatEscaping(message.msg)
102+
"text": message.msg.slackFormatEscaping()
107103
]
108104
addSentMessage(json)
109105
do {
@@ -124,15 +120,8 @@ public class Client: WebSocketDelegate {
124120
sentMessages[ts!.stringValue] = Message(message: message)
125121
}
126122

127-
private func slackFormatEscaping(string: String) -> String {
128-
var escapedString = string.stringByReplacingOccurrencesOfString("&", withString: "&amp;")
129-
escapedString = escapedString.stringByReplacingOccurrencesOfString("<", withString: "&lt;")
130-
escapedString = escapedString.stringByReplacingOccurrencesOfString(">", withString: "&gt;")
131-
return escapedString
132-
}
133-
134123
//MARK: - Client setup
135-
private func initialSetup(json: [String: AnyObject]) {
124+
internal func initialSetup(json: [String: AnyObject]) {
136125
team = Team(team: json["team"] as? [String: AnyObject])
137126
authenticatedUser = User(user: json["self"] as? [String: AnyObject])
138127
authenticatedUser?.doNotDisturbStatus = DoNotDisturbStatus(status: json["dnd"] as? [String: AnyObject])
@@ -145,7 +134,7 @@ public class Client: WebSocketDelegate {
145134
enumerateSubteams(json["subteams"] as? [String: AnyObject])
146135
}
147136

148-
private func enumerateUsers(users: [AnyObject]?) {
137+
internal func enumerateUsers(users: [AnyObject]?) {
149138
if let users = users {
150139
for user in users {
151140
let u = User(user: user as? [String: AnyObject])
@@ -154,7 +143,7 @@ public class Client: WebSocketDelegate {
154143
}
155144
}
156145

157-
private func enumerateChannels(channels: [AnyObject]?) {
146+
internal func enumerateChannels(channels: [AnyObject]?) {
158147
if let channels = channels {
159148
for channel in channels {
160149
let c = Channel(channel: channel as? [String: AnyObject])
@@ -163,7 +152,7 @@ public class Client: WebSocketDelegate {
163152
}
164153
}
165154

166-
private func enumerateGroups(groups: [AnyObject]?) {
155+
internal func enumerateGroups(groups: [AnyObject]?) {
167156
if let groups = groups {
168157
for group in groups {
169158
let g = Channel(channel: group as? [String: AnyObject])
@@ -172,7 +161,7 @@ public class Client: WebSocketDelegate {
172161
}
173162
}
174163

175-
private func enumerateIMs(ims: [AnyObject]?) {
164+
internal func enumerateIMs(ims: [AnyObject]?) {
176165
if let ims = ims {
177166
for im in ims {
178167
let i = Channel(channel: im as? [String: AnyObject])
@@ -181,7 +170,7 @@ public class Client: WebSocketDelegate {
181170
}
182171
}
183172

184-
private func enumerateMPIMs(mpims: [AnyObject]?) {
173+
internal func enumerateMPIMs(mpims: [AnyObject]?) {
185174
if let mpims = mpims {
186175
for mpim in mpims {
187176
let m = Channel(channel: mpim as? [String: AnyObject])
@@ -190,7 +179,7 @@ public class Client: WebSocketDelegate {
190179
}
191180
}
192181

193-
private func enumerateBots(bots: [AnyObject]?) {
182+
internal func enumerateBots(bots: [AnyObject]?) {
194183
if let bots = bots {
195184
for bot in bots {
196185
let b = Bot(bot: bot as? [String: AnyObject])
@@ -199,7 +188,7 @@ public class Client: WebSocketDelegate {
199188
}
200189
}
201190

202-
private func enumerateSubteams(subteams: [String: AnyObject]?) {
191+
internal func enumerateSubteams(subteams: [String: AnyObject]?) {
203192
if let subteams = subteams {
204193
if let all = subteams["all"] as? [[String: AnyObject]] {
205194
for item in all {
@@ -217,8 +206,7 @@ public class Client: WebSocketDelegate {
217206
}
218207

219208
// MARK: - WebSocketDelegate
220-
public func websocketDidConnect(socket: WebSocket) {
221-
}
209+
public func websocketDidConnect(socket: WebSocket) {}
222210

223211
public func websocketDidDisconnect(socket: WebSocket, error: NSError?) {
224212
connected = false
@@ -241,7 +229,6 @@ public class Client: WebSocketDelegate {
241229
}
242230
}
243231

244-
public func websocketDidReceiveData(socket: WebSocket, data: NSData) {
245-
}
232+
public func websocketDidReceiveData(socket: WebSocket, data: NSData) {}
246233

247234
}

0 commit comments

Comments
 (0)