-
Notifications
You must be signed in to change notification settings - Fork 3
/
context.go
267 lines (220 loc) · 6.85 KB
/
context.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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
package fire
import (
"encoding/json"
"net/http"
"github.com/256dpi/fire/coal"
"github.com/256dpi/jsonapi"
"github.com/globalsign/mgo/bson"
)
// An Operation indicates the purpose of a yield to a callback in the processing
// flow of an API request by a controller. These operations may occur multiple
// times during a single request.
type Operation int
// All the available operations.
const (
_ Operation = iota
// The list operation will used to authorize the loading of multiple
// resources from a collection.
//
// Note: This operation is also used to load related resources.
List
// The find operation will be used to authorize the loading of a specific
// resource from a collection.
//
// Note: This operation is also used to load a specific related resource.
Find
// The create operation will be used to authorize and validate the creation
// of a new resource in a collection.
Create
// The update operation will be used to authorize the loading and validate
// the updating of a specific resource in a collection.
//
// Note: Updates can include attributes, relationships or both.
Update
// The delete operation will be used to authorize the loading and validate
// the deletion of a specific resource in a collection.
Delete
// The collection action operation will be used to authorize the execution
// of a callback for a collection action.
CollectionAction
// The resource action operation will be used to authorize the execution
// of a callback for a resource action.
ResourceAction
)
// Read will return true when this operations does only read data.
func (o Operation) Read() bool {
return o == List || o == Find
}
// Write will return true when this operation does write data.
func (o Operation) Write() bool {
return o == Create || o == Update || o == Delete
}
// Action will return true when this operation is a collection or resource action.
func (o Operation) Action() bool {
return o == CollectionAction || o == ResourceAction
}
// String returns the name of the operation.
func (o Operation) String() string {
switch o {
case List:
return "List"
case Find:
return "Find"
case Create:
return "Create"
case Update:
return "Update"
case Delete:
return "Delete"
case CollectionAction:
return "CollectionAction"
case ResourceAction:
return "ResourceAction"
}
return ""
}
// A Context provides useful contextual information.
type Context struct {
// Data can be used to carry data between callbacks.
Data Map
// The current operation in process.
//
// Usage: Read Only, Availability: Authorizers
Operation Operation
// The query that will be used during an List, Find, Update, Delete or
// ResourceAction operation to select a list of models or a specific model.
//
// On Find, Update and Delete operations, the "_id" key is preset to the
// resource id, while on forwarded List operations the relationship filter
// is preset.
//
// Usage: Read Only, Availability: Authorizers
// Operations: !Create, !CollectionAction
Selector bson.M
// The filters that will be used during an List, Find, Update, Delete or
// ResourceAction operation to further filter the selection of a list of
// models or a specific model.
//
// On List operations, attribute and relationship filters are preset.
//
// Usage: Append Only, Availability: Authorizers
// Operations: !Create, !CollectionAction
Filters []bson.M
// The sorting that will be used during List.
//
// Usage: No Restriction, Availability: Authorizers
// Operations: List
Sorting []string
// Only the whitelisted readable fields are exposed to the client as
// attributes and relationships.
//
// Usage: Reduce Only, Availability: Authorizers
// Operations: !Delete, !ResourceAction, !CollectionAction
ReadableFields []string
// Only the whitelisted writable fields can be altered by requests.
//
// Usage: Reduce Only, Availability: Authorizers
// Operations: Create, Update
WritableFields []string
// The Model that will be created, updated, deleted or is requested by a
// resource action.
//
// Usage: Modify Only, Availability: Validators
// Operations: Create, Update, Delete, ResourceAction
Model coal.Model
// The models that will will be returned for a List operation.
//
// Usage: Modify Only, Availability: Decorators
// Operations: List
Models []coal.Model
// The document that will be written to the client.
//
// Usage: Modify Only, Availability: Notifiers,
// Operations: !CollectionAction, !ResourceAction
Response *jsonapi.Document
// The store that is used to retrieve and persist the model.
//
// Usage: Read Only
Store *coal.SubStore
// The underlying JSON-API request.
//
// Usage: Read Only
JSONAPIRequest *jsonapi.Request
// The underlying HTTP request.
//
// Note: The path is not updated when a controller forwards a request to
// a related controller.
//
// Usage: Read Only
HTTPRequest *http.Request
// The underlying HTTP response writer. The response writer should only be
// used during collection or resource actions to write a custom response.
//
// Usage: Read Only
ResponseWriter http.ResponseWriter
// The Controller that is managing the request.
//
// Usage: Read Only
Controller *Controller
// The Group that received the request.
//
// Usage: Read Only
Group *Group
// The Tracer used to trace code execution.
//
// Usage: Read Only
Tracer *Tracer
original coal.Model
}
// Query returns the composite query of Selector and Filter.
func (c *Context) Query() bson.M {
return bson.M{"$and": append([]bson.M{c.Selector}, c.Filters...)}
}
// Original will return the stored version of the model. This method is intended
// to be used to calculate the changed fields during an Update operation. Any
// returned error is already marked as fatal. This function will cache and reuse
// loaded models between multiple callbacks.
//
// Note: The method will panic if being used during any other operation than Update.
func (c *Context) Original() (coal.Model, error) {
// begin trace
c.Tracer.Push("fire/Context.Original")
// check operation
if c.Operation != Update {
panic("fire: the original can only be loaded during an update operation")
}
// return cached model
if c.original != nil {
c.Tracer.Pop()
return c.original, nil
}
// create a new model
m := c.Model.Meta().Make()
// read original document
c.Tracer.Push("mgo/Query.One")
c.Tracer.Tag("id", c.Model.ID())
err := c.Store.C(c.Model).FindId(c.Model.ID()).One(m)
if err != nil {
return nil, err
}
c.Tracer.Pop()
// cache model
c.original = coal.Init(m)
// finish trace
c.Tracer.Pop()
return c.original, nil
}
// Respond will encode the provided value as JSON and write it to the client.
func (c *Context) Respond(value interface{}) error {
// encode response
bytes, err := json.Marshal(value)
if err != nil {
return err
}
// write token
_, err = c.ResponseWriter.Write(bytes)
if err != nil {
return err
}
return nil
}