|
|
|
|
@ -14,38 +14,51 @@ public enum HTTPMethod: String, CaseIterable, Codable { |
|
|
|
|
case delete = "DELETE" |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fileprivate enum ServiceConf: String { |
|
|
|
|
case createAccount = "users/" |
|
|
|
|
case requestToken = "token-auth/" |
|
|
|
|
case logout = "api-token-logout/" |
|
|
|
|
case getUser = "user-by-token/" |
|
|
|
|
case changePassword = "change-password/" |
|
|
|
|
case postDeviceToken = "device-token/" |
|
|
|
|
|
|
|
|
|
var method: HTTPMethod { |
|
|
|
|
switch self { |
|
|
|
|
case .createAccount, .requestToken, .logout, .postDeviceToken: |
|
|
|
|
return .post |
|
|
|
|
case .changePassword: |
|
|
|
|
return .put |
|
|
|
|
default: |
|
|
|
|
return .get |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var requiresToken: Bool? { |
|
|
|
|
switch self { |
|
|
|
|
case .createAccount, .requestToken: |
|
|
|
|
return false |
|
|
|
|
case .getUser, .changePassword, .logout, .postDeviceToken: |
|
|
|
|
return true |
|
|
|
|
// default: |
|
|
|
|
// return nil |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
struct ServiceCall { |
|
|
|
|
var path: String |
|
|
|
|
var method: HTTPMethod |
|
|
|
|
var requiresToken: Bool |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let createAccountCall: ServiceCall = ServiceCall(path: "users", method: .post, requiresToken: false) |
|
|
|
|
let requestTokenCall: ServiceCall = ServiceCall(path: "token-auth/", method: .post, requiresToken: false) |
|
|
|
|
let logoutCall: ServiceCall = ServiceCall(path: "api-token-logout/", method: .post, requiresToken: true) |
|
|
|
|
let getUserCall: ServiceCall = ServiceCall(path: "user-by-token/", method: .get, requiresToken: true) |
|
|
|
|
let changePasswordCall: ServiceCall = ServiceCall(path: "change-password/", method: .put, requiresToken: true) |
|
|
|
|
let postDeviceTokenCall: ServiceCall = ServiceCall(path: "device-token/", method: .post, requiresToken: true) |
|
|
|
|
|
|
|
|
|
//fileprivate enum ServiceConf: String { |
|
|
|
|
// case createAccount = "users/" |
|
|
|
|
// case requestToken = "token-auth/" |
|
|
|
|
// case logout = "api-token-logout/" |
|
|
|
|
// case getUser = "user-by-token/" |
|
|
|
|
// case changePassword = "change-password/" |
|
|
|
|
// case postDeviceToken = "device-token/" |
|
|
|
|
// |
|
|
|
|
// var method: HTTPMethod { |
|
|
|
|
// switch self { |
|
|
|
|
// case .createAccount, .requestToken, .logout, .postDeviceToken: |
|
|
|
|
// return .post |
|
|
|
|
// case .changePassword: |
|
|
|
|
// return .put |
|
|
|
|
// default: |
|
|
|
|
// return .get |
|
|
|
|
// } |
|
|
|
|
// } |
|
|
|
|
// |
|
|
|
|
// var requiresToken: Bool? { |
|
|
|
|
// switch self { |
|
|
|
|
// case .createAccount, .requestToken: |
|
|
|
|
// return false |
|
|
|
|
// case .getUser, .changePassword, .logout, .postDeviceToken: |
|
|
|
|
// return true |
|
|
|
|
//// default: |
|
|
|
|
//// return nil |
|
|
|
|
// } |
|
|
|
|
// } |
|
|
|
|
// |
|
|
|
|
//} |
|
|
|
|
|
|
|
|
|
/// A class used to send HTTP request to the django server |
|
|
|
|
public class Services { |
|
|
|
|
|
|
|
|
|
@ -87,8 +100,8 @@ public class Services { |
|
|
|
|
/// - serviceConf: A instance of ServiceConf |
|
|
|
|
/// - payload: a codable value stored in the body of the request |
|
|
|
|
/// - apiCallId: an optional id referencing an ApiCall |
|
|
|
|
fileprivate func _runRequest<T: Encodable, U: Decodable>(serviceConf: ServiceConf, payload: T, apiCallId: String? = nil) async throws -> U { |
|
|
|
|
var request = try self._baseRequest(conf: serviceConf) |
|
|
|
|
fileprivate func _runRequest<T: Encodable, U: Decodable>(serviceCall: ServiceCall, payload: T, apiCallId: String? = nil) async throws -> U { |
|
|
|
|
var request = try self._baseRequest(call: serviceCall) |
|
|
|
|
request.httpBody = try jsonEncoder.encode(payload) |
|
|
|
|
return try await _runRequest(request, apiCallId: apiCallId) |
|
|
|
|
} |
|
|
|
|
@ -189,8 +202,8 @@ public class Services { |
|
|
|
|
/// Returns the base URLRequest for a ServiceConf instance |
|
|
|
|
/// - Parameters: |
|
|
|
|
/// - conf: a ServiceConf instance |
|
|
|
|
fileprivate func _baseRequest(conf: ServiceConf) throws -> URLRequest { |
|
|
|
|
return try self._baseRequest(servicePath: conf.rawValue, method: conf.method, requiresToken: conf.requiresToken) |
|
|
|
|
fileprivate func _baseRequest(call: ServiceCall) throws -> URLRequest { |
|
|
|
|
return try self._baseRequest(servicePath: call.path, method: call.method, requiresToken: call.requiresToken) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Returns a base request for a path and method |
|
|
|
|
@ -292,7 +305,7 @@ public class Services { |
|
|
|
|
/// - Parameters: |
|
|
|
|
/// - user: A user instance to send to the server |
|
|
|
|
public func createAccount<U: UserPasswordBase, V: UserBase>(user: U) async throws -> V { |
|
|
|
|
return try await _runRequest(serviceConf: .createAccount, payload: user) |
|
|
|
|
return try await _runRequest(serviceCall: createAccountCall, payload: user) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Requests a token for a username and password |
|
|
|
|
@ -300,7 +313,7 @@ public class Services { |
|
|
|
|
/// - username: the account's username |
|
|
|
|
/// - password: the account's password |
|
|
|
|
public func requestToken(username: String, password: String) async throws -> String { |
|
|
|
|
var postRequest = try self._baseRequest(conf: .requestToken) |
|
|
|
|
var postRequest = try self._baseRequest(call: requestTokenCall) |
|
|
|
|
let deviceId = StoreCenter.main.deviceId() |
|
|
|
|
let credentials = Credentials(username: username, password: password, deviceId: deviceId) |
|
|
|
|
postRequest.httpBody = try jsonEncoder.encode(credentials) |
|
|
|
|
@ -328,7 +341,7 @@ public class Services { |
|
|
|
|
/// - password: the account's password |
|
|
|
|
public func login<U: UserBase>(username: String, password: String) async throws -> U { |
|
|
|
|
_ = try await requestToken(username: username, password: password) |
|
|
|
|
let postRequest = try self._baseRequest(conf: .getUser) |
|
|
|
|
let postRequest = try self._baseRequest(call: getUserCall) |
|
|
|
|
let user: U = try await self._runRequest(postRequest) |
|
|
|
|
// StoreCenter.main.setUserUUID(uuidString: user.id) |
|
|
|
|
// StoreCenter.main.setUserName(user.username) |
|
|
|
|
@ -342,7 +355,7 @@ public class Services { |
|
|
|
|
/// - password: the account's password |
|
|
|
|
public func logout() async throws { |
|
|
|
|
let deviceId: String = StoreCenter.main.deviceId() |
|
|
|
|
let _: Empty = try await self._runRequest(serviceConf: .logout, payload: Logout(deviceId: deviceId)) |
|
|
|
|
let _: Empty = try await self._runRequest(serviceCall: logoutCall, payload: Logout(deviceId: deviceId)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// A login method that actually requests a token from the server, and stores the appropriate data for later usage |
|
|
|
|
@ -352,8 +365,8 @@ public class Services { |
|
|
|
|
public func postDeviceToken(deviceToken: Data) async throws { |
|
|
|
|
let tokenString = deviceToken.map { String(format: "%02x", $0) }.joined() |
|
|
|
|
let token = DeviceToken(value: tokenString) |
|
|
|
|
Logger.log("Send device token = \(tokenString)") |
|
|
|
|
let _: DeviceToken = try await self._runRequest(serviceConf: .postDeviceToken, payload: token) |
|
|
|
|
// Logger.log("Send device token = \(tokenString)") |
|
|
|
|
let _: DeviceToken = try await self._runRequest(serviceCall: postDeviceTokenCall, payload: token) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// A method that sends a request to change a user's password |
|
|
|
|
@ -374,7 +387,7 @@ public class Services { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let params = ChangePasswordParams(old_password: oldPassword, new_password1: password1, new_password2: password2) |
|
|
|
|
let response: Token = try await self._runRequest(serviceConf: .changePassword, payload: params) |
|
|
|
|
let response: Token = try await self._runRequest(serviceCall: changePasswordCall, payload: params) |
|
|
|
|
|
|
|
|
|
self._storeToken(username: username, token: response.token) |
|
|
|
|
} |
|
|
|
|
@ -389,6 +402,21 @@ public class Services { |
|
|
|
|
Logger.log("response = \(response)") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// A login method that actually requests a token from the server, and stores the appropriate data for later usage |
|
|
|
|
/// - Parameters: |
|
|
|
|
/// - username: the account's username |
|
|
|
|
/// - password: the account's password |
|
|
|
|
public func deleteAccount() async throws { |
|
|
|
|
guard let userId = StoreCenter.main.userId else { |
|
|
|
|
throw ServiceError.missingUserId |
|
|
|
|
} |
|
|
|
|
let path = "users/\(userId)/" |
|
|
|
|
let deleteAccount = ServiceCall(path: path, method: .delete, requiresToken: true) |
|
|
|
|
|
|
|
|
|
let request = try self._baseRequest(call: deleteAccount) |
|
|
|
|
let _: Empty = try await self._runRequest(request) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Deletes the locally stored token |
|
|
|
|
func deleteToken() throws { |
|
|
|
|
try self.keychainStore.deleteValue() |
|
|
|
|
|