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