Search code examples
pythonconfluenceconfluence-rest-api

Issue Updating Confluence Page with Python and API


I am working on updating a Confluence page via python and the Confluence API.

I have found a function to write the data to the my page, unfortunately it creates a new page with my data and the old page becomes an archived version.

I have been searching the reference material and cannot see the reason I am getting a new page instead of appending the data to the end of the page. The only solution I can think of is to copy the body and append the new data to it, then create the new page ... but I am thinking there should be a way to append.

The write function code I found / am leveraging is as follows :

def write_data(auth, html, pageid, title = None):


    info = get_page_info(auth, pageid)
    print ("after get page info")
    ver = int(info['version']['number']) + 1

    ancestors = get_page_ancestors(auth, pageid)

    anc = ancestors[-1]
    del anc['_links']
    del anc['_expandable']
    del anc['extensions']

    if title is not None:
        info['title'] = title

    data = {
        'id' : str(pageid),
        'type' : 'page',
        'title' : info['title'],
        'version' : {'number' : ver},
        'ancestors' : [anc],
        'body'  : {
            'storage' :
            {
                'representation' : 'storage',
                'value' : str(html),
            }
        }
    }

    data = json.dumps(data)
    pprint (data)
    url = '{base}/{pageid}'.format(base = BASE_URL, pageid = pageid)

    r = requests.put(
        url,
        data = data,
        auth = auth,
        headers = { 'Content-Type' : 'application/json' }
    )

    r.raise_for_status()

I am starting to think copying / appending to the body is the option, but hope someone else has encountered this issue.


Solution

  • Not an elegant solution, but I went with the copy the old body and append option.

    Basically, wrote a simple function to return the existing body :

    def get_page_content(auth, pageid):
    
        url = '{base}/{pageid}?expand=body.storage'.format(
            base = BASE_URL,
            pageid = pageid)
    
        r = requests.get(url, auth = auth)
        r.raise_for_status()
    
        return (r.json()['body']['storage']['value'])
    

    In this example, just appending (+=) a new string to the existing body.

    def write_data(auth, html, pageid, title = None):
    
        info = get_page_info(auth, pageid)
        page_content = get_page_content(auth, pageid)
        ver = int(info['version']['number']) + 1
    
        ancestors = get_page_ancestors(auth, pageid)
    
        anc = ancestors[-1]
        del anc['_links']
        del anc['_expandable']
        del anc['extensions']
    
        page_content += "\n\n"
        page_content += html
    
        if title is not None:
            info['title'] = title
    
        data = {
            'id' : str(pageid),
            'type' : 'page',
            'title' : info['title'],
            'version' : {'number' : ver},
            'ancestors' : [anc],
            'body'  : {
                'storage' :
                {
                    'representation' : 'storage',
                    'value' : str(page_content),
                }
            }
        }
    
        data = json.dumps(data)
        url = '{base}/{pageid}'.format(base = BASE_URL, pageid = pageid)
    
        r = requests.put(
            url,
            data = data,
            auth = auth,
            headers = { 'Content-Type' : 'application/json' }
        )
    
        r.raise_for_status()
    
        print "Wrote '%s' version %d" % (info['title'], ver)
        print "URL: %s%d" % (VIEW_URL, pageid)
    

    Should note that as this is a post to a confluence body, the text being passed is html. '\n' for newline does not work, you need to pass '<br \>' etc ...

    If anyone has a more elegant solution, would welcome the suggestions.

    Dan.