diff --git a/modules/webcomment/.cvsignore b/modules/webcomment/.cvsignore new file mode 100644 index 000000000..a3409fca7 --- /dev/null +++ b/modules/webcomment/.cvsignore @@ -0,0 +1,5 @@ +Makefile +Makefile.in +z_* +*.O +*~ \ No newline at end of file diff --git a/modules/webcomment/Makefile.am b/modules/webcomment/Makefile.am new file mode 100644 index 000000000..18a27e626 --- /dev/null +++ b/modules/webcomment/Makefile.am @@ -0,0 +1,22 @@ +## $Id$ + +## This file is part of the CERN Document Server Software (CDSware). +## Copyright (C) 2002, 2003, 2004, 2005 CERN. +## +## The CDSware 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. +## +## The CDSware 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 CDSware; if not, write to the Free Software Foundation, Inc., +## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + +SUBDIRS = lib doc web + +CLEANFILES = *~ diff --git a/modules/webcomment/doc/.cvsignore b/modules/webcomment/doc/.cvsignore new file mode 100644 index 000000000..b644e5e86 --- /dev/null +++ b/modules/webcomment/doc/.cvsignore @@ -0,0 +1,7 @@ +Makefile +Makefile.in +z_* +*.O +*~ +*.shtml +*.html diff --git a/modules/webcomment/doc/Makefile.am b/modules/webcomment/doc/Makefile.am new file mode 100644 index 000000000..98f8cd936 --- /dev/null +++ b/modules/webcomment/doc/Makefile.am @@ -0,0 +1,21 @@ +## $Id$ + +## This file is part of the CERN Document Server Software (CDSware). +## Copyright (C) 2002, 2003, 2004, 2005 CERN. +## +## The CDSware 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. +## +## The CDSware 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 CDSware; if not, write to the Free Software Foundation, Inc., +## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + +SUBDIRS = admin hacking + diff --git a/modules/webcomment/doc/admin/.cvsignore b/modules/webcomment/doc/admin/.cvsignore new file mode 100644 index 000000000..b644e5e86 --- /dev/null +++ b/modules/webcomment/doc/admin/.cvsignore @@ -0,0 +1,7 @@ +Makefile +Makefile.in +z_* +*.O +*~ +*.shtml +*.html diff --git a/modules/webcomment/doc/admin/Makefile.am b/modules/webcomment/doc/admin/Makefile.am new file mode 100644 index 000000000..7bf43a95e --- /dev/null +++ b/modules/webcomment/doc/admin/Makefile.am @@ -0,0 +1,30 @@ +## $Id$ + +## This file is part of the CERN Document Server Software (CDSware). +## Copyright (C) 2002, 2003, 2004, 2005 CERN. +## +## The CDSware 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. +## +## The CDSware 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 CDSware; if not, write to the Free Software Foundation, Inc., +## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + +docdir = $(WEBDIR)/admin/webcomment + +doc_DATA = guide.html + +FILESWML = $(wildcard $(srcdir)/*.wml) +EXTRA_DIST = $(FILESWML:$(srcdir)/%=%) + +CLEANFILES = $(doc_DATA) *~ *.tmp + +%.html: %.html.wml $(top_srcdir)/config/config.wml $(top_builddir)/config/configbis.wml $(top_srcdir)/config/cdsnavbar.wml + $(WML) -o\(ALL-LANG_*\)+LANG_EN:$@ $< diff --git a/modules/webcomment/doc/admin/guide.html.wml b/modules/webcomment/doc/admin/guide.html.wml new file mode 100644 index 000000000..181b85a49 --- /dev/null +++ b/modules/webcomment/doc/admin/guide.html.wml @@ -0,0 +1,27 @@ +## -*- mode: html; coding: utf-8; -*- +## $Id$ + +## This file is part of the CERN Document Server Software (CDSware). +## Copyright (C) 2002, 2003, 2004, 2005 CERN. +## +## The CDSware 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. +## +## The CDSware 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 CDSware; if not, write to the Free Software Foundation, Inc., +## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + +#include "cdspage.wml" \ + title="WebComment Admin Guide" \ + navtrail_previous_links="/admin/> > /admin/websearch/>WebComment Admin" \ + navbar_name="admin" \ + navbar_select="webcomment-admin-guide" + +FIXME diff --git a/modules/webcomment/doc/hacking/.cvsignore b/modules/webcomment/doc/hacking/.cvsignore new file mode 100644 index 000000000..f0878fb91 --- /dev/null +++ b/modules/webcomment/doc/hacking/.cvsignore @@ -0,0 +1,8 @@ +Makefile +Makefile.in +z_* +*.O +*~ +*.py +*.shtml +*.html \ No newline at end of file diff --git a/modules/webcomment/doc/hacking/Makefile.am b/modules/webcomment/doc/hacking/Makefile.am new file mode 100644 index 000000000..5ac343f5b --- /dev/null +++ b/modules/webcomment/doc/hacking/Makefile.am @@ -0,0 +1,21 @@ +## $Id$ + +## This file is part of the CERN Document Server Software (CDSware). +## Copyright (C) 2002, 2003, 2004, 2005 CERN. +## +## The CDSware 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. +## +## The CDSware 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 CDSware; if not, write to the Free Software Foundation, Inc., +## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + +docdir = $(WEBDIR)/hacking/webcomment + diff --git a/modules/webcomment/lib/.cvsignore b/modules/webcomment/lib/.cvsignore new file mode 100644 index 000000000..9638520ce --- /dev/null +++ b/modules/webcomment/lib/.cvsignore @@ -0,0 +1,6 @@ +Makefile +Makefile.in +z_* +*.O +*~ +*.pyc \ No newline at end of file diff --git a/modules/webcomment/lib/Makefile.am b/modules/webcomment/lib/Makefile.am new file mode 100644 index 000000000..97ab2552f --- /dev/null +++ b/modules/webcomment/lib/Makefile.am @@ -0,0 +1,26 @@ +## $Id$ + +## This file is part of the CERN Document Server Software (CDSware). +## Copyright (C) 2002, 2003, 2004, 2005 CERN. +## +## The CDSware 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. +## +## The CDSware 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 CDSware; if not, write to the Free Software Foundation, Inc., +## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + +pylibdir = $(libdir)/python/cdsware + +pylib_DATA = webcomment_config.py webcomment.py webcomment_tests.py webcomment_templates.py webcommentadminlib.py + +EXTRA_DIST = $(pylib_DATA) + +CLEANFILES = *~ *.tmp *.pyc diff --git a/modules/webcomment/lib/webcomment.py b/modules/webcomment/lib/webcomment.py new file mode 100644 index 000000000..539ba0c96 --- /dev/null +++ b/modules/webcomment/lib/webcomment.py @@ -0,0 +1,857 @@ +# -*- coding: utf-8 -*- +## $Id$ +## Comments and reviews for records. + +## This file is part of the CERN Document Server Software (CDSware). +## Copyright (C) 2002, 2003, 2004, 2005 CERN. +## +## The CDSware 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. +## +## The CDSware 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 CDSware; if not, write to the Free Software Foundation, Inc., +## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + +__lastupdated__ = """FIXME: last updated""" + +# non CDSware imports: +from email.Utils import quote +import time +import math +import string +from cgi import escape + +# import CDSware stuff: +from webcomment_config import * +from dbquery import run_sql +from config import cdslang +from elmsubmit_html2txt import html2txt + +import template +webcomment_templates = template.load('webcomment') + +def perform_request_display_comments_or_remarks(recID, ln=cdslang, display_order='od', display_since='all', nb_per_page=100, page=1, voted=-1, reported=-1, reviews=0): + """ + Returns all the comments (reviews) of a specific internal record or external basket record. + @param recID: record id where (internal record IDs > 0) or (external basket record IDs < -100) + @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 nb_per_page: number of results per page + @param page: results page + @param voted: boolean, active if user voted for a review, see perform_request_vote function + @param reported: boolean, active if user reported a certain comment/review, perform_request_report function + @param reviews: boolean, enabled if reviews, disabled for comments + @return html body. + """ + + errors = [] + warnings = [] + + # wash arguments + recID= wash_url_argument(recID, 'int') + ln = wash_url_argument(ln, 'str') + display_order = wash_url_argument(display_order, 'str') + display_since = wash_url_argument(display_since, 'str') + nb_per_page = wash_url_argument(nb_per_page, 'int') + page = wash_url_argument(page, 'int') + voted = wash_url_argument(voted, 'int') + reported = wash_url_argument(reported, 'int') + reviews = wash_url_argument(reviews, 'int') + + # vital argument check + check_recID_is_in_range(recID, errors) + + # Query the database and filter results + res = query_retrieve_comments_or_remarks(recID, display_order, display_since, reviews) + nb_res = len(res) + + # chekcing non vital arguemnts - will be set to default if wrong + #if page <= 0 or page.lower() != 'all': + if page < 0: + page = 1 + warnings.append(('WRN_WEBCOMMENT_INVALID_PAGE_NB',)) + if nb_per_page < 0: + nb_per_page = 100 + warnings.append(('WRN_WEBCOMMENT_INVALID_NB_RESULTS_PER_PAGE',)) + if cfg_webcomment_allow_reviews and reviews: + if display_order not in ['od', 'nd', 'hh', 'lh', 'hs', 'ls']: + display_order = 'hh' + warnings.append(('WRN_WEBCOMMENT_INVALID_REVIEW_DISPLAY_ORDER',)) + else: + if display_order not in ['od', 'nd']: + display_order = 'od' + warnings.append(('WRN_WEBCOMMENT_INVALID_DISPLAY_ORDER',)) + + # filter results according to page and number of reults per page + if nb_per_page > 0: + if nb_res > 0: + last_page = int(math.ceil(nb_res / float(nb_per_page))) + else: + last_page = 1 + if page > last_page: + page = 1 + warnings.append(("WRN_WEBCOMMENT_INVALID_PAGE_NB",)) + if nb_res > nb_per_page: # if more than one page of results + if page < last_page: + res = res[(page-1)*(nb_per_page) : (page*nb_per_page)] + else: + res = res[(page-1)*(nb_per_page) : ] + else: # one page of results + pass + else: + last_page = 1 + + # Send to template + # record is an internal record + if recID > 0: + avg_score = 0.0 + if not cfg_webcomment_allow_comments and not cfg_webcomment_allow_reviews: # comments not allowed by admin + errors.append(('ERR_WEBCOMMENT_COMMENTS_NOT_ALLOWED',)) + if reported > 0: + warnings.append(('WRN_WEBCOMMENT_FEEDBACK_RECORDED_GREEN_TEXT',)) + elif reported == 0: + warnings.append(('WRN_WEBCOMMENT_FEEDBACK_NOT_RECORDED_RED_TEXT',)) + if cfg_webcomment_allow_reviews and reviews: + avg_score = calculate_avg_score(res) + if voted>0: + warnings.append(('WRN_WEBCOMMENT_FEEDBACK_RECORDED_GREEN_TEXT',)) + elif voted == 0: + warnings.append(('WRN_WEBCOMMENT_FEEDBACK_NOT_RECORDED_RED_TEXT',)) + body = webcomment_templates.tmpl_get_comments(recID, ln, nb_per_page, page, last_page, display_order, display_since, cfg_webcomment_allow_reviews, res, + nb_res, avg_score, warnings, border=0, reviews=reviews) + return (body, errors, warnings) + # record is an external record + else: + return ("TODO", errors, warnings) #!FIXME + +def perform_request_vote(comID, value): + """ + Vote positively or negatively for a comment/review + @param comID: review id + @param value: +1 for voting positively + -1 for voting negatively + @return integer 1 if successful, integer 0 if not + """ + #FIXME should record IP address and not allow voters to vote more than once + comID = wash_url_argument(comID, 'int') + value = wash_url_argument(value, 'int') + if comID > 0 and value in [-1, 1]: + return query_record_useful_review(comID, value) + else: + return 0 + +def perform_request_report(comID): + """ + Report a comment/review for inappropriate content. + Will send an email to the administrator if number of reports is a multiple of config.py/cfg_comment_nb_reports_before_send_email_to_admin + @param comID: comment id + @return integer 1 if successful, integer 0 if not + """ + #FIXME should record IP address and not allow reporters to report more than once + comID = wash_url_argument(comID, 'int') + if comID <= 0: + return 0 + (query_res, nb_reported) = query_record_report_this(comID) + if query_res == 0: + return 0 + if nb_reported % cfg_webcomment_nb_reports_before_send_email_to_admin == 0: + (comID2, id_bibrec, id_user, com_body, com_date, com_star, com_vote, com_nb_votes, com_star_note, com_reported) = query_get_comment(comID) + (user_nb_reported, user_votes, user_nb_votes) = query_get_user_reports_and_votes(int(id_user)) + (nickname, user_email, last_login) = query_get_user_contact_info(id_user) + from_addr = 'CDS Alert Engine <%s>' % alertengineemail + to_addr = adminemail + body = ''' +The following comment has been reported a total of %(com_reported)s times. + +Author: nickname = %(nickname)s + email = %(user_email)s + user_id = %(uid)s + This user has: + total number of reports = %(user_nb_reported)s + %(votes)s +Comment: comment_id = %(comID)s + record_id = %(id_bibrec)s + date written = %(com_date)s + nb reports = %(com_reported)s + %(review_stuff)s + body = +---start body--- +%(com_body)s +---end body--- + +Please go to the Comments Admin Panel %(comment_admin_link)s to delete this message if necessary. A warning will be sent to the user in question.''' % \ + { 'cfg-report_max' : cfg_webcomment_nb_reports_before_send_email_to_admin, + 'nickname' : nickname, + 'user_email' : user_email, + 'uid' : id_user, + 'user_nb_reported' : user_nb_reported, + 'user_votes' : user_votes, + 'votes' : cfg_webcomment_allow_reviews and \ + "total number of positive votes\t= %s\n\t\t\t\ttotal number of negative votes\t= %s" % \ + (user_votes, (user_nb_votes - user_votes)) or "\n", + 'comID' : comID, + 'id_bibrec' : id_bibrec, + 'com_date' : com_date, + 'com_reported' : com_reported, + 'review_stuff' : cfg_webcomment_allow_reviews and \ + "star score\t\t= %s\n\t\t\treview title\t\t= %s" % (com_star, com_star_note) or "", + 'com_body' : com_body, + 'comment_admin_link' : "http://%s/admin/webcomment/" % weburl, + 'user_admin_link' : "user_admin_link" #! FIXME + } + + #FIXME to be added to email + #If you wish to ban the user, you can do so via the User Admin Panel %(user_admin_link)s. + + from alert_engine import send_email + send_email(from_addr, to_addr, body) + return 1 + +def query_get_user_contact_info(uid): + """ + Get the user contact information + @return tuple (nickname, email, last_login), if none found return () + Note: for the moment, if no nickname, will return email address up to the '@' + """ + query1 = "SELECT email, nickname, last_login FROM user WHERE id=%s" + params1 = (uid,) + res1 = run_sql(query1, params1) + if len(res1)==0: + return () + #!FIXME - extra code because still possible to have no nickname + res2 = list(res1[0]) + if not res2[1]: + res2[1] = res2[0].split('@')[0] + return (res2[1], res2[0], res2[2]) +# return (res1[0][1], res1[0][0], res1[0][2]) + +def query_get_user_reports_and_votes(uid): + """ + Retrieve total number of reports and votes of a particular user + @param uid: user id + @return tuple (total_nb_reports, total_vote_value, total_nb_votes) + if none found return () + """ + query1 = "SELECT vote_value, nb_votes, nb_reported FROM cmtRECORDCOMMENT WHERE id_user=%s" + params1 = (uid,) + res1 = run_sql(query1, params1) + if len(res1)==0: + return () + vote_value = nb_votes = nb_reported = 0 + for cmt_tuple in res1: + vote_value += int(cmt_tuple[0]) + nb_votes += int(cmt_tuple[1]) + nb_reported += int(cmt_tuple[2]) + return (nb_reported, vote_value, nb_votes) + +def query_get_comment(comID): + """ + Get all fields of a comment + @param comID: comment id + @return tuple (comID, id_bibrec, id_user, body, date_creation, star_score, vote_value, nb_votes, star_note, nb_reported) + if none found return () + """ + query1 = "SELECT * FROM cmtRECORDCOMMENT WHERE id=%s" + params1 = (comID,) + res1 = run_sql(query1, params1) + if len(res1)>0: + return res1[0] + else: + return () + +def query_record_report_this(comID): + """ + Increment the number of reports for a comment + @param comID: comment id + @return tuple (success, new_total_nb_reports_for_this_comment) where success is integer 1 if success, integer 0 if not + if none found, return () + """ + #retrieve nb_reported + query1 = "SELECT nb_reported FROM cmtRECORDCOMMENT WHERE id=%s" + params1 = (comID,) + res1 = run_sql(query1, params1) + if len(res1)==0: + return () + + #increment and update + nb_reported = int(res1[0][0]) + 1 + query2 = "UPDATE cmtRECORDCOMMENT SET nb_reported=%s WHERE id=%s" + params2 = (nb_reported, comID) + res2 = run_sql(query2, params2) + return (int(res2), nb_reported) + +def query_record_useful_review(comID, value): + """ + private funciton + Adjust the number of useful votes and number of total votes for a comment. + @param comID: comment id + @param value: +1 or -1 + @return integer 1 if successful, integer 0 if not + """ + # retrieve nb_useful votes + query1 = "SELECT nb_votes, vote_value FROM cmtRECORDCOMMENT WHERE id=%s" + params1 = (comID,) + res1 = run_sql(query1, params1) + if len(res1)==0: + return 0 + + # modify and insert new nb_useful votes + vote_value = int(res1[0][1]) + value + nb_votes = int(res1[0][0]) + 1 + query2 = "UPDATE cmtRECORDCOMMENT SET nb_votes=%s, vote_value=%s WHERE id=%s" + params2 = (nb_votes, vote_value, comID) + res2 = run_sql(query2, params2) + return int(res2) + +def query_retrieve_comments_or_remarks (recID=-1, display_order='od', display_since='0000-00-00 00:00:00', ranking=0): + """ + Private function + Retrieve tuple of comments or remarks from the database + @param recID: record id + @param display_order: hh = highest helpful score + lh = lowest helpful score + hs = highest star score + ls = lowest star score + od = oldest date + nd = newest date + @param display_since: datetime, e.g. 0000-00-00 00:00:00 + @param ranking: boolean, enabled if reviews, disabled for comments + @return tuple of comment where comment is + tuple (nickname, date_creation, body, id) if ranking disabled or + tuple (nickname, date_creation, body, vote_value, nb_votes, star_score, star_note, id) + Note: for the moment, if no nickname, will return email address up to '@' + """ + display_since = calculate_start_date(display_since) + + order_dict = { 'hh' : "c.vote_value/(c.nb_votes+1) DESC, c.date_creation DESC ", + 'lh' : "c.vote_value/(c.nb_votes+1) ASC, c.date_creation ASC ", + 'ls' : "c.star_score ASC, c.date_creation DESC ", + 'hs' : "c.star_score DESC, c.date_creation DESC ", + 'od' : "c.date_creation ASC ", + 'nd' : "c.date_creation DESC " + } + + # Ranking only done for comments and when allowed + if ranking: + try: + display_order = order_dict[display_order] + except: + display_order = order_dict['od'] + else: + try: + if display_order[-1] == 'd': + display_order = order_dict[display_order] + else: + display_order = order_dict['od'] + except: + display_order = order_dict['od'] + + query = "SELECT u.nickname, c.date_creation, c.body, %(ranking)s c.id " \ + "FROM %(table)s AS c, user AS u " \ + "WHERE %(id_bibrec)s=\'%(recID)s\' " \ + "AND c.id_user=u.id "\ + "%(ranking_only)s " \ + "%(display_since)s " \ + "ORDER BY %(display_order)s " + + params = { 'ranking' : ranking and ' c.vote_value, c.nb_votes, c.star_score, c.star_note, ' or '', + 'ranking_only' : ranking and ' AND c.star_score>0 ' or ' AND c.star_score=0 ', + 'id_bibrec' : recID>0 and 'c.id_bibrec' or 'c.id_bskBASKET_bibrec_bskEXTREC', + 'table' : recID>0 and 'cmtRECORDCOMMENT' or 'bskREMARK', + 'recID' : recID, + 'display_since' : display_since=='0000-00-00 00:00:00' and ' ' or 'AND c.date_creation>=\'%s\' ' % display_since, + 'display_order' : display_order + } + # return run_sql(query % params) + #FIXME - Extra horrible code cause nickname can still be blank + res = run_sql(query % params) #!FIXME + res2= [] + for comment in res: + if not comment[0]: + comment2 = list(comment) + user_id = query_get_comment(comment[-1])[2] + comment2[0] = query_get_user_contact_info(user_id)[1].split('@')[0] + res2.append(comment2) + else: + res2.append(comment) + return tuple(res2) + +def query_add_comment_or_remark(recID=-1, uid=-1, msg="", note="", score=0, priority=0): + """ + Private function + Insert a comment/review or remarkinto the database + @param recID: record id + @param uid: user id + @param msg: comment body + @param note: comment title + @param score: review star score + @param priority: remark priority #!FIXME + @return integer >0 representing id if successful, integer 0 if not + """ + current_date = calculate_start_date('0d') + if recID > 0: + # get rid of html tags in msg but keep newlines + msg = msg.replace ('\n', "#br#") + msg= html2txt(msg) + msg = msg.replace('#br#', '
') + note= html2txt(note) + #unicode + msg = msg.encode('utf-8') + note = note.encode('utf-8') + query = "INSERT INTO cmtRECORDCOMMENT (id_bibrec, id_user, body, date_creation, star_score, nb_votes, star_note) " \ + "VALUES (%s, %s, %s, %s, %s, %s, %s)" + params = (recID, uid, msg, current_date, score, 0, note) + else: + # get rid of html tags in msg but keep newlines + msg = msg.replace ('\n', "#br#") + msg= html2txt(msg) + msg = msg.replace('#br#', '
') + msg = msg.encode('utf-8') + query = "INSERT INTO bskREMARK (id_bskBASKET_bibrec_bibEXTREC, id_user, body, date_creation, priority) " \ + "VALUES (%s, %s, %s, %s, %s)" + params = (recID, uid, msg, current_date, priority) + + return int(run_sql(query, params)) + +def calculate_start_date(display_since): + """ + Private function + Returns the datetime of display_since argument in MYSQL datetime format + calculated according to the local time. + @param display_since = all= no filtering + nd = n days ago + nw = n weeks ago + nm = n months ago + ny = n years ago + where n is a single digit number + @return string of wanted datetime. + If 'all' given as argument, will return "0000-00-00 00:00:00" + If bad arguement given, will return "0000-00-00 00:00:00" + """ + # time type and seconds coefficients + time_types = {'d':0,'w':0,'m':0,'y':0} + + ## verify argument + # argument wrong size + if (display_since==(None or 'all')) or (len(display_since) > 2): + return ("0000-00-00 00:00:00") + try: + nb = int(display_since[0]) + except: + return ("0000-00-00 00:00:00") + if str(display_since[1]) in time_types: + time_type = str(display_since[1]) + else: + return ("0000-00-00 00:00:00") + + ## calculate date + # initialize the coef + if time_type == 'w': + time_types[time_type] = 7 + else: + time_types[time_type] = 1 + + start_time = time.localtime(time.time()) + start_time = time.mktime(( start_time[0] - nb*time_types['y'], + start_time[1] - nb*time_types['m'], + start_time[2] - nb*time_types['d'] - nb*time_types['w'], + start_time[3], + start_time[4], + start_time[5], + start_time[6], + start_time[7], + start_time[8])) + return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(start_time)) + +def get_first_comments_or_remarks(recID=-1, ln=cdslang, nb='all', voted=-1, reported=-1): + """ + Gets nb number comments/reviews or remarks. + In the case of comments, will get both comments and reviews + Comments and remarks sorted by most recent date, reviews sorted by highest helpful score + @param recID: record id + @param ln: language + @param nb: number of comment/reviews or remarks to get + @param voted: 1 if user has voted for a remark + @param reported: 1 if user has reported a comment or review + @return if comment, tuple (comments, reviews) both being html of first nb comments/reviews + if remark, tuple (remakrs, None) + """ + warnings = [] + errors = [] + voted = wash_url_argument(voted, 'int') + reported = wash_url_argument(reported, 'int') + + ## check recID argument + if type(recID) is not int: + return () + if recID >= 1 or recID <= -100: #comment or remark + if cfg_webcomment_allow_reviews: + res_reviews = query_retrieve_comments_or_remarks(recID=recID, display_order="hh", ranking=1) + nb_res_reviews = len(res_reviews) + ## check nb argument + if type(nb) is int and nb < len(res_reviews): + first_res_reviews = res_reviews[:nb] + else: + if nb_res_reviews > cfg_webcomment_nb_reviews_in_detailed_view: + first_res_reviews = res_reviews[:cfg_comment_nb_reports_before_send_email_to_admin] + else: + first_res_reviews = res_reviews + if cfg_webcomment_allow_comments: + res_comments = query_retrieve_comments_or_remarks(recID=recID, display_order="od", ranking=0) + nb_res_comments = len(res_comments) + ## check nb argument + if type(nb) is int and nb < len(res_comments): + first_res_comments = res_comments[:nb] + else: + if nb_res_comments > cfg_webcomment_nb_comments_in_detailed_view: + first_res_comments = res_comments[:cfg_webcomment_nb_comments_in_detailed_view] + else: + first_res_comments = res_comments + else: #error + errors.append(('ERR_WEBCOMMENT_RECID_INVALID', recID)) #!FIXME dont return error anywhere since search page + + # comment + if recID >= 1: + comments = reviews = "" + if reported > 0: + warnings.append(('WRN_WEBCOMMENT_FEEDBACK_RECORDED_GREEN_TEXT',)) + elif reported == 0: + warnings.append(('WRN_WEBCOMMENT_FEEDBACK_NOT_RECORDED_RED_TEXT',)) + if cfg_webcomment_allow_comments: # normal comments + comments = webcomment_templates.tmpl_get_first_comments_without_ranking(recID, ln, first_res_comments, nb_res_comments, warnings) + if cfg_webcomment_allow_reviews: # ranked comments + #calculate average score + avg_score = calculate_avg_score(res_reviews) + if voted > 0: + warnings.append(('WRN_WEBCOMMENT_FEEDBACK_RECORDED_GREEN_TEXT',)) + elif voted == 0: + warnings.append(('WRN_WEBCOMMENT_FEEDBACK_NOT_RECORDED_RED_TEXT',)) + reviews = webcomment_templates.tmpl_get_first_comments_with_ranking(recID, ln, first_res_reviews, nb_res_reviews, avg_score, warnings) + return (comments, reviews) + # remark + else: + return(webcomment_templates.tmpl_get_first_remarks(first_res_comments, ln, nb_res_comments), None) + +def calculate_avg_score(res): + """ + private function + Calculate the avg score of reviews present in res + @param res: tuple of tuple returned from query_retrieve_comments_or_remarks + @return a float of the average score rounded to the closest 0.5 + """ + + c_nickname = 0 + c_date_creation = 1 + c_body = 2 + c_vote_value = 3 + c_nb_votes = 4 + c_star_score = 5 + c_star_note = 6 + c_id = 7 + + avg_score = 0.0 + nb_reviews = 0 + for comment in res: + if comment[c_star_score] > 0: + avg_score += comment[c_star_score] + nb_reviews += 1 + if nb_reviews == 0: + return 0.0 + avg_score = avg_score / nb_reviews + avg_score_unit = avg_score - math.floor(avg_score) + if avg_score_unit < 0.25: + avg_score = math.floor(avg_score) + elif avg_score_unit > 0.75: + avg_score = math.floor(avg_score) + 1 + else: + avg_score = math.floor(avg_score) + 0.5 + if avg_score > 5: + avg_score = 5.0 + return avg_score + +def perform_request_add_comment_or_remark(recID=-1, uid=-1, action='DISPLAY', ln=cdslang, msg=None, score=None, note=None, priority=None, reviews=0, comID=-1): + """ + Add a comment/review or remark + @param recID: record id + @param uid: user id + @param action: 'DISPLAY' to display add form + 'SUBMIT' to submit comment once form is filled + 'REPLY' to reply to an existing comment + @param ln: language + @param msg: the body of the comment/review or remark + @param score: star score of the review + @param note: title of the review + @param priority: priority of remark + @param reviews: boolean, if enabled will add a review, if disabled will add a comment + @param comID: if replying, this is the comment id of the commetn are replying to + @return html add form if action is display or reply + html successful added form if action is submit + """ + + warnings = [] + errors = [] + + actions = ['DISPLAY', 'REPLY', 'SUBMIT'] + ## wash arguments + recID = wash_url_argument(recID, 'int') + uid = wash_url_argument(uid, 'int') + msg = wash_url_argument(msg, 'str') + score = wash_url_argument(score, 'int') + note = wash_url_argument(note, 'str') + priority = wash_url_argument(priority, 'int') + reviews = wash_url_argument(reviews, 'int') + comID = wash_url_argument(comID, 'int') + + ## check arguments + check_recID_is_in_range(recID, errors) + if uid <= 0: + errors.append(('ERR_WEBCOMMENT_UID_INVALID', uid)) + else: + nickname = query_get_user_contact_info(uid)[0] + + # show the form + if action == 'DISPLAY': + if reviews and cfg_webcomment_allow_reviews: + return (webcomment_templates.tmpl_add_comment_form_with_ranking(recID, uid, nickname, ln, msg, score, note, warnings), errors, warnings) + elif not reviews and cfg_webcomment_allow_comments: + return (webcomment_templates.tmpl_add_comment_form(recID, uid, nickname, ln, msg, warnings), errors, warnings) + else: + errors.append(('ERR_WEBCOMMENT_COMMENTS_NOT_ALLOWED',)) + + elif action == 'REPLY': + if reviews and cfg_webcomment_allow_reviews: + errors.append(('ERR_WEBCOMMENT_REPLY_REVIEW',)) + return (webcomment_templates.tmpl_add_comment_form_with_ranking(recID, uid, nickname, ln, msg, score, note, warnings), errors, warnings) + elif not reviews and cfg_webcomment_allow_comments: + if comID>0: + comment = query_get_comment(comID) + if comment: + user_info = query_get_user_contact_info(comment[2]) + if user_info: + msg = comment[3].replace('\n', ' ') + msg = msg.replace('
', '\n') + msg = "Quoting %s:\n%s\n" % (user_info[0], msg) + return (webcomment_templates.tmpl_add_comment_form(recID, uid, nickname, ln, msg, warnings), errors, warnings) + else: + errors.append(('ERR_WEBCOMMENT_COMMENTS_NOT_ALLOWED',)) + + # check before submitting form + elif action == 'SUBMIT': + if reviews and cfg_webcomment_allow_reviews: + if note.strip() in ["", "None"]: + warnings.append(('WRN_WEBCOMMENT_ADD_NO_TITLE',)) + if score == 0 or score > 5: + warnings.append(("WRN_WEBCOMMENT_ADD_NO_SCORE",)) + if msg.strip() in ["", "None"]: + warnings.append(('WRN_WEBCOMMENT_ADD_NO_BODY',)) + # if no warnings, submit + if len(warnings) == 0: + success = query_add_comment_or_remark(recID=recID, uid=uid, msg=msg, note=note, score=score, priority=0) + if success > 0: + if cfg_webcomment_admin_notification_level > 0: + notify_admin_of_new_comment(comID=success) + return (webcomment_templates.tmpl_add_comment_successful(recID, ln, reviews), errors, warnings) + else: + errors.append(('ERR_WEBCOMMENT_DB_INSERT_ERROR',)) + # if are warnings or if inserting comment failed, show user where warnings are + if reviews and cfg_webcomment_allow_reviews: + return (webcomment_templates.tmpl_add_comment_form_with_ranking(recID, uid, nickname, ln, msg, score, note, warnings), errors, warnings) + else: + return (webcomment_templates.tmpl_add_comment_form(recID, uid, nickname, ln, msg, warnings), errors, warnings) + # unknown action send to display + else: + warnings.append(('WRN_WEBCOMMENT_ADD_UNKNOWN_ACTION',)) + if reviews and cfg_webcomment_allow_reviews: + return (webcomment_templates.tmpl_add_comment_form_with_ranking(recID, uid, ln, msg, score, note, warnings), errors, warnings) + else: + return (webcomment_templates.tmpl_add_comment_form(recID, uid, ln, msg, warnings), errors, warnings) + +def notify_admin_of_new_comment(comID): + """ + Sends an email to the admin with details regarding comment with ID = comID + """ + comment = query_get_comment(comID) + if len(comment) > 0: + (comID2, id_bibrec, id_user, body, date_creation, star_score, vote_value, nb_votes, star_note, nb_reported) = comment + else: + return + user_info = query_get_user_contact_info(id_user) + if len(user_info) > 0: + (nickname, email, last_login) = user_info + if not len(nickname) > 0: + nickname = email.split('@')[0] + else: + nickname = email = last_login = "ERROR: Could not retrieve" + + from search_engine import print_record + record = print_record(recID=id_bibrec, format='hs') + + review_stuff = ''' + Star score = %s + Title = %s''' % (star_score, star_note) + + out = ''' +The following %(comment_or_review)s has just been posted (%(date)s). + +AUTHOR: + Nickname = %(nickname)s + Email = %(email)s + User ID = %(uid)s + +RECORD CONCERNED: + Record ID = %(recID)s + Record = %(record_details)s + +%(comment_or_review2)s: + %(comment_or_review)s ID = %(comID)s %(review_stuff)s + Body = +%(body)s + +ADMIN OPTIONS: +To delete comment go to %(weburl)s/admin/webcomment/webcommentadmin.py/delete?comid=%(comID)s + ''' % \ + { 'comment_or_review' : star_score>0 and 'review' or 'comment', + 'comment_or_review' : star_score>0 and 'REVIEW' or 'COMMENT', + 'date' : date_creation, + 'nickname' : nickname, + 'email' : email, + 'uid' : id_user, + 'recID' : id_bibrec, + 'record_details' : record, + 'comID' : comID2, + 'review_stuff' : star_score>0 and review_stuff or "", + 'body' : body.replace('
','\n'), + 'weburl' : weburl + } + + from_addr = 'CDS Alert Engine <%s>' % alertengineemail + to_addr = adminemail + + from alert_engine import send_email + send_email(from_addr, to_addr, out) + +def check_recID_is_in_range(recID, errors): + """ + Check that recID is >= 0 or <= -100 + Append error messages to errors listi + @param recID: record id + @param errors: list of error tuples (error_id, value) + @return boolean (1=true, 0=false) + """ + # Make errors into a list if needed + if type(errors) is not list: + errors = [errors] + + if type(recID) is int: + if recID >= 1 or recID <= -100: + return + else: + errors.append(('ERR_WEBCOMMENT_RECID_INVALID', recID)) + else: + errors.append(('ERR_WEBCOMMENT_RECID_INVALID', recID)) + +def check_int_arg_is_in_range(value, name, errors, gte_value, lte_value=None): + """ + Check that variable with name 'name' >= gte_value and optionally <= lte_value + Append error messages to errors list + @param value: variable value + @param name: variable name + @param errors: list of error tuples (error_id, value) + @param gte_value: greater than or equal to value + @param lte_value: less than or equal to value + @return boolean (1=true, 0=false) + """ + # Make errors into a list if needed + if type(errors) is not list: + errors = [errors] + + if type(value) is not int or type(gte_value) is not int: + errors.append(('ERR_WEBCOMMENT_PROGRAMNING_ERROR',)) + return 0 + + if type(value) is not int: + errors.append(('ERR_WEBCOMMENT_ARGUMENT_NAN', value)) + return 0 + + if value < gte_value: + errors.append(('ERR_WEBCOMMENT_ARGUMENT_INVALID', value)) + return 0 + if lte_value: + if type(lte_value) is not int: + errors.append(('ERR_WEBCOMMENT_PROGRAMNING_ERROR',)) + return 0 + if value > lte_value: + errors.append(('ERR_WEBCOMMENT_ARGUMENT_INVALID', value)) + return 0 + return 1 + +def wash_url_argument(var, new_type): + """ + Wash argument into 'new_type', that can be 'list', 'str', or 'int'. + If needed, the check 'type(var) is not None' should be done before calling this function + @param var: variable value + @param new_type: variable type, 'list', 'str' or 'int' + @return as much as possible, value var as type new_type + If var is a list, will change first element into new_type. + If int check unsuccessful, returns 0 + """ + out = [] + if new_type == 'list': # return lst + if type(var) is list: + out = var + else: + out = [var] + elif new_type == 'str': # return str + if type(var) is list: + try: + out = "%s" % var[0] + except: + out = "" + elif type(var) is str: + out = var + else: + out = "%s" % var + elif new_type == 'int': # return int + if type(var) is list: + try: + out = int(var[0]) + except: + out = 0 + elif type(var) is int: + out = var + elif type(var) is str: + try: + out = int(var) + except: + out = 0 + else: + out = 0 + elif new_type == 'tuple': # return tuple + if type(var) is tuple: + out = var + else: + out = (var,) + elif new_type == 'dict': # return dictionary + if type(var) is dict: + out = var + else: + out = {0:var} + return out + diff --git a/modules/webcomment/lib/webcomment_config.py b/modules/webcomment/lib/webcomment_config.py new file mode 100644 index 000000000..db62f11b6 --- /dev/null +++ b/modules/webcomment/lib/webcomment_config.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- +## $Id$ +## Comments and reviews for records. + +## This file is part of the CERN Document Server Software (CDSware). +## Copyright (C) 2002, 2003, 2004, 2005 CERN. +## +## The CDSware 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. +## +## The CDSware 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 CDSware; if not, write to the Free Software Foundation, Inc., +## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + +__lastupdated__ = """FIXME: last updated""" + +from config import * + +cfg_webcomment_error_messages = \ +{ 'ERR_WEBCOMMENT_RECID_INVALID' : ' %s is an invalid record ID ', + 'ERR_WEBCOMMENT_RECID_NAN' : ' Record ID %s is not a number ', + 'ERR_WEBCOMMENT_UID_INVALID' : ' %s is an invalid user ID ', + 'ERR_WEBCOMMENT_DB_ERROR' : ' %s ', + 'ERR_WEBCOMMENT_COMMENTS_NOT_ALLOWED': ' Comments on library record have been disallowed by the Administrator ', + 'ERR_WEBCOMMENT_ARGUMENT_NAN' : ' %s is not a number ', + 'ERR_WEBCOMMENT_ARGUEMENT_INVALID' : ' %s invalid argument ', + 'ERR_WEBCOMMENT_PROGRAMMING_ERROR' : ' Programming error, please inform the Administrator ', + 'ERR_WEBCOMMENT_FOR_TESTING_PURPOSES': ' THIS IS FOR TESTING PURPOSES ONLY var1=%s var2=%s var3=%s var4=%s var5=%s var6=%s ', + 'ERR_WEBCOMMENT_REPLY_REVIEW' : ' Cannot reply to a review ' +} + +cfg_webcomment_warning_messages = \ +{ 'WRN_WEBCOMMENT_INVALID_PAGE_NB' : "Bad page number --> showing first page", + 'WRN_WEBCOMMENT_INVALID_NB_RESULTS_PER_PAGE' : "Bad number of results per page --> showing 10 results per page", + 'WRN_WEBCOMMENT_INVALID_REVIEW_DISPLAY_ORDER' : "Bad display order --> showing most helpful first", + 'WRN_WEBCOMMENT_INVALID_DISPLAY_ORDER' : "Bad display order --> showing oldest first", + 'WRN_WEBCOMMENT_FEEDBACK_RECORDED_GREEN_TEXT' : "Your feedback has been recorded, many thanks", + 'WRN_WEBCOMMENT_FEEDBACK_NOT_RECORDED_RED_TEXT' : "Your feedback could not be recorded, please try again", + 'WRN_WEBCOMMENT_ADD_NO_TITLE' : "You must enter a title", + 'WRN_WEBCOMMENT_ADD_NO_SCORE' : "You must choose a score", + 'WRN_WEBCOMMENT_ADD_NO_BODY' : "You must enter a text", + 'ERR_WEBCOMMENT_DB_INSERT_ERROR' : 'Failed to insert your comment to the database. Please try again.', + 'WRN_WEBCOMMENT_ADD_UNKNOWN_ACTION' : 'Unknown action --> showing you the default add comment form', + 'WRN_WEBCOMMENT_ADMIN_COMID_NAN' : 'comment ID must be a number, try again', + 'WRN_WEBCOMMENT_ADMIN_INVALID_COMID' : 'Invalid comment ID, try again', + 'WRN_WEBCOMMENT_ADMIN_COMID_INEXISTANT' : "Comment ID %s does not exist, try again", + +} + + diff --git a/modules/webcomment/lib/webcomment_templates.py b/modules/webcomment/lib/webcomment_templates.py new file mode 100644 index 000000000..903e1fad8 --- /dev/null +++ b/modules/webcomment/lib/webcomment_templates.py @@ -0,0 +1,915 @@ +# -*- coding: utf-8 -*- +## $Id$ +## Comments and reviews for records. + +## This file is part of the CERN Document Server Software (CDSware). +## Copyright (C) 2002, 2003, 2004, 2005 CERN. +## +## The CDSware 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. +## +## The CDSware 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 CDSware; if not, write to the Free Software Foundation, Inc., +## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + +__lastupdated__ = """FIXME: last updated""" + +import urllib +import time +import string + +from config import * +from messages import gettext_set_language, language_list_long +from bibrankadminlib import addadminbox + +class Template: + 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_msg, arg1, arg2, ...) + @return html of comments + """ + + # load the right message language + _ = gettext_set_language(ln) + + # naming data fields of comments + c_nickname = 0 + c_date_creation = 1 + c_body = 2 + c_id = 3 + + warnings = self.tmpl_warnings(warnings) + + report_link = '''%s/comments.py/report?recid=%s&ln=%s&comid=%%(comid)s&reviews=0''' % (weburl, recID, ln) + + # comments + comment_rows = ''' ''' + for comment in comments: + comment_rows += ''' + + ''' + comment_rows += self.tmpl_get_comment_without_ranking(recID, ln, comment[c_nickname], comment[c_date_creation], comment[c_body]) + comment_rows += ''' +

+ + ''' + + # write button + write_button_link = '''%s/comments.py/add''' % (weburl,) + write_button_form = ''' + + ''' % (recID, ln) + write_button_form = self.createhiddenform(action=write_button_link, method="Get", text=write_button_form, button='Write a comment') + + # output + if nb_comments_total > 0: + out = warnings + ''' + +
%(comment_title)s
+ Showing the latest %(nb_comments)s comment%(s)s: %(tab)s
+ + + %(comment_rows)s +
+ %(view_all_comments_link)s +
+
+ %(write_button_form)s
+ ''' % \ + { 'comment_title' : "Discuss this document:", + 'nb_comments_total' : nb_comments_total, + 'recID' : recID, + 'comment_rows' : comment_rows, + 'tab' : ' '*4, + 'weburl' : weburl, + 's' : cfg_webcomment_nb_comments_in_detailed_view>1 and 's' or "", + 'view_all_comments_link' : nb_comments_total>0 and '''View all %s comments''' \ + % (weburl, recID, nb_comments_total) or "", + 'write_button_form' : write_button_form, + 'nb_comments' : cfg_webcomment_nb_comments_in_detailed_view>1 and cfg_webcomment_nb_comments_in_detailed_view or "" + } + else: + out = ''' + +
Discuss this document:
+ Open a a discussion about any aspect of this document. +
+ %s +
''' % (write_button_form,) + + return out + + 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_msg, arg1, arg2, ...) + @return html of comments + """ + # load the right message language + _ = gettext_set_language(ln) + + # naming data fields of comments + c_nickname = 0 + c_date_creation = 1 + c_body = 2 + c_vote_value = 3 + c_nb_votes = 4 + c_star_score = 5 + c_star_note = 6 + c_id = 7 + + warnings = self.tmpl_warnings(warnings) + + #stars + if avg_score > 0: + avg_score_img = 'stars-' + str(avg_score).split('.')[0] + '-' + str(avg_score).split('.')[1] + '.gif' + else: + avg_score_img = "stars-except.gif" + + # voting links + useful_dict = { 'weburl' : weburl, + 'recID' : recID, + 'ln' : ln, + 'yes_img' : 'smchk_gr.gif', #'yes.gif', + 'no_img' : 'iconcross.gif' #'no.gif' + } + useful_yes = '''Yes''' % useful_dict + useful_no = ''' No''' % useful_dict + report_link = '''%(weburl)s/comments.py/report?recid=%(recID)s&ln=%(ln)s&comid=%%(comid)s&reviews=1''' % useful_dict + + #comment row + comment_rows = ''' ''' + for comment in comments: + comment_rows += ''' + + ''' + comment_rows += self.tmpl_get_comment_with_ranking(recID, ln, comment[c_nickname], comment[c_date_creation], comment[c_body], + comment[c_nb_votes], comment[c_vote_value], comment[c_star_score], comment[c_star_note]) + comment_rows += ''' + Was this review helpful? %s / %s
''' % (useful_yes % {'comid':comment[c_id]}, useful_no % {'comid':comment[c_id]}) + comment_rows += ''' +
+ ''' + + # write button + write_button_link = '''%s/comments.py/add''' % (weburl,) + write_button_form = ''' + + ''' % (recID, 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: + out = warnings + ''' + +
%(comment_title)s
+ Average review score: %(avg_score)s based on %(nb_comments_total)s reviews
+ Readers found the following %(nb_helpful)s review%(s)s to be most helpful. + + + %(comment_rows)s +
+ %(view_all_comments_link)s + %(write_button_form)s
+ ''' % \ + { 'comment_title' : "Rate this document:", + 'avg_score_img' : avg_score_img, + 'avg_score' : avg_score, + 'nb_comments_total' : nb_comments_total, + 'recID' : recID, + 'view_all_comments' : "view all %s reviews" % (nb_comments_total,), + 'write_comment' : "write a review", + 'comment_rows' : comment_rows, + 's' : cfg_webcomment_nb_reviews_in_detailed_view>1 and 's' or "", + 'tab' : ' '*4, + 'weburl' : weburl, + 'nb_helpful' : cfg_webcomment_nb_reviews_in_detailed_view>1 and cfg_webcomment_nb_reviews_in_detailed_view or "", + 'view_all_comments_link': nb_comments_total>0 and """View all %s reviews
""" \ + % (weburl, recID, ln, nb_comments_total) or "", + 'write_button_form' : write_button_form + } + else: + out = ''' + +
Rate this document:
+ Have the honor of being the first to review this document.
+ %s +
''' % (write_button_form,) + return out + + def tmpl_get_comment_without_ranking(self, recID, ln, nickname, date_creation, body, reply_link=None, report_link=None): + """ + private function + @param ln: language + @param nickname: nickname + @param date_creation: date comment was written + @param body: comment body + @param reply_link: if want reply and report, give the http links + @param repot_link: if want reply and report, give the http links + @return html table of comment + """ + # load the right message language + _ = gettext_set_language(ln) + + date_creation = str(date_creation) + date_creation_data = date_creation[:18] + date_creation_data = time.strptime(str(date_creation_data), "%Y-%m-%d %H:%M:%S") + date_creation_data = time.strftime("%d %b %Y %H:%M:%S %Z", date_creation_data) + date_creation = str(date_creation_data) + date_creation[22:] # 22 to get rid of the .00 after time + + out = ''' ''' + + # load the right message language + #_ = gettext_set_language(ln) + + out += """ + + + + + + + + +
%(nickname)s wrote on %(date_creation)s%(links)s
%(body)s
""" % \ + { #! FIXME put send_a_private_message view_shared_baskets + 'nickname' : nickname, + 'date_creation' : date_creation, + 'body' : body, + 'links' : (report_link!=None and reply_link!=None) and "Report this | Reply" % (report_link, reply_link) or "" + } + return out + + + def tmpl_get_comment_with_ranking(self, recID, ln, nickname, date_creation, body, nb_votes, vote_value, star_score, star_note): + """ + private function + @param ln: language + @param nickname: nickname + @param date_creation: date comment was written + @param body: comment body + @param nb_votes: total number of votes for this review + @param vote_value: number of positive votes for this record + @param star_score: star score for this record + @param star_note: title of review + @return html table of review + """ + # load the right message language + _ = gettext_set_language(ln) + + if star_score > 0: + star_score_img = 'stars-' + str(star_score) + '-0.gif' + else: + star_score_img = 'stars-except.gif' + + out = """""" + date_creation = str(date_creation) + date_creation_data = date_creation[:18] + date_creation_data = time.strptime(str(date_creation_data), "%Y-%m-%d %H:%M:%S") + date_creation_data = time.strftime("%d %b %Y %H:%M:%S %Z", date_creation_data) + date_creation = str(date_creation_data) + date_creation[22:] + + # load the right message language + #_ = gettext_set_language(ln) + + out += """ + + + + + + + +
+ %(star_score)s %(star_note)s
+ Reviewed by %(nickname)s on %(date_creation)s
+ %(vote_value)s out of %(nb_votes)s people found this review useful.
+
%(body)s
+ """ % \ + { #! FIXME put send_a_private_message view_shared_baskets + 'nickname' : nickname, + 'weburl' : weburl, + 'star_score_img': star_score_img, + 'date_creation' : date_creation, + 'body' : body, + 'nb_votes' : nb_votes, + 'star_score' : star_score, + 'star_note' : star_note, + 'vote_value' : vote_value<0 and "0" or vote_value + } + return out + + def tmpl_get_comments(self, 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): + """ + 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_msg, color) + @param border: boolean, active if want to show border around each comment/review + @param reviews: booelan, enabled for reviews, disabled for comments + """ + # load the right message language + _ = gettext_set_language(ln) + + # naming data fields of comments + if reviews: + c_nickname = 0 + c_date_creation = 1 + c_body = 2 + c_vote_value = 3 + c_nb_votes = 4 + c_star_score = 5 + c_star_note = 6 + c_id = 7 + else: + c_nickname = 0 + c_date_creation = 1 + c_body = 2 + c_id = 3 + + # voting links + useful_dict = { 'weburl' : weburl, + 'recID' : recID, + 'ln' : ln, + 'do' : display_order, + 'ds' : display_since, + 'nb' : nb_per_page, + 'p' : page, + 'reviews' : reviews + } + useful_yes = '''Yes''' % useful_dict + useful_no = '''No''' % useful_dict + warnings = self.tmpl_warnings(warnings) + + ## record details + from search_engine import print_record + record_details = print_record(recID=recID, format='hb') + + link_dic = { 'weburl' : weburl, + 'module' : 'comments.py', + 'function' : 'index', + 'arguments' : 'recid=%s&do=%s&ds=%s&nb=%s&reviews=%s' % (recID, display_order, display_since, nb_per_page, reviews), + 'arg_page' : '&p=%s' % page, + 'page' : page } + + ## comments table + comments_rows = ''' ''' + for comment in comments: + comments_rows += ''' + + + ''' + if not reviews: + report_link = '''%(weburl)s/comments.py/report?recid=%(recID)s&ln=%(ln)s&comid=%%(comid)s&do=%(do)s&ds=%(ds)s&nb=%(nb)s&p=%(p)s&reviews=%(reviews)s&referer=%(weburl)s/comments.py/display''' % useful_dict % {'comid':comment[c_id]} + reply_link = '''%(weburl)s/comments.py/add?recid=%(recID)s&ln=%(ln)s&action=REPLY&comid=%%(comid)s''' % useful_dict % {'comid':comment[c_id]} + comments_rows += self.tmpl_get_comment_without_ranking(recID, ln, comment[c_nickname], comment[c_date_creation], comment[c_body], reply_link, report_link) + else: + report_link = '''%(weburl)s/comments.py/report?recid=%(recID)s&ln=%(ln)s&comid=%%(comid)s&do=%(do)s&ds=%(ds)s&nb=%(nb)s&p=%(p)s&reviews=%(reviews)s&referer=%(weburl)s/comments.py/display''' % useful_dict % {'comid':comment[c_id]} + comments_rows += self.tmpl_get_comment_with_ranking(recID, ln, comment[c_nickname], comment[c_date_creation], comment[c_body], + comment[c_nb_votes], comment[c_vote_value], comment[c_star_score], comment[c_star_note]) + comments_rows += ''' + + + + + + + +
Was this review helpful? %(tab)s %(yes)s / %(no)s %(tab)s%(tab)s(Report abuse)
''' \ + % { 'yes' : useful_yes % {'comid':comment[c_id]}, + 'no' : useful_no % {'comid':comment[c_id]}, + 'report' : report_link % {'comid':comment[c_id]}, + 'tab' : ' '*2 + } + 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: + comments_or_reviews = 'review' + if avg_score > 0: + avg_score_img = 'stars-' + str(avg_score).split('.')[0] + '-' + str(avg_score).split('.')[1] + '.gif' + else: + avg_score_img = "stars-except.gif" + ranking_average = '''
Average review socre: %(avg_score)s based on %(nb_comments_total)s reviews
''' \ + % { 'weburl' : weburl, + 'avg_score' : avg_score, + 'avg_score_img' : avg_score_img, + 'nb_comments_total' : total_nb_comments } + else: + ranking_average = "" + comments_or_reviews = 'comment' + + write_button_link = '''%s/comments.py/add''' % (weburl, ) + write_button_form = ''' + + ''' % (recID, ln, reviews) + write_button_form = self.createhiddenform(action=write_button_link, method="Get", text=write_button_form, button='Write a %s' % comments_or_reviews) + + ## html + body = ''' + +

Record %(recid)s

Back to search results
+
+ %(record_details)s +
+
+

%(comments_or_reviews_title)ss

+ There is a total of %(total_nb_comments)s %(comments_or_reviews)ss. %(ranking_avg)s
+ %(write_button_form)s
+ + + %(comments_rows)s +
+ + + + + + +
%(write_button_form_again)sBack to search results
+
+ ''' % \ + { 'record_details' : record_details, + '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' : comments_or_reviews, + 'comments_or_reviews_title' : comments_or_reviews[0].upper() + comments_or_reviews[1:], + 'weburl' : weburl, + 'module' : "comments.py", + 'recid' : recID, + 'ln' : ln, + 'border' : border, + 'ranking_avg' : ranking_average } + form = ''' + Display + comments per page that are + and sorted by + ''' % \ + (reviews==1 and ''' + + + + + ''' or ''' + ''') + form_link = "%(weburl)s/%(module)s/%(function)s" % link_dic + form = self.createhiddenform(action=form_link, method="Get", text=form, button='Go', recid=recID, p=1) + pages = ''' +
+ Viewing %(comments_or_reviews)s %(results_nb_lower)s-%(results_nb_higher)s
+ %(page_links)s +
+ ''' % \ + { 'page_links' : "Page: " + page_links , + 'comments_or_reviews' : not reviews and 'comments' or 'reviews', + '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 + + return body + + + 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 = '
\n' % (action, string.lower(method).strip() in ['get','post'] and method or 'Get') + output += '\n
' + output += text + if cnfrm: + output += ' ' + for key in hidden.keys(): + if type(hidden[key]) is list: + for value in hidden[key]: + output += ' \n' % (key, value) + else: + output += ' \n' % (key, hidden[key]) + output += '' + output += ' \n' % (button, ) + output += '
' + output += '
\n' + + return output + + def tmpl_warnings(self, warnings): + """ + Prepare the warnings list + @param warnings: list of warning tuples (warning_msg, arg1, arg2, etc) + @return html string of warnings + """ + from errorlib import get_msgs_for_code_list + span_class = 'important' + out = "" + if type(warnings) is not list: + warnings = [warnings] + if len(warnings) > 0: + warnings_parsed = get_msgs_for_code_list(warnings, 'warning') + for (warning_code, warning_text) in warnings_parsed: + if not warning_code.startswith('WRN'): #display only warnings that begin with WRN to user + continue + if warning_code.find('GREEN_TEXT') >= 0: + span_class = "exampleleader" + elif warning_code.find('RED_TEXT') >= 0: + span_class = "important" + out += ''' + %(warning)s
''' % \ + { 'span_class' : span_class, + 'warning' : warning_text } + return out + else: + return "" + + def tmpl_add_comment_form(self, recID, uid, nickname, ln, msg, warnings): + """ + 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 + @param warnings: list of warning tuples (warning_msg, color) + @return html add comment form + """ + link_dic = { 'weburl' : weburl, + 'module' : 'comments.py', + 'function' : 'add', + 'arguments' : 'recid=%s&ln=%s&action=%s&reviews=0' % (recID, ln, 'SUBMIT') } + + from search_engine import print_record + record_details = print_record(recID=recID, format='hb') + + warnings = self.tmpl_warnings(warnings) + form = ''' + + + + + + +
Article:
%(record)s

Your nickname: %(nickname)s

Comment:
+

''' % { 'msg' : msg!='None' and urllib.unquote(msg) or "", + 'nickname' : nickname, + 'record' : record_details } + form_link = "%(weburl)s/%(module)s/%(function)s?%(arguments)s" % link_dic + form = self.createhiddenform(action=form_link, method="Post", text=form, button='Add comment') + return warnings + form + + def tmpl_add_comment_form_with_ranking(self, recID, uid, nickname, ln, msg, score, note, warnings): + """ + Add form for reviews + @param recID: record id + @param uid: user id + @param ln: language + @param msg: comment body contents for when refreshing due to warning + @param score: review score + @param note: review title + @param warnings: list of warning tuples (warning_msg, color) + @return html add review form + """ + link_dic = { 'weburl' : weburl, + 'module' : 'comments.py', + 'function' : 'add', + 'arguments' : 'recid=%s&ln=%s&action=%s&reviews=1' % (recID, ln, 'SUBMIT') } + warnings = self.tmpl_warnings(warnings) + + from search_engine import print_record + record_details = print_record(recID=recID, format='hb') + + form = ''' + + + + + + + + + +
Article:
%(record)s

Select your score:

+
Your nickname: %(nickname)s

Give a title to your review:


Write your review:
+

''' % { 'note' : note!='None' and note or "", + 'msg' : msg!='None' and msg or "", + 'nickname' : nickname, + 'record' : record_details } + form_link = "%(weburl)s/%(module)s/%(function)s?%(arguments)s" % link_dic + form = self.createhiddenform(action=form_link, method="Post", text=form, button='Add Review') + return warnings + form + + def tmpl_add_comment_successful(self, recID, ln, reviews): + """ + @param recID: record id + @param ln: language + @return html page of successfully added comment/review + """ + link_dic = { 'weburl' : weburl, + 'module' : 'comments.py', + 'function' : 'display', + 'arguments' : 'recid=%s&ln=%s&do=od&reviews=%s' % (recID, ln, reviews) } + link = "%(weburl)s/%(module)s/%(function)s?%(arguments)s" % link_dic + return '''Your %s was successfully added

Back to record''' % (reviews==1 and 'review' or 'comment', link) + + def tmpl_admin_index(self, ln): + """ + """ + # load the right message language + _ = gettext_set_language(ln) + + out = ''' + ''' + if cfg_webcomment_allow_comments or cfg_webcomment_allow_reviews: + if cfg_webcomment_allow_comments: + out += ''' + ''' + if cfg_webcomment_allow_reviews: + out += ''' + ''' + out += ''' + + + ''' + out = out % { 'weburl' : weburl, + 'ln' : ln } + else: + out += ''' + ''' + out += '''
0.  View all reported comments
0. View all reported reviews
1. Delete a specific comment/review (by ID)
2. View all users who have been reported

Comments and reviews are disabled
''' + return addadminbox('Menu', [out]) + + + def tmpl_admin_delete_form(self, ln, warnings): + """ + @param warnings: list of warning_tuples where warning_tuple is (warning_message, text_color) + see tmpl_warnings, color is optional + """ + # load the right message language + _ = gettext_set_language(ln) + + warnings = self.tmpl_warnings(warnings) + + out = ''' +
+ Please enter the ID of the comment/review so that you can view it before deciding to delete it or not
+
''' + form = ''' + + + + + + + + +
Comment ID:

+
+ ''' + form_link = "%s/admin/webcomment/webcommentadmin.py/delete?ln=%s" % (weburl, ln) + form = self.createhiddenform(action=form_link, method="Get", text=form, button='View Comment') + return warnings + out + form + + def tmpl_admin_users(self, ln, users_data): + """ + @param users_data: tuple of ct, i.e. (ct, ct, ...) + where ct is a tuple (total_number_reported, total_comments_reported, total_reviews_reported, total_vote_value_of_reported, + total_nb_votes_of_reported, user_id, user_email, user_nickname) + sorted by order of ct having highest total_number_reported + """ + u_reports = 0 + u_comment_reports = 1 + u_reviews_reports = 2 + u_vote_value = 3 + u_nb_votes = 4 + u_uid = 5 + u_email = 6 + u_nickname = 7 + + if not users_data: + return self.tmpl_warnings([("There have been no reports so far.", 'green')]) + + user_rows = "" + for utuple in users_data: + com_link = '''View all %s reported comments
''' % \ + (weburl, ln, utuple[u_uid], utuple[u_comment_reports]) + rev_link = '''View all %s reported reviews''' % \ + (weburl, ln, utuple[u_uid], utuple[u_reviews_reports]) + user_rows += ''' + + %(nickname)s + %(email)s + %(uid)s + %(review_row)s + %(reports)s + %(com_link)s%(rev_link)s + + ''' % { 'nickname' : len(utuple[u_nickname])>0 and utuple[u_nickname] or utuple[u_email].split('@')[0], + 'email' : utuple[u_email], + 'uid' : utuple[u_uid], + 'reports' : utuple[u_reports], + 'review_row': cfg_webcomment_allow_reviews>0 and "%s%s%s" % \ + (utuple[u_vote_value], utuple[u_nb_votes]-utuple[u_vote_value], utuple[u_nb_votes]) or "", + 'weburl' : weburl, + 'ln' : ln, + 'com_link' : cfg_webcomment_allow_comments>0 and com_link or "", + 'rev_link' : cfg_webcomment_allow_reviews>0 and rev_link or "" + } + + out = ''' +
+ Here is a list, sorted by total number of reports, of all users who have had at least one report to one of their comments.
+
+ + + + + + %(reviews_columns)s + + + + %(user_rows)s +
NicknameEmailUser IDTotal number of reportsView all user's reported comments/reviews
+ ''' % { 'reviews_columns' : cfg_webcomment_allow_reviews>0 and + "Number positive votesNumber negative votesTotal number votes" or "", + 'user_rows' : user_rows + } + return out + + def tmpl_admin_comments(self, ln, uid, comID, comment_data, reviews): + """ + @param comment_data: same type of tuple as that which is returned by webcomment.py/query_retrieve_comments_or_remarks i.e. + tuple of comment where comment is + tuple (nickname, date_creation, body, id) if ranking disabled or + tuple (nickname, date_creation, body, vote_value, nb_votes, star_score, star_note, id) + """ + comments = self.tmpl_get_comments(recID=-1, ln=ln, nb_per_page=0, page=1, nb_pages=1, display_order='od', display_since='all', + cfg_webcomment_allow_reviews=cfg_webcomment_allow_reviews, comments=comment_data, total_nb_comments=len(comment_data), + avg_score=-1, warnings=[], border=1, reviews=reviews) + comments = comments.split("")[1] + comments = comments.split("")[0] + + form_link = "%s/admin/webcomment/webcommentadmin.py/del_com?ln=%s" % (weburl, ln) + form = self.createhiddenform(action=form_link, method="Post", text=comments, button='Delete Selected Comments') + + if uid > 0: + header = "
Here are the reported %s of user %s

" % (reviews>0 and "reviews" or "comments", uid) + if comID > 0: + header = "
Here is comment/review %s

" % comID + if uid > 0 and comID > 0: + header = "
Here is comment/review %s written by user %s

" % (comID, uid) + if uid ==0 and comID == 0: + header = "
Here are all reported %s sorted by most reported

" % (reviews>0 and "reviews" or "comments",) + + return header + form + + def tmpl_admin_del_com(self, del_res): + """ + @param del_res: list of the following tuple (comment_id, was_successfully_deleted), + was_successfully_deleted is boolean (0=false, >0=true + """ + table_rows = ''' ''' + for deltuple in del_res: + table_rows += ''' + %s%s + ''' % (deltuple[0], deltuple[1]>0 and "Yes" or "No") + + out = ''' + + + %s +
comment IDsuccessfully deleted
''' % (table_rows) + + return out + + 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 = '\n' % (action, string.lower(method).strip() in ['get','post'] and method or 'Get') + output += '
\n
' + output += text + if cnfrm: + output += ' ' + for key in hidden.keys(): + if type(hidden[key]) is list: + for value in hidden[key]: + output += ' \n' % (key, value) + else: + output += ' \n' % (key, hidden[key]) + output += '' + output += ' \n' % (button, ) + output += '
' + output += '\n' + + return output + + diff --git a/modules/webcomment/lib/webcomment_tests.py b/modules/webcomment/lib/webcomment_tests.py new file mode 100644 index 000000000..7a4c02e69 --- /dev/null +++ b/modules/webcomment/lib/webcomment_tests.py @@ -0,0 +1,31 @@ +import webcomment +import unittest + +class TestWashQueryParameters(unittest.TestCase): + """Test for washing of search query parameters.""" + + def test_wash_url_argument(self): + """search engine - washing of URL arguments""" + self.assertEqual(1, search_engine.wash_url_argument(['1'],'int')) + self.assertEqual("1", search_engine.wash_url_argument(['1'],'str')) + self.assertEqual(['1'], search_engine.wash_url_argument(['1'],'list')) + self.assertEqual(0, search_engine.wash_url_argument('ellis','int')) + self.assertEqual("ellis", search_engine.wash_url_argument('ellis','str')) + self.assertEqual(["ellis"], search_engine.wash_url_argument('ellis','list')) + self.assertEqual(0, search_engine.wash_url_argument(['ellis'],'int')) + self.assertEqual("ellis", search_engine.wash_url_argument(['ellis'],'str')) + self.assertEqual(["ellis"], search_engine.wash_url_argument(['ellis'],'list')) + + def test_wash_pattern(self): + """search engine - washing of query patterns""" + self.assertEqual("Ellis, J", search_engine.wash_pattern('Ellis, J')) + self.assertEqual("ell", search_engine.wash_pattern('ell*')) + +def create_test_suite(): + """Return test suite for the search engine.""" + return unittest.TestSuite((unittest.makeSuite(TestWashQueryParameters,'test'), + unittest.makeSuite(TestStripAccents,'test'), + unittest.makeSuite(TestQueryParser,'test'))) + +if __name__ == "__main__": + unittest.TextTestRunner(verbosity=2).run(create_test_suite()) diff --git a/modules/webcomment/lib/webcommentadminlib.py b/modules/webcomment/lib/webcommentadminlib.py new file mode 100644 index 000000000..53b310411 --- /dev/null +++ b/modules/webcomment/lib/webcommentadminlib.py @@ -0,0 +1,232 @@ +# -*- coding: utf-8 -*- +## $Id$ +## Comments and reviews for records. + +## This file is part of the CERN Document Server Software (CDSware). +## Copyright (C) 2002, 2003, 2004, 2005 CERN. +## +## The CDSware 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. +## +## The CDSware 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 CDSware; if not, write to the Free Software Foundation, Inc., +## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + +__lastupdated__ = """FIXME: last updated""" + + +from bibrankadminlib import check_user + #write_outcome,modify_translations,get_def_name,get_i8n_name,get_name,get_rnk_nametypes,get_languages,check_user,is_adminuser, + #adderrorbox,addadminbox,tupletotable,tupletotable_onlyselected,addcheckboxes,createhiddenform,serialize_via_numeric_array_dumps, + #serialize_via_numeric_array_compr,serialize_via_numeric_array_escape,serialize_via_numeric_array,deserialize_via_numeric_array, + #serialize_via_marshal,deserialize_via_marshal +from config import * +from webcomment import wash_url_argument, query_get_comment, query_get_user_contact_info +from mod_python import apache +from dbquery import run_sql + +import template +webcomment_templates = template.load('webcomment') + +def getnavtrail(previous = ''): + """Get the navtrail""" + + navtrail = """Admin Area > WebComment Admin """ % (weburl, weburl) + navtrail = navtrail + previous + return navtrail + +def perform_request_index(ln=cdslang): + """ + """ + return webcomment_templates.tmpl_admin_index(ln=ln) + +def perform_request_delete(ln=cdslang, comID=-1): + """ + """ + warnings = [] + + ln = wash_url_argument(ln, 'str') + comID = wash_url_argument(comID, 'int') + + if comID is not None: + if comID <= 0: + if comID != -1: + warnings.append(("WRN_WEBCOMMENT_ADMIN_INVALID_COMID",)) + return (webcomment_templates.tmpl_admin_delete_form(ln, warnings),None, warnings) + + comment = query_get_comment(comID) + if comment: + c_star_score = 5 + if comment[c_star_score] > 0: + reviews = 1 + else: + reviews = 0 + return (perform_request_comments(ln=ln, comID=comID, reviews=reviews), None, warnings) + else: + warnings.append(('WRN_WEBCOMMENT_ADMIN_COMID_INEXISTANT', comID)) + return (webcomment_templates.tmpl_admin_delete_form(ln, warnings), None, warnings) + else: + return (webcomment_templates.tmpl_admin_delete_form(ln, warnings), None, warnings) + +def perform_request_users(ln=cdslang): + """ + """ + ln = wash_url_argument(ln, 'str') + + users_data = query_get_users_reported() + + return webcomment_templates.tmpl_admin_users(ln=ln, users_data=users_data) + +def query_get_users_reported(): + """ + Get the users who have been reported at least one. + @return tuple of ct, i.e. (ct, ct, ...) + where ct is a tuple (total_number_reported, total_comments_reported, total_reviews_reported, + total_vote_value_of_reported, total_nb_votes_of_reported, user_id, user_email, user_nickname) + sorted by order of ct having highest total_number_reported + """ + query1 = "SELECT c.nb_reported, c.vote_value, c.nb_votes, u.id, u.email, u.nickname, c.star_score " \ + "FROM user AS u, cmtRECORDCOMMENT AS c " \ + "WHERE c.id_user=u.id AND c.nb_reported > 0 " \ + "ORDER BY u.id " + res1 = run_sql(query1) + if type(res1) is None: + return () + users = {} + for cmt in res1: + uid = int(cmt[3]) + if users.has_key(uid): + users[uid] = (users[uid][0]+int(cmt[0]), int(cmt[6])>0 and users[uid][1] or users[uid][1]+1, int(cmt[6])>0 and users[uid][2]+1 or users[uid][2], + users[uid][3]+int(cmt[1]), users[uid][4]+int(cmt[2]), int(cmt[3]), cmt[4], cmt[5]) + else: + users[uid] = (int(cmt[0]), int(cmt[6])==0 and 1 or 0, int(cmt[6])>0 and 1 or 0, int(cmt[1]), int(cmt[2]), int(cmt[3]), cmt[4], cmt[5]) + users = users.values() + users.sort() + users.reverse() + users = tuple(users) + return users + +def perform_request_comments(ln=cdslang, uid="", comID="", reviews=0): + """ + """ + warning = [] + + ln = wash_url_argument(ln, 'str') + uid = wash_url_argument(uid, 'int') + comID = wash_url_argument(comID, 'int') + reviews = wash_url_argument(reviews, 'int') + + comments = query_get_comments(uid, comID, reviews) + return webcomment_templates.tmpl_admin_comments(ln=ln, uid=uid, comID=comID, comment_data=comments, reviews=reviews) + +def query_get_comments(uid, comID, reviews): + """ + private funciton + Get the reported comments of user uid or get the comment comID or get the comment comID which was written by user uid + @return same type of tuple as that which is returned by webcomment.py/query_retrieve_comments_or_remarks i.e. + tuple of comment where comment is + tuple (nickname, date_creation, body, id) if ranking disabled or + tuple (nickname, date_creation, body, vote_value, nb_votes, star_score, star_note, id) + """ + query1 = "SELECT u.nickname, c.date_creation, c.body, %s c.id, c.id_bibrec, c.id_user, " \ + "c.nb_reported, u.id, u.email, u.nickname " \ + "FROM user AS u, cmtRECORDCOMMENT AS c " \ + "WHERE c.id_user=u.id %s %s %s " \ + "ORDER BY c.nb_reported DESC, c.vote_value DESC, c.date_creation " + params1 = ( reviews>0 and " c.vote_value, c.nb_votes, c.star_score, c.star_note, " or "", + reviews>0 and " AND c.star_score>0 " or " AND c.star_score=0 ", + uid>0 and " AND c.id_user=%s " % uid or "", + comID>0 and " AND c.id=%s " % comID or " AND c.nb_reported>0 " ) + res1 = run_sql(query1 % params1) + res2 = [] + for qtuple1 in res1: + # exceptional use of html here for giving admin extra information + new_info = """
user (nickname=%s, email=%s, id=%s)
+ comment/review id = %s
+ commented this record (id=%s)
+ + + + reported %s times +   +       + + + + """ \ + % (len(qtuple1[0])>0 and qtuple1[0] or qtuple1[-2].split('@')[0], + qtuple1[-2], qtuple1[-5], qtuple1[-7], weburl, qtuple1[-6], qtuple1[-6], qtuple1[-4], qtuple1[-7]) + if reviews: + qtuple2 = (len(qtuple1[0])>0 and qtuple1[0] or qtuple1[-2].split('@')[0], + str(qtuple1[1])+new_info, qtuple1[2], qtuple1[3], qtuple1[4], qtuple1[5], qtuple1[6], qtuple1[7]) + else: + qtuple2 = (len(qtuple1[0])>0 and qtuple1[0] or qtuple1[-2].split('@')[0], + str(qtuple1[1])+new_info, qtuple1[2], qtuple1[3]) + + res2.append(qtuple2) + return tuple(res2) + +def perform_request_del_com(ln=cdslang, comIDs=[]): + """ + private function + Delete the comments and say whether successful or not + @param ln: language + @param comIDs: list of comment ids + """ + ln = wash_url_argument(ln, 'str') + comIDs = wash_url_argument(comIDs, 'list') + # map ( fct, list, arguments of function) + comIDs = map(wash_url_argument, comIDs, ('int '*len(comIDs)).split(' ')[:-1]) + + if not comIDs: + comIDs = map(coerce, comIDs, ('0 '*len(comIDs)).split(' ')[:-1]) + return webcomment_templates.tmpl_admin_del_com(del_res=comIDs) + + del_res=[] + for id in comIDs: + del_res.append((id, query_delete_comment(id))) + return webcomment_templates.tmpl_admin_del_com(del_res=del_res) + +def query_delete_comment(comID): + """ + delete comment with id comID + @return integer 1 if successful, integer 0 if not + """ + query1 = "DELETE FROM cmtRECORDCOMMENT WHERE id=%s" + params1 = (comID,) + res1 = run_sql(query1, params1) + return int(res1) + +def getnavtrail(previous = ''): + """ + Get the navtrail + """ + + navtrail = """Admin Area > WebComment Admin """ % (weburl, weburl) + navtrail = navtrail + previous + return navtrail + + + + + + + + + + + + + + + + + + diff --git a/modules/webcomment/web/.cvsignore b/modules/webcomment/web/.cvsignore new file mode 100644 index 000000000..d4766d920 --- /dev/null +++ b/modules/webcomment/web/.cvsignore @@ -0,0 +1,5 @@ +Makefile +Makefile.in +z_* +*.O +*~ diff --git a/modules/webcomment/web/Makefile.am b/modules/webcomment/web/Makefile.am new file mode 100644 index 000000000..27cee6f76 --- /dev/null +++ b/modules/webcomment/web/Makefile.am @@ -0,0 +1,28 @@ +## $Id$ + +## This file is part of the CERN Document Server Software (CDSware). +## Copyright (C) 2002, 2003, 2004, 2005 CERN. +## +## The CDSware 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. +## +## The CDSware 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 CDSware; if not, write to the Free Software Foundation, Inc., +## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + +SUBDIRS = admin + +webappdir = $(WEBDIR) + +webapp_DATA = comments.py + +EXTRA_DIST = $(webapp_DATA) + +CLEANFILES = *~ *.tmp comments.pyc diff --git a/modules/webcomment/web/admin/.cvsignore b/modules/webcomment/web/admin/.cvsignore new file mode 100644 index 000000000..92fecb09d --- /dev/null +++ b/modules/webcomment/web/admin/.cvsignore @@ -0,0 +1,6 @@ +Makefile +Makefile.in +z_* +*.O +*~ +*.html diff --git a/modules/webcomment/web/admin/Makefile.am b/modules/webcomment/web/admin/Makefile.am new file mode 100644 index 000000000..302ce3402 --- /dev/null +++ b/modules/webcomment/web/admin/Makefile.am @@ -0,0 +1,29 @@ +## $Id$ + +## This file is part of the CERN Document Server Software (CDSware). +## Copyright (C) 2002, 2003, 2004, 2005 CERN. +## +## The CDSware 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. +## +## The CDSware 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 CDSware; if not, write to the Free Software Foundation, Inc., +## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + +webappdir = $(WEBDIR)/admin/webcomment + +webapp_DATA = index.html webcommentadmin.py + +EXTRA_DIST = index.html.wml webcommentadmin.py + +CLEANFILES = index.html *~ *.tmp + +%.html: %.html.wml $(top_srcdir)/config/config.wml $(top_builddir)/config/configbis.wml + $(WML) -o\(ALL-LANG_*\)+LANG_EN:$@ $< diff --git a/modules/webcomment/web/admin/index.html.wml b/modules/webcomment/web/admin/index.html.wml new file mode 100644 index 000000000..53ab2ae09 --- /dev/null +++ b/modules/webcomment/web/admin/index.html.wml @@ -0,0 +1,38 @@ +## $Id$ + +## This file is part of the CERN Document Server Software (CDSware). +## Copyright (C) 2002, 2003, 2004, 2005 CERN. +## +## The CDSware 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. +## +## The CDSware 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 CDSware; if not, write to the Free Software Foundation, Inc., +## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + +#include "cdspage.wml" \ + title="WebComment Admin" \ + navtrail_previous_links="/admin/>" \ + navbar_name="admin" \ + navbar_select="webcomment" + +

+ This is the gate to the admin area for WebComment. You need to + login to enter. +

+ +
+
WebComment Admin Interface
+
Start area for WebComment administration.
+
+
+
WebComment Admin Guide
+
Everything you want to know about WebComment administration
+
diff --git a/modules/webcomment/web/admin/webcommentadmin.py b/modules/webcomment/web/admin/webcommentadmin.py new file mode 100644 index 000000000..0c310e589 --- /dev/null +++ b/modules/webcomment/web/admin/webcommentadmin.py @@ -0,0 +1,168 @@ +# -*- coding: utf-8 -*- +## $Id$ +## Comments and reviews for records. + +## This file is part of the CERN Document Server Software (CDSware). +## Copyright (C) 2002, 2003, 2004, 2005 CERN. +## +## The CDSware 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. +## +## The CDSware 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 CDSware; if not, write to the Free Software Foundation, Inc., +## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + + +__lastupdated__ = """$FIXME $""" + +from cdsware.webcommentadminlib import * +from cdsware.webpage import page, create_error_box +from cdsware.config import weburl,cdslang +from cdsware.webuser import getUid, page_not_authorized + +def index(req, ln=cdslang): + """ + Menu of admin options + @param ln: language + """ + navtrail_previous_links = getnavtrail() + """ > Comment Management""" % (weburl,) + + try: + uid = getUid(req) + except MySQLdb.Error, e: + return error_page(req) + + (auth_code, auth_msg) = check_user(uid,'cfgwebcomment') + if not auth_code: + return page(title="Comment Management", + body=perform_request_index(ln=ln), + uid=uid, + language=ln, + urlargs=req.args, + navtrail = navtrail_previous_links, + lastupdated=__lastupdated__) + else: + return page_not_authorized(req=req, text=auth_msg, navtrail=navtrail_previous_links) + +def delete(req, ln=cdslang, comid=""): + """ + Delete a comment by giving its comment id + @param ln: language + @param comid: comment id + """ + navtrail_previous_links = getnavtrail() + """ > Comment Management""" % (weburl,) + + try: + uid = getUid(req) + except MySQLdb.Error, e: + return error_page(req) + + (auth_code, auth_msg) = check_user(uid,'cfgwebcomment') + if not auth_code: + (body, errors, warnings) = perform_request_delete(ln=ln, comID=comid) + return page(title="Delete Comment", + body=body, + uid=uid, + language=ln, + urlargs=req.args, + navtrail = navtrail_previous_links, + req = req, + errors = errors, + warnings = warnings, + lastupdated=__lastupdated__) + else: + return page_not_authorized(req=req, text=auth_msg, navtrail=navtrail_previous_links) + + +def comments(req, ln=cdslang, uid="", comid="", reviews=0): + """ + View reported comments, filter by either user or a specific comment (only one given at a time) + @param ln: language + @param uid: user id + @param comid: comment id + @param reviews: boolean enabled for reviews, disabled for comments + """ + navtrail_previous_links = getnavtrail() + """ > Comment Management""" % (weburl,) + + try: + auid = getUid(req) + except MySQLdb.Error, e: + return error_page(req) + + (auth_code, auth_msg) = check_user(auid,'cfgwebcomment') + if not auth_code: + return page(title="View all Reported %s" % (reviews>0 and "Reviews" or "Comments",), + body=perform_request_comments(ln=ln, uid=uid, comID=comid, reviews=reviews), + uid=uid, + language=ln, + urlargs=req.args, + navtrail = navtrail_previous_links, + lastupdated=__lastupdated__) + else: + return page_not_authorized(req=req, text=auth_msg, navtrail=navtrail_previous_links) + + +def users(req, ln=cdslang): + """ + View a list of all the users that have been reported, sorted by most reported + @param ln: language + """ + navtrail_previous_links = getnavtrail() + """ > Comment Management""" % (weburl,) + + try: + uid = getUid(req) + except MySQLdb.Error, e: + return error_page(req) + + (auth_code, auth_msg) = check_user(uid,'cfgwebcomment') + if not auth_code: + return page(title="View all Reported Users", + body=perform_request_users(ln=ln), + uid=uid, + language=ln, + urlargs=req.args, + navtrail = navtrail_previous_links, + lastupdated=__lastupdated__) + else: + return page_not_authorized(req=req, text=auth_msg, navtrail=navtrail_previous_links) + +def del_com(req, ln=cdslang, **hidden): + """ + private funciton + Delete a comment + @param ln: language + @param **hidden: ids of comments to delete sent as individual variables comidX=on, where X is id + """ + navtrail_previous_links = getnavtrail() + """ > Comment Management""" % (weburl,) + + try: + uid = getUid(req) + except MySQLdb.Error, e: + return error_page(req) + + (auth_code, auth_msg) = check_user(uid,'cfgwebcomment') + if not auth_code: + comIDs = [] + args = hidden.keys() + for var in args: + try: + comIDs.append(int(var.split('comid')[1])) + except: + pass + return page(title="Delete Comments", + body=perform_request_del_com(ln=ln, comIDs=comIDs), + uid=uid, + language=ln, + urlargs=req.args, + navtrail = navtrail_previous_links, + lastupdated=__lastupdated__) + else: + return page_not_authorized(req=req, text=auth_msg, navtrail=navtrail_previous_links) + diff --git a/modules/webcomment/web/comments.py b/modules/webcomment/web/comments.py new file mode 100644 index 000000000..39af458e0 --- /dev/null +++ b/modules/webcomment/web/comments.py @@ -0,0 +1,194 @@ +# -*- coding: utf-8 -*- +## $Id$ +## Comments and reviews for records. + +## This file is part of the CERN Document Server Software (CDSware). +## Copyright (C) 2002, 2003, 2004, 2005 CERN. +## +## The CDSware 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. +## +## The CDSware 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 CDSware; if not, write to the Free Software Foundation, Inc., +## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + +__lastupdated__ = """FIXME: last updated""" + +from cdsware import webcomment +from cdsware.config import * +from cdsware.webuser import getUid, page_not_authorized, isGuestUser +from cdsware.webaccount import create_login_page_box, create_register_page_box +from cdsware.webpage import page, create_error_box +from cdsware.search_engine import create_navtrail_links, guess_primary_collection_of_a_record + +from mod_python import apache +import urllib + +def index(req): + """ + Redirects to display function + """ + req.err_headers_out.add("Location", "%s/comments.py/display?%s" % (weburl, req.args)) + raise apache.SERVER_RETURN, apache.HTTP_MOVED_PERMANENTLY + +def display(req, ln=cdslang, recid=-1, do='od', ds='all', nb=100, p=1, voted=-1, reported=-1, reviews=0): + """ + Display comments (reviews if enabled) associated with record having id recid where recid>0. + This function can also be used to display remarks associated with basket having id recid where recid<-99. + @param ln: language + @param recid: record id, integer + @param do: 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 ds: 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 nb: number of results per page + @param p: results page + @param voted: boolean, active if user voted for a review, see vote function + @param reported: boolean, active if user reported a certain comment/review, see report function + @param reviews: boolean, enabled for reviews, disabled for comments + @return the full html page. + """ + (body, errors_to_display, warnings) = webcomment.perform_request_display_comments_or_remarks(recID=recid, display_order=do, display_since=ds, nb_per_page=nb, + page=p, ln=ln, voted=voted, reported=reported, reviews=reviews) + uid = getUid(req) + + navtrail = create_navtrail_links(cc=guess_primary_collection_of_a_record(recid)) + \ + """ > Detailed record #%s""" % (weburl, recid, ln, recid) + \ + """ > %s""" % (reviews==1 and "Reviews" or "Comments",) + + return page(title="", body=body, navtrail=navtrail, description="", keywords="", uid=uid, + cdspageheaderadd="", cdspageboxlefttopadd="", cdspageboxleftbottomadd="", cdspageboxrighttopadd="", + cdspageboxrightbottomadd="", cdspagefooteradd="", lastupdated="", urlargs="", verbose=1, titleprologue="", titleepilogue="", + req=req, errors=errors_to_display, warnings=warnings) + +def add(req, ln=cdslang, recid=-1, action='DISPLAY', msg="", note="", score="", reviews=0, comid=-1): + """ + Add a comment (review) to record with id recid where recid>0 + Also works for adding a remark to basket with id recid where recid<-99 + @param ln: languange + @param recid: record id + @param action: 'DISPLAY' to display add form + 'SUBMIT' to submit comment once form is filled + 'REPLY' to reply to an already existing comment + @param msg: the body of the comment/review or remark + @param score: star score of the review + @param note: title of the review + @param comid: comment id, needed for replying + @return the full html page. + """ + actions = ['DISPLAY', 'REPLY', 'SUBMIT'] + + uid = getUid(req) + + navtrail = create_navtrail_links(cc=guess_primary_collection_of_a_record(recid)) + \ + """ > Detailed record #%s""" % (weburl, recid, ln, recid) + \ + """ > %s""" % (weburl, recid, ln, reviews==1 and 'Reviews' or 'Comments') + + if action not in actions: + action = 'DISPLAY' + + # is page allowed to be viewed + if uid == -1 or (not cfg_webcomment_allow_comments and not cfg_comment_allow_reviews): + return page_not_authorized(req, "../comments.py/add") + + # if guest, must log in first + if isGuestUser(uid): + msg = "Before you add your comment, you need to log in first" + referer = "%s/comments.py/add?recid=%s&ln=%s&reviews=%s&comid=%s&action=%s" % (weburl, recid, ln, reviews, comid, action) + login_box = create_login_page_box(referer) + return page(title="Login", body=msg+login_box, navtrail=navtrail, description="", keywords="", + uid=uid, cdspageheaderadd="", cdspageboxlefttopadd="", cdspageboxleftbottomadd="", + cdspageboxrighttopadd="", cdspageboxrightbottomadd="", cdspagefooteradd="", + lastupdated="", language=cdslang, urlargs="", verbose=1, titleprologue="", titleepilogue="") + # user logged in + else: + (body, errors, warnings) = webcomment.perform_request_add_comment_or_remark(recID=recid, uid=uid, action=action, msg=msg, note=note, score=score, reviews=reviews, comID=comid) + title = "Add %s" % (reviews==1 and 'Review' or 'Comment') + return page(title=title, body=body, navtrail=navtrail, description="", keywords="", uid=uid, + cdspageheaderadd="", cdspageboxlefttopadd="", cdspageboxleftbottomadd="", + cdspageboxrighttopadd="", cdspageboxrightbottomadd="", cdspagefooteradd="", + lastupdated="", language=cdslang, urlargs="", verbose=1, titleprologue="", titleepilogue="", errors=errors, warnings=warnings) + +def vote(req, comid=-1, com_value=0, recid=-1, ln=cdslang, do='od', ds='all', nb=100, p=1, referer=None, reviews=0): + """ + Vote positively or negatively for a comment/review. + @param comid: comment/review id + @param com_value: +1 to vote positively + -1 to vote negatively + @param recid: the id of the record the comment/review is associated with + @param ln: language + @param do: 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 ds: 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 nb: number of results per page + @param p: results page + @param referer: http address of the calling function to redirect to (refresh) + @param reviews: boolean, enabled for reviews, disabled for comments + """ + success = webcomment.perform_request_vote(comid, com_value) + if referer: + referer = referer + '''?recid=%s&ln=%s&do=%s&ds=%s&nb=%s&p=%s&voted=%s&reviews=%s''' % \ + (recid, ln, do, ds, nb, p, success, reviews) + req.err_headers_out.add("Location", referer) + raise apache.SERVER_RETURN, apache.HTTP_MOVED_PERMANENTLY + else: #Note: sent to commetns display + req.err_headers_out.add("Location", "%s/comments.py/display?recid=%s&ln=%s&reviews=1&voted=1" % (weburl, recid, ln)) + raise apache.SERVER_RETURN, apache.HTTP_MOVED_PERMANENTLY + +def report(req, comid=-1, recid=-1, ln=cdslang, do='od', ds='all', nb=100, p=1, referer=None, reviews=0): + """ + Report a comment/review for inappropriate content + @param comid: comment/review id + @param recid: the id of the record the comment/review is associated with + @param ln: language + @param do: 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 ds: 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 nb: number of results per page + @param p: results page + @param referer: http address of the calling function to redirect to (refresh) + @param reviews: boolean, enabled for reviews, disabled for comments + """ + success = webcomment.perform_request_report(comid) + if referer: + referer = referer + '''?recid=%s&ln=%s&do=%s&ds=%s&nb=%s&p=%s&reported=%s&reviews=%s''' % \ + (recid, ln, do, ds, nb, p, success, reviews) + req.err_headers_out.add("Location", referer) + raise apache.SERVER_RETURN, apache.HTTP_MOVED_PERMANENTLY + else: #Note: sent to comments display + req.err_headers_out.add("Location", "%s/comments.py/display?recid=%s&ln=%s&reviews=1&voted=1" % (weburl, recid, ln)) + raise apache.SERVER_RETURN, apache.HTTP_MOVED_PERMANENTLY +