-
Notifications
You must be signed in to change notification settings - Fork 20
/
summary.go
172 lines (146 loc) · 4.92 KB
/
summary.go
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
package runs
import (
"encoding/json"
"fmt"
"github.com/nyaruka/gocommon/jsonx"
"github.com/nyaruka/goflow/assets"
"github.com/nyaruka/goflow/envs"
"github.com/nyaruka/goflow/excellent/types"
"github.com/nyaruka/goflow/flows"
"github.com/nyaruka/goflow/utils"
)
// concrete run summary which might be stored on a trigger or event
type runSummary struct {
uuid flows.RunUUID
flow flows.Flow
flowRef *assets.FlowReference
contact *flows.Contact
status flows.RunStatus
results flows.Results
}
// creates a new run summary from the given run
func newRunSummaryFromRun(run flows.Run) flows.RunSummary {
return &runSummary{
uuid: run.UUID(),
flow: run.Flow(),
flowRef: run.Flow().Reference(),
contact: run.Contact().Clone(),
status: run.Status(),
results: run.Results().Clone(),
}
}
func (r *runSummary) UUID() flows.RunUUID { return r.uuid }
func (r *runSummary) Flow() flows.Flow { return r.flow }
func (r *runSummary) Contact() *flows.Contact { return r.contact }
func (r *runSummary) Status() flows.RunStatus { return r.status }
func (r *runSummary) Results() flows.Results { return r.results }
var _ flows.RunSummary = (*runSummary)(nil)
// wrapper for a run summary (concrete like runSummary or view of child run via interface)
type relatedRunContext struct {
run flows.RunSummary
}
func newRelatedRunContext(run flows.RunSummary) *relatedRunContext {
if utils.IsNil(run) {
return nil
}
return &relatedRunContext{run: run}
}
// Context returns the properties available in expressions for @parent and @child
//
// __default__:text -> the contact name and flow UUID
// uuid:text -> the UUID of the run
// contact:contact -> the contact of the run
// flow:flow -> the flow of the run
// fields:fields -> the custom field values of the run's contact
// urns:urns -> the URN values of the run's contact
// results:any -> the results saved by the run
// status:text -> the current status of the run
//
// @context related_run
func (c *relatedRunContext) Context(env envs.Environment) map[string]types.XValue {
var urns, fields types.XValue
if c.run.Contact() != nil {
urns = flows.ContextFunc(env, c.run.Contact().URNs().MapContext)
fields = flows.Context(env, c.run.Contact().Fields())
}
return map[string]types.XValue{
"__default__": types.NewXText(FormatRunSummary(env, c.run)),
"uuid": types.NewXText(string(c.run.UUID())),
"contact": flows.Context(env, c.run.Contact()),
"flow": flows.Context(env, c.run.Flow()),
"urns": urns,
"fields": fields,
"results": flows.Context(env, c.run.Results()),
"status": types.NewXText(string(c.run.Status())),
// deprecated but used by a lot of flows for @child.run.status as that is what editor has
// been using for subflow splits
"run": types.NewXObject(map[string]types.XValue{
"status": types.NewXText(string(c.run.Status())),
}),
}
}
// FormatRunSummary formats an instance of the RunSummary interface
func FormatRunSummary(env envs.Environment, run flows.RunSummary) string {
var flow, contact string
if run.Flow() != nil {
flow = run.Flow().Name()
} else {
flow = "<missing>"
}
if run.Contact() != nil {
contact = run.Contact().Format(env)
} else {
contact = "<nocontact>"
}
return fmt.Sprintf("%s@%s", contact, flow)
}
//------------------------------------------------------------------------------------------
// JSON Encoding / Decoding
//------------------------------------------------------------------------------------------
type runSummaryEnvelope struct {
UUID flows.RunUUID `json:"uuid" validate:"uuid4"`
Flow *assets.FlowReference `json:"flow" validate:"required,dive"`
Contact json.RawMessage `json:"contact"`
Status flows.RunStatus `json:"status" validate:"required"`
Results flows.Results `json:"results"`
}
// ReadRunSummary reads a run summary from the given JSON
func ReadRunSummary(sessionAssets flows.SessionAssets, data json.RawMessage, missing assets.MissingCallback) (flows.RunSummary, error) {
var err error
e := runSummaryEnvelope{}
if err = utils.UnmarshalAndValidate(data, &e); err != nil {
return nil, err
}
run := &runSummary{
uuid: e.UUID,
flowRef: e.Flow,
status: e.Status,
results: e.Results,
}
// lookup the actual flow
if run.flow, err = sessionAssets.Flows().Get(e.Flow.UUID); err != nil {
missing(e.Flow, err)
}
// read the contact
if e.Contact != nil {
if run.contact, err = flows.ReadContact(sessionAssets, e.Contact, missing); err != nil {
return nil, err
}
}
return run, nil
}
// MarshalJSON marshals this run summary into JSON
func (r *runSummary) MarshalJSON() ([]byte, error) {
envelope := runSummaryEnvelope{}
var err error
envelope.UUID = r.uuid
envelope.Flow = r.flowRef
envelope.Status = r.status
envelope.Results = r.results
if r.contact != nil {
if envelope.Contact, err = r.contact.MarshalJSON(); err != nil {
return nil, err
}
}
return jsonx.Marshal(envelope)
}