http://git-wip-us.apache.org/repos/asf/usergrid/blob/7442c881/sdks/swift/Samples/ActivityFeed/Pods/UsergridSDK/sdks/swift/Source/UsergridClient.swift ---------------------------------------------------------------------- diff --git a/sdks/swift/Samples/ActivityFeed/Pods/UsergridSDK/sdks/swift/Source/UsergridClient.swift b/sdks/swift/Samples/ActivityFeed/Pods/UsergridSDK/sdks/swift/Source/UsergridClient.swift new file mode 100644 index 0000000..cbb416f --- /dev/null +++ b/sdks/swift/Samples/ActivityFeed/Pods/UsergridSDK/sdks/swift/Source/UsergridClient.swift @@ -0,0 +1,875 @@ +// +// UsergridClient.swift +// UsergridSDK +// +// Created by Robert Walsh on 9/3/15. +// +/* + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. The ASF licenses this file to You + * under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. For additional information regarding + * copyright in this work, please see the NOTICE file in the top level + * directory of this distribution. + * + */ + + +import Foundation + +/** +The `UsergridClient` class is the base handler for making client connections to and managing relationships with Usergrid's API. +*/ +public class UsergridClient: NSObject, NSCoding { + + static let DEFAULT_BASE_URL = "https://api.usergrid.com" + + // MARK: - Instance Properties - + + lazy private var _requestManager: UsergridRequestManager = UsergridRequestManager(client: self) + + /// The configuration object used by the client. + public let config: UsergridClientConfig + + /// The application identifier. + public var appId : String { return config.appId } + + /// The organization identifier. + public var orgId : String { return config.orgId } + + /// The base URL that all calls will be made with. + public var baseUrl : String { return config.baseUrl } + + /// The constructed URL string based on the `UsergridClient`'s `baseUrl`, `orgId`, and `appId`. + internal var clientAppURL : String { return "\(baseUrl)/\(orgId)/\(appId)" } + + /// The currently logged in `UsergridUser`. + internal(set) public var currentUser: UsergridUser? = nil { + didSet { + if let newUser = self.currentUser { + UsergridUser.saveCurrentUserKeychainItem(self,currentUser:newUser) + } else if oldValue != nil { + UsergridUser.deleteCurrentUserKeychainItem(self) + } + } + } + + /// The `UsergridUserAuth` which consists of the token information from the `currentUser` property. + public var userAuth: UsergridUserAuth? { return currentUser?.auth } + + /// The temporary `UsergridAuth` object that is set when calling the `UsergridClient.usingAuth()` method. + private var tempAuth: UsergridAuth? = nil + + /// The application level `UsergridAppAuth` object. Can be set manually but must call `authenticateApp` to retrive token. + public var appAuth: UsergridAppAuth? { + set { config.appAuth = newValue } + get { return config.appAuth } + } + + /// The `UsergridAuthFallback` value used to determine what type of token will be sent, if any. + public var authFallback: UsergridAuthFallback { + set { config.authFallback = newValue } + get { return config.authFallback } + } + + // MARK: - Initialization - + + /** + Initializes instances of `UsergridClient`. + + - parameter orgId: The organization identifier. + - parameter appId: The application identifier. + + - returns: The new instance of `UsergridClient`. + */ + public convenience init(orgId: String, appId:String) { + self.init(configuration:UsergridClientConfig(orgId: orgId, appId: appId)) + } + + /** + Initializes instances of `UsergridClient`. + + - parameter orgId: The organization identifier. + - parameter appId: The application identifier. + - parameter baseUrl: The base URL that all calls will be made with. + + - returns: The new instance of `UsergridClient`. + */ + public convenience init(orgId: String, appId:String, baseUrl:String) { + self.init(configuration:UsergridClientConfig(orgId: orgId, appId: appId, baseUrl:baseUrl)) + } + + /** + Initializes instances of `UsergridClient`. + + - parameter configuration: The configuration for the client to be set up with. + + - returns: The new instance of `UsergridClient`. + */ + public init(configuration:UsergridClientConfig) { + self.config = configuration + super.init() + self.currentUser = UsergridUser.getCurrentUserFromKeychain(self) // Attempt to get the current user from the saved keychain data. + } + + // MARK: - NSCoding - + + /** + NSCoding protocol initializer. + + - parameter aDecoder: The decoder. + + - returns: A decoded `UsergridClient` object. + */ + public required init?(coder aDecoder: NSCoder) { + guard let config = aDecoder.decodeObjectForKey("config") as? UsergridClientConfig + else { + self.config = UsergridClientConfig(orgId: "", appId: "") + super.init() + return nil + } + + self.config = config + super.init() + + if let currentUser = aDecoder.decodeObjectForKey("currentUser") as? UsergridUser { + self.currentUser = currentUser + } else { + // If we didn't decode a current user, attempt to get the current user from the saved keychain data. + self.currentUser = UsergridUser.getCurrentUserFromKeychain(self) + } + } + + /** + NSCoding protocol encoder. + + - parameter aCoder: The encoder. + */ + public func encodeWithCoder(aCoder: NSCoder) { + aCoder.encodeObject(self.config, forKey: "config") + aCoder.encodeObject(self.currentUser, forKey: "currentUser") + } + + // MARK: - Device Registration/Push Notifications - + + /** + Sets the push token for the given notifier ID and performs a PUT request to update the shared `UsergridDevice` instance. + + - parameter pushToken: The push token from Apple. + - parameter notifierID: The Usergrid notifier ID. + - parameter completion: The completion block. + */ + public func applyPushToken(pushToken: NSData, notifierID: String, completion: UsergridResponseCompletion? = nil) { + self.applyPushToken(UsergridDevice.sharedDevice, pushToken: pushToken, notifierID: notifierID, completion: completion) + } + + /** + Sets the push token for the given notifier ID and performs a PUT request to update the given `UsergridDevice` instance. + + - parameter device: The `UsergridDevice` object. + - parameter pushToken: The push token from Apple. + - parameter notifierID: The Usergrid notifier ID. + - parameter completion: The completion block. + */ + public func applyPushToken(device: UsergridDevice, pushToken: NSData, notifierID: String, completion: UsergridResponseCompletion? = nil) { + device.applyPushToken(pushToken, notifierID: notifierID) + PUT(UsergridDevice.DEVICE_ENTITY_TYPE, jsonBody: device.jsonObjectValue, completion: completion) + } + + // MARK: - Authorization and User Management - + + /** + Determines the `UsergridAuth` object that will be used for all outgoing requests made. + + If there is a valid temporary `UsergridAuth` set by the functions `usingAuth` or `usingToken` it will return that. + + If there is a `UsergridUser` logged in and the token of that user is valid then it will return that. + + Otherwise, if the `authFallback` is `.App`, and the `UsergridAppAuth` of the client is set and the token is valid it will return that. + + - returns: The `UsergridAuth` if one is found or nil if not. + */ + internal func authForRequests() -> UsergridAuth? { + var usergridAuth: UsergridAuth? + if let tempAuth = self.tempAuth where tempAuth.isValid { + usergridAuth = tempAuth + self.tempAuth = nil + } else if let userAuth = self.userAuth where userAuth.isValid { + usergridAuth = userAuth + } else if self.authFallback == .App, let appAuth = self.appAuth where appAuth.isValid { + usergridAuth = appAuth + } + return usergridAuth + } + + /** + Sets the client's `tempAuth` property using the passed in `UsergridAuth`. + + This will cause the next CRUD method performed by the client to use the `tempAuth` property once and will then reset. + + - parameter auth: The `UsergridAuth` object to temporarily use for authentication. + + - returns: `Self` + */ + public func usingAuth(auth:UsergridAuth) -> Self { + self.tempAuth = auth + return self + } + + /** + Sets the client's `tempAuth` property using the passed in token. + + This will cause the next CRUD method performed by the client to use the `tempAuth` property once and will then reset. + + - parameter auth: The access token to temporarily use for authentication. + + - returns: `Self` + */ + public func usingToken(token:String) -> Self { + self.tempAuth = UsergridAuth(accessToken: token) + return self + } + + /** + Authenticates with the `UsergridAppAuth` that is contained this instance of `UsergridCient`. + + - parameter completion: The completion block that will be called after authentication has completed. + */ + public func authenticateApp(completion: UsergridAppAuthCompletionBlock? = nil) { + guard let appAuth = self.appAuth + else { + let error = UsergridResponseError(errorName: "Invalid UsergridAppAuth.", errorDescription: "UsergridClient's appAuth is nil.") + completion?(auth: nil, error: error) + return + } + self.authenticateApp(appAuth, completion: completion) + } + + /** + Authenticates with the `UsergridAppAuth` that is passed in. + + - parameter auth: The `UsergridAppAuth` that will be authenticated. + - parameter completion: The completion block that will be called after authentication has completed. + */ + public func authenticateApp(appAuth: UsergridAppAuth, completion: UsergridAppAuthCompletionBlock? = nil) { + let request = UsergridRequest(method: .Post, + baseUrl: self.clientAppURL, + paths: ["token"], + auth: self.authForRequests(), + jsonBody: appAuth.credentialsJSONDict) + + _requestManager.performAppAuthRequest(appAuth, request: request) { [weak self] (auth,error) in + self?.appAuth = auth + completion?(auth: auth, error: error) + } + } + + /** + Authenticates with the `UsergridUserAuth` that is passed in. + + - parameter auth: The `UsergridUserAuth` that will be authenticated. + - parameter completion: The completion block that will be called after authentication has completed. + */ + public func authenticateUser(userAuth: UsergridUserAuth, completion: UsergridUserAuthCompletionBlock? = nil) { + self.authenticateUser(userAuth, setAsCurrentUser:true, completion:completion) + } + + /** + Authenticates with the `UsergridUserAuth` that is passed in. + + - parameter auth: The `UsergridUserAuth` that will be authenticated. + - parameter setAsCurrentUser: If the authenticated user should be set as the `UsergridClient.currentUser`. + - parameter completion: The completion block that will be called after authentication has completed. + */ + public func authenticateUser(userAuth: UsergridUserAuth, setAsCurrentUser: Bool, completion: UsergridUserAuthCompletionBlock? = nil) { + let request = UsergridRequest(method: .Post, + baseUrl: self.clientAppURL, + paths: ["token"], + auth: self.authForRequests(), + jsonBody: userAuth.credentialsJSONDict) + _requestManager.performUserAuthRequest(userAuth, request: request) { [weak self] (auth,user,error) in + if setAsCurrentUser { + self?.currentUser = user + } + completion?(auth: auth, user: user, error: error) + } + } + + /** + Changes the give `UsergridUser`'s current password with the shared instance of `UsergridClient`. + + - parameter user: The user. + - parameter old: The old password. + - parameter new: The new password. + - parameter completion: The optional completion block. + */ + public func resetPassword(user: UsergridUser, old:String, new:String, completion:UsergridUserResetPasswordCompletion? = nil) { + guard let usernameOrEmail = user.usernameOrEmail + else { + completion?(error: UsergridResponseError(errorName: "Error resetting password.", errorDescription: "The UsergridUser object must contain a valid username or email to reset the password."), didSucceed: false) + return + } + + let request = UsergridRequest(method: .Put, + baseUrl: self.clientAppURL, + paths: ["users",usernameOrEmail,"password"], + auth: self.authForRequests(), + jsonBody:["oldpassword":old,"newpassword":new]) + + _requestManager.performRequest(request, completion: { (response) -> Void in + completion?(error: response.error, didSucceed: response.statusCode == 200) + }) + } + + /** + Logs out the current user locally and remotely. + + - parameter completion: The completion block that will be called after logout has completed. + */ + public func logoutCurrentUser(completion:UsergridResponseCompletion? = nil) { + guard let uuidOrUsername = self.currentUser?.uuidOrUsername, + let token = self.currentUser?.auth?.accessToken + else { + completion?(response:UsergridResponse(client: self, errorName: "Logout Failed.", errorDescription: "UsergridClient's currentUser is not valid.")) + return + } + + self.logoutUser(uuidOrUsername, token: token) { (response) -> Void in + if response.ok || response.error?.errorName == "auth_bad_access_token" { + self.currentUser?.auth = nil + self.currentUser = nil + } + completion?(response: response) + } + } + + /** + Logs out the user remotely with the given tokens. + + - parameter completion: The completion block that will be called after logout has completed. + */ + public func logoutUserAllTokens(uuidOrUsername:String, completion:UsergridResponseCompletion? = nil) { + self.logoutUser(uuidOrUsername, token: nil, completion: completion) + } + + /** + Logs out a user with the give UUID or username using the shared instance of `UsergridCient`. + + Passing in a token will log out the user for just that token. Passing in nil for the token will logout the user for all tokens. + + - parameter completion: The completion block that will be called after logout has completed. + */ + public func logoutUser(uuidOrUsername:String, token:String?, completion:UsergridResponseCompletion? = nil) { + var paths = ["users",uuidOrUsername] + var queryParams: [String: String]? + if let accessToken = token { + paths.append("revoketoken") + queryParams = ["token": accessToken] + } else { + paths.append("revoketokens") + } + let request = UsergridRequest(method: .Put, + baseUrl: self.clientAppURL, + paths: paths, + auth: self.authForRequests(), + queryParams: queryParams) + self.sendRequest(request, completion: completion) + } + + // MARK: - Generic Request Methods - + + /** + Starts the `UsergridRequest` sending process. + + - Note: This method should only be used when you construct your own `UsergridRequest` objects. + + - parameter request: The `UsergridRequest` object to send. + - parameter completion: The optional completion block that will be called once the request has completed. + */ + public func sendRequest(request:UsergridRequest, completion:UsergridResponseCompletion? = nil) { + _requestManager.performRequest(request, completion: completion) + } + + // MARK: - GET - + + /** + Gets a single `UsergridEntity` of a given type with a specific UUID/name. + + - parameter type: The `UsergridEntity` type. + - parameter uuidOrName: The UUID or name of the `UsergridEntity`. + - parameter completion: The optional completion block that will be called once the request has completed. + */ + public func GET(type: String, uuidOrName: String, completion: UsergridResponseCompletion? = nil) { + let request = UsergridRequest(method: .Get, baseUrl: self.clientAppURL, paths: [type,uuidOrName], auth:self.authForRequests()) + self.sendRequest(request, completion: completion) + } + + /** + Gets a group of `UsergridEntity` objects of a given type with an optional query. + + - parameter type: The `UsergridEntity` type. + - parameter query: The optional query to use when gathering `UsergridEntity` objects. + - parameter completion: The optional completion block that will be called once the request has completed. + */ + public func GET(type: String, query: UsergridQuery? = nil, completion: UsergridResponseCompletion? = nil) { + let request = UsergridRequest(method: .Get, baseUrl: self.clientAppURL, paths: [type], query: query, auth: self.authForRequests()) + self.sendRequest(request, completion: completion) + } + + // MARK: - PUT - + + /** + Updates an `UsergridEntity` with the given type and UUID/name specified using the passed in jsonBody. + + - parameter type: The `UsergridEntity` type. + - parameter uuidOrName: The UUID or name of the `UsergridEntity`. + - parameter jsonBody: The valid JSON body dictionary to update the `UsergridEntity` with. + - parameter completion: The optional completion block that will be called once the request has completed. + */ + public func PUT(type: String, uuidOrName: String, jsonBody:[String:AnyObject], completion: UsergridResponseCompletion? = nil) { + let request = UsergridRequest(method: .Put, + baseUrl: self.clientAppURL, + paths: [type,uuidOrName], + auth: self.authForRequests(), + headers: UsergridRequest.JSON_CONTENT_TYPE_HEADER, + jsonBody: jsonBody) + self.sendRequest(request, completion: completion) + } + + /** + Updates the passed in `UsergridEntity`. + + - parameter entity: The `UsergridEntity` to update. + - parameter completion: The optional completion block that will be called once the request has completed. + */ + public func PUT(entity: UsergridEntity, completion: UsergridResponseCompletion? = nil) { + PUT(entity.type, jsonBody: entity.jsonObjectValue, completion: completion) + } + + /** + Updates an `UsergridEntity` with the given type using the jsonBody where the UUID/name is specified inside of the jsonBody. + + - Note: The `jsonBody` must contain a valid value for either `uuid` or `name` keys. + + - parameter type: The `UsergridEntity` type. + - parameter jsonBody: The valid JSON body dictionary to update the `UsergridEntity` with. + - parameter completion: The optional completion block that will be called once the request has completed. + */ + public func PUT(type: String, jsonBody:[String:AnyObject], completion: UsergridResponseCompletion? = nil) { + guard let uuidOrName = (jsonBody[UsergridEntityProperties.UUID.stringValue] ?? jsonBody[UsergridEntityProperties.Name.stringValue]) as? String + else { + completion?(response: UsergridResponse(client:self, errorName: "jsonBody not valid.", errorDescription: "The `jsonBody` must contain a valid value for either `uuid` or `name`.")) + return + } + let request = UsergridRequest(method: .Put, + baseUrl: self.clientAppURL, + paths: [type,uuidOrName], + auth: self.authForRequests(), + headers: UsergridRequest.JSON_CONTENT_TYPE_HEADER, + jsonBody: jsonBody) + self.sendRequest(request, completion: completion) + } + + /** + Updates the entities that fit the given query using the passed in jsonBody. + + - Note: The query parameter must have a valid `collectionName` before calling this method. + + - parameter query: The query to use when filtering what entities to update. + - parameter jsonBody: The valid JSON body dictionary to update with. + - parameter queryCompletion: The optional completion block that will be called once the request has completed. + */ + public func PUT(query: UsergridQuery, jsonBody:[String:AnyObject], queryCompletion: UsergridResponseCompletion? = nil) { + guard let type = query.collectionName + else { + queryCompletion?(response: UsergridResponse(client:self, errorName: "Query collection name invalid.", errorDescription: "Query is missing a collection name.")) + return + } + let request = UsergridRequest(method: .Put, + baseUrl: self.clientAppURL, + paths: [type], + query: query, + auth: self.authForRequests(), + headers: UsergridRequest.JSON_CONTENT_TYPE_HEADER, + jsonBody: jsonBody) + self.sendRequest(request, completion: queryCompletion) + } + + // MARK: - POST - + + /** + Creates and posts creates an `UsergridEntity`. + - parameter entity: The `UsergridEntity` to create. + - parameter completion: The optional completion block that will be called once the request has completed. + */ + public func POST(entity:UsergridEntity, completion: UsergridResponseCompletion? = nil) { + let request = UsergridRequest(method: .Post, + baseUrl: self.clientAppURL, + paths: [entity.type], + auth: self.authForRequests(), + headers: UsergridRequest.JSON_CONTENT_TYPE_HEADER, + jsonBody: entity.jsonObjectValue) + self.sendRequest(request, completion: completion) + } + + /** + Creates and posts an array of `UsergridEntity` objects. + + - Note: Each `UsergridEntity` in the array much already have a type assigned and must be the same. + + - parameter entities: The `UsergridEntity` objects to create. + - parameter entitiesCompletion: The optional completion block that will be called once the request has completed. + */ + public func POST(entities:[UsergridEntity], entitiesCompletion: UsergridResponseCompletion? = nil) { + guard let type = entities.first?.type + else { + entitiesCompletion?(response: UsergridResponse(client:self, errorName: "No type found.", errorDescription: "The first entity in the array had no type found.")) + return + } + POST(type, jsonBodies: entities.map { return ($0).jsonObjectValue }, completion: entitiesCompletion) + } + + /** + Creates and posts an `UsergridEntity` of the given type with the given jsonBody. + + - parameter type: The `UsergridEntity` type. + - parameter jsonBody: The valid JSON body dictionary to use when creating the `UsergridEntity`. + - parameter completion: The optional completion block that will be called once the request has completed. + */ + public func POST(type: String, jsonBody:[String:AnyObject], completion: UsergridResponseCompletion? = nil) { + let request = UsergridRequest(method: .Post, + baseUrl: self.clientAppURL, + paths: [type], + auth: self.authForRequests(), + headers: UsergridRequest.JSON_CONTENT_TYPE_HEADER, + jsonBody: jsonBody) + self.sendRequest(request, completion: completion) + } + + /** + Creates and posts an array of `Entity` objects while assigning the given type to them. + + - parameter type: The `UsergridEntity` type. + - parameter jsonBody: The valid JSON body dictionaries to use when creating the `UsergridEntity` objects. + - parameter completion: The optional completion block that will be called once the request has completed. + */ + public func POST(type: String, jsonBodies:[[String:AnyObject]], completion: UsergridResponseCompletion? = nil) { + let request = UsergridRequest(method: .Post, + baseUrl: self.clientAppURL, + paths: [type], + auth: self.authForRequests(), + headers: UsergridRequest.JSON_CONTENT_TYPE_HEADER, + jsonBody: jsonBodies) + self.sendRequest(request, completion: completion) + } + + /** + Creates and posts an `UsergridEntity` of the given type with a given name and the given jsonBody. + + - parameter type: The `UsergridEntity` type. + - parameter name: The name of the `UsergridEntity`. + - parameter jsonBody: The valid JSON body dictionary to use when creating the `UsergridEntity`. + - parameter completion: The optional completion block that will be called once the request has completed. + */ + public func POST(type: String, name: String, jsonBody:[String:AnyObject], completion: UsergridResponseCompletion? = nil) { + var jsonBodyWithName = jsonBody + jsonBodyWithName[UsergridEntityProperties.Name.stringValue] = name + let request = UsergridRequest(method: .Post, + baseUrl: self.clientAppURL, + paths: [type], + auth: self.authForRequests(), + headers: UsergridRequest.JSON_CONTENT_TYPE_HEADER, + jsonBody: jsonBodyWithName) + self.sendRequest(request, completion: completion) + + } + + // MARK: - DELETE - + + /** + Destroys the passed `UsergridEntity`. + + - Note: The entity object must have a `uuid` or `name` assigned. + + - parameter entity: The `UsergridEntity` to delete. + - parameter completion: The optional completion block that will be called once the request has completed. + */ + public func DELETE(entity:UsergridEntity, completion: UsergridResponseCompletion? = nil) { + guard let uuidOrName = entity.uuidOrName + else { + completion?(response: UsergridResponse(client:self, errorName: "No UUID or name found.", errorDescription: "The entity object must have a `uuid` or `name` assigned.")) + return + } + + DELETE(entity.type, uuidOrName: uuidOrName, completion: completion) + } + + /** + Destroys the `UsergridEntity` objects that fit the given `UsergridQuery`. + + - Note: The query parameter must have a valid `collectionName` before calling this method. + + - parameter query: The query to use when filtering what entities to delete. + - parameter queryCompletion: The optional completion block that will be called once the request has completed. + */ + public func DELETE(query:UsergridQuery, queryCompletion: UsergridResponseCompletion? = nil) { + guard let type = query.collectionName + else { + queryCompletion?(response: UsergridResponse(client:self, errorName: "Query collection name invalid.", errorDescription: "Query is missing a collection name.")) + return + } + + let request = UsergridRequest(method: .Delete, + baseUrl: self.clientAppURL, + paths: [type], + query: query, + auth: self.authForRequests(), + headers: UsergridRequest.JSON_CONTENT_TYPE_HEADER) + self.sendRequest(request, completion: queryCompletion) + } + + /** + Destroys the `UsergridEntity` of a given type with a specific UUID/name. + + - parameter type: The `UsergridEntity` type. + - parameter uuidOrName: The UUID or name of the `UsergridEntity`. + - parameter completion: The optional completion block that will be called once the request has completed. + */ + public func DELETE(type:String, uuidOrName: String, completion: UsergridResponseCompletion? = nil) { + let request = UsergridRequest(method: .Delete, + baseUrl: self.clientAppURL, + paths: [type,uuidOrName], + auth: self.authForRequests(), + headers: UsergridRequest.JSON_CONTENT_TYPE_HEADER) + self.sendRequest(request, completion: completion) + } + + // MARK: - Connection Management - + + /** + Connects the `UsergridEntity` objects via the relationship. + + - parameter entity: The `UsergridEntity` that will contain the connection. + - parameter relationship: The relationship of the connection. + - parameter to: The `UsergridEntity` which is connected. + - parameter completion: The optional completion block that will be called once the request has completed. + */ + public func connect(entity:UsergridEntity, relationship:String, to:UsergridEntity, completion: UsergridResponseCompletion? = nil) { + guard let entityID = entity.uuidOrName, + let toID = to.uuidOrName + else { + completion?(response: UsergridResponse(client: self, errorName: "Invalid Entity Connection Attempt.", errorDescription: "One or both entities that are attempting to be connected do not contain a valid UUID or Name property.")) + return + } + self.connect(entity.type, entityID: entityID, relationship: relationship, toType: to.type, toID: toID, completion: completion) + } + + /** + Connects the entity objects via the relationship. + + - parameter entityType: The entity type. + - parameter entityID: The entity UUID or name. + - parameter relationship: The relationship of the connection. + - parameter toType: The type of the entity you are connecting to. + - parameter toName: The name of the entity you are connecting to. + - parameter completion: The optional completion block that will be called once the request has completed. + */ + public func connect(entityType:String, entityID:String, relationship:String, toType:String, toName: String, completion: UsergridResponseCompletion? = nil) { + self.connect(entityType, entityID: entityID, relationship: relationship, toType: toType, toID: toName, completion: completion) + } + + /** + Connects the entity objects via the relationship. + + - parameter entityType: The entity type. + - parameter entityID: The entity UUID or name. + - parameter relationship: The relationship of the connection. + - parameter toType: The optional type of the entity you are connecting to. + - parameter toID: The UUID of the entity you are connecting to. + - parameter completion: The optional completion block that will be called once the request has completed. + */ + public func connect(entityType:String, entityID:String, relationship:String, toType:String?, toID: String, completion: UsergridResponseCompletion? = nil) { + var paths = [entityType,entityID,relationship] + if let toType = toType { + paths.append(toType) + } + paths.append(toID) + + let request = UsergridRequest(method: .Post, + baseUrl: self.clientAppURL, + paths: paths, + auth: self.authForRequests()) + self.sendRequest(request, completion: completion) + } + + /** + Disconnects the `UsergridEntity` objects via the relationship. + + - parameter entity: The `UsergridEntity` that contains the connection. + - parameter relationship: The relationship of the connection. + - parameter from: The `UsergridEntity` which is connected. + - parameter completion: The optional completion block that will be called once the request has completed. + */ + public func disconnect(entity:UsergridEntity, relationship:String, from:UsergridEntity, completion: UsergridResponseCompletion? = nil) { + guard let entityID = entity.uuidOrName, + let fromID = from.uuidOrName + else { + completion?(response: UsergridResponse(client: self, errorName: "Invalid Entity Disconnect Attempt.", errorDescription: "The connecting and connected entities must have a `uuid` or `name` assigned.")) + return + } + + self.disconnect(entity.type, entityID: entityID, relationship: relationship, fromType: from.type, fromID: fromID, completion: completion) + } + + /** + Disconnects the entity objects via the relationship. + + - parameter entityType: The entity type. + - parameter entityID: The entity UUID or name. + - parameter relationship: The relationship of the connection. + - parameter fromType: The type of the entity you are disconnecting from. + - parameter fromName: The name of the entity you are disconnecting from. + - parameter completion: The optional completion block that will be called once the request has completed. + */ + public func disconnect(entityType:String, entityID:String, relationship:String, fromType:String, fromName: String, completion: UsergridResponseCompletion? = nil) { + self.disconnect(entityType, entityID: entityID, relationship: relationship, fromType: fromType, fromID: fromName, completion: completion) + } + + /** + Disconnects the entity objects via the relationship. + + - parameter entityType: The entity type. + - parameter entityID: The entity UUID or name. + - parameter relationship: The relationship of the connection. + - parameter fromType: The optional type of the entity you are disconnecting from. + - parameter toID: The UUID of the entity you are disconnecting from. + - parameter completion: The optional completion block that will be called once the request has completed. + */ + public func disconnect(entityType:String, entityID:String, relationship:String, fromType:String?, fromID: String, completion: UsergridResponseCompletion? = nil) { + + var paths = [entityType,entityID,relationship] + if let fromType = fromType { + paths.append(fromType) + } + paths.append(fromID) + + let request = UsergridRequest(method: .Delete, + baseUrl: self.clientAppURL, + paths: paths, + auth: self.authForRequests()) + self.sendRequest(request, completion: completion) + } + + /** + Gets the connected entities for the given relationship. + + - parameter entity: The entity that contains the connection. + - parameter relationship: The relationship of the connection. + - parameter query: The optional query. + - parameter completion: The optional completion block that will be called once the request has completed. + */ + public func getConnections(direction:UsergridDirection, entity:UsergridEntity, relationship:String, query:UsergridQuery?, completion:UsergridResponseCompletion? = nil) { + guard let uuidOrName = entity.uuidOrName + else { + completion?(response: UsergridResponse(client: self, errorName: "Invalid Entity Get Connections Attempt.", errorDescription: "The entity must have a `uuid` or `name` assigned.")) + return + } + self.getConnections(direction, type: entity.type, uuidOrName: uuidOrName, relationship: relationship, query:query, completion: completion) + } + + /** + Gets the connected entities for the given relationship. + + - parameter direction: The direction of the connection. + - parameter type: The entity type. + - parameter uuidOrName: The entity UUID or name. + - parameter relationship: The relationship of the connection. + - parameter query: The optional query. + - parameter completion: The optional completion block that will be called once the request has completed. + */ + public func getConnections(direction:UsergridDirection, type:String, uuidOrName:String, relationship:String, query:UsergridQuery?, completion:UsergridResponseCompletion? = nil) { + let request = UsergridRequest(method: .Get, + baseUrl: self.clientAppURL, + paths: [type, uuidOrName, direction.connectionValue, relationship], + query: query, + auth: self.authForRequests()) + self.sendRequest(request, completion: completion) + } + + /** + Gets the connected entities for the given relationship. + + - parameter direction: The direction of the connection. + - parameter uuid: The entity UUID. + - parameter relationship: The relationship of the connection. + - parameter query: The optional query. + - parameter completion: The optional completion block that will be called once the request has completed. + */ + public func getConnections(direction:UsergridDirection, uuid:String, relationship:String, query:UsergridQuery?, completion:UsergridResponseCompletion? = nil) { + let request = UsergridRequest(method: .Get, + baseUrl: self.clientAppURL, + paths: [uuid, direction.connectionValue, relationship], + query: query, + auth: self.authForRequests()) + self.sendRequest(request, completion: completion) + } + + // MARK: - Asset Management - + + /** + Uploads the asset and connects the data to the given `UsergridEntity`. + + - parameter entity: The `UsergridEntity` to connect the asset to. + - parameter asset: The `UsergridAsset` to upload. + - parameter progress: The optional progress block that will be called to update the progress of the upload. + - parameter completion: The optional completion block that will be called once the request has completed. + */ + public func uploadAsset(entity:UsergridEntity, asset:UsergridAsset, progress:UsergridAssetRequestProgress? = nil, completion:UsergridAssetUploadCompletion? = nil) { + let assetRequest = UsergridAssetUploadRequest(baseUrl: self.clientAppURL, + paths: [entity.type,entity.uuidOrName!], + auth: self.authForRequests(), + asset: asset) + + _requestManager.performAssetUpload(assetRequest, progress: progress) { [weak entity] (response, asset, error) -> Void in + entity?.asset = asset + completion?(response: response, asset: asset, error: error) + } + } + + /** + Downloads the asset from the given `UsergridEntity`. + + - parameter entity: The `UsergridEntity` to which the asset to. + - parameter contentType: The content type of the asset's data. + - parameter progress: The optional progress block that will be called to update the progress of the download. + - parameter completion: The optional completion block that will be called once the request has completed. + */ + public func downloadAsset(entity:UsergridEntity, contentType:String, progress:UsergridAssetRequestProgress? = nil, completion:UsergridAssetDownloadCompletion? = nil) { + guard entity.hasAsset + else { + completion?(asset: nil, error: "Entity does not have an asset attached.") + return + } + + let downloadAssetRequest = UsergridRequest(method: .Get, + baseUrl: self.clientAppURL, + paths: [entity.type,entity.uuidOrName!], + auth: self.authForRequests(), + headers: ["Accept":contentType]) + + _requestManager.performAssetDownload(contentType, usergridRequest: downloadAssetRequest, progress: progress, completion: { (asset, error) -> Void in + entity.asset = asset + completion?(asset: asset, error: error) + }) + } +}
http://git-wip-us.apache.org/repos/asf/usergrid/blob/7442c881/sdks/swift/Samples/ActivityFeed/Pods/UsergridSDK/sdks/swift/Source/UsergridClientConfig.swift ---------------------------------------------------------------------- diff --git a/sdks/swift/Samples/ActivityFeed/Pods/UsergridSDK/sdks/swift/Source/UsergridClientConfig.swift b/sdks/swift/Samples/ActivityFeed/Pods/UsergridSDK/sdks/swift/Source/UsergridClientConfig.swift new file mode 100644 index 0000000..c79b6b2 --- /dev/null +++ b/sdks/swift/Samples/ActivityFeed/Pods/UsergridSDK/sdks/swift/Source/UsergridClientConfig.swift @@ -0,0 +1,142 @@ +// +// UsergridClientConfig.swift +// UsergridSDK +// +// Created by Robert Walsh on 10/5/15. +// +/* + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. The ASF licenses this file to You + * under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. For additional information regarding + * copyright in this work, please see the NOTICE file in the top level + * directory of this distribution. + * + */ + +import Foundation + +/** +`UsergridClientConfig` is used when initializing `UsergridClient` objects. + +The `UsergridClientConfig` is meant for further customization of `UsergridClient` objects when needed. +*/ +public class UsergridClientConfig : NSObject, NSCoding { + + // MARK: - Instance Properties - + + /// The organization identifier. + public var orgId : String + + /// The application identifier. + public var appId : String + + /// The base URL that all calls will be made with. + public var baseUrl: String = UsergridClient.DEFAULT_BASE_URL + + /// The `UsergridAuthFallback` value used to determine what type of token will be sent, if any. + public var authFallback: UsergridAuthFallback = .App + + /** + The application level `UsergridAppAuth` object. + + Note that you still need to call the authentication methods within `UsergridClient` once it has been initialized. + */ + public var appAuth: UsergridAppAuth? + + // MARK: - Initialization - + + /** + Designated initializer for `UsergridClientConfig` objects. + + - parameter orgId: The organization identifier. + - parameter appId: The application identifier. + + - returns: A new instance of `UsergridClientConfig`. + */ + public init(orgId: String, appId: String) { + self.orgId = orgId + self.appId = appId + } + + /** + Convenience initializer for `UsergridClientConfig`. + + - parameter orgId: The organization identifier. + - parameter appId: The application identifier. + - parameter baseUrl: The base URL that all calls will be made with. + + - returns: A new instance of `UsergridClientConfig`. + */ + public convenience init(orgId: String, appId: String, baseUrl:String) { + self.init(orgId:orgId,appId:appId) + self.baseUrl = baseUrl + } + + /** + Convenience initializer for `UsergridClientConfig`. + + - parameter orgId: The organization identifier. + - parameter appId: The application identifier. + - parameter baseUrl: The base URL that all calls will be made with. + - parameter authFallback: The `UsergridAuthFallback` value used to determine what type of token will be sent, if any. + - parameter appAuth: The application level `UsergridAppAuth` object. + + - returns: A new instance of `UsergridClientConfig`. + */ + public convenience init(orgId: String, appId: String, baseUrl:String, authFallback:UsergridAuthFallback, appAuth:UsergridAppAuth? = nil) { + self.init(orgId:orgId,appId:appId,baseUrl:baseUrl) + self.authFallback = authFallback + self.appAuth = appAuth + } + + // MARK: - NSCoding - + + /** + NSCoding protocol initializer. + + - parameter aDecoder: The decoder. + + - returns: A decoded `UsergridUser` object. + */ + public required init?(coder aDecoder: NSCoder) { + guard let appId = aDecoder.decodeObjectForKey("appId") as? String, + let orgId = aDecoder.decodeObjectForKey("orgId") as? String, + let baseUrl = aDecoder.decodeObjectForKey("baseUrl") as? String + else { + self.appId = "" + self.orgId = "" + super.init() + return nil + } + self.appId = appId + self.orgId = orgId + self.baseUrl = baseUrl + self.appAuth = aDecoder.decodeObjectForKey("appAuth") as? UsergridAppAuth + self.authFallback = UsergridAuthFallback(rawValue:aDecoder.decodeIntegerForKey("authFallback")) ?? .App + super.init() + } + + /** + NSCoding protocol encoder. + + - parameter aCoder: The encoder. + */ + public func encodeWithCoder(aCoder: NSCoder) { + aCoder.encodeObject(self.appId, forKey: "appId") + aCoder.encodeObject(self.orgId, forKey: "orgId") + aCoder.encodeObject(self.baseUrl, forKey: "baseUrl") + aCoder.encodeObject(self.appAuth, forKey: "appAuth") + aCoder.encodeInteger(self.authFallback.rawValue, forKey: "authFallback") + } +} http://git-wip-us.apache.org/repos/asf/usergrid/blob/7442c881/sdks/swift/Samples/ActivityFeed/Pods/UsergridSDK/sdks/swift/Source/UsergridDevice.swift ---------------------------------------------------------------------- diff --git a/sdks/swift/Samples/ActivityFeed/Pods/UsergridSDK/sdks/swift/Source/UsergridDevice.swift b/sdks/swift/Samples/ActivityFeed/Pods/UsergridSDK/sdks/swift/Source/UsergridDevice.swift new file mode 100644 index 0000000..c08fcf6 --- /dev/null +++ b/sdks/swift/Samples/ActivityFeed/Pods/UsergridSDK/sdks/swift/Source/UsergridDevice.swift @@ -0,0 +1,168 @@ +// +// UsergridDevice.swift +// UsergridSDK +// +// Created by Robert Walsh on 10/23/15. +// +/* + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. The ASF licenses this file to You + * under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. For additional information regarding + * copyright in this work, please see the NOTICE file in the top level + * directory of this distribution. + * + */ + +import Foundation + +#if !os(OSX) +import UIKit +#endif + +#if os(watchOS) +import WatchKit +#endif + +/** +`UsergridDevice` is an `UsergridEntity` subclass that encapsulates information about the current device as well as stores information about push tokens and Usergrid notifiers. + +To apply push tokens for Usergrid notifiers use the `UsergridClient.applyPushToken` method. +*/ +public class UsergridDevice : UsergridEntity { + + /// The `UsergridDevice` type. + static let DEVICE_ENTITY_TYPE = "device" + + // MARK: - Instance Properties - + + /// Property helper method for the `UsergridDevice` objects `uuid`. + override public var uuid: String! { return super[UsergridEntityProperties.UUID.stringValue] as! String } + + /// Property helper method for the `UsergridDevice` objects device model. + public var model: String { return super[UsergridDeviceProperties.Model.stringValue] as! String } + + /// Property helper method for the `UsergridDevice` objects device platform. + public var platform: String { return super[UsergridDeviceProperties.Platform.stringValue] as! String } + + /// Property helper method for the `UsergridDevice` objects device operating system version. + public var osVersion: String { return super[UsergridDeviceProperties.OSVersion.stringValue] as! String } + + // MARK: - Initialization - + + /// The shared instance of `UsergridDevice`. + public static var sharedDevice: UsergridDevice = UsergridDevice() + + /** + Designated Initializer for `UsergridDevice` objects + + Most likely you will never need to create seperate instances of `UsergridDevice`. Use of `UsergridDevice.sharedInstance` is recommended. + + - returns: A new instance of `UsergridDevice`. + */ + public init() { + var deviceEntityDict: [String:AnyObject] = [:] + deviceEntityDict[UsergridEntityProperties.EntityType.stringValue] = UsergridDevice.DEVICE_ENTITY_TYPE + deviceEntityDict[UsergridEntityProperties.UUID.stringValue] = UsergridDevice.usergridDeviceUUID() + + #if os(watchOS) + deviceEntityDict[UsergridDeviceProperties.Model.stringValue] = WKInterfaceDevice.currentDevice().model + deviceEntityDict[UsergridDeviceProperties.Platform.stringValue] = WKInterfaceDevice.currentDevice().systemName + deviceEntityDict[UsergridDeviceProperties.OSVersion.stringValue] = WKInterfaceDevice.currentDevice().systemVersion + #elseif os(iOS) || os(tvOS) + deviceEntityDict[UsergridDeviceProperties.Model.stringValue] = UIDevice.currentDevice().model + deviceEntityDict[UsergridDeviceProperties.Platform.stringValue] = UIDevice.currentDevice().systemName + deviceEntityDict[UsergridDeviceProperties.OSVersion.stringValue] = UIDevice.currentDevice().systemVersion + #elseif os(OSX) + deviceEntityDict[UsergridDeviceProperties.Model.stringValue] = "Mac" + deviceEntityDict[UsergridDeviceProperties.Platform.stringValue] = "OSX" + deviceEntityDict[UsergridDeviceProperties.OSVersion.stringValue] = NSProcessInfo.processInfo().operatingSystemVersionString + #endif + + super.init(type: UsergridDevice.DEVICE_ENTITY_TYPE, propertyDict: deviceEntityDict) + } + + /** + The required public initializer for `UsergridEntity` subclasses. + + - parameter type: The type associated with the `UsergridEntity` object. + - parameter name: The optional name associated with the `UsergridEntity` object. + - parameter propertyDict: The optional property dictionary that the `UsergridEntity` object will start out with. + + - returns: A new `UsergridDevice` object. + */ + required public init(type: String, name: String?, propertyDict: [String : AnyObject]?) { + super.init(type: type, name: name, propertyDict: propertyDict) + } + + // MARK: - NSCoding - + + /** + NSCoding protocol initializer. + + - parameter aDecoder: The decoder. + + - returns: A decoded `UsergridUser` object. + */ + required public init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } + + /** + NSCoding protocol encoder. + + - parameter aCoder: The encoder. + */ + public override func encodeWithCoder(aCoder: NSCoder) { + super.encodeWithCoder(aCoder) + } + + /** + Subscript for the `UsergridDevice` class. Note that all of the `UsergridDeviceProperties` are immutable. + + - Warning: When setting a properties value must be a valid JSON object. + + - Example usage: + ``` + let uuid = usergridDevice["uuid"] + ``` + */ + override public subscript(propertyName: String) -> AnyObject? { + get { + return super[propertyName] + } + set(propertyValue) { + if UsergridDeviceProperties.fromString(propertyName) == nil { + super[propertyName] = propertyValue + } + } + } + + // MARK: - Push Token Handling - + + /** + Sets the push token for the given notifier ID. + + This does not perform any API requests to update on Usergrid, rather it will just set the information in the `UsergridDevice` instance. + + In order to set the push token and perform an API request, use `UsergridClient.applyPushToken`. + + - parameter pushToken: The push token from Apple. + - parameter notifierID: The notifier ID. + */ + internal func applyPushToken(pushToken: NSData, notifierID: String) { + self[notifierID + USERGRID_NOTIFIER_ID_SUFFIX] = pushToken.description.stringByTrimmingCharactersInSet(NSCharacterSet(charactersInString: "<>")).stringByReplacingOccurrencesOfString(" ", withString: "") + } +} + +private let USERGRID_NOTIFIER_ID_SUFFIX = ".notifier.id" http://git-wip-us.apache.org/repos/asf/usergrid/blob/7442c881/sdks/swift/Samples/ActivityFeed/Pods/UsergridSDK/sdks/swift/Source/UsergridEntity.swift ---------------------------------------------------------------------- diff --git a/sdks/swift/Samples/ActivityFeed/Pods/UsergridSDK/sdks/swift/Source/UsergridEntity.swift b/sdks/swift/Samples/ActivityFeed/Pods/UsergridSDK/sdks/swift/Source/UsergridEntity.swift new file mode 100644 index 0000000..4b6fe8f --- /dev/null +++ b/sdks/swift/Samples/ActivityFeed/Pods/UsergridSDK/sdks/swift/Source/UsergridEntity.swift @@ -0,0 +1,613 @@ +// +// UsergridEntity.swift +// UsergridSDK +// +// Created by Robert Walsh on 7/21/15. +// +/* + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. The ASF licenses this file to You + * under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. For additional information regarding + * copyright in this work, please see the NOTICE file in the top level + * directory of this distribution. + * + */ + +import Foundation +import CoreLocation + +/** +`UsergridEntity` is the base class that contains a single Usergrid entity. + +`UsergridEntity` maintains a set of accessor properties for standard Usergrid schema properties (e.g. name, uuid), and supports helper methods for accessing any custom properties that might exist. +*/ +public class UsergridEntity: NSObject, NSCoding { + + static private var subclassMappings: [String:UsergridEntity.Type] = [UsergridUser.USER_ENTITY_TYPE:UsergridUser.self,UsergridDevice.DEVICE_ENTITY_TYPE:UsergridDevice.self] + + // MARK: - Instance Properties - + + /// The property dictionary that stores the properties values of the `UsergridEntity` object. + private var properties: [String : AnyObject] { + didSet { + if let fileMetaData = properties.removeValueForKey(UsergridFileMetaData.FILE_METADATA) as? [String:AnyObject] { + self.fileMetaData = UsergridFileMetaData(fileMetaDataJSON: fileMetaData) + } else { + self.fileMetaData = nil + } + } + } + + /// The `UsergridAsset` that contains the asset data. + public var asset: UsergridAsset? + + /// The `UsergridFileMetaData` of this `UsergridEntity`. + private(set) public var fileMetaData : UsergridFileMetaData? + + /// Property helper method for the `UsergridEntity` objects `UsergridEntityProperties.EntityType`. + public var type: String { return self.getEntitySpecificProperty(.EntityType) as! String } + + /// Property helper method for the `UsergridEntity` objects `UsergridEntityProperties.UUID`. + public var uuid: String? { return self.getEntitySpecificProperty(.UUID) as? String } + + /// Property helper method for the `UsergridEntity` objects `UsergridEntityProperties.Name`. + public var name: String? { return self.getEntitySpecificProperty(.Name) as? String } + + /// Property helper method for the `UsergridEntity` objects `UsergridEntityProperties.Created`. + public var created: NSDate? { return self.getEntitySpecificProperty(.Created) as? NSDate } + + /// Property helper method for the `UsergridEntity` objects `UsergridEntityProperties.Modified`. + public var modified: NSDate? { return self.getEntitySpecificProperty(.Modified) as? NSDate } + + /// Property helper method for the `UsergridEntity` objects `UsergridEntityProperties.Location`. + public var location: CLLocation? { + get { return self.getEntitySpecificProperty(.Location) as? CLLocation } + set { self[UsergridEntityProperties.Location.stringValue] = newValue } + } + + /// Property helper method to get the UUID or name of the `UsergridEntity`. + public var uuidOrName: String? { return self.uuid ?? self.name } + + /// Tells you if this `UsergridEntity` has a type of `user`. + public var isUser: Bool { return self is UsergridUser || self.type == UsergridUser.USER_ENTITY_TYPE } + + /// Tells you if there is an asset associated with this entity. + public var hasAsset: Bool { return self.asset != nil || self.fileMetaData?.contentLength > 0 } + + /// The JSON object value. + public var jsonObjectValue : [String:AnyObject] { return self.properties } + + /// The string value. + public var stringValue : String { return NSString(data: try! NSJSONSerialization.dataWithJSONObject(self.jsonObjectValue, options: .PrettyPrinted), encoding: NSASCIIStringEncoding) as! String } + + /// The description. + public override var description : String { + return "Properties of Entity: \(stringValue)." + } + + /// The debug description. + public override var debugDescription : String { + return "Properties of Entity: \(stringValue)." + } + + // MARK: - Initialization - + + /** + Designated initializer for `UsergridEntity` objects + + - parameter type: The type associated with the `UsergridEntity` object. + - parameter name: The optional name associated with the `UsergridEntity` object. + - parameter propertyDict: The optional property dictionary that the `UsergridEntity` object will start out with. + + - returns: A new `UsergridEntity` object. + */ + required public init(type:String, name:String? = nil, propertyDict:[String:AnyObject]? = nil) { + self.properties = propertyDict ?? [:] + super.init() + if self is UsergridUser { + self.properties[UsergridEntityProperties.EntityType.stringValue] = UsergridUser.USER_ENTITY_TYPE + } else if self is UsergridDevice { + self.properties[UsergridEntityProperties.EntityType.stringValue] = UsergridDevice.DEVICE_ENTITY_TYPE + } else { + self.properties[UsergridEntityProperties.EntityType.stringValue] = type + } + if let entityName = name { + self.properties[UsergridEntityProperties.Name.stringValue] = entityName + } + } + + private func copyInternalsFromEntity(entity:UsergridEntity) { + self.properties = entity.properties + self.asset = entity.asset ?? self.asset + } + + + /** + Used for custom mapping subclasses to a given `Usergrid` type. + + - parameter type: The type of the `Usergrid` object. + - parameter toSubclass: The subclass `UsergridEntity.Type` to map it to. + */ + public static func mapCustomType(type:String,toSubclass:UsergridEntity.Type) { + UsergridEntity.subclassMappings[type] = toSubclass + } + + /** + Class convenience constructor for creating `UsergridEntity` objects dynamically. + + - parameter jsonDict: A valid JSON dictionary which must contain at the very least a value for the `type` key. + + - returns: A `UsergridEntity` object provided that the `type` key within the dictionay exists. Otherwise nil. + */ + public class func entity(jsonDict jsonDict: [String:AnyObject]) -> UsergridEntity? { + if let type = jsonDict[UsergridEntityProperties.EntityType.stringValue] as? String { + if let mapping = UsergridEntity.subclassMappings[type] { + return mapping.init(type: type,propertyDict:jsonDict) + } else { + return UsergridEntity(type:type, propertyDict:jsonDict) + } + } else { + return nil + } + } + + /** + Class convenience constructor for creating multiple `UsergridEntity` objects dynamically. + + - parameter entitiesJSONArray: An array which contains dictionaries that are used to create the `UsergridEntity` objects. + + - returns: An array of `UsergridEntity`. + */ + public class func entities(jsonArray entitiesJSONArray: [[String:AnyObject]]) -> [UsergridEntity] { + var entityArray : [UsergridEntity] = [] + for entityJSONDict in entitiesJSONArray { + if let entity = UsergridEntity.entity(jsonDict:entityJSONDict) { + entityArray.append(entity) + } + } + return entityArray + } + + // MARK: - NSCoding - + + /** + NSCoding protocol initializer. + + - parameter aDecoder: The decoder. + + - returns: A decoded `UsergridUser` object. + */ + required public init?(coder aDecoder: NSCoder) { + guard let properties = aDecoder.decodeObjectForKey("properties") as? [String:AnyObject] + else { + self.properties = [:] + super.init() + return nil + } + self.properties = properties + self.fileMetaData = aDecoder.decodeObjectForKey("fileMetaData") as? UsergridFileMetaData + self.asset = aDecoder.decodeObjectForKey("asset") as? UsergridAsset + super.init() + } + + /** + NSCoding protocol encoder. + + - parameter aCoder: The encoder. + */ + public func encodeWithCoder(aCoder: NSCoder) { + aCoder.encodeObject(self.properties, forKey: "properties") + aCoder.encodeObject(self.fileMetaData, forKey: "fileMetaData") + aCoder.encodeObject(self.asset, forKey: "asset") + } + + // MARK: - Property Manipulation - + + /** + Subscript for the `UsergridEntity` class. + + - Example usage: + ``` + let propertyValue = usergridEntity["propertyName"] + usergridEntity["propertyName"] = propertyValue + ``` + */ + public subscript(propertyName: String) -> AnyObject? { + get { + if let entityProperty = UsergridEntityProperties.fromString(propertyName) { + return self.getEntitySpecificProperty(entityProperty) + } else { + let propertyValue = self.properties[propertyName] + if propertyValue === NSNull() { // Let's just return nil for properties that have been removed instead of NSNull + return nil + } else { + return propertyValue + } + } + } + set(propertyValue) { + if let value = propertyValue { + if let entityProperty = UsergridEntityProperties.fromString(propertyName) { + if entityProperty.isMutableForEntity(self) { + if entityProperty == .Location { + if let location = value as? CLLocation { + properties[propertyName] = [ENTITY_LATITUDE:location.coordinate.latitude, + ENTITY_LONGITUDE:location.coordinate.longitude] + } else if let location = value as? CLLocationCoordinate2D { + properties[propertyName] = [ENTITY_LATITUDE:location.latitude, + ENTITY_LONGITUDE:location.longitude] + } else if let location = value as? [String:Double] { + if let lat = location[ENTITY_LATITUDE], long = location[ENTITY_LONGITUDE] { + properties[propertyName] = [ENTITY_LATITUDE:lat, + ENTITY_LONGITUDE:long] + } + } + } else { + properties[propertyName] = value + } + } + } else { + properties[propertyName] = value + } + } else { // If the property value is nil we assume they wanted to remove the property. + + // We set the value for this property to Null so that when a PUT is performed on the entity the property will actually be removed from the Entity on Usergrid + if let entityProperty = UsergridEntityProperties.fromString(propertyName){ + if entityProperty.isMutableForEntity(self) { + properties[propertyName] = NSNull() + } + } else { + properties[propertyName] = NSNull() + } + } + } + } + + /** + Updates a properties value for the given property name. + + - parameter name: The name of the property. + - parameter value: The value to update to. + */ + public func putProperty(name:String,value:AnyObject?) { + self[name] = value + } + + /** + Updates a set of properties that are within the given properties dictionary. + + - parameter properties: The property dictionary containing the properties names and values. + */ + public func putProperties(properties:[String:AnyObject]) { + for (name,value) in properties { + self.putProperty(name, value: value) + } + } + + /** + Removes the property for the given property name. + + - parameter name: The name of the property. + */ + public func removeProperty(name:String) { + self[name] = nil + } + + /** + Removes the properties with the names within the propertyNames array + + - parameter propertyNames: An array of property names. + */ + public func removeProperties(propertyNames:[String]) { + for name in propertyNames { + self.removeProperty(name) + } + } + + /** + Appends the given value to the end of the properties current value. + + - parameter name: The name of the property. + - parameter value: The value or an array of values to append. + */ + public func append(name:String, value:AnyObject) { + self.insertArray(name, values:value as? [AnyObject] ?? [value], index: Int.max) + } + + /** + Inserts the given value at the given index within the properties current value. + + - parameter name: The name of the property. + - parameter index: The index to insert at. + - parameter value: The value or an array of values to insert. + */ + public func insert(name:String, value:AnyObject, index:Int = 0) { + self.insertArray(name, values:value as? [AnyObject] ?? [value], index: index) + } + + /** + Inserts an array of property values at a given index within the properties current value. + + - parameter name: The name of the property + - parameter index: The index to insert at. + - parameter values: The values to insert. + */ + private func insertArray(name:String,values:[AnyObject], index:Int = 0) { + if let propertyValue = self[name] { + if let arrayValue = propertyValue as? [AnyObject] { + var arrayOfValues = arrayValue + if index > arrayValue.count { + arrayOfValues.appendContentsOf(values) + } else { + arrayOfValues.insertContentsOf(values, at: index) + } + self[name] = arrayOfValues + } else { + if index > 0 { + self[name] = [propertyValue] + values + } else { + self[name] = values + [propertyValue] + } + } + } else { + self[name] = values + } + } + + /** + Removes the last value of the properties current value. + + - parameter name: The name of the property. + */ + public func pop(name:String) { + if let arrayValue = self[name] as? [AnyObject] where arrayValue.count > 0 { + var arrayOfValues = arrayValue + arrayOfValues.removeLast() + self[name] = arrayOfValues + } + } + + /** + Removes the first value of the properties current value. + + - parameter name: The name of the property. + */ + public func shift(name:String) { + if let arrayValue = self[name] as? [AnyObject] where arrayValue.count > 0 { + var arrayOfValues = arrayValue + arrayOfValues.removeFirst() + self[name] = arrayOfValues + } + } + + private func getEntitySpecificProperty(entityProperty: UsergridEntityProperties) -> AnyObject? { + var propertyValue: AnyObject? = nil + switch entityProperty { + case .UUID,.EntityType,.Name : + propertyValue = self.properties[entityProperty.stringValue] + case .Created,.Modified : + if let utcTimeStamp = self.properties[entityProperty.stringValue] as? Int { + propertyValue = NSDate(utcTimeStamp: utcTimeStamp.description) + } + case .Location : + if let locationDict = self.properties[entityProperty.stringValue] as? [String:Double], lat = locationDict[ENTITY_LATITUDE], long = locationDict[ENTITY_LONGITUDE] { + propertyValue = CLLocation(latitude: lat, longitude: long) + } + } + return propertyValue + } + + // MARK: - CRUD Convenience Methods - + + /** + Performs a GET on the `UsergridEntity` using the shared instance of `UsergridClient`. + + - parameter completion: An optional completion block that, if successful, will contain the reloaded `UsergridEntity` object. + */ + public func reload(completion: UsergridResponseCompletion? = nil) { + self.reload(Usergrid.sharedInstance, completion: completion) + } + + /** + Performs a GET on the `UsergridEntity`. + + - parameter client: The client to use when reloading. + - parameter completion: An optional completion block that, if successful, will contain the reloaded `UsergridEntity` object. + */ + public func reload(client:UsergridClient, completion: UsergridResponseCompletion? = nil) { + if let uuidOrName = self.uuidOrName { + client.GET(self.type, uuidOrName: uuidOrName) { (response) -> Void in + if let responseEntity = response.entity { + self.copyInternalsFromEntity(responseEntity) + } + completion?(response: response) + } + } else { + completion?(response: UsergridResponse(client: client, errorName: "Entity cannot be reloaded.", errorDescription: "Entity has neither an UUID or specified.")) + } + } + + /** + Performs a PUT (or POST if no UUID is found) on the `UsergridEntity` using the shared instance of `UsergridClient`. + + - parameter completion: An optional completion block that, if successful, will contain the updated/saved `UsergridEntity` object. + */ + public func save(completion: UsergridResponseCompletion? = nil) { + self.save(Usergrid.sharedInstance, completion: completion) + } + + /** + Performs a PUT (or POST if no UUID is found) on the `UsergridEntity`. + + - parameter client: The client to use when saving. + - parameter completion: An optional completion block that, if successful, will contain the updated/saved `UsergridEntity` object. + */ + public func save(client:UsergridClient, completion: UsergridResponseCompletion? = nil) { + if let _ = self.uuid { // If UUID exists we PUT otherwise POST + client.PUT(self, completion: { (response) -> Void in + if let responseEntity = response.entity { + self.copyInternalsFromEntity(responseEntity) + } + completion?(response: response) + }) + } else { + client.POST(self, completion: { (response) -> Void in + if let responseEntity = response.entity { + self.copyInternalsFromEntity(responseEntity) + } + completion?(response: response) + }) + } + } + + /** + Performs a DELETE on the `UsergridEntity` using the shared instance of the `UsergridClient`. + + - parameter completion: An optional completion block. + */ + public func remove(completion: UsergridResponseCompletion? = nil) { + Usergrid.sharedInstance.DELETE(self, completion: completion) + } + + /** + Performs a DELETE on the `UsergridEntity`. + + - parameter client: The client to use when removing. + - parameter completion: An optional completion block. + */ + public func remove(client:UsergridClient, completion: UsergridResponseCompletion? = nil) { + client.DELETE(self, completion: completion) + } + + // MARK: - Asset Management - + + /** + Uploads the given `UsergridAsset` and the data within it and creates an association between this `UsergridEntity` with the given `UsergridAsset` using the shared instance of `UsergridClient`. + + - parameter asset: The `UsergridAsset` object to upload. + - parameter progress: An optional progress block to keep track of upload progress. + - parameter completion: An optional completion block. + */ + public func uploadAsset(asset:UsergridAsset, progress:UsergridAssetRequestProgress? = nil, completion:UsergridAssetUploadCompletion? = nil) { + Usergrid.sharedInstance.uploadAsset(self, asset: asset, progress:progress, completion:completion) + } + + /** + Uploads the given `UsergridAsset` and the data within it and creates an association between this `UsergridEntity` with the given `UsergridAsset`. + + - parameter client: The client to use when uploading. + - parameter asset: The `UsergridAsset` object to upload. + - parameter progress: An optional progress block to keep track of upload progress. + - parameter completion: An optional completion block. + */ + public func uploadAsset(client:UsergridClient, asset:UsergridAsset, progress:UsergridAssetRequestProgress? = nil, completion:UsergridAssetUploadCompletion? = nil) { + client.uploadAsset(self, asset: asset, progress:progress, completion:completion) + } + + /** + Downloads the `UsergridAsset` that is associated with this `UsergridEntity` using the shared instance of `UsergridClient`. + + - parameter contentType: The content type of the data to load. + - parameter progress: An optional progress block to keep track of download progress. + - parameter completion: An optional completion block. + */ + public func downloadAsset(contentType:String, progress:UsergridAssetRequestProgress? = nil, completion:UsergridAssetDownloadCompletion? = nil) { + Usergrid.sharedInstance.downloadAsset(self, contentType: contentType, progress:progress, completion: completion) + } + + /** + Downloads the `UsergridAsset` that is associated with this `UsergridEntity`. + + - parameter client: The client to use when uploading. + - parameter contentType: The content type of the data to load. + - parameter progress: An optional progress block to keep track of download progress. + - parameter completion: An optional completion block. + */ + public func downloadAsset(client:UsergridClient, contentType:String, progress:UsergridAssetRequestProgress? = nil, completion:UsergridAssetDownloadCompletion? = nil) { + client.downloadAsset(self, contentType: contentType, progress:progress, completion: completion) + } + + // MARK: - Connection Management - + + /** + Creates a relationship between this `UsergridEntity` and the given entity using the shared instance of `UsergridClient`. + + - parameter relationship: The relationship type. + - parameter toEntity: The entity to connect. + - parameter completion: An optional completion block. + */ + public func connect(relationship:String, toEntity:UsergridEntity, completion: UsergridResponseCompletion? = nil) { + Usergrid.sharedInstance.connect(self, relationship: relationship, to: toEntity, completion: completion) + } + + /** + Creates a relationship between this `UsergridEntity` and the given entity. + + - parameter client: The client to use when connecting. + - parameter relationship: The relationship type. + - parameter toEntity: The entity to connect. + - parameter completion: An optional completion block. + */ + public func connect(client:UsergridClient, relationship:String, toEntity:UsergridEntity, completion: UsergridResponseCompletion? = nil) { + client.connect(self, relationship: relationship, to: toEntity, completion: completion) + } + + /** + Removes a relationship between this `UsergridEntity` and the given entity using the shared instance of `UsergridClient`. + + - parameter relationship: The relationship type. + - parameter fromEntity: The entity to disconnect. + - parameter completion: An optional completion block. + */ + public func disconnect(relationship:String, fromEntity:UsergridEntity, completion: UsergridResponseCompletion? = nil) { + Usergrid.sharedInstance.disconnect(self, relationship: relationship, from: fromEntity, completion: completion) + } + + /** + Removes a relationship between this `UsergridEntity` and the given entity. + + - parameter client: The client to use when disconnecting. + - parameter relationship: The relationship type. + - parameter fromEntity: The entity to disconnect. + - parameter completion: An optional completion block. + */ + public func disconnect(client:UsergridClient, relationship:String, fromEntity:UsergridEntity, completion: UsergridResponseCompletion? = nil) { + client.disconnect(self, relationship: relationship, from: fromEntity, completion: completion) + } + + /** + Gets the `UsergridEntity` objects, if any, which are connected via the relationship using the shared instance of `UsergridClient`. + + - parameter direction: The direction of the connection. + - parameter relationship: The relationship type. + - parameter query: The optional query. + - parameter completion: An optional completion block. + */ + public func getConnections(direction:UsergridDirection, relationship:String, query:UsergridQuery?, completion:UsergridResponseCompletion? = nil) { + Usergrid.sharedInstance.getConnections(direction, entity: self, relationship: relationship, query:query, completion: completion) + } + + /** + Gets the `UsergridEntity` objects, if any, which are connected via the relationship. + + - parameter client: The client to use when getting the connected `UsergridEntity` objects. + - parameter direction: The direction of the connection. + - parameter relationship: The relationship type. + - parameter query: The optional query. + - parameter completion: An optional completion block. + */ + public func getConnections(client:UsergridClient, direction:UsergridDirection, relationship:String, query:UsergridQuery?, completion:UsergridResponseCompletion? = nil) { + client.getConnections(direction, entity: self, relationship: relationship, query:query, completion: completion) + } +} \ No newline at end of file