Skip to content
This repository has been archived by the owner on Jun 20, 2023. It is now read-only.

Feature/5588 event host/small tasks #2335

Merged
merged 13 commits into from
Apr 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2133,6 +2133,8 @@ Die Angaben werden statistisch ausgewertet, sie werden nicht zu einem Profil ges

"TraceLocations_Configuration_HoursUnit" = "%@ Std.";

"TraceLocations_Configuration_SavingErrorMessage" = "Der QR-Code kann aktuell nicht gespeichert werden. Bitte versuchen Sie es später noch einmal (Fehlercode %@).";

/* Error Reporting */

"ErrorReport_Title" = "Fehlerberichte";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ class EventStore: SecureSQLStore, EventStoringProviding {
Log.info("[EventStore] Update TraceLocations publisher.", log: .localData)

let sql = """
SELECT * FROM TraceLocation;
SELECT * FROM TraceLocation ORDER BY description ASC;
"""

do {
Expand Down
30 changes: 16 additions & 14 deletions src/xcode/ENA/ENA/Source/Scenes/Events/Store/MockEventStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,17 @@ class MockEventStore: EventStoring, EventProviding {

@discardableResult
func createTraceLocation(_ traceLocation: TraceLocation) -> SecureSQLStore.VoidResult {
traceLocationsPublisher.value.append(traceLocation)
traceLocationsPublisher.value = appendTraceLocationAndSort(traceLocation)
return .success(())
}

@discardableResult
func updateTraceLocation(_ traceLocation: TraceLocation) -> SecureSQLStore.VoidResult {
var traceLocations = traceLocationsPublisher.value
guard let oldTraceLocation = (traceLocations.first { $0.id == traceLocation.id }) else {
guard let oldTraceLocation = (traceLocationsPublisher.value.first { $0.id == traceLocation.id }) else {
return .failure(.database(.unknown))
}
let updatedTraceLocation = oldTraceLocation.updatedWith(traceLocation: traceLocation)
traceLocations.removeAll { $0.id == oldTraceLocation.id }
traceLocations.append(updatedTraceLocation)
traceLocationsPublisher.send(traceLocations)
traceLocationsPublisher.value = appendTraceLocationAndSort(updatedTraceLocation)
return .success(())
}

Expand All @@ -49,13 +46,10 @@ class MockEventStore: EventStoring, EventProviding {

@discardableResult
func updateCheckin(_ checkin: Checkin) -> SecureSQLStore.VoidResult {
var checkins = checkinsPublisher.value
guard let oldCheckin = (checkins.first { $0.id == checkin.id }) else {
guard let oldCheckin = (checkinsPublisher.value.first { $0.id == checkin.id }) else {
return .failure(.database(.unknown))
}
let updatedCheckin = oldCheckin.updatedWith(checkin: checkin)
checkins.removeAll { $0.id == oldCheckin.id }
checkins.append(updatedCheckin)
checkinsPublisher.value = appendCheckInAndSort(updatedCheckin)
return .success(())
}
Expand Down Expand Up @@ -133,17 +127,25 @@ class MockEventStore: EventStoring, EventProviding {

var traceWarningPackageMetadatasPublisher = OpenCombine.CurrentValueSubject<[TraceWarningPackageMetadata], Never>([])

/// private helper to simulate DESC order from EventStore

private func appendCheckInAndSort(_ checkIn: Checkin) -> [Checkin] {
var currentValues = checkinsPublisher.value
currentValues.removeAll { $0.id == checkIn.id }
currentValues.append(checkIn)
currentValues.sort { lhCheckIn, rhCheckIn -> Bool in
lhCheckIn.checkinEndDate > rhCheckIn.checkinEndDate
currentValues.sort {
$0.checkinEndDate > $1.checkinEndDate
}
return currentValues
}

private func appendTraceLocationAndSort(_ traceLocation: TraceLocation) -> [TraceLocation] {
var currentValues = traceLocationsPublisher.value
currentValues.append(traceLocation)
currentValues.sort {
$0.description < $1.description
}
return currentValues
}

}

private extension TraceTimeIntervalMatch {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,6 @@ struct TraceLocation {
let defaultCheckInLengthInMinutes: Int?
let cryptographicSeed: Data
let cnPublicKey: Data

var isActive: Bool {
guard let endDate = endDate else {
return true
}

return Date() < endDate
}

var idHash: Data? {
return id.sha256()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,35 @@ class EventStoreTests: XCTestCase {
waitForExpectations(timeout: .medium)
}

func testGIVEN_StoreWithUnsortedTraceLocations_WHEN_TraceLocationPublisherFires_THEN_TraceLocationsAreSortedByDescriptionASC() {
// GIVEN
let store = makeStore(with: makeDatabaseQueue())
let traceLocationOne = makeTraceLocation(id: "1".data(using: .utf8) ?? Data(), description: "B")
let traceLocationTwo = makeTraceLocation(id: "2".data(using: .utf8) ?? Data(), description: "A")

let traceLocationsPublisherExpectation = expectation(description: "traceLocationsPublisher is triggered.")

// WHEN
store.traceLocationsPublisher
.dropFirst(2)
.sink { traceLocations in
traceLocationsPublisherExpectation.fulfill()
XCTAssertEqual(traceLocations.count, 2)

let traceLocationOne = traceLocations[0]
XCTAssertEqual(traceLocationOne.description, "A")

let traceLocationTwo = traceLocations[1]
XCTAssertEqual(traceLocationTwo.description, "B")
}
.store(in: &subscriptions)

// THEN
store.createTraceLocation(traceLocationOne)
store.createTraceLocation(traceLocationTwo)
waitForExpectations(timeout: .medium)
}

func test_When_createCheckin_Then_CheckinWasCreated_And_PublisherWasUpdated() {
let store = makeStore(with: makeDatabaseQueue())
let traceLocationStartDate = Date()
Expand Down Expand Up @@ -970,12 +999,12 @@ class EventStoreTests: XCTestCase {
return store
}

private func makeTraceLocation(id: Data, endDate: Date = Date()) -> TraceLocation {
private func makeTraceLocation(id: Data, description: String = "Some description", endDate: Date = Date()) -> TraceLocation {
TraceLocation(
id: id,
version: 1,
type: .locationTypePermanentOther,
description: "Some description",
description: description,
address: "Some address",
startDate: Date(),
endDate: endDate,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import Foundation
extension TraceLocation {

static func mock(
id: Data = Data(),
id: Data = UUID().uuidString.data(using: .utf8) ?? Data(),
version: Int = 0,
type: TraceLocationType = .locationTypeUnspecified,
description: String = "",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class TraceLocationConfigurationViewController: UIViewController, FooterViewHand
onDismiss()
} catch {
Log.error("Error saving trace location: \(error.localizedDescription)", log: .traceLocation, error: error)
showError(error)
}
}

Expand Down Expand Up @@ -342,4 +343,24 @@ class TraceLocationConfigurationViewController: UIViewController, FooterViewHand
.store(in: &subscriptions)
}

private func showError(_ error: Error) {
let alert = UIAlertController(
title: String(
format: AppStrings.TraceLocations.Configuration.savingErrorMessage,
String(describing: error)
),
message: nil,
preferredStyle: .alert
)

alert.addAction(
UIAlertAction(
title: AppStrings.Common.alertActionOk,
style: .default
)
)

present(alert, animated: true)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class TraceLocationConfigurationViewModel {
enum SavingError: Error {
case cryptographicSeedCreationFailed
case qrCodePayloadCreationFailed
case publicKeyDecodingFailed
case sqlStoreError(SecureSQLStoreError)
}

Expand Down Expand Up @@ -167,8 +168,6 @@ class TraceLocationConfigurationViewModel {
let trimmedDescription = description.trimmingCharacters(in: .whitespacesAndNewlines)
let trimmedAddress = address.trimmingCharacters(in: .whitespacesAndNewlines)

let cnPublicKey = Data() // still TBD according to tech spec

let cwaLocationData = SAP_Internal_Pt_CWALocationData.with {
$0.version = 1
$0.type = SAP_Internal_Pt_TraceLocationType(rawValue: traceLocationType.rawValue) ?? .locationTypeUnspecified
Expand All @@ -177,6 +176,11 @@ class TraceLocationConfigurationViewModel {

let cwaLocationSerializedData = try cwaLocationData.serializedData()

let publicKey = "gwLMzE153tQwAOf2MZoUXXfzWTdlSpfS99iZffmcmxOG9njSK4RTimFOFwDh6t0Tyw8XR01ugDYjtuKwjjuK49Oh83FWct6XpefPi9Skjxvvz53i9gaMmUEc96pbtoaA"
guard let publicKeyData = Data(base64Encoded: publicKey) else {
throw SavingError.publicKeyDecodingFailed
}

let qrCodePayload = SAP_Internal_Pt_QRCodePayload.with {
$0.version = 1

Expand All @@ -189,7 +193,7 @@ class TraceLocationConfigurationViewModel {
$0.vendorData = cwaLocationSerializedData

$0.crowdNotifierData.version = 1
$0.crowdNotifierData.publicKey = cnPublicKey
$0.crowdNotifierData.publicKey = publicKeyData
$0.crowdNotifierData.cryptographicSeed = cryptographicSeed
}

Expand All @@ -208,7 +212,7 @@ class TraceLocationConfigurationViewModel {
endDate: endDate,
defaultCheckInLengthInMinutes: defaultCheckInLengthInMinutes,
cryptographicSeed: cryptographicSeed,
cnPublicKey: cnPublicKey
cnPublicKey: publicKeyData
)
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,13 @@ class TraceLocationCellModel: EventCellModel {
}
.store(in: &subscriptions)

updateForActiveState()
scheduleUpdateTimer()
timePublisher.value = timeString
}

// MARK: - Internal

var isInactiveIconHiddenPublisher = CurrentValueSubject<Bool, Never>(true)
var isActiveContainerViewHiddenPublisher = CurrentValueSubject<Bool, Never>(true)
var isActiveContainerViewHiddenPublisher = CurrentValueSubject<Bool, Never>(false)
var isButtonHiddenPublisher = CurrentValueSubject<Bool, Never>(true)
var durationPublisher = CurrentValueSubject<String?, Never>(nil)
var timePublisher = CurrentValueSubject<String?, Never>(nil)
Expand Down Expand Up @@ -81,58 +80,18 @@ class TraceLocationCellModel: EventCellModel {

private var subscriptions = Set<AnyCancellable>()

private var updateTimer: Timer?

@objc
private func updateForActiveState() {
isInactiveIconHiddenPublisher.value = traceLocation.isActive
isActiveContainerViewHiddenPublisher.value = !traceLocation.isActive

private var timeString: String? {
if let startDate = traceLocation.startDate, let endDate = traceLocation.endDate {
let endsOnSameDay = Calendar.current.isDate(startDate, inSameDayAs: endDate)

let dateFormatter = DateIntervalFormatter()
dateFormatter.dateStyle = traceLocation.isActive && endsOnSameDay ? .none : .short
dateFormatter.dateStyle = endsOnSameDay ? .none : .short
dateFormatter.timeStyle = .short

timePublisher.value = dateFormatter.string(from: startDate, to: endDate)
return dateFormatter.string(from: startDate, to: endDate)
} else {
timePublisher.value = nil
}
}

private func scheduleUpdateTimer() {
updateTimer?.invalidate()
NotificationCenter.default.removeObserver(self, name: UIApplication.didEnterBackgroundNotification, object: nil)
NotificationCenter.default.removeObserver(self, name: UIApplication.didBecomeActiveNotification, object: nil)

guard let endDate = traceLocation.endDate, traceLocation.isActive else {
return
return nil
}

// Schedule new timer.
NotificationCenter.default.addObserver(self, selector: #selector(invalidateUpdatedTimer), name: UIApplication.didEnterBackgroundNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(refreshUpdateTimerAfterResumingFromBackground), name: UIApplication.didBecomeActiveNotification, object: nil)

updateTimer = Timer(fireAt: endDate, interval: 0, target: self, selector: #selector(updateFromTimer), userInfo: nil, repeats: false)
guard let updateTimer = updateTimer else { return }
RunLoop.current.add(updateTimer, forMode: .common)
}

@objc
private func invalidateUpdatedTimer() {
updateTimer?.invalidate()
}

@objc
private func refreshUpdateTimerAfterResumingFromBackground() {
scheduleUpdateTimer()
}

@objc
private func updateFromTimer() {
updateForActiveState()
onUpdate()
}

}
Loading