diff --git a/invenio/lib/webcomment_templates.py b/invenio/lib/webcomment_templates.py new file mode 100644 index 0000000000..67fd151f4d --- /dev/null +++ b/invenio/lib/webcomment_templates.py @@ -0,0 +1,2540 @@ +# -*- coding: utf-8 -*- +## Comments and reviews for records. + +## This file is part of Invenio. +## Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 CERN. +## +## Invenio is free software; you can redistribute it and/or +## modify it under the terms of the GNU General Public License as +## published by the Free Software Foundation; either version 2 of the +## License, or (at your option) any later version. +## +## Invenio is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Invenio; if not, write to the Free Software Foundation, Inc., +## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + +"""HTML Templates for commenting features """ + +__revision__ = "$Id$" + +import cgi + +# Invenio imports +from invenio.urlutils import create_html_link, create_url +from invenio.webuser import get_user_info, collect_user_info, isGuestUser, get_email +from invenio.dateutils import convert_datetext_to_dategui +from invenio.webmessage_mailutils import email_quoted_txt2html +from invenio.config import CFG_SITE_URL, \ + CFG_SITE_SECURE_URL, \ + CFG_SITE_LANG, \ + CFG_SITE_NAME, \ + CFG_SITE_NAME_INTL,\ + CFG_SITE_SUPPORT_EMAIL,\ + CFG_WEBCOMMENT_ALLOW_REVIEWS, \ + CFG_WEBCOMMENT_ALLOW_COMMENTS, \ + CFG_WEBCOMMENT_USE_RICH_TEXT_EDITOR, \ + CFG_WEBCOMMENT_NB_REPORTS_BEFORE_SEND_EMAIL_TO_ADMIN, \ + CFG_WEBCOMMENT_AUTHOR_DELETE_COMMENT_OPTION, \ + CFG_CERN_SITE, \ + CFG_SITE_RECORD, \ + CFG_WEBCOMMENT_MAX_ATTACHED_FILES, \ + CFG_WEBCOMMENT_MAX_ATTACHMENT_SIZE +from invenio.htmlutils import get_html_text_editor, create_html_select +from invenio.messages import gettext_set_language +from invenio.bibformat import format_record +from invenio.access_control_engine import acc_authorize_action +from invenio.access_control_admin import acc_get_user_roles_from_user_info, acc_get_role_id +from invenio.search_engine_utils import get_fieldvalues + +class Template: + """templating class, refer to webcomment.py for examples of call""" + + def tmpl_get_first_comments_without_ranking(self, recID, ln, comments, nb_comments_total, warnings): + """ + @param recID: record id + @param ln: language + @param comments: tuple as returned from webcomment.py/query_retrieve_comments_or_remarks + @param nb_comments_total: total number of comments for this record + @param warnings: list of warning tuples (warning_text, warning_color) + @return: html of comments + """ + + # load the right message language + _ = gettext_set_language(ln) + + # naming data fields of comments + c_nickname = 0 + c_user_id = 1 + c_date_creation = 2 + c_body = 3 + c_id = 6 + + warnings = self.tmpl_warnings(warnings, ln) + + # write button + write_button_label = _("Write a comment") + write_button_link = '%s/%s/%s/comments/add' % (CFG_SITE_URL, CFG_SITE_RECORD, recID) + write_button_form = '' % ln + write_button_form = self.createhiddenform(action=write_button_link, method="get", text=write_button_form, button=write_button_label) + + # comments + comment_rows = '' + last_comment_round_name = None + comment_round_names = [comment[0] for comment in comments] + if comment_round_names: + last_comment_round_name = comment_round_names[-1] + + for comment_round_name, comments_list in comments: + comment_rows += '
' % (comment_round_name) + if comment_round_name: + comment_rows += '
' + \ + _('%(x_nb)i Comments for round "%(x_name)s"') % {'x_nb': len(comments_list), 'x_name': comment_round_name} + "
" + else: + comment_rows += '
' + \ + _('%(x_nb)i Comments') % {'x_nb': len(comments_list),} + "
" + for comment in comments_list: + if comment[c_nickname]: + nickname = comment[c_nickname] + display = nickname + else: + (uid, nickname, display) = get_user_info(comment[c_user_id]) + messaging_link = self.create_messaging_link(nickname, display, ln) + comment_rows += """ + + """ + report_link = '%s/%s/%s/comments/report?ln=%s&comid=%s' % (CFG_SITE_URL, CFG_SITE_RECORD, recID, ln, comment[c_id]) + reply_link = '%s/%s/%s/comments/add?ln=%s&comid=%s&action=REPLY' % (CFG_SITE_URL, CFG_SITE_RECORD, recID, ln, comment[c_id]) + comment_rows += self.tmpl_get_comment_without_ranking(req=None, ln=ln, nickname=messaging_link, comment_uid=comment[c_user_id], + date_creation=comment[c_date_creation], + body=comment[c_body], status='', nb_reports=0, + report_link=report_link, reply_link=reply_link, recID=recID) + comment_rows += """ +
+
+ + """ + # Close comment round + comment_rows += '
' + + # output + if nb_comments_total > 0: + out = warnings + comments_label = len(comments) > 1 and _("Showing the latest %i comments:") % len(comments) \ + or "" + out += """ +
+ + + + +
%(comment_title)s
+
%(comments_label)s
+ %(comment_rows)s +%(view_all_comments_link)s +%(write_button_form)s
""" % \ + {'comment_title': _("Discuss this document"), + 'comments_label': comments_label, + 'nb_comments_total' : nb_comments_total, + 'recID': recID, + 'comment_rows': comment_rows, + 'tab': ' '*4, + 'siteurl': CFG_SITE_URL, + 's': nb_comments_total>1 and 's' or "", + 'view_all_comments_link': nb_comments_total>0 and '''View all %s comments''' \ + % (CFG_SITE_URL, CFG_SITE_RECORD, recID, nb_comments_total) or "", + 'write_button_form': write_button_form, + 'nb_comments': len(comments) + } + if not comments: + out = """ + + + + + +
%(discuss_label)s:
+
%(detailed_info)s +
+
+%(form)s +""" % {'form': write_button_form, + 'discuss_label': _("Discuss this document"), + 'detailed_info': _("Start a discussion about any aspect of this document.") + } + + return out + + def tmpl_record_not_found(self, status='missing', recID="", ln=CFG_SITE_LANG): + """ + Displays a page when bad or missing record ID was given. + @param status: 'missing' : no recID was given + 'inexistant': recID doesn't have an entry in the database + 'nan' : recID is not a number + 'invalid' : recID is an error code, i.e. in the interval [-99,-1] + @param return: body of the page + """ + _ = gettext_set_language(ln) + if status == 'inexistant': + body = _("Sorry, the record %s does not seem to exist.") % (recID,) + elif status in ('nan', 'invalid'): + body = _("Sorry, %s is not a valid ID value.") % (recID,) + else: + body = _("Sorry, no record ID was provided.") + + body += "

" + link = "%s." % (CFG_SITE_URL, ln, CFG_SITE_NAME_INTL.get(ln, CFG_SITE_NAME)) + body += _("You may want to start browsing from %s") % link + return body + + def tmpl_get_first_comments_with_ranking(self, recID, ln, comments=None, nb_comments_total=None, avg_score=None, warnings=[]): + """ + @param recID: record id + @param ln: language + @param comments: tuple as returned from webcomment.py/query_retrieve_comments_or_remarks + @param nb_comments_total: total number of comments for this record + @param avg_score: average score of all reviews + @param warnings: list of warning tuples (warning_text, warning_color) + @return: html of comments + """ + # load the right message language + _ = gettext_set_language(ln) + + # naming data fields of comments + c_nickname = 0 + c_user_id = 1 + c_date_creation = 2 + c_body = 3 + c_nb_votes_yes = 4 + c_nb_votes_total = 5 + c_star_score = 6 + c_title = 7 + c_id = 8 + + warnings = self.tmpl_warnings(warnings, ln) + + #stars + if avg_score > 0: + avg_score_img = 'stars-' + str(avg_score).split('.')[0] + '-' + str(avg_score).split('.')[1] + '.png' + else: + avg_score_img = "stars-0-0.png" + + # voting links + useful_dict = { 'siteurl' : CFG_SITE_URL, + 'CFG_SITE_RECORD' : CFG_SITE_RECORD, + 'recID' : recID, + 'ln' : ln, + 'yes_img' : 'smchk_gr.gif', #'yes.gif', + 'no_img' : 'iconcross.gif' #'no.gif' + } + link = '' + _("Yes") + '' + useful_no = link + '&com_value=-1">' + _("No") + '' + + #comment row + comment_rows = ' ' + last_comment_round_name = None + comment_round_names = [comment[0] for comment in comments] + if comment_round_names: + last_comment_round_name = comment_round_names[-1] + + for comment_round_name, comments_list in comments: + comment_rows += '
' % (comment_round_name) + comment_rows += _('%(x_nb)i comments for round "%(x_name)s"') % {'x_nb': len(comments_list), 'x_name': comment_round_name} + "
" + for comment in comments_list: + if comment[c_nickname]: + nickname = comment[c_nickname] + display = nickname + else: + (uid, nickname, display) = get_user_info(comment[c_user_id]) + messaging_link = self.create_messaging_link(nickname, display, ln) + + comment_rows += ''' + + ''' + report_link = '%s/%s/%s/reviews/report?ln=%s&comid=%s' % (CFG_SITE_URL, CFG_SITE_RECORD, recID, ln, comment[c_id]) + comment_rows += self.tmpl_get_comment_with_ranking(None, ln=ln, nickname=messaging_link, + comment_uid=comment[c_user_id], + date_creation=comment[c_date_creation], + body=comment[c_body], + status='', nb_reports=0, + nb_votes_total=comment[c_nb_votes_total], + nb_votes_yes=comment[c_nb_votes_yes], + star_score=comment[c_star_score], + title=comment[c_title], report_link=report_link, recID=recID) + comment_rows += ''' + %s %s / %s
''' % (_("Was this review helpful?"), useful_yes % {'comid':comment[c_id]}, useful_no % {'comid':comment[c_id]}) + comment_rows += ''' +
+ + ''' + # Close comment round + comment_rows += '
' + + # write button + write_button_link = '''%s/%s/%s/reviews/add''' % (CFG_SITE_URL, CFG_SITE_RECORD, recID) + write_button_form = ' ' % ln + write_button_form = self.createhiddenform(action=write_button_link, method="get", text=write_button_form, button=_("Write a review")) + + if nb_comments_total > 0: + avg_score_img = str(avg_score_img) + avg_score = str(avg_score) + nb_comments_total = str(nb_comments_total) + score = '' + score += _("Average review score: %(x_nb_score)s based on %(x_nb_reviews)s reviews") % \ + {'x_nb_score': '' + avg_score + '', + 'x_nb_reviews': nb_comments_total} + useful_label = _("Readers found the following %s reviews to be most helpful.") + useful_label %= len(comments) > 1 and len(comments) or "" + view_all_comments_link ='' % (CFG_SITE_URL, CFG_SITE_RECORD, recID, ln) + view_all_comments_link += _("View all %s reviews") % nb_comments_total + view_all_comments_link += '
' + + out = warnings + """ + + + + + +
%(comment_title)s:
+ %(score_label)s
+ %(useful_label)s + + + %(comment_rows)s +
+ %(view_all_comments_link)s + %(write_button_form)s
+ """ % \ + { 'comment_title' : _("Rate this document"), + 'score_label' : score, + 'useful_label' : useful_label, + 'recID' : recID, + 'view_all_comments' : _("View all %s reviews") % (nb_comments_total,), + 'write_comment' : _("Write a review"), + 'comment_rows' : comment_rows, + 'tab' : ' '*4, + 'siteurl' : CFG_SITE_URL, + 'view_all_comments_link': nb_comments_total>0 and view_all_comments_link or "", + 'write_button_form' : write_button_form + } + else: + out = ''' + + + + + +
%s:
+ %s
+ %s +
''' % (_("Rate this document"), + _('Be the first to review this document.'), + write_button_form) + return out + + def tmpl_get_comment_without_ranking(self, req, ln, nickname, comment_uid, date_creation, body, status, nb_reports, reply_link=None, report_link=None, undelete_link=None, delete_links=None, unreport_link=None, recID=-1, com_id='', attached_files=None, collapsed_p=False): + """ + private function + @param req: request object to fetch user info + @param ln: language + @param nickname: nickname + @param date_creation: date comment was written + @param body: comment body + @param status: status of the comment: + da: deleted by author + dm: deleted by moderator + ok: active + @param nb_reports: number of reports the comment has + @param reply_link: if want reply and report, give the http links + @param report_link: if want reply and report, give the http links + @param undelete_link: http link to delete the message + @param delete_links: http links to delete the message + @param unreport_link: http link to unreport the comment + @param recID: recID where the comment is posted + @param com_id: ID of the comment displayed + @param attached_files: list of attached files + @param collapsed_p: if the comment should be collapsed or not + @return: html table of comment + """ + from invenio.search_engine import guess_primary_collection_of_a_record + # load the right message language + _ = gettext_set_language(ln) + user_info = collect_user_info(req) + date_creation = convert_datetext_to_dategui(date_creation, ln=ln) + if attached_files is None: + attached_files = [] + out = '' + final_body = email_quoted_txt2html(body) + title = nickname + title += '' % (com_id, com_id) + links = '' + if not isGuestUser(user_info['uid']): + # Add link to toggle comment visibility + links += create_html_link(CFG_SITE_URL + '/' + CFG_SITE_RECORD + '/' + str(recID) + '/comments/toggle', + {'comid': com_id, 'ln': ln, 'collapse': collapsed_p and '0' or '1', 'referer': user_info['uri']}, + _("Close"), + {'onclick': "return toggle_visibility(this, %s, 'fast');" % com_id}, + escape_linkattrd=False) + moderator_links = '' + if reply_link: + links += '' + _("Reply") +'' + if report_link and status != 'ap': + links += '' + _("Report abuse") + '' + # Check if user is a comment moderator + record_primary_collection = guess_primary_collection_of_a_record(recID) + (auth_code, auth_msg) = acc_authorize_action(user_info, 'moderatecomments', collection=record_primary_collection) + if status in ['dm', 'da'] and req: + if not auth_code: + if status == 'dm': + final_body = '
(Comment deleted by the moderator) - not visible for users

' +\ + final_body + '
' + else: + final_body = '
(Comment deleted by the author) - not visible for users

' +\ + final_body + '
' + + links = '' + moderator_links += '' + _("Undelete comment") + '' + else: + if status == 'dm': + final_body = '
Comment deleted by the moderator
' + else: + final_body = '
Comment deleted by the author
' + links = '' + else: + if not auth_code: + moderator_links += '' + _("Delete comment") + '' + elif (user_info['uid'] == comment_uid) and CFG_WEBCOMMENT_AUTHOR_DELETE_COMMENT_OPTION: + moderator_links += '' + _("Delete comment") + '' + + if nb_reports >= CFG_WEBCOMMENT_NB_REPORTS_BEFORE_SEND_EMAIL_TO_ADMIN: + if not auth_code: + final_body = '
(Comment reported. Pending approval) - not visible for users

' + final_body + '
' + links = '' + moderator_links += '' + _("Unreport comment") + '' + else: + final_body = '
This comment is pending approval due to user reports
' + links = '' + if links and moderator_links: + links = links + moderator_links + elif not links: + links = moderator_links + + attached_files_html = '' + if attached_files: + attached_files_html = '
%s:
' % (len(attached_files) == 1 and _("Attached file") or _("Attached files")) + for (filename, filepath, fileurl) in attached_files: + attached_files_html += create_html_link(urlbase=fileurl, urlargd={}, + link_label=cgi.escape(filename)) + '
' + attached_files_html += '
' + + toggle_visibility_block = '' + if not isGuestUser(user_info['uid']): + toggle_visibility_block = """
%(collapse_label)s
""" % \ + {'comid': com_id, + 'toggle_url': create_url(CFG_SITE_URL + '/' + CFG_SITE_RECORD + '/' + str(recID) + '/comments/toggle', {'comid': com_id, 'ln': ln, 'collapse': collapsed_p and '0' or '1', 'referer': user_info['uri']}), + 'collapse_ctr_class': collapsed_p and 'webcomment_collapse_ctr_right' or 'webcomment_collapse_ctr_down', + 'collapse_label': collapsed_p and _("Open") or _("Close")} + + out += """ +
+ %(toggle_visibility_block)s +
avatar
+
+
+ %(title)s +
%(date)s
+ +
+
+
+ %(body)s +
+ %(attached_files_html)s + +
%(links)s
+
+
+
+
+
""" % \ + {'title' : title, + 'body' : final_body, + 'links' : links, + 'attached_files_html': attached_files_html, + 'date': date_creation, + 'site_url': CFG_SITE_URL, + 'comid': com_id, + 'collapsible_content_style': collapsed_p and 'display:none' or '', + 'toggle_visibility_block': toggle_visibility_block, + } + return out + + def tmpl_get_comment_with_ranking(self, req, ln, nickname, comment_uid, date_creation, body, status, nb_reports, nb_votes_total, nb_votes_yes, star_score, title, report_link=None, delete_links=None, undelete_link=None, unreport_link=None, recID=-1): + """ + private function + @param req: request object to fetch user info + @param ln: language + @param nickname: nickname + @param date_creation: date comment was written + @param body: comment body + @param status: status of the comment + @param nb_reports: number of reports the comment has + @param nb_votes_total: total number of votes for this review + @param nb_votes_yes: number of positive votes for this record + @param star_score: star score for this record + @param title: title of review + @param report_link: if want reply and report, give the http links + @param undelete_link: http link to delete the message + @param delete_link: http link to delete the message + @param unreport_link: http link to unreport the comment + @param recID: recID where the comment is posted + @return: html table of review + """ + from invenio.search_engine import guess_primary_collection_of_a_record + # load the right message language + _ = gettext_set_language(ln) + + if star_score > 0: + star_score_img = 'stars-' + str(star_score) + '-0.png' + else: + star_score_img = 'stars-0-0.png' + + out = "" + + date_creation = convert_datetext_to_dategui(date_creation, ln=ln) + reviewed_label = _("Reviewed by %(x_nickname)s on %(x_date)s") % {'x_nickname': nickname, 'x_date':date_creation} + ## FIX + nb_votes_yes = str(nb_votes_yes) + nb_votes_total = str(nb_votes_total) + useful_label = _("%(x_nb_people)s out of %(x_nb_total)s people found this review useful") % {'x_nb_people': nb_votes_yes, + 'x_nb_total': nb_votes_total} + links = '' + _body = '' + if body != '': + _body = ''' +
+%s +
''' % email_quoted_txt2html(body, linebreak_html='') + + # Check if user is a comment moderator + record_primary_collection = guess_primary_collection_of_a_record(recID) + user_info = collect_user_info(req) + (auth_code, auth_msg) = acc_authorize_action(user_info, 'moderatecomments', collection=record_primary_collection) + if status in ['dm', 'da'] and req: + if not auth_code: + if status == 'dm': + _body = '
(Review deleted by moderator) - not visible for users

' +\ + _body + '
' + else: + _body = '
(Review deleted by author) - not visible for users

' +\ + _body + '
' + links = '' + _("Undelete review") + '' + else: + if status == 'dm': + _body = '
Review deleted by moderator
' + else: + _body = '
Review deleted by author
' + links = '' + else: + if not auth_code: + links += '' + _("Delete review") + '' + + if nb_reports >= CFG_WEBCOMMENT_NB_REPORTS_BEFORE_SEND_EMAIL_TO_ADMIN: + if not auth_code: + _body = '
(Review reported. Pending approval) - not visible for users

' + _body + '
' + links += ' | ' + links += '' + _("Unreport review") + '' + else: + _body = '
This review is pending approval due to user reports.
' + links = '' + + out += ''' +
+
+ %(star_score)s/>
+      <div class=%(title)s
+
%(reviewed_label)s
+
%(useful_label)s
+ %(body)s +
+ +%(abuse)s''' % {'siteurl' : CFG_SITE_URL, + 'star_score_img': star_score_img, + 'star_score' : star_score, + 'title' : cgi.escape(title), + 'reviewed_label': reviewed_label, + 'useful_label' : useful_label, + 'body' : _body, + 'abuse' : links + } + return out + + def tmpl_get_comments(self, req, recID, ln, + nb_per_page, page, nb_pages, + display_order, display_since, + CFG_WEBCOMMENT_ALLOW_REVIEWS, + comments, total_nb_comments, + avg_score, + warnings, + border=0, reviews=0, + total_nb_reviews=0, + nickname='', uid=-1, note='',score=5, + can_send_comments=False, + can_attach_files=False, + user_is_subscribed_to_discussion=False, + user_can_unsubscribe_from_discussion=False, + display_comment_rounds=None): + """ + Get table of all comments + @param recID: record id + @param ln: language + @param nb_per_page: number of results per page + @param page: page number + @param display_order: hh = highest helpful score, review only + lh = lowest helpful score, review only + hs = highest star score, review only + ls = lowest star score, review only + od = oldest date + nd = newest date + @param display_since: all= no filtering by date + nd = n days ago + nw = n weeks ago + nm = n months ago + ny = n years ago + where n is a single digit integer between 0 and 9 + @param CFG_WEBCOMMENT_ALLOW_REVIEWS: is ranking enable, get from config.py/CFG_WEBCOMMENT_ALLOW_REVIEWS + @param comments: tuple as returned from webcomment.py/query_retrieve_comments_or_remarks + @param total_nb_comments: total number of comments for this record + @param avg_score: average score of reviews for this record + @param warnings: list of warning tuples (warning_text, warning_color) + @param border: boolean, active if want to show border around each comment/review + @param reviews: boolean, enabled for reviews, disabled for comments + @param can_send_comments: boolean, if user can send comments or not + @param can_attach_files: boolean, if user can attach file to comment or not + @param user_is_subscribed_to_discussion: True if user already receives new comments by email + @param user_can_unsubscribe_from_discussion: True is user is allowed to unsubscribe from discussion + """ + # load the right message language + _ = gettext_set_language(ln) + + # CERN hack begins: display full ATLAS user name. Check further below too. + current_user_fullname = "" + override_nickname_p = False + if CFG_CERN_SITE: + from invenio.search_engine import get_all_collections_of_a_record + user_info = collect_user_info(uid) + if 'atlas-readaccess-active-members [CERN]' in user_info['group']: + # An ATLAS member is never anonymous to its colleagues + # when commenting inside ATLAS collections + recid_collections = get_all_collections_of_a_record(recID) + if 'ATLAS' in str(recid_collections): + override_nickname_p = True + current_user_fullname = user_info.get('external_fullname', '') + # CERN hack ends + + # naming data fields of comments + if reviews: + c_nickname = 0 + c_user_id = 1 + c_date_creation = 2 + c_body = 3 + c_status = 4 + c_nb_reports = 5 + c_nb_votes_yes = 6 + c_nb_votes_total = 7 + c_star_score = 8 + c_title = 9 + c_id = 10 + c_round_name = 11 + c_restriction = 12 + reply_to = 13 + c_visibility = 14 + discussion = 'reviews' + comments_link = '%s (%i)' % (CFG_SITE_URL, CFG_SITE_RECORD, recID, _('Comments'), total_nb_comments) + reviews_link = '%s (%i)' % (_('Reviews'), total_nb_reviews) + add_comment_or_review = self.tmpl_add_comment_form_with_ranking(recID, uid, current_user_fullname or nickname, ln, '', score, note, warnings, show_title_p=True, can_attach_files=can_attach_files) + else: + c_nickname = 0 + c_user_id = 1 + c_date_creation = 2 + c_body = 3 + c_status = 4 + c_nb_reports = 5 + c_id = 6 + c_round_name = 7 + c_restriction = 8 + reply_to = 9 + c_visibility = 10 + discussion = 'comments' + comments_link = '%s (%i)' % (_('Comments'), total_nb_comments) + reviews_link = '%s (%i)' % (CFG_SITE_URL, CFG_SITE_RECORD, recID, _('Reviews'), total_nb_reviews) + add_comment_or_review = self.tmpl_add_comment_form(recID, uid, nickname, ln, note, warnings, can_attach_files=can_attach_files, user_is_subscribed_to_discussion=user_is_subscribed_to_discussion) + + # voting links + useful_dict = { 'siteurl' : CFG_SITE_URL, + 'CFG_SITE_RECORD' : CFG_SITE_RECORD, + 'recID' : recID, + 'ln' : ln, + 'do' : display_order, + 'ds' : display_since, + 'nb' : nb_per_page, + 'p' : page, + 'reviews' : reviews, + 'discussion' : discussion + } + useful_yes = '' + _("Yes") + '' + useful_yes %= useful_dict + useful_no = '' + _("No") + '' + useful_no %= useful_dict + warnings = self.tmpl_warnings(warnings, ln) + + link_dic = { 'siteurl' : CFG_SITE_URL, + 'CFG_SITE_RECORD' : CFG_SITE_RECORD, + 'module' : 'comments', + 'function' : 'index', + 'discussion': discussion, + 'arguments' : 'do=%s&ds=%s&nb=%s' % (display_order, display_since, nb_per_page), + 'arg_page' : '&p=%s' % page, + 'page' : page, + 'rec_id' : recID} + + if not req: + req = None + ## comments table + comments_rows = '' + last_comment_round_name = None + comment_round_names = [comment[0] for comment in comments] + if comment_round_names: + last_comment_round_name = comment_round_names[-1] + + for comment_round_name, comments_list in comments: + comment_round_style = "display:none;" + comment_round_is_open = False + + if comment_round_name in display_comment_rounds: + comment_round_is_open = True + comment_round_style = "" + comments_rows += '
' % (comment_round_name) + if not comment_round_is_open and \ + (comment_round_name or len(comment_round_names) > 1): + new_cmtgrp = list(display_comment_rounds) + new_cmtgrp.append(comment_round_name) + comments_rows += '''Open group + ' + comments_rows += _('%(x_nb)i comments for round "%(x_name)s"') % {'x_nb': len(comments_list), 'x_name': comment_round_name} + "
" + elif comment_round_name or len(comment_round_names) > 1: + new_cmtgrp = list(display_comment_rounds) + new_cmtgrp.remove(comment_round_name) + + comments_rows += '''Close group + ' + comments_rows += _('%(x_nb)i comments for round "%(x_name)s"') % {'x_nb': len(comments_list), 'x_name': comment_round_name}+ "
" + comments_rows += '
' % (comment_round_name, + comment_round_style) + comments_rows += ''' + + ''' % {'siteurl': CFG_SITE_URL, + 'recID': recID, + 'ln': ln, + 'CFG_SITE_RECORD': CFG_SITE_RECORD, + 'open_label': _("Open"), + 'close_label': _("Close")} + thread_history = [0] + previous_depth = 0 + for comment in comments_list: + if comment[reply_to] not in thread_history: + # Going one level down in the thread + thread_history.append(comment[reply_to]) + depth = thread_history.index(comment[reply_to]) + else: + depth = thread_history.index(comment[reply_to]) + thread_history = thread_history[:depth + 1] + + if previous_depth > depth: + comments_rows += ("""
""" * (previous_depth-depth)) + + if previous_depth < depth: + comments_rows += ("""
""" * (depth-previous_depth)) + + previous_depth = depth + + # CERN hack begins: display full ATLAS user name. + comment_user_fullname = "" + if CFG_CERN_SITE and override_nickname_p: + comment_user_fullname = get_email(comment[c_user_id]) + # CERN hack ends + + if comment[c_nickname]: + _nickname = comment[c_nickname] + display = _nickname + else: + (uid, _nickname, display) = get_user_info(comment[c_user_id]) + messaging_link = self.create_messaging_link(_nickname, comment_user_fullname or display, ln) + from invenio.webcomment import get_attached_files # FIXME + files = get_attached_files(recID, comment[c_id]) + # do NOT delete the HTML comment below. It is used for parsing... (I plead unguilty!) + comments_rows += """ + +
""" + delete_links = {} + if not reviews: + report_link = '%(siteurl)s/%(CFG_SITE_RECORD)s/%(recID)s/comments/report?ln=%(ln)s&comid=%%(comid)s&do=%(do)s&ds=%(ds)s&nb=%(nb)s&p=%(p)s&referer=%(siteurl)s/%(CFG_SITE_RECORD)s/%(recID)s/comments/display' % useful_dict % {'comid':comment[c_id]} + reply_link = '%(siteurl)s/%(CFG_SITE_RECORD)s/%(recID)s/comments/add?ln=%(ln)s&action=REPLY&comid=%%(comid)s' % useful_dict % {'comid':comment[c_id]} + delete_links['mod'] = "%s/admin/webcomment/webcommentadmin.py/del_single_com_mod?ln=%s&id=%s" % (CFG_SITE_URL, ln, comment[c_id]) + delete_links['auth'] = "%s/admin/webcomment/webcommentadmin.py/del_single_com_auth?ln=%s&id=%s" % (CFG_SITE_URL, ln, comment[c_id]) + undelete_link = "%s/admin/webcomment/webcommentadmin.py/undel_com?ln=%s&id=%s" % (CFG_SITE_URL, ln, comment[c_id]) + unreport_link = "%s/admin/webcomment/webcommentadmin.py/unreport_com?ln=%s&id=%s" % (CFG_SITE_URL, ln, comment[c_id]) + comments_rows += self.tmpl_get_comment_without_ranking(req, ln, messaging_link, comment[c_user_id], comment[c_date_creation], comment[c_body], comment[c_status], comment[c_nb_reports], reply_link, report_link, undelete_link, delete_links, unreport_link, recID, comment[c_id], files, comment[c_visibility]) + else: + report_link = '%(siteurl)s/%(CFG_SITE_RECORD)s/%(recID)s/reviews/report?ln=%(ln)s&comid=%%(comid)s&do=%(do)s&ds=%(ds)s&nb=%(nb)s&p=%(p)s&referer=%(siteurl)s/%(CFG_SITE_RECORD)s/%(recID)s/reviews/display' % useful_dict % {'comid': comment[c_id]} + delete_links['mod'] = "%s/admin/webcomment/webcommentadmin.py/del_single_com_mod?ln=%s&id=%s" % (CFG_SITE_URL, ln, comment[c_id]) + delete_links['auth'] = "%s/admin/webcomment/webcommentadmin.py/del_single_com_auth?ln=%s&id=%s" % (CFG_SITE_URL, ln, comment[c_id]) + undelete_link = "%s/admin/webcomment/webcommentadmin.py/undel_com?ln=%s&id=%s" % (CFG_SITE_URL, ln, comment[c_id]) + unreport_link = "%s/admin/webcomment/webcommentadmin.py/unreport_com?ln=%s&id=%s" % (CFG_SITE_URL, ln, comment[c_id]) + comments_rows += self.tmpl_get_comment_with_ranking(req, ln, messaging_link, comment[c_user_id], comment[c_date_creation], comment[c_body], comment[c_status], comment[c_nb_reports], comment[c_nb_votes_total], comment[c_nb_votes_yes], comment[c_star_score], comment[c_title], report_link, delete_links, undelete_link, unreport_link, recID) + helpful_label = _("Was this review helpful?") + report_abuse_label = "(" + _("Report abuse") + ")" + yes_no_separator = ' / ' + if comment[c_nb_reports] >= CFG_WEBCOMMENT_NB_REPORTS_BEFORE_SEND_EMAIL_TO_ADMIN or comment[c_status] in ['dm', 'da']: + report_abuse_label = "" + helpful_label = "" + useful_yes = "" + useful_no = "" + yes_no_separator = "" + comments_rows += """ + + + + + %(yes_no_separator)s + + + +
%(helpful_label)s %(tab)s %(yes)s %(no)s %(tab)s%(tab)s%(report_abuse_label)s
""" \ + % {'helpful_label': helpful_label, + 'yes' : useful_yes % {'comid':comment[c_id]}, + 'yes_no_separator': yes_no_separator, + 'no' : useful_no % {'comid':comment[c_id]}, + 'report' : report_link % {'comid':comment[c_id]}, + 'report_abuse_label': comment[c_nb_reports] >= CFG_WEBCOMMENT_NB_REPORTS_BEFORE_SEND_EMAIL_TO_ADMIN and '' or report_abuse_label, + 'tab' : ' '*2} + # do NOT remove HTML comment below. It is used for parsing... + comments_rows += """ +
+ """ + comments_rows += '
' + + ## page links + page_links = '' + # Previous + if page != 1: + link_dic['arg_page'] = 'p=%s' % (page - 1) + page_links += '<< ' % link_dic + else: + page_links += ' %s ' % (' '*(len(_('Previous'))+7)) + # Page Numbers + for i in range(1, nb_pages+1): + link_dic['arg_page'] = 'p=%s' % i + link_dic['page'] = '%s' % i + if i != page: + page_links += ''' + %(page)s ''' % link_dic + else: + page_links += ''' %s ''' % i + # Next + if page != nb_pages: + link_dic['arg_page'] = 'p=%s' % (page + 1) + page_links += ''' + >> ''' % link_dic + else: + page_links += '%s' % (' '*(len(_('Next'))+7)) + + ## stuff for ranking if enabled + if reviews: + if avg_score > 0: + avg_score_img = 'stars-' + str(avg_score).split('.')[0] + '-' + str(avg_score).split('.')[1] + '.png' + else: + avg_score_img = "stars-0-0.png" + ranking_average = '
' + ranking_average += _("Average review score: %(x_nb_score)s based on %(x_nb_reviews)s reviews") % \ + {'x_nb_score': '' + str(avg_score) + '', + 'x_nb_reviews': str(total_nb_reviews)} + ranking_average += '
' + else: + ranking_average = "" + + write_button_link = '''%s/%s/%s/%s/add''' % (CFG_SITE_URL, CFG_SITE_RECORD, recID, discussion) + write_button_form = '' + write_button_form = self.createhiddenform(action=write_button_link, + method="get", + text=write_button_form, + button = reviews and _('Write a review') or _('Write a comment')) + + if reviews: + total_label = _("There is a total of %s reviews") + else: + total_label = _("There is a total of %s comments") + total_label %= total_nb_comments + + review_or_comment_first = '' + if reviews == 0 and total_nb_comments == 0 and can_send_comments: + review_or_comment_first = _("Start a discussion about any aspect of this document.") + '
' + elif reviews == 1 and total_nb_reviews == 0 and can_send_comments: + review_or_comment_first = _("Be the first to review this document.") + '
' + + # do NOT remove the HTML comments below. Used for parsing + body = ''' +%(comments_and_review_tabs)s + +
+ %(comments_rows)s +
+ +%(review_or_comment_first)s +
''' % \ + { 'record_label': _("Record"), + 'back_label': _("Back to search results"), + 'total_label': total_label, + 'write_button_form' : write_button_form, + 'write_button_form_again' : total_nb_comments>3 and write_button_form or "", + 'comments_rows' : comments_rows, + 'total_nb_comments' : total_nb_comments, + 'comments_or_reviews' : reviews and _('review') or _('comment'), + 'comments_or_reviews_title' : reviews and _('Review') or _('Comment'), + 'siteurl' : CFG_SITE_URL, + 'module' : "comments", + 'recid' : recID, + 'ln' : ln, + #'border' : border, + 'ranking_avg' : ranking_average, + 'comments_and_review_tabs' : CFG_WEBCOMMENT_ALLOW_REVIEWS and \ + CFG_WEBCOMMENT_ALLOW_COMMENTS and \ + '%s | %s
' % \ + (comments_link, reviews_link) or '', + 'review_or_comment_first' : review_or_comment_first + } + + # form is not currently used. reserved for an eventual purpose + #form = """ + # Display + # comments per page that are + # and sorted by + # """ % \ + # (reviews==1 and ''' + # + # + # + # + # ''' or ''' + # ''') + # + #form_link = "%(siteurl)s/%(module)s/%(function)s" % link_dic + #form = self.createhiddenform(action=form_link, method="get", text=form, button='Go', recid=recID, p=1) + pages = """ +
+%(v_label)s %(comments_or_reviews)s %(results_nb_lower)s-%(results_nb_higher)s
+%(page_links)s +
+""" % \ + {'v_label': _("Viewing"), + 'page_links': _("Page:") + page_links , + 'comments_or_reviews': reviews and _('review') or _('comment'), + 'results_nb_lower': len(comments)>0 and ((page-1) * nb_per_page)+1 or 0, + 'results_nb_higher': page == nb_pages and (((page-1) * nb_per_page) + len(comments)) or (page * nb_per_page)} + + if nb_pages > 1: + #body = warnings + body + form + pages + body = warnings + body + pages + else: + body = warnings + body + + if reviews == 0: + if not user_is_subscribed_to_discussion: + body += '
' + '' % CFG_SITE_URL + \ + ' ' + '' + create_html_link(urlbase=CFG_SITE_URL + '/'+ CFG_SITE_RECORD +'/' + \ + str(recID) + '/comments/subscribe', + urlargd={}, + link_label=_('Subscribe')) + \ + '' + ' to this discussion. You will then receive all new comments by email.' + '
' + body += '
' + elif user_can_unsubscribe_from_discussion: + body += '
' + '' % CFG_SITE_URL + \ + ' ' + '' + create_html_link(urlbase=CFG_SITE_URL + '/'+ CFG_SITE_RECORD +'/' + \ + str(recID) + '/comments/unsubscribe', + urlargd={}, + link_label=_('Unsubscribe')) + \ + '' + ' from this discussion. You will no longer receive emails about new comments.' + '
' + body += '
' + + if can_send_comments: + body += add_comment_or_review + else: + body += '
' + _("You are not authorized to comment or review.") + '' + + return '
' + body + '
' + + def create_messaging_link(self, to, display_name, ln=CFG_SITE_LANG): + """prints a link to the messaging system""" + link = "%s/yourmessages/write?msg_to=%s&ln=%s" % (CFG_SITE_URL, to, ln) + if to: + return '%s' % (link, display_name) + else: + return display_name + + def createhiddenform(self, action="", method="get", text="", button="confirm", cnfrm='', **hidden): + """ + create select with hidden values and submit button + @param action: name of the action to perform on submit + @param method: 'get' or 'post' + @param text: additional text, can also be used to add non hidden input + @param button: value/caption on the submit button + @param cnfrm: if given, must check checkbox to confirm + @param **hidden: dictionary with name=value pairs for hidden input + @return: html form + """ + + output = """ +
""" % (action, method.lower().strip() in ['get', 'post'] and method or 'get') + output += """ + + + + + + + +
+""" + output += text + '\n' + if cnfrm: + output += """ + """ + for key in hidden.keys(): + if type(hidden[key]) is list: + for value in hidden[key]: + output += """ + """ % (key, value) + else: + output += """ + """ % (key, hidden[key]) + output += """ +
""" + output += """ + """ % (button, ) + output += """ +
+
""" + return output + + def create_write_comment_hiddenform(self, action="", method="get", text="", button="confirm", cnfrm='', + enctype='', form_id=None, form_name=None, **hidden): + """ + create select with hidden values and submit button + @param action: name of the action to perform on submit + @param method: 'get' or 'post' + @param text: additional text, can also be used to add non hidden input + @param button: value/caption on the submit button + @param cnfrm: if given, must check checkbox to confirm + @param form_id: HTML 'id' attribute of the form tag + @param form_name: HTML 'name' attribute of the form tag + @param **hidden: dictionary with name=value pairs for hidden input + @return: html form + """ + enctype_attr = '' + if enctype: + enctype_attr = 'enctype="%s"' % enctype + + output = """ +
""" % \ + (action, method.lower().strip() in ['get', 'post'] and method or 'get', + enctype_attr, form_name and ' name="%s"' % form_name or '', + form_id and ' id="%s"' % form_id or '') + if cnfrm: + output += """ + """ + for key in hidden.keys(): + if type(hidden[key]) is list: + for value in hidden[key]: + output += """ + """ % (key, value) + else: + output += """ + """ % (key, hidden[key]) + output += text + '\n' + output += """ +
""" + return output + + def tmpl_warnings(self, warnings=[], ln=CFG_SITE_LANG): + """ + Display len(warnings) warning fields + @param warnings: list of warning tuples (warning_text, warning_color) + @param ln=language + @return: html output + """ + if type(warnings) is not list: + warnings = [warnings] + warningbox = "" + if warnings: + for i in range(len(warnings)): + warning_text = warnings[i][0] + warning_color = warnings[i][1] + if warning_color == 'green': + span_class = 'exampleleader' + else: + span_class = 'important' + warningbox += ''' + %(warning)s
''' % \ + { 'span_class' : span_class, + 'warning' : warning_text } + return warningbox + else: + return "" + + def tmpl_error(self, error, ln=CFG_SITE_LANG): + """ + Display error + @param error: string + @param ln=language + @return: html output + """ + _ = gettext_set_language(ln) + errorbox = "" + if error != "": + errorbox = "
\n Error:\n" + errorbox += "

" + errorbox += error + "

" + errorbox += "

\n" + return errorbox + + def tmpl_add_comment_form(self, recID, uid, nickname, ln, msg, + warnings, textual_msg=None, can_attach_files=False, + user_is_subscribed_to_discussion=False, reply_to=None): + """ + Add form for comments + @param recID: record id + @param uid: user id + @param ln: language + @param msg: comment body contents for when refreshing due to + warning, or when replying to a comment + @param textual_msg: same as 'msg', but contains the textual + version in case user cannot display CKeditor + @param warnings: list of warning tuples (warning_text, warning_color) + @param can_attach_files: if user can upload attach file to record or not + @param user_is_subscribed_to_discussion: True if user already receives new comments by email + @param reply_to: the ID of the comment we are replying to. None if not replying + @return html add comment form + """ + _ = gettext_set_language(ln) + link_dic = { 'siteurl' : CFG_SITE_URL, + 'CFG_SITE_RECORD' : CFG_SITE_RECORD, + 'module' : 'comments', + 'function' : 'add', + 'arguments' : 'ln=%s&action=%s' % (ln, 'SUBMIT'), + 'recID' : recID} + if textual_msg is None: + textual_msg = msg + + # FIXME a cleaner handling of nicknames is needed. + if not nickname: + (uid, nickname, display) = get_user_info(uid) + if nickname: + note = _("Note: Your nickname, %s, will be displayed as author of this comment.") % ('' + nickname + '') + else: + (uid, nickname, display) = get_user_info(uid) + link = '' % CFG_SITE_SECURE_URL + note = _("Note: you have not %(x_url_open)sdefined your nickname%(x_url_close)s. %(x_nickname)s will be displayed as the author of this comment.") % \ + {'x_url_open': link, + 'x_url_close': '', + 'x_nickname': '
' + display + ''} + + if not CFG_WEBCOMMENT_USE_RICH_TEXT_EDITOR: + note += '
' + ' '*10 + cgi.escape('You can use some HTML tags: , ,
,
,

, ,