Compare commits

..

9 Commits

Author SHA1 Message Date
Peter Zignego b2be8d0170 Merge pull request #24 from pvzig/1.0.1
v1.0.1
2016-04-09 11:40:17 -04:00
Peter Zignego 45be1b7a3f Bump version number 2016-04-09 11:33:22 -04:00
Peter Zignego 09aa72d43e Update readme to include explanation of Leaderboard example 2016-04-09 11:24:47 -04:00
Peter Zignego bf4b55bbd6 Add leaderboard bot example 2016-04-09 11:02:30 -04:00
Peter Zignego a82279fad1 Code cleanup and improvement 2016-04-04 23:49:25 -04:00
Peter Zignego 500e489d5d Add AttachmentField type and AttachmentColor enum 2016-04-04 21:26:09 -04:00
Peter Zignego 874f4f51e1 Fix send message optional parameter handling 2016-04-03 21:04:49 -04:00
Peter Zignego 654f419f4e Support for rtm.start parameters 2016-04-03 15:45:53 -04:00
Peter Zignego a7c25fe33b Version bump 2016-03-22 21:55:26 -04:00
12 changed files with 335 additions and 119 deletions
+23 -19
View File
@@ -1,40 +1,44 @@
//
// AppDelegate.swift
// OSX-Sample
// AppDelegate.swift
// OSX-Sample
//
// Created by Peter Zignego on 2/18/16.
// Copyright © 2016 Launch Software LLC. All rights reserved.
// 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 Cocoa
import SlackKit
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate, SlackEventsDelegate {
class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet weak var window: NSWindow!
let client = Client(apiToken: "")
let learderboard = Leaderboard(token: "SLACK_AUTH_TOKEN")
func applicationDidFinishLaunching(aNotification: NSNotification) {
client.connect()
client.slackEventsDelegate = self
learderboard.client.connect()
}
func applicationWillTerminate(aNotification: NSNotification) {
// Insert code here to tear down your application
}
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) {}
}
+160
View File
@@ -0,0 +1,160 @@
//
// Leaderboard.swift
// OSX-Sample
//
// 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 SlackKit
import Foundation
class Leaderboard: MessageEventsDelegate {
var leaderboard: [String: Int] = [String: Int]()
let atSet = NSCharacterSet(charactersInString: "@")
let client: Client
init(token: String) {
client = Client(apiToken: token)
client.messageEventsDelegate = self
}
enum Command: String {
case Leaderboard = "leaderboard"
}
enum Trigger: String {
case PlusPlus = "++"
case MinusMinus = "--"
}
// MARK: MessageEventsDelegate
func messageReceived(message: Message) {
listen(message)
}
func messageSent(message: Message){}
func messageChanged(message: Message){}
func messageDeleted(message: Message?){}
// MARK: Leaderboard Internal Logic
private func listen(message: Message) {
if let id = client.authenticatedUser?.id, text = message.text {
if text.lowercaseString.containsString(Command.Leaderboard.rawValue) && text.containsString(id) == true {
handleCommand(.Leaderboard, channel: message.channel)
}
}
if message.text?.containsString(Trigger.PlusPlus.rawValue) == true {
handleMessageWithTrigger(message, trigger: .PlusPlus)
}
if message.text?.containsString(Trigger.MinusMinus.rawValue) == true {
handleMessageWithTrigger(message, trigger: .MinusMinus)
}
}
private func handleMessageWithTrigger(message: Message, trigger: Trigger) {
if let text = message.text,
end = text.rangeOfString(trigger.rawValue)?.startIndex.predecessor(),
start = text.rangeOfCharacterFromSet(atSet, options: .BackwardsSearch, range: text.startIndex..<end)?.startIndex {
let string = text.substringWithRange(start...end)
let users = client.users.values.filter{$0.id == self.userID(string)}
if users.count > 0 {
let idString = userID(string)
initalizationForValue(&leaderboard, value: idString)
scoringForValue(&leaderboard, value: idString, trigger: trigger)
} else {
initalizationForValue(&leaderboard, value: string)
scoringForValue(&leaderboard, value: string, trigger: trigger)
}
}
}
private func handleCommand(command: Command, channel:String?) {
switch command {
case .Leaderboard:
if let id = channel {
client.webAPI.sendMessage(id, text: "", linkNames: true, attachments: [constructLeaderboardAttachment()], success: {(response) in
}, failure: { (error) in
print("Leaderboard failed to post due to error:\(error)")
})
}
}
}
private func initalizationForValue(inout dictionary: [String: Int], value: String) {
if dictionary[value] == nil {
dictionary[value] = 0
}
}
private func scoringForValue(inout dictionary: [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(topItems(&leaderboard)), short: true)
let 💩 = AttachmentField(title: "💩", value: swapIDsForNames(bottomItems(&leaderboard)), short: true)
return Attachment(fallback: "Leaderboard", title: "Leaderboard", colorHex: AttachmentColor.Good.rawValue, text: "", fields: [💯, 💩])
}
private func topItems(inout dictionary: [String: Int]) -> String {
let sortedKeys = Array(dictionary.keys).sort({dictionary[$0] > dictionary[$1]}).filter({dictionary[$0] > 0})
let sortedValues = Array(dictionary.values).sort({$0 > $1}).filter({$0 > 0})
return leaderboardString(sortedKeys, values: sortedValues)
}
private func bottomItems(inout dictionary: [String: Int]) -> String {
let sortedKeys = Array(dictionary.keys).sort({dictionary[$0] < dictionary[$1]}).filter({dictionary[$0] < 0})
let sortedValues = Array(dictionary.values).sort({$0 < $1}).filter({$0 < 0})
return leaderboardString(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 {
returnString = returnString.stringByReplacingOccurrencesOfString(key, withString: "@"+name, options: NSStringCompareOptions.LiteralSearch, range: returnString.startIndex..<returnString.endIndex)
}
}
return returnString
}
private func userID(string: String) -> String {
return string.stringByTrimmingCharactersInSet(NSCharacterSet.alphanumericCharacterSet().invertedSet)
}
}
+13 -2
View File
@@ -12,7 +12,7 @@ import PackageDescription
let package = Package(
dependencies: [
.Package(url: "https://github.com/pvzig/SlackKit.git", majorVersion: 0)
.Package(url: "https://github.com/pvzig/SlackKit.git", majorVersion: 1)
]
)
```
@@ -40,7 +40,6 @@ To use SlackKit you'll need a bearer token which identifies a single user. You c
Once you have a token, initialize a client instance using it:
```swift
let client = Client(apiToken: "YOUR_SLACK_API_TOKEN")
```
If you want to receive messages from the Slack RTM API, connect to it.
@@ -217,6 +216,18 @@ func subteamSelfAdded(subteamID: String)
func subteamSelfRemoved(subteamID: String)
```
###Examples
####Leaderboard
Included in the OSX-Sample is an example application of a bot you might make using SlackKit. Its a basic leaderboard scoring bot, in the spirit of [PlusPlus](https://plusplus.chat).
To configure it, enter your bots API token in `AppDelegate.swift` for the Leaderboard bot:
```swift
let learderboard = Leaderboard(token: "SLACK_AUTH_TOKEN")
```
It adds a point for every `@thing++`, subtracts a point for every `@thing--`, and shows a leaderboard when asked `@botname leaderboard`.
###Get In Touch
[@pvzig](https://twitter.com/pvzig)
+1 -1
View File
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "SlackKit"
s.version = "0.9.9"
s.version = "1.0.1"
s.summary = "a Slack client library for iOS and OS X written in Swift"
s.homepage = "https://github.com/pvzig/SlackKit"
s.license = 'MIT'
+4
View File
@@ -28,6 +28,7 @@
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 */; };
26F4BAC31C9DEBD1000910BA /* Leaderboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26F4BAC21C9DEBD1000910BA /* Leaderboard.swift */; };
FFE3AC870D1C42EF276CCA2D /* Pods_SlackKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 407A2ABFC0611867E2BE34D0 /* Pods_SlackKit.framework */; };
/* End PBXBuildFile section */
@@ -58,6 +59,7 @@
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>"; };
26F4BAC21C9DEBD1000910BA /* Leaderboard.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Leaderboard.swift; sourceTree = "<group>"; };
407A2ABFC0611867E2BE34D0 /* Pods_SlackKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SlackKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
4347F92F3932C96C23B10B2A /* Pods-SlackKit.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SlackKit.release.xcconfig"; path = "Pods/Target Support Files/Pods-SlackKit/Pods-SlackKit.release.xcconfig"; sourceTree = "<group>"; };
F59B6A12F1C4C4E24C58E1BF /* Pods-SlackKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SlackKit.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SlackKit/Pods-SlackKit.debug.xcconfig"; sourceTree = "<group>"; };
@@ -95,6 +97,7 @@
isa = PBXGroup;
children = (
2601D6261C7688610012BF22 /* AppDelegate.swift */,
26F4BAC21C9DEBD1000910BA /* Leaderboard.swift */,
2601D6281C7688610012BF22 /* Assets.xcassets */,
2601D62A1C7688610012BF22 /* MainMenu.xib */,
2601D62D1C7688610012BF22 /* Info.plist */,
@@ -302,6 +305,7 @@
buildActionMask = 2147483647;
files = (
2601D6271C7688610012BF22 /* AppDelegate.swift in Sources */,
26F4BAC31C9DEBD1000910BA /* Leaderboard.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
+1 -1
View File
@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>0.9.9</string>
<string>1.0.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
+44 -4
View File
@@ -34,7 +34,7 @@ public struct Attachment {
public let title: String?
public let titleLink: String?
public let text: String?
public let fields: [[String: AnyObject]]?
public let fields: [AttachmentField]?
public let imageURL: String?
public let thumbURL: String?
@@ -48,12 +48,14 @@ public struct Attachment {
title = attachment?["title"] as? String
titleLink = attachment?["title_link"] as? String
text = attachment?["text"] as? String
fields = attachment?["fields"] as? [[String: AnyObject]]
imageURL = attachment?["image_url"] as? String
thumbURL = attachment?["thumb_url"] as? String
fields = (attachment?["fields"] as? [[String: AnyObject]])?.objectArrayFromDictionaryArray({(field) -> AttachmentField? in
return AttachmentField(field: field)
})
}
public init?(fallback: String, title:String, colorHex: String? = nil, pretext: String? = nil, authorName: String? = nil, authorLink: String? = nil, authorIcon: String? = nil, titleLink: String? = nil, text: String? = nil, fields: [[String: AnyObject]]? = nil, imageURL: String? = nil, thumbURL: String? = nil) {
public init?(fallback: String, title:String, colorHex: String? = nil, pretext: String? = nil, authorName: String? = nil, authorLink: String? = nil, authorIcon: String? = nil, titleLink: String? = nil, text: String? = nil, fields: [AttachmentField]? = nil, imageURL: String? = nil, thumbURL: String? = nil) {
self.fallback = fallback
self.color = colorHex
self.pretext = pretext
@@ -79,10 +81,48 @@ public struct Attachment {
attachment["title"] = title
attachment["title_link"] = titleLink
attachment["text"] = text
attachment["fields"] = fields
attachment["fields"] = fieldJSONArray(fields)
attachment["image_url"] = imageURL
attachment["thumb_url"] = thumbURL
return attachment
}
private func fieldJSONArray(fields: [AttachmentField]?) -> [[String: AnyObject]] {
var returnValue = [[String: AnyObject]]()
if let f = fields {
for field in f {
returnValue.append(field.dictionary())
}
}
return returnValue
}
}
public struct AttachmentField {
public let title: String?
public let value: String?
public let short: Bool?
internal init?(field: [String: AnyObject]?) {
title = field?["title"] as? String
value = field?["value"] as? String
short = field?["short"] as? Bool
}
public init(title:String, value:String, short: Bool? = nil) {
self.title = title
self.value = value.slackFormatEscaping()
self.short = short
}
internal func dictionary() -> [String: AnyObject] {
var field = [String: AnyObject]()
field["title"] = title
field["value"] = value
field["short"] = short
return field
}
}
+6 -1
View File
@@ -66,11 +66,16 @@ public struct Channel {
purpose = Topic(topic: channel?["purpose"] as? [String: AnyObject])
isMember = channel?["is_member"] as? Bool
lastRead = channel?["last_read"] as? String
latest = Message(message: channel?["latest"] as? [String: AnyObject])
unread = channel?["unread_count"] as? Int
unreadCountDisplay = channel?["unread_count_display"] as? Int
hasPins = channel?["has_pins"] as? Bool
members = channel?["members"] as? [String]
if (Message(message: channel?["latest"] as? [String: AnyObject])?.ts == nil) {
latest = Message(ts: channel?["latest"] as? String)
} else {
latest = Message(message: channel?["latest"] as? [String: AnyObject])
}
}
internal init?(id:String?) {
+31 -56
View File
@@ -78,12 +78,12 @@ public class Client: WebSocketDelegate {
self.token = apiToken
}
public func connect(pingInterval pingInterval: NSTimeInterval? = nil, timeout: NSTimeInterval? = nil, reconnect: Bool? = nil) {
public func connect(simpleLatest simpleLatest: Bool? = nil, noUnreads: Bool? = nil, mpimAware: Bool? = nil, pingInterval: NSTimeInterval? = nil, timeout: NSTimeInterval? = nil, reconnect: Bool? = nil) {
self.pingInterval = pingInterval
self.timeout = timeout
self.reconnect = reconnect
dispatcher = EventDispatcher(client: self)
webAPI.rtmStart(success: {
webAPI.rtmStart(simpleLatest, noUnreads: noUnreads, mpimAware: mpimAware, success: {
(response) -> Void in
self.initialSetup(response)
if let socketURL = response["url"] as? String {
@@ -99,7 +99,7 @@ public class Client: WebSocketDelegate {
webSocket?.disconnect()
}
//MARK: - Message send
//MARK: - RTM Message send
public func sendMessage(message: String, channelID: String) {
if (connected) {
if let data = formatMessageToSlackJsonString(msg: message, channel: channelID) {
@@ -183,74 +183,38 @@ public class Client: WebSocketDelegate {
}
//MARK: - Client setup
internal func initialSetup(json: [String: AnyObject]) {
private func initialSetup(json: [String: AnyObject]) {
team = Team(team: json["team"] as? [String: AnyObject])
authenticatedUser = User(user: json["self"] as? [String: AnyObject])
authenticatedUser?.doNotDisturbStatus = DoNotDisturbStatus(status: json["dnd"] as? [String: AnyObject])
enumerateUsers(json["users"] as? Array)
enumerateChannels(json["channels"] as? Array)
enumerateGroups(json["groups"] as? Array)
enumerateMPIMs(json["mpims"] as? Array)
enumerateIMs(json["ims"] as? Array)
enumerateBots(json["bots"] as? Array)
enumerateObjects(json["users"] as? Array) { (user) in self.addUser(user) }
enumerateObjects(json["channels"] as? Array) { (channel) in self.addChannel(channel) }
enumerateObjects(json["groups"] as? Array) { (group) in self.addChannel(group) }
enumerateObjects(json["mpims"] as? Array) { (mpim) in self.addChannel(mpim) }
enumerateObjects(json["ims"] as? Array) { (ims) in self.addChannel(ims) }
enumerateObjects(json["bots"] as? Array) { (bots) in self.addBot(bots) }
enumerateSubteams(json["subteams"] as? [String: AnyObject])
}
internal func enumerateUsers(users: [AnyObject]?) {
if let users = users {
for user in users {
let u = User(user: user as? [String: AnyObject])
self.users[u!.id!] = u
}
private func addUser(aUser: [String: AnyObject]) {
if let user = User(user: aUser), id = user.id {
users[id] = user
}
}
internal func enumerateChannels(channels: [AnyObject]?) {
if let channels = channels {
for channel in channels {
let c = Channel(channel: channel as? [String: AnyObject])
self.channels[c!.id!] = c
}
private func addChannel(aChannel: [String: AnyObject]) {
if let channel = Channel(channel: aChannel), id = channel.id {
channels[id] = channel
}
}
internal func enumerateGroups(groups: [AnyObject]?) {
if let groups = groups {
for group in groups {
let g = Channel(channel: group as? [String: AnyObject])
self.channels[g!.id!] = g
}
private func addBot(aBot: [String: AnyObject]) {
if let bot = Bot(bot: aBot), id = bot.id {
bots[id] = bot
}
}
internal func enumerateIMs(ims: [AnyObject]?) {
if let ims = ims {
for im in ims {
let i = Channel(channel: im as? [String: AnyObject])
self.channels[i!.id!] = i
}
}
}
internal func enumerateMPIMs(mpims: [AnyObject]?) {
if let mpims = mpims {
for mpim in mpims {
let m = Channel(channel: mpim as? [String: AnyObject])
self.channels[m!.id!] = m
}
}
}
internal func enumerateBots(bots: [AnyObject]?) {
if let bots = bots {
for bot in bots {
let b = Bot(bot: bot as? [String: AnyObject])
self.bots[b!.id!] = b
}
}
}
internal func enumerateSubteams(subteams: [String: AnyObject]?) {
private func enumerateSubteams(subteams: [String: AnyObject]?) {
if let subteams = subteams {
if let all = subteams["all"] as? [[String: AnyObject]] {
for item in all {
@@ -267,6 +231,17 @@ public class Client: WebSocketDelegate {
}
}
// MARK: - Utilities
private func enumerateObjects(array: [AnyObject]?, initalizer: ([String: AnyObject])-> Void) {
if let array = array {
for object in array {
if let dictionary = object as? [String: AnyObject] {
initalizer(dictionary)
}
}
}
}
// MARK: - WebSocketDelegate
public func websocketDidConnect(socket: WebSocket) {
if let pingInterval = pingInterval {
+28 -9
View File
@@ -46,14 +46,25 @@ extension Client {
//MARK: - Utilities
internal func stripString(string: String) -> String? {
var strippedString: String?
if string[string.startIndex] == "@" {
strippedString = string.substringFromIndex(string.startIndex.advancedBy(1))
} else if string[string.startIndex] == "#" {
var strippedString = string
if string[string.startIndex] == "@" || string[string.startIndex] == "#" {
strippedString = string.substringFromIndex(string.startIndex.advancedBy(1))
}
return strippedString
}
}
public enum AttachmentColor: String {
case Good = "good"
case Warning = "warning"
case Danger = "danger"
}
public extension NSDate {
func slackTimestamp() -> Double {
return NSNumber(double: timeIntervalSince1970).doubleValue
}
}
@@ -68,10 +79,18 @@ internal extension String {
}
public extension NSDate {
func slackTimestamp() -> Double {
return NSNumber(double: timeIntervalSince1970).doubleValue
}
internal extension Array {
func objectArrayFromDictionaryArray<T>(intializer:([String: AnyObject])->T?) -> [T] {
var returnValue = [T]()
for object in self {
if let dictionary = object as? [String: AnyObject] {
if let value = intializer(dictionary) {
returnValue.append(value)
}
}
}
return returnValue
}
}
+19 -22
View File
@@ -21,13 +21,6 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
public enum ItemType: String {
case ChannelMessage = "C"
case PrivateGroupMessage = "G"
case File = "F"
case FileComments = "Fc"
}
public class Message {
public let type = "message"
@@ -53,7 +46,7 @@ public class Message {
public let comment: Comment?
public let file: File?
internal(set) public var reactions = [String: Reaction]()
internal(set) public var attachments: [Attachment] = []
internal(set) public var attachments: [Attachment]?
public init?(message: [String: AnyObject]?) {
subtype = message?["subtype"] as? String
@@ -78,7 +71,24 @@ public class Message {
comment = Comment(comment: message?["comment"] as? [String: AnyObject])
file = File(file: message?["file"] as? [String: AnyObject])
reactions = messageReactions(message?["reactions"] as? [[String: AnyObject]])
attachments = messageAttachments(message?["attachments"] as? [[String: AnyObject]])
attachments = (message?["attachments"] as? [[String: AnyObject]])?.objectArrayFromDictionaryArray({(attachment) -> Attachment? in
return Attachment(attachment: attachment)
})
}
internal init?(ts:String?) {
self.ts = ts
subtype = nil
user = nil
channel = nil
botID = nil
username = nil
icons = nil
deletedTs = nil
upload = nil
itemType = nil
comment = nil
file = nil
}
private func messageReactions(reactions: [[String: AnyObject]]?) -> [String: Reaction] {
@@ -92,19 +102,6 @@ public class Message {
}
return returnValue
}
private func messageAttachments(attachments: [[String: AnyObject]]?) -> [Attachment] {
var returnValue:[Attachment] = []
if let a = attachments {
for attachment in a {
if let attachment = Attachment(attachment: attachment) {
returnValue.append(attachment)
}
}
}
return returnValue
}
}
extension Message: Equatable {}
+5 -4
View File
@@ -110,8 +110,9 @@ public class SlackWebAPI {
}
//MARK: - RTM
public func rtmStart(success success: ((response: [String: AnyObject])->Void)?, failure: FailureClosure?) {
client.api.request(.RTMStart, token: client.token, parameters: nil, successClosure: {
public func rtmStart(simpleLatest: Bool? = nil, noUnreads: Bool? = nil, mpimAware: Bool? = nil, success: ((response: [String: AnyObject])->Void)?, failure: FailureClosure?) {
let parameters: [String: AnyObject?] = ["simple_latest": simpleLatest, "no_unreads": noUnreads, "mpim_aware": mpimAware]
client.api.request(.RTMStart, token: client.token, parameters: filterNilParameters(parameters), successClosure: {
(response) -> Void in
success?(response: response)
}) {(error) -> Void in
@@ -194,8 +195,8 @@ public class SlackWebAPI {
}
}
public func sendMessage(channel: String, text: String, username: String? = nil, asUser: Bool = false, parse: ParseMode = .Full, linkNames: Bool = false, attachments: [Attachment?]? = nil, unfurlLinks: Bool = false, unfurlMedia: Bool = false, iconURL: String? = nil, iconEmoji: String? = nil, success: (((ts: String?, channel: String?))->Void)?, failure: FailureClosure?) {
let parameters: [String: AnyObject?] = ["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]
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: AnyObject?] = ["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]
client.api.request(.ChatPostMessage, token: client.token, parameters: filterNilParameters(parameters), successClosure: {
(response) -> Void in
success?((ts: response["ts"] as? String, response["channel"] as? String))