COVIDSafe code from version 1.11 (#22)

This commit is contained in:
COVIDSafe Support 2020-09-14 11:23:11 +10:00 committed by GitHub
parent 746841a945
commit a2b6a8bfb5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
65 changed files with 6555 additions and 2216 deletions

View file

@ -13,36 +13,45 @@ class MessageAPI {
static let keyLastApiUpdate = "keyLastApiUpdate"
static let keyLastVersionChecked = "keyLastVersionChecked"
static func getMessagesIfNeeded(completion: @escaping (MessageResponse?, Swift.Error?) -> Void) {
static func getMessagesIfNeeded(completion: @escaping (MessageResponse?, MessageAPIError?) -> Void) {
if shouldGetMessages() {
guard let token = UserDefaults.standard.string(forKey: "deviceTokenForAPN") else {
getMessages(completion: completion)
}
}
static func getMessages(completion: @escaping (MessageResponse?, MessageAPIError?) -> Void) {
guard let token = UserDefaults.standard.string(forKey: "deviceTokenForAPN") else {
completion(nil, .RequestError)
return
}
//Get relevat encounter data
guard let persistentContainer =
EncounterDB.shared.persistentContainer else {
completion(nil, .RequestError)
return
}
//Get relevat encounter data
guard let persistentContainer =
EncounterDB.shared.persistentContainer else {
return
}
let managedContext = persistentContainer.newBackgroundContext()
guard let encounterLastWeekRequest = Encounter.fetchEncountersInLast(days: 7) else {
return
}
}
let managedContext = persistentContainer.newBackgroundContext()
guard let encounterLastWeekRequest = Encounter.fetchEncountersInLast(days: 7) else {
completion(nil, .RequestError)
return
}
do {
//fetch last week encounters count
let weekEncounters = try managedContext.count(for: encounterLastWeekRequest)
let healthcheck = BluetraceManager.shared.isBluetoothOn() && BluetraceManager.shared.isBluetoothAuthorized() ?
healthCheckParamValue.OK :
healthCheckParamValue.POSSIBLE_ERROR
let encounterCheck = weekEncounters > 0 ? healthCheckParamValue.OK : healthCheckParamValue.POSSIBLE_ERROR
do {
//fetch last week encounters count
let weekEncounters = try managedContext.count(for: encounterLastWeekRequest)
let healthcheck = (BluetraceManager.shared.isBluetoothOn() &&
BluetraceManager.shared.isBluetoothAuthorized() &&
weekEncounters > 0 ? healthCheckParamValue.OK : healthCheckParamValue.POSSIBLE_ERROR)
// Make API call to get messages
let messageRequest = MessageRequest(remotePushToken: token, healthcheck: healthcheck)
getMessages(msgRequest: messageRequest, completion: completion)
} catch let error as NSError {
DLog("Could not fetch encounter(s) from db. \(error), \(error.userInfo)")
}
// Make API call to get messages
let messageRequest = MessageRequest(remotePushToken: token, healthcheck: healthcheck, encountershealth: encounterCheck)
getMessages(msgRequest: messageRequest, completion: completion)
} catch let error as NSError {
completion(nil, .RequestError)
DLog("Could not fetch encounter(s) from db. \(error), \(error.userInfo)")
}
}
@ -62,10 +71,10 @@ class MessageAPI {
if lastChecked > 0 {
let lastCheckedDate = Date(timeIntervalSince1970: lastChecked)
let components = calendar.dateComponents([.day], from: lastCheckedDate, to: currentDate)
let components = calendar.dateComponents([.hour], from: lastCheckedDate, to: currentDate)
if let numDays = components.day {
shouldGetMessages = numDays > 0
if let numHours = components.hour {
shouldGetMessages = numHours > 4
}
}
@ -73,25 +82,29 @@ class MessageAPI {
}
private static func getMessages(msgRequest: MessageRequest,
completion: @escaping (MessageResponse?, Swift.Error?) -> Void) {
completion: @escaping (MessageResponse?, MessageAPIError?) -> Void) {
let keychain = KeychainSwift()
guard let apiHost = PlistHelper.getvalueFromInfoPlist(withKey: "API_Host", plistName: "CovidSafe-config") else {
completion(nil, .RequestError)
return
}
guard let token = keychain.get("JWT_TOKEN") else {
completion(nil, nil)
completion(nil, .RequestError)
return
}
let headers: HTTPHeaders = [
"Authorization": "Bearer \(token)"
]
let preferredLanguages = Locale.preferredLanguages.count > 5 ? Locale.preferredLanguages[0...5].joined(separator: ",") : Locale.preferredLanguages.joined(separator: ",")
var params: [String : Any] = [
"os" : "ios-\(UIDevice.current.systemVersion)",
"healthcheck" : msgRequest.healthcheck.rawValue,
"preferredlanguages": Locale.preferredLanguages
]
"encountershealth" : msgRequest.encountershealth.rawValue,
"preferredlanguages": preferredLanguages
]
if let buildString = Bundle.main.version {
params["appversion"] = "\(buildString)"
@ -104,20 +117,35 @@ class MessageAPI {
parameters: params,
headers: headers
).validate().responseDecodable(of: MessageResponse.self) { (response) in
switch response.result {
case .success:
guard let messageResponse = response.value else { return }
// save successful timestamp
let calendar = NSCalendar.current
let currentDate = calendar.startOfDay(for: Date())
switch response.result {
case .success:
guard let messageResponse = response.value else { return }
// save successful timestamp
let minutesToDefer = Int.random(in: 0..<10)
let calendar = NSCalendar.current
let currentDate = Date()
if let deferredDate = calendar.date(byAdding: .minute, value: minutesToDefer, to: currentDate) {
UserDefaults.standard.set(deferredDate.timeIntervalSince1970, forKey: keyLastApiUpdate)
} else {
UserDefaults.standard.set(currentDate.timeIntervalSince1970, forKey: keyLastApiUpdate)
UserDefaults.standard.set(Bundle.main.version, forKey: keyLastVersionChecked)
completion(messageResponse, nil)
case let .failure(error):
completion(nil, error)
}
UserDefaults.standard.set(Bundle.main.version, forKey: keyLastVersionChecked)
completion(messageResponse, nil)
case .failure(_):
guard let statusCode = response.response?.statusCode else {
completion(nil, .UnknownError)
return
}
if (statusCode == 200) {
completion(nil, .ResponseError)
}
if (statusCode >= 400 && statusCode < 500) {
completion(nil, .RequestError)
}
completion(nil, .ServerError)
}
}
}
}
@ -131,6 +159,7 @@ enum healthCheckParamValue: String {
struct MessageRequest {
var remotePushToken: String?
var healthcheck: healthCheckParamValue
var encountershealth: healthCheckParamValue
}
struct MessageResponse: Decodable {
@ -154,3 +183,10 @@ struct Message: Decodable {
case destination
}
}
enum MessageAPIError: Error {
case RequestError
case ResponseError
case ServerError
case UnknownError
}

View file

@ -0,0 +1,105 @@
//
// MessageAPI.swift
// CovidSafe
//
// Copyright © 2020 Australian Government. All rights reserved.
//
import Foundation
import Alamofire
import KeychainSwift
class StatisticsAPI {
static let keyCovidStatistics = "keyCovidStatistics"
static func getStatistics(completion: @escaping (StatisticsResponse?, MessageAPIError?) -> Void) {
let keychain = KeychainSwift()
guard let apiHost = PlistHelper.getvalueFromInfoPlist(withKey: "API_Host", plistName: "CovidSafe-config") else {
completion(nil, .RequestError)
return
}
guard let token = keychain.get("JWT_TOKEN") else {
completion(nil, .RequestError)
return
}
let headers: HTTPHeaders = [
"Authorization": "Bearer \(token)"
]
CovidNetworking.shared.session.request("\(apiHost)/statistics",
method: .get,
headers: headers
).validate().responseDecodable(of: StatisticsResponse.self) { (response) in
switch response.result {
case .success:
guard let statisticsResponse = response.value else { return }
let statsData = try? PropertyListEncoder().encode(statisticsResponse)
UserDefaults.standard.set(statsData, forKey: keyCovidStatistics)
completion(statisticsResponse, nil)
case .failure(_):
var lastStats: StatisticsResponse? = nil
if let savedStats = UserDefaults.standard.data(forKey: keyCovidStatistics) {
lastStats = try? PropertyListDecoder().decode(StatisticsResponse.self, from: savedStats)
}
guard let statusCode = response.response?.statusCode else {
completion(lastStats, .UnknownError)
return
}
if (statusCode == 200) {
completion(lastStats, .ResponseError)
}
if (statusCode >= 400 && statusCode < 500) {
completion(lastStats, .RequestError)
}
completion(lastStats, .ServerError)
}
}
}
}
struct StatisticsResponse: Codable {
let updatedDate: String?
let national: StateTerritoryStatistics?
let act: StateTerritoryStatistics?
let nsw: StateTerritoryStatistics?
let nt: StateTerritoryStatistics?
let qld: StateTerritoryStatistics?
let sa: StateTerritoryStatistics?
let tas: StateTerritoryStatistics?
let vic: StateTerritoryStatistics?
let wa: StateTerritoryStatistics?
enum CodingKeys: String, CodingKey {
case updatedDate = "updated_date"
case national
case act
case nsw
case nt
case qld
case sa
case tas
case vic
case wa
}
}
struct StateTerritoryStatistics: Codable {
let totalCases: Int?
let activeCases: Int?
let newCases: Int?
let recoveredCases: Int?
let deaths: Int?
enum CodingKeys: String, CodingKey {
case totalCases = "total_cases"
case activeCases = "active_cases"
case newCases = "new_cases"
case recoveredCases = "recovered_cases"
case deaths
}
}