Forums

Articles
Create
cancel
Showing results for 
Search instead for 
Did you mean: 

Managing Review Comments

Stacy Dow February 3, 2017

Hey All,

Still new to authoring in Confluence... The main reason we went to Confluence is because our engineers had a major pain point in providing review comments using Adobe Acrobat Review Server. Their hope is that they can modify small details directly in the source, AND provide comments on pages. (Don't tell me it's a terrible idea, because I lost that battle.)

So, now each page in a doc has a growing list of comments. Tracking this activity, even on a small document, is so flawed! I have no way of marking a comment done, filtering only unresolved comments, seeing a history of added and deleted comments, etc. So, what is already happening is that I'm missing newly added comments/replies to threads. So, I started deleting comments once I incorporated them until I needed to go back and see the comment again and had no way to restore it. 

I'm so frustrated. There is no way this is going to work on bigger docs. WAY too error prone...

Does anyone know if there's an add-on? Or a different way to get/track feedback on the actual Confluence page (not a PDF output, since they don't want to review that way). HELP???

TIA!

4 answers

1 accepted

1 vote
Answer accepted
Rodney Hughes
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
February 3, 2017

Firstly it is a brilliant idea!!  (sorry you lost the battle again smile )

Our industry association Working Groups uses Confluence for drafting reference documents for ultimately publishing to the industry.

Each Chapter of the document is drafted directly on screen.

There are two commenting methods now (depending on your version  - we have v5.8.16)

Page Comments are added at the bottom of the page in "threads", but as you have noticed there is no way to mark them as "resolved"

But the new "In-line Comment" facility allows you to highlight some text in normal View mode and a pop up box appears e.g.

image2017-2-4 9:48:57.png

That then gives a comment box that also has an option to mark it as Resolved

image2017-2-4 9:50:3.png

 

Stacy Dow February 3, 2017

This is such great news! We are updating to 6 right now! SO HAPPY to see that this will get easier..... THANK YOU

1 vote
Roman Kirilenko
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
February 3, 2017

Just for information. There is the add-on called Talk. It has many features and in some cases can be even better than Confluence inline comments (it allows you to insert inline comments too). You can also try it without installing to your instance, the team created a demo server for this purpose.

0 votes
Biwords Services August 25, 2018

Hi,

This is a good approach. But sometimes authors use a different tool to author content. 

Can we have a plugin from the authoring tool to launch confluence. 

Thanks,

Nuz

0 votes
Adrian Hepworth April 20, 2017

We use Confluence for collaborative review comments between ourselves and the customer. Inline comments work well, with footer comments being used for things like saying "I've reviewed this page, back to you for updates". One thing that was difficult is tracking all the comments collectively, so we wrote a PHP macro that walks the pages below a starting page, fetches all the comments, and then builds a single review comments page below the same parent with all the comments from all child pages on it. That helps because you can't see the actual comment when you go to edit the page to resolve it (a major flaw IMHO).

Screen Shot 2017-04-20 at 09.09.39.png

hieroglyf
I'm New Here
I'm New Here
Those new to the Atlassian Community have posted less than three times. Give them a warm welcome!
September 10, 2018

Hello Adrian,

we are looking for a similar comments tracking solution. Would you be able to share/sell such script? Does it also work for comments under the page?

Thanks for letting me know.

Adrian Hepworth May 13, 2020

Here's the Python code (we upgraded from PHP) that produces the table above. Apologies for not replying sooner hieroglyf - I've only just seen this !

It's crude code without much error checking (don't judge!) but does the job. It should be obvious to a decent coder what needs to change to work on your instance (be it Cloud or Hosted). Feedback welcome.

Usual disclaimer, you are free to use this code, but please attribute the author. No liability will be accepted for your use of this software (it does write new pages to your instance via the brilliant API services - thanks Atlassian).

--

import requests
import json
from requests.auth import HTTPBasicAuth
from pprint import pprint
import csv, re, datetime
import urllib.parse
import html
from datetime import datetime
from html.parser import HTMLParser

# Author: Adrian Hepworth / Worldline

# Licensed under Creative Commons - CC BY-SA 4.0

# The base content API - change to point at your instance
contenturl = 'https://organisation.atlassian.net/wiki/rest/api/content'
# The space ID in which the parent page resides
space = "SPACE"
# The Parent Page
source = "My Page"

# Get the username and password from a local CSV file called 'atlassian-login.txt'
with open('atlassian-login.txt', newline='') as csvfile:
cred_reader = csv.reader(csvfile, delimiter=',', quotechar='"')
for item in cred_reader:
username=item[0]
token=item[1]

auth = HTTPBasicAuth(username,token)

comment_list = []

def escape(s):
# this has to be first:
s = s.replace("&", "&")
s = s.replace("<", "&lt;")
s = s.replace(">", "&gt;")
s = s.replace('\\n', "<br />")
s = s.replace('\n', "<br />")
return s

class MLStripper(HTMLParser):
def __init__(self):
super().__init__()
self.reset()
self.fed = []
def handle_data(self, d):
self.fed.append(d)
def get_data(self):
return ''.join(self.fed)

def strip_tags(html):
s = MLStripper()
s.feed(html)
return s.get_data()

def find_page(space,title):
global contenturl
params = {'spaceKey':space,
'title':title}
resp = requests.get(contenturl,params=params,auth=auth)
if resp.status_code != 200:
return None
results = json.loads(resp.text)
if results['size'] == 0:
return None
page=results['results'][0]
return page

def get_url(url,params):
#print("Get URL for %s with %s params" % (url,params))
global auth
resp = requests.get(url,params=params,auth=auth)
if resp.status_code != 200:
return None
results = json.loads(resp.text)
if results['size'] == 0:
return None
return results

def get_comment_list(id,url):

global comment_list

print("Going for %s,%s,%s with %d comments so far" % (space,id,url,len(comment_list)))

params = {'expand':'extensions.inlineProperties,extensions.resolution,history,body.view'
,'limit':'125'
,'depth':'all'}

comments = get_url(url+'/child/comment',params=params)

# print("There are %d comments\nComments: %s" % (len(comments),comments)); exit()

if comments:
for comment in comments['results']:
# print('\nComment: %s' % comment)
if comment['extensions']['location']=='inline':
comment_list.append({'page' : comment['title'],
'pageURL' : comment['_links']['self'],
'pageUI' : comments['_links']['base']+comment['_links']['webui'],
'location' : comment['extensions']['location'],
'status' : comment['extensions']['resolution']['status'],
'selection' : comment['extensions']['inlineProperties']['originalSelection'],
'title' : comment['title'],
'who' : comment['history']['createdBy']['publicName'],
'when' : comment['history']['createdDate'],
'link' : comment['_links']['self'],
'web' : comments['_links']['base']+comment['_links']['webui'],
'comment' : strip_tags(html.unescape(comment['body']['view']['value']))}
)

#print (comment_list)

# Recurse to call itself to walk the tree
content = get_url(url+'/child/page',{'limit':150});

if content:
for childPage in content['results']:
# Append the comments on each page
print('Found child page: %s' % childPage['id'])
get_comment_list(childPage['id'],childPage['_links']['self'])

# Find the parent page
start_page = find_page(space,source)

get_comment_list(start_page['id'],start_page['_links']['self'])

body = "<h1>Comment Extract</h1>"

body += '<table class=\"wrapped fixed-table\"><colgroup><col style=\"width: 150px;\" /> <col style=\"width: 100px;\" /> <col style=\"width: 100px;\" /> <col style=\"width: 600px;\" /> </colgroup><tbody><tr><th>Page</th><th>Location</th><th>Status</th><th>Comments</th></tr>';

for ix,comment in enumerate(comment_list):
# print(comment)
# output the comment
if comment['location'] != "inline":
# Complete new line
if ix>0:
body += "</td></tr>"
body += '<tr><td><a href=\"'+escape(comment['pageUI'])+'\">'+escape(comment['page'])+'</a></td>'
body +='<td class=\"highlight-blue\" data-highlight-colour=\"blue\">'+comment['location']+'</td>'
body += '<td>'+comment['status']+'</td>'
body += '<td><a href=\"'+escape(comment['web'])+'\">'+comment['who']+'</a> - '+comment['when']
body += '<br />'+escape(comment['comment'])
else:
if comment['selection'] == "":
# This is a reply to a comment
body += '<br /><a href=\"'+escape(comment['web'])+'\">'+comment['who']+'</a> - '+comment['when']
body += '<br />'+escape(comment['comment'])
else:
if ix>0:
body += "</td></tr>"
body += '<tr><td><a href=\"'+escape(comment['pageUI'])+'\">'+escape(comment['page'])+'</a></td>'
body += '<td>'+comment['location']+'</td>'
if comment['status'] == "resolved" or comment['status'] == "dangling":
body += '<td class=\"highlight-green\" data-highlight-colour=\"green\">'+comment['status']+'</td>'
else:
body += '<td>'+comment['status']+'</td>'
body += '<td><span style=\"color: blue;\"><em>'+escape(comment['selection'])+'</em></span>'
body += '<br /><a href=\"'+escape(comment['web'])+'\">'+comment['who']+'</a> - '+comment['when']
body += '<br />'+escape(comment['comment'])


body += '</td></tr></tbody></table>'

title = "Comments extracted on %s" % datetime.today().strftime('%Y-%m-%d %H:%M:%S')
header = {'Content-Type': 'application/json'}
reqbody = {"type":"page",
"title":title,
"space":{"key":space},
"ancestors":[{"id":start_page['id']}],
"metadata":{"labels":[{"name":"no-print"}]},
"body":{"storage":{"value":body,
"representation":"storage"}}}

resp = requests.post(contenturl,headers=header,json=reqbody,auth=auth)

if resp.status_code != 200:
print('Unable to process creation - response %s' % resp.status_code)
print('Response: %s' % resp.text)
exit()

page = resp.json()

print('Successfully created page id (%s)\n' % page['id'])

exit()

Adrian Hepworth May 13, 2020

You'll need to re-tab the code as it's pasted without correct Python tabs.

Suggest an answer

Log in or Sign up to answer
TAGS
AUG Leaders

Atlassian Community Events