911 lines
25 KiB
Swift
Executable File
911 lines
25 KiB
Swift
Executable File
//
|
|
// Client.swift
|
|
//
|
|
// Copyright © 2017 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.
|
|
|
|
#if os(Linux)
|
|
import Dispatch
|
|
#endif
|
|
import Foundation
|
|
#if !COCOAPODS
|
|
@_exported import SKCore
|
|
#endif
|
|
|
|
open class Client {
|
|
internal(set) public var authenticatedUser: User?
|
|
internal(set) public var team: Team?
|
|
internal(set) public var channels = [String: Channel]()
|
|
internal(set) public var users = [String: User]()
|
|
internal(set) public var userGroups = [String: UserGroup]()
|
|
internal(set) public var bots = [String: Bot]()
|
|
internal(set) public var files = [String: File]()
|
|
internal(set) public var sentMessages = [String: Message]()
|
|
|
|
public init(){}
|
|
|
|
open func notificationForEvent(_ event: Event, type: EventType) {
|
|
switch type {
|
|
case .hello:
|
|
// Connection event
|
|
break
|
|
case .ok:
|
|
messageSent(event)
|
|
case .message:
|
|
if event.subtype != nil {
|
|
messageDispatcher(event)
|
|
} else {
|
|
messageReceived(event)
|
|
}
|
|
case .userTyping:
|
|
userTyping(event)
|
|
case .channelMarked, .imMarked, .groupMarked:
|
|
channelMarked(event)
|
|
case .channelCreated, .imCreated:
|
|
channelCreated(event)
|
|
case .channelJoined, .groupJoined:
|
|
channelJoined(event)
|
|
case .channelLeft, .groupLeft:
|
|
channelLeft(event)
|
|
case .channelDeleted:
|
|
channelDeleted(event)
|
|
case .channelRenamed, .groupRename:
|
|
channelRenamed(event)
|
|
case .channelArchive, .groupArchive:
|
|
channelArchived(event, archived: true)
|
|
case .channelUnarchive, .groupUnarchive:
|
|
channelArchived(event, archived: false)
|
|
case .channelHistoryChanged, .imHistoryChanged, .groupHistoryChanged:
|
|
channelHistoryChanged(event)
|
|
case .dndUpdated:
|
|
doNotDisturbUpdated(event)
|
|
case .dndUpatedUser:
|
|
doNotDisturbUserUpdated(event)
|
|
case .imOpen, .groupOpen:
|
|
open(event, open: true)
|
|
case .imClose, .groupClose:
|
|
open(event, open: false)
|
|
case .fileCreated:
|
|
processFile(event)
|
|
case .fileShared:
|
|
processFile(event)
|
|
case .fileUnshared:
|
|
processFile(event)
|
|
case .filePublic:
|
|
processFile(event)
|
|
case .filePrivate:
|
|
filePrivate(event)
|
|
case .fileChanged:
|
|
processFile(event)
|
|
case .fileDeleted:
|
|
deleteFile(event)
|
|
case .fileCommentAdded:
|
|
fileCommentAdded(event)
|
|
case .fileCommentEdited:
|
|
fileCommentEdited(event)
|
|
case .fileCommentDeleted:
|
|
fileCommentDeleted(event)
|
|
case .pinAdded:
|
|
pinAdded(event)
|
|
case .pinRemoved:
|
|
pinRemoved(event)
|
|
case .pong:
|
|
// Pong event
|
|
break
|
|
case .presenceChange:
|
|
presenceChange(event)
|
|
case .manualPresenceChange:
|
|
manualPresenceChange(event)
|
|
case .prefChange:
|
|
changePreference(event)
|
|
case .memberJoinedChannel:
|
|
memberJoinedChannel(event)
|
|
case .memberLeftChannel:
|
|
memberLeftChannel(event)
|
|
case .userChange:
|
|
userChange(event)
|
|
case .teamJoin:
|
|
teamJoin(event)
|
|
case .starAdded:
|
|
itemStarred(event, star: true)
|
|
case .starRemoved:
|
|
itemStarred(event, star: false)
|
|
case .reactionAdded:
|
|
addedReaction(event)
|
|
case .reactionRemoved:
|
|
removedReaction(event)
|
|
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.
|
|
// Until they are released other clients should ignore this event.
|
|
break
|
|
case .teamPlanChange:
|
|
teamPlanChange(event)
|
|
case .teamPrefChange:
|
|
teamPreferenceChange(event)
|
|
case .teamRename:
|
|
teamNameChange(event)
|
|
case .teamDomainChange:
|
|
teamDomainChange(event)
|
|
case .emailDomainChanged:
|
|
emailDomainChanged(event)
|
|
case .teamProfileChange:
|
|
teamProfileChange(event)
|
|
case .teamProfileDelete:
|
|
teamProfileDeleted(event)
|
|
case .teamProfileReorder:
|
|
teamProfileReordered(event)
|
|
case .botAdded:
|
|
bot(event)
|
|
case .botChanged:
|
|
bot(event)
|
|
case .accountsChanged:
|
|
// The accounts_changed event is used by our web client to maintain a list of logged-in accounts.
|
|
// Other clients should ignore this event.
|
|
break
|
|
case .teamMigrationStarted:
|
|
// Team migration event
|
|
break
|
|
case .reconnectURL:
|
|
// The reconnect_url event is currently unsupported and experimental.
|
|
break
|
|
case .subteamCreated, .subteamUpdated:
|
|
subteam(event)
|
|
case .subteamSelfAdded:
|
|
subteamAddedSelf(event)
|
|
case .subteamSelfRemoved:
|
|
subteamRemovedSelf(event)
|
|
case .error:
|
|
// Error event
|
|
break
|
|
case .goodbye:
|
|
// Goodbye event
|
|
break
|
|
case .unknown:
|
|
// Unsupported event
|
|
break
|
|
@unknown default:
|
|
// Unsupported event
|
|
break
|
|
}
|
|
}
|
|
|
|
// MARK: - Client setup
|
|
open func initialSetup(JSON: [String: Any]) {
|
|
team = Team(team: JSON["team"] as? [String: Any])
|
|
authenticatedUser = User(user: JSON["self"] as? [String: Any])
|
|
authenticatedUser?.doNotDisturbStatus = DoNotDisturbStatus(status: JSON["dnd"] as? [String: Any])
|
|
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: Any])
|
|
}
|
|
|
|
private func messageDispatcher(_ event: Event) {
|
|
guard let value = event.subtype, let subtype = MessageSubtype(rawValue:value) else {
|
|
return
|
|
}
|
|
switch subtype {
|
|
case .messageChanged:
|
|
messageChanged(event)
|
|
case .messageDeleted:
|
|
messageDeleted(event)
|
|
default:
|
|
messageReceived(event)
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Messages
|
|
extension Client {
|
|
func messageSent(_ event: Event) {
|
|
guard
|
|
let reply = event.replyTo,
|
|
let message = sentMessages[NSNumber(value: reply).stringValue],
|
|
let channel = message.channel,
|
|
let ts = message.ts
|
|
else {
|
|
return
|
|
}
|
|
message.ts = event.ts
|
|
message.text = event.text
|
|
channels[channel]?.messages[ts] = message
|
|
}
|
|
|
|
func messageReceived(_ event: Event) {
|
|
guard
|
|
let channel = event.channel,
|
|
let message = event.message,
|
|
let id = channel.id,
|
|
let ts = message.ts
|
|
else {
|
|
return
|
|
}
|
|
channels[id]?.messages[ts] = message
|
|
}
|
|
|
|
func messageChanged(_ event: Event) {
|
|
guard
|
|
let id = event.channel?.id,
|
|
let nested = event.nestedMessage,
|
|
let ts = nested.ts
|
|
else {
|
|
return
|
|
}
|
|
channels[id]?.messages[ts] = nested
|
|
}
|
|
|
|
func messageDeleted(_ event: Event) {
|
|
guard
|
|
let id = event.channel?.id,
|
|
let key = event.message?.deletedTs
|
|
else {
|
|
return
|
|
}
|
|
_ = channels[id]?.messages.removeValue(forKey: key)
|
|
}
|
|
}
|
|
|
|
// MARK: - Channels
|
|
extension Client {
|
|
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
|
|
}
|
|
channels[channelID]?.usersTyping.append(userID)
|
|
|
|
let timeout = DispatchTime.now() + Double(Int64(5.0 * Double(UInt64.nanosecondsPerSecond))) / Double(UInt64.nanosecondsPerSecond)
|
|
DispatchQueue.main.asyncAfter(deadline: timeout, execute: {
|
|
if let index = self.channels[channelID]?.usersTyping.firstIndex(of: userID) {
|
|
self.channels[channelID]?.usersTyping.remove(at: index)
|
|
}
|
|
})
|
|
}
|
|
|
|
func channelMarked(_ event: Event) {
|
|
guard
|
|
let channel = event.channel,
|
|
let id = channel.id
|
|
else {
|
|
return
|
|
}
|
|
channels[id]?.lastRead = event.ts
|
|
}
|
|
|
|
func channelCreated(_ event: Event) {
|
|
guard
|
|
let channel = event.channel,
|
|
let id = channel.id
|
|
else {
|
|
return
|
|
}
|
|
channels[id] = channel
|
|
}
|
|
|
|
func channelDeleted(_ event: Event) {
|
|
guard
|
|
let channel = event.channel,
|
|
let id = channel.id
|
|
else {
|
|
return
|
|
}
|
|
channels.removeValue(forKey: id)
|
|
}
|
|
|
|
func channelJoined(_ event: Event) {
|
|
guard
|
|
let channel = event.channel,
|
|
let id = channel.id
|
|
else {
|
|
return
|
|
}
|
|
channels[id] = event.channel
|
|
}
|
|
|
|
func channelLeft(_ event: Event) {
|
|
guard
|
|
let channel = event.channel,
|
|
let id = channel.id
|
|
else {
|
|
return
|
|
}
|
|
|
|
if let userID = authenticatedUser?.id, let index = channels[id]?.members?.firstIndex(of: userID) {
|
|
channels[id]?.members?.remove(at: index)
|
|
}
|
|
}
|
|
|
|
func channelRenamed(_ event: Event) {
|
|
guard
|
|
let channel = event.channel,
|
|
let id = channel.id
|
|
else {
|
|
return
|
|
}
|
|
channels[id]?.name = channel.name
|
|
}
|
|
|
|
func channelArchived(_ event: Event, archived: Bool) {
|
|
guard
|
|
let channel = event.channel,
|
|
let id = channel.id
|
|
else {
|
|
return
|
|
}
|
|
channels[id]?.isArchived = archived
|
|
}
|
|
|
|
func channelHistoryChanged(_ event: Event) {
|
|
|
|
}
|
|
|
|
func memberJoinedChannel(_ event: Event) {
|
|
guard
|
|
let channel = event.channel?.id,
|
|
let member = event.user?.id
|
|
else {
|
|
return
|
|
}
|
|
|
|
channels[channel]?.members?.append(member)
|
|
}
|
|
|
|
func memberLeftChannel(_ event: Event) {
|
|
guard
|
|
let channel = event.channel?.id,
|
|
let member = event.user?.id
|
|
else {
|
|
return
|
|
}
|
|
|
|
if let index = channels[channel]?.members?.firstIndex(of: member) {
|
|
channels[channel]?.members?.remove(at: index)
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Do Not Disturb
|
|
extension Client {
|
|
func doNotDisturbUpdated(_ event: Event) {
|
|
guard let dndStatus = event.dndStatus else {
|
|
return
|
|
}
|
|
authenticatedUser?.doNotDisturbStatus = dndStatus
|
|
}
|
|
|
|
func doNotDisturbUserUpdated(_ event: Event) {
|
|
guard
|
|
let dndStatus = event.dndStatus,
|
|
let user = event.user,
|
|
let id = user.id
|
|
else {
|
|
return
|
|
}
|
|
users[id]?.doNotDisturbStatus = dndStatus
|
|
}
|
|
}
|
|
|
|
// MARK: - IM & Group Open/Close
|
|
extension Client {
|
|
func open(_ event: Event, open: Bool) {
|
|
guard
|
|
let channel = event.channel,
|
|
let id = channel.id
|
|
else {
|
|
return
|
|
}
|
|
channels[id]?.isOpen = open
|
|
}
|
|
}
|
|
|
|
// MARK: - Files
|
|
extension Client {
|
|
func processFile(_ event: Event) {
|
|
for file in event.files {
|
|
guard
|
|
let id = file.id
|
|
else {
|
|
continue
|
|
}
|
|
if let comment = file.initialComment, let commentID = comment.id {
|
|
if files[id]?.comments[commentID] == nil {
|
|
files[id]?.comments[commentID] = comment
|
|
}
|
|
}
|
|
files[id] = file
|
|
}
|
|
}
|
|
|
|
func filePrivate(_ event: Event) {
|
|
for file in event.files {
|
|
guard
|
|
let id = file.id
|
|
else {
|
|
continue
|
|
}
|
|
files[id]?.isPublic = false
|
|
}
|
|
}
|
|
|
|
func deleteFile(_ event: Event) {
|
|
for file in event.files {
|
|
guard
|
|
let id = file.id
|
|
else {
|
|
continue
|
|
}
|
|
if files[id] != nil {
|
|
files.removeValue(forKey: id)
|
|
}
|
|
}
|
|
}
|
|
|
|
func fileCommentAdded(_ event: Event) {
|
|
for file in event.files {
|
|
guard
|
|
let id = file.id,
|
|
let comment = event.comment,
|
|
let commentID = comment.id
|
|
else {
|
|
continue
|
|
}
|
|
files[id]?.comments[commentID] = comment
|
|
}
|
|
}
|
|
|
|
func fileCommentEdited(_ event: Event) {
|
|
for file in event.files {
|
|
guard
|
|
let id = file.id,
|
|
let comment = event.comment,
|
|
let commentID = comment.id
|
|
else {
|
|
continue
|
|
}
|
|
files[id]?.comments[commentID]?.comment = comment.comment
|
|
}
|
|
}
|
|
|
|
func fileCommentDeleted(_ event: Event) {
|
|
for file in event.files {
|
|
guard
|
|
let id = file.id,
|
|
let comment = event.comment,
|
|
let commentID = comment.id
|
|
else {
|
|
continue
|
|
}
|
|
_ = files[id]?.comments.removeValue(forKey: commentID)
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Pins
|
|
extension Client {
|
|
func pinAdded(_ event: Event) {
|
|
guard
|
|
let id = event.channelID,
|
|
let item = event.item
|
|
else {
|
|
return
|
|
}
|
|
channels[id]?.pinnedItems.append(item)
|
|
}
|
|
|
|
func pinRemoved(_ event: Event) {
|
|
guard
|
|
let id = event.channelID,
|
|
let item = event.item
|
|
else {
|
|
return
|
|
}
|
|
if let pins = channels[id]?.pinnedItems.filter({$0 != item}) {
|
|
channels[id]?.pinnedItems = pins
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Stars
|
|
extension Client {
|
|
func itemStarred(_ event: Event, star: Bool) {
|
|
guard
|
|
let item = event.item,
|
|
let type = item.type
|
|
else {
|
|
return
|
|
}
|
|
switch type {
|
|
case "message":
|
|
starMessage(item, star: star)
|
|
case "file":
|
|
starFile(item, star: star)
|
|
case "file_comment":
|
|
starComment(item)
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
|
|
func starMessage(_ item: Item, star: Bool) {
|
|
guard
|
|
let message = item.message,
|
|
let ts = message.ts,
|
|
let channel = item.channel,
|
|
channels[channel]?.messages[ts] != nil
|
|
else {
|
|
return
|
|
}
|
|
channels[channel]?.messages[ts]?.isStarred = star
|
|
}
|
|
|
|
func starFile(_ item: Item, star: Bool) {
|
|
guard
|
|
let file = item.file,
|
|
let id = file.id
|
|
else {
|
|
return
|
|
}
|
|
files[id]?.isStarred = star
|
|
if let stars = files[id]?.stars {
|
|
if star == true {
|
|
files[id]?.stars = stars + 1
|
|
} else {
|
|
if stars > 0 {
|
|
files[id]?.stars = stars - 1
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func starComment(_ item: Item) {
|
|
guard
|
|
let file = item.file,
|
|
let id = file.id,
|
|
let comment = item.comment,
|
|
let commentID = comment.id
|
|
else {
|
|
return
|
|
}
|
|
files[id]?.comments[commentID] = comment
|
|
}
|
|
}
|
|
|
|
// MARK: - Reactions
|
|
extension Client {
|
|
func addedReaction(_ event: Event) {
|
|
guard
|
|
let item = event.item,
|
|
let type = item.type,
|
|
let reaction = event.reaction,
|
|
let userID = event.user?.id
|
|
else {
|
|
return
|
|
}
|
|
switch type {
|
|
case "message":
|
|
guard
|
|
let channel = item.channel,
|
|
let ts = item.ts,
|
|
let message = channels[channel]?.messages[ts]
|
|
else {
|
|
return
|
|
}
|
|
message.reactions.append(Reaction(name: reaction, user: userID))
|
|
case "file":
|
|
guard let id = item.file?.id else {
|
|
return
|
|
}
|
|
files[id]?.reactions.append(Reaction(name: reaction, user: userID))
|
|
case "file_comment":
|
|
guard
|
|
let id = item.file?.id,
|
|
let commentID = item.fileCommentID
|
|
else {
|
|
return
|
|
}
|
|
files[id]?.comments[commentID]?.reactions.append(Reaction(name: reaction, user: userID))
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
|
|
func removedReaction(_ event: Event) {
|
|
guard
|
|
let item = event.item,
|
|
let type = item.type,
|
|
let key = event.reaction,
|
|
let userID = event.user?.id
|
|
else {
|
|
return
|
|
}
|
|
switch type {
|
|
case "message":
|
|
guard
|
|
let channel = item.channel,
|
|
let ts = item.ts,
|
|
let message = channels[channel]?.messages[ts]
|
|
else {
|
|
return
|
|
}
|
|
message.reactions = message.reactions.filter({$0.name != key && $0.user != userID})
|
|
case "file":
|
|
guard
|
|
let itemFile = item.file,
|
|
let id = itemFile.id
|
|
else {
|
|
return
|
|
}
|
|
files[id]?.reactions = files[id]!.reactions.filter({$0.name != key && $0.user != userID})
|
|
case "file_comment":
|
|
guard
|
|
let id = item.file?.id,
|
|
let commentID = item.fileCommentID
|
|
else {
|
|
return
|
|
}
|
|
files[id]?.comments[commentID]?.reactions = files[id]!.comments[commentID]!.reactions.filter({$0.name != key && $0.user != userID})
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Preferences
|
|
extension Client {
|
|
func changePreference(_ event: Event) {
|
|
guard let name = event.name else {
|
|
return
|
|
}
|
|
authenticatedUser?.preferences?[name] = event.value
|
|
}
|
|
}
|
|
|
|
// MARK: - User Change
|
|
extension Client {
|
|
func userChange(_ event: Event) {
|
|
guard
|
|
let user = event.user,
|
|
let id = user.id
|
|
else {
|
|
return
|
|
}
|
|
let preferences = users[id]?.preferences
|
|
users[id] = user
|
|
users[id]?.preferences = preferences
|
|
}
|
|
}
|
|
|
|
// MARK: - User Presence
|
|
extension Client {
|
|
func presenceChange(_ event: Event) {
|
|
guard
|
|
let user = event.user,
|
|
let id = user.id
|
|
else {
|
|
return
|
|
}
|
|
users[id]?.presence = event.presence
|
|
}
|
|
}
|
|
|
|
// MARK: - Team
|
|
extension Client {
|
|
func teamJoin(_ event: Event) {
|
|
guard
|
|
let user = event.user,
|
|
let id = user.id
|
|
else {
|
|
return
|
|
}
|
|
users[id] = user
|
|
}
|
|
|
|
func teamPlanChange(_ event: Event) {
|
|
guard let plan = event.plan else {
|
|
return
|
|
}
|
|
team?.plan = plan
|
|
}
|
|
|
|
func teamPreferenceChange(_ event: Event) {
|
|
guard let name = event.name else {
|
|
return
|
|
}
|
|
team?.prefs?[name] = event.value
|
|
}
|
|
|
|
func teamNameChange(_ event: Event) {
|
|
guard let name = event.name else {
|
|
return
|
|
}
|
|
team?.name = name
|
|
}
|
|
|
|
func teamDomainChange(_ event: Event) {
|
|
guard let domain = event.domain else {
|
|
return
|
|
}
|
|
team?.domain = domain
|
|
}
|
|
|
|
func emailDomainChanged(_ event: Event) {
|
|
guard let domain = event.emailDomain else {
|
|
return
|
|
}
|
|
team?.emailDomain = domain
|
|
}
|
|
|
|
func emojiChanged(_ event: Event) {}
|
|
}
|
|
|
|
// MARK: - Bots
|
|
extension Client {
|
|
func bot(_ event: Event) {
|
|
guard
|
|
let bot = event.bot,
|
|
let id = bot.id
|
|
else {
|
|
return
|
|
}
|
|
bots[id] = bot
|
|
}
|
|
}
|
|
|
|
// MARK: - Subteams
|
|
extension Client {
|
|
func subteam(_ event: Event) {
|
|
guard
|
|
let subteam = event.subteam,
|
|
let id = subteam.id
|
|
else {
|
|
return
|
|
}
|
|
userGroups[id] = subteam
|
|
}
|
|
|
|
func subteamAddedSelf(_ event: Event) {
|
|
guard
|
|
let subteamID = event.subteamID,
|
|
authenticatedUser?.userGroups != nil
|
|
else {
|
|
return
|
|
}
|
|
authenticatedUser?.userGroups![subteamID] = subteamID
|
|
}
|
|
|
|
func subteamRemovedSelf(_ event: Event) {
|
|
guard let subteamID = event.subteamID else {
|
|
return
|
|
}
|
|
_ = authenticatedUser?.userGroups?.removeValue(forKey: subteamID)
|
|
}
|
|
}
|
|
|
|
// MARK: - Team Profiles
|
|
extension Client {
|
|
func teamProfileChange(_ event: Event) {
|
|
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])
|
|
}
|
|
}
|
|
}
|
|
|
|
func teamProfileDeleted(_ event: Event) {
|
|
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
|
|
}
|
|
}
|
|
}
|
|
|
|
func teamProfileReordered(_ event: Event) {
|
|
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
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Authenticated User
|
|
extension Client {
|
|
func manualPresenceChange(_ event: Event) {
|
|
guard let presence = event.presence else {
|
|
return
|
|
}
|
|
authenticatedUser?.presence = presence
|
|
}
|
|
}
|
|
|
|
// MARK: - Utilities
|
|
public extension Client {
|
|
fileprivate func addUser(_ aUser: [String: Any]) {
|
|
let user = User(user: aUser)
|
|
if let id = user.id {
|
|
users[id] = user
|
|
}
|
|
}
|
|
|
|
fileprivate func addChannel(_ aChannel: [String: Any]) {
|
|
let channel = Channel(channel: aChannel)
|
|
if let id = channel.id {
|
|
channels[id] = channel
|
|
}
|
|
}
|
|
|
|
fileprivate func addBot(_ aBot: [String: Any]) {
|
|
let bot = Bot(bot: aBot)
|
|
if let id = bot.id {
|
|
bots[id] = bot
|
|
}
|
|
}
|
|
|
|
fileprivate func enumerateSubteams(_ subteams: [String: Any]?) {
|
|
if let subteams = subteams {
|
|
if let all = subteams["all"] as? [[String: Any]] {
|
|
for item in all {
|
|
let u = UserGroup(userGroup: item)
|
|
if let id = u.id {
|
|
self.userGroups[id] = u
|
|
}
|
|
}
|
|
}
|
|
if let auth = subteams["self"] as? [String] {
|
|
for item in auth {
|
|
authenticatedUser?.userGroups = [String: String]()
|
|
authenticatedUser?.userGroups?[item] = item
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fileprivate func enumerateObjects(_ array: [Any]?, initalizer: ([String: Any]) -> Void) {
|
|
if let array = array {
|
|
for object in array {
|
|
if let dictionary = object as? [String: Any] {
|
|
initalizer(dictionary)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|