Hello all,
I've recently switched from the SOAP api to the rest API to create and update confluence pages (I'm using Confluence 5.5.6).
I would like to report a strange behaviour with the API when updating a page.
First, it's important to know that if you use the example from the Rest API example page ( https://developer.atlassian.com/display/CONFDEV/Confluence+REST+API+Examples ), your page will loose its ancestor. The page ancestor is deleted and the page ancestor is its space: you cannot browse it with the treeview. In order to avoid that problem, you have to provide the ancestor in the request.
Second, to update a JIRA issue or a confluence page with the REST API, I send a request with all the elements needed to update the issue or the page, I modify the JSON received and I send it back (it seems to be pretty obvious behaviour).
So in order to update a confluence page the minimal request has this form: http://<host>:8080/confluence/rest/api/content/<id>?expand=body.storage,version,ancestors
body.storage and version are updated in the JSON and a PUT request is sent back.
Unfortunately, if you do so, your page will still loose its ancestor... And it took me a while to figure out why: the returned JSON has ALL the ancestors of the page: the direct ancestor of the page, the ancestor of the ancestor and so on until the space root. So the array has several ancestors... And if you don't remove them except the direct ancestor, your page will loose its ancestor.
So I wonder, anyone else came accross that problem ? Is it a normal behaviour or a bug/feature ?
Any opinions welcome.
Fabio
I took Joshua Senecal's response a bit further and I think I address his caveat - before uploading a new version of the page (from a Python script), I find the id of the direct ancestor of that page. The method looks at the page's "ancestors" attribute:
With this code I could update a space of 342 pages at different tree depths without moving the pages. They also maintained their order relative to their siblings.
Here is the python code, in this code:
page_tree = dict() API_URL_PATH = '/rest/api' def get_parent_id(user, password, space_key, url, page): if not 'ancestors' in page or len(page['ancestors']) == 0: return None if len(page['ancestors']) == 1: return page['ancestors'][0]['id'] page_id = page['id'] for ancestor in reversed(page['ancestors']): parent_id = ancestor['id'] if parent_id not in page_tree: page_tree[parent_id] = get_page_children(user, password, space_key, url, parent_id) if page_id in page_tree[parent_id]: return parent_id return None def get_page_children(user, password, space_key, url, page_id): children = set() location = url + API_URL_PATH + ('/content/%s/child/page' % page_id) while True: response = get(user, password, location, { 'spaceKey': space_key }) children.update(map(lambda child: child['id'], response['results'])) if 'next' in response['_links']: location = url + response['_links']['next'] else: break return children
Very nice! This is likely the sort of thing I'll have to implement as well to ensure my code is robust.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
What exactly do you do in the wrapper method get(...) (line:23)?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Here is a rough version of get
:
def get(user, password, payload, url): request = requests.Request('POST', url, data = json.dumps(payload), headers = headers = { 'content-type': 'application/json', 'Authorization': 'Basic %s' % base64.encodestring('%s:%s' % (user, password)).replace('\n', '') }) prepared = request.prepare() return session.send(prepared)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I'm in the process of moving code to using the REST API from the XML-RPC API. I ran into this problem, and here's how I worked around it.
I need to preface this with a warning that (as you've probably discovered) the Confluence documentation isn't very good. Either there's still a lot of functionality not available in the REST API yet, or it's not documented. Either way, the solution I have here is based on my own observations, and not on any documentation I've read.
I'm using Confluence 5.6.3, interacting with it using Perl and the JSON, URI, and LWP libraries.
For starters, I have not found a way to get the immediate ancestor of a page (I'll be posting a question about this). As you've observed, you can only get a list of all ancestors. However, I noticed that the list is ordered (usually, more on this below) such that the last item on the list is the immediate parent of the page I'm working with. So after parsing the JSON-formatted string and getting a list, I pull the page ID from the last item in the list, and use that.
In another post somewhere someone said to only set the ID of the page's immediate ancestor. There's no need to set it for all the parents. Something like this:
..., "ancestors":[{"id", "12345"}], ...
You're essentially giving it a one-element list, with the ID of the immediate ancestor. This seems to work.
Now, a big warning: I've come across circumstances when the list of ancestors returned by the REST API is not in order, and even contains duplicate entries. This appears to happen only when I've fouled up a page's ancestry while testing and debugging code. The pages all end up on the space root, and in the wiki I manually drag them back into the proper order, Everything on the wiki looks good, but after doing this the ancestor list I get from the REST API is no longer nicely ordered.
One workaround to this might be to sort the ancestors by page ID number. On our system I noticed that the further down the tree I go, the higher the page numbers are. So if I sort the ancestor list and then take the highest-numbered ID, that should be the ID I want.
I hope this is helpful. If there's anything that needs clarifying let me know.
-Josh
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Thanks! This worked like a charm for me.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hello,
Thank you for your feedback!
Can we all agree it's a bug ?
By bug I mean that you request some data, you modify it and you cannot send it back as it is, you have to clean it otherwise the ancestors are lost.
Anyway unlike Joshua I've never came across a case where the ancestors list is not sorted (the first one in the list is the farthest one). But of course Amos's method is the safest one.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Has this been logged with Atlassian? If that's the case, it would be good to post here the ticket number
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I have logged this issue, please add any comments you consider relevant: [CRA-487](https://jira.atlassian.com/browse/CRA-487)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Update - the issue was marked as Resolved in version 5.8 (and I assumed current cloud version, dunno how to see this).
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi Everyone,
This is a known bug in confluence. It has been fixed in 5.8 and above:
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.