-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathOGCloud.swift
390 lines (332 loc) · 13.6 KB
/
OGCloud.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
//
// OGCloud.swift
// Bourbon-iOS
//
// Created by Mitchell Kahn on 5/26/17.
// Copyright © 2017 Ourglass. All rights reserved.
//
// Replacement for Asahi singleton which was having problems with SSL for some reason
import Foundation
import Alamofire
import PromiseKit
import SwiftyJSON
/// Error class used with Asahi
///
/// - authFailure: the user is not authorized to perform the action
/// - tokenInvalid: the current token is invalid
/// - malformedJson: the response JSON was not as expected
enum OGCloudError: Error {
case authFailure
case tokenInvalid
case malformedJson
}
open class OGCloud: NSObject {
static let sharedInstance = OGCloud()
let q = DispatchQueue.global()
let initGroup = DispatchGroup()
var belliniCore: String!
var belliniDM : String!
override init() {
super.init()
updateServers()
// throwaway call to set the Sails cookie
// put in DispatchGroup so we don't make any other calls until this completes
self.initGroup.enter()
self.checkJWT().always {
self.initGroup.leave()
}
}
func updateServers(){
if (Settings.sharedInstance.useDevServer){
belliniCore = "http://138.68.230.239:2000/"
belliniDM = "http://138.68.230.239:2001/"
} else {
belliniCore = "https://cloud.ourglass.tv/"
belliniDM = "https://cloud-dm.ourglass.tv/"
}
}
// Promisified JSON getter
func getJson(_ endpoint: String, parameters: [String: AnyObject] = [:]) -> Promise<JSON> {
return firstly {
Alamofire.request( endpoint, method: .get,
parameters: parameters,
headers: [ "Authorization" : "Bearer \(Settings.sharedInstance.userBelliniJWT ?? "")" ] )
.validate()
.responseJSON()
}
.then( on:q){ value in
JSON(value)
}
}
// Promisified JSON Poster
func postJson( _ endpoint: String, data: Dictionary<String, AnyObject> ) -> Promise<JSON> {
return firstly{
Alamofire.request(endpoint, method: .post,
parameters: data,
headers: [ "Authorization" : "Bearer \(Settings.sharedInstance.userBelliniJWT ?? "")" ] )
.validate() //Checks for non-200 response
.responseJSON()
}
.then( on:q){ value in
JSON(value)
}
}
// Promisified JSON Putter
func putJson( _ endpoint: String, data: Dictionary<String, AnyObject> ) -> Promise<JSON> {
return firstly{
Alamofire.request(endpoint, method: .put,
parameters: data,
headers: [ "Authorization" : "Bearer \(Settings.sharedInstance.userBelliniJWT ?? "")" ] )
.validate() //Checks for non-200 response
.responseJSON()
}
.then( on:q){ value in
JSON(value)
}
}
// MARK: VENUES
// Gets all venues.
//
// - Returns: a promise resolving in the response JSON which contains the venues
func getVenues() -> Promise<JSON> {
return getJson( belliniCore + "venue/all" )
}
/// Gets the venues associated with the current user.
///
/// - Returns: a promise resolving in the venues JSON
func getUserVenues() -> Promise<JSON> {
return getJson( belliniCore + "venue/myvenues" )
}
/// Creates a new venue.
///
/// - Parameter venue: the venue to create
/// - Returns: a promise resolving in the new venue's uuid
func addVenue(venue: OGVenue) -> Promise<String> {
let params: [String: Any] = [
"name": venue.name,
"address": [
"street": venue.street,
"street2": venue.street2,
"city": venue.city,
"state": venue.state,
"zip": venue.zip
],
"geolocation": [
"latitude": venue.latitude,
"longitude": venue.longitude
],
"yelpId": venue.yelpId
]
return postJson( belliniCore + "venue", data: params as Dictionary<String, AnyObject>)
.then { response -> String in
guard let uuid = response["uuid"].string else {
throw OGCloudError.malformedJson
}
ASNotification.asahiAddedVenue.issue()
return uuid
}
}
// MARK: USER LOGIN/CREATE
func login(_ email: String, password: String) -> Promise<JSON> {
let loginData = ["email": email, "password": password, "type":"local" ]
return postJson( belliniCore + "auth/login", data: loginData as Dictionary<String, AnyObject>)
.then{ response -> JSON in
Settings.sharedInstance.userEmail = email
ASNotification.asahiLoggedIn.issue()
return response
}
}
func loginAndGetToken(_ email: String, password: String) -> Promise<String> {
return login(email, password: password).then { _ -> Promise<String> in
return self.getToken()
}
.then { token -> Promise<String> in
return self.checkSession().then {_ -> Promise<String> in
return token
}
}
}
func extractUserInfo(_ response: JSON ){
Settings.sharedInstance.userId = response["id"].string
Settings.sharedInstance.userFirstName = response["firstName"].string
Settings.sharedInstance.userLastName = response["lastName"].string
Settings.sharedInstance.userEmail = response["email"].string
Settings.sharedInstance.userIsDeveloper = response["isDev"].boolValue || response["auth"]["ring"].intValue == 1
}
// Checks the current user's JWT and stores user info if it finds it.
//
// - Returns: a promise resolving in the response JSON
func checkJWT() -> Promise<JSON> {
return getJson(belliniCore + "user/checkjwt")
.then { response -> JSON in
self.extractUserInfo(response)
return response
}
}
/// Gets a JWT.
///
/// - Returns: a promise resolving in the JWT
func getToken() -> Promise<String> {
return getJson( belliniCore + "user/jwt")
.then{ response -> String in
guard let token = response["token"].string,
let expires = response["expires"].double else {
throw OGCloudError.malformedJson
}
Settings.sharedInstance.userBelliniJWT = token
Settings.sharedInstance.userBelliniJWTExpiry = expires / 1000.0
return token
}
}
// Checks the current user's session and stores user info if it finds it.
//
// - Returns: a promise resolving in the response JSON
func checkSession() -> Promise<JSON> {
return getJson( belliniCore + "user/checksession")
.then { response -> JSON in
self.extractUserInfo(response)
return response
}
}
/// Changes account information of a user.
///
/// - Parameters:
/// - firstName: new first name
/// - lastName: new last name
/// - email: new email
/// - userId: the user's ID
/// - Returns: a promise resolving in the response JSON
func changeAccountInfo(_ firstName: String, lastName: String, email: String, userId: String) -> Promise<JSON> {
let params: Dictionary<String, Any> = ["email": email, "firstName": firstName, "lastName": lastName]
return putJson( belliniCore + "user/\(userId)", data: params as Dictionary<String, AnyObject>)
}
/// Changes the password of the user.
///
/// - Parameters:
/// - email: user's email
/// - newPassword: new password
/// - Returns: a promise resolving in `true` on success
func changePassword(_ email: String, newPassword: String) -> Promise<Bool> {
let params = ["email": email, "newpass": newPassword]
return postJson( belliniCore + "auth/changePwd", data: params as Dictionary<String, AnyObject>)
.then{ json -> Bool in
return true
}
}
/// Logs out of OurGlass by removing stored information.
func logout() -> Promise<JSON>{
return postJson(belliniCore + "auth/logout", data: Dictionary<String, AnyObject>())
.then{ json -> JSON in
Settings.sharedInstance.userBelliniJWT = nil
Settings.sharedInstance.userBelliniJWTExpiry = nil
Settings.sharedInstance.userId = nil
return json
}
}
/// Invites someone to OurGlass via email.
///
/// - Parameter email: invitee's email
/// - Returns: a promise resolving in the response JSON
func inviteNewUser(_ email: String) -> Promise<JSON> {
let params = ["email": email]
//return postJson(createApiEndpoint("/user/inviteNewUser"), data: params)
return postJson( belliniCore + "user/inviteNewUser",
data: params as Dictionary<String, AnyObject>)
}
// Registers a new user, gets a token, and sets `Settings` user variables.
//
// - Parameters:
// - email: user's email
// - password: user's password
// - user: user's first and last name
// - Returns: a promise resolving in the new user's JWT
func register(_ email: String, password: String, user: Dictionary<String, Any>)
-> Promise<String> {
let params: Dictionary<String, Any> = [
"email":email,
"password":password,
"user": user,
"type":"local"]
return postJson( belliniCore + "auth/addUser",
data: params as Dictionary<String, AnyObject>)
.then{ _ -> Promise<String> in
Settings.sharedInstance.userEmail = email
return self.getToken()
}.then { token -> Promise<String> in
return self.checkSession().then {_ -> Promise<String> in
return token
}
}
}
// MARK: BELLINI DEVICE MANAGER METHODS
/// Finds a device by its registration code.
///
/// - Parameter regCode: registration code
/// - Returns: a promise resolving in the device JSON
func findByRegCode(_ regCode: String) -> Promise<JSON> {
let params = ["regcode": regCode]
return getJson( OGCloud.sharedInstance.belliniDM + "ogdevice/findByRegCode",
parameters: params as [String : AnyObject])
}
/// Changes the name of the device associated with `udid`.
///
/// - Parameters:
/// - udid: device UDID
/// - name: name to give the device
/// - Returns: a promise resolving in the device's `udid`
func changeDeviceName(_ udid: String, name: String) -> Promise<String> {
let params = ["deviceUDID": udid, "name": name]
return postJson( belliniDM + "ogdevice/changeName",
data: params as Dictionary<String, AnyObject>)
.then { _ -> String in
ASNotification.asahiUpdatedDevice.issue()
return udid
}
}
/// Associates a device with a venue.
///
/// - Parameters:
/// - deviceUdid: device UDID
/// - withVenueUuid: venue UUID
/// - Returns: a promise resolving in the JSON response from the call
func associate(deviceUdid: String, withVenueUuid: String) -> Promise<JSON> {
let params = ["deviceUDID": deviceUdid, "venueUUID": withVenueUuid]
return postJson( belliniDM + "ogdevice/associateWithVenue",
data: params as Dictionary<String, AnyObject>)
.then { response -> JSON in
ASNotification.asahiUpdatedDevice.issue()
return response
}
}
/// Gets the devices associated with a venue.
///
/// - Parameter venueUUID: venue's UUID
/// - Returns: a promise resolving in the response JSON
func getDevices(_ venueUUID: String) -> Promise<JSON> {
return getJson( belliniDM + "venue/devices?atVenueUUID=" + venueUUID )
}
// MARK: YELP
/// Performs a Yelp search.
///
/// - Parameters:
/// - location: location of the search
/// - term: search term
/// - Returns: a promise resolving in a JSON array of the results
func yelpSearch(location: String, term: String) -> Promise<JSON> {
let params = ["location": location, "term": term]
return getJson( belliniCore + "venue/yelpSearch",
parameters: params as Dictionary<String, AnyObject>)
}
/// Performs a Yelp search.
///
/// - Parameters:
/// - latitude: latitude of search location
/// - longitude: longitude of search location
/// - term: search term
/// - Returns: a promise resolving in a JSON array of the results
func yelpSearch(latitude: Double, longitude: Double, term: String) -> Promise<JSON> {
let params = ["latitude": latitude, "longitude": longitude, "term": term] as [String : Any]
return getJson( belliniCore + "venue/yelpSearch",
parameters: params as Dictionary<String, AnyObject>)
}
}