Commit 19ec81a1 authored by Sebastien Robin's avatar Sebastien Robin

hypermedia: enable computer + software navigation

parent d4d16b45
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>from zExceptions import Unauthorized\n
from AccessControl import getSecurityManager\n
if REQUEST is None:\n
raise Unauthorized\n
\n
response = REQUEST.RESPONSE\n
type = \'application/vnd.slapos.org.hal+json; class=slapos.org.computer\'\n
\n
if REQUEST.other[\'method\'] != "GET":\n
response.setStatus(405)\n
return ""\n
elif type != context.Base_handleAcceptHeader([type]):\n
response.setStatus(406)\n
return ""\n
elif context.getPortalType() != "Computer":\n
response.setStatus(403)\n
return ""\n
else:\n
\n
# XXX Set more properties on the document\n
\n
import json\n
result_dict = {\n
\'_class\': \'slapos.org.computer\',\n
\'title\': context.getTitle(),\n
\'_links\': {\n
"self": { "href": context.Base_getRequestUrl(),\n
"type": "application/vnd.slapos.org.hal+json; class=slapos.org.computer" },\n
\n
"http://slapos.org/reg/software": {\n
"href": "%s/Computer_getHateoasSoftwareList" % context.absolute_url(),\n
"type": "application/vnd.slapos.org.hal+json; class=slapos.org.collection",\n
},\n
\n
},\n
}\n
\n
response.setHeader(\'Content-Type\', type)\n
return json.dumps(result_dict)\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>REQUEST=None</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Computer_getHateoas</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>from zExceptions import Unauthorized\n
from AccessControl import getSecurityManager\n
if REQUEST is None:\n
raise Unauthorized\n
\n
response = REQUEST.RESPONSE\n
type = \'application/vnd.slapos.org.hal+json; class=slapos.org.collection\'\n
\n
if REQUEST.other[\'method\'] != "GET":\n
response.setStatus(405)\n
return ""\n
elif type != context.Base_handleAcceptHeader([type]):\n
response.setStatus(406)\n
return ""\n
elif context.getPortalType() != "Computer":\n
response.setStatus(403)\n
return ""\n
else:\n
import json\n
result_dict = {\n
\'_class\': \'slapos.org.collection\',\n
\'_links\': {\n
"self": { "href": context.Base_getRequestUrl(),\n
"type": type },\n
"item": [],\n
},\n
}\n
\n
for sql_obj in context.getPortalObject().portal_catalog(\n
portal_type=\'Software Installation\',\n
aggregate_relative_url=context.getRelativeUrl(),\n
):\n
obj = sql_obj.getObject()\n
result_dict[\'_links\'][\'item\'].append({\n
\'href\': \'%s/Software_getHateoas\' % obj.absolute_url(),\n
\'type\': \'application/vnd.slapos.org.hal+json; class=slapos.org.software\',\n
})\n
\n
response.setHeader(\'Content-Type\', type)\n
return json.dumps(result_dict)\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>REQUEST=None</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Computer_getHateoasSoftwareList</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -81,6 +81,11 @@ else:\n
"method": "POST",\n
"type": "application/json; class=slapos.org.hosting_subscription",\n
},\n
\n
"http://slapos.org/reg/computer": {\n
"href": "%s/Person_getHateoasComputerList" % context.absolute_url(),\n
"type": "application/vnd.slapos.org.hal+json; class=slapos.org.collection",\n
},\n
\n
"http://slapos.org/reg/hosting_subscription": {\n
"href": "%s/Person_getHateoasHostingSubscriptionList" % context.absolute_url(),\n
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>from zExceptions import Unauthorized\n
from AccessControl import getSecurityManager\n
if REQUEST is None:\n
raise Unauthorized\n
\n
response = REQUEST.RESPONSE\n
type = \'application/vnd.slapos.org.hal+json; class=slapos.org.collection\'\n
\n
if REQUEST.other[\'method\'] != "GET":\n
response.setStatus(405)\n
return ""\n
elif type != context.Base_handleAcceptHeader([type]):\n
response.setStatus(406)\n
return ""\n
elif context.getPortalType() != "Person":\n
response.setStatus(403)\n
return ""\n
else:\n
import json\n
result_dict = {\n
\'_class\': \'slapos.org.collection\',\n
\'_links\': {\n
"self": { "href": context.Base_getRequestUrl(),\n
"type": type },\n
"item": [],\n
},\n
}\n
\n
for sql_obj in context.getPortalObject().portal_catalog(\n
portal_type="Computer",\n
source_administration_uid=context.getUid(),\n
):\n
obj = sql_obj.getObject()\n
result_dict[\'_links\'][\'item\'].append({\n
\'href\': \'%s/Computer_getHateoas\' % obj.absolute_url(),\n
\'type\': \'application/vnd.slapos.org.hal+json; class=slapos.org.computer\',\n
})\n
\n
response.setHeader(\'Content-Type\', type)\n
return json.dumps(result_dict)\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>REQUEST=None</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Person_getHateoasComputerList</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>from zExceptions import Unauthorized\n
from AccessControl import getSecurityManager\n
if REQUEST is None:\n
raise Unauthorized\n
\n
response = REQUEST.RESPONSE\n
type = \'application/vnd.slapos.org.hal+json; class=slapos.org.software\'\n
\n
if REQUEST.other[\'method\'] != "GET":\n
response.setStatus(405)\n
return ""\n
elif type != context.Base_handleAcceptHeader([type]):\n
response.setStatus(406)\n
return ""\n
elif context.getPortalType() not in ["Software Installation"]:\n
response.setStatus(403)\n
return ""\n
else:\n
\n
if context.getSlapState() == "stop_requested":\n
state = \'stopped\'\n
elif context.getSlapState() == "start_requested":\n
state = \'started\'\n
else:\n
state = \'destroyed\'\n
\n
import json\n
result_dict = {\n
\'_class\': \'slapos.org.software\',\n
\'title\': context.getTitle(),\n
\'software_url\': context.getUrlString(),\n
\'status\': state,\n
\'_links\': {\n
"self": { "href": context.Base_getRequestUrl(),\n
"type": "application/vnd.slapos.org.hal+json; class=slapos.org.software" },\n
},\n
}\n
\n
response.setHeader(\'Content-Type\', type)\n
return json.dumps(result_dict)\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>REQUEST=None</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Software_getHateoas</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -230,3 +230,112 @@ class TestSlapOSHypermediaPersonScenario(testSlapOSMixin):
self.assertEquals(response.status, 200)
self.assertEquals(response.getheader('Content-Type'), content_type)
news_hal = json.loads(response.read())
# We are going to check computer and software
# First create a computer and a software. We could alternatively later
# create them through hypermedia links
self.login(erp5_person.getReference())
self.portal.portal_slap.requestComputer(
"computer %s" % erp5_person.getReference())
self.tic()
computer = self.portal.portal_catalog(portal_type="Computer",
sort_on=[('creation_date','descending')])[0].getObject()
self.tic()
self.portal.portal_slap.supplySupply("http://foo.com/software.cfg",
computer.getReference(), "available")
self.tic()
self.logout()
#####################################################
# Get user's computer list
#####################################################
content_type = "application/vnd.slapos.org.hal+json; " \
"class=slapos.org.collection"
user_link_dict = user_hal['_links']\
['http://slapos.org/reg/computer']
connection = httplib.HTTPConnection(api_netloc)
connection.request(
method=user_link_dict.get('method', 'GET'),
url=user_link_dict['href'],
headers={
'Authorization': authorization,
'Accept': user_link_dict['type'],
},
body="",
)
response = connection.getresponse()
self.assertEquals(response.status, 200)
self.assertEquals(response.getheader('Content-Type'), content_type)
computer_collection_hal = json.loads(response.read())
#####################################################
# Get user's computer
#####################################################
content_type = "application/vnd.slapos.org.hal+json; " \
"class=slapos.org.computer"
computer_link_dict = computer_collection_hal['_links']\
['item'][0]
connection = httplib.HTTPConnection(api_netloc)
connection.request(
method=computer_link_dict.get('method', 'GET'),
url=computer_link_dict['href'],
headers={
'Authorization': authorization,
'Accept': computer_link_dict['type'],
},
body="",
)
response = connection.getresponse()
self.assertEquals(response.status, 200)
self.assertEquals(response.getheader('Content-Type'), content_type)
computer_hal = json.loads(response.read())
#####################################################
# Get computer's software list
#####################################################
content_type = "application/vnd.slapos.org.hal+json; " \
"class=slapos.org.collection"
computer_link_dict = computer_hal['_links']\
['http://slapos.org/reg/software']
connection = httplib.HTTPConnection(api_netloc)
connection.request(
method=computer_link_dict.get('method', 'GET'),
url=computer_link_dict['href'],
headers={
'Authorization': authorization,
'Accept': computer_link_dict['type'],
},
body="",
)
response = connection.getresponse()
self.assertEquals(response.status, 200)
self.assertEquals(response.getheader('Content-Type'), content_type)
software_collection_hal = json.loads(response.read())
#####################################################
# Get user's software
#####################################################
content_type = "application/vnd.slapos.org.hal+json; " \
"class=slapos.org.software"
software_link_dict = software_collection_hal['_links']\
['item'][0]
connection = httplib.HTTPConnection(api_netloc)
connection.request(
method=software_link_dict.get('method', 'GET'),
url=software_link_dict['href'],
headers={
'Authorization': authorization,
'Accept': software_link_dict['type'],
},
body="",
)
response = connection.getresponse()
self.assertEquals(response.getheader('Content-Type'), content_type)
software_hal = json.loads(response.read())
......@@ -920,3 +920,187 @@ class TestSlapOSInstance_getHateoasNews(testSlapOSMixin):
},
},
})))
class ComputerAndSoftwareMixin(testSlapOSMixin):
script_name = None
def afterSetUp(self):
self.logout()
self.login('ERP5TypeTestCase')
self.erp5_person = self._makePerson()
#self.logout()
self.login(self.erp5_person.getReference())
self.portal.portal_slap.requestComputer(
"computer %s" % self.erp5_person.getReference())
self.tic()
self.computer = self.portal.portal_catalog(portal_type="Computer",
sort_on=[('creation_date','descending')])[0].getObject()
self.tic()
self.portal.portal_slap.supplySupply("http://foo.com/software.cfg",
self.computer.getReference(), "available")
self.tic()
self.software_installation = self.portal.portal_catalog(
portal_type="Software Installation",
aggregate_relative_url=self.computer.getRelativeUrl())[0].getObject()
def _makePerson(self):
new_id = self.generateNewId()
person_user = self.portal.person_module.template_member.\
Base_createCloneDocument(batch_mode=1)
person_user.edit(
title="live_test_%s" % new_id,
reference="live_test_%s" % new_id,
default_email_text="live_test_%s@example.org" % new_id,
)
person_user.validate()
for assignment in person_user.contentValues(portal_type="Assignment"):
assignment.open()
self.tic()
return person_user
def test_REQUEST_mandatory(self):
self.assertRaises(
Unauthorized,
getattr(self.portal, self.script_name)
)
@simulate('Base_getRequestHeader', '*args, **kwargs',
'return "application/vnd+bar"')
def test_wrong_ACCEPT(self):
fake_request = do_fake_request("GET")
result = getattr(self.portal, self.script_name)(REQUEST=fake_request)
self.assertEquals(fake_request.RESPONSE.status, 406)
self.assertEquals(result, "")
def test_bad_method(self):
@simulate('Base_getRequestHeader', '*args, **kwargs',
'return "application/vnd.slapos.org.hal+json; ' \
'class=' + self.json_class + '"')
def check_bad_method(self):
fake_request = do_fake_request("POST")
result = getattr(self.portal, self.script_name)(REQUEST=fake_request)
self.assertEquals(fake_request.RESPONSE.status, 405)
self.assertEquals(result, "")
check_bad_method(self)
def test_request_not_correct_context(self):
@simulate('Base_getRequestHeader', '*args, **kwargs',
'return "application/vnd.slapos.org.hal+json; ' \
'class=' + self.json_class + '"')
def check_not_correct_context(self):
fake_request = do_fake_request("GET")
result = getattr(self.portal, self.script_name)(REQUEST=fake_request)
self.assertEquals(fake_request.RESPONSE.status, 403)
self.assertEquals(result, "")
check_not_correct_context(self)
def checkResult(self, context, expected_data):
@simulate('Base_getRequestUrl', '*args, **kwargs',
'return "http://example.org/foo"')
@simulate('Base_getRequestHeader', '*args, **kwargs',
'return "application/vnd.slapos.org.hal+json; ' \
'class=' + self.json_class + '"')
def check(self):
fake_request = do_fake_request("GET")
result = getattr(context, self.script_name)(REQUEST=fake_request)
self.assertEquals(fake_request.RESPONSE.status, 200)
self.assertEquals(fake_request.RESPONSE.getHeader('Content-Type'),
"application/vnd.slapos.org.hal+json; class=" + self.json_class
)
self.assertEquals(result, json.dumps(expected_data))
check(self)
class TestSlapOSPerson_getHateoasComputerList(ComputerAndSoftwareMixin):
script_name = "Person_getHateoasComputerList"
json_class = "slapos.org.collection"
def test_result(self):
self.checkResult(self.erp5_person, {
'_class': 'slapos.org.collection',
'_links': {
"self": {
"href": "http://example.org/foo",
"type": "application/vnd.slapos.org.hal+json; " \
"class=slapos.org.collection"
},
"item": [{
"href": "%s/Computer_getHateoas" % \
self.computer.absolute_url(),
"type": "application/vnd.slapos.org.hal+json; " \
"class=slapos.org.computer"
}],
},
})
class TestSlapOSComputer_getHateoas(ComputerAndSoftwareMixin):
script_name = "Computer_getHateoas"
json_class = "slapos.org.computer"
def test_result(self):
self.checkResult(self.computer, {
'_class': 'slapos.org.computer',
'title': self.computer.getTitle(),
'_links': {
"self": {
"href": "http://example.org/foo",
"type": "application/vnd.slapos.org.hal+json; " \
"class=slapos.org.computer"
},
"http://slapos.org/reg/software": {
"href": "%s/Computer_getHateoasSoftwareList" % \
self.computer.absolute_url(),
"type": "application/vnd.slapos.org.hal+json; " \
"class=slapos.org.collection"
},
},
})
class TestSlapOSComputer_getSoftwareList(ComputerAndSoftwareMixin):
script_name = "Computer_getHateoasSoftwareList"
json_class = "slapos.org.collection"
def test_result(self):
self.checkResult(self.computer, {
'_class': 'slapos.org.collection',
'_links': {
"self": {
"href": "http://example.org/foo",
"type": "application/vnd.slapos.org.hal+json; " \
"class=slapos.org.collection"
},
"item": [{
"href": "%s/Software_getHateoas" % \
self.software_installation.absolute_url(),
"type": "application/vnd.slapos.org.hal+json; " \
"class=slapos.org.software"
}],
},
})
class TestSlapOSSoftware_getHateoas(ComputerAndSoftwareMixin):
script_name = "Software_getHateoas"
json_class = "slapos.org.software"
def test_result(self):
self.checkResult(self.software_installation, {
'_class': 'slapos.org.software',
'title': self.software_installation.getTitle(),
'status': 'started',
'software_url': "http://foo.com/software.cfg",
'_links': {
"self": {
"href": "http://example.org/foo",
"type": "application/vnd.slapos.org.hal+json; " \
"class=slapos.org.software"
},
},
})
2
\ No newline at end of file
3
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment