Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
erp5
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
7
Merge Requests
7
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Jobs
Commits
Open sidebar
Jérome Perrin
erp5
Commits
53108963
Commit
53108963
authored
Dec 08, 2017
by
Tomáš Peterka
Committed by
Tomáš Peterka
Dec 08, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[hal_json_style] Improve ListBox value resolution on search results
/reviewed-on
nexedi/erp5!521
parent
a17ce292
Changes
4
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
624 additions
and
97 deletions
+624
-97
bt5/erp5_configurator_standard_trade_template/bt/dependency_list
...5_configurator_standard_trade_template/bt/dependency_list
+2
-1
bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_style/ERP5Document_getHateoas.py
...rtal_skins/erp5_hal_json_style/ERP5Document_getHateoas.py
+443
-88
bt5/erp5_hal_json_style/TestTemplateItem/portal_components/test.erp5.testHalJsonStyle.py
...plateItem/portal_components/test.erp5.testHalJsonStyle.py
+176
-7
bt5/erp5_hal_json_style/bt/test_dependency_list
bt5/erp5_hal_json_style/bt/test_dependency_list
+3
-1
No files found.
bt5/erp5_configurator_standard_trade_template/bt/dependency_list
View file @
53108963
erp5_trade
erp5_trade
erp5_simulation
\ No newline at end of file
bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_style/ERP5Document_getHateoas.py
View file @
53108963
This diff is collapsed.
Click to expand it.
bt5/erp5_hal_json_style/TestTemplateItem/portal_components/test.erp5.testHalJsonStyle.py
View file @
53108963
...
@@ -63,18 +63,30 @@ def simulate(script_id, params_string, code_string):
...
@@ -63,18 +63,30 @@ def simulate(script_id, params_string, code_string):
return
decorated
return
decorated
return
upperWrap
return
upperWrap
def
createIndexedDocument
():
def
wipeFolder
(
folder
):
"""Create a Foo document inside Foo module and pass it as "document" argument into wrapped function."""
folder
.
deleteContent
(
list
(
folder
.
objectIds
()))
transaction
.
commit
()
def
createIndexedDocument
(
quantity
=
1
):
"""Create `quantity` Foo document(s) in Foo module and pass it as `document(_list)` argument into the wrapped function."""
def
decorator
(
func
):
def
decorator
(
func
):
def
wrapped
(
self
,
*
args
,
**
kwargs
):
def
wrapped
(
self
,
*
args
,
**
kwargs
):
wipeFolder
(
self
.
portal
.
foo_module
)
if
quantity
<=
1
:
kwargs
.
update
(
document
=
self
.
_makeDocument
())
kwargs
.
update
(
document
=
self
.
_makeDocument
())
else
:
kwargs
.
update
(
document_list
=
[
self
.
_makeDocument
()
for
_
in
range
(
quantity
)])
self
.
portal
.
portal_caches
.
clearAllCache
()
self
.
portal
.
portal_caches
.
clearAllCache
()
self
.
tic
()
self
.
tic
()
try
:
return
func
(
self
,
*
args
,
**
kwargs
)
return
func
(
self
,
*
args
,
**
kwargs
)
finally
:
wipeFolder
(
self
.
portal
.
foo_module
)
self
.
tic
()
# unindex
return
wrapped
return
wrapped
return
decorator
return
decorator
def
do_fake_request
(
request_method
,
headers
=
None
):
def
do_fake_request
(
request_method
,
headers
=
None
,
data
=
()
):
__version__
=
"0.1"
__version__
=
"0.1"
if
(
headers
is
None
):
if
(
headers
is
None
):
headers
=
{}
headers
=
{}
...
@@ -93,7 +105,25 @@ def do_fake_request(request_method, headers=None):
...
@@ -93,7 +105,25 @@ def do_fake_request(request_method, headers=None):
env
[
'GATEWAY_INTERFACE'
]
=
'CGI/1.1 '
env
[
'GATEWAY_INTERFACE'
]
=
'CGI/1.1 '
env
[
'SCRIPT_NAME'
]
=
'Main'
env
[
'SCRIPT_NAME'
]
=
'Main'
env
.
update
(
headers
)
env
.
update
(
headers
)
return
HTTPRequest
(
StringIO
.
StringIO
(),
env
,
HTTPResponse
())
body_stream
=
StringIO
.
StringIO
()
# for some mysterious reason QUERY_STRING does not get parsed into data fields
if
data
and
request_method
.
upper
()
==
'GET'
:
# see: GET http://www.cgi101.com/book/ch3/text.html
env
[
'QUERY_STRING'
]
=
'&'
.
join
(
'{}={}'
.
format
(
urllib
.
quote_plus
(
key
),
urllib
.
quote
(
value
))
for
key
,
value
in
data
)
if
data
and
request_method
.
upper
()
==
'POST'
:
# see: POST request body https://tools.ietf.org/html/rfc1866#section-8.2.1
env
[
'CONTENT_TYPE'
]
=
'application/x-www-form-urlencoded'
for
key
,
value
in
data
:
body_stream
.
write
(
'{}={!s}&'
.
format
(
urllib
.
quote_plus
(
key
),
urllib
.
quote
(
value
)))
return
HTTPRequest
(
body_stream
,
env
,
HTTPResponse
())
from
Products.ERP5Type.tests.ERP5TypeTestCase
import
ERP5TypeTestCase
from
Products.ERP5Type.tests.ERP5TypeTestCase
import
ERP5TypeTestCase
...
@@ -952,6 +982,145 @@ class TestERP5Document_getHateoas_mode_search(ERP5HALJSONStyleSkinsMixin):
...
@@ -952,6 +982,145 @@ class TestERP5Document_getHateoas_mode_search(ERP5HALJSONStyleSkinsMixin):
mode
=
"search"
,
mode
=
"search"
,
default_param_json
=
'eyJcdTAwZWEiOiAiXHUwMGU4In0='
)
default_param_json
=
'eyJcdTAwZWEiOiAiXHUwMGU4In0='
)
@
simulate
(
'Base_getRequestUrl'
,
'*args, **kwargs'
,
'return "http://example.org/bar"'
)
@
simulate
(
'Base_getRequestHeader'
,
'*args, **kwargs'
,
'return "application/hal+json"'
)
@
simulate
(
'Test_listObjects'
,
'*args, **kwargs'
,
"""
from Products.PythonScripts.standard import Object
return [Object(debit_price=1000.00, credit_price=100.00),
Object(debit_price=10.00, credit_price=0.00)]
"""
)
@
simulate
(
'Test_listProducts'
,
'*args, **kwargs'
,
"""
return context.getPortalObject().foo_module.values()
"""
)
@
simulate
(
'Test_listCatalog'
,
'*args, **kwargs'
,
"""
return context.getPortalObject().portal_catalog(portal_type='Foo', sort_on=[('id', 'ASC')])
"""
)
@
createIndexedDocument
(
quantity
=
2
)
@
changeSkin
(
'Hal'
)
def
test_getHateoas_exotic_search_results
(
self
,
document_list
):
"""Test that ingestion of `list_method` result does not fail.
The only limit for the result of `list_method` is that it should be an iterable.
Practically, because we code in python, it can be any object.
"""
fake_request
=
do_fake_request
(
"GET"
)
result
=
self
.
portal
.
web_site_module
.
hateoas
.
ERP5Document_getHateoas
(
REQUEST
=
fake_request
,
mode
=
"search"
,
local_roles
=
[
"Assignor"
,
"Assignee"
],
list_method
=
'Test_listObjects'
,
select_list
=
[
'credit_price'
,
'debit_price'
]
)
self
.
assertEquals
(
fake_request
.
RESPONSE
.
status
,
200
)
self
.
assertEquals
(
fake_request
.
RESPONSE
.
getHeader
(
'Content-Type'
),
"application/hal+json"
)
result_dict
=
json
.
loads
(
result
)
self
.
assertEqual
(
len
(
result_dict
[
'_embedded'
][
'contents'
]),
2
)
self
.
assertEqual
(
result_dict
[
'_embedded'
][
'contents'
][
0
][
'debit_price'
],
1000.0
)
self
.
assertEqual
(
result_dict
[
'_embedded'
][
'contents'
][
0
][
'credit_price'
],
100.0
)
self
.
assertEqual
(
result_dict
[
'_embedded'
][
'contents'
][
1
][
'debit_price'
],
10.0
)
self
.
assertEqual
(
result_dict
[
'_embedded'
][
'contents'
][
1
][
'credit_price'
],
0.0
)
# Render a Document using Form Field template (only for field 'id')
result
=
self
.
portal
.
web_site_module
.
hateoas
.
ERP5Document_getHateoas
(
REQUEST
=
fake_request
,
mode
=
"search"
,
local_roles
=
[
"Assignor"
,
"Assignee"
],
list_method
=
'Test_listProducts'
,
select_list
=
[
'id'
],
form_relative_url
=
'portal_skins/erp5_ui_test/FooModule_viewFooList/listbox'
)
result_dict
=
json
.
loads
(
result
)
self
.
assertEqual
(
2
,
len
(
result_dict
[
'_embedded'
][
'contents'
]))
self
.
assertIn
(
"field_listbox"
,
result_dict
[
'_embedded'
][
'contents'
][
0
][
'id'
][
'key'
])
self
.
assertEqual
(
"StringField"
,
result_dict
[
'_embedded'
][
'contents'
][
0
][
'id'
][
'type'
])
self
.
assertEqual
(
document_list
[
0
].
getId
(),
result_dict
[
'_embedded'
][
'contents'
][
0
][
'id'
][
'default'
])
self
.
assertIn
(
"field_listbox"
,
result_dict
[
'_embedded'
][
'contents'
][
1
][
'id'
][
'key'
])
self
.
assertEqual
(
"StringField"
,
result_dict
[
'_embedded'
][
'contents'
][
1
][
'id'
][
'type'
])
self
.
assertEqual
(
document_list
[
1
].
getId
(),
result_dict
[
'_embedded'
][
'contents'
][
1
][
'id'
][
'default'
])
# Test rendering without form template of attribute, getterm and a script
result
=
self
.
portal
.
web_site_module
.
hateoas
.
ERP5Document_getHateoas
(
REQUEST
=
fake_request
,
mode
=
"search"
,
local_roles
=
[
"Assignor"
,
"Assignee"
],
list_method
=
'Test_listCatalog'
,
select_list
=
[
'title'
,
'Foo_getLocalTitle'
,
'getTotalQuantity'
]
# property, Script, method
)
result_dict
=
json
.
loads
(
result
)
self
.
assertEqual
(
len
(
result_dict
[
'_embedded'
][
'contents'
]),
2
)
self
.
assertEqual
(
result_dict
[
'_embedded'
][
'contents'
][
0
][
'title'
].
encode
(
'utf-8'
),
document_list
[
0
].
getTitle
())
self
.
assertEqual
(
result_dict
[
'_embedded'
][
'contents'
][
0
][
'Foo_getLocalTitle'
],
None
)
self
.
assertEqual
(
result_dict
[
'_embedded'
][
'contents'
][
0
][
'getTotalQuantity'
],
0
)
self
.
assertEqual
(
result_dict
[
'_embedded'
][
'contents'
][
1
][
'title'
].
encode
(
'utf-8'
),
document_list
[
1
].
getTitle
())
self
.
assertEqual
(
result_dict
[
'_embedded'
][
'contents'
][
1
][
'Foo_getLocalTitle'
],
None
)
self
.
assertEqual
(
result_dict
[
'_embedded'
][
'contents'
][
1
][
'getTotalQuantity'
],
0
)
class
TestERP5PDM_getHateoas_mode_search
(
ERP5HALJSONStyleSkinsMixin
):
"""This class allows ticking for Movements to be picked up by activities."""
def
afterSetUp
(
self
):
self
.
folder
=
getattr
(
self
.
portal
,
'test_hal_json_folder'
,
None
)
if
self
.
folder
is
None
:
self
.
folder
=
self
.
portal
.
newContent
(
portal_type
=
'Folder'
,
id
=
'test_hal_json_folder'
)
self
.
vendor
=
self
.
portal
.
organisation_module
.
newContent
(
portal_type
=
'Organisation'
,
title
=
"Test Vendor"
)
self
.
buyer
=
self
.
portal
.
organisation_module
.
newContent
(
portal_type
=
'Organisation'
,
title
=
"Test Buyer"
)
self
.
product
=
self
.
portal
.
product_module
.
newContent
(
portal_type
=
'Product'
,
title
=
"Resource"
)
self
.
movement
=
self
.
folder
.
newContent
(
portal_type
=
'Dummy Movement'
)
self
.
movement
.
edit
(
resource_value
=
self
.
product
,
destination_section_value
=
self
.
buyer
,
source_section_value
=
self
.
vendor
,
destination_value
=
self
.
buyer
,
source_value
=
self
.
vendor
,
)
self
.
tic
()
def
beforeTearDown
(
self
):
self
.
portal
.
organisation_module
.
deleteContent
([
self
.
buyer
.
getId
(),
self
.
vendor
.
getId
()])
self
.
portal
.
product_module
.
deleteContent
(
self
.
product
.
getId
())
wipeFolder
(
self
.
folder
)
self
.
portal
.
deleteContent
(
self
.
folder
.
getId
())
@
simulate
(
'Base_getRequestUrl'
,
'*args, **kwargs'
,
'return "http://example.org/bar"'
)
@
simulate
(
'Base_getRequestHeader'
,
'*args, **kwargs'
,
'return "application/hal+json"'
)
@
simulate
(
'Organisation_listInventory'
,
'*args, **kwargs'
,
"""
portal = context.getPortalObject()
return portal.portal_simulation.getInventoryList(section_uid=context.getUid())
"""
)
@
changeSkin
(
'Hal'
)
def
test_getHateoas_getInventoryasListMethod
(
self
):
"""Test that `list_method` can resolve dynamic objects from Inventory management.
This test has dependency on erp5_pdm, erp5_trade and base_trade_categories!
"""
fake_request
=
do_fake_request
(
"GET"
)
result
=
self
.
portal
.
web_site_module
.
hateoas
.
ERP5Document_getHateoas
(
REQUEST
=
fake_request
,
mode
=
"search"
,
relative_url
=
self
.
vendor
.
getRelativeUrl
(),
local_roles
=
[
"Assignor"
,
"Assignee"
],
list_method
=
'Organisation_listInventory'
,
select_list
=
[
'total_price'
,
'total_quantity'
]
)
self
.
assertEquals
(
fake_request
.
RESPONSE
.
status
,
200
)
self
.
assertEquals
(
fake_request
.
RESPONSE
.
getHeader
(
'Content-Type'
),
"application/hal+json"
)
result_dict
=
json
.
loads
(
result
)
self
.
assertEqual
(
len
(
result_dict
[
'_embedded'
][
'contents'
]),
1
)
self
.
assertEqual
(
result_dict
[
'_embedded'
][
'contents'
][
0
][
'total_price'
],
0
)
self
.
assertEqual
(
result_dict
[
'_embedded'
][
'contents'
][
0
][
'total_quantity'
],
0
)
class
TestERP5Document_getHateoas_mode_bulk
(
ERP5HALJSONStyleSkinsMixin
):
class
TestERP5Document_getHateoas_mode_bulk
(
ERP5HALJSONStyleSkinsMixin
):
@
simulate
(
'Base_getRequestHeader'
,
'*args, **kwargs'
,
@
simulate
(
'Base_getRequestHeader'
,
'*args, **kwargs'
,
...
@@ -963,6 +1132,7 @@ class TestERP5Document_getHateoas_mode_bulk(ERP5HALJSONStyleSkinsMixin):
...
@@ -963,6 +1132,7 @@ class TestERP5Document_getHateoas_mode_bulk(ERP5HALJSONStyleSkinsMixin):
self
.
assertEquals
(
fake_request
.
RESPONSE
.
status
,
405
)
self
.
assertEquals
(
fake_request
.
RESPONSE
.
status
,
405
)
self
.
assertEquals
(
result
,
""
)
self
.
assertEquals
(
result
,
""
)
@
simulate
(
'Base_getRequestUrl'
,
'*args, **kwargs'
,
@
simulate
(
'Base_getRequestUrl'
,
'*args, **kwargs'
,
'return "http://example.org/bar"'
)
'return "http://example.org/bar"'
)
@
simulate
(
'Base_getRequestHeader'
,
'*args, **kwargs'
,
@
simulate
(
'Base_getRequestHeader'
,
'*args, **kwargs'
,
...
@@ -1072,7 +1242,6 @@ class TestERP5Document_getHateoas_mode_worklist(ERP5HALJSONStyleSkinsMixin):
...
@@ -1072,7 +1242,6 @@ class TestERP5Document_getHateoas_mode_worklist(ERP5HALJSONStyleSkinsMixin):
self
.
assertEquals
(
fake_request
.
RESPONSE
.
status
,
405
)
self
.
assertEquals
(
fake_request
.
RESPONSE
.
status
,
405
)
self
.
assertEquals
(
result
,
""
)
self
.
assertEquals
(
result
,
""
)
@
simulate
(
'Base_getRequestUrl'
,
'*args, **kwargs'
,
@
simulate
(
'Base_getRequestUrl'
,
'*args, **kwargs'
,
'return "http://example.org/bar"'
)
'return "http://example.org/bar"'
)
@
simulate
(
'Base_getRequestHeader'
,
'*args, **kwargs'
,
@
simulate
(
'Base_getRequestHeader'
,
'*args, **kwargs'
,
...
...
bt5/erp5_hal_json_style/bt/test_dependency_list
View file @
53108963
erp5_full_text_mroonga_catalog
erp5_full_text_mroonga_catalog
erp5_ui_test_core
erp5_ui_test_core
erp5_ui_test
erp5_ui_test
erp5_dummy_movement
erp5_configurator_standard_trade_template
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment