Doctests¶
AUTH¶
Running this test from the buildout directory:
bin/test test_doctests -t auth
Test Setup¶
Needed Imports:
>>> import transaction
>>> from plone.app.testing import setRoles
>>> from plone.app.testing import TEST_USER_ID
>>> from plone.app.testing import TEST_USER_PASSWORD
Functional Helpers:
>>> def get(url):
... browser.open("{}/{}".format(api_url, url))
... return browser.contents
Variables:
>>> portal = self.portal
>>> portal_url = portal.absolute_url()
>>> api_url = "{}/@@API/senaite/v1".format(portal_url)
>>> browser = self.getBrowser()
>>> setRoles(portal, TEST_USER_ID, ["LabManager", "Manager"])
>>> transaction.commit()
Login¶
User can login with a GET:
>>> get("login?__ac_name={}&__ac_password={}".format(TEST_USER_ID, TEST_USER_PASSWORD))
'..."authenticated": true...'
And once logged, auth route does not rise an unauthorized response 401:
>>> get("auth")
'{"_runtime": ...}'
Logout¶
User can logout easily too:
>>> get("users/logout")
'..."authenticated": false...'
And auth route rises an unauthorized response 401:
>>> get("auth")
Traceback (most recent call last):
[...]
HTTPError: HTTP Error 401: Unauthorized
VERSION¶
Running this test from the buildout directory:
bin/test test_doctests -t version
Test Setup¶
Needed Imports:
>>> import transaction
>>> from plone.app.testing import setRoles
>>> from plone.app.testing import TEST_USER_ID
>>> from plone.app.testing import TEST_USER_PASSWORD
Functional Helpers:
>>> def logout():
... browser.open(portal_url + "/logout")
... assert("You are now logged out" in browser.contents)
Variables:
>>> portal = self.portal
>>> portal_url = portal.absolute_url()
>>> browser = self.getBrowser()
>>> setRoles(portal, TEST_USER_ID, ["LabManager", "Manager"])
>>> transaction.commit()
JSON API:
>>> api_base_url = portal_url + "/@@API/senaite/v1"
Authenticated user¶
The version route should be visible to authenticated users:
>>> browser.open(api_base_url + "/version")
>>> browser.contents
'{"url": "http://nohost/plone/@@API/senaite/v1/version", "date": "...", "version": ..., "_runtime": ...}'
Unauthenticated user¶
Log out:
>>> logout()
The version route should be visible to unauthenticated users too:
>>> browser.open(api_base_url + "/version")
>>> browser.contents
'{"url": "http://nohost/plone/@@API/senaite/v1/version", "date": "...", "version": ..., "_runtime": ...}'
USERS¶
Running this test from the buildout directory:
bin/test test_doctests -t users
Test Setup¶
Needed Imports:
>>> import json
>>> import transaction
>>> from plone.app.testing import setRoles
>>> from plone.app.testing import TEST_USER_ID
>>> from plone.app.testing import TEST_USER_PASSWORD
Functional Helpers:
>>> def get(url):
... browser.open("{}/{}".format(api_url, url))
... return browser.contents
Variables:
>>> portal = self.portal
>>> portal_url = portal.absolute_url()
>>> api_url = "{}/@@API/senaite/v1".format(portal_url)
>>> browser = self.getBrowser()
>>> setRoles(portal, TEST_USER_ID, ["LabManager", "Manager"])
>>> transaction.commit()
Get all users¶
The API is capable to find SENAITE users:
>>> response = get("users")
>>> data = json.loads(response)
>>> items = data.get("items")
>>> sorted(map(lambda it: it["username"], items))
[u'test-user', u'test_analyst_0',...u'test_labmanager_1']
And for each user, the roles and groups are displayed:
>>> analyst = filter(lambda it: it["username"] == "test_analyst_0", items)[0]
>>> sorted(analyst.get("roles"))
[u'Analyst', u'Authenticated', u'Member']
>>> sorted(analyst.get("groups"))
[u'Analysts', u'AuthenticatedUsers']
As well as other properties:
>>> sorted(analyst.keys())
[u'api_url', u'authenticated', u'description', u'email', ...]
Get current user¶
Current user can also be retrieved easily:
>>> response = get("users/current")
>>> data = json.loads(response)
>>> data.get("count")
1
>>> current = data.get("items")[0]
>>> current.get("username")
u'test-user'
and includes all properties too:
>>> sorted(current.keys())
[u'api_url', u'authenticated', u'description', u'email',...u'groups',...u'roles'...]
Get a single user¶
A single user can be retrieved too:
>>> get("users/test_analyst_0")
'..."username": "test_analyst_0"...'
CATALOGS¶
Running this test from the buildout directory:
bin/test test_doctests -t catalogs
Test Setup¶
Needed Imports:
>>> import json
>>> import transaction
>>> from plone.app.testing import setRoles
>>> from plone.app.testing import TEST_USER_ID
>>> from plone.app.testing import TEST_USER_PASSWORD
Functional Helpers:
>>> def get(url):
... browser.open("{}/{}".format(api_url, url))
... return browser.contents
Variables:
>>> portal = self.portal
>>> portal_url = portal.absolute_url()
>>> api_url = "{}/@@API/senaite/v1".format(portal_url)
>>> browser = self.getBrowser()
>>> setRoles(portal, TEST_USER_ID, ["LabManager", "Manager"])
>>> transaction.commit()
Get all catalogs¶
senaite.jsonapi is capable to retrieve information about the catalogs registered in the system:
>>> response = get("catalogs")
>>> data = json.loads(response)
>>> items = data.get("items")
>>> catalog_ids = map(lambda cat: cat["id"], items)
>>> sorted(catalog_ids)
[u'auditlog_catalog', ..., u'portal_catalog']
Catalogs for internal use are not included though:
>>> "uid_catalog" in catalog_ids
False
>>> "reference_catalog" in catalog_ids
False
For each catalog, indexes, schema fields and allowed portal types are listed:
>>> cat = filter(lambda it: it["id"]=="portal_catalog", items)[0]
>>> sorted(cat.get("indexes"))
[u'Analyst', u'Creator', u'Date', ...]
>>> sorted(cat.get("schema"))
[u'Analyst', u'CreationDate', u'Creator',...]
>>> sorted(cat.get("portal_types"))
[u'ARReport', u'ARTemplate', u'ARTemplates',...]
Get a single catalog¶
A single catalog can also be retrieved by it’s id:
>>> response = get("catalogs/portal_catalog")
>>> cat = json.loads(response)
>>> sorted(cat.get("indexes"))
[u'Analyst', u'Creator', u'Date', ...]
>>> sorted(cat.get("schema"))
[u'Analyst', u'CreationDate', u'Creator',...]
>>> sorted(cat.get("portal_types"))
[u'ARReport', u'ARTemplate', u'ARTemplates',...]
SEARCH¶
Running this test from the buildout directory:
bin/test test_doctests -t search
Test Setup¶
Needed Imports:
>>> import json
>>> import transaction
>>> from plone.app.testing import setRoles
>>> from plone.app.testing import TEST_USER_ID
>>> from plone.app.testing import TEST_USER_PASSWORD
>>> from bika.lims import api
Functional Helpers:
>>> def get(url):
... browser.open("{}/{}".format(api_url, url))
... return browser.contents
>>> def get_count(response):
... data = json.loads(response)
... return data.get("count")
>>> def get_items_ids(response, sort=True):
... data = json.loads(response)
... items = data.get("items")
... items = map(lambda it: it["id"], items)
... if sort:
... return sorted(items)
... return items
>>> def init_data():
... api.create(portal.clients, "Client", title="Happy Hills", ClientID="HH")
... api.create(portal.clients, "Client", title="ACME", ClientID="AC")
... api.create(portal.clients, "Client", title="Fill the gap", ClientID="FG")
... api.create(setup.bika_sampletypes, "SampleType", title="Water", Prefix="W")
... api.create(setup.bika_sampletypes, "SampleType", title="Dust", Prefix="D")
... transaction.commit()
Variables:
>>> portal = self.portal
>>> portal_url = portal.absolute_url()
>>> api_url = "{}/@@API/senaite/v1".format(portal_url)
>>> setup = api.get_setup()
>>> browser = self.getBrowser()
>>> setRoles(portal, TEST_USER_ID, ["LabManager", "Manager"])
Initialize the instance with some objects for testing:
>>> init_data()
Basic search¶
We can directly search by resource:
>>> response = get("client")
>>> get_count(response)
3
>>> get_items_ids(response)
[u'client-1', u'client-2', u'client-3']
We can also add search criteria as well:
>>> response = get("client?id=client-1")
>>> get_count(response)
1
>>> get_items_ids(response)
[u'client-1']
>>> response = get("client?getName=ACME")
>>> get_count(response)
1
>>> get_items_ids(response)
[u'client-2']
Sort and limit¶
We can use sort and limit too:
>>> response = get("client?sort_on=id&sort_order=asc")
>>> get_items_ids(response, sort=False)
[u'client-1', u'client-2', u'client-3']
>>> response = get("client?sort_on=id&sort_order=desc")
>>> get_items_ids(response, sort=False)
[u'client-3', u'client-2', u'client-1']
>>> response = get("client?sort_on=id&sort_order=desc&limit=2")
>>> get_items_ids(response, sort=False)
[u'client-3', u'client-2']
Search without resource¶
We can also omit the resource and search directly by portal_type:
>>> response = get("search?portal_type=Client")
>>> get_items_ids(response)
[u'client-1', u'client-2', u'client-3']
Additional search criteria and sorting works as well:
>>> response = get("search?portal_type=Client&getName=ACME")
>>> get_items_ids(response)
[u'client-2']
>>> response = get("search?portal_type=Client&sort_on=id&sort_order=desc&limit=2")
>>> get_items_ids(response, sort=False)
[u'client-3', u'client-2']
Catalog search¶
We can specify the catalog to use in searches. Sample Types are stored in both portal_catalog and setup_catalog:
>>> response = get("sampletype")
>>> get_items_ids(response)
[u'sampletype-1', u'sampletype-2']
>>> response = get("sampletype?catalog=portal_catalog")
>>> get_items_ids(response)
[u'sampletype-1', u'sampletype-2']
>>> response = get("sampletype?catalog=bika_setup_catalog")
>>> get_items_ids(response)
[u'sampletype-1', u'sampletype-2']
But Sample Types are not stored in “bika_catalog”:
>>> response = get("sampletype?catalog=bika_catalog")
>>> get_items_ids(response)
[]
CREATE¶
Running this test from the buildout directory:
bin/test test_doctests -t create
Test Setup¶
Needed Imports:
>>> import json
>>> import transaction
>>> import urllib
>>> from DateTime import DateTime
>>> from plone.app.testing import setRoles
>>> from plone.app.testing import TEST_USER_ID
>>> from plone.app.testing import TEST_USER_PASSWORD
>>> from bika.lims import api
Functional Helpers:
>>> def get(url):
... browser.open("{}/{}".format(api_url, url))
... return browser.contents
>>> def post(url, data):
... url = "{}/{}".format(api_url, url)
... browser.post(url, urllib.urlencode(data, doseq=True))
... return browser.contents
>>> def create(data):
... response = post("create", data)
... assert("items" in response)
... response = json.loads(response)
... items = response.get("items")
... assert(len(items)==1)
... item = response.get("items")[0]
... assert("uid" in item)
... return api.get_object(item["uid"])
Variables:
>>> portal = self.portal
>>> portal_url = portal.absolute_url()
>>> api_url = "{}/@@API/senaite/v1".format(portal_url)
>>> setup = api.get_setup()
>>> browser = self.getBrowser()
>>> setRoles(portal, TEST_USER_ID, ["LabManager", "Manager"])
>>> transaction.commit()
Create with resource¶
We can create an object by providing the resource and the parent uid directly in the request:
>>> clients = portal.clients
>>> clients_uid = api.get_uid(clients)
>>> url = "client/create/{}".format(clients_uid)
>>> data = {"title": "Test client 1",
... "ClientID": "TC1"}
>>> post(url, data)
'...clients/client-1"...'
We can also omit the parent uid while defining the resource, but passing the uid of the container via post:
>>> data = {"title": "Test client 2",
... "ClientID": "TC2",
... "parent_uid": clients_uid}
>>> post("client/create", data)
'...clients/client-2"...'
We can use parent_path instead of parent_uid:
>>> data = {"title": "Test client 3",
... "ClientID": "TC3",
... "parent_path": api.get_path(clients)}
>>> post("client/create", data)
'...clients/client-3"...'
Create without resource¶
Or we can create an object without the resource, but with the parent uid and defining the portal_type via post:
>>> url = "create/{}".format(clients_uid)
>>> data = {"title": "Test client 4",
... "ClientID": "TC4",
... "portal_type": "Client"}
>>> post(url, data)
'...clients/client-4"...'
Create via post only¶
We can omit both the resource and container uid and pass everything via post:
>>> data = {"title": "Test client 5",
... "ClientID": "TC5",
... "portal_type": "Client",
... "parent_path": api.get_path(clients)}
>>> post("create", data)
'...clients/client-5"...'
>>> data = {"title": "Test client 6",
... "ClientID": "TC6",
... "portal_type": "Client",
... "parent_uid": clients_uid}
>>> post("create", data)
'...clients/client-6"...'
If we do a search now for clients, we will get all them:
>>> output = get("client")
>>> output = json.loads(output)
>>> items = output.get("items")
>>> items = map(lambda it: it.get("getClientID"), items)
>>> sorted(items)
[u'TC1', u'TC2', u'TC3', u'TC4', u'TC5', u'TC6']
Required fields¶
System will fail with a 400 error when trying to create an object without a required attribute:
>>> data = {"portal_type": "SampleType",
... "parent_path": api.get_path(setup.bika_sampletypes),
... "title": "Fresh Egg",
... "Prefix": "FE"}
>>> post("create", data)
Traceback (most recent call last):
[...]
HTTPError: HTTP Error 400: Bad Request
Create a Client¶
>>> data = {"portal_type": "Client",
... "parent_path": api.get_path(clients),
... "title": "Omelette corp",
... "ClientID": "EC"}
>>> client = create(data)
>>> client.getClientID()
'EC'
>>> api.get_parent(client)
<ClientFolder at /plone/clients>
Create a Client Contact¶
>>> data = {"portal_type": "Contact",
... "parent_path": api.get_path(client),
... "Firstname": "Proud",
... "Surname": "Hen"}
>>> contact = create(data)
>>> contact.getFullname()
'Proud Hen'
>>> api.get_parent(contact)
<Client at /plone/clients/client-7>
Create a Sample Type¶
>>> data = {"portal_type": "SampleType",
... "parent_path": api.get_path(setup.bika_sampletypes),
... "title": "Fresh Egg",
... "MinimumVolume": "10 gr",
... "Prefix": "FE"}
>>> sample_type = create(data)
>>> sample_type.Title()
'Fresh Egg'
>>> sample_type.getPrefix()
'FE'
>>> api.get_parent(sample_type)
<SampleTypes at /plone/bika_setup/bika_sampletypes>
Create a Laboratory Contact¶
>>> data = {"portal_type": "LabContact",
... "parent_path": api.get_path(setup.bika_labcontacts),
... "Firstname": "Lab",
... "Surname": "Chicken"}
>>> lab_contact = create(data)
>>> lab_contact.getFullname()
'Lab Chicken'
>>> api.get_parent(lab_contact)
<LabContacts at /plone/bika_setup/bika_labcontacts>
Create a Department¶
>>> data = {"portal_type": "Department",
... "parent_path": api.get_path(setup.bika_departments),
... "title": "Microbiology",
... "Manager": api.get_uid(lab_contact)}
>>> department = create(data)
>>> department.Title()
'Microbiology'
>>> api.get_parent(department)
<Departments at /plone/bika_setup/bika_departments>
Create an Analysis Category¶
>>> data = {"portal_type": "AnalysisCategory",
... "parent_path": api.get_path(setup.bika_analysiscategories),
... "title": "Microbiology identification",
... "Department": api.get_uid(department)}
>>> category = create(data)
>>> category.Title()
'Microbiology identification'
>>> api.get_parent(category)
<AnalysisCategories at /plone/bika_setup/bika_analysiscategories>
>>> category.getDepartment()
<Department at /plone/bika_setup/bika_departments/department-1>
Create an Analysis Service¶
>>> data = {"portal_type": "AnalysisService",
... "parent_path": api.get_path(setup.bika_analysisservices),
... "title": "Salmonella",
... "Keyword": "Sal",
... "ScientificName": True,
... "Price": 15,
... "Category": api.get_uid(category),
... "Accredited": True}
>>> sal = create(data)
>>> sal.Title()
'Salmonella'
>>> sal.getKeyword()
'Sal'
>>> sal.getScientificName()
True
>>> sal.getAccredited()
True
>>> sal.getCategory()
<AnalysisCategory at /plone/bika_setup/bika_analysiscategories/analysiscategory-1>
>>> data = {"portal_type": "AnalysisService",
... "parent_path": api.get_path(setup.bika_analysisservices),
... "title": "Escherichia coli",
... "Keyword": "Ecoli",
... "ScientificName": True,
... "Price": 15,
... "Category": api.get_uid(category)}
>>> ecoli = create(data)
>>> ecoli.Title()
'Escherichia coli'
>>> ecoli.getKeyword()
'Ecoli'
>>> ecoli.getScientificName()
True
>>> ecoli.getPrice()
'15.00'
>>> ecoli.getCategory()
<AnalysisCategory at /plone/bika_setup/bika_analysiscategories/analysiscategory-1>
Creating a Sample¶
The creation of a Sample (AnalysisRequest portal type) is handled differently from the rest of objects, an specific function in senaite.core must be used instead of the plone’s default creation.
>>> data = {"portal_type": "AnalysisRequest",
... "parent_uid": api.get_uid(client),
... "Contact": api.get_uid(contact),
... "DateSampled": DateTime().ISO8601(),
... "SampleType": api.get_uid(sample_type),
... "Analyses": map(api.get_uid, [sal, ecoli]) }
>>> sample = create(data)
>>> sample
<AnalysisRequest at /plone/clients/client-7/FE-0001>
>>> analyses = sample.getAnalyses(full_objects=True)
>>> sorted(map(lambda an: an.getKeyword(), analyses))
['Ecoli', 'Sal']
>>> sample.getSampleType()
<SampleType at /plone/bika_setup/bika_sampletypes/sampletype-2>
>>> sample.getClient()
<Client at /plone/clients/client-7>
>>> sample.getContact()
<Contact at /plone/clients/client-7/contact-1>
Creation restrictions¶
We get a 401 error if we try to create an object inside portal root:
>>> data = {"title": "My clients folder",
... "portal_type": "ClientsFolder",
... "parent_path": api.get_path(portal)}
>>> post("create", data)
Traceback (most recent call last):
[...]
HTTPError: HTTP Error 401: Unauthorized
We get a 401 error if we try to create an object inside setup folder:
>>> data = {"title": "My Analysis Categories folder",
... "portal_type": "AnalysisCategories",
... "parent_path": api.get_path(setup)}
>>> post("create", data)
Traceback (most recent call last):
[...]
HTTPError: HTTP Error 401: Unauthorized
We get a 401 error when we try to create an object from a type that is not allowed by the container:
>>> data = {"title": "My Method",
... "portal_type": "Method",
... "parent_path": api.get_path(clients)}
>>> post("create", data)
Traceback (most recent call last):
[...]
HTTPError: HTTP Error 401: Unauthorized
READ¶
Running this test from the buildout directory:
bin/test test_doctests -t read
Test Setup¶
Needed Imports:
>>> import json
>>> import transaction
>>> from plone.app.testing import setRoles
>>> from plone.app.testing import TEST_USER_ID
>>> from plone.app.testing import TEST_USER_PASSWORD
>>> from bika.lims import api
Functional Helpers:
>>> def get(url):
... browser.open("{}/{}".format(api_url, url))
... return browser.contents
>>> def get_count(response):
... data = json.loads(response)
... return data.get("count")
>>> def get_items_ids(response, sort=True):
... data = json.loads(response)
... items = data.get("items")
... items = map(lambda it: it["id"], items)
... if sort:
... return sorted(items)
... return items
>>> def init_data():
... api.create(portal.clients, "Client", title="Happy Hills", ClientID="HH")
... api.create(portal.clients, "Client", title="ACME", ClientID="AC")
... api.create(portal.clients, "Client", title="Fill the gap", ClientID="FG")
... transaction.commit()
Variables:
>>> portal = self.portal
>>> portal_url = portal.absolute_url()
>>> api_url = "{}/@@API/senaite/v1".format(portal_url)
>>> browser = self.getBrowser()
>>> setRoles(portal, TEST_USER_ID, ["LabManager", "Manager"])
>>> transaction.commit()
Initialize the instance with some objects for testing:
>>> init_data()
Get resource objects¶
We can get the objects from a resource type:
>>> response = get("client")
>>> get_count(response)
3
>>> get_items_ids(response)
[u'client-1', u'client-2', u'client-3']
Get by uid¶
We can directly fetch a given object by it’s UID and resource:
>>> client = api.create(portal.clients, "Client", title="Woow", ClientID="WO")
>>> uid = api.get_uid(client)
>>> transaction.commit()
>>> response = get("client/{}".format(uid))
>>> get_count(response)
1
>>> response
'..."title": "Woow"...'
Even with only the uid:
>>> response = get(uid)
>>> response
'..."title": "Woow"...'
but with no items in the response:
>>> "items" in response
False
>>> sorted(json.loads(response).keys())
[u'AccountName', u'AccountNumber', u'AccountType',...]
UPDATE¶
Running this test from the buildout directory:
bin/test test_doctests -t update
Test Setup¶
Needed Imports:
>>> import json
>>> import transaction
>>> import urllib
>>> from plone.app.testing import setRoles
>>> from plone.app.testing import TEST_USER_ID
>>> from plone.app.testing import TEST_USER_PASSWORD
>>> from bika.lims import api
Functional Helpers:
>>> def get(url):
... browser.open("{}/{}".format(api_url, url))
... return browser.contents
>>> def post(url, data):
... url = "{}/{}".format(api_url, url)
... browser.post(url, urllib.urlencode(data, doseq=True))
... return browser.contents
>>> def get_item_object(response):
... assert("items" in response)
... response = json.loads(response)
... items = response.get("items")
... assert(len(items)==1)
... item = response.get("items")[0]
... assert("uid" in item)
... return api.get_object(item["uid"])
>>> def create(data):
... response = post("create", data)
... return get_item_object(response)
Variables:
>>> portal = self.portal
>>> portal_url = portal.absolute_url()
>>> api_url = "{}/@@API/senaite/v1".format(portal_url)
>>> setup = api.get_setup()
>>> browser = self.getBrowser()
>>> setRoles(portal, TEST_USER_ID, ["LabManager", "Manager"])
>>> transaction.commit()
Initialize the instance with some objects for testing:
>>> clients = api.get_portal().clients
>>> data = {"portal_type": "Client",
... "parent_path": api.get_path(clients),
... "title": "Chicken corp",
... "ClientID": "CC"}
>>> client1 = create(data)
>>> data = {"portal_type": "Client",
... "parent_path": api.get_path(clients),
... "title": "Beef Corp",
... "ClientID": "BC"}
>>> client2 = create(data)
>>> data = {"portal_type": "Client",
... "parent_path": api.get_path(clients),
... "title": "Octopus Corp",
... "ClientID": "OC"}
>>> client3 = create(data)
Update by resource and uid¶
We can update an object by providing the resource and the uid of the object:
>>> client_uid = api.get_uid(client1)
>>> data = {"ClientID": "CC1"}
>>> response = post("client/update/{}".format(client_uid), data)
>>> obj = get_item_object(response)
>>> obj.getClientID()
'CC1'
Update by uid without resource¶
Even easier, we can update with only the uid:
>>> data = {"ClientID": "CC2"}
>>> response = post("update/{}".format(client_uid), data)
>>> obj = get_item_object(response)
>>> obj.getClientID()
'CC2'
Update via post only¶
When updating by resource (without an UID explicitly set), the system expects a the data to passed via POST to contain the item to be updated.
The object to be updated can be send in the HTTP POST body by using the uid:
>>> data = {"uid": client_uid,
... "ClientID": "CC3"}
>>> response = post("update", data)
>>> obj = get_item_object(response)
>>> obj.getClientID()
'CC3'
By using the path, as the physical path of the object:
>>> data = {"path": api.get_path(client1),
... "ClientID": "CC4"}
>>> response = post("update", data)
>>> obj = get_item_object(response)
>>> obj.getClientID()
'CC4'
Or by using the id of the object together with parent_path, as the physical path of the container object:
>>> data = {"id": api.get_id(client1),
... "parent_path": api.get_path(clients),
... "ClientID": "CC5"}
>>> response = post("update", data)
>>> obj = get_item_object(response)
>>> obj.getClientID()
'CC5'
Do a transition¶
We can transition the objects by using the keyord transition in the data sent via POST:
>>> api.is_active(client1)
True
>>> data = {"uid": api.get_uid(client1),
... "transition": "deactivate"}
>>> response = post("update", data)
>>> obj = get_item_object(response)
>>> api.is_active(obj)
False
We can update and transition at same time:
>>> data = {"uid": api.get_uid(client1),
... "ClientID": "CC6",
... "transition": "activate"}
>>> response = post("update", data)
>>> obj = get_item_object(response)
>>> api.is_active(obj)
True
>>> obj.getClientID()
'CC6'
Update restrictions¶
We get a 401 error if we try to update an object from inside portal root:
>>> data = {"title": "My clients folder",
... "uid": api.get_uid(clients),}
>>> post("update", data)
Traceback (most recent call last):
[...]
HTTPError: HTTP Error 401: Unauthorized
We get a 401 error if we try to update an object from inside setup folder:
>>> cats_uid = api.get_uid(api.get_setup().bika_analysiscategories)
>>> data = {"title": "My Analysis Categories folder",
... "uid": cats_uid,}
>>> post("update", data)
Traceback (most recent call last):
[...]
HTTPError: HTTP Error 401: Unauthorized
We cannot update the id of an object:
>>> original_id = api.get_id(client1)
>>> data = {"id": "client-123123",
... "uid": client_uid }
>>> response = post("update", data)
>>> obj = get_item_object(response)
>>> api.get_id(obj) == original_id
True
Test Setup¶
Needed Imports:
>>> import json
>>> import transaction
>>> import urllib
>>> from plone.app.testing import setRoles
>>> from plone.app.testing import TEST_USER_ID
>>> from plone.app.testing import TEST_USER_PASSWORD
>>> from senaite.jsonapi.interfaces import IPushConsumer
>>> from zope.component import getGlobalSiteManager
>>> from zope.interface import implements
Functional Helpers:
>>> def post(url, data):
... url = "{}/{}".format(api_url, url)
... browser.post(url, urllib.urlencode(data, doseq=True))
... return browser.contents
Variables:
>>> portal = self.portal
>>> portal_url = portal.absolute_url()
>>> api_url = "{}/@@API/senaite/v1".format(portal_url)
>>> browser = self.getBrowser()
>>> setRoles(portal, TEST_USER_ID, ["LabManager", "Manager"])
>>> transaction.commit()
Create a dummy IPushConsumer adapter:
>>> class DummyConsumerAdapter(object):
... implements(IPushConsumer)
...
... def __init__(self, record):
... self.record = record
...
... def process(self):
... if not self.record.get("target"):
... return False
... return True
>>> sm = getGlobalSiteManager()
>>> sm.registerAdapter(DummyConsumerAdapter, (dict,), IPushConsumer, name="dummy")
>>> transaction.commit()
Push with success¶
>>> post("push", {"consumer": "dummy", "target": "defined"})
'..."success": true...'
Push without success¶
If an adapter is registered, but it rises an exception, the outcome is failed:
>>> post("push", {"consumer": "dummy"})
'..."success": false...'
Non-registered adapter¶
>>> post("push", {"consumer": "zummy"})
Traceback (most recent call last):
[...]
HTTPError: HTTP Error 500: Internal Server Error