@@ -28,11 +28,15 @@ cfg_if! {
28
28
}
29
29
30
30
use grid_sdk:: permissions:: PermissionChecker ;
31
- use grid_sdk:: protos:: product_payload:: * ;
32
- use grid_sdk:: protos:: product_state:: Product ;
31
+ use grid_sdk:: protocol:: product:: payload:: {
32
+ Action , ProductCreateAction , ProductDeleteAction , ProductPayload , ProductUpdateAction ,
33
+ } ;
34
+ use grid_sdk:: protocol:: product:: state:: { ProductBuilder , ProductType } ;
35
+
36
+ use grid_sdk:: protos:: FromBytes ;
33
37
34
38
use crate :: addressing:: * ;
35
- use crate :: payload:: { Action , ProductPayload } ;
39
+ use crate :: payload:: validate_payload ;
36
40
use crate :: state:: ProductState ;
37
41
use crate :: validation:: validate_gtin;
38
42
@@ -76,11 +80,16 @@ impl ProductTransactionHandler {
76
80
77
81
fn create_product (
78
82
& self ,
79
- payload : ProductCreateAction ,
80
- mut state : ProductState ,
83
+ payload : & ProductCreateAction ,
84
+ state : & mut ProductState ,
81
85
signer : & str ,
82
86
perm_checker : & PermissionChecker ,
83
87
) -> Result < ( ) , ApplyError > {
88
+ let product_id = payload. identifier ( ) ;
89
+ let owner = payload. owner ( ) ;
90
+ let product_type = payload. product_type ( ) ;
91
+ let properties = payload. properties ( ) ;
92
+
84
93
// Check that the agent submitting the transactions exists in state
85
94
let agent = match state. get_agent ( signer) ? {
86
95
Some ( agent) => agent,
@@ -92,6 +101,9 @@ impl ProductTransactionHandler {
92
101
}
93
102
} ;
94
103
104
+ // Check signing agent's permission
105
+ check_permission ( perm_checker, signer, "can_create_product" ) ?;
106
+
95
107
// Check that the agent has an organization associated with it
96
108
if agent. org_id ( ) . is_empty ( ) {
97
109
return Err ( ApplyError :: InvalidTransaction ( format ! (
@@ -100,47 +112,37 @@ impl ProductTransactionHandler {
100
112
) ) ) ;
101
113
}
102
114
103
- // Check that the agent has the pike permission "can_create_product" for the organization
104
- check_permission ( perm_checker, signer, "can_create_product" ) ?;
115
+ // Check if product exists in state
116
+ if state. get_product ( product_id) ?. is_some ( ) {
117
+ return Err ( ApplyError :: InvalidTransaction ( format ! (
118
+ "Product already exists: {}" ,
119
+ product_id,
120
+ ) ) ) ;
121
+ }
105
122
106
123
// Check if the product type is a GS1 product
107
- if payload . get_product_type ( ) != ProductCreateAction_ProductType :: GS1 {
124
+ if product_type != & ProductType :: GS1 {
108
125
return Err ( ApplyError :: InvalidTransaction (
109
126
"Invalid product type enum for product" . to_string ( ) ,
110
127
) ) ;
111
128
}
112
- // Use this varible to pass in the type correct enum (product_state) on product create
113
- let product_type = grid_sdk:: protos:: product_state:: Product_ProductType :: GS1 ;
114
129
115
130
// Check if product identifier is a valid gtin
116
- let product_id = payload. get_identifier ( ) ;
117
131
if let Err ( e) = validate_gtin ( product_id) {
118
132
return Err ( ApplyError :: InvalidTransaction ( e. to_string ( ) ) ) ;
119
133
}
120
134
121
135
// Check that the org owns the GS1 company prefix in the identifier
122
- let org = match state. get_organization ( payload. get_owner ( ) ) ? {
136
+ let org = match state. get_organization ( payload. owner ( ) ) ? {
123
137
Some ( org) => org,
124
138
None => {
125
139
return Err ( ApplyError :: InvalidTransaction ( format ! (
126
- "The Agents organization does not exist: {}" ,
127
- signer
140
+ "The Agent's organization does not exist: {}" ,
141
+ signer,
128
142
) ) ) ;
129
143
}
130
144
} ;
131
145
132
- // Check if product exists in state
133
- match state. get_product ( product_id) {
134
- Ok ( Some ( _) ) => {
135
- return Err ( ApplyError :: InvalidTransaction ( format ! (
136
- "Product already exists: {}" ,
137
- product_id
138
- ) ) ) ;
139
- }
140
- Ok ( None ) => ( ) ,
141
- Err ( err) => return Err ( err) ,
142
- }
143
-
144
146
/* Check if the agents organization contain GS1 Company Prefix key in its metadata
145
147
(gs1_company_prefixes), and the prefix must match the company prefix in the identifier */
146
148
let gs1_company_prefix_vec = org. metadata ( ) . to_vec ( ) ;
@@ -167,25 +169,32 @@ impl ProductTransactionHandler {
167
169
}
168
170
}
169
171
170
- let mut new_product = Product :: new ( ) ;
171
- new_product. set_identifier ( product_id. to_string ( ) ) ;
172
- new_product. set_owner ( payload. get_owner ( ) . to_string ( ) ) ;
173
- new_product. set_field_type ( product_type) ;
174
- new_product. set_product_values ( protobuf:: RepeatedField :: from_vec (
175
- payload. get_properties ( ) . to_vec ( ) ,
176
- ) ) ;
172
+ let new_product = ProductBuilder :: new ( )
173
+ . with_identifier ( product_id. to_string ( ) )
174
+ . with_owner ( owner. to_string ( ) )
175
+ . with_product_type ( product_type. clone ( ) )
176
+ . with_product_values ( properties. to_vec ( ) )
177
+ . build ( )
178
+ . map_err ( |err| {
179
+ ApplyError :: InvalidTransaction ( format ! ( "Cannot build product: {}" , err) )
180
+ } ) ?;
181
+
182
+ state. set_product ( product_id, new_product) ?;
177
183
178
- state. set_product ( signer, new_product) ?;
179
184
Ok ( ( ) )
180
185
}
181
186
182
187
fn update_product (
183
188
& self ,
184
- payload : ProductUpdateAction ,
185
- mut state : ProductState ,
189
+ payload : & ProductUpdateAction ,
190
+ state : & mut ProductState ,
186
191
signer : & str ,
187
192
perm_checker : & PermissionChecker ,
188
193
) -> Result < ( ) , ApplyError > {
194
+ let product_id = payload. identifier ( ) ;
195
+ let product_type = payload. product_type ( ) ;
196
+ let properties = payload. properties ( ) ;
197
+
189
198
// Check that the agent submitting the transactions exists in state
190
199
let agent = match state. get_agent ( signer) ? {
191
200
Some ( agent) => agent,
@@ -197,22 +206,26 @@ impl ProductTransactionHandler {
197
206
}
198
207
} ;
199
208
209
+ // Check signing agent's permission
210
+ check_permission ( perm_checker, signer, "can_update_product" ) ?;
211
+
212
+ // Check that the agent has an organization associated with it
213
+ if agent. org_id ( ) . is_empty ( ) {
214
+ return Err ( ApplyError :: InvalidTransaction ( format ! (
215
+ "The signing Agent does not have an associated organization: {}" ,
216
+ signer
217
+ ) ) ) ;
218
+ }
219
+
200
220
// Check if the product type is a GS1 product
201
- let product_type = payload. get_product_type ( ) ;
202
- if product_type != ProductUpdateAction_ProductType :: GS1 {
221
+ if product_type != & ProductType :: GS1 {
203
222
return Err ( ApplyError :: InvalidTransaction (
204
223
"Invalid product type enum for product" . to_string ( ) ,
205
224
) ) ;
206
225
}
207
- let product_id = payload. get_identifier ( ) ;
208
-
209
- // Check if product identifier is a valid gtin
210
- if let Err ( e) = validate_gtin ( product_id) {
211
- return Err ( ApplyError :: InvalidTransaction ( e. to_string ( ) ) ) ;
212
- }
213
226
214
227
// Check if product exists
215
- let mut product = match state. get_product ( product_id) {
228
+ let product = match state. get_product ( product_id) {
216
229
Ok ( Some ( product) ) => Ok ( product) ,
217
230
Ok ( None ) => Err ( ApplyError :: InvalidTransaction ( format ! (
218
231
"No product exists: {}" ,
@@ -222,31 +235,44 @@ impl ProductTransactionHandler {
222
235
} ?;
223
236
224
237
// Check if the agent updating the product is part of the organization associated with the product
225
- if product. get_owner ( ) != agent. org_id ( ) {
238
+ if product. owner ( ) != agent. org_id ( ) {
226
239
return Err ( ApplyError :: InvalidTransaction (
227
240
"Invalid organization for the agent submitting this transaction" . to_string ( ) ,
228
241
) ) ;
229
242
}
230
243
231
- // Check that the agent has the pike permission "can_update_product" for the organization
232
- check_permission ( perm_checker, signer, "can_update_product" ) ?;
244
+ // Check if product identifier is a valid gtin
245
+ if let Err ( e) = validate_gtin ( product_id) {
246
+ return Err ( ApplyError :: InvalidTransaction ( e. to_string ( ) ) ) ;
247
+ }
233
248
234
249
// Handle updating the product
235
- let updated_product_values = payload. properties . clone ( ) ;
236
- product. set_product_values ( updated_product_values) ;
250
+ let updated_product = ProductBuilder :: new ( )
251
+ . with_identifier ( product_id. to_string ( ) )
252
+ . with_owner ( product. owner ( ) . to_string ( ) )
253
+ . with_product_type ( product_type. clone ( ) )
254
+ . with_product_values ( properties. to_vec ( ) )
255
+ . build ( )
256
+ . map_err ( |err| {
257
+ ApplyError :: InvalidTransaction ( format ! ( "Cannot build product: {}" , err) )
258
+ } ) ?;
259
+
260
+ state. set_product ( product_id, updated_product) ?;
237
261
238
- state. set_product ( product_id, product) ?;
239
262
Ok ( ( ) )
240
263
}
241
264
242
265
fn delete_product (
243
266
& self ,
244
- payload : ProductDeleteAction ,
245
- mut state : ProductState ,
267
+ payload : & ProductDeleteAction ,
268
+ state : & mut ProductState ,
246
269
signer : & str ,
247
270
perm_checker : & PermissionChecker ,
248
271
) -> Result < ( ) , ApplyError > {
249
- // Check that the agent (signer) submitting the transactions exists in state
272
+ let product_id = payload. identifier ( ) ;
273
+ let product_type = payload. product_type ( ) ;
274
+
275
+ // Check that the agent submitting the transactions exists in state
250
276
let agent = match state. get_agent ( signer) ? {
251
277
Some ( agent) => agent,
252
278
None => {
@@ -257,19 +283,15 @@ impl ProductTransactionHandler {
257
283
}
258
284
} ;
259
285
286
+ // Check signing agent's permission
287
+ check_permission ( perm_checker, signer, "can_delete_product" ) ?;
288
+
260
289
// Check if the product type is a GS1 product
261
- let product_type = payload. get_product_type ( ) ;
262
- if product_type != ProductDeleteAction_ProductType :: GS1 {
290
+ if product_type != & ProductType :: GS1 {
263
291
return Err ( ApplyError :: InvalidTransaction (
264
292
"Invalid product type enum for product" . to_string ( ) ,
265
293
) ) ;
266
294
}
267
- let product_id = payload. get_identifier ( ) ;
268
-
269
- // Check if product identifier is a valid gtin
270
- if let Err ( e) = validate_gtin ( product_id) {
271
- return Err ( ApplyError :: InvalidTransaction ( e. to_string ( ) ) ) ;
272
- }
273
295
274
296
// Check if product exists in state
275
297
let product = match state. get_product ( product_id) {
@@ -281,16 +303,18 @@ impl ProductTransactionHandler {
281
303
Err ( err) => Err ( err) ,
282
304
} ?;
283
305
306
+ // Check if product identifier is a valid gtin
307
+ if let Err ( e) = validate_gtin ( product_id) {
308
+ return Err ( ApplyError :: InvalidTransaction ( e. to_string ( ) ) ) ;
309
+ }
310
+
284
311
// Check that the owner of the products organization is the same as the agent trying to delete the product
285
- if product. get_owner ( ) != agent. org_id ( ) {
312
+ if product. owner ( ) != agent. org_id ( ) {
286
313
return Err ( ApplyError :: InvalidTransaction (
287
314
"Invalid organization for the agent submitting this transaction" . to_string ( ) ,
288
315
) ) ;
289
316
}
290
317
291
- // Check that the agent deleting the product has the "can_delete_product" permission for the organization
292
- check_permission ( perm_checker, signer, "can_delete_product" ) ?;
293
-
294
318
// Delete the product
295
319
state. remove_product ( product_id) ?;
296
320
Ok ( ( ) )
@@ -315,45 +339,31 @@ impl TransactionHandler for ProductTransactionHandler {
315
339
request : & TpProcessRequest ,
316
340
context : & mut dyn TransactionContext ,
317
341
) -> Result < ( ) , ApplyError > {
318
- let payload = ProductPayload :: new ( request. get_payload ( ) ) ;
319
- let payload = match payload {
320
- Err ( e) => return Err ( e) ,
321
- Ok ( payload) => payload,
322
- } ;
323
- let payload = match payload {
324
- Some ( x) => x,
325
- None => {
326
- return Err ( ApplyError :: InvalidTransaction ( String :: from (
327
- "Request must contain a payload" ,
328
- ) ) ) ;
329
- }
330
- } ;
342
+ let payload = ProductPayload :: from_bytes ( request. get_payload ( ) ) . map_err ( |err| {
343
+ ApplyError :: InvalidTransaction ( format ! ( "Cannot build product payload: {}" , err) )
344
+ } ) ?;
331
345
332
- if payload. get_timestamp ( ) . to_string ( ) . is_empty ( ) {
333
- return Err ( ApplyError :: InvalidTransaction ( String :: from (
334
- "Timestamp is not set" ,
335
- ) ) ) ;
336
- }
346
+ validate_payload ( & payload) ?;
337
347
338
348
info ! (
339
349
"Grid Product Payload {:?} {}" ,
340
- payload. get_action ( ) ,
341
- payload. get_timestamp ( )
350
+ payload. action ( ) ,
351
+ payload. timestamp ( ) ,
342
352
) ;
343
353
344
354
let signer = request. get_header ( ) . get_signer_public_key ( ) ;
345
- let state = ProductState :: new ( context) ;
355
+ let mut state = ProductState :: new ( context) ;
346
356
let perm_checker = PermissionChecker :: new ( context) ;
347
357
348
- match payload. get_action ( ) {
349
- Action :: CreateProduct ( create_product_payload) => {
350
- self . create_product ( create_product_payload, state, signer, & perm_checker) ?
358
+ match payload. action ( ) {
359
+ Action :: ProductCreate ( create_product_payload) => {
360
+ self . create_product ( create_product_payload, & mut state, signer, & perm_checker) ?
351
361
}
352
- Action :: UpdateProduct ( update_product_payload) => {
353
- self . update_product ( update_product_payload, state, signer, & perm_checker) ?
362
+ Action :: ProductUpdate ( update_product_payload) => {
363
+ self . update_product ( update_product_payload, & mut state, signer, & perm_checker) ?
354
364
}
355
- Action :: DeleteProduct ( delete_product_payload) => {
356
- self . delete_product ( delete_product_payload, state, signer, & perm_checker) ?
365
+ Action :: ProductDelete ( delete_product_payload) => {
366
+ self . delete_product ( delete_product_payload, & mut state, signer, & perm_checker) ?
357
367
}
358
368
}
359
369
Ok ( ( ) )
0 commit comments