-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathUserActivityTaskHandler.swift
169 lines (142 loc) · 4.86 KB
/
UserActivityTaskHandler.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
//
// UserActivityTaskHandler.swift
// C-Tracker-SCCS
//
// Created by Pascal Pfiffner on 15.03.17.
// Copyright © 2017 SCCS. All rights reserved.
//
import Foundation
import SMART
/**
This handler submits the following resources to the profile manager's data server if a survey task is completed, after referencing an
"anonymous" Patient to the resource's subjects (see `ProfileManager.anonPatientResource`):
1. a QuestionnaireResponse resources that come out of a survey task
2. pulls latest bio data from the manager's user and creates Observation resources
3. samples activity of the latest `ProfileManager.settings.activitySampleNumDays` days and creates a QuestionnaireResponse with that data,
if more than 0 days are specified
*/
open class UserActivityTaskHandler: ProfileTaskHandler {
/// The manager this handler belongs to.
public unowned let manager: ProfileManager
/// Where on the local filesystem the Core Motion reporter is storing data; only need to set if it's relevant to the manager, i.e. if
/// it is supposed to automatically sample and submit activity data with questionnaires.
public var motionReporterStore: URL?
/// The custom core motion interpreter, if the default one is not desired.
public var coreMotionInterpreter: CoreMotionActivityInterpreter?
public required init(manager: ProfileManager) {
self.manager = manager
}
open func handle(task: UserTask) {
guard let user = manager.user else {
c3_warn("The profile manager does not have a user, cannot handle task")
return
}
if user.isSampleUser {
c3_logIfDebug("This is a sample user, not submitting any task data")
#if DEBUG
if .survey == task.type, let resource = task.resultResource {
debugPrint(resource)
}
#endif
return
}
// survey completed: submit, submit current user data, sample activity data and submit as well
if .survey == task.type {
guard let server = manager.dataServer else {
c3_warn("Task completed but no dataServer set on profileManager, cannot submit!")
return
}
server.ready { error in
if let error = error {
c3_warn("Task completed but dataServer is not ready: \(error)")
return
}
self.submitResult(of: task, for: user, to: server)
self.submitLatestSubjectData(for: user, to: server)
self.sampleAndSubmitLatestActivityData(for: user, to: server)
}
}
}
// MARK: - Submit Task Data
func submitResult(of task: UserTask, for user: User, to server: Server) {
c3_logIfDebug("Task completed, submitting")
guard let resource = task.resultResource as? QuestionnaireResponse else {
c3_warn("Task completed but no questionnaire response resource received, have this: \(task.resultResource?.description ?? "nil")")
return
}
do {
resource.subject = try manager.anonPatientResource(for: user).asRelativeReference()
}
catch {
c3_warn("Failed to reference resource subject: \(error)")
}
resource.create(server) { error in
if let error = error {
c3_warn("Failed to submit questionnaire response resource: \(error)")
}
}
#if DEBUG
debugPrint(resource)
#endif
}
// MARK: - Health Data
func submitLatestSubjectData(for user: User, to server: Server) {
let (_, observationsTuple) = user.c3_asPatientAndObservations()
guard let observations = observationsTuple, observations.count > 0 else {
c3_logIfDebug("No observations from user \(user), nothing to submit")
return
}
for observation in observations {
observation.create(server) { error in
if let error = error {
c3_logIfDebug("Failed to send subject observation: \(error)")
}
}
#if DEBUG
debugPrint(observation)
#endif
}
}
// MARK: - Activity Data
var activityCollector: ActivityCollector?
func sampleAndSubmitLatestActivityData(for user: User, to server: Server) {
guard let path = motionReporterStore?.path else {
return
}
guard nil == activityCollector else {
c3_logIfDebug("Already collecting activity, skipping")
return
}
let days = manager.settings?.activitySampleNumDays ?? 0
guard days > 0 else {
return
}
var reference: Reference?
do {
reference = try manager.anonPatientResource(for: user).asRelativeReference()
}
catch {
c3_warn("Failed to reference resource subject: \(error)")
}
activityCollector = ActivityCollector(coreMotionDBPath: path, coreMotionInterpreter: coreMotionInterpreter)
activityCollector?.resourceForAllActivity(ofLastDays: days) { response, error in
if let resource = response {
resource.subject = reference
resource.create(server) { error in
if let error = error {
c3_logIfDebug("Failed to submit activity data resource: \(error)")
}
}
#if DEBUG
debugPrint(resource)
#endif
}
else if let error = error {
c3_logIfDebug("Error receiving activity data: \(error)")
}
else {
c3_logIfDebug("Did not receive any activity data")
}
}
}
}