Affen is a requests Session equiped to easily consume plone.restapi
>>> import requests
>>> response = requests.get('https://plonedemo.kitconcept.com/@search?sort_on=path',
... headers={'Accept': 'application/json'}, auth=('admin', 'admin'))
>>> for i, item in enumerate(response.json()['items']):
... print(i, item['@id'])
...
0 https://plonedemo.kitconcept.com/de
1 https://plonedemo.kitconcept.com/de/Assets
2 https://plonedemo.kitconcept.com/de/demo
3 https://plonedemo.kitconcept.com/de/demo/a-image.jpg
4 https://plonedemo.kitconcept.com/de/demo/big_buck_bunny.mp4
5 https://plonedemo.kitconcept.com/de/demo/ein-link
6 https://plonedemo.kitconcept.com/de/demo/ein-ordner
7 https://plonedemo.kitconcept.com/de/demo/ein-ordner/eine-seite-in-einem-ordner
8 https://plonedemo.kitconcept.com/de/demo/ein-termin
9 https://plonedemo.kitconcept.com/de/demo/eine-nachricht
10 https://plonedemo.kitconcept.com/de/demo/eine-seite
11 https://plonedemo.kitconcept.com/de/demo/ploneconf-plone5.pdf
12 https://plonedemo.kitconcept.com/de/frontpage
13 https://plonedemo.kitconcept.com/en
14 https://plonedemo.kitconcept.com/en/assets
15 https://plonedemo.kitconcept.com/en/demo
16 https://plonedemo.kitconcept.com/en/demo/a-event
17 https://plonedemo.kitconcept.com/en/demo/a-file.pdf
18 https://plonedemo.kitconcept.com/en/demo/a-folder
19 https://plonedemo.kitconcept.com/en/demo/a-folder/a-page-inside-a-folder
20 https://plonedemo.kitconcept.com/en/demo/a-link
21 https://plonedemo.kitconcept.com/en/demo/a-news-item
22 https://plonedemo.kitconcept.com/en/demo/a-page
23 https://plonedemo.kitconcept.com/en/demo/a-photo.jpg
24 https://plonedemo.kitconcept.com/en/demo/a-video.mp4
>>>
And then follow the batching for more.
(and remember to start enumerate
at the right number)
>>> response = requests.get(response.json()['batching']['next'],
... headers={'Accept': 'application/json'}, auth=2*('admin',))
>>> for i, item in enumerate(response.json()['items'], start=i + 1):
... print(i, item['@id'])
...
25 https://plonedemo.kitconcept.com/en/frontpage
26 https://plonedemo.kitconcept.com/my-document
>>>
An Affen Session can take credentials and an api_root in the contructor, and
has an items
function that iterates over anything in restapi that uses the
batching protocol; like Folders, Collectors and restapi endpoints like
@search
:
>>> from affen import Session
>>> plone = Session('admin', 'admin', 'https://plonedemo.kitconcept.com')
>>> for i, item in enumerate(plone.items('@search?sort_on=path')):
... print(i, item['@id'])
...
0 https://plonedemo.kitconcept.com/de
1 https://plonedemo.kitconcept.com/de/Assets
2 https://plonedemo.kitconcept.com/de/demo
3 https://plonedemo.kitconcept.com/de/demo/a-image.jpg
4 https://plonedemo.kitconcept.com/de/demo/big_buck_bunny.mp4
5 https://plonedemo.kitconcept.com/de/demo/ein-link
6 https://plonedemo.kitconcept.com/de/demo/ein-ordner
7 https://plonedemo.kitconcept.com/de/demo/ein-ordner/eine-seite-in-einem-ordner
8 https://plonedemo.kitconcept.com/de/demo/ein-termin
9 https://plonedemo.kitconcept.com/de/demo/eine-nachricht
10 https://plonedemo.kitconcept.com/de/demo/eine-seite
11 https://plonedemo.kitconcept.com/de/demo/ploneconf-plone5.pdf
12 https://plonedemo.kitconcept.com/de/frontpage
13 https://plonedemo.kitconcept.com/en
14 https://plonedemo.kitconcept.com/en/assets
15 https://plonedemo.kitconcept.com/en/demo
16 https://plonedemo.kitconcept.com/en/demo/a-event
17 https://plonedemo.kitconcept.com/en/demo/a-file.pdf
18 https://plonedemo.kitconcept.com/en/demo/a-folder
19 https://plonedemo.kitconcept.com/en/demo/a-folder/a-page-inside-a-folder
20 https://plonedemo.kitconcept.com/en/demo/a-link
21 https://plonedemo.kitconcept.com/en/demo/a-news-item
22 https://plonedemo.kitconcept.com/en/demo/a-page
23 https://plonedemo.kitconcept.com/en/demo/a-photo.jpg
24 https://plonedemo.kitconcept.com/en/demo/a-video.mp4
25 https://plonedemo.kitconcept.com/en/frontpage
26 https://plonedemo.kitconcept.com/my-document
>>>
And if you have the permissions, you can read and write to the registry as if it were a dictionary:
>>> plone = Session('admin', 'admin', 'http://127.0.0.1:8080/Plone')
>>> plone.registry['plone.allowed_sizes']
['large 768:768',
'preview 400:400',
'mini 200:200',
'thumb 128:128',
'tile 64:64',
'icon 32:32',
'listing 16:16']
>>> plone.registry['plone.allowed_sizes'] = ['supersize_me 3840:2160']
>>> plone.registry['plone.allowed_sizes']
['supersize_me 3840:2160']
>>>
>>> vanilla = requests.Session()
>>> vanilla.auth = ('admin', 'admin')
>>> vanilla.headers['accept'] = 'application/json'
>>> ROOT = 'http://127.0.0.1:8080/Plone'
>>> # these two lines make it almost as short as Affen...
>>> [t['title'] for t in vanilla.get(f'{ROOT}/@types').json()]
['Collection', 'Event', 'File', 'Folder', 'Image', 'Link', 'News Item', 'Page']
>>> # see? f-strings were such a great idea!
>>> # Affen is hardly shorter
>>> [t['title'] for t in plone.get('@types').json()]
['Collection', 'Event', 'File', 'Folder', 'Image', 'Link', 'News Item', 'Page']
>>>
Sure, until you accidentally reuse the session for requests to a different
host. It's so conveniently close, and seems to behave like requests.get
. So
your mypy powered IDE didn't catch it. In fact, it provided handy
autocompletion, so it looked like the Right Thing™.
>>> vanilla.get('https://httpbin.org/headers').json()['headers']['Authorization']
'Basic YWRtaW46YWRtaW4='
>>>
OOPS, did we just send our 'Authorization' header to the nice people of httpbin.org? An Affen Session will throw a fit when you try to do that:
>>> plone.get('https://httpbin.org/headers').json()
Traceback (most recent call last):
...
ValueError: Making requests to other hosts than http://127.0.0.1:8080/Plone/ may leak credentials. Use a different requests.Session for those or change root
>>> # and even when whe change the api root
>>> plone.root = 'https://httpbin.org'
>>> plone.get('headers').json()['headers']['Authorization']
Traceback (most recent call last):
...
KeyError: 'Authorization'
>>> # it won't send the secrets