diff --git a/modules/bibedit/lib/bibedit_templates.py b/modules/bibedit/lib/bibedit_templates.py
index 44d6b79f8..f1338649e 100644
--- a/modules/bibedit/lib/bibedit_templates.py
+++ b/modules/bibedit/lib/bibedit_templates.py
@@ -1,537 +1,530 @@
## $Id$
##
## This file is part of CDS Invenio.
## Copyright (C) 2002, 2003, 2004, 2005, 2006 CERN.
##
## CDS Invenio is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License as
## published by the Free Software Foundation; either version 2 of the
## License, or (at your option) any later version.
##
## CDS Invenio is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
from invenio.bibedit_dblayer import *
from invenio.config import weburl
from invenio.messages import gettext_set_language
## Link of edit and delete button:
btn_delete_url = weburl + "/img/iconcross.gif"
btn_edit_url = weburl + "/img/iconpen.gif"
weburl_bibedit = "%s/admin/bibedit/bibeditadmin.py" % weburl
class Template:
def tmpl_table_header(self, ln, type_table, recid, temp="false", format_tag='marc',
tag='', num_field=None, add=0):
""" Return the Header of table. """
_ = gettext_set_language(ln)
(tag, ind1, ind2, junk) = marc_to_split_tag(tag)
tag = tag + ind1 + ind2 + "%"
if type_table != "record":
if add == 1:
print_input_add_form = self.tmpl_input('hidden', 2, 'add')
else:
print_input_add_form = ''
print_action_add_subfield = print_input_add_form + self.tmpl_input('hidden', str(num_field), 'num_field')
if add != 1:
link_add_subfields = self.tmpl_link(ln, _("Add Subfield"), weburl_bibedit, 'edit',
{'recid' : str(recid),
'tag' : tag[:3],
'num_field' : str(num_field),
'format_tag' : format_tag,
'temp' : 'true',
'add' : 1})
print_action_add_subfield = """ %(field)s:
%(link_add_subfields)s
""" % {'field' : _("Field"),
'link_add_subfields' : link_add_subfields}
if add == 1:
link_form = "edit"
else:
link_form = "index"
result = """
""" % {'weburl_bibedit' : weburl_bibedit,
'message' : _("Please enter the ID of the record you want to edit"),
'input_ln' : self.tmpl_input('hidden', ln, 'ln'),
'input_recid' : self.tmpl_input('text' , '', 'recid'),
'input_button' : self.tmpl_input('submit', _("Edit"),
class_css='formbutton')}
return result
def tmpl_submit(self, ln):
""" Return a end message of Bibedit. """
_ = gettext_set_language(ln)
- link = '%s' % (weburl, ln, _("BibEdit Admin Interface"))
- return """ %(message1)s
- %(message2)s
- %(message3)s:
- %(link)s.
- """ % {'message1': _("Your modifications have now been submitted."),
- 'message2': _("They will be processed as soon as the task queue is empty."),
- 'message3': _("You can now go back to %s.") % link}
+ out = _("Your modifications have now been submitted. They will be processed as soon as the task queue is empty.") + '
""" % {'message' : _("Do you really want to delete this record?"),
'weburl_bibedit' : weburl_bibedit,
'recid' : str(recid),
'input_ln' : self.tmpl_input('hidden', ln, 'ln'),
'input_button_yes' : self.tmpl_input('submit', _("Yes"), class_css='formbutton'),
'input_button_no' : self.tmpl_input('submit', _("No"), class_css='formbutton'),
'temp' : temp,
'format_tag' : format_tag}
else:
- out = """%(message)s %(message_back)s %(link)s."""
- out %= {'message': _("The record will be deleted as soon as the task queue is empty."),
- 'message_back': _("You can now go back to"),
- 'link' : _("BibEdit Admin Interface"),
- 'weburl' : weburl,
- 'ln' : ln}
+ out = _("The record will be deleted as soon as the task queue is empty.") + '
'
+ link_open = ''
+ out += _("You can now go back to %(x_url_open)sBibEdit Admin Interface%(x_url_close)s.") % {'x_url_open': link_open, 'x_url_close': ''}
return out
def tmpl_link(self, ln, text, url, dest, dict_args='', ancre=''):
""" Return a link. """
if dict_args == '':
link_args = ''
else:
link_args = '?'
list_args = dict_args.items()
for arg in list_args:
link_args += "%(name)s=%(value)s&" % {'name' : str(arg[0]),
- 'value' : str(arg[1])}
+ 'value' : str(arg[1])}
link_args += "ln=%s" % ln
if ancre != '':
ancre = '#' + ancre
return ' %(text)s ' % {'text' : text,
'url' : url,
'dest' : dest,
'args' : link_args,
'ancre' : ancre}
def tmpl_input(self, type_input, value='', name='', maxlength='', size='', class_css='', style=''):
""" Return a input form. """
if value != '':
value = 'value="%s"' % str(value)
if name != '':
name = 'name="%s"' % str(name)
if maxlength != '':
maxlength = 'maxlength="%s"' % str(maxlength)
if size != '':
size = 'size="%s"' % str(size)
if class_css != '':
class_css = 'class="%s"' % str(class_css)
if style != '':
style = 'style="%s"' % str(style)
out = ''
out %= {'type' : type_input,
'value' : value,
'name' : name,
'maxlength' : maxlength,
'size' : size,
'class_css' : class_css,
'style' : style}
return out
diff --git a/modules/webalert/lib/webalert.py b/modules/webalert/lib/webalert.py
index a010d6c15..142e7b750 100644
--- a/modules/webalert/lib/webalert.py
+++ b/modules/webalert/lib/webalert.py
@@ -1,370 +1,370 @@
## $Id$
## This file is part of CDS Invenio.
## Copyright (C) 2002, 2003, 2004, 2005, 2006 CERN.
##
## CDS Invenio is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License as
## published by the Free Software Foundation; either version 2 of the
## License, or (at your option) any later version.
##
## CDS Invenio is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
"""PERSONAL FEATURES - YOUR ALERTS"""
import cgi
import time
from invenio.config import weburl, cdslang
from invenio.dbquery import run_sql
from invenio.webuser import isGuestUser
from invenio.webaccount import warning_guest_user
from invenio.webbasket import create_personal_baskets_selection_box
from invenio.messages import gettext_set_language
from invenio.dateutils import convert_datestruct_to_datetext, convert_datetext_to_dategui
import invenio.template
webalert_templates = invenio.template.load('webalert')
### IMPLEMENTATION
class AlertError(Exception):
pass
def check_alert_name(alert_name, uid, ln=cdslang):
"""check this user does not have another alert with this name."""
sql = """select id_query
from user_query_basket
where id_user=%s and alert_name='%s'"""%(uid, alert_name.strip())
res = run_sql( sql )
# load the right message language
_ = gettext_set_language(ln)
if len( run_sql( sql ) ) > 0:
raise AlertError( _("You already have an alert named %s.") % ('' + alert_name + '',) )
def get_textual_query_info_from_urlargs(urlargs, ln=cdslang):
"""Return nicely formatted search pattern and catalogue from urlargs of the search query.
Suitable for 'your searches' display."""
out = ""
args = cgi.parse_qs(urlargs)
return webalert_templates.tmpl_textual_query_info_from_urlargs(
ln = ln,
args = args,
)
return out
def perform_display(permanent, uid, ln=cdslang):
"""display the searches performed by the current user
input: default permanent="n"; permanent="y" display permanent queries(most popular)
output: list of searches in formatted html
"""
# load the right message language
_ = gettext_set_language(ln)
# first detect number of queries:
nb_queries_total = 0
nb_queries_distinct = 0
id_queries_distinct = []
query = "SELECT COUNT(*),COUNT(DISTINCT(id_query)) FROM user_query WHERE id_user=%s"
res = run_sql(query, (uid,), 1)
try:
nb_queries_total = res[0][0]
nb_queries_distinct = res[0][1]
except:
pass
# query for queries:
if permanent == "n":
SQL_query = "SELECT DISTINCT(q.id),q.urlargs "\
"FROM query q, user_query uq "\
"WHERE uq.id_user='%s' "\
"AND uq.id_query=q.id "\
"ORDER BY q.id DESC" % uid
else:
# permanent="y"
SQL_query = "SELECT q.id,q.urlargs "\
"FROM query q "\
"WHERE q.type='p'"
query_result = run_sql(SQL_query)
queries = []
if len(query_result) > 0:
for row in query_result :
if permanent == "n":
res = run_sql("SELECT DATE_FORMAT(MAX(date),'%%Y-%%m-%%d %%H:%%i:%%s') FROM user_query WHERE id_user=%s and id_query=%s",
(uid, row[0]))
try:
lastrun = res[0][0]
except:
lastrun = _("unknown")
else:
lastrun = ""
queries.append({
'id' : row[0],
'args' : row[1],
'textargs' : get_textual_query_info_from_urlargs(row[1], ln=ln),
'lastrun' : lastrun,
})
return webalert_templates.tmpl_display_alerts(
ln = ln,
permanent = permanent,
nb_queries_total = nb_queries_total,
nb_queries_distinct = nb_queries_distinct,
queries = queries,
guest = isGuestUser(uid),
guesttxt = warning_guest_user(type="alerts", ln=ln),
weburl = weburl
)
def perform_input_alert(action, id_query, alert_name, frequency, notification, id_basket,uid, old_id_basket=None, ln = cdslang):
"""get the alert settings
input: action="add" for a new alert (blank form), action="modify" for an update
(get old values)
id_query id the identifier of the search to be alerted
for the "modify" action specify old alert_name, frequency of checking,
e-mail notification and basket id.
output: alert settings input form"""
# display query information
res = run_sql("SELECT urlargs FROM query WHERE id=%s", (id_query,))
try:
urlargs = res[0][0]
except:
urlargs = "UNKNOWN"
baskets = create_personal_baskets_selection_box(uid=uid,
html_select_box_name='idb',
selected_bskid=old_id_basket,
ln=cdslang)
return webalert_templates.tmpl_input_alert(
ln = ln,
query = get_textual_query_info_from_urlargs(urlargs, ln = ln),
action = action,
frequency = frequency,
notification = notification,
alert_name = alert_name,
baskets = baskets,
old_id_basket = old_id_basket,
id_basket = id_basket,
id_query = id_query,
)
def check_alert_is_unique(id_basket, id_query, uid, ln=cdslang ):
"""check the user does not have another alert for the specified query and basket"""
_ = gettext_set_language(ln)
sql = """select id_query
from user_query_basket
where id_user = %s and id_query = %s
and id_basket= %s"""%(uid, id_query, id_basket)
res = run_sql(sql)
if len(res):
raise AlertError(_("You already have an alert defined for the specified query and basket."))
def perform_add_alert(alert_name, frequency, notification,
id_basket, id_query, uid, ln = cdslang):
"""add an alert to the database
input: the name of the new alert;
alert frequency: 'month', 'week' or 'day';
setting for e-mail notification: 'y' for yes, 'n' for no;
basket identifier: 'no' for no basket;
new basket name for this alert;
identifier of the query to be alerted
output: confirmation message + the list of alerts Web page"""
alert_name = alert_name.strip()
# load the right message language
_ = gettext_set_language(ln)
#check the alert name is not empty
if alert_name.strip() == "":
raise AlertError(_("The alert name cannot be empty."))
#check if the alert can be created
check_alert_name(alert_name, uid, ln)
check_alert_is_unique(id_basket, id_query, uid, ln)
# add a row to the alerts table: user_query_basket
query = """INSERT INTO user_query_basket (id_user, id_query, id_basket,
frequency, date_creation, date_lastrun,
alert_name, notification)
VALUES ('%s','%s','%s','%s','%s','','%s','%s')"""
query %= (uid, id_query, id_basket,
frequency, convert_datestruct_to_datetext(time.localtime()),
alert_name, notification)
run_sql(query)
out = _("The alert %s has been added to your profile.")
out %= '' + alert_name + ''
out += perform_list_alerts(uid, ln=ln)
return out
def perform_list_alerts (uid, ln=cdslang):
"""perform_list_alerts display the list of alerts for the connected user"""
# set variables
out = ""
# query the database
query = """ SELECT q.id, q.urlargs,
a.id_basket, b.name,
a.alert_name, a.frequency,a.notification,
DATE_FORMAT(a.date_creation,'%%Y-%%m-%%d %%H:%%i:%%s'),
DATE_FORMAT(a.date_lastrun,'%%Y-%%m-%%d %%H:%%i:%%s')
FROM user_query_basket a LEFT JOIN query q ON a.id_query=q.id
LEFT JOIN bskBASKET b ON a.id_basket=b.id
WHERE a.id_user='%s'
ORDER BY a.alert_name ASC """ % uid
res = run_sql(query)
alerts = []
for (qry_id, qry_args,
bsk_id, bsk_name,
alrt_name, alrt_frequency, alrt_notification, alrt_creation, alrt_last_run) in res:
alerts.append({
'queryid' : qry_id,
'queryargs' : qry_args,
'textargs' : get_textual_query_info_from_urlargs(qry_args, ln=ln),
'userid' : uid,
'basketid' : bsk_id,
'basketname' : bsk_name,
'alertname' : alrt_name,
'frequency' : alrt_frequency,
'notification' : alrt_notification,
'created' : convert_datetext_to_dategui(alrt_creation),
'lastrun' : convert_datetext_to_dategui(alrt_last_run)
})
# link to the "add new alert" form
out = webalert_templates.tmpl_list_alerts(ln=ln, weburl=weburl, alerts=alerts,
guest=isGuestUser(uid),
guesttxt=warning_guest_user(type="alerts", ln=ln))
return out
def perform_remove_alert(alert_name, id_user, id_query, id_basket, uid, ln=cdslang):
"""perform_remove_alert: remove an alert from the database
input: identifier of the user;
identifier of the query;
identifier of the basket
output: confirmation message + the list of alerts Web page"""
# set variables
out = ""
# remove a row from the alerts table: user_query_basket
query = """DELETE FROM user_query_basket
WHERE id_user='%s' AND id_query='%s' AND id_basket='%s'"""
query %= (id_user, id_query, id_basket)
run_sql(query)
out += "The alert %s has been removed from your profile.
\n" % alert_name
out += perform_list_alerts(uid, ln=ln)
return out
def perform_update_alert(alert_name, frequency, notification, id_basket, id_query, old_id_basket,uid, ln = cdslang):
"""update alert settings into the database
input: the name of the new alert;
alert frequency: 'month', 'week' or 'day';
setting for e-mail notification: 'y' for yes, 'n' for no;
new basket identifier: 'no' for no basket;
new basket name for this alert;
identifier of the query to be alerted
old identifier of the basket associated to the alert
output: confirmation message + the list of alerts Web page"""
#set variables
out = ""
# load the right message language
_ = gettext_set_language(ln)
#check the alert name is not empty
if alert_name.strip() == "":
raise AlertError(_("The alert name cannot be empty."))
#check if the alert can be created
sql = """select alert_name
from user_query_basket
where id_user=%s
and id_basket=%s
and id_query=%s"""%( uid, old_id_basket, id_query )
old_alert_name = run_sql( sql )[0][0]
if old_alert_name.strip()!="" and old_alert_name != alert_name:
check_alert_name( alert_name, uid, ln)
if id_basket != old_id_basket:
check_alert_is_unique( id_basket, id_query, uid, ln)
# update a row into the alerts table: user_query_basket
query = """UPDATE user_query_basket
SET alert_name='%s',frequency='%s',notification='%s',
date_creation='%s',date_lastrun='',id_basket='%s'
WHERE id_user='%s' AND id_query='%s' AND id_basket='%s'"""
query %= (alert_name, frequency, notification,
convert_datestruct_to_datetext(time.localtime()),
id_basket, uid, id_query, old_id_basket)
run_sql(query)
out += _("The alert %s has been successfully updated.") % ("" + alert_name + "",)
out += "
\n" + perform_list_alerts(uid, ln=ln)
return out
def is_selected(var, fld):
"Checks if the two are equal, and if yes, returns ' selected'. Useful for select boxes."
if var == fld:
return " selected"
else:
return ""
def account_list_alerts(uid, ln=cdslang):
"""account_list_alerts: list alert for the account page
input: the user id
language
output: the list of alerts Web page"""
query = """ SELECT q.id, q.urlargs, a.id_user, a.id_query,
a.id_basket, a.alert_name, a.frequency,
a.notification,
DATE_FORMAT(a.date_creation,'%%d %%b %%Y'),
DATE_FORMAT(a.date_lastrun,'%%d %%b %%Y'),
a.id_basket
FROM query q, user_query_basket a
WHERE a.id_user='%s' AND a.id_query=q.id
ORDER BY a.alert_name ASC """ % uid
res = run_sql(query)
alerts = []
if len(res):
for row in res:
alerts.append({
'id' : row[0],
'name' : row[5]
})
return webalert_templates.tmpl_account_list_alerts(ln=ln, alerts=alerts)
def account_list_searches(uid, ln=cdslang):
""" account_list_searches: list the searches of the user
input: the user id
output: resume of the searches"""
out =""
# first detect number of queries:
nb_queries_total = 0
nb_queries_distinct = 0
id_queries_distinct = []
res = run_sql("SELECT COUNT(*),COUNT(DISTINCT(id_query)) FROM user_query WHERE id_user=%s", (uid,), 1)
try:
nb_queries_total = res[0][0]
nb_queries_distinct = res[0][1]
except:
pass
# load the right message language
_ = gettext_set_language(ln)
- out += _("You have made %s queries. A %sdetailed list%s is available with a posibility to (a) view search results and (b) subscribe to an automatic email alerting service for these queries.") % (nb_queries_total, '' % ln, '')
+ out += _("You have made %(x_nb)s queries. A %(x_url_open)sdetailed list%(x_url_close)s is available with a posibility to (a) view search results and (b) subscribe to an automatic email alerting service for these queries.") % {'x_nb': nb_queries_total, 'x_url_open': '' % ln, 'x_url_close': ''}
return out
diff --git a/modules/webalert/lib/webalert_templates.py b/modules/webalert/lib/webalert_templates.py
index 92deb28fc..3e3eafaab 100644
--- a/modules/webalert/lib/webalert_templates.py
+++ b/modules/webalert/lib/webalert_templates.py
@@ -1,549 +1,553 @@
## $Id$
## This file is part of CDS Invenio.
## Copyright (C) 2002, 2003, 2004, 2005, 2006 CERN.
##
## CDS Invenio is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License as
## published by the Free Software Foundation; either version 2 of the
## License, or (at your option) any later version.
##
## CDS Invenio is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
import urllib
import time
import cgi
import gettext
import string
import locale
import re
import operator
from invenio.config import *
from invenio.messages import gettext_set_language
from invenio.htmlparser import get_as_text, wrap
from invenio.alert_engine_config import cfg_webalert_max_num_of_records_in_alert_email
class Template:
def tmpl_errorMsg(self, ln, error_msg, rest = ""):
"""
Adds an error message to the output
Parameters:
- 'ln' *string* - The language to display the interface in
- 'error_msg' *string* - The error message
- 'rest' *string* - The rest of the page
"""
# load the right message language
_ = gettext_set_language(ln)
out = """
%(error)s
%(rest)s""" % {
'error' : error_msg,
'rest' : rest
}
return out
def tmpl_textual_query_info_from_urlargs(self, ln, args):
"""
Displays a human inteligible textual representation of a query
Parameters:
- 'ln' *string* - The language to display the interface in
- 'args' *array* - The URL arguments array (parsed)
"""
# load the right message language
_ = gettext_set_language(ln)
out = ""
if args.has_key('p'):
out += "" + _("Pattern") + ": " + string.join(args['p'], "; ") + " "
if args.has_key('f'):
out += "" + _("Field") + ": " + string.join(args['f'], "; ") + " "
if args.has_key('p1'):
out += "" + _("Pattern 1") + ": " + string.join(args['p1'], "; ") + " "
if args.has_key('f1'):
out += "" + _("Field 1") + ": " + string.join(args['f1'], "; ") + " "
if args.has_key('p2'):
out += "" + _("Pattern 2") + ": " + string.join(args['p2'], "; ") + " "
if args.has_key('f2'):
out += "" + _("Field 2") + ": " + string.join(args['f2'], "; ") + " "
if args.has_key('p3'):
out += "" + _("Pattern 3") + ": " + string.join(args['p3'], "; ") + " "
if args.has_key('f3'):
out += "" + _("Field 3") + ": " + string.join(args['f3'], "; ") + " "
if args.has_key('c'):
out += "" + _("Collections") + ": " + string.join(args['c'], "; ") + " "
elif args.has_key('cc'):
out += "" + _("Collection") + ": " + string.join(args['cc'], "; ") + " "
return out
def tmpl_account_list_alerts(self, ln, alerts):
"""
Displays all the alerts in the main "Your account" page
Parameters:
- 'ln' *string* - The language to display the interface in
- 'alerts' *array* - The existing alerts IDs ('id' + 'name' pairs)
"""
# load the right message language
_ = gettext_set_language(ln)
out = """
%(you_own)s:
""" % {
'show' : _("SHOW"),
}
return out
def tmpl_input_alert(self, ln, query, alert_name, action, frequency, notification, baskets, old_id_basket, id_basket, id_query):
"""
Displays an alert adding form.
Parameters:
- 'ln' *string* - The language to display the interface in
- 'query' *string* - The HTML code of the textual representation of the query (as returned ultimately by tmpl_textual_query_info_from_urlargs...)
- 'alert_name' *string* - The alert name
- 'action' *string* - The action to complete ('update' or 'add')
- 'frequency' *string* - The frequency of alert running ('day', 'week', 'month')
- 'notification' *string* - If notification should be sent by email ('y', 'n')
- 'baskets' *array* - The existing baskets ('id' + 'name' pairs)
- 'old_id_basket' *string* - The id of the previous basket of this alert
- 'id_basket' *string* - The id of the basket of this alert
- 'id_query' *string* - The id of the query associated to this alert
"""
# load the right message language
_ = gettext_set_language(ln)
out = ""
out += """
%(notify_cond)s
%(query_text)s:
%(query)s
""" % {
'notify_cond' : _("This alert will notify you each time/only if a new item satisfies the following query:"),
'query_text' : _("QUERY"),
'query' : query,
}
out += """
%(alert_name)s:
%(freq)s:
%(send_email)s
(%(specify)s)
%(store_basket)s
%(baskets)s
""" % {
'action': action,
'alert_name' : _("Alert identification name:"),
'alert' : alert_name,
'freq' : _("Search-checking frequency:"),
'freq_month' : (frequency == 'month' and 'selected="selected"' or ""),
'freq_week' : (frequency == 'week' and 'selected="selected"' or ""),
'freq_day' : (frequency == 'day' and 'selected="selected"' or ""),
'monthly' : _("monthly"),
'weekly' : _("weekly"),
'daily' : _("daily"),
'send_email' : _("Send notification email?"),
'notif_yes' : (notification == 'y' and "selected" or ""),
'notif_no' : (notification == 'n' and "selected" or ""),
'yes' : _("yes"),
'no' : _("no"),
- 'specify' : _("if %sno%s you must specify a basket") % ('', ''),
+ 'specify' : _("if %(x_fmt_open)sno%(x_fmt_close)s you must specify a basket") % {'x_fmt_open': '',
+ 'x_fmt_close': ''},
'store_basket' : _("Store results in basket?"),
'baskets': baskets
}
out += """
""" % {
'idq' : id_query,
'ln' : ln,
'set_alert' : _("SET ALERT"),
'clear_data' : _("CLEAR DATA"),
}
if action == "update":
out += '' % old_id_basket
out += "
"
return out
def tmpl_list_alerts(self, ln, weburl, alerts, guest, guesttxt):
"""
Displays the list of alerts
Parameters:
- 'ln' *string* - The language to display the interface in
- 'weburl' *string* - The url of CDS Invenio
- 'alerts' *array* - The existing alerts:
- 'queryid' *string* - The id of the associated query
- 'queryargs' *string* - The query string
- 'textargs' *string* - The textual description of the query string
- 'userid' *string* - The user id
- 'basketid' *string* - The basket id
- 'basketname' *string* - The basket name
- 'alertname' *string* - The alert name
- 'frequency' *string* - The frequency of alert running ('day', 'week', 'month')
- 'notification' *string* - If notification should be sent by email ('y', 'n')
- 'created' *string* - The date of alert creation
- 'lastrun' *string* - The last running date
- 'guest' *bool* - If the user is a guest user
- 'guesttxt' *string* - The HTML content of the warning box for guest users (produced by webaccount.tmpl_warning_guest_user)
"""
# load the right message language
_ = gettext_set_language(ln)
- out = '
' + _("Set a new alert from %syour searches%s, the %spopular_searches%s, or the input form.") + '
' + (_("You have defined %s alerts.") % ('' + str(len(alerts)) + '' )) + '
'
if guest:
out += guesttxt
return out
def tmpl_display_alerts(self, ln, weburl, permanent, nb_queries_total, nb_queries_distinct, queries, guest, guesttxt):
"""
Displays the list of alerts
Parameters:
- 'ln' *string* - The language to display the interface in
- 'weburl' *string* - The url of CDS Invenio
- 'permanent' *string* - If displaying most popular searches ('y') or only personal searches ('n')
- 'nb_queries_total' *string* - The number of personal queries in the last period
- 'nb_queries_distinct' *string* - The number of distinct queries in the last period
- 'queries' *array* - The existing queries:
- 'id' *string* - The id of the associated query
- 'args' *string* - The query string
- 'textargs' *string* - The textual description of the query string
- 'lastrun' *string* - The last running date (only for personal queries)
- 'guest' *bool* - If the user is a guest user
- 'guesttxt' *string* - The HTML content of the warning box for guest users (produced by webaccount.tmpl_warning_guest_user)
"""
# load the right message language
_ = gettext_set_language(ln)
if len(queries) == 0:
- out = _("You have not executed any search yet. Please go to the %ssearch interface%s first.") % ('' % (weburl, ln),
- '')
+ out = _("You have not executed any search yet. Please go to the %(x_url_open)ssearch interface%(x_url_close)s first.") % \
+ {'x_url_open': '',
+ 'x_url_close': ''}
return out
out = ''
# display message: number of items in the list
if permanent=="n":
- msg = _("You have performed %s searches (%s different questions) during the last 30 days or so.") % (nb_queries_total, nb_queries_distinct)
+ msg = _("You have performed %(x_nb1)s searches (%(x_nb2)s different questions) during the last 30 days or so.") % {'x_nb1': nb_queries_total,
+ 'x_nb_2': nb_queries_distinct}
out += '
' + msg + '
'
else:
# permanent="y"
msg = _("Here are the %s most popular searches.")
- msg %= ('' + str(len(query_result)) + '')
+ msg %= ('' + str(len(queries)) + '')
out += '
' + msg + '
'
# display the list of searches
out += """
%(no)s
%(question)s
%(action)s
""" % {
'no' : "#",
'question' : _("Question"),
'action' : _("Action")
}
if permanent=="n":
out += '
%s
' % _("Last Run")
out += "
\n"
i = 0
for query in queries :
i += 1
# id, pattern, base, search url and search set alert, date
out += """
""" % {
'index' : i,
'textargs' : query['textargs'],
'weburl' : weburl,
'args' : query['args'],
'id' : query['id'],
'ln': ln,
'execute_query' : _("Execute search"),
'set_alert' : _("Set new alert")
}
if permanent=="n":
out += '
%s
' % query['lastrun']
out += """
\n"""
out += "
\n"
if guest :
out += guesttxt
return out
def tmpl_alert_email_headers(self, name, headers):
headers['Subject'] = 'Alert %s run on %s' % (
name, time.strftime("%Y-%m-%d"))
headers['From'] = 'CDS Alert Engine <%s>' % alertengineemail
def tmpl_alert_email_body(self, name, url, records, pattern,
catalogues, frequency):
l = len(catalogues)
if l == 0:
collections = ''
elif l == 1:
collections = "collection: %s\n" % catalogues[0]
else:
collections = "collections: %s\n" % wrap(', '.join(catalogues))
if pattern:
pattern = 'pattern: %s\n' % pattern
frequency = {'day': 'daily',
'month': 'monthly',
'year': 'yearly'}[frequency]
l = len(records)
if l == 1:
total = '1 record'
else:
total = '%d records' % l
body = """\
Hello:
Below are the results of the email notification alert that
you set up with the %(cdsname)s.
This is an automatic message, please don't reply to it.
For any question, please use <%(supportemail)s> instead.
alert name: %(name)s
%(pattern)s%(collections)sfrequency: %(frequency)s
run time: %(runtime)s
found: %(total)s
url: <%(url)s>
""" % {'supportemail': supportemail,
'name': name,
'cdsname': cdsname,
'pattern': pattern,
'collections': collections,
'frequency': frequency,
'runtime': time.strftime("%a %Y-%m-%d %H:%M:%S"),
'total': total,
'url': url}
for index, recid in enumerate(records[:cfg_webalert_max_num_of_records_in_alert_email]):
body += "\n%i) " % (index + 1)
body += self.tmpl_alert_email_record(recid)
body += "\n"
if len(records) > cfg_webalert_max_num_of_records_in_alert_email:
body += '''
Only the first %s records were displayed. Please consult the search
URL given at the top of this email to see all the results.
''' % cfg_webalert_max_num_of_records_in_alert_email
body += '''
--
%s Alert Service <%s>
Unsubscribe? See <%s>
Need human intervention? Contact <%s>
''' % (cdsname, weburl, weburl + '/youralerts/list', supportemail)
return body
def tmpl_alert_email_record(self, recid):
""" Format a single record."""
out = wrap(get_as_text(recid))
out += "Detailed record: <%s/record/%s>" % (weburl, recid)
return out
diff --git a/modules/webbasket/lib/webbasket.py b/modules/webbasket/lib/webbasket.py
index b15d5fc02..4f0f8f2af 100644
--- a/modules/webbasket/lib/webbasket.py
+++ b/modules/webbasket/lib/webbasket.py
@@ -1,795 +1,797 @@
## $Id$
## This file is part of CDS Invenio.
## Copyright (C) 2002, 2003, 2004, 2005, 2006 CERN.
##
## CDS Invenio is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License as
## published by the Free Software Foundation; either version 2 of the
## License, or (at your option) any later version.
##
## CDS Invenio is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
"""Web Baskets features."""
from zlib import decompress
from invenio.config import cdslang, weburl
from invenio.messages import gettext_set_language
from invenio.dateutils import convert_datetext_to_dategui, \
convert_datetext_to_datestruct,\
convert_datestruct_to_dategui
from invenio.search_engine import print_record
from invenio.webbasket_config import cfg_webbasket_share_levels, \
cfg_webbasket_share_levels_ordered, \
cfg_webbasket_categories, \
cfg_webbasket_actions, \
cfg_webbasket_warning_messages, \
cfg_webbasket_error_messages, \
cfg_webbasket_max_number_of_displayed_baskets
from invenio.webuser import isGuestUser
import invenio.webbasket_dblayer as db
try:
import invenio.template
webbasket_templates = invenio.template.load('webbasket')
except ImportError:
pass
def perform_request_display(uid,
category=cfg_webbasket_categories['PRIVATE'],
selected_topic=0,
selected_group_id=0,
ln=cdslang):
"""Display all the baskets of given category, topic or group.
@param uid: user id
@param category: selected category (see webbasket_config.py)
@param selected_topic: # of selected topic to display baskets
@param selected_group_id: id of group to display baskets
@param ln: language"""
warnings = []
errors = []
baskets_html = []
_ = gettext_set_language(ln)
nb_groups = db.count_groups_user_member_of(uid)
nb_external_baskets = db.count_external_baskets(uid)
selectionbox = ''
infobox = ''
if category == cfg_webbasket_categories['EXTERNAL']:
baskets = db.get_external_baskets_infos(uid)
if len(baskets):
map(list, baskets)
else:
category = cfg_webbasket_categories['PRIVATE']
if category == cfg_webbasket_categories['GROUP']:
groups = db.get_group_infos(uid)
if len(groups):
if selected_group_id == 0 and len(groups):
selected_group_id = groups[0][0]
selectionbox = webbasket_templates.tmpl_group_selection(groups,
selected_group_id,
ln)
baskets = db.get_group_baskets_infos(selected_group_id)
def adapt_group_rights(item):
"""Suppress unused element in tuple."""
out = list(item)
if out[-1] == uid:
out[-2] = cfg_webbasket_share_levels['MANAGE']
return out[:-1]
baskets = map(adapt_group_rights, baskets)
else:
category = cfg_webbasket_categories['PRIVATE']
if category == cfg_webbasket_categories['PRIVATE']:
topics_list = db.get_personal_topics_infos(uid)
if not selected_topic and len(topics_list):
selected_topic = 0
selectionbox = webbasket_templates.tmpl_topic_selection(topics_list,
selected_topic,
ln)
if len(topics_list) > 0:
baskets = db.get_personal_baskets_infos(uid, topics_list[selected_topic][0])
else:
baskets = []
def add_manage_rights(item):
""" Convert a tuple to a list and add rights"""
out = list(item)
out.append(cfg_webbasket_share_levels['MANAGE'])
return out
baskets = map(add_manage_rights, baskets)
bskids = []
for basket in baskets:
bskids.append(basket[0])
levels = dict(db.is_shared_to(bskids))
create_link = ''
if category == cfg_webbasket_categories['PRIVATE']:
create_link = webbasket_templates.tmpl_create_basket_link(selected_topic, ln)
infobox = webbasket_templates.tmpl_baskets_infobox(map(lambda x: (x[0], x[1], x[2]),
baskets),
create_link,
ln)
for (bskid, name, date_modification,
nb_views, nb_items, last_added, share_level) in baskets:
(bsk_html, bsk_e, bsk_w) = __display_basket(bskid,
name,
date_modification,
nb_views,
nb_items,
last_added,
share_level,
levels[bskid],
category,
selected_topic,
selected_group_id,
ln)
baskets_html.append(bsk_html)
errors.extend(bsk_e)
warnings.extend(bsk_w)
body = webbasket_templates.tmpl_display(selectionbox,
infobox,
baskets_html,
category,
nb_groups,
nb_external_baskets,
ln)
return (body, errors, warnings)
def __display_basket(bskid, name, date_modification, nb_views,
nb_items, last_added,
share_level, group_sharing_level,
category=cfg_webbasket_categories['PRIVATE'],
selected_topic=0, selected_group_id=0,
ln=cdslang):
"""Private function. Display a basket giving its category and topic or group.
@param share_level: rights user has on basket
@param group_sharing_level: None if basket is not shared,
0 if public basket,
> 0 if shared to usergroups but not public.
@param category: selected category (see webbasket_config.py)
@param selected_topic: # of selected topic to display baskets
@param selected_group_id: id of group to display baskets
@param ln: language"""
_ = gettext_set_language(ln)
errors = []
warnings = []
nb_bsk_cmts = 0
last_cmt = _("N/A")
records = []
cmt_dates = []
date_modification = convert_datetext_to_dategui(date_modification, ln)
items = db.get_basket_content(bskid, 'hb')
for (recid, nb_cmt, last_cmt, ext_val, int_val, score) in items:
cmt_dates.append(convert_datetext_to_datestruct(last_cmt))
last_cmt = convert_datetext_to_dategui(last_cmt, ln)
val = ''
nb_bsk_cmts += nb_cmt
if recid < 0:
if ext_val:
val = decompress(ext_val)
else:
if int_val:
val = decompress(int_val)
records.append((recid, nb_cmt, last_cmt, val, score))
if len(cmt_dates) > 0:
last_cmt = convert_datestruct_to_dategui(max(cmt_dates), ln)
body = webbasket_templates.tmpl_basket(bskid,
name,
date_modification,
nb_views,
nb_items, last_added,
(__check_sufficient_rights(share_level, cfg_webbasket_share_levels['READITM']),
__check_sufficient_rights(share_level, cfg_webbasket_share_levels['MANAGE']),
__check_sufficient_rights(share_level, cfg_webbasket_share_levels['READCMT']),
__check_sufficient_rights(share_level, cfg_webbasket_share_levels['ADDITM']),
__check_sufficient_rights(share_level, cfg_webbasket_share_levels['DELITM'])),
nb_bsk_cmts, last_cmt,
group_sharing_level,
category, selected_topic, selected_group_id,
records,
ln)
return (body, errors, warnings)
def perform_request_display_item(uid, bskid, recid, format='hb',
category=cfg_webbasket_categories['PRIVATE'],
topic=0, group_id=0, ln=cdslang):
"""Display an item of a basket of given category, topic or group.
@param uid: user id
@param bskid: basket_id
@param recid: record id
@param format: format of the record (hb, hd, etc.)
@param category: selected category (see webbasket_config.py)
@param topic: # of selected topic to display baskets
@param group_id: id of group to display baskets
@param ln: language"""
body = ''
errors = []
warnings = []
rights = db.get_max_user_rights_on_basket(uid, bskid)
if not(__check_sufficient_rights(rights, cfg_webbasket_share_levels['READITM'])):
errors.append('ERR_WEBBASKET_NO_RIGHTS')
return (body, errors, warnings)
if category == cfg_webbasket_categories['PRIVATE']:
topics_list = db.get_personal_topics_infos(uid)
if not topic and len(topics_list):
topic = 0
topicsbox = webbasket_templates.tmpl_topic_selection(topics_list, topic, ln)
elif category == cfg_webbasket_categories['GROUP']:
groups = db.get_group_infos(uid)
if group_id == 0 and len(groups):
group_id = groups[0][0]
topicsbox = webbasket_templates.tmpl_group_selection(groups, group_id, ln)
else:
topicsbox = ''
record = db.get_basket_record(bskid, recid, format)
comments = db.get_comments(bskid, recid)
group_sharing_level = None
levels = db.is_shared_to(bskid)
if len(levels):
group_sharing_level = levels[0][1]
basket = db.get_basket_general_infos(bskid)
if not(len(basket)):
errors.append('ERR_WEBBASKET_DB_ERROR')
return (body, errors, warnings)
basket = basket[0]
item_html = webbasket_templates.tmpl_item(basket,
recid, record, comments,
group_sharing_level,
(__check_sufficient_rights(rights, cfg_webbasket_share_levels['READCMT']),
__check_sufficient_rights(rights, cfg_webbasket_share_levels['ADDCMT']),
__check_sufficient_rights(rights, cfg_webbasket_share_levels['DELCMT'])),
selected_category=category, selected_topic=topic, selected_group_id=group_id,
ln=ln)
body = webbasket_templates.tmpl_display(topicsbox=topicsbox, baskets=[item_html],
selected_category=category,
nb_groups=db.count_groups_user_member_of(uid),
nb_external_baskets=db.count_external_baskets(uid),
ln=ln)
return (body, errors, warnings)
def perform_request_write_comment(uid, bskid, recid, cmtid=0,
category=cfg_webbasket_categories['PRIVATE'],
topic=0, group_id=0,
ln=cdslang):
"""Display a comment writing form
@param uid: user id
@param bskid: basket id
@param recid: record id (comments are on a specific record in a specific basket)
@param cmtid: if provided this comment is a reply to comment cmtid.
@param category: selected category
@param topic: selected topic
@param group id: selected group id
@param ln: language
"""
body = ''
warnings = []
errors = []
cmt_body = ''
if not __check_user_can_comment(uid, bskid):
errors.append(('ERR_WEBBASKET_CANNOT_COMMENT'))
return (body, errors, warnings)
if cmtid:
# this is a reply to another comment
comment = db.get_comment(cmtid)
if comment:
cmt_body = webbasket_templates.tmpl_quote_comment(comment[2], # title
uid,
comment[0], # nickname
comment[4], # date
comment[3],
ln)
else:
warning = (cfg_webbasket_warning_messages['ERR_WEBBASKET_cmtid_INVALID'], cmtid)
warnings.append(warning)
record = db.get_basket_record(bskid, recid, 'hb')
body = webbasket_templates.tmpl_write_comment(bskid=bskid,
recid=recid,
cmt_body=cmt_body,
record = record,
selected_category=category,
selected_topic=topic,
selected_group_id=group_id,
warnings=warnings)
if category == cfg_webbasket_categories['PRIVATE']:
topics_list = db.get_personal_topics_infos(uid)
if not topic and len(topics_list):
topic = 0
topicsbox = webbasket_templates.tmpl_topic_selection(topics_list, topic, ln)
elif category == cfg_webbasket_categories['GROUP']:
groups = db.get_group_infos(uid)
if group_id == 0 and len(groups):
group_id = groups[0][0]
topicsbox = webbasket_templates.tmpl_group_selection(groups, group_id, ln)
else:
topicsbox = ''
body = webbasket_templates.tmpl_display(topicsbox, '', [ body ], category, ln)
return (body, errors, warnings)
def perform_request_save_comment(uid, bskid, recid, title='', text='', ln=cdslang):
""" Save a given comment if able to.
@param uid: user id (int)
@param bskid: basket id (int)
@param recid: record id (int)
@param title: title of comment (string)
@param text: comment's body (string)
@param ln: language (string)
@return (errors, infos) where errors: list of errors while saving
infos: list of informations to display"""
_ = gettext_set_language(ln)
errors = []
infos = []
if not __check_user_can_comment(uid, bskid):
errors.append(('ERR_WEBBASKET_CANNOT_COMMENT'))
return (errors, infos)
if not(db.save_comment(uid, bskid, recid, title, text)):
errors.append(('ERR_WEBBASKET_DB_ERROR'))
else:
infos.append(_('Your comment has been successfully posted'))
return (errors, infos)
def perform_request_delete_comment(uid, bskid, recid, cmtid):
"""Delete comment cmtid on record recid for basket bskid."""
errors = []
if __check_user_can_perform_action(uid, bskid, cfg_webbasket_share_levels['DELCMT']):
db.delete_comment(bskid, recid, cmtid)
else:
errors.append('ERR_WEBBASKET_NO_RIGHTS')
return errors
def perform_request_add(uid, recids=[], bskids=[], referer='',
new_basket_name='', new_topic_name='', create_in_topic='',
ln=cdslang):
"""Add records to baskets
@param uid: user id
@param recids: list of records to add
@param bskids: list of baskets to add records to. if not provided, will return a
page where user can select baskets
@param referer: URL of the referring page
@param new_basket_name: add record to new basket
@param new_topic_name: new basket goes into new topic
@param create_in_topic: # of topic to put basket into
@param ln: language
@return (body, errors, warnings) tuple
"""
body = ''
errors = []
warnings = []
if not(type(recids) == list):
recids = [recids]
if not(len(recids)):
warnings.append('WRN_WEBBASKET_NO_RECORD')
body += webbasket_templates.tmpl_warnings(warnings, ln)
if referer and not(referer.find(weburl) == -1):
body += webbasket_templates.tmpl_back_link(referer, ln)
return (body, errors, warnings)
if new_basket_name != '':
new_topic_name = new_topic_name.strip()
if new_topic_name:
topic = new_topic_name
elif create_in_topic != -1:
topics = map(lambda x: x[0], db.get_personal_topics_infos(uid))
try:
topic = topics[create_in_topic]
except IndexError:
topic = ''
if topic:
id_bsk = db.create_basket(uid, new_basket_name, topic)
bskids.append(id_bsk)
if len(bskids):
# save
nb_modified_baskets = db.add_to_basket(uid, recids, bskids)
body = webbasket_templates.tmpl_added_to_basket(nb_modified_baskets, ln)
body += webbasket_templates.tmpl_back_link(referer, ln)
else:
# Display basket_selection
personal_baskets = db.get_all_personal_baskets_names(uid)
group_baskets = db.get_all_group_baskets_names(uid)
external_baskets = db.get_all_external_baskets_names(uid)
topics = map(lambda x: x[0], db.get_personal_topics_infos(uid))
body = webbasket_templates.tmpl_add(recids=recids,
personal_baskets=personal_baskets,
group_baskets=group_baskets,
external_baskets=external_baskets,
topics=topics,
referer=referer,
ln=ln)
body += webbasket_templates.tmpl_back_link(referer, ln)
return (body, errors, warnings)
def perform_request_delete(uid, bskid, confirmed=0,
category=cfg_webbasket_categories['PRIVATE'],
selected_topic=0, selected_group_id=0,
ln=cdslang):
"""Delete a given basket.
@param uid: user id (user has to be owner of this basket)
@param bskid: basket id
@param confirmed: if 0 will return a confirmation page; if 1 will delete basket.
@param category: category currently displayed
@param selected_topic: topic currently displayed
@param selected_group id: if category is group, id of the group currently displayed
@param ln: language"""
body = ''
errors = []
warnings = []
if not(db.check_user_owns_baskets(uid, [bskid])):
errors.append(('ERR_WEBBASKET_NO_RIGHTS',))
return (body, errors, warnings)
if confirmed:
success = db.delete_basket(bskid)
if not success:
errors.append(('ERR_WEBBASKET_DB_ERROR',))
else:
body = webbasket_templates.tmpl_confirm_delete(bskid,
db.count_subscribers(uid, bskid),
category,
selected_topic, selected_group_id,
ln)
return (body, errors, warnings)
def delete_record(uid, bskid, recid):
"""Delete a given record in a given basket.
@param uid: user id (user has to have sufficient rights on basket
@param bskid: basket id
@param recid: record id
"""
if __check_user_can_perform_action(uid, bskid, cfg_webbasket_share_levels['DELITM']):
db.delete_item(bskid, recid)
def move_record(uid, bskid, recid, direction):
"""Move a record up or down in a basket (change score).
@param uid: user id (user has to have manage rights over this basket)
@param bskid: basket id
@param recid: record we want to move
@param direction: cfg_webbasket_actions['UP'] or cfg_webbasket_actions['DOWN']
"""
if __check_user_can_perform_action(uid, bskid, cfg_webbasket_share_levels['MANAGE']):
db.move_item(bskid, recid, direction)
def perform_request_edit(uid, bskid, topic=0, new_name='',
new_topic = '', new_topic_name='',
groups=[], external='',
ln=cdslang):
"""Interface for management of basket. If names, groups or external is provided,
will save new rights into database, else will provide interface.
@param uid: user id (user has to have sufficient rights on this basket
@param bskid: basket id to change rights on
@param topic: topic currently used (int)
@param new_name: new name of basket
@param new_topic: topic in which to move basket (int), new_topic_name must be left blank
@param new_topic_name: new topic in which to move basket (will overwrite param new_topic)
@param groups: list of strings formed in this way: group_id + '_' + rights
@param external: rights for everybody (can be 'NO')
@param ln: language
"""
body = ''
errors = []
warnings = []
rights = db.get_max_user_rights_on_basket(uid, bskid)
if rights != cfg_webbasket_share_levels['MANAGE']:
errors.append(('ERR_WEBBASKET_NO_RIGHTS',))
return (body, errors, warnings)
bsk_name = db.get_basket_name(bskid)
if not(groups) and not(external) and not(new_name) and not(new_topic) and not(new_topic_name):
# display interface
topics = map(lambda x: x[0], db.get_personal_topics_infos(uid))
groups_rights = db.get_groups_subscribing_to_basket(bskid)
external_rights = ''
if groups_rights and groups_rights[0][0] == 0:
external_rights = groups_rights[0][2]
groups_rights = groups_rights[1:]
display_delete = db.check_user_owns_baskets(uid, bskid)
display_general = display_delete
if isGuestUser(uid):
display_sharing = 0
else:
display_sharing = 1
body = webbasket_templates.tmpl_edit(bskid=bskid, bsk_name=bsk_name,
display_general=display_general, topics=topics, topic=topic,
display_delete=display_delete, display_sharing=display_sharing,
groups_rights=groups_rights, external_rights=external_rights,
ln=ln)
else:
out_groups = {}
if len(groups):
for group in groups:
(group_id, group_rights) = group.split('_')
out_groups[group_id] = group_rights
out_groups['0'] = external
if not(isGuestUser(uid)):
db.update_rights(bskid, out_groups)
if new_name != bsk_name:
db.rename_basket(bskid, new_name)
if new_topic_name:
db.move_baskets_to_topic(uid, bskid, new_topic_name)
elif new_topic != -1:
if db.check_user_owns_baskets(uid, bskid):
topics = map(lambda x: x[0], db.get_personal_topics_infos(uid))
try:
new_topic_name = topics[new_topic]
db.move_baskets_to_topic(uid, bskid, new_topic_name)
except:
errors.append(('ERR_WEBBASKET_DB_ERROR'))
else:
topic = 0
errors.append(('ERR_WEBBASKET_NOT_OWNER'))
return (body, errors, warnings)
def perform_request_add_group(uid, bskid, topic=0, group_id=0, ln=cdslang):
"""If group id is specified, share basket bskid to this group with READITM rights;
else return a page for selection of a group.
@param uid: user id (selection only of groups user is member of)
@param bskid: basket id
@param topic: topic currently displayed
@param group_id: id of group to share basket to
@param ln: language
"""
if group_id:
db.share_basket_with_group(bskid, group_id, cfg_webbasket_share_levels['READITM'])
else:
groups = db.get_groups_user_member_of(uid)
body = webbasket_templates.tmpl_add_group(bskid, topic, groups, ln)
return body
def perform_request_create_basket(uid,
new_basket_name='',
new_topic_name='', create_in_topic=-1, topic_number=-1,
ln=cdslang):
"""if new_basket_name and topic infos are given create a basket and return topic number,
else return (body, errors, warnings) tuple of basket creation form.
@param uid: user id (int)
@param new_basket_name: name of the basket to create (str)
@param new_topic_name: name of new topic to create new basket in (str)
@param create_in_topic: identification number of topic to create new basket in (int)
@param topic_number: number of topic to preselect on the creation form.
@pram ln: language
"""
if new_basket_name and (new_topic_name or create_in_topic != -1):
- topics = map(lambda x: x[0], db.get_personal_topics_infos(uid))
+ topics_infos = db.get_personal_topics_infos(uid)
new_topic_name = new_topic_name.strip()
if new_topic_name:
topic = new_topic_name
else:
try:
topic = topics_infos[create_in_topic]
except IndexError:
return 0
db.create_basket(uid, new_basket_name, topic)
- topics = map(lambda x: x[0], db.get_personal_topics_infos(uid))
+ topics = map(lambda x: x[0], topics_infos)
try:
return topics.index(topic)
except ValueError:
return 0
else:
topics = map(lambda x: x[0], db.get_personal_topics_infos(uid))
if topic_number in range (0, len(topics)):
create_in_topic = topics[topic_number]
body = webbasket_templates.tmpl_create_basket(new_basket_name,
new_topic_name, create_in_topic,
topics,
ln)
return (body, [], [])
def perform_request_display_public(bskid=0, of='hb', ln=cdslang):
"""return html representation of a public basket
@param bskid: basket id
@param of: format
@param ln: language"""
_ = gettext_set_language(ln)
body = ''
errors = []
warnings = []
basket = db.get_public_basket_infos(bskid)
if of[0]=='x':
items = []
if len(basket) == 7:
content = db.get_basket_content(bskid)
for item in content:
items.append(print_record(item[0], of))
return webbasket_templates.tmpl_xml_basket(items)
if len(basket) == 7:
items = db.get_basket_content(bskid)
last_cmt = _("N/A")
records = []
cmt_dates = []
for (recid, nb_cmt, last_cmt, ext_val, int_val, score) in items:
cmt_dates.append(convert_datetext_to_datestruct(last_cmt))
last_cmt = convert_datetext_to_dategui(last_cmt, ln)
val = ''
if recid < 0:
if ext_val:
val = decompress(ext_val)
else:
if int_val:
val = print_record(recid)
records.append((recid, nb_cmt, last_cmt, val, score))
body = webbasket_templates.tmpl_display_public(basket, records, ln)
else:
errors.append('ERR_WEBBASKET_RESTRICTED_ACCESS')
return (body, errors, warnings)
def perform_request_list_public_baskets(inf_limit=0, order=1, asc=1, ln=cdslang):
"""Display list of public baskets.
@param inf_limit: display baskets from inf_limit
@param order: 1: order by name of basket, 2: number of views, 3: owner
@param asc: ascending order if 1, descending if 0
@param ln: language
"""
errors = []
warnings = []
total_baskets = db.count_public_baskets()
baskets = db.get_public_baskets_list(inf_limit, cfg_webbasket_max_number_of_displayed_baskets, order, asc)
body = webbasket_templates.tmpl_display_list_public_baskets(baskets, inf_limit, total_baskets, order, asc, ln)
return (body, errors, warnings)
def perform_request_subscribe(uid, bskid):
"""subscribe to external basket bskid"""
errors = []
if db.is_public(bskid):
db.subscribe(uid, bskid)
else:
errors.append('ERR_WEBBASKET_RESTRICTED_ACCESS')
return errors
def perform_request_unsubscribe(uid, bskid):
"""unsubscribe from external basket bskid"""
db.unsubscribe(uid, bskid)
def __check_user_can_comment(uid, bskid):
""" Private function. check if a user can comment """
min_right = cfg_webbasket_share_levels['ADDCMT']
rights = db.get_max_user_rights_on_basket(uid, bskid)
if rights:
if cfg_webbasket_share_levels_ordered.index(rights) >= cfg_webbasket_share_levels_ordered.index(min_right):
return 1
return 0
def __check_user_can_perform_action(uid, bskid, rights):
""" Private function, check if a user has sufficient rights"""
min_right = rights
rights = db.get_max_user_rights_on_basket(uid, bskid)
if rights:
if cfg_webbasket_share_levels_ordered.index(rights) >= cfg_webbasket_share_levels_ordered.index(min_right):
return 1
return 0
def __check_sufficient_rights(rights_user_has, rights_needed):
"""Private function, check if the rights are sufficient."""
try:
out = cfg_webbasket_share_levels_ordered.index(rights_user_has) >= cfg_webbasket_share_levels_ordered.index(rights_needed)
except ValueError:
out = 0
return out
def create_guest_warning_box(ln=cdslang):
"""return a warning message about logging into system"""
return webbasket_templates.tmpl_create_guest_warning_box(ln)
def create_personal_baskets_selection_box(uid,
html_select_box_name='baskets',
selected_bskid=None,
ln=cdslang):
"""Return HTML box for basket selection. Only for personal baskets.
@param uid: user id
@param html_select_box_name: name used in html form
@param selected_bskid: basket currently selected
@param ln: language
"""
baskets = db.get_all_personal_baskets_names(uid)
return webbasket_templates.tmpl_personal_baskets_selection_box(baskets,
html_select_box_name,
selected_bskid,
ln)
def create_basket_navtrail(uid,
category=cfg_webbasket_categories['PRIVATE'], topic=0, group=0,
bskid=0, ln=cdslang):
"""display navtrail for basket navigation.
@param uid: user id (int)
@param category: selected category (see cfg_webbasket_categories)
@param topic: selected topic # if personal baskets
@param group: selected group id for displaying (int)
@param bskid: basket id (int)
@param ln: language"""
_ = gettext_set_language(ln)
out = ''
if category == cfg_webbasket_categories['PRIVATE']:
out += ' > %s'
out %= (weburl, 'category=' + category + '&ln=' + ln, _("Personal baskets"))
topics = map(lambda x: x[0], db.get_personal_topics_infos(uid))
if topic in range(0, len(topics)):
out += ' > '
out += '%s'
out %= (weburl,
'category=' + category + '&topic=' + str(topic) + '&ln=' + ln,
topics[topic])
if bskid:
basket = db.get_public_basket_infos(bskid)
if basket:
out += ' > '
out += '%s'
out %= (weburl,
'category=' + category + '&topic=' + str(topic) + \
'&ln=' + ln + '#bsk' + str(bskid),
basket[1])
elif category == cfg_webbasket_categories['GROUP']:
out += ' > %s'
out %= (weburl, 'category=' + category + '&ln=' + ln, _("Group baskets"))
groups = db.get_group_infos(uid)
if group:
groups = filter(lambda x: x[0]==group, groups)
if len(groups):
out += ' > '
out += '%s'
out %= (weburl,
'category=' + category + '&group=' + str(group) + '&ln=' + ln,
groups[0][1])
if bskid:
basket = db.get_public_basket_infos(bskid)
if basket:
out += ' > '
out += '%s'
out %= (weburl,
'category=' + category + '&group=' + str(group) + \
'&ln=' + ln + '#bsk' + str(bskid),
basket[1])
elif category == cfg_webbasket_categories['EXTERNAL']:
out += ' > %s'
out %= (weburl, 'category=' + category + '&ln=' + ln, _("Others' baskets"))
if bskid:
basket = db.get_public_basket_infos(bskid)
if basket:
out += ' > '
out += '%s'
out %= (weburl,
'category=' + category + '&ln=' + ln + '#bsk' + str(bskid),
basket[1])
return out
def create_infobox(infos=[]):
"""Create an infos box. infos param should be a list of strings. Return formatted infos"""
return webbasket_templates.tmpl_create_infobox(infos)
def account_list_baskets(uid, ln=cdslang):
"""Display baskets informations on account page"""
_ = gettext_set_language(ln)
(personal, group, external) = db.count_baskets(uid)
link = '%s'
base_url = weburl + '/yourbaskets/display?category=%s&ln=' + ln
personal_text = personal
if personal:
url = base_url % cfg_webbasket_categories['PRIVATE']
personal_text = link % (url, personal_text)
group_text = group
if group:
url = base_url % cfg_webbasket_categories['GROUP']
group_text = link % (url, group_text)
external_text = external
if external:
url = base_url % cfg_webbasket_categories['EXTERNAL']
else:
url = weburl + '/yourbaskets/list_public_baskets?ln=' + ln
external_text = link % (url, external_text)
- out = _("You have %s personal baskets and are subscribed to %s group baskets and %s other users public baskets.")
- out %= (personal_text, group_text, external_text)
+ out = _("You have %(x_nb_perso)s personal baskets and are subscribed to %(x_nb_group)s group baskets and %(x_nb_public)s other users public baskets.") %\
+ {'x_nb_perso': personal_text,
+ 'x_nb_group': group_text,
+ 'x_nb_public': external_text}
return out
diff --git a/modules/webbasket/lib/webbasket_templates.py b/modules/webbasket/lib/webbasket_templates.py
index 6613c5ab9..214f03f4b 100644
--- a/modules/webbasket/lib/webbasket_templates.py
+++ b/modules/webbasket/lib/webbasket_templates.py
@@ -1,1509 +1,1488 @@
## $Id$
## This file is part of CDS Invenio.
## Copyright (C) 2002, 2003, 2004, 2005, 2006 CERN.
##
## CDS Invenio is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License as
## published by the Free Software Foundation; either version 2 of the
## License, or (at your option) any later version.
##
## CDS Invenio is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
from invenio.messages import gettext_set_language
from invenio.webbasket_config import cfg_webbasket_categories, \
cfg_webbasket_share_levels, \
cfg_webbasket_max_number_of_displayed_baskets
from invenio.webmessage_mailutils import email_quoted_txt2html, email_quote_txt
from invenio.config import weburl, sweburl, cdslang
from invenio.textutils import indent_text
from invenio.webuser import get_user_info
from invenio.dateutils import convert_datetext_to_dategui
class Template:
######################## General interface ###############################
def tmpl_display(self,
topicsbox='',
baskets_infobox='',
baskets=[],
selected_category=cfg_webbasket_categories['PRIVATE'],
nb_groups=0,
nb_external_baskets=0,
ln=cdslang):
"""Generic display. takes already formatted baskets (list of formatted baskets), infobox and topicsbox,
add tabs and returns complete interface"""
_ = gettext_set_language(ln)
if type(baskets) not in (list, tuple):
baskets = [baskets]
tabs = self.__create_tabs(selected_category, nb_groups, nb_external_baskets, ln)
out = """
%s
""" % indent_text(tabs, 2)
if topicsbox:
out += indent_text(topicsbox, 6)
out += """
"""
if baskets_infobox:
out += """
%s
""" % indent_text(baskets_infobox, 5)
for basket in baskets:
out += basket
out += """
"""
out = tab % {'selected': selected_category == private and selected or '',
'url': weburl,
'img': 'webbasket_us.png',
'label': _("Personal baskets"),
'cat': private,
'ln': ln}
if nb_groups:
out += tab % {'selected': selected_category == group and selected or '',
'url': weburl,
'img': 'webbasket_ugs.png',
'label': _("Group baskets"),
'cat': group,
'ln': ln}
if nb_external_baskets:
out += tab % {'selected': selected_category == external and selected or '',
'url': weburl,
'img': 'webbasket_ws.png',
'label': _("Others' baskets"),
'cat': external,
'ln': ln}
return out
def tmpl_topic_selection(self,
topics_list=[],
selected_topic=0,
ln=cdslang):
"""Display the topics selection area.
@param topics_list: list of (topic name, number of baskets) tuples
@param selected_topic: # of selected topic in topics_list"""
category = cfg_webbasket_categories['PRIVATE']
if len(topics_list):
selected_topic = selected_topic <= len(topics_list) and selected_topic or 0
i = 0
out = ''
for (topic, number_of_baskets) in topics_list:
out += ''
topic_label = topic + ' (' + str(number_of_baskets) + ')'
if i != selected_topic:
topic_link = '%s/yourbaskets/display?category=%s&topic=%i&ln=%s'
topic_link %= (weburl, category, i, ln)
out += '' % topic_link
out += topic_label + ''
else:
out += topic_label
out += ' '
i += 1
out = """
%s
""" % out
else:
out = self.tmpl_create_basket(ln=ln)
return out
def tmpl_group_selection(self,
groups_list=[],
selected_group_id=0,
ln=cdslang):
"""Display the group selection area which appears on the top of group baskets category.
@param groups_list: list of (group id, group name, number of baskets) tuples
@param selected_group id: id of group selected"""
out = ''
category = cfg_webbasket_categories['GROUP']
if len(groups_list):
for (group_id, group_name, number_of_baskets) in groups_list:
out += ''
group_label = group_name + ' (' + str(number_of_baskets) + ')'
if group_id != selected_group_id:
group_link = '%s/yourbaskets/display?category=%s&group=%i&ln=%s'
group_link %= (weburl, category, group_id, ln)
out += '' % group_link
out += group_label + ''
else:
out += group_label
out += ''
out = """
%s
""" % out
return out
def tmpl_baskets_infobox(self, basket_infos=[], create_link='', ln=cdslang):
"""
displays infos about baskets.
@param basket_infos: list of (bskid, bsk_name, bsk_last_update) tuples
@param create_link: link for the creation of basket (will appear next to descriptions)
@param ln: language
@return html as string
"""
_ = gettext_set_language(ln)
label = _("There are %i baskets") % len(basket_infos)
basket_list = ''
if len(basket_infos):
basket_list += '
\n'
for (bskid, name, last_update) in basket_infos:
last_update = convert_datetext_to_dategui(last_update)
basket_list += '
'
if len(basket_infos) < 2:
label = ''
basket_list = ''
out = """
%s
%s
%s
""" % (label, basket_list, create_link)
return out
def tmpl_display_public(self,
(bskid, bsk_name,
bsk_date_modification,bsk_nb_views,
bskid_owner, bsk_owner_nickname, bsk_share_level),
bsk_items=[],
ln=cdslang):
"""
Display public basketwith link to subscribe to it.
@param bsk_share_level is not currently used.
"""
_ = gettext_set_language(ln)
items_html = ''
if not(len(bsk_items)):
items_html = """
%s
""" % _("Basket is empty")
for item in bsk_items:
items_html += self.__tmpl_basket_item(bskid=bskid, item=item, ln=ln)
if bsk_owner_nickname:
display = bsk_owner_nickname
else:
(bskid_owner, bsk_owner_nickname, display) = get_user_info(int(bskid_owner))
messaging_link = self.__create_messaging_link(bsk_owner_nickname, display, ln)
link_subscribe = '' % (weburl, bskid, ln)
- end_link_subscribe = ''
- general_label = _("This basket belongs to %s. You can freely %ssubscribe%s to it") % (messaging_link, link_subscribe, end_link_subscribe)
+ general_label = _("This basket belongs to %(x_name)s. You can freely %(x_url_open)ssubscribe%(x_url_close)s to it") % {'x_name': messaging_link,
+ 'x_url_open': link_subscribe,
+ 'x_url_close': ''}
out = """
%(general_label)s
""" % {'name': name_label,
'nb_views': nb_views_label,
'user': owner_label,
'actions': _("Actions"),
'baskets': baskets_html,
'footer': footer}
return out
############################ Baskets ###################################
def tmpl_basket(self, bskid,
name,
date_modification,
nb_views,
nb_items, last_added,
(user_can_view_content, user_can_edit_basket,
user_can_view_comments, user_can_add_item, user_can_delete_item),
nb_comments, last_comment,
group_sharing_level,
selected_category=cfg_webbasket_categories['PRIVATE'],
selected_topic=0, selected_group=0,
items=[],
ln=cdslang):
"""
display a basket.
@param group_sharing_level: Indicate to which level a basket is shared
(None for nobody, 0 for everybody, any other positive int for group)
@param items: list of (record id, nb of comments, last comment (date), body to display, score (int)) tuples
"""
_ = gettext_set_language(ln)
items_html = ''
actions = '
"
if user_can_view_content:
if not(len(items)):
items_html = """
%s
""" % _("Basket is empty")
for item in items:
copy = 1
up = down = delete = 0
if user_can_add_item:
up = down = 1
if item == items[0]:
up = 0
if item == items[-1]:
down = 0
if user_can_delete_item:
delete = 1
items_html += self.__tmpl_basket_item(bskid=bskid,
item=item,
uparrow=up,
downarrow=down,
copy_item=copy,
delete_item=delete,
view_comments=user_can_view_comments,
selected_category=selected_category,
selected_topic=selected_topic,
selected_group=selected_group,
ln=ln)
else:
items_html = """
%s
-
""" % _("You do not have sufficient rights to view this basket's content")
+""" % _("You do not have sufficient rights to view this basket's content.")
content = ''
if selected_category == cfg_webbasket_categories['EXTERNAL']:
url = "%s/yourbaskets/unsubscribe?bskid=%i&ln=%s" % (weburl, bskid, ln)
action = "%s"
action %= (url, _("Unsubscribe from this basket"))
content += action
footer = self.tmpl_basket_footer(bskid,
selected_category,
selected_topic,
selected_group,
group_sharing_level,
content,
ln)
comments_field = ''
if nb_comments:
comments_field = """
%i %s
%s %s""" % (nb_comments, _("comments"), _("last comment:"), last_comment)
out = """
%(content)s
"""
if view_comments:
if nb_cmt > 0:
out += """
%(nb_cmts)i %(cmts_label)s; %(last_cmt_label)s: %(last_cmt)s
"""
out += """
%(detailed_label)s
"""
out += """
"""
out = out % {'actions': actions,
'content': val,
'nb_cmts': nb_cmt,
'last_cmt': last_cmt,
'weburl': weburl,
'bskid': bskid,
'recid': recid,
'cmts_label': _("comments"),
'last_cmt_label': _("last"),
'detailed_label': _("Details and comments"),
'category': selected_category,
'topic': selected_topic,
'group': selected_group,
'ln': ln}
return out
def tmpl_basket_footer(self,
bskid,
selected_category=cfg_webbasket_categories['PRIVATE'],
selected_topic=0,
selected_group=0,
group_sharing_level=None,
content='',
ln=cdslang):
"""display footer of a basket.
@param group sharing level: None: basket is not shared,
0: basket is publcly accessible,
any positive int: basket is shared to groups"""
_ = gettext_set_language(ln)
public_infos = ''
if group_sharing_level == 0:
public_url = weburl + '/yourbaskets/display_public?bskid=' + str(bskid)
public_link = '%s' % (public_url, public_url)
public_infos = _("This basket is publicly accessible at the following address:") + public_link
if content:
content += ' '
if not(content) and not(public_infos):
content += ' '
out = """
%(content)s
%(public_infos)s
"""
out %= {'weburl': weburl,
'bskid': int(bskid),
'category': selected_category,
'topic': int(selected_topic),
'group_id': int(selected_group),
'ln': ln,
- 'sort_label': _("Sort by"),
+ 'sort_label': _("Sort by:"),
'title_label': _("Title"),
'date_label': _("Date"),
'content': content,
'public_infos': public_infos
}
return out
######################## Display of items and commenting ###################
def tmpl_item(self,
(bskid, bsk_name, bsk_date_modification, bsk_nb_views, bsk_nb_records, bsk_id_owner),
recid, record, comments,
group_sharing_level,
(user_can_view_comments, user_can_add_comment, user_can_delete_comment),
selected_category=cfg_webbasket_categories['PRIVATE'],
selected_topic=0, selected_group_id=0, ln=cdslang):
"""display a specific item inside a basket. first parameter is this a big tuple which defines a basket.
@param group sharing level: None: basket is not shared,
0: basket is publcly accessible,
any positive int: basket is shared to groups
@param comments: list of comments as string
"""
_ = gettext_set_language(ln)
total_comments = len(comments)
action = weburl + '/yourbaskets/write_comment?bskid=%i&recid=%i'
action += '&category=%s&topic=%i&group=%i&ln=%s'
action %= (bskid, recid, selected_category, selected_topic, selected_group_id, ln)
back_url = weburl + '/yourbaskets/display?category=%s&topic=%i&group=%i'
back_url %= (selected_category, selected_topic, selected_group_id)
def list_to_str(elt1, elt2):
"""return elt1 elt2"""
return elt1 + " \n" + elt2
if comments and user_can_view_comments:
comments = [self.__tmpl_display_comment(bskid, recid, comment,
(user_can_add_comment, user_can_delete_comment),
selected_category, selected_topic, selected_group_id,
ln)
for comment in comments]
comments = reduce(list_to_str, comments)
else:
comments = ''
record_text = ''
if record:
record_text = record[-1]
body = """
%(record)s
"""
if user_can_view_comments:
body += """
%(comments_label)s
%(total_label)s """
if user_can_add_comment:
body += """
"""
if user_can_view_comments:
body += """
%(comments)s"""
body %= {'record': record_text,
'comments_label': _("Comments"),
'total_label': _("There is a total of %i comments") % total_comments,
'action': action,
'button_label': _("Write a comment"),
'comments': comments}
if group_sharing_level == None:
img = '' % (weburl, _("Non-shared basket"))
elif group_sharing_level == 0:
img = '' % (weburl, _("Shared basket"))
else:
img = '' % (weburl, _("Group-shared basket"))
content = ''
if selected_category == cfg_webbasket_categories['EXTERNAL']:
url = "%s/yourbaskets/unsubscribe?bskid=%i&ln=%s" % (weburl, bskid, ln)
action = "%s"
action %= (url, _("Unsubscribe from this basket"))
content += action
footer = self.tmpl_basket_footer(bskid,
selected_category,
selected_topic,
selected_group_id,
group_sharing_level,
content,
ln)
out = """
%(body)s
"""
if user_can_add_comment:
out += """
%(reply_label)s"""
if user_can_delete_comment:
out += """
| %(delete_label)s"""
out += """
"""
out %= {'title': cmt_title,
'url': weburl,
'label_author': _("by"),
'label_date': _("on"),
'user': cmt_nickname or cmt_uid,
'user_display': cmt_nickname or get_user_info(cmt_uid)[2],
'date': convert_datetext_to_dategui(cmt_date),
'body': email_quoted_txt2html(cmt_body),
'bskid': bskid,
'recid': recid,
'cmtid': cmtid,
'category': selected_category,
'topic': selected_topic,
'group_id': selected_group_id,
'ln': ln,
'reply_label': _("Reply"),
'delete_label': _("Delete comment")}
return out
def tmpl_quote_comment(self, title, uid, nickname, date, body, ln=cdslang):
"""Return a comment in a quoted form (i.e. with '>' signs before each line)
@param title: title of comment to quote
@param uid: user id of user who posted comment to quote
@param nickname: nickname of user who posted comment to quote
@param date: date of post of comment to quote
@param body: body of comment to quote
@param ln: language"""
_ = gettext_set_language(ln)
if not(nickname):
nickname = get_user_info(uid)[2]
out = title + ', ' + _("by") + ' ' + nickname + ' ' + _("on") + ' ' + date + '\n' + body
return email_quote_txt(out)
def tmpl_write_comment(self, bskid, recid,
record,
cmt_body='',
selected_category=cfg_webbasket_categories['PRIVATE'],
selected_topic=0, selected_group_id=0,
ln=cdslang,
warnings=[]):
"""Display interface to write a comment.
@param bskid: basket id (int)
@param recid: record id (int)
@param record: text of the record (str)
@param selected_category: cfg_webbasket_categories
@param selected_topic: # of topic
@param selected_group_id: in case of category: group, id of selected group
@param ln: language
@param warnings: list of warnings"""
_ = gettext_set_language(ln)
- action = '%s/yourbaskets/save_comment?bskid=%i&recid=%i'
- action += '&category=%s&topic=%i&group=%i&ln=%s'
- action %= (weburl, bskid, recid,
- selected_category, selected_topic, selected_group_id, ln)
+ action = '%s/yourbaskets/save_comment?bskid=%i&recid=%i' % (weburl, bskid, recid)
+ action += '&category=%s&topic=%i&group=%i&ln=%s' % ( selected_category, selected_topic, selected_group_id, ln)
if warnings:
warnings_box = self.tmpl_warnings(warnings, ln)
else:
warnings_box = ''
out = """
%(warnings)s
%(record)s
%(write_label)s
%(title_label)s:
%(comment_label)s:
""" % {'warnings': warnings_box,
'record': record and record[-1] or '',
'write_label': _("Add Comment"),
'title_label': _("Title"),
'comment_label': _("Comment"),
'action': action,
'cmt_body': cmt_body,
'button_label': _("Add Comment")
}
return out
############################ Basket creation ###################################
def tmpl_create_basket_link(self, selected_topic=0, ln=cdslang):
""" Create link to basket creation """
_ = gettext_set_language(ln)
url = weburl + '/yourbaskets/create_basket?topic_number=%i&ln=%s'
url %= (selected_topic, ln)
image = '' % weburl
out = """
""" % (url, image, _("Create new basket"))
return out
def __tmpl_basket_box(self, img='', title=' ', subtitle=' ', body=''):
""" private function, display a basket/topic selection box """
out = """
%(label)s
%(count)s
%(basket_list)s
"""
out %= {'logo': img,
'label': title, 'count': subtitle,
'basket_list': body}
return out
def tmpl_create_box(self, new_basket_name='', new_topic_name='',
topics=[], selected_topic=None,
ln=cdslang):
"""Display a HTML box for creation of a new basket
@param new_basket_name: prefilled value (string)
@param new_topic_name: prefilled value (string)
@param topics: list of topics (list of strings)
@param selected_topic: preselected value for topic selection
@param ln: language"""
_ = gettext_set_language(ln)
topics_html = ''
if selected_topic:
try:
selected_topic = topics.index(selected_topic)
except:
selected_topic = None
if len(topics):
topics = zip(range(len(topics)), topics)
topics.insert(0, (-1, _("Select topic")))
topics_html = self.__create_select_menu('create_in_topic', topics, selected_topic)
create_html = """
%s
%s
%s
%s
""" % (_("Basket's name"), new_basket_name,
topics_html != '' and _("Choose topic") or '', topics_html,
topics_html != '' and _("or create a new one") or _("Create new topic"), new_topic_name)
return self.__tmpl_basket_box(img=weburl + '/img/webbasket_create.png',
title=_("Create a new basket"),
body=create_html)
def tmpl_create_basket(self, new_basket_name='',
new_topic_name='', create_in_topic=None, topics=[],
ln=cdslang):
"""Template for basket creation
@param new_basket_name: prefilled value (string)
@param new_topic_name: prefilled value (string)
@param topics: list of topics (list of strings)
@param create_in_topic: preselected value for topic selection
@param ln: language"""
_ = gettext_set_language(ln)
out = """
%(create_box)s
""" % {'action': weburl + '/yourbaskets/create_basket',
'ln': ln,
'create_box': self.tmpl_create_box(new_basket_name=new_basket_name,
new_topic_name=new_topic_name,
topics=topics,
selected_topic=create_in_topic,
ln=ln),
'label': _("Create new basket")}
return out
########################## functions on baskets #########################
def tmpl_add(self, recids,
personal_baskets,
group_baskets,
external_baskets,
topics,
referer, ln=cdslang):
""" returns HTML for the basket selection form when adding new records
@param recids: list of record ids
@param personal_baskets: list of (basket id, basket name, topic) tuples
@param group_baskets: list of (bskid, bsk_name, group_name) tuples
@param external_baskets: list of (bskid, bsk_name) tuples
@param topics: list of all the topics the user owns
@param referer: url from where this page has been reached
@param ln: language"""
_ = gettext_set_language(ln)
personal = ''
group = ''
external = ''
if personal_baskets:
topic_names = {}
map(topic_names.setdefault, [row[2] for row in personal_baskets])
topic_names = topic_names.keys()
topic_names.sort()
personal_html = ''
for topic_name in topic_names:
baskets = map(lambda x: (x[0], x[1]),
filter(lambda x: x[2]==topic_name,
personal_baskets))
baskets.insert(0, (-1, _("Select basket")))
personal_html += """
%s
%s
"""
personal_html %= (topic_name,
self.__create_select_menu('bskids', baskets))
personal = self.__tmpl_basket_box(weburl + '/img/webbasket_user.png',
_("Add to a personal basket"),
_("%i baskets") % len(personal_baskets),
personal_html)
if group_baskets:
group_names = {}
map(group_names.setdefault, [row[2] for row in group_baskets])
group_names = group_names.keys()
group_names.sort()
groups_html = ''
for group_name in group_names:
baskets = map(lambda x: (x[0], x[1]),
filter(lambda x: x[2]==group_name,
group_baskets))
baskets.insert(0, (-1, _("Select basket")))
groups_html += """
%s
%s
"""
groups_html %= (group_name,
self.__create_select_menu('bskids', baskets))
group = self.__tmpl_basket_box(weburl + '/img/webbasket_usergroup.png',
_("Add to a group-shared basket"),
_("%i baskets") % len(group_baskets),
groups_html)
if external_baskets:
external_html = """
"""
external = self.__tmpl_basket_box(weburl + '/img/webbasket_world.png',
_("Add to a public basket"),
_("%i baskets") % len(external_baskets),
external_html)
create = self.tmpl_create_box(topics=topics, ln=ln)
out_hidden_recids = ""
for recid in recids:
out_hidden_recids += """""" % recid
fields = filter(lambda x: x != '', [personal, group, external, create])
while (len(fields) != 4):
fields.append('')
out = """
%(label)s:
%(out_hidden_recids)s
%(field1)s
%(field2)s
%(field3)s
%(field4)s
""" % {'action': weburl + '/yourbaskets/add?ln=' + ln,
'referer': referer,
'out_hidden_recids': out_hidden_recids,
'label': _("Adding %i records to these baskets") % len(recids),
'field1': fields[0],
'field2': fields[1],
'field3': fields[2],
'field4': fields[3],
'submit_label': _("Add to baskets")}
return out
def tmpl_added_to_basket(self, nb_baskets_modified=0, ln=cdslang):
"""Display message for addition of records to baskets"""
_ = gettext_set_language(ln)
if nb_baskets_modified:
out = _("The selected records have been successfully added to %i baskets.")
out %= nb_baskets_modified
else:
out = _("No records were added to the selected baskets.")
return '
' + out + '
'
def tmpl_confirm_delete(self, bskid,
(nb_users, nb_groups, nb_alerts),
category=cfg_webbasket_categories['PRIVATE'],
selected_topic=0, selected_group_id=0,
ln=cdslang):
"""
display a confirm message
@param bskid: basket id
@param nb*: nb of users/groups/alerts linked to this basket
@param category: private, group or external baskets are selected
@param selected_topic: if private baskets, topic nb
@param selected_group_id: if group: group to display baskets of
@param ln: language
@return html output
"""
_ = gettext_set_language(ln)
message = _("Are you sure you want to delete this basket?")
if nb_users:
message += '
' + _("%i users are subscribed to this basket.")% nb_users + '
'
if nb_groups:
message += '
' + _("%i user groups are subscribed to this basket.")% nb_groups + '
'
if nb_alerts:
message += '
' + _("You have set %i alerts on this basket.")% nb_alerts + '
'
out = """
%(message)s
"""% {'message': message,
'bskid': bskid,
'url_ok': 'delete',
'url_cancel': 'display',
'category': category,
'topic': selected_topic,
'group': selected_group_id,
'ln':ln,
'yes_label': _("Yes"),
'no_label': _("Cancel")}
return out
def tmpl_edit(self, bskid, bsk_name, topic, topics, groups_rights, external_rights,
display_general=0, display_sharing=0, display_delete=0, ln=cdslang):
"""Display interface for rights management over the given basket
@param group_rights: list of (group id, name, rights) tuples
@param external_rights: rights as defined in cfg_webbasket_share_levels for public access.
@param display_general: display fields name and topic, used with personal baskets
@param display_sharing: display sharing possibilities
@param display_delete: display delete basket button
"""
_ = gettext_set_language(ln)
general_body = ''
if display_general:
general_body = """
""" % _("You are not a member of a group")
+""" % _("You are not a member of a group.")
groups_box = self.__tmpl_basket_box(img=weburl + '/img/webbasket_usergroup.png',
title=_("Add group"),
body=groups_body)
out = """
%(label)s
%(groups)s
""" % {'label': _('Sharing basket to a new group'),
'action': weburl + '/yourbaskets/edit',
'ln': ln,
'topic': selected_topic,
'bskid': bskid,
'groups': indent_text(groups_box, 4),
'cancel_label': _("Cancel"),
'submit_label': _("Add group")}
return out
def tmpl_personal_baskets_selection_box(self,
baskets=[],
select_box_name='baskets',
selected_bskid=None,
ln=cdslang):
"""return an HTML popupmenu
@param baskets: list of (bskid, bsk_name, bsk_topic) tuples
@param select_box_name: name that will be used for the control
@param selected_bskid: id of the selcte basket, use None for no selection
@param ln: language"""
_ = gettext_set_language(ln)
elements = [(0, '- ' + _("no basket") + ' -')]
for (bskid, bsk_name, bsk_topic) in baskets:
elements.append((bskid, bsk_topic + ' > ' + bsk_name))
return self.__create_select_menu(select_box_name, elements, selected_bskid)
def tmpl_create_guest_warning_box(self, ln=cdslang):
"""return html warning box for non registered users"""
_ = gettext_set_language(ln)
- message = _("You are logged in as a guest user, so your baskets will disappear at the end of the current session. If you wish you can %slogin or register here%s.")
- message %= (''% (sweburl, ln), '')
+ message = _("You are logged in as a guest user, so your baskets will disappear at the end of the current session.") + ' '
+ message += _("If you wish you can %(x_url_open)slogin or register here%(x_url_close)s.") %\
+ {'x_url_open': '',
+ 'X_url_close': ''}
out = """
%s
"""
return out % message
def tmpl_create_guest_forbidden_box(self, ln=cdslang):
"""return html warning box for non registered users"""
_ = gettext_set_language(ln)
- message = _("This functionality is forbidden to guest users. If you wish you can %slogin or register here%s.") % (''% (sweburl, ln),
- '')
+ message = _("This functionality is forbidden to guest users.") + ' '
+ message += _("If you wish you can %(x_url_open)slogin or register here%(x_url_close)s.") %\
+ {'x_url_open': '',
+ 'x_url_close': ''}
out = """
%s
"""
return out % message
############################ Utilities ###################################
def __create_select_menu(self, name, elements, selected_key=None):
""" private function, returns a popup menu
@param name: name of HTML control
@param elements: list of (key, value)
@param selected_key: item that should be selected (key of elements tuple)
"""
out = ''
return out
def tmpl_warnings(self, warnings=[], ln=cdslang):
""" returns HTML for warnings """
from invenio.errorlib import get_msgs_for_code_list
out = ''
if type(warnings) is not list:
warnings = [warnings]
if len(warnings):
warnings_parsed = get_msgs_for_code_list(warnings, 'warning', ln)
for (warning_code, warning_text) in warnings_parsed:
out += '
%s
' % warning_text
return out
def tmpl_create_infobox(self, infos = []):
""" returns html for general informations
@param infos: list of strings to display"""
out = ''
if len(infos):
out += '
'
for info in infos:
out += info + ' '
out += '
'
return out
def tmpl_back_link(self, link, ln=cdslang):
""" returns HTML for a link whose label should be
'Back to search results'
"""
_ = gettext_set_language(ln)
label = _("Back to search results")
out = '%s' % (link, label)
return out
def __create_messaging_link(self, to, display_name, ln=cdslang):
"""prints a link to the messaging system"""
link = "%s/yourmessages/write?msg_to=%s&ln=%s" % (weburl, to, ln)
if to:
return '%s' % (link, display_name)
else:
return display_name
def tmpl_xml_basket(self, items=[]):
"""Template for XML output of basket
@param items: XML version of each item (list)"""
items_xml = ''
for item in items:
items_xml += ' ' + item + '\n'
return """
%s
""" % items_xml
diff --git a/modules/webcomment/lib/webcomment.py b/modules/webcomment/lib/webcomment.py
index 2b767cf94..748f294ca 100644
--- a/modules/webcomment/lib/webcomment.py
+++ b/modules/webcomment/lib/webcomment.py
@@ -1,1000 +1,1000 @@
# -*- coding: utf-8 -*-
## $Id$
## This file is part of CDS Invenio.
## Copyright (C) 2002, 2003, 2004, 2005, 2006 CERN.
##
## CDS Invenio is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License as
## published by the Free Software Foundation; either version 2 of the
## License, or (at your option) any later version.
##
## CDS Invenio is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
""" Comments and reviews for records """
__lastupdated__ = """$Date$"""
# non CDS Invenio imports:
import time
import math
# CDS Invenio imports:
from invenio.dbquery import run_sql
from invenio.config import cdslang, \
alertengineemail,\
adminemail,\
weburl,\
cfg_webcomment_allow_reviews,\
cfg_webcomment_allow_comments,\
cfg_webcomment_admin_notification_level,\
cfg_webcomment_nb_reviews_in_detailed_view,\
cfg_webcomment_nb_reports_before_send_email_to_admin,\
cfg_webcomment_nb_comments_in_detailed_view,\
cfg_webcomment_timelimit_processing_comments_in_seconds,\
cfg_webcomment_timelimit_processing_reviews_in_seconds
from invenio.webmessage_mailutils import email_quote_txt
from invenio.webuser import get_user_info
from invenio.dateutils import convert_datetext_to_dategui, \
datetext_default, \
convert_datestruct_to_datetext
from invenio.messages import wash_language, gettext_set_language
from invenio.urlutils import wash_url_argument
from invenio.webuser import isGuestUser
from invenio.webcomment_config import cfg_webcomment_action_code
try:
import invenio.template
webcomment_templates = invenio.template.load('webcomment')
except:
pass
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_language(ln)
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
(valid, error_body) = check_recID_is_in_range(recID, warnings, ln)
if not(valid):
return (error_body, errors, warnings)
# Query the database and filter results
res = query_retrieve_comments_or_remarks(recID, display_order, display_since, reviews)
nb_res = len(res)
# checking 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
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',))
elif reported == 0:
warnings.append(('WRN_WEBCOMMENT_ALREADY_REPORTED',))
if cfg_webcomment_allow_reviews and reviews:
avg_score = calculate_avg_score(res)
if voted > 0:
warnings.append(('WRN_WEBCOMMENT_FEEDBACK_RECORDED',))
elif voted == 0:
warnings.append(('WRN_WEBCOMMENT_ALREADY_VOTED',))
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)
def perform_request_vote(cmt_id, client_ip_address, value, uid=-1):
"""
Vote positively or negatively for a comment/review
@param cmt_id: review id
@param value: +1 for voting positively
-1 for voting negatively
@return integer 1 if successful, integer 0 if not
"""
cmt_id = wash_url_argument(cmt_id, 'int')
client_ip_address = wash_url_argument(client_ip_address, 'str')
value = wash_url_argument(value, 'int')
uid = wash_url_argument(uid, 'int')
if cmt_id > 0 and value in [-1, 1] and check_user_can_vote(cmt_id, client_ip_address, uid):
action_date = convert_datestruct_to_datetext(time.localtime())
action_code = cfg_webcomment_action_code['VOTE']
query = """INSERT INTO cmtACTIONHISTORY
VALUES (%i, NULL ,%i, inet_aton('%s'), '%s', '%s')"""
query %= (cmt_id, uid, client_ip_address, action_date, action_code)
run_sql(query)
return query_record_useful_review(cmt_id, value)
else:
return 0
def check_user_can_comment(recID, client_ip_address, uid=-1):
""" Check if a user hasn't already commented within the last seconds
time limit: cfg_webcomment_timelimit_processing_comments_in_seconds
@param recID: record id
@param client_ip_address: IP => use: str(req.get_remote_host(apache.REMOTE_NOLOOKUP))
@param uid: user id, as given by invenio.webuser.getUid(req)
"""
recID = wash_url_argument(recID, 'int')
client_ip_address = wash_url_argument(client_ip_address, 'str')
uid = wash_url_argument(uid, 'int')
max_action_time = time.time() - cfg_webcomment_timelimit_processing_comments_in_seconds
max_action_time = convert_datestruct_to_datetext(time.localtime(max_action_time))
action_code = cfg_webcomment_action_code['ADD_COMMENT']
query = """SELECT id_bibrec
FROM cmtACTIONHISTORY
WHERE id_bibrec=%i AND
action_code='%s' AND
action_time>'%s'
""" % (recID, action_code, max_action_time)
if uid < 0:
query += " AND client_host=inet_aton('%s')" % client_ip_address
else:
query += " AND id_user=%i" % uid
res = run_sql(query)
return len(res) == 0
def check_user_can_review(recID, client_ip_address, uid=-1):
""" Check if a user hasn't already reviewed within the last seconds
time limit: cfg_webcomment_timelimit_processing_reviewss_in_seconds
@param cmt_id: comment id
@param client_ip_address: IP => use: str(req.get_remote_host(apache.REMOTE_NOLOOKUP))
@param uid: user id, as given by invenio.webuser.getUid(req)
"""
action_code = cfg_webcomment_action_code['ADD_REVIEW']
query = """SELECT id_bibrec
FROM cmtACTIONHISTORY
WHERE id_bibrec=%i AND
action_code='%s'
""" % (recID, action_code)
if uid < 0:
query += " AND client_host=inet_aton('%s')" % client_ip_address
else:
query += " AND id_user=%i" % uid
res = run_sql(query)
return len(res) == 0
def check_user_can_vote(cmt_id, client_ip_address, uid=-1):
""" Checks if a user hasn't already voted
@param cmt_id: comment id
@param client_ip_address: IP => use: str(req.get_remote_host(apache.REMOTE_NOLOOKUP))
@param uid: user id, as given by invenio.webuser.getUid(req)
"""
cmt_id = wash_url_argument(cmt_id, 'int')
client_ip_address = wash_url_argument(client_ip_address, 'str')
uid = wash_url_argument(uid, 'int')
query = """SELECT id_cmtRECORDCOMMENT
FROM cmtACTIONHISTORY
WHERE id_cmtRECORDCOMMENT=%i""" % cmt_id
if uid < 0:
query += " AND client_host=inet_aton('%s')" % client_ip_address
else:
query += " AND id_user=%i" % uid
res = run_sql(query)
return (len(res) == 0)
def perform_request_report(cmt_id, client_ip_address, uid=-1):
"""
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 cmt_id: comment id
@return integer 1 if successful, integer 0 if not
"""
cmt_id = wash_url_argument(cmt_id, 'int')
if cmt_id <= 0:
return 0
(query_res, nb_abuse_reports) = query_record_report_this(cmt_id)
if query_res == 0:
return 0
if not(check_user_can_report(cmt_id, client_ip_address, uid)):
return 0
action_date = convert_datestruct_to_datetext(time.localtime())
action_code = cfg_webcomment_action_code['REPORT_ABUSE']
query = """INSERT INTO cmtACTIONHISTORY
VALUES (%i, NULL, %i, inet_aton('%s'), '%s', '%s')"""
query %= (cmt_id, uid, client_ip_address, action_date, action_code)
run_sql(query)
if nb_abuse_reports % cfg_webcomment_nb_reports_before_send_email_to_admin == 0:
(cmt_id2,
id_bibrec,
id_user,
cmt_body,
cmt_date,
cmt_star,
cmt_vote, cmt_nb_votes_total,
cmt_title,
cmt_reported) = query_get_comment(cmt_id)
(user_nb_abuse_reports,
user_votes,
user_nb_votes_total) = 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
subject = "An error report has been sent from a user"
body = '''
The following comment has been reported a total of %(cmt_reported)s times.
Author: nickname = %(nickname)s
email = %(user_email)s
user_id = %(uid)s
This user has:
total number of reports = %(user_nb_abuse_reports)s
%(votes)s
Comment: comment_id = %(cmt_id)s
record_id = %(id_bibrec)s
date written = %(cmt_date)s
nb reports = %(cmt_reported)s
%(review_stuff)s
body =
---start body---
%(cmt_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_abuse_reports' : user_nb_abuse_reports,
'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_total - user_votes)) or "\n",
'cmt_id' : cmt_id,
'id_bibrec' : id_bibrec,
'cmt_date' : cmt_date,
'cmt_reported' : cmt_reported,
'review_stuff' : cfg_webcomment_allow_reviews and \
"star score\t\t= %s\n\t\t\treview title\t\t= %s" % (cmt_star, cmt_title) or "",
'cmt_body' : cmt_body,
'comment_admin_link' : "http://%s/admin/webcomment/" % weburl,
'user_admin_link' : "user_admin_link" #! FIXME
}
#FIXME to be added to email when websession module is over:
#If you wish to ban the user, you can do so via the User Admin Panel %(user_admin_link)s.
from invenio.alert_engine import send_email, forge_email
body = forge_email(from_addr, to_addr, subject, body)
send_email(from_addr, to_addr, body)
return 1
def check_user_can_report(cmt_id, client_ip_address, uid=-1):
""" Checks if a user hasn't already reported a comment
@param cmt_id: comment id
@param client_ip_address: IP => use: str(req.get_remote_host(apache.REMOTE_NOLOOKUP))
@param uid: user id, as given by invenio.webuser.getUid(req)
"""
cmt_id = wash_url_argument(cmt_id, 'int')
client_ip_address = wash_url_argument(client_ip_address, 'str')
uid = wash_url_argument(uid, 'int')
query = """SELECT id_cmtRECORDCOMMENT
FROM cmtACTIONHISTORY
WHERE id_cmtRECORDCOMMENT=%i""" % cmt_id
if uid < 0:
query += " AND client_host=inet_aton('%s')" % client_ip_address
else:
query += " AND id_user=%i" % uid
res = run_sql(query)
return (len(res) == 0)
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 nickname, email,
DATE_FORMAT(last_login, '%%Y-%%m-%%d %%H:%%i:%%s')
FROM user WHERE id=%s"""
params1 = (uid,)
res1 = run_sql(query1, params1)
if res1:
return res1[0]
else:
return ()
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_nb_votes_yes, total_nb_votes_total)
if none found return ()
"""
query1 = """SELECT nb_votes_yes,
nb_votes_total,
nb_abuse_reports
FROM cmtRECORDCOMMENT
WHERE id_user=%s"""
params1 = (uid,)
res1 = run_sql(query1, params1)
if len(res1) == 0:
return ()
nb_votes_yes = nb_votes_total = nb_abuse_reports = 0
for cmt_tuple in res1:
nb_votes_yes += int(cmt_tuple[0])
nb_votes_total += int(cmt_tuple[1])
nb_abuse_reports += int(cmt_tuple[2])
return (nb_abuse_reports, nb_votes_yes, nb_votes_total)
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, nb_votes_yes, nb_votes_total, title, nb_abuse_reports)
if none found return ()
"""
query1 = """SELECT id,
id_bibrec,
id_user,
body,
DATE_FORMAT(date_creation, '%%Y-%%m-%%d %%H:%%i:%%s'),
star_score,
nb_votes_yes,
nb_votes_total,
title,
nb_abuse_reports
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_abuse_reports
query1 = "SELECT nb_abuse_reports FROM cmtRECORDCOMMENT WHERE id=%s"
params1 = (comID,)
res1 = run_sql(query1, params1)
if len(res1)==0:
return ()
#increment and update
nb_abuse_reports = int(res1[0][0]) + 1
query2 = "UPDATE cmtRECORDCOMMENT SET nb_abuse_reports=%s WHERE id=%s"
params2 = (nb_abuse_reports, comID)
res2 = run_sql(query2, params2)
return (int(res2), nb_abuse_reports)
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_total, nb_votes_yes 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
nb_votes_yes = int(res1[0][1])
if value >= 1:
nb_votes_yes = int(res1[0][1]) + 1
nb_votes_total = int(res1[0][0]) + 1
query2 = "UPDATE cmtRECORDCOMMENT SET nb_votes_total=%s, nb_votes_yes=%s WHERE id=%s"
params2 = (nb_votes_total, nb_votes_yes, comID)
res2 = run_sql(query2, params2)
return int(res2)
def query_retrieve_comments_or_remarks (recID, 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, nb_votes_yes, nb_votes_total, star_score, title, id)
Note: for the moment, if no nickname, will return email address up to '@'
"""
display_since = calculate_start_date(display_since)
order_dict = { 'hh' : "cmt.nb_votes_yes/(cmt.nb_votes_total+1) DESC, cmt.date_creation DESC ",
'lh' : "cmt.nb_votes_yes/(cmt.nb_votes_total+1) ASC, cmt.date_creation ASC ",
'ls' : "cmt.star_score ASC, cmt.date_creation DESC ",
'hs' : "cmt.star_score DESC, cmt.date_creation DESC ",
'od' : "cmt.date_creation ASC ",
'nd' : "cmt.date_creation DESC "
}
# Ranking only done for comments and when allowed
if ranking and recID > 0:
try:
display_order = order_dict[display_order]
except:
display_order = order_dict['od']
else:
# in case of recID > 0 => external record => no ranking!
ranking = 0
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 user.nickname,
cmt.id_user,
DATE_FORMAT(cmt.date_creation, '%%Y-%%m-%%d %%H:%%i:%%s'),
cmt.body,
%(ranking)s cmt.id
FROM %(table)s cmt LEFT JOIN user ON
user.id=cmt.id_user
WHERE %(id_bibrec)s=%(recID)i
%(ranking_only)s
%(display_since)s
ORDER BY %(display_order)s"""
params = { 'ranking' : ranking and ' cmt.nb_votes_yes, cmt.nb_votes_total, cmt.star_score, cmt.title, ' or '',
'ranking_only' : ranking and ' AND cmt.star_score>0 ' or ' AND cmt.star_score=0 ',
'id_bibrec' : recID > 0 and 'cmt.id_bibrec' or 'cmt.id_bibrec_or_bskEXTREC',
'table' : recID > 0 and 'cmtRECORDCOMMENT' or 'bskRECORDCOMMENT',
'recID' : recID,
'display_since' : display_since=='0000-00-00 00:00:00' and ' ' or 'AND cmt.date_creation>=\'%s\' ' % display_since,
'display_order' : display_order
}
res = run_sql(query % params)
if res:
return res
return ()
def query_add_comment_or_remark(reviews=0, recID=0, uid=-1, msg="", note="", score=0, priority=0, client_ip_address=''):
"""
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')
#change utf-8 message into general unicode
msg = msg.decode('utf-8')
note = note.decode('utf-8')
#change general unicode back to utf-8
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_total,
title)
VALUES (%s, %s, %s, %s, %s, %s, %s)"""
params = (recID, uid, msg, current_date, score, 0, note)
res = run_sql(query, params)
if res:
action_code = cfg_webcomment_action_code[reviews and 'ADD_REVIEW' or 'ADD_COMMENT']
action_time = convert_datestruct_to_datetext(time.localtime())
query2 = """INSERT INTO cmtACTIONHISTORY
values ('', %i, %i, inet_aton('%s'), '%s', '%s')"""
params2 = (recID, uid, client_ip_address, action_time, action_code)
run_sql(query2%params2)
return int(res)
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 datetext_default
datetext_default is defined in miscutils/lib/dateutils and
equals 0000-00-00 00:00:00 => MySQL format
If bad arguement given, will return datetext_default
"""
# 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 datetext_default
try:
nb = int(display_since[0])
except:
return datetext_default
if str(display_since[1]) in time_types:
time_type = str(display_since[1])
else:
return datetext_default
## calculate date
# initialize the coef
if time_type == 'w':
time_types[time_type] = 7
else:
time_types[time_type] = 1
start_time = time.localtime()
start_time = (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 convert_datestruct_to_datetext(start_time)
def get_first_comments_or_remarks(recID=-1,
ln=cdslang,
nb_comments='all',
nb_reviews='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: #comment or review. NB: suppressed reference to basket (handled in webbasket)
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_reviews) is int and nb_reviews < len(res_reviews):
first_res_reviews = res_reviews[:nb_reviews]
else:
if nb_res_reviews > cfg_webcomment_nb_reviews_in_detailed_view:
first_res_reviews = res_reviews[:cfg_webcomment_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_comments) is int and nb_comments < len(res_comments):
first_res_comments = res_comments[:nb_comments]
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_star_score = 6
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=0,
uid=-1,
action='DISPLAY',
ln=cdslang,
msg=None,
score=None,
note=None,
priority=None,
reviews=0,
comID=-1,
client_ip_address=None):
"""
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 (int)
@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']
_ = gettext_set_language(ln)
## check arguments
check_recID_is_in_range(recID, warnings, ln)
if uid <= 0:
errors.append(('ERR_WEBCOMMENT_UID_INVALID', uid))
return ('', errors, warnings)
user_contact_info = query_get_user_contact_info(uid)
nickname = ''
if user_contact_info:
if user_contact_info[0]:
nickname = user_contact_info[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 = get_user_info(comment[2])
if user_info:
date_creation = convert_datetext_to_dategui(str(comment[4]))
- msg = _("%s wrote on %s:")% (user_info[2], date_creation)
+ msg = _("%(x_name)s wrote on %(x_date)s:")% {'x_name': user_info[2], 'x_date': date_creation}
msg += "\n\n" + comment[3]
msg = email_quote_txt(text=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:
if reviews:
if check_user_can_review(recID, client_ip_address, uid):
success = query_add_comment_or_remark(reviews, recID=recID, uid=uid, msg=msg,
note=note, score=score, priority=0,
client_ip_address=client_ip_address)
else:
warnings.append('WRN_WEBCOMMENT_CANNOT_REVIEW_TWICE')
success = 1
else:
if check_user_can_comment(recID, client_ip_address, uid):
success = query_add_comment_or_remark(reviews, recID=recID, uid=uid, msg=msg,
note=note, score=score, priority=0,
client_ip_address=client_ip_address)
else:
warnings.append('WRN_WEBCOMMENT_TIMELIMIT')
success = 1
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, warnings), 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)
return ('', 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, nb_votes_yes, nb_votes_total,
title,
nb_abuse_reports) = 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 invenio.search_engine import print_record
record = print_record(recID=id_bibrec, format='hs')
review_stuff = '''
Star score = %s
Title = %s''' % (star_score, title)
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_review_caps)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_caps': 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 Invenio WebComment <%s>' % alertengineemail
to_addr = adminemail
subject = "A new comment/review has just been posted"
from invenio.alert_engine import send_email, forge_email
out = forge_email(from_addr, to_addr, subject, out)
send_email(from_addr, to_addr, out)
def check_recID_is_in_range(recID, warnings=[], ln=cdslang):
"""
Check that recID is >= 0
Append error messages to errors listi
@param recID: record id
@param warnings: the warnings list of the calling function
@return tuple (boolean, html) where boolean (1=true, 0=false)
and html is the body of the page to display if there was a problem
"""
# Make errors into a list if needed
if type(warnings) is not list:
errors = [warnings]
try:
recID = int(recID)
except:
pass
if type(recID) is int:
if recID > 0:
from invenio.search_engine import record_exists
success = record_exists(recID)
if success == 1:
return (1,"")
else:
warnings.append(('ERR_WEBCOMMENT_RECID_INEXISTANT', recID))
return (0, webcomment_templates.tmpl_record_not_found(status='inexistant', recID=recID, ln=ln))
elif recID == 0:
warnings.append(('ERR_WEBCOMMENT_RECID_MISSING',))
return (0, webcomment_templates.tmpl_record_not_found(status='missing', recID=recID, ln=ln))
else:
warnings.append(('ERR_WEBCOMMENT_RECID_INVALID', recID))
return (0, webcomment_templates.tmpl_record_not_found(status='invalid', recID=recID, ln=ln))
else:
warnings.append(('ERR_WEBCOMMENT_RECID_NAN', recID))
return (0, webcomment_templates.tmpl_record_not_found(status='nan', recID=recID, ln=ln))
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
diff --git a/modules/webcomment/lib/webcomment_templates.py b/modules/webcomment/lib/webcomment_templates.py
index 7de443c06..00417775e 100644
--- a/modules/webcomment/lib/webcomment_templates.py
+++ b/modules/webcomment/lib/webcomment_templates.py
@@ -1,1335 +1,1335 @@
# -*- coding: utf-8 -*-
## $Id$
## Comments and reviews for records.
## This file is part of CDS Invenio.
## Copyright (C) 2002, 2003, 2004, 2005, 2006 CERN.
##
## CDS Invenio is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License as
## published by the Free Software Foundation; either version 2 of the
## License, or (at your option) any later version.
##
## CDS Invenio is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
"""HTML Templates for commenting features """
__lastupdated__ = """$Date$"""
# non CDS Invenio imports
import string
# CDS Invenio imports
from invenio.webuser import get_user_info
from invenio.dateutils import convert_datetext_to_dategui
from invenio.webmessage_mailutils import email_quoted_txt2html
from invenio.config import weburl, \
sweburl, \
cdslang, \
cdsnameintl,\
cfg_webcomment_nb_reviews_in_detailed_view, \
cfg_webcomment_allow_reviews, \
cfg_webcomment_allow_comments, \
cfg_webcomment_nb_comments_in_detailed_view
from invenio.messages import gettext_set_language
from invenio.textutils import indent_text
class Template:
"""templating class, refer to webcomment.py for examples of call"""
def tmpl_get_first_comments_without_ranking(self, recID, ln, comments, nb_comments_total, warnings):
"""
@param recID: record id
@param ln: language
@param comments: tuple as returned from webcomment.py/query_retrieve_comments_or_remarks
@param nb_comments_total: total number of comments for this record
@param warnings: list of warning tuples (warning_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_user_id = 1
c_date_creation = 2
c_body = 3
c_id = 4
warnings = self.tmpl_warnings(warnings, ln)
# comments
comment_rows = ''
for comment in comments:
if comment[c_nickname]:
nickname = comment[c_nickname]
display = nickname
else:
(uid, nickname, display) = get_user_info(comment[c_user_id])
messaging_link = self.create_messaging_link(nickname, display, ln)
comment_rows += """
"""
# write button
write_button_label = _("Write a comment")
write_button_link = '%s/comments/add' % (weburl,)
write_button_form = """
""" % (recID, ln)
write_button_form = self.createhiddenform(action=write_button_link, method="Get", text=write_button_form, button=write_button_label)
# output
if nb_comments_total > 0:
out = warnings
comments_label = cfg_webcomment_nb_comments_in_detailed_view and \
cfg_webcomment_nb_comments_in_detailed_view>1 and \
_("Showing the latest %i comments:")% cfg_webcomment_nb_comments_in_detailed_view or ""
out += """
%(comment_title)s
%(comments_label)s
%(comment_rows)s
%(view_all_comments_link)s
%(write_button_form)s """ % \
{'comment_title': _("Discuss this document"),
'comments_label': comments_label,
'nb_comments_total' : nb_comments_total,
'recID': recID,
'comment_rows': comment_rows,
'tab': ' '*4,
'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_label)s:
%(detailed_info)s
%(form)s
""" % {'form': write_button_form,
'discuss_label': _("Discuss this document"),
'detailed_info': _("Start a discussion about any aspect of this document.")
}
return out
def tmpl_record_not_found(self, status='missing', recID="", ln=cdslang):
"""
Displays a page when bad or missing record ID was given.
@param status: 'missing' : no recID was given
'inexistant': recID doesn't have an entry in the database
'nan' : recID is not a number
'invalid' : recID is an error code, i.e. in the interval [-99,-1]
@param return: body of the page
"""
_ = gettext_set_language(ln)
if status == 'inexistant':
body = _("Sorry, the record %s does not seem to exist.") % (recID,)
elif status in ('nan', 'invalid'):
body = _("Sorry, %s is not a valid ID value.") % (recID,)
else:
body = _("Sorry, no record ID was provided.")
body += "
"
link = "%s." % (weburl, ln, cdsnameintl[ln])
body += _("You may want to start browsing from %s") % link
return body
def tmpl_get_first_comments_with_ranking(self, recID, ln, comments=None, nb_comments_total=None, avg_score=None, warnings=[]):
"""
@param recID: record id
@param ln: language
@param comments: tuple as returned from webcomment.py/query_retrieve_comments_or_remarks
@param nb_comments_total: total number of comments for this record
@param avg_score: average score of all reviews
@param warnings: list of warning tuples (warning_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_user_id = 1
c_date_creation = 2
c_body = 3
c_nb_votes_yes = 4
c_nb_votes_total = 5
c_star_score = 6
c_title = 7
c_id = 8
warnings = self.tmpl_warnings(warnings, ln)
#stars
if avg_score > 0:
avg_score_img = 'stars-' + str(avg_score).split('.')[0] + '-' + str(avg_score).split('.')[1] + '.png'
else:
avg_score_img = "stars-0-0.png"
# voting links
useful_dict = { 'weburl' : weburl,
'recID' : recID,
'ln' : ln,
'yes_img' : 'smchk_gr.gif', #'yes.gif',
'no_img' : 'iconcross.gif' #'no.gif'
}
link = '' + _("Yes") + ''
useful_no = link + '&com_value=-1">' + _("No") + ''
#comment row
comment_rows = ' '
for comment in comments:
if comment[c_nickname]:
nickname = comment[c_nickname]
display = nickname
else:
(uid, nickname, display) = get_user_info(comment[c_user_id])
messaging_link = self.create_messaging_link(nickname, display, ln)
comment_rows += '''
%(view_all_comments_link)s
%(write_button_form)s
""" % \
{ 'comment_title' : _("Rate this document"),
'score_label' : score,
'useful_label' : useful_label,
'recID' : recID,
'view_all_comments' : _("View all %s reviews") % (nb_comments_total,),
'write_comment' : _("Write a review"),
'comment_rows' : comment_rows,
'tab' : ' '*4,
'weburl' : weburl,
'view_all_comments_link': nb_comments_total>0 and view_all_comments_link or "",
'write_button_form' : write_button_form
}
else:
out = '''
%s:
%s
%s
''' % (_("Rate this document"),
_("Be the first to review this document."),
write_button_form)
return out
def tmpl_get_comment_without_ranking(self, 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 = convert_datetext_to_dategui(date_creation)
out = ''
final_body = email_quoted_txt2html(body)
- title = nickname + ' ' + _("wrote on") + ' ' + date_creation + ''
+ title = _("%(x_name)s wrote on %(x_date)s:") % {'x_name': nickname,
+ 'x_date': '' + date_creation + ''}
links = ''
if reply_link:
links += '' + _("Reply") +''
if report_link:
links += ' | '
if report_link:
links += '' + _("Report abuse") + ''
out += """
%(title)s
%(body)s
%(links)s
""" % \
{'title' : title,
'body' : final_body,
'links' : links}
return out
def tmpl_get_comment_with_ranking(self, ln, nickname, date_creation, body, nb_votes_total, nb_votes_yes, star_score, title, report_link=None):
"""
private function
@param ln: language
@param nickname: nickname
@param date_creation: date comment was written
@param body: comment body
@param nb_votes_total: total number of votes for this review
@param nb_votes_yes: number of positive votes for this record
@param star_score: star score for this record
@param title: title of review
@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.png'
else:
star_score_img = 'stars-0-0.png'
out = ""
date_creation = convert_datetext_to_dategui(date_creation)
reviewed_label = _("Reviewed by %(x_nickname)s on %(x_date)s") % {'x_nickname': nickname, 'x_date':date_creation}
- useful_label = _("%i out of %i people found this review useful")
- useful_label %= (nb_votes_yes, nb_votes_total)
+ useful_label = _("%(x_nb_people)i out of %(x_nb_total)i people found this review useful") % {'x_nb_people': nb_votes_yes,
+ 'x_nb_total': nb_votes_total}
links = ''
if report_link:
links += '' + _("Report abuse") + ''
out += """
%(title)s
%(reviewed_label)s
%(useful_label)s
%(body)s
%(abuse)s
""" % {'weburl' : weburl,
'star_score_img': star_score_img,
'star_score' : star_score,
'title' : title,
'reviewed_label': reviewed_label,
'useful_label' : useful_label,
'body' : body,
'abuse' : links
}
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_user_id = 1
c_date_creation = 2
c_body = 3
c_nb_votes_yes = 4
c_nb_votes_total = 5
c_star_score = 6
c_title = 7
c_id = 8
else:
c_nickname = 0
c_user_id = 1
c_date_creation = 2
c_body = 3
c_id = 4
# 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_yes %= useful_dict
useful_no = '' + _("No") + ''
useful_no %= useful_dict
warnings = self.tmpl_warnings(warnings, ln)
## record details
from search_engine import print_record
record_details = print_record(recID=recID, format='hb', ln=ln)
link_dic = { 'weburl' : weburl,
'module' : 'comments',
'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:
if comment[c_nickname]:
nickname = comment[c_nickname]
display = nickname
else:
(uid, nickname, display) = get_user_info(comment[c_user_id])
messaging_link = self.create_messaging_link(nickname, display, ln)
# do NOT delete the HTML comment below. It is used for parsing... (I plead unguilty!)
comments_rows += """
""" % \
{ 'record_label': _("Record"),
'back_label': _("Back to search results"),
'total_label': total_label,
'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' : indent_text(comments_rows, 1),
'total_nb_comments' : total_nb_comments,
'comments_or_reviews' : reviews and _('review') or _('comment'),
'comments_or_reviews_title' : reviews and _('Review') or _('Comment'),
'weburl' : weburl,
'module' : "comments",
'recid' : recID,
'ln' : ln,
'border' : border,
'ranking_avg' : ranking_average }
# form is not currently used. reserved for an eventual purpose
#form = """
# Display
# comments per page that are
# and sorted by
# """ % \
# (reviews==1 and '''
#
#
#
#
# ''' or '''
# ''')
#
#form_link = "%(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 = """
%(v_label)s %(comments_or_reviews)s %(results_nb_lower)s-%(results_nb_higher)s
%(page_links)s
""" % \
{'v_label': _("Viewing"),
'page_links': _("Page:") + page_links ,
'comments_or_reviews': reviews and _('review') or _('comment'),
'results_nb_lower': len(comments)>0 and ((page-1) * nb_per_page)+1 or 0,
'results_nb_higher': page == nb_pages and (((page-1) * nb_per_page) + len(comments)) or (page * nb_per_page) }
if nb_pages > 1:
#body = warnings + body + form + pages
body = warnings + body + pages
else:
body = warnings + body
return body
def create_messaging_link(self, to, display_name, ln=cdslang):
"""prints a link to the messaging system"""
link = "%s/yourmessages/write?msg_to=%s&ln=%s" % (weburl, to, ln)
if to:
return '%s' % (link, display_name)
else:
return display_name
def createhiddenform(self, action="", method="Get", text="", button="confirm", cnfrm='', **hidden):
"""
create select with hidden values and submit button
@param action: name of the action to perform on submit
@param method: 'get' or 'post'
@param text: additional text, can also be used to add non hidden input
@param button: value/caption on the submit button
@param cnfrm: if given, must check checkbox to confirm
@param **hidden: dictionary with name=value pairs for hidden input
@return html form
"""
output = """
""" % (action, string.lower(method).strip() in ['get','post'] and method or 'Get')
output += """
"""
output += text + '\n'
if cnfrm:
output += """
"""
for key in hidden.keys():
if type(hidden[key]) is list:
for value in hidden[key]:
output += """
""" % (key, value)
else:
output += """
""" % (key, hidden[key])
output += """
"""
output += """
""" % (button, )
output += """
"""
return output
def tmpl_warnings(self, warnings, ln=cdslang):
"""
Prepare the warnings list
@param warnings: list of warning tuples (warning_msg, arg1, arg2, etc)
@return html string of warnings
"""
red_text_warnings = ['WRN_WEBCOMMENT_FEEDBACK_NOT_RECORDED',
'WRN_WEBCOMMENT_ALREADY_VOTED']
green_text_warnings = ['WRN_WEBCOMMENT_FEEDBACK_RECORDED']
from invenio.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', ln)
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 in red_text_warnings:
span_class = 'important'
elif warning_code in green_text_warnings:
span_class = 'exampleleader'
else:
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
"""
_ = gettext_set_language(ln)
link_dic = { 'weburl' : weburl,
'module' : 'comments',
'function' : 'add',
'arguments' : 'recid=%s&ln=%s&action=%s&reviews=0' % (recID, ln, 'SUBMIT') }
if nickname:
note = _("Note: Your nickname, %s, will be displayed as author of this comment") % ('' + nickname + '')
else:
(uid, nickname, display) = get_user_info(uid)
link = '' % sweburl
- note = _("Note: you have not %sdefined your nickname%s. %s will be displayed as the author of this comment.")
- note %= (link, '', ' ' + display + '')
+ note = _("Note: you have not %(x_url_open)sdefined your nickname%(x_url_close)s. %(x_nickname)s will be displayed as the author of this comment.") %\
+ {'x_url_open': link,
+ 'x_url_close': '',
+ 'x_nickname': ' ' + display + ''}
from invenio.search_engine import print_record
record_details = print_record(recID=recID, format='hb', ln=ln)
warnings = self.tmpl_warnings(warnings, ln)
form = """
%(record_label)s
%(record)s
%(comment_label)s
%(note)s
""" % {'msg': msg,
'note': note,
'record': record_details,
'record_label': _("Article") + ":",
'comment_label': _("Comment") + ":"}
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
"""
_ = gettext_set_language(ln)
link_dic = { 'weburl' : weburl,
'module' : 'comments',
'function' : 'add',
'arguments' : 'recid=%s&ln=%s&action=%s&reviews=1' % (recID, ln, 'SUBMIT') }
warnings = self.tmpl_warnings(warnings, ln)
from search_engine import print_record
record_details = print_record(recID=recID, format='hb', ln=ln)
note_label = _("Note: Your nickname, %s, will be displayed as the author of this review.")
note_label %= ('' + nickname + '')
form = """
%(article_label)s:
%(record)s
%(rate_label)s:
%(title_label)s:
%(write_label)s:
%(note_label)s
""" % {'article_label': _('Article'),
'rate_label': _("Rate this article"),
'select_label': _("Select a score"),
'title_label': _("Give a title to your review"),
'write_label': _("Write your review"),
'note_label': note_label,
'note' : note!='' and note or "",
'msg' : msg!='' and msg or "",
'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, warnings):
"""
@param recID: record id
@param ln: language
@return html page of successfully added comment/review
"""
_ = gettext_set_language(ln)
link_dic = { 'weburl' : weburl,
'module' : 'comments',
'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
if warnings:
out = self.tmpl_warnings(warnings, ln) + '
'
else:
if reviews:
out = _("Your review was successfully added.") + '
'
else:
out = _("Your comment was successfully added.") + '
'
out += '' % link
out += _('Back to record') + ''
return out
def tmpl_create_multiple_actions_form(self,
form_name="",
form_action="",
method="GET",
action_display={},
action_field_name="",
button_label="",
button_name="",
content="",
**hidden):
""" Creates an HTML form with a multiple choice of actions and a button to select it.
@param form_action: link to the receiver of the formular
@param form_name: name of the HTML formular
@param method: either 'GET' or 'POST'
@param action_display: dictionary of actions.
action is HTML name (name of action)
display is the string provided in the popup
@param action_field_name: html name of action field
@param button_label: what's written on the button
@param button_name: html name of the button
@param content: what's inside te formular
@param **hidden: dictionary of name/value pairs of hidden fields.
"""
output = """
""" % (form_action, method)
output += """
"""
output += content + '\n'
for key in hidden.keys():
if type(hidden[key]) is list:
for value in hidden[key]:
output += """
""" % (key, value)
else:
output += """
""" % (key, hidden[key])
output += """
"""
if type(action_display) is dict and len(action_display.keys()):
output += """
"""
output += """
""" % (button_label, button_name)
output += """
"""
return output
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 += '''
-
- '''
- out = out % { 'weburl' : weburl,
- 'reported_cmt_label': _("View all reported comments"),
- 'reported_rev_label': _("View all reported reviews"),
- 'delete_label': _("Delete a specific comment/review (by ID)"),
- 'view_users': _("View all users who have been reported"),
- 'ln' : ln }
+ """ % {'weburl' : weburl,
+ 'delete_label': _("Delete a specific comment/review (by ID)"),
+ 'view_users': _("View all users who have been reported"),
+ 'ln' : ln}
else:
out += _("Comments and reviews are disabled") + ' '
out += ''
from invenio.bibrankadminlib import addadminbox
return addadminbox('%s'%_("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, ln)
out = '''
%s
'''%_("Please enter the ID of the comment/review so that you can view it before deciding whether to delete it or not")
form = '''
-
%s:
+
%s
- ''' %_("Comment ID")
+ ''' %_("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_nb_votes_yes_of_reported,
total_nb_votes_total_of_reported, user_id, user_email, user_nickname)
sorted by order of ct having highest total_number_reported
"""
_ = gettext_set_language(ln)
u_reports = 0
u_comment_reports = 1
u_reviews_reports = 2
u_nb_votes_yes = 3
u_nb_votes_total = 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_label = _("View all %s reported comments") % utuple[u_comment_reports]
com_link = '''%s ''' % \
(weburl, ln, utuple[u_uid], com_label)
rev_label = _("View all %s reported reviews") % utuple[u_reviews_reports]
rev_link = '''%s''' % \
(weburl, ln, utuple[u_uid], rev_label)
if not utuple[u_nickname]:
user_info = get_user_info(utuple[u_uid])
nickname = user_info[2]
else:
nickname = utuple[u_nickname]
if cfg_webcomment_allow_reviews:
review_row = """
""" % { 'nickname' : nickname,
'email' : utuple[u_email],
'uid' : utuple[u_uid],
'reports' : utuple[u_reports],
'review_row': review_row,
'weburl' : weburl,
'ln' : ln,
'com_link' : cfg_webcomment_allow_comments and com_link or "",
'rev_link' : cfg_webcomment_allow_reviews and rev_link or ""
}
out = " "
out += _("Here is a list, sorted by total number of reports, of all users who have had a comment reported at least once.")
out += """
"""
out += _("Nickname") + '
\n'
out += indent_text('
' + _("Email") + '
\n', 3)
out += indent_text('
' + _("User ID") + '
\n', 3)
if cfg_webcomment_allow_reviews > 0:
out += indent_text('
' + _("Number positive votes") + '
\n', 3)
out += indent_text('
' + _("Number negative votes") + '
\n', 3)
out += indent_text('
' + _("Total number votes") + '
\n', 3)
out += indent_text('
' + _("Total number of reports") + '
\n', 3)
out += indent_text('
' + _("View all user's reported comments/reviews") + '
\n', 3)
out += """
%s
""" % indent_text(user_rows, 2)
return out
def tmpl_admin_select_comment_checkbox(self, cmt_id):
""" outputs a checkbox named "comidXX" where XX is cmt_id """
return '' % int(cmt_id)
def tmpl_admin_user_info(self, ln, nickname, uid, email):
""" prepares informations about a user"""
_ = gettext_set_language(ln)
out = """
%(nickname_label)s: %(messaging)s
%(uid_label)s: %(uid)i
%(email_label)s: %(email)s"""
out %= {'nickname_label': _("Nickname"),
'messaging': self.create_messaging_link(uid, nickname, ln),
'uid_label': _("User ID"),
'uid': int(uid),
'email_label': _("Email"),
'email': email}
return out
def tmpl_admin_review_info(self, ln, reviews, nb_reports, cmt_id, rec_id):
""" outputs information about a review """
_ = gettext_set_language(ln)
if reviews:
reported_label = _("This review has been reported %i times")
else:
reported_label = _("This comment has been reported %i times")
reported_label %= int(nb_reports)
out = """
%(reported_label)s %(rec_id_label)s
%(cmt_id_label)s"""
out %= {'reported_label': reported_label,
'rec_id_label': _("Record") + ' #' + str(rec_id),
'weburl': weburl,
'rec_id': int(rec_id),
'cmt_id_label': _("Comment") + ' #' + str(cmt_id),
'ln': ln}
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,
nb_votes_yes,
nb_votes_total,
star_score,
title,
id)
"""
_ = gettext_set_language(ln)
comments = []
comments_info = []
checkboxes = []
users = []
for (cmt_tuple, meta_data) in comment_data:
if reviews:
comments.append(self.tmpl_get_comment_with_ranking(ln,
cmt_tuple[0],#nickname
cmt_tuple[2],#date_creation
cmt_tuple[3],#body
cmt_tuple[5],#nb_votes_total
cmt_tuple[4],#nb_votes_yes
cmt_tuple[6],#star_score
cmt_tuple[7]))#title
else:
comments.append(self.tmpl_get_comment_without_ranking(ln,
cmt_tuple[0],#nickname
cmt_tuple[2],#date_creation
cmt_tuple[3],#body
None, #reply_link
None)) #report_link
users.append(self.tmpl_admin_user_info(ln,
meta_data[0], #nickname
meta_data[1], #uid
meta_data[2]))#email
comments_info.append(self.tmpl_admin_review_info(ln,
reviews,
meta_data[5], # nb abuse reports
meta_data[3], # cmt_id
meta_data[4]))# rec_id
checkboxes.append(self.tmpl_admin_select_comment_checkbox(meta_data[3]))
form_link = "%s/admin/webcomment/webcommentadmin.py/del_com?ln=%s" % (weburl, ln)
out = """
%(review_label)s
%(written_by_label)s
%(review_info_label)s
%(select_label)s
""" % {'review_label': reviews and _("Review") or _("Comment"),
'written_by_label': _("Written by"),
'review_info_label': _("General informations"),
'select_label': _("Select")}
for i in range (0, len(comments)):
out += """
%s
%s
%s
%s
""" % (comments[i], users[i], comments_info[i], checkboxes[i])
out += """
"""
if reviews:
action_display = {
'delete': _('Delete selected reviews'),
'unreport': _('Suppress selected abuse report')
}
else:
action_display = {
'delete': _('Delete selected comments'),
'unreport': _('Suppress selected abuse report')
}
form = self.tmpl_create_multiple_actions_form(form_name="admin_comment",
form_action=form_link,
method="POST",
action_display=action_display,
action_field_name='action',
button_label=_("OK"),
button_name="okbutton",
content=out)
if uid > 0:
header = ' '
if reviews:
header += _("Here are the reported reviews of user %s") % uid
else:
header += _("Here are the reported comments of user %s") % uid
header += '
'
if comID > 0:
header = ' ' +_("Here is comment/review %s")% comID + '
'
if uid > 0 and comID > 0:
header = ' ' + _("Here is comment/review %(x_cmtID)s written by user %(x_user)s") % {'x_cmtID': comID, 'x_user': uid}
header += '
'
if uid == 0 and comID == 0:
header = ' '
if reviews:
header += _("Here are all reported reviews sorted by the most reported")
else:
header += _("Here are all reported comments sorted by the most reported")
header += "
"
return header + form
def tmpl_admin_del_com(self, del_res, ln=cdslang):
"""
@param del_res: list of the following tuple (comment_id, was_successfully_deleted),
was_successfully_deleted is boolean (0=false, >0=true
"""
_ = gettext_set_language(ln)
table_rows = ''
for deltuple in del_res:
table_rows += """
%s
%s
""" % (deltuple[0], deltuple[1]>0 and _("Yes") or "" +_("No") + "")
out = """
%s
%s
%s
""" % (_("comment ID"), _("successfully deleted"), table_rows)
return out
def tmpl_admin_suppress_abuse_report(self, del_res, ln=cdslang):
"""
@param del_res: list of the following tuple (comment_id, was_successfully_deleted),
was_successfully_deleted is boolean (0=false, >0=true
"""
_ = gettext_set_language(ln)
table_rows = ''
for deltuple in del_res:
table_rows += """
%s
%s
""" % (deltuple[0], deltuple[1]>0 and _("Yes") or "" +_("No") + "")
out = """
%s
%s
%s
""" % (_("comment ID"), _("successfully suppressed abuse report"), table_rows)
return out
diff --git a/modules/webmessage/lib/webmessage_templates.py b/modules/webmessage/lib/webmessage_templates.py
index bf0cfa69f..2bad6f678 100644
--- a/modules/webmessage/lib/webmessage_templates.py
+++ b/modules/webmessage/lib/webmessage_templates.py
@@ -1,646 +1,646 @@
# -*- coding: utf-8 -*-
## $Id$
##
## handles rendering of webmessage module
##
## This file is part of CDS Invenio.
## Copyright (C) 2002, 2003, 2004, 2005, 2006 CERN.
##
## CDS Invenio is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License as
## published by the Free Software Foundation; either version 2 of the
## License, or (at your option) any later version.
##
## CDS Invenio is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
""" templates for webmessage module """
# CDS imports
from invenio.webmessage_mailutils import email_quoted_txt2html, email_quote_txt
from invenio.webmessage_config import cfg_webmessage_status_code, \
cfg_webmessage_separator, \
cfg_webmessage_max_nb_of_messages, \
cfg_webmessage_results_field
from invenio.textutils import indent_text
from invenio.dateutils import convert_datetext_to_dategui, \
datetext_default, \
create_day_selectbox, \
create_month_selectbox, \
create_year_selectbox
from invenio.config import weburl, cdslang
from invenio.messages import gettext_set_language
from invenio.webuser import get_user_info
class Template:
def tmpl_display_inbox(self, messages, infos=[], warnings=[], nb_messages=0, no_quota=0, ln=cdslang):
"""
Displays a list of messages, with the appropriate links and buttons
@param messages: a list of tuples:
[(message_id,
user_from_id,
user_from_nickname,
subject,
sent_date,
status=]
@param infos: a list of informations to print on top of page
@param warnings: a list of warnings to display
@param nb_messages: number of messages user has
@param no_quota: 1 if user has no quota (admin) or 0 else.
@param ln: language of the page.
@return the list in HTML format
"""
_ = gettext_set_language(ln)
junk = 0
inbox = self.tmpl_warning(warnings, ln)
inbox += self.tmpl_infobox(infos, ln)
if not(no_quota):
inbox += self.tmpl_quota(nb_messages, ln)
inbox += """
""" % {'ln': ln,
'write_label': _("Write new message"),
'delete_all_label': _("Delete All")}
return indent_text(inbox, 2)
def tmpl_write(self,
msg_to="",
msg_to_group="",
msg_id=0,
msg_subject="",
msg_body="",
msg_send_year=0,
msg_send_month=0,
msg_send_day=0,
warnings=[],
search_results_list=[],
search_pattern="",
results_field=cfg_webmessage_results_field['NONE'],
ln=cdslang):
"""
Displays a writing message form with optional prefilled fields
@param msg_to: nick of the user (prefills the To: field)
@param msg_subject: subject of the message (prefills the Subject: field)
@param msg_body: body of the message (prefills the Message: field)
@param msg_send_year: prefills to year field
@param msg_send_month: prefills the month field
@param msg_send_day: prefills the day field
@param warnings: display warnings on top of page
@param search_results_list: list of tuples. (user/groupname, is_selected)
@param search_pattern: pattern used for searching
@param results_field: 'none', 'user' or 'group', see cfg_webmessage_results_field
@param ln: language of the form
@return the form in HTML format
"""
_ = gettext_set_language(ln)
write_box = self.tmpl_warning(warnings)
# escape forbidden character
msg_to = msg_to.replace('"', '"')
msg_to_group = msg_to_group.replace('"', '"')
msg_subject = msg_subject.replace('"', '"')
search_pattern = search_pattern.replace('"','"')
to_select = self.tmpl_user_or_group_search(search_results_list,
search_pattern,
results_field,
ln)
if (msg_id != 0):
msg_subject = _("Re:") + " " + msg_subject
msg_body = email_quote_txt(msg_body)
msg_body = msg_body.replace('>', '>')
write_box += """
%(to_label)s
%(users_label)s
%(groups_label)s
%(subject_label)s
%(message_label)s
%(send_later_label)s
%(day_field)s
%(month_field)s
%(year_field)s
%(to_select)s
"""
write_box_part2 = indent_text(write_box_part2, 2)
write_box += "%(body)s" ""+ write_box_part2
day_field = create_day_selectbox('msg_send_day', msg_send_day, ln)
month_field = create_month_selectbox('msg_send_month', msg_send_month, ln)
year_field = create_year_selectbox('msg_send_year', -1, 10, msg_send_year, ln)
write_box = write_box % {'to_users' : msg_to,
'to_groups': msg_to_group,
'subject' : msg_subject,
'body' : msg_body,
'ln': ln,
'day_field': day_field,
'month_field': month_field,
'year_field': year_field,
'to_select': to_select,
'send_later_label': _("Send later?"),
'to_label': _("To:"),
'users_label': _("Users"),
'groups_label': _("Groups"),
'subject_label': _("Subject:"),
'message_label': _("Message:"),
'send_label': _("SEND")}
return write_box
def tmpl_display_msg(self,
msg_id="",
msg_from_id="",
msg_from_nickname="",
msg_sent_to="",
msg_sent_to_group="",
msg_subject="",
msg_body="",
msg_sent_date="",
msg_received_date=datetext_default,
ln=cdslang):
"""
Displays a given message
@param msg_id: id of the message
@param msg_from_id: id of user who sent the message
@param msg_from_nickname: nickname of the user who sent the message
@param msg_sent_to: list of users who received the message
(comma separated string)
@param msg_sent_to_group: list of groups who received the message
(comma separated string)
@param msg_subject: subject of the message
@param msg_body: body of the message
@param msg_sent_date: date at which the message was sent
@param msg_received_date: date at which the message had to be received
(if this argument != 0000-00-00 => reminder
@param ln: language of the page
@return the message in HTML format
"""
# load the right message language
_ = gettext_set_language(ln)
sent_to_link = ''
tos = msg_sent_to.split(cfg_webmessage_separator)
if (tos):
for to in tos[0:-1]:
to_display = to
if to.isdigit():
(junk, to, to_display) = get_user_info(int(to), ln)
sent_to_link += ''% (to, ln)
sent_to_link += '%s%s '% (to_display, cfg_webmessage_separator)
to_display = tos[-1]
to = tos[-1]
if to.isdigit():
(junk, to, to_display) = get_user_info(int(to), ln)
sent_to_link += '%s'% (to, ln, to_display)
group_to_link = ""
groups = msg_sent_to_group.split(cfg_webmessage_separator)
if (groups):
for group in groups[0:-1]:
group_to_link += ''% (group, ln)
group_to_link += '%s%s '% (group, cfg_webmessage_separator)
group_to_link += '%s'% (groups[-1], ln, groups[-1])
# format the msg so that the '>>' chars give vertical lines
final_body = email_quoted_txt2html(msg_body)
out = """
"""
if (msg_received_date != datetext_default):
out += """
-
%(received_label)s:
+
%(received_label)s
%(received_date)s
"""
out += """
-
%(sent_to_label)s:
+
%(sent_to_label)s
%(sent_to)s
"""
if (msg_sent_to_group != ""):
out += """
-
%(groups_label)s:
-
%(sent_to_group)s:
+
%(groups_label)s
+
%(sent_to_group)s
"""
out += """
%(body)s
"""
if msg_from_nickname:
msg_from_display = msg_from_nickname
else:
msg_from_display = get_user_info(msg_from_id, ln)[2]
msg_from_nickname = msg_from_id
out = out % {'from' : msg_from_nickname,
'from_display': msg_from_display,
'sent_date' : convert_datetext_to_dategui(msg_sent_date, ln),
'received_date': convert_datetext_to_dategui(msg_received_date, ln),
'sent_to': sent_to_link,
'sent_to_group': group_to_link,
'subject' : msg_subject,
'body' : final_body,
'reply_to': msg_from_id,
'msg_id': msg_id,
'ln': ln,
- 'from_label':_("From"),
- 'subject_label':_("Subject"),
- 'sent_label': _("Sent on"),
- 'received_label':_("Received on"),
- 'sent_to_label': _("Sent to"),
- 'groups_label': _("Sent to groups"),
+ 'from_label':_("From:"),
+ 'subject_label':_("Subject:"),
+ 'sent_label': _("Sent on:"),
+ 'received_label':_("Received on:"),
+ 'sent_to_label': _("Sent to:"),
+ 'groups_label': _("Sent to groups:"),
'reply_but_label':_("REPLY"),
'delete_but_label': _("DELETE")}
return indent_text(out, 2)
def tmpl_navtrail(self, ln=cdslang, title=""):
"""
display the navtrail, e.g.:
Your account > Your messages > title
@param title: the last part of the navtrail. Is not a link
@param ln: language
return html formatted navtrail
"""
_ = gettext_set_language(ln)
nav_h1 = '%s'
nav_h2 = ""
if (title != ""):
nav_h2 = ' > %s'
nav_h2 = nav_h2 % (weburl, ln, _("Your Messages"))
return nav_h1 % (weburl, ln, _("Your Account")) + nav_h2
def tmpl_confirm_delete(self, ln=cdslang):
"""
display a confirm message
@param ln: language
@return html output
"""
_ = gettext_set_language(ln)
out = """
%(message)s
"""% {'message': _("Are you sure you want to empty your whole mailbox?"),
'ln':ln,
'yes_label': _("Yes"),
'no_label': _("No")}
return indent_text(out, 2)
def tmpl_infobox(self, infos, ln=cdslang):
"""Display len(infos) information fields
@param infos: list of strings
@param ln=language
@return html output
"""
_ = gettext_set_language(ln)
if not((type(infos) is list) or (type(infos) is tuple)):
infos = [infos]
infobox = ""
for info in infos:
infobox += "
"
lines = info.split("\n")
for line in lines[0:-1]:
infobox += line + " \n"
infobox += lines[-1] + "
\n"
return infobox
def tmpl_warning(self, warnings, ln=cdslang):
"""
Display len(warnings) warning fields
@param infos: list of strings
@param ln=language
@return html output
"""
if not((type(warnings) is list) or (type(warnings) is tuple)):
warnings = [warnings]
warningbox = ""
if warnings != []:
warningbox = "
\n Warning:\n"
for warning in warnings:
lines = warning.split("\n")
warningbox += "
"
for line in lines[0:-1]:
warningbox += line + " \n"
warningbox += lines[-1] + "
"
warningbox += "
\n"
return warningbox
def tmpl_quota(self, nb_messages=0, ln=cdslang):
"""
Display a quota bar.
@nb_messages: number of messages in inbox.
@ln=language
@return html output
"""
_ = gettext_set_language(ln)
quota = float(cfg_webmessage_max_nb_of_messages)
ratio = float(nb_messages) / quota
out = """
%(quota_label)s
""" %{'quota_label' : _("Quota used: %i messages out of max. %i")%(nb_messages, cfg_webmessage_max_nb_of_messages),
'width' : int(ratio * 200)
}
return out
def tmpl_multiple_select(self, select_name, tuples_list, ln=cdslang):
"""displays a multiple select environment
@param tuples_list: a list of (value, isSelected) tuples
@return HTML output
"""
_ = gettext_set_language(ln)
if not((type(tuples_list) is list) or (type(tuples_list) is tuple)):
tuples_list = [tuples_list]
out = """
%s
\n"
return out
def tmpl_user_or_group_search(self,
tuples_list=[],
search_pattern="",
results_field=cfg_webmessage_results_field['NONE'],
ln=cdslang):
"""
Display a box for user searching
@param tuples_list: list of (value, is_selected) tuples
@param search_pattern: text to display in this field
@param results_field: either 'none', 'user', 'group', look at cfg_webmessage_results_field
@param ln: language
@return html output
"""
_ = gettext_set_language(ln)
multiple_select = ''
add_button = ''
if results_field != cfg_webmessage_results_field['NONE'] and results_field in cfg_webmessage_results_field.values():
if len(tuples_list):
multiple_select = self.tmpl_multiple_select('names_selected', tuples_list)
add_button = ''
if results_field == cfg_webmessage_results_field['USER']:
add_button = add_button % ('add_user', _("Add to users"))
else:
add_button = add_button % ('add_group', _("Add to groups"))
else:
if results_field == cfg_webmessage_results_field['USER']:
multiple_select = _("No matching user")
else:
multiple_select = _("No matching group")
out = """
%(title_label)s
%(multiple_select)s
%(add_button)s
"""
out = out% {'title_label' : _("Find users or groups:"),
'search_user_label' : _("Find a user"),
'search_group_label' : _("Find a group"),
'results_field' : results_field,
'search_pattern' : search_pattern,
'multiple_select' : multiple_select,
'add_button' : add_button}
return out
def tmpl_account_new_mail(self, nb_new_mail=0, total_mail=0, ln=cdslang):
"""
display infos about inbox (used by myaccount.py)
@param nb_new_mail: number of new mails
@param ln: language
return: html output.
"""
_ = gettext_set_language(ln)
out = _("You have %s new messages out of %s messages")
out %= ('' + str(nb_new_mail) + '',
'' + str(total_mail))
out += '.'
return out
diff --git a/modules/websearch/lib/search_engine.py b/modules/websearch/lib/search_engine.py
index 358a062c1..7e30cfecc 100644
--- a/modules/websearch/lib/search_engine.py
+++ b/modules/websearch/lib/search_engine.py
@@ -1,3494 +1,3494 @@
# -*- coding: utf-8 -*-
## $Id$
## This file is part of CDS Invenio.
## Copyright (C) 2002, 2003, 2004, 2005, 2006 CERN.
##
## CDS Invenio is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License as
## published by the Free Software Foundation; either version 2 of the
## License, or (at your option) any later version.
##
## CDS Invenio is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
"""CDS Invenio Search Engine in mod_python."""
__lastupdated__ = """$Date$"""
__version__ = "$Id$"
## import general modules:
import cgi
import copy
import Cookie
import cPickle
import marshal
import fileinput
import getopt
import string
from string import split
import os
import sre
import sys
import time
import traceback
import urllib
import zlib
import Numeric
import md5
import base64
import unicodedata
from xml.dom import minidom
## import CDS Invenio stuff:
from invenio.config import *
from invenio.search_engine_config import *
from invenio.bibrank_record_sorter import get_bibrank_methods,rank_records
from invenio.bibrank_downloads_similarity import register_page_view_event, calculate_reading_similarity_list
if cfg_experimental_features:
from invenio.bibrank_citation_searcher import calculate_cited_by_list, calculate_co_cited_with_list
from invenio.bibrank_citation_grapher import create_citation_history_graph_and_box
from invenio.bibrank_downloads_grapher import create_download_history_graph_and_box
from invenio.dbquery import run_sql, escape_string, Error
try:
from mod_python import apache
from invenio.webuser import getUid
from invenio.webpage import pageheaderonly, pagefooteronly, create_error_box
except ImportError, e:
pass # ignore user personalisation, needed e.g. for command-line
from invenio.messages import gettext_set_language, wash_language
try:
import invenio.template
websearch_templates = invenio.template.load('websearch')
except:
pass
## global vars:
search_cache = {} # will cache results of previous searches
cfg_nb_browse_seen_records = 100 # limit of the number of records to check when browsing certain collection
cfg_nicely_ordered_collection_list = 0 # do we propose collection list nicely ordered or alphabetical?
## precompile some often-used regexp for speed reasons:
sre_word = sre.compile('[\s]')
sre_quotes = sre.compile('[\'\"]')
sre_doublequote = sre.compile('\"')
sre_equal = sre.compile('\=')
sre_logical_and = sre.compile('\sand\s', sre.I)
sre_logical_or = sre.compile('\sor\s', sre.I)
sre_logical_not = sre.compile('\snot\s', sre.I)
sre_operators = sre.compile(r'\s([\+\-\|])\s')
sre_pattern_wildcards_at_beginning = sre.compile(r'(\s)[\*\%]+')
sre_pattern_single_quotes = sre.compile("'(.*?)'")
sre_pattern_double_quotes = sre.compile("\"(.*?)\"")
sre_pattern_regexp_quotes = sre.compile("\/(.*?)\/")
sre_pattern_short_words = sre.compile(r'([\s\"]\w{1,3})[\*\%]+')
sre_pattern_space = sre.compile("__SPACE__")
sre_pattern_today = sre.compile("\$TODAY\$")
sre_unicode_lowercase_a = sre.compile(unicode(r"(?u)[áàäâãå]", "utf-8"))
sre_unicode_lowercase_ae = sre.compile(unicode(r"(?u)[æ]", "utf-8"))
sre_unicode_lowercase_e = sre.compile(unicode(r"(?u)[éèëê]", "utf-8"))
sre_unicode_lowercase_i = sre.compile(unicode(r"(?u)[íìïî]", "utf-8"))
sre_unicode_lowercase_o = sre.compile(unicode(r"(?u)[óòöôõø]", "utf-8"))
sre_unicode_lowercase_u = sre.compile(unicode(r"(?u)[úùüû]", "utf-8"))
sre_unicode_lowercase_y = sre.compile(unicode(r"(?u)[ýÿ]", "utf-8"))
sre_unicode_lowercase_c = sre.compile(unicode(r"(?u)[çć]", "utf-8"))
sre_unicode_lowercase_n = sre.compile(unicode(r"(?u)[ñ]", "utf-8"))
sre_unicode_uppercase_a = sre.compile(unicode(r"(?u)[ÁÀÄÂÃÅ]", "utf-8"))
sre_unicode_uppercase_ae = sre.compile(unicode(r"(?u)[Æ]", "utf-8"))
sre_unicode_uppercase_e = sre.compile(unicode(r"(?u)[ÉÈËÊ]", "utf-8"))
sre_unicode_uppercase_i = sre.compile(unicode(r"(?u)[ÍÌÏÎ]", "utf-8"))
sre_unicode_uppercase_o = sre.compile(unicode(r"(?u)[ÓÒÖÔÕØ]", "utf-8"))
sre_unicode_uppercase_u = sre.compile(unicode(r"(?u)[ÚÙÜÛ]", "utf-8"))
sre_unicode_uppercase_y = sre.compile(unicode(r"(?u)[Ý]", "utf-8"))
sre_unicode_uppercase_c = sre.compile(unicode(r"(?u)[ÇĆ]", "utf-8"))
sre_unicode_uppercase_n = sre.compile(unicode(r"(?u)[Ñ]", "utf-8"))
def get_alphabetically_ordered_collection_list(collid=1, level=0):
"""Returns nicely ordered (score respected) list of collections, more exactly list of tuples
(collection name, printable collection name).
Suitable for create_search_box()."""
out = []
query = "SELECT id,name FROM collection ORDER BY name ASC"
res = run_sql(query)
for c_id, c_name in res:
# make a nice printable name (e.g. truncate c_printable for for long collection names):
if len(c_name)>30:
c_printable = c_name[:30] + "..."
else:
c_printable = c_name
if level:
c_printable = " " + level * '-' + " " + c_printable
out.append([c_name, c_printable])
return out
def get_nicely_ordered_collection_list(collid=1, level=0):
"""Returns nicely ordered (score respected) list of collections, more exactly list of tuples
(collection name, printable collection name).
Suitable for create_search_box()."""
colls_nicely_ordered = []
query = "SELECT c.name,cc.id_son FROM collection_collection AS cc, collection AS c "\
" WHERE c.id=cc.id_son AND cc.id_dad='%s' ORDER BY score DESC" % collid
res = run_sql(query)
for c, cid in res:
# make a nice printable name (e.g. truncate c_printable for for long collection names):
if len(c)>30:
c_printable = c[:30] + "..."
else:
c_printable = c
if level:
c_printable = " " + level * '-' + " " + c_printable
colls_nicely_ordered.append([c, c_printable])
colls_nicely_ordered = colls_nicely_ordered + get_nicely_ordered_collection_list(cid, level+1)
return colls_nicely_ordered
def get_index_id(field):
"""Returns first index id where the field code FIELD is indexed.
Returns zero in case there is no table for this index.
Example: field='author', output=4."""
out = 0
query = """SELECT w.id FROM idxINDEX AS w, idxINDEX_field AS wf, field AS f
WHERE f.code='%s' AND wf.id_field=f.id AND w.id=wf.id_idxINDEX
LIMIT 1""" % escape_string(field)
res = run_sql(query, None, 1)
if res:
out = res[0][0]
return out
def get_words_from_pattern(pattern):
"Returns list of whitespace-separated words from pattern."
words = {}
for word in split(pattern):
if not words.has_key(word):
words[word] = 1;
return words.keys()
def create_basic_search_units(req, p, f, m=None, of='hb'):
"""Splits search pattern and search field into a list of independently searchable units.
- A search unit consists of '(operator, pattern, field, type, hitset)' tuples where
'operator' is set union (|), set intersection (+) or set exclusion (-);
'pattern' is either a word (e.g. muon*) or a phrase (e.g. 'nuclear physics');
'field' is either a code like 'title' or MARC tag like '100__a';
'type' is the search type ('w' for word file search, 'a' for access file search).
- Optionally, the function accepts the match type argument 'm'.
If it is set (e.g. from advanced search interface), then it
performs this kind of matching. If it is not set, then a guess is made.
'm' can have values: 'a'='all of the words', 'o'='any of the words',
'p'='phrase/substring', 'r'='regular expression',
'e'='exact value'.
- Warnings are printed on req (when not None) in case of HTML output formats."""
opfts = [] # will hold (o,p,f,t,h) units
## check arguments: if matching type phrase/string/regexp, do we have field defined?
if (m=='p' or m=='r' or m=='e') and not f:
m = 'a'
if of.startswith("h"):
print_warning(req, "This matching type cannot be used within any field. I will perform a word search instead." )
print_warning(req, "If you want to phrase/substring/regexp search in a specific field, e.g. inside title, then please choose within title search option.")
## is desired matching type set?
if m:
## A - matching type is known; good!
if m == 'e':
# A1 - exact value:
opfts.append(['+',p,f,'a']) # '+' since we have only one unit
elif m == 'p':
# A2 - phrase/substring:
opfts.append(['+',"%"+p+"%",f,'a']) # '+' since we have only one unit
elif m == 'r':
# A3 - regular expression:
opfts.append(['+',p,f,'r']) # '+' since we have only one unit
elif m == 'a' or m == 'w':
# A4 - all of the words:
p = strip_accents(p) # strip accents for 'w' mode, FIXME: delete when not needed
for word in get_words_from_pattern(p):
opfts.append(['+',word,f,'w']) # '+' in all units
elif m == 'o':
# A5 - any of the words:
p = strip_accents(p) # strip accents for 'w' mode, FIXME: delete when not needed
for word in get_words_from_pattern(p):
if len(opfts)==0:
opfts.append(['+',word,f,'w']) # '+' in the first unit
else:
opfts.append(['|',word,f,'w']) # '|' in further units
else:
if of.startswith("h"):
print_warning(req, "Matching type '%s' is not implemented yet." % m, "Warning")
opfts.append(['+',"%"+p+"%",f,'a'])
else:
## B - matching type is not known: let us try to determine it by some heuristics
if f and p[0]=='"' and p[-1]=='"':
## B0 - does 'p' start and end by double quote, and is 'f' defined? => doing ACC search
opfts.append(['+',p[1:-1],f,'a'])
elif f and p[0]=="'" and p[-1]=="'":
## B0bis - does 'p' start and end by single quote, and is 'f' defined? => doing ACC search
opfts.append(['+','%'+p[1:-1]+'%',f,'a'])
elif f and p[0]=="/" and p[-1]=="/":
## B0ter - does 'p' start and end by a slash, and is 'f' defined? => doing regexp search
opfts.append(['+',p[1:-1],f,'r'])
elif f and string.find(p, ',') >= 0:
## B1 - does 'p' contain comma, and is 'f' defined? => doing ACC search
opfts.append(['+',p,f,'a'])
elif f and str(f[0:2]).isdigit():
## B2 - does 'f' exist and starts by two digits? => doing ACC search
opfts.append(['+',p,f,'a'])
else:
## B3 - doing WRD search, but maybe ACC too
# search units are separated by spaces unless the space is within single or double quotes
# so, let us replace temporarily any space within quotes by '__SPACE__'
p = sre_pattern_single_quotes.sub(lambda x: "'"+string.replace(x.group(1), ' ', '__SPACE__')+"'", p)
p = sre_pattern_double_quotes.sub(lambda x: "\""+string.replace(x.group(1), ' ', '__SPACE__')+"\"", p)
p = sre_pattern_regexp_quotes.sub(lambda x: "/"+string.replace(x.group(1), ' ', '__SPACE__')+"/", p)
# wash argument:
p = sre_equal.sub(":", p)
p = sre_logical_and.sub(" ", p)
p = sre_logical_or.sub(" |", p)
p = sre_logical_not.sub(" -", p)
p = sre_operators.sub(r' \1', p)
for pi in split(p): # iterate through separated units (or items, as "pi" stands for "p item")
pi = sre_pattern_space.sub(" ", pi) # replace back '__SPACE__' by ' '
# firstly, determine set operator
if pi[0] == '+' or pi[0] == '-' or pi[0] == '|':
oi = pi[0]
pi = pi[1:]
else:
# okay, there is no operator, so let us decide what to do by default
oi = '+' # by default we are doing set intersection...
# secondly, determine search pattern and field:
if string.find(pi, ":") > 0:
fi, pi = split(pi, ":", 1)
else:
fi, pi = f, pi
# look also for old ALEPH field names:
if fi and cfg_fields_convert.has_key(string.lower(fi)):
fi = cfg_fields_convert[string.lower(fi)]
# wash 'pi' argument:
if sre_quotes.match(pi):
# B3a - quotes are found => do ACC search (phrase search)
if fi:
if pi[0] == '"' and pi[-1] == '"':
pi = string.replace(pi, '"', '') # remove quote signs
opfts.append([oi,pi,fi,'a'])
elif pi[0] == "'" and pi[-1] == "'":
pi = string.replace(pi, "'", "") # remove quote signs
opfts.append([oi,"%"+pi+"%",fi,'a'])
else: # unbalanced quotes, so do WRD query:
opfts.append([oi,pi,fi,'w'])
else:
# fi is not defined, look at where we are doing exact or subphrase search (single/double quotes):
if pi[0]=='"' and pi[-1]=='"':
opfts.append([oi,pi[1:-1],"anyfield",'a'])
if of.startswith("h"):
print_warning(req, "Searching for an exact match inside any field may be slow. You may want to search for words instead, or choose to search within specific field.")
else:
# nope, subphrase in global index is not possible => change back to WRD search
pi = strip_accents(pi) # strip accents for 'w' mode, FIXME: delete when not needed
for pii in get_words_from_pattern(pi):
# since there may be '-' and other chars that we do not index in WRD
opfts.append([oi,pii,fi,'w'])
if of.startswith("h"):
print_warning(req, "The partial phrase search does not work in any field. I'll do a boolean AND searching instead.")
print_warning(req, "If you want to do a partial phrase search in a specific field, e.g. inside title, then please choose 'within title' search option.", "Tip")
print_warning(req, "If you want to do exact phrase matching, then please use double quotes.", "Tip")
elif fi and str(fi[0]).isdigit() and str(fi[0]).isdigit():
# B3b - fi exists and starts by two digits => do ACC search
opfts.append([oi,pi,fi,'a'])
elif fi and not get_index_id(fi):
# B3c - fi exists but there is no words table for fi => try ACC search
opfts.append([oi,pi,fi,'a'])
elif fi and pi.startswith('/') and pi.endswith('/'):
# B3d - fi exists and slashes found => try regexp search
opfts.append([oi,pi[1:-1],fi,'r'])
else:
# B3e - general case => do WRD search
pi = strip_accents(pi) # strip accents for 'w' mode, FIXME: delete when not needed
for pii in get_words_from_pattern(pi):
opfts.append([oi,pii,fi,'w'])
## sanity check:
for i in range(0,len(opfts)):
try:
pi = opfts[i][1]
if pi == '*':
if of.startswith("h"):
print_warning(req, "Ignoring standalone wildcard word.", "Warning")
del opfts[i]
if pi == '' or pi == ' ':
fi = opfts[i][2]
if fi:
if of.startswith("h"):
print_warning(req, "Ignoring empty %s search term." % fi, "Warning")
del opfts[i]
except:
pass
## return search units:
return opfts
def page_start(req, of, cc, as, ln, uid, title_message=None,
description='', keywords=''):
"Start page according to given output format."
_ = gettext_set_language(ln)
if not title_message: title_message = _("Search Results")
if not req:
return # we were called from CLI
if of.startswith('x'):
# we are doing XML output:
req.content_type = "text/xml"
req.send_http_header()
req.write("""\n""")
if of.startswith("xm"):
req.write("""\n""")
else:
req.write("""\n""")
elif of.startswith('t') or str(of[0:3]).isdigit():
# we are doing plain text output:
req.content_type = "text/plain"
req.send_http_header()
elif of == "id":
pass # nothing to do, we shall only return list of recIDs
else:
# we are doing HTML output:
req.content_type = "text/html"
req.send_http_header()
if not description:
description = "%s %s." % (cc, _("Search Results"))
if not keywords:
keywords = "CDS Invenio, WebSearch, %s" % cc
req.write(pageheaderonly(req=req, title=title_message,
navtrail=create_navtrail_links(cc, as, ln),
description=description,
keywords=keywords,
uid=uid,
language=ln))
req.write(websearch_templates.tmpl_search_pagestart(ln=ln))
def page_end(req, of="hb", ln=cdslang):
"End page according to given output format: e.g. close XML tags, add HTML footer, etc."
if of == "id":
return [] # empty recID list
if not req:
return # we were called from CLI
if of.startswith('h'):
req.write(websearch_templates.tmpl_search_pageend(ln = ln)) # pagebody end
req.write(pagefooteronly(lastupdated=__lastupdated__, language=ln, req=req))
elif of.startswith('x'):
req.write("""\n""")
return "\n"
def create_inputdate_box(name="d1", selected_year=0, selected_month=0, selected_day=0, ln=cdslang):
"Produces 'From Date', 'Until Date' kind of selection box. Suitable for search options."
_ = gettext_set_language(ln)
box = ""
# day
box += """"""
# month
box += """"""
# year
box += """"""
return box
def create_google_box(cc, p, f, p1, p2, p3, ln=cdslang,
prolog_start="""
""",
prolog_end="""
""",
column_separator="""
""",
link_separator= """ """,
epilog="""
"""):
"Creates the box that proposes links to other useful search engines like Google. 'p' is the search pattern."
if not p and (p1 or p2 or p3):
p = p1 + " " + p2 + " " + p3
# check suitable p's whether we want to print it
if cfg_google_box == 0 or \
p == "" or \
string.find(p, "recid:")>=0 or \
string.find(p, "sysno:")>=0 or \
string.find(p, "sysnos:")>=0:
return ""
# remove our logical field index names:
p = sre.sub(r'\w+:', '', p)
return websearch_templates.tmpl_google_box(
ln = ln,
cc = cc,
p = p,
f = f,
prolog_start = prolog_start,
prolog_end = prolog_end,
column_separator = column_separator,
link_separator = link_separator,
epilog = epilog,
)
def create_search_box(cc, colls, p, f, rg, sf, so, sp, rm, of, ot, as,
ln, p1, f1, m1, op1, p2, f2, m2, op2, p3, f3,
m3, sc, pl, d1y, d1m, d1d, d2y, d2m, d2d, jrec,
action=""):
"Create search box for 'search again in the results page' functionality."
# load the right message language
_ = gettext_set_language(ln)
# some computations
if cc == cdsname:
cc_intl = cdsnameintl[ln]
else:
cc_intl = get_coll_i18nname(cc, ln)
colls_nicely_ordered = []
if cfg_nicely_ordered_collection_list:
colls_nicely_ordered = get_nicely_ordered_collection_list()
else:
colls_nicely_ordered = get_alphabetically_ordered_collection_list()
colls_nice = []
for (cx, cx_printable) in colls_nicely_ordered:
if not cx.startswith("Unnamed collection"):
colls_nice.append({ 'value' : cx,
'text' : cx_printable
})
coll_selects = []
if colls and colls[0] != cdsname:
# some collections are defined, so print these first, and only then print 'add another collection' heading:
for c in colls:
if c:
temp = []
temp.append({ 'value' : '',
'text' : '*** %s ***' % _("any collection")
})
for val in colls_nice:
# print collection:
if not cx.startswith("Unnamed collection"):
temp.append({ 'value' : val['value'],
'text' : val['text'],
'selected' : (c == sre.sub("^[\s\-]*","", val['value']))
})
coll_selects.append(temp)
coll_selects.append([{ 'value' : '',
'text' : '*** %s ***' % _("add another collection")
}] + colls_nice)
else: # we searched in CDSNAME, so print 'any collection' heading
coll_selects.append([{ 'value' : '',
'text' : '*** %s ***' % _("any collection")
}] + colls_nice)
sort_formats = [{
'value' : '',
'text' : _("latest first")
}]
query = """SELECT DISTINCT(f.code),f.name FROM field AS f, collection_field_fieldvalue AS cff
WHERE cff.type='soo' AND cff.id_field=f.id
ORDER BY cff.score DESC, f.name ASC"""
res = run_sql(query)
for code, name in res:
sort_formats.append({
'value' : code,
'text' : name,
})
## ranking methods
ranks = [{
'value' : '',
'text' : "- %s %s -" % (_("OR").lower (), _("rank by")),
}]
for (code,name) in get_bibrank_methods(get_colID(cc), ln):
# propose found rank methods:
ranks.append({
'value' : code,
'text' : name,
})
formats = []
query = """SELECT code,name FROM format ORDER BY name ASC"""
res = run_sql(query)
if res:
# propose found formats:
for code, name in res:
formats.append({ 'value' : code,
'text' : name
})
else:
formats.append({'value' : 'hb',
'text' : _("HTML brief")
})
return websearch_templates.tmpl_search_box(
ln = ln,
as = as,
cc_intl = cc_intl,
cc = cc,
ot = ot,
sp = sp,
action = action,
fieldslist = get_searchwithin_fields(ln = ln),
f1 = f1,
f2 = f2,
f3 = f3,
m1 = m1,
m2 = m2,
m3 = m3,
p1 = p1,
p2 = p2,
p3 = p3,
op1 = op1,
op2 = op2,
rm = rm,
p = p,
f = f,
coll_selects = coll_selects,
d1y = d1y, d2y = d2y, d1m = d1m, d2m = d2m, d1d = d1d, d2d = d2d,
sort_formats = sort_formats,
sf = sf,
so = so,
ranks = ranks,
sc = sc,
rg = rg,
formats = formats,
of = of,
pl = pl,
jrec=jrec,
)
def create_navtrail_links(cc=cdsname, as=0, ln=cdslang, self_p=1):
"""Creates navigation trail links, i.e. links to collection
ancestors (except Home collection). If as==1, then links to
Advanced Search interfaces; otherwise Simple Search.
"""
dads = []
for dad in get_coll_ancestors(cc):
if dad != cdsname: # exclude Home collection
dads.append ((dad, get_coll_i18nname (dad, ln)))
if self_p and cc != cdsname:
dads.append((cc, get_coll_i18nname(cc, ln)))
return websearch_templates.tmpl_navtrail_links(
as=as, ln=ln, dads=dads)
def create_searchwithin_selection_box(fieldname='f', value='', ln='en'):
"Produces 'search within' selection box for the current collection."
out = ""
out += """"""
return out
def get_searchwithin_fields(ln='en'):
"Retrieves the fields name used in the 'search within' selection box for the current collection."
query = "SELECT code,name FROM field ORDER BY name ASC"
res = run_sql(query)
fields = [{
'value' : '',
'text' : get_field_i18nname("any field", ln)
}]
for field_code, field_name in res:
if field_code and field_code != "anyfield":
fields.append({ 'value' : field_code,
'text' : get_field_i18nname(field_name, ln)
})
return fields
def create_andornot_box(name='op', value='', ln='en'):
"Returns HTML code for the AND/OR/NOT selection box."
_ = gettext_set_language(ln)
out = """
""" % (name,
is_selected('a', value), _("AND"),
is_selected('o', value), _("OR"),
is_selected('n', value), _("AND NOT"))
return out
def create_matchtype_box(name='m', value='', ln='en'):
"Returns HTML code for the 'match type' selection box."
_ = gettext_set_language(ln)
out = """
""" % (name,
is_selected('a', value), _("All of the words:"),
is_selected('o', value), _("Any of the words:"),
is_selected('e', value), _("Exact phrase:"),
is_selected('p', value), _("Partial phrase:"),
is_selected('r', value), _("Regular expression:"))
return out
def is_selected(var, fld):
"Checks if the two are equal, and if yes, returns ' selected'. Useful for select boxes."
if type(var) is int and type(fld) is int:
if var == fld:
return " selected"
elif str(var) == str(fld):
return " selected"
elif fld and len(fld)==3 and fld[0] == "w" and var == fld[1:]:
return " selected"
return ""
def urlargs_replace_text_in_arg(urlargs, regexp_argname, text_old, text_new):
"""Analyze `urlargs' (URL CGI GET query arguments) and for each
occurrence of argument matching `regexp_argname' replace every
substring `text_old' by `text_new'. Return the resulting URL.
Useful for create_nearest_terms_box."""
out = ""
# parse URL arguments into a dictionary:
urlargsdict = cgi.parse_qs(urlargs)
## construct new URL arguments:
urlargsdictnew = {}
for key in urlargsdict.keys():
if sre.match(regexp_argname, key): # replace `arg' by new values
urlargsdictnew[key] = []
for parg in urlargsdict[key]:
urlargsdictnew[key].append(string.replace(parg, text_old, text_new))
else: # keep old values
urlargsdictnew[key] = urlargsdict[key]
# build new URL for this word:
for key in urlargsdictnew.keys():
for val in urlargsdictnew[key]:
out += "&" + key + "=" + urllib.quote_plus(val, '')
if out.startswith("&"):
out = out[1:]
return out
class HitSet:
"""Class describing set of records, implemented as bit vectors of recIDs.
Using Numeric arrays for speed (1 value = 8 bits), can use later "real"
bit vectors to save space."""
def __init__(self, init_set=None):
self._nbhits = -1
if init_set:
self._set = init_set
else:
self._set = Numeric.zeros(cfg_max_recID+1, Numeric.Int0)
def __repr__(self, join=string.join):
return "%s(%s)" % (self.__class__.__name__, join(map(repr, self._set), ', '))
def add(self, recID):
"Adds a record to the set."
self._set[recID] = 1
def addmany(self, recIDs):
"Adds several recIDs to the set."
for recID in recIDs: self._set[recID] = 1
def addlist(self, arr):
"Adds an array of recIDs to the set."
Numeric.put(self._set, arr, 1)
def remove(self, recID):
"Removes a record from the set."
self._set[recID] = 0
def removemany(self, recIDs):
"Removes several records from the set."
for recID in recIDs:
self.remove(recID)
def intersect(self, other):
"Does a set intersection with other. Keep result in self."
self._set = Numeric.bitwise_and(self._set, other._set)
def union(self, other):
"Does a set union with other. Keep result in self."
self._set = Numeric.bitwise_or(self._set, other._set)
def difference(self, other):
"Does a set difference with other. Keep result in self."
#self._set = Numeric.bitwise_not(self._set, other._set)
for recID in Numeric.nonzero(other._set):
self.remove(recID)
def contains(self, recID):
"Checks whether the set contains recID."
return self._set[recID]
__contains__ = contains # Higher performance member-test for python 2.0 and above
def __getitem__(self, index):
"Support for the 'for item in set:' protocol."
return Numeric.nonzero(self._set)[index]
def calculate_nbhits(self):
"Calculates the number of records set in the hitset."
self._nbhits = Numeric.sum(self._set.copy().astype(Numeric.Int))
def items(self):
"Return an array containing all recID."
return Numeric.nonzero(self._set)
def tolist(self):
"Return an array containing all recID."
return Numeric.nonzero(self._set).tolist()
# speed up HitSet operations by ~20% if Psyco is installed:
try:
import psyco
psyco.bind(HitSet)
except:
pass
def wash_colls(cc, c, split_colls=0):
"""Wash collection list by checking whether user has deselected
anything under 'Narrow search'. Checks also if cc is a list or not.
Return list of cc, colls_to_display, colls_to_search since the list
of collections to display is different from that to search in.
This is because users might have chosen 'split by collection'
functionality.
The behaviour of "collections to display" depends solely whether
user has deselected a particular collection: e.g. if it started
from 'Articles and Preprints' page, and deselected 'Preprints',
then collection to display is 'Articles'. If he did not deselect
anything, then collection to display is 'Articles & Preprints'.
The behaviour of "collections to search in" depends on the
'split_colls' parameter:
* if is equal to 1, then we can wash the colls list down
and search solely in the collection the user started from;
* if is equal to 0, then we are splitting to the first level
of collections, i.e. collections as they appear on the page
we started to search from;
"""
colls_out = []
colls_out_for_display = []
# check what type is 'cc':
if type(cc) is list:
for ci in cc:
if collection_reclist_cache.has_key(ci):
# yes this collection is real, so use it:
cc = ci
break
else:
# check once if cc is real:
if not collection_reclist_cache.has_key(cc):
cc = cdsname # cc is not real, so replace it with Home collection
# check type of 'c' argument:
if type(c) is list:
colls = c
else:
colls = [c]
# remove all 'unreal' collections:
colls_real = []
for coll in colls:
if collection_reclist_cache.has_key(coll):
colls_real.append(coll)
colls = colls_real
# check if some real collections remain:
if len(colls)==0:
colls = [cc]
# then let us check the list of non-restricted "real" sons of 'cc' and compare it to 'coll':
query = "SELECT c.name FROM collection AS c, collection_collection AS cc, collection AS ccc WHERE c.id=cc.id_son AND cc.id_dad=ccc.id AND ccc.name='%s' AND cc.type='r' AND c.restricted IS NULL" % escape_string(cc)
res = run_sql(query)
l_cc_nonrestricted_sons = []
l_c = colls
for row in res:
l_cc_nonrestricted_sons.append(row[0])
l_c.sort()
l_cc_nonrestricted_sons.sort()
if l_cc_nonrestricted_sons == l_c:
colls_out_for_display = [cc] # yep, washing permitted, it is sufficient to display 'cc'
else:
colls_out_for_display = colls # nope, we need to display all 'colls' successively
# remove duplicates:
colls_out_for_display_nondups=filter(lambda x, colls_out_for_display=colls_out_for_display: colls_out_for_display[x-1] not in colls_out_for_display[x:], range(1, len(colls_out_for_display)+1))
colls_out_for_display = map(lambda x, colls_out_for_display=colls_out_for_display:colls_out_for_display[x-1], colls_out_for_display_nondups)
# second, let us decide on collection splitting:
if split_colls == 0:
# type A - no sons are wanted
colls_out = colls_out_for_display
# elif split_colls == 1:
else:
# type B - sons (first-level descendants) are wanted
for coll in colls_out_for_display:
coll_sons = get_coll_sons(coll)
if coll_sons == []:
colls_out.append(coll)
else:
colls_out = colls_out + coll_sons
# remove duplicates:
colls_out_nondups=filter(lambda x, colls_out=colls_out: colls_out[x-1] not in colls_out[x:], range(1, len(colls_out)+1))
colls_out = map(lambda x, colls_out=colls_out:colls_out[x-1], colls_out_nondups)
return (cc, colls_out_for_display, colls_out)
def strip_accents(x):
"""Strip accents in the input phrase X (assumed in UTF-8) by replacing
accented characters with their unaccented cousins (e.g. é by e).
Return such a stripped X."""
# convert input into Unicode string:
try:
y = unicode(x, "utf-8")
except:
return x # something went wrong, probably the input wasn't UTF-8
# asciify Latin-1 lowercase characters:
y = sre_unicode_lowercase_a.sub("a", y)
y = sre_unicode_lowercase_ae.sub("ae", y)
y = sre_unicode_lowercase_e.sub("e", y)
y = sre_unicode_lowercase_i.sub("i", y)
y = sre_unicode_lowercase_o.sub("o", y)
y = sre_unicode_lowercase_u.sub("u", y)
y = sre_unicode_lowercase_y.sub("y", y)
y = sre_unicode_lowercase_c.sub("c", y)
y = sre_unicode_lowercase_n.sub("n", y)
# asciify Latin-1 uppercase characters:
y = sre_unicode_uppercase_a.sub("A", y)
y = sre_unicode_uppercase_ae.sub("AE", y)
y = sre_unicode_uppercase_e.sub("E", y)
y = sre_unicode_uppercase_i.sub("I", y)
y = sre_unicode_uppercase_o.sub("O", y)
y = sre_unicode_uppercase_u.sub("U", y)
y = sre_unicode_uppercase_y.sub("Y", y)
y = sre_unicode_uppercase_c.sub("C", y)
y = sre_unicode_uppercase_n.sub("N", y)
# return UTF-8 representation of the Unicode string:
return y.encode("utf-8")
def wash_pattern(p):
"""Wash pattern passed by URL. Check for sanity of the wildcard by
removing wildcards if they are appended to extremely short words
(1-3 letters). TODO: instead of this approximative treatment, it
will be much better to introduce a temporal limit, e.g. to kill a
query if it does not finish in 10 seconds."""
# strip accents:
# p = strip_accents(p) # FIXME: when available, strip accents all the time
# add leading/trailing whitespace for the two following wildcard-sanity checking regexps:
p = " " + p + " "
# get rid of wildcards at the beginning of words:
p = sre_pattern_wildcards_at_beginning.sub("\\1", p)
# replace spaces within quotes by __SPACE__ temporarily:
p = sre_pattern_single_quotes.sub(lambda x: "'"+string.replace(x.group(1), ' ', '__SPACE__')+"'", p)
p = sre_pattern_double_quotes.sub(lambda x: "\""+string.replace(x.group(1), ' ', '__SPACE__')+"\"", p)
p = sre_pattern_regexp_quotes.sub(lambda x: "/"+string.replace(x.group(1), ' ', '__SPACE__')+"/", p)
# get rid of extremely short words (1-3 letters with wildcards):
p = sre_pattern_short_words.sub("\\1", p)
# replace back __SPACE__ by spaces:
p = sre_pattern_space.sub(" ", p)
# replace special terms:
p = sre_pattern_today.sub(time.strftime("%Y-%m-%d", time.localtime()), p)
# remove unnecessary whitespace:
p = string.strip(p)
return p
def wash_field(f):
"""Wash field passed by URL."""
# get rid of unnecessary whitespace:
f = string.strip(f)
# wash old-style CDS Invenio/ALEPH 'f' field argument, e.g. replaces 'wau' and 'au' by 'author'
if cfg_fields_convert.has_key(string.lower(f)):
f = cfg_fields_convert[f]
return f
def wash_dates(d1y=0, d1m=0, d1d=0, d2y=0, d2m=0, d2d=0):
"""Take user-submitted washed date arguments (D1Y, D1M, D1Y) and
(D2Y, D2M, D2Y) and return (YYY1-M1-D2, YYY2-M2-D2) strings in the
YYYY-MM-DD format suitable for time restricted searching.
I.e. pay attention when months are not there to put 01 or 12
according to whether it's the starting or the ending date, etc.
"""
day1, day2 = "", ""
# sanity checking:
if d1y==0 and d1m==0 and d1d==0 and d2y==0 and d2m==0 and d2d==0:
return ("", "") # nothing selected, so return empty values
# construct day1 (from):
if d1y:
day1 += "%04d" % d1y
else:
day1 += "0000"
if d1m:
day1 += "-%02d" % d1m
else:
day1 += "-01"
if d1d:
day1 += "-%02d" % d1d
else:
day1 += "-01"
# construct day2 (until):
if d2y:
day2 += "%04d" % d2y
else:
day2 += "9999"
if d2m:
day2 += "-%02d" % d2m
else:
day2 += "-12"
if d2d:
day2 += "-%02d" % d2d
else:
day2 += "-31" # NOTE: perhaps we should add max(datenumber) in
# given month, but for our quering it's not
# needed, 31 will always do
# okay, return constructed YYYY-MM-DD dates
return (day1, day2)
def get_colID(c):
"Return collection ID for collection name C. Return None if no match found."
colID = None
res = run_sql("SELECT id FROM collection WHERE name=%s", (c,), 1)
if res:
colID = res[0][0]
return colID
def get_coll_i18nname(c, ln=cdslang):
"""Return nicely formatted collection name (of name type 'ln',
'long name') for collection C in language LN."""
global collection_i18nname_cache
global collection_i18nname_cache_timestamp
# firstly, check whether the collectionname table was modified:
res = run_sql("SHOW TABLE STATUS LIKE 'collectionname'")
if res and str(res[0][11])>collection_i18nname_cache_timestamp:
# yes it was, cache clear-up needed:
collection_i18nname_cache = create_collection_i18nname_cache()
# secondly, read i18n name from either the cache or return common name:
out = c
try:
out = collection_i18nname_cache[c][ln]
except KeyError:
pass # translation in LN does not exist
return out
def get_field_i18nname(f, ln=cdslang):
"""Return nicely formatted field name (of type 'ln', 'long name')
for field F in language LN."""
global field_i18nname_cache
global field_i18nname_cache_timestamp
# firstly, check whether the fieldname table was modified:
res = run_sql("SHOW TABLE STATUS LIKE 'fieldname'")
if res and str(res[0][11])>field_i18nname_cache_timestamp:
# yes it was, cache clear-up needed:
field_i18nname_cache = create_field_i18nname_cache()
# secondly, read i18n name from either the cache or return common name:
out = f
try:
out = field_i18nname_cache[f][ln]
except KeyError:
pass # translation in LN does not exist
return out
def get_coll_ancestors(coll):
"Returns a list of ancestors for collection 'coll'."
coll_ancestors = []
coll_ancestor = coll
while 1:
query = "SELECT c.name FROM collection AS c "\
"LEFT JOIN collection_collection AS cc ON c.id=cc.id_dad "\
"LEFT JOIN collection AS ccc ON ccc.id=cc.id_son "\
"WHERE ccc.name='%s' ORDER BY cc.id_dad ASC LIMIT 1" \
% escape_string(coll_ancestor)
res = run_sql(query, None, 1)
if res:
coll_name = res[0][0]
coll_ancestors.append(coll_name)
coll_ancestor = coll_name
else:
break
# ancestors found, return reversed list:
coll_ancestors.reverse()
return coll_ancestors
def get_coll_sons(coll, type='r', public_only=1):
"""Return a list of sons (first-level descendants) of type 'type' for collection 'coll'.
If public_only, then return only non-restricted son collections.
"""
coll_sons = []
query = "SELECT c.name FROM collection AS c "\
"LEFT JOIN collection_collection AS cc ON c.id=cc.id_son "\
"LEFT JOIN collection AS ccc ON ccc.id=cc.id_dad "\
"WHERE cc.type='%s' AND ccc.name='%s'" \
% (escape_string(type), escape_string(coll))
if public_only:
query += " AND c.restricted IS NULL "
query += " ORDER BY cc.score DESC"
res = run_sql(query)
for name in res:
coll_sons.append(name[0])
return coll_sons
def get_coll_real_descendants(coll):
"""Return a list of all descendants of collection 'coll' that are defined by a 'dbquery'.
IOW, we need to decompose compound collections like "A & B" into "A" and "B" provided
that "A & B" has no associated database query defined.
"""
coll_sons = []
query = "SELECT c.name,c.dbquery FROM collection AS c "\
"LEFT JOIN collection_collection AS cc ON c.id=cc.id_son "\
"LEFT JOIN collection AS ccc ON ccc.id=cc.id_dad "\
"WHERE ccc.name='%s' ORDER BY cc.score DESC" \
% escape_string(coll)
res = run_sql(query)
for name, dbquery in res:
if dbquery: # this is 'real' collection, so return it:
coll_sons.append(name)
else: # this is 'composed' collection, so recurse:
coll_sons.extend(get_coll_real_descendants(name))
return coll_sons
def get_collection_reclist(coll):
"""Return hitset of recIDs that belong to the collection 'coll'.
But firstly check the last updated date of the collection table.
If it's newer than the cache timestamp, then empty the cache,
since new records could have been added."""
global collection_reclist_cache
global collection_reclist_cache_timestamp
# firstly, check whether the collection table was modified:
res = run_sql("SHOW TABLE STATUS LIKE 'collection'")
if res and str(res[0][11])>collection_reclist_cache_timestamp:
# yes it was, cache clear-up needed:
collection_reclist_cache = create_collection_reclist_cache()
# secondly, read reclist from either the cache or the database:
if not collection_reclist_cache[coll]:
# not yet it the cache, so calculate it and fill the cache:
set = HitSet()
query = "SELECT nbrecs,reclist FROM collection WHERE name='%s'" % coll
res = run_sql(query, None, 1)
if res:
try:
set._nbhits, set._set = res[0][0], Numeric.loads(zlib.decompress(res[0][1]))
except:
set._nbhits = 0
collection_reclist_cache[coll] = set
# finally, return reclist:
return collection_reclist_cache[coll]
def coll_restricted_p(coll):
"Predicate to test if the collection coll is restricted or not."
if not coll:
return 0
query = "SELECT restricted FROM collection WHERE name='%s'" % escape_string(coll)
res = run_sql(query, None, 1)
if res and res[0][0] != None:
return 1
else:
return 0
def coll_restricted_group(coll):
"Return Apache group to which the collection is restricted. Return None if it's public."
if not coll:
return None
query = "SELECT restricted FROM collection WHERE name='%s'" % escape_string(coll)
res = run_sql(query, None, 1)
if res:
return res[0][0]
else:
return None
def create_collection_reclist_cache():
"""Creates list of records belonging to collections. Called on startup
and used later for intersecting search results with collection universe."""
global collection_reclist_cache_timestamp
# populate collection reclist cache:
collrecs = {}
try:
res = run_sql("SELECT name,reclist FROM collection")
except Error:
# database problems, set timestamp to zero and return empty cache
collection_reclist_cache_timestamp = 0
return collrecs
for name,reclist in res:
collrecs[name] = None # this will be filled later during runtime by calling get_collection_reclist(coll)
# update timestamp:
try:
collection_reclist_cache_timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
except NameError:
collection_reclist_cache_timestamp = 0
return collrecs
try:
collection_reclist_cache.has_key(cdsname)
except:
try:
collection_reclist_cache = create_collection_reclist_cache()
except:
collection_reclist_cache = {}
def create_collection_i18nname_cache():
"""Create cache of I18N collection names of type 'ln' (=long name).
Called on startup and used later during the search time."""
global collection_i18nname_cache_timestamp
# populate collection I18N name cache:
names = {}
try:
res = run_sql("SELECT c.name,cn.ln,cn.value FROM collectionname AS cn, collection AS c WHERE cn.id_collection=c.id AND cn.type='ln'") # ln=long name
except Error:
# database problems, set timestamp to zero and return empty cache
collection_i18nname_cache_timestamp = 0
return names
for c,ln,i18nname in res:
if i18nname:
try:
names[c]
except KeyError:
names[c] = {}
names[c][ln] = i18nname
# update timestamp:
try:
collection_i18nname_cache_timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
except NameError:
collection_i18nname_cache_timestamp = 0
return names
try:
collection_i18nname_cache.has_key(cdsname)
except:
try:
collection_i18nname_cache = create_collection_i18nname_cache()
except:
collection_i18nname_cache = {}
def create_field_i18nname_cache():
"""Create cache of I18N field names of type 'ln' (=long name).
Called on startup and used later during the search time."""
global field_i18nname_cache_timestamp
# populate field I18 name cache:
names = {}
try:
res = run_sql("SELECT f.name,fn.ln,fn.value FROM fieldname AS fn, field AS f WHERE fn.id_field=f.id AND fn.type='ln'") # ln=long name
except Error:
# database problems, set timestamp to zero and return empty cache
field_i18nname_cache_timestamp = 0
return names
for f,ln,i18nname in res:
if i18nname:
try:
names[f]
except KeyError:
names[f] = {}
names[f][ln] = i18nname
# update timestamp:
try:
field_i18nname_cache_timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
except NameError:
field_i18nname_cache_timestamp = 0
return names
try:
field_i18nname_cache.has_key(cdsname)
except:
try:
field_i18nname_cache = create_field_i18nname_cache()
except:
field_i18nname_cache = {}
def browse_pattern(req, colls, p, f, rg, ln=cdslang):
"""Browse either biliographic phrases or words indexes, and display it."""
# load the right message language
_ = gettext_set_language(ln)
## do we search in words indexes?
if not f:
return browse_in_bibwords(req, p, f)
p_orig = p
## okay, "real browse" follows:
browsed_phrases = get_nearest_terms_in_bibxxx(p, f, rg, 1)
while not browsed_phrases:
# try again and again with shorter and shorter pattern:
try:
p = p[:-1]
browsed_phrases = get_nearest_terms_in_bibxxx(p, f, rg, 1)
except:
# probably there are no hits at all:
req.write(_("No values found."))
return
## try to check hits in these particular collection selection:
browsed_phrases_in_colls = []
if 0:
for phrase in browsed_phrases:
phrase_hitset = HitSet()
phrase_hitsets = search_pattern("", phrase, f, 'e')
for coll in colls:
phrase_hitset.union(phrase_hitsets[coll])
phrase_hitset.calculate_nbhits()
if phrase_hitset._nbhits > 0:
# okay, this phrase has some hits in colls, so add it:
browsed_phrases_in_colls.append([phrase, phrase_hitset._nbhits])
## were there hits in collections?
if browsed_phrases_in_colls == []:
if browsed_phrases != []:
#print_warning(req, """
No match close to %s found in given collections.
#Please try different term.
Displaying matches in any collection...""" % p_orig)
## try to get nbhits for these phrases in any collection:
for phrase in browsed_phrases:
browsed_phrases_in_colls.append([phrase, get_nbhits_in_bibxxx(phrase, f)])
## display results now:
out = websearch_templates.tmpl_browse_pattern(
f=get_field_i18nname(f, ln),
ln=ln,
browsed_phrases_in_colls=browsed_phrases_in_colls,
colls=colls,
)
req.write(out)
return
def browse_in_bibwords(req, p, f, ln=cdslang):
"""Browse inside words indexes."""
if not p:
return
_ = gettext_set_language(ln)
urlargd = {}
urlargd.update(req.argd)
urlargd['action'] = 'search'
nearest_box = create_nearest_terms_box(urlargd, p, f, 'w', ln=ln, intro_text_p=0)
req.write(websearch_templates.tmpl_search_in_bibwords(
p = p,
f = f,
ln = ln,
nearest_box = nearest_box
))
return
def search_pattern(req=None, p=None, f=None, m=None, ap=0, of="id", verbose=0, ln=cdslang):
"""Search for complex pattern 'p' within field 'f' according to
matching type 'm'. Return hitset of recIDs.
The function uses multi-stage searching algorithm in case of no
exact match found. See the Search Internals document for
detailed description.
The 'ap' argument governs whether an alternative patterns are to
be used in case there is no direct hit for (p,f,m). For
example, whether to replace non-alphanumeric characters by
spaces if it would give some hits. See the Search Internals
document for detailed description. (ap=0 forbits the
alternative pattern usage, ap=1 permits it.)
The 'of' argument governs whether to print or not some
information to the user in case of no match found. (Usually it
prints the information in case of HTML formats, otherwise it's
silent).
The 'verbose' argument controls the level of debugging information
to be printed (0=least, 9=most).
All the parameters are assumed to have been previously washed.
This function is suitable as a mid-level API.
"""
_ = gettext_set_language(ln)
hitset_empty = HitSet()
hitset_empty._nbhits = 0
# sanity check:
if not p:
hitset_full = HitSet(Numeric.ones(cfg_max_recID+1, Numeric.Int0))
hitset_full._nbhits = cfg_max_recID
# no pattern, so return all universe
return hitset_full
# search stage 1: break up arguments into basic search units:
if verbose and of.startswith("h"):
t1 = os.times()[4]
basic_search_units = create_basic_search_units(req, p, f, m, of)
if verbose and of.startswith("h"):
t2 = os.times()[4]
print_warning(req, "Search stage 1: basic search units are: %s" % basic_search_units)
print_warning(req, "Search stage 1: execution took %.2f seconds." % (t2 - t1))
# search stage 2: do search for each search unit and verify hit presence:
if verbose and of.startswith("h"):
t1 = os.times()[4]
basic_search_units_hitsets = []
for idx_unit in range(0,len(basic_search_units)):
bsu_o, bsu_p, bsu_f, bsu_m = basic_search_units[idx_unit]
basic_search_unit_hitset = search_unit(bsu_p, bsu_f, bsu_m)
if verbose >= 9 and of.startswith("h"):
print_warning(req, "Search stage 1: pattern %s gave hitlist %s" % (bsu_p, Numeric.nonzero(basic_search_unit_hitset._set)))
if basic_search_unit_hitset._nbhits>0 or \
ap==0 or \
bsu_o=="|" or \
((idx_unit+1) 0:
# we retain the new unit instead
if of.startswith('h'):
- print_warning(req, _("No exact match found for %s, using %s instead...") % (""+bsu_p+"",
- ""+bsu_pn+""))
+ print_warning(req, _("No exact match found for %(x_query1)s, using %(x_query2)s instead...") % {'x_query1': ""+bsu_p+"",
+ 'x_query2': ""+bsu_pn+""})
basic_search_units[idx_unit][1] = bsu_pn
basic_search_units_hitsets.append(basic_search_unit_hitset)
else:
# stage 2-3: no hits found either, propose nearest indexed terms:
if of.startswith('h'):
if req:
if bsu_f == "recid":
print_warning(req, "Requested record does not seem to exist.")
else:
print_warning(req, create_nearest_terms_box(req.argd, bsu_p, bsu_f, bsu_m, ln=ln))
return hitset_empty
else:
# stage 2-3: no hits found either, propose nearest indexed terms:
if of.startswith('h'):
if req:
if bsu_f == "recid":
print_warning(req, "Requested record does not seem to exist.")
else:
print_warning(req, create_nearest_terms_box(req.argd, bsu_p, bsu_f, bsu_m, ln=ln))
return hitset_empty
if verbose and of.startswith("h"):
t2 = os.times()[4]
for idx_unit in range(0,len(basic_search_units)):
print_warning(req, "Search stage 2: basic search unit %s gave %d hits." %
(basic_search_units[idx_unit][1:], basic_search_units_hitsets[idx_unit]._nbhits))
print_warning(req, "Search stage 2: execution took %.2f seconds." % (t2 - t1))
# search stage 3: apply boolean query for each search unit:
if verbose and of.startswith("h"):
t1 = os.times()[4]
# let the initial set be the complete universe:
hitset_in_any_collection = HitSet(Numeric.ones(cfg_max_recID+1, Numeric.Int0))
for idx_unit in range(0,len(basic_search_units)):
this_unit_operation = basic_search_units[idx_unit][0]
this_unit_hitset = basic_search_units_hitsets[idx_unit]
if this_unit_operation == '+':
hitset_in_any_collection.intersect(this_unit_hitset)
elif this_unit_operation == '-':
hitset_in_any_collection.difference(this_unit_hitset)
elif this_unit_operation == '|':
hitset_in_any_collection.union(this_unit_hitset)
else:
if of.startswith("h"):
print_warning(req, "Invalid set operation %s." % this_unit_operation, "Error")
hitset_in_any_collection.calculate_nbhits()
if hitset_in_any_collection._nbhits == 0:
# no hits found, propose alternative boolean query:
if of.startswith('h'):
nearestterms = []
for idx_unit in range(0,len(basic_search_units)):
bsu_o, bsu_p, bsu_f, bsu_m = basic_search_units[idx_unit]
if bsu_p.startswith("%") and bsu_p.endswith("%"):
bsu_p = "'" + bsu_p[1:-1] + "'"
bsu_nbhits = basic_search_units_hitsets[idx_unit]._nbhits
# create a similar query, but with the basic search unit only
argd = {}
argd.update(req.argd)
argd['p'] = bsu_p
argd['f'] = bsu_f
nearestterms.append((bsu_p, bsu_nbhits, argd))
text = websearch_templates.tmpl_search_no_boolean_hits(
ln=ln, nearestterms=nearestterms)
print_warning(req, text)
if verbose and of.startswith("h"):
t2 = os.times()[4]
print_warning(req, "Search stage 3: boolean query gave %d hits." % hitset_in_any_collection._nbhits)
print_warning(req, "Search stage 3: execution took %.2f seconds." % (t2 - t1))
return hitset_in_any_collection
def search_unit(p, f=None, m=None):
"""Search for basic search unit defined by pattern 'p' and field
'f' and matching type 'm'. Return hitset of recIDs.
All the parameters are assumed to have been previously washed.
'p' is assumed to be already a ``basic search unit'' so that it
is searched as such and is not broken up in any way. Only
wildcard and span queries are being detected inside 'p'.
This function is suitable as a low-level API.
"""
## create empty output results set:
set = HitSet()
if not p: # sanity checking
return set
if m == 'a' or m == 'r':
# we are doing either direct bibxxx search or phrase search or regexp search
set = search_unit_in_bibxxx(p, f, m)
else:
# we are doing bibwords search by default
set = search_unit_in_bibwords(p, f)
set.calculate_nbhits()
return set
def search_unit_in_bibwords(word, f, decompress=zlib.decompress):
"""Searches for 'word' inside bibwordsX table for field 'f' and returns hitset of recIDs."""
set = HitSet() # will hold output result set
set_used = 0 # not-yet-used flag, to be able to circumvent set operations
# deduce into which bibwordsX table we will search:
bibwordsX = "idxWORD%02dF" % get_index_id("anyfield")
if f:
index_id = get_index_id(f)
if index_id:
bibwordsX = "idxWORD%02dF" % index_id
else:
return HitSet() # word index f does not exist
# wash 'word' argument and construct query:
word = string.replace(word, '*', '%') # we now use '*' as the truncation character
words = string.split(word, "->", 1) # check for span query
if len(words) == 2:
word0 = sre_word.sub('', words[0])
word1 = sre_word.sub('', words[1])
query = "SELECT term,hitlist FROM %s WHERE term BETWEEN '%s' AND '%s'" % (bibwordsX, escape_string(word0[:50]), escape_string(word1[:50]))
else:
word = sre_word.sub('', word)
if string.find(word, '%') >= 0: # do we have wildcard in the word?
query = "SELECT term,hitlist FROM %s WHERE term LIKE '%s'" % (bibwordsX, escape_string(word[:50]))
else:
query = "SELECT term,hitlist FROM %s WHERE term='%s'" % (bibwordsX, escape_string(word[:50]))
# launch the query:
res = run_sql(query)
# fill the result set:
for word,hitlist in res:
hitset_bibwrd = HitSet(Numeric.loads(decompress(hitlist)))
# add the results:
if set_used:
set.union(hitset_bibwrd)
else:
set = hitset_bibwrd
set_used = 1
# okay, return result set:
return set
def search_unit_in_bibxxx(p, f, type):
"""Searches for pattern 'p' inside bibxxx tables for field 'f' and returns hitset of recIDs found.
The search type is defined by 'type' (e.g. equals to 'r' for a regexp search)."""
p_orig = p # saving for eventual future 'no match' reporting
# wash arguments:
f = string.replace(f, '*', '%') # replace truncation char '*' in field definition
if type == 'r':
pattern = "REGEXP '%s'" % escape_string(p)
else:
p = string.replace(p, '*', '%') # we now use '*' as the truncation character
ps = string.split(p, "->", 1) # check for span query:
if len(ps) == 2:
pattern = "BETWEEN '%s' AND '%s'" % (escape_string(ps[0]), escape_string(ps[1]))
else:
if string.find(p, '%') > -1:
pattern = "LIKE '%s'" % escape_string(ps[0])
else:
pattern = "='%s'" % escape_string(ps[0])
# construct 'tl' which defines the tag list (MARC tags) to search in:
tl = []
if str(f[0]).isdigit() and str(f[1]).isdigit():
tl.append(f) # 'f' seems to be okay as it starts by two digits
else:
# convert old ALEPH tag names, if appropriate: (TODO: get rid of this before entering this function)
if cfg_fields_convert.has_key(string.lower(f)):
f = cfg_fields_convert[string.lower(f)]
# deduce desired MARC tags on the basis of chosen 'f'
tl = get_field_tags(f)
if not tl:
# f index does not exist, nevermind
pass
# okay, start search:
l = [] # will hold list of recID that matched
for t in tl:
# deduce into which bibxxx table we will search:
digit1, digit2 = int(t[0]), int(t[1])
bx = "bib%d%dx" % (digit1, digit2)
bibx = "bibrec_bib%d%dx" % (digit1, digit2)
# construct query:
if t == "001":
query = "SELECT id FROM bibrec WHERE id %s" % pattern
else:
if len(t) != 6 or t[-1:]=='%': # only the beginning of field 't' is defined, so add wildcard character:
query = "SELECT bibx.id_bibrec FROM %s AS bx LEFT JOIN %s AS bibx ON bx.id=bibx.id_bibxxx WHERE bx.value %s AND bx.tag LIKE '%s%%'" %\
(bx, bibx, pattern, t)
else:
query = "SELECT bibx.id_bibrec FROM %s AS bx LEFT JOIN %s AS bibx ON bx.id=bibx.id_bibxxx WHERE bx.value %s AND bx.tag='%s'" %\
(bx, bibx, pattern, t)
# launch the query:
res = run_sql(query)
# fill the result set:
for id_bibrec in res:
if id_bibrec[0]:
l.append(id_bibrec[0])
# check no of hits found:
nb_hits = len(l)
# okay, return result set:
set = HitSet()
set.addlist(Numeric.array(l))
return set
def search_unit_in_bibrec(day1, day2, type='creation_date'):
"""Return hitset of recIDs found that were either created or modified (see 'type' arg)
from day1 until day2, inclusive. Does not pay attention to pattern, collection, anything.
Useful to intersect later on with the 'real' query."""
set = HitSet()
if type != "creation_date" and type != "modification_date":
# type argument is invalid, so search for creation dates by default
type = "creation_date"
res = run_sql("SELECT id FROM bibrec WHERE %s>=%s AND %s<=%s" % (type, "%s", type, "%s"),
(day1, day2))
l = []
for row in res:
l.append(row[0])
set.addlist(Numeric.array(l))
return set
def intersect_results_with_collrecs(req, hitset_in_any_collection, colls, ap=0, of="hb", verbose=0, ln=cdslang):
"""Return dict of hitsets given by intersection of hitset with the collection universes."""
_ = gettext_set_language(ln)
# search stage 4: intersect with the collection universe:
if verbose and of.startswith("h"):
t1 = os.times()[4]
results = {}
results_nbhits = 0
for coll in colls:
results[coll] = HitSet()
results[coll]._set = Numeric.bitwise_and(hitset_in_any_collection._set, get_collection_reclist(coll)._set)
results[coll].calculate_nbhits()
results_nbhits += results[coll]._nbhits
if results_nbhits == 0:
# no hits found, try to search in Home:
results_in_Home = HitSet()
results_in_Home._set = Numeric.bitwise_and(hitset_in_any_collection._set, get_collection_reclist(cdsname)._set)
results_in_Home.calculate_nbhits()
if results_in_Home._nbhits > 0:
# some hits found in Home, so propose this search:
if of.startswith("h"):
url = websearch_templates.build_search_url(req.argd, cc=cdsname, c=[])
- print_warning(req, _("No match found in collection %s. Other public collections gave %s%d hits%s.") %
- (string.join(colls, ','),
- '' % (url),
- results_in_Home._nbhits,
- ''))
+ print_warning(req, _("No match found in collection %(x_collection)s. Other public collections gave %(x_url_open)s%(x_nb_hits)d hits%(x_url_close)s.") %\
+ {'x_collection': string.join(colls, ','),
+ 'x_url_open': '' % (url),
+ 'x_nb_hits': results_in_Home._nbhits,
+ 'x_url_close': ''})
results = {}
else:
# no hits found in Home, recommend different search terms:
if of.startswith("h"):
print_warning(req, _("No public collection matched your query. "
"If you were looking for a non-public document, please choose "
"the desired restricted collection first."))
results = {}
if verbose and of.startswith("h"):
t2 = os.times()[4]
print_warning(req, "Search stage 4: intersecting with collection universe gave %d hits." % results_nbhits)
print_warning(req, "Search stage 4: execution took %.2f seconds." % (t2 - t1))
return results
def intersect_results_with_hitset(req, results, hitset, ap=0, aptext="", of="hb"):
"""Return intersection of search 'results' (a dict of hitsets
with collection as key) with the 'hitset', i.e. apply
'hitset' intersection to each collection within search
'results'.
If the final 'results' set is to be empty, and 'ap'
(approximate pattern) is true, and then print the `warningtext'
and return the original 'results' set unchanged. If 'ap' is
false, then return empty results set.
"""
if ap:
results_ap = copy.deepcopy(results)
else:
results_ap = {} # will return empty dict in case of no hits found
nb_total = 0
for coll in results.keys():
results[coll].intersect(hitset)
results[coll].calculate_nbhits()
nb_total += results[coll]._nbhits
if nb_total == 0:
if of.startswith("h"):
print_warning(req, aptext)
results = results_ap
return results
def create_similarly_named_authors_link_box(author_name, ln=cdslang):
"""Return a box similar to ``Not satisfied...'' one by proposing
author searches for similar names. Namely, take AUTHOR_NAME
and the first initial of the firstame (after comma) and look
into author index whether authors with e.g. middle names exist.
Useful mainly for CERN Library that sometimes contains name
forms like Ellis-N, Ellis-Nick, Ellis-Nicolas all denoting the
same person. The box isn't proposed if no similarly named
authors are found to exist.
"""
# return nothing if not configured:
if cfg_create_similarly_named_authors_link_box == 0:
return ""
# return empty box if there is no initial:
if sre.match(r'[^ ,]+, [^ ]', author_name) is None:
return ""
# firstly find name comma initial:
author_name_to_search = sre.sub(r'^([^ ,]+, +[^ ,]).*$', '\\1', author_name)
# secondly search for similar name forms:
similar_author_names = {}
for name in author_name_to_search, strip_accents(author_name_to_search):
for tag in get_field_tags("author"):
# deduce into which bibxxx table we will search:
digit1, digit2 = int(tag[0]), int(tag[1])
bx = "bib%d%dx" % (digit1, digit2)
bibx = "bibrec_bib%d%dx" % (digit1, digit2)
if len(tag) != 6 or tag[-1:]=='%':
# only the beginning of field 't' is defined, so add wildcard character:
query = "SELECT bx.value FROM %s AS bx WHERE bx.value LIKE '%s%%' AND bx.tag LIKE '%s%%'" \
% (bx, escape_string(name), tag)
else:
query = "SELECT bx.value FROM %s AS bx WHERE bx.value LIKE '%s%%' AND bx.tag='%s'" \
% (bx, escape_string(name), tag)
res = run_sql(query)
for row in res:
similar_author_names[row[0]] = 1
# remove the original name and sort the list:
try:
del similar_author_names[author_name]
except KeyError:
pass
# thirdly print the box:
out = ""
if similar_author_names:
out_authors = similar_author_names.keys()
out_authors.sort()
tmp_authors = []
for out_author in out_authors:
nbhits = get_nbhits_in_bibxxx(out_author, "author")
if nbhits:
tmp_authors.append((out_author, nbhits))
out += websearch_templates.tmpl_similar_author_names(
authors=tmp_authors, ln=ln)
return out
def create_nearest_terms_box(urlargd, p, f, t='w', n=5, ln=cdslang, intro_text_p=True):
"""Return text box containing list of 'n' nearest terms above/below 'p'
for the field 'f' for matching type 't' (words/phrases) in
language 'ln'.
Propose new searches according to `urlargs' with the new words.
If `intro_text_p' is true, then display the introductory message,
otherwise print only the nearest terms in the box content.
"""
# load the right message language
_ = gettext_set_language(ln)
out = ""
nearest_terms = []
if not p: # sanity check
p = "."
# look for nearest terms:
if t == 'w':
nearest_terms = get_nearest_terms_in_bibwords(p, f, n, n)
if not nearest_terms:
return "%s %s." % (_("No words index available for"), get_field_i18nname(f, ln))
else:
nearest_terms = get_nearest_terms_in_bibxxx(p, f, n, n)
if not nearest_terms:
return "%s %s." % (_("No phrase index available for"), get_field_i18nname(f, ln))
terminfo = []
for term in nearest_terms:
if t == 'w':
hits = get_nbhits_in_bibwords(term, f)
else:
hits = get_nbhits_in_bibxxx(term, f)
argd = {}
argd.update(urlargd)
# check which fields contained the requested parameter, and replace it.
for field in ('p', 'p1', 'p2', 'p3'):
if field in argd and argd[field] == p:
argd[field] = term
break
terminfo.append((term, hits, argd))
intro = ""
if intro_text_p: # add full leading introductory text
if f:
- intro = _("Search term %s inside index %s did not match any record. Nearest terms in any collection are:") % \
- ("" + (p.startswith("%") and p.endswith("%") and p[1:-1] or p) + "",
- "" + get_field_i18nname(f, ln) + "")
+ intro = _("Search term %(x_term)s inside index %(x_index)s did not match any record. Nearest terms in any collection are:") % \
+ {'x_term': "" + (p.startswith("%") and p.endswith("%") and p[1:-1] or p) + "",
+ 'x_index': "" + get_field_i18nname(f, ln) + ""}
else:
intro = _("Search term %s did not match any record. Nearest terms in any collection are:") % \
("" + (p.startswith("%") and p.endswith("%") and p[1:-1] or p) + "")
return websearch_templates.tmpl_nearest_term_box(p=p, ln=ln, f=f, terminfo=terminfo,
intro=intro)
def get_nearest_terms_in_bibwords(p, f, n_below, n_above):
"""Return list of +n -n nearest terms to word `p' in index for field `f'."""
nearest_words = [] # will hold the (sorted) list of nearest words to return
# deduce into which bibwordsX table we will search:
bibwordsX = "idxWORD%02dF" % get_index_id("anyfield")
if f:
index_id = get_index_id(f)
if index_id:
bibwordsX = "idxWORD%02dF" % index_id
else:
return nearest_words
# firstly try to get `n' closest words above `p':
query = "SELECT term FROM %s WHERE term<'%s' ORDER BY term DESC LIMIT %d" % (bibwordsX, escape_string(p), n_above)
res = run_sql(query)
for row in res:
nearest_words.append(row[0])
nearest_words.reverse()
# secondly insert given word `p':
nearest_words.append(p)
# finally try to get `n' closest words below `p':
query = "SELECT term FROM %s WHERE term>'%s' ORDER BY term ASC LIMIT %d" % (bibwordsX, escape_string(p), n_below)
res = run_sql(query)
for row in res:
nearest_words.append(row[0])
return nearest_words
def get_nearest_terms_in_bibxxx(p, f, n_below, n_above):
"""Browse (-n_above, +n_below) closest bibliographic phrases
for the given pattern p in the given field f, regardless
of collection.
Return list of [phrase1, phrase2, ... , phrase_n]."""
## determine browse field:
if not f and string.find(p, ":") > 0: # does 'p' contain ':'?
f, p = split(p, ":", 1)
## We are going to take max(n_below, n_above) as the number of
## values to ferch from bibXXx. This is needed to work around
## MySQL UTF-8 sorting troubles in 4.0.x. Proper solution is to
## use MySQL 4.1.x or our own idxPHRASE in the future.
n_fetch = 2*max(n_below,n_above)
## construct 'tl' which defines the tag list (MARC tags) to search in:
tl = []
if str(f[0]).isdigit() and str(f[1]).isdigit():
tl.append(f) # 'f' seems to be okay as it starts by two digits
else:
# deduce desired MARC tags on the basis of chosen 'f'
tl = get_field_tags(f)
## start browsing to fetch list of hits:
browsed_phrases = {} # will hold {phrase1: 1, phrase2: 1, ..., phraseN: 1} dict of browsed phrases (to make them unique)
# always add self to the results set:
browsed_phrases[p.startswith("%") and p.endswith("%") and p[1:-1] or p] = 1
for t in tl:
# deduce into which bibxxx table we will search:
digit1, digit2 = int(t[0]), int(t[1])
bx = "bib%d%dx" % (digit1, digit2)
bibx = "bibrec_bib%d%dx" % (digit1, digit2)
# firstly try to get `n' closest phrases above `p':
if len(t) != 6 or t[-1:]=='%': # only the beginning of field 't' is defined, so add wildcard character:
query = "SELECT bx.value FROM %s AS bx WHERE bx.value<'%s' AND bx.tag LIKE '%s%%' ORDER BY bx.value DESC LIMIT %d" \
% (bx, escape_string(p), t, n_fetch)
else:
query = "SELECT bx.value FROM %s AS bx WHERE bx.value<'%s' AND bx.tag='%s' ORDER BY bx.value DESC LIMIT %d" \
% (bx, escape_string(p), t, n_fetch)
res = run_sql(query)
for row in res:
browsed_phrases[row[0]] = 1
# secondly try to get `n' closest phrases equal to or below `p':
if len(t) != 6 or t[-1:]=='%': # only the beginning of field 't' is defined, so add wildcard character:
query = "SELECT bx.value FROM %s AS bx WHERE bx.value>='%s' AND bx.tag LIKE '%s%%' ORDER BY bx.value ASC LIMIT %d" \
% (bx, escape_string(p), t, n_fetch)
else:
query = "SELECT bx.value FROM %s AS bx WHERE bx.value>='%s' AND bx.tag='%s' ORDER BY bx.value ASC LIMIT %d" \
% (bx, escape_string(p), t, n_fetch)
res = run_sql(query)
for row in res:
browsed_phrases[row[0]] = 1
# select first n words only: (this is needed as we were searching
# in many different tables and so aren't sure we have more than n
# words right; this of course won't be needed when we shall have
# one ACC table only for given field):
phrases_out = browsed_phrases.keys()
phrases_out.sort(lambda x, y: cmp(string.lower(strip_accents(x)),
string.lower(strip_accents(y))))
# find position of self:
try:
idx_p = phrases_out.index(p)
except:
idx_p = len(phrases_out)/2
# return n_above and n_below:
return phrases_out[max(0,idx_p-n_above):idx_p+n_below]
def get_nbhits_in_bibwords(word, f):
"""Return number of hits for word 'word' inside words index for field 'f'."""
out = 0
# deduce into which bibwordsX table we will search:
bibwordsX = "idxWORD%02dF" % get_index_id("anyfield")
if f:
index_id = get_index_id(f)
if index_id:
bibwordsX = "idxWORD%02dF" % index_id
else:
return 0
if word:
query = "SELECT hitlist FROM %s WHERE term='%s'" % (bibwordsX, escape_string(word))
res = run_sql(query)
for hitlist in res:
out += Numeric.sum(Numeric.loads(zlib.decompress(hitlist[0])).copy().astype(Numeric.Int))
return out
def get_nbhits_in_bibxxx(p, f):
"""Return number of hits for word 'word' inside words index for field 'f'."""
## determine browse field:
if not f and string.find(p, ":") > 0: # does 'p' contain ':'?
f, p = split(p, ":", 1)
## construct 'tl' which defines the tag list (MARC tags) to search in:
tl = []
if str(f[0]).isdigit() and str(f[1]).isdigit():
tl.append(f) # 'f' seems to be okay as it starts by two digits
else:
# deduce desired MARC tags on the basis of chosen 'f'
tl = get_field_tags(f)
# start searching:
recIDs = {} # will hold dict of {recID1: 1, recID2: 1, ..., } (unique recIDs, therefore)
for t in tl:
# deduce into which bibxxx table we will search:
digit1, digit2 = int(t[0]), int(t[1])
bx = "bib%d%dx" % (digit1, digit2)
bibx = "bibrec_bib%d%dx" % (digit1, digit2)
if len(t) != 6 or t[-1:]=='%': # only the beginning of field 't' is defined, so add wildcard character:
query = """SELECT bibx.id_bibrec FROM %s AS bibx, %s AS bx
WHERE bx.value='%s' AND bx.tag LIKE '%s%%' AND bibx.id_bibxxx=bx.id""" \
% (bibx, bx, escape_string(p), t)
else:
query = """SELECT bibx.id_bibrec FROM %s AS bibx, %s AS bx
WHERE bx.value='%s' AND bx.tag='%s' AND bibx.id_bibxxx=bx.id""" \
% (bibx, bx, escape_string(p), t)
res = run_sql(query)
for row in res:
recIDs[row[0]] = 1
return len(recIDs)
def get_mysql_recid_from_aleph_sysno(sysno):
"""Returns DB's recID for ALEPH sysno passed in the argument (e.g. "002379334CER").
Returns None in case of failure."""
out = None
query = "SELECT bb.id_bibrec FROM bibrec_bib97x AS bb, bib97x AS b WHERE b.value='%s' AND b.tag='970__a' AND bb.id_bibxxx=b.id" %\
(escape_string(sysno))
res = run_sql(query, None, 1)
if res:
out = res[0][0]
return out
def guess_primary_collection_of_a_record(recID):
"""Return primary collection name a record recid belongs to, by testing 980 identifier.
May lead to bad guesses when a collection is defined dynamically bia dbquery.
In that case, return 'cdsname'."""
out = cdsname
dbcollids = get_fieldvalues(recID, "980__a")
if dbcollids:
dbquery = "collection:" + dbcollids[0]
res = run_sql("SELECT name FROM collection WHERE dbquery=%s", (dbquery,))
if res:
out = res[0][0]
return out
def get_tag_name(tag_value, prolog="", epilog=""):
"""Return tag name from the known tag value, by looking up the 'tag' table.
Return empty string in case of failure.
Example: input='100__%', output=first author'."""
out = ""
res = run_sql("SELECT name FROM tag WHERE value=%s", (tag_value,))
if res:
out = prolog + res[0][0] + epilog
return out
def get_fieldcodes():
"""Returns a list of field codes that may have been passed as 'search options' in URL.
Example: output=['subject','division']."""
out = []
res = run_sql("SELECT DISTINCT(code) FROM field")
for row in res:
out.append(row[0])
return out
def get_field_tags(field):
"""Returns a list of MARC tags for the field code 'field'.
Returns empty list in case of error.
Example: field='author', output=['100__%','700__%']."""
out = []
query = """SELECT t.value FROM tag AS t, field_tag AS ft, field AS f
WHERE f.code='%s' AND ft.id_field=f.id AND t.id=ft.id_tag
ORDER BY ft.score DESC""" % field
res = run_sql(query)
for val in res:
out.append(val[0])
return out
def get_fieldvalues(recID, tag):
"""Return list of field values for field TAG inside record RECID."""
out = []
if tag == "001___":
# we have asked for recID that is not stored in bibXXx tables
out.append(str(recID))
else:
# we are going to look inside bibXXx tables
digit = tag[0:2]
bx = "bib%sx" % digit
bibx = "bibrec_bib%sx" % digit
query = "SELECT bx.value FROM %s AS bx, %s AS bibx WHERE bibx.id_bibrec='%s' AND bx.id=bibx.id_bibxxx AND bx.tag LIKE '%s'" \
"ORDER BY bibx.field_number, bx.tag ASC" % (bx, bibx, recID, tag)
res = run_sql(query)
for row in res:
out.append(row[0])
return out
def get_fieldvalues_alephseq_like(recID, tags_in):
"""Return textual lines in ALEPH sequential like format for field 'tag' inside record 'recID'."""
out = ""
if len(tags_in) == 1 and len(tags_in[0]) == 6:
## case A: one concrete subfield asked, so print its value if found
## (use with care: can false you if field has multiple occurrences)
out += string.join(get_fieldvalues(recID, tags_in[0]),"\n")
else:
## case B: print our "text MARC" format; works safely all the time
# find out which tags to output:
dict_of_tags_out = {}
if not tags_in:
for i in range(0,10):
for j in range(0,10):
dict_of_tags_out["%d%d%%" % (i, j)] = 1
else:
for tag in tags_in:
if len(tag) == 0:
for i in range(0,10):
for j in range(0,10):
dict_of_tags_out["%d%d%%" % (i, j)] = 1
elif len(tag) == 1:
for j in range(0,10):
dict_of_tags_out["%s%d%%" % (tag, j)] = 1
elif len(tag) < 5:
dict_of_tags_out["%s%%" % tag] = 1
elif tag >= 6:
dict_of_tags_out[tag[0:5]] = 1
tags_out = dict_of_tags_out.keys()
tags_out.sort()
# search all bibXXx tables as needed:
for tag in tags_out:
digits = tag[0:2]
if tag.startswith("001") or tag.startswith("00%"):
if out:
out += "\n"
out += "%09d %s %d" % (recID, "001__", recID)
bx = "bib%sx" % digits
bibx = "bibrec_bib%sx" % digits
query = "SELECT b.tag,b.value,bb.field_number FROM %s AS b, %s AS bb "\
"WHERE bb.id_bibrec='%s' AND b.id=bb.id_bibxxx AND b.tag LIKE '%s%%' "\
"ORDER BY bb.field_number, b.tag ASC" % (bx, bibx, recID, tag)
res = run_sql(query)
# go through fields:
field_number_old = -999
field_old = ""
for row in res:
field, value, field_number = row[0], row[1], row[2]
ind1, ind2 = field[3], field[4]
if ind1 == "_":
ind1 = ""
if ind2 == "_":
ind2 = ""
# print field tag
if field_number != field_number_old or field[:-1] != field_old[:-1]:
if out:
out += "\n"
out += "%09d %s " % (recID, field[:5])
field_number_old = field_number
field_old = field
# print subfield value
out += "$$%s%s" % (field[-1:], value)
return out
def record_exists(recID):
"""Return 1 if record RECID exists.
Return 0 if it doesn't exist.
Return -1 if it exists but is marked as deleted."""
out = 0
query = "SELECT id FROM bibrec WHERE id='%s'" % recID
res = run_sql(query, None, 1)
if res:
# record exists; now check whether it isn't marked as deleted:
dbcollids = get_fieldvalues(recID, "980__%")
if ("DELETED" in dbcollids) or (cfg_cern_site and "DUMMY" in dbcollids):
out = -1 # exists, but marked as deleted
else:
out = 1 # exists fine
return out
def record_public_p(recID):
"""Return 1 if the record is public, i.e. if it can be found in the Home collection.
Return 0 otherwise.
"""
return get_collection_reclist(cdsname).contains(recID)
def get_creation_date(recID, fmt="%Y-%m-%d"):
"Returns the creation date of the record 'recID'."
out = ""
res = run_sql("SELECT DATE_FORMAT(creation_date,%s) FROM bibrec WHERE id=%s", (fmt, recID), 1)
if res:
out = res[0][0]
return out
def get_modification_date(recID, fmt="%Y-%m-%d"):
"Returns the date of last modification for the record 'recID'."
out = ""
res = run_sql("SELECT DATE_FORMAT(modification_date,%s) FROM bibrec WHERE id=%s", (fmt, recID), 1)
if res:
out = res[0][0]
return out
def print_warning(req, msg, type='', prologue=' ', epilogue=' '):
"Prints warning message and flushes output."
if req and msg:
req.write(websearch_templates.tmpl_print_warning(
msg = msg,
type = type,
prologue = prologue,
epilogue = epilogue,
))
return
def print_search_info(p, f, sf, so, sp, rm, of, ot, collection=cdsname, nb_found=-1, jrec=1, rg=10,
as=0, ln=cdslang, p1="", p2="", p3="", f1="", f2="", f3="", m1="", m2="", m3="", op1="", op2="",
sc=1, pl_in_url="",
d1y=0, d1m=0, d1d=0, d2y=0, d2m=0, d2d=0,
cpu_time=-1, middle_only=0):
"""Prints stripe with the information on 'collection' and 'nb_found' results and CPU time.
Also, prints navigation links (beg/next/prev/end) inside the results set.
If middle_only is set to 1, it will only print the middle box information (beg/netx/prev/end/etc) links.
This is suitable for displaying navigation links at the bottom of the search results page."""
out = ""
# sanity check:
if jrec < 1:
jrec = 1
if jrec > nb_found:
jrec = max(nb_found-rg+1, 1)
return websearch_templates.tmpl_print_search_info(
ln = ln,
weburl = weburl,
collection = collection,
as = as,
collection_name = get_coll_i18nname(collection, ln),
collection_id = get_colID(collection),
middle_only = middle_only,
rg = rg,
nb_found = nb_found,
sf = sf,
so = so,
rm = rm,
of = of,
ot = ot,
p = p,
f = f,
p1 = p1,
p2 = p2,
p3 = p3,
f1 = f1,
f2 = f2,
f3 = f3,
m1 = m1,
m2 = m2,
m3 = m3,
op1 = op1,
op2 = op2,
pl_in_url = pl_in_url,
d1y = d1y,
d1m = d1m,
d1d = d1d,
d2y = d2y,
d2m = d2m,
d2d = d2d,
jrec = jrec,
sc = sc,
sp = sp,
all_fieldcodes = get_fieldcodes(),
cpu_time = cpu_time,
)
def print_results_overview(req, colls, results_final_nb_total, results_final_nb, cpu_time, ln=cdslang):
"Prints results overview box with links to particular collections below."
out = ""
new_colls = []
for coll in colls:
new_colls.append({
'id': get_colID(coll),
'code': coll,
'name': get_coll_i18nname(coll, ln),
})
return websearch_templates.tmpl_print_results_overview(
ln = ln,
weburl = weburl,
results_final_nb_total = results_final_nb_total,
results_final_nb = results_final_nb,
cpu_time = cpu_time,
colls = new_colls,
)
def sort_records(req, recIDs, sort_field='', sort_order='d', sort_pattern='', verbose=0, of='hb', ln=cdslang):
"""Sort records in 'recIDs' list according sort field 'sort_field' in order 'sort_order'.
If more than one instance of 'sort_field' is found for a given record, try to choose that that is given by
'sort pattern', for example "sort by report number that starts by CERN-PS".
Note that 'sort_field' can be field code like 'author' or MARC tag like '100__a' directly."""
_ = gettext_set_language(ln)
## check arguments:
if not sort_field:
return recIDs
if len(recIDs) > cfg_nb_records_to_sort:
if of.startswith('h'):
print_warning(req, _("Sorry, sorting is allowed on sets of up to %d records only. Using default sort order.") % cfg_nb_records_to_sort, "Warning")
return recIDs
sort_fields = string.split(sort_field, ",")
recIDs_dict = {}
recIDs_out = []
## first deduce sorting MARC tag out of the 'sort_field' argument:
tags = []
for sort_field in sort_fields:
if sort_field and str(sort_field[0:2]).isdigit():
# sort_field starts by two digits, so this is probably a MARC tag already
tags.append(sort_field)
else:
# let us check the 'field' table
query = """SELECT DISTINCT(t.value) FROM tag AS t, field_tag AS ft, field AS f
WHERE f.code='%s' AND ft.id_field=f.id AND t.id=ft.id_tag
ORDER BY ft.score DESC""" % sort_field
res = run_sql(query)
if res:
for row in res:
tags.append(row[0])
else:
if of.startswith('h'):
print_warning(req, _("Sorry, %s does not seem to be a valid sort option. Choosing title sort instead.") % sort_field, "Error")
tags.append("245__a")
if verbose >= 3:
print_warning(req, "Sorting by tags %s." % tags)
if sort_pattern:
print_warning(req, "Sorting preferentially by %s." % sort_pattern)
## check if we have sorting tag defined:
if tags:
# fetch the necessary field values:
for recID in recIDs:
val = "" # will hold value for recID according to which sort
vals = [] # will hold all values found in sorting tag for recID
for tag in tags:
vals.extend(get_fieldvalues(recID, tag))
if sort_pattern:
# try to pick that tag value that corresponds to sort pattern
bingo = 0
for v in vals:
if v.startswith(sort_pattern): # bingo!
bingo = 1
val = v
break
if not bingo: # sort_pattern not present, so add other vals after spaces
val = sort_pattern + " " + string.join(vals)
else:
# no sort pattern defined, so join them all together
val = string.join(vals)
val = val.lower()
if recIDs_dict.has_key(val):
recIDs_dict[val].append(recID)
else:
recIDs_dict[val] = [recID]
# sort them:
recIDs_dict_keys = recIDs_dict.keys()
recIDs_dict_keys.sort()
# now that keys are sorted, create output array:
for k in recIDs_dict_keys:
for s in recIDs_dict[k]:
recIDs_out.append(s)
# ascending or descending?
if sort_order == 'a':
recIDs_out.reverse()
# okay, we are done
return recIDs_out
else:
# good, no sort needed
return recIDs
def print_record_list_for_similarity_boxen(req, title, recID_score_list, ln=cdslang):
"""Print list of records in the "hs" (HTML Similarity) format for similarity boxes.
FIXME: templatize.
"""
recID_score_list_to_be_printed = []
# firstly find 5 first public records to print:
nb_records_to_be_printed = 0
nb_records_seen = 0
while nb_records_to_be_printed < 5 and nb_records_seen < len(recID_score_list) and nb_records_seen < 50:
# looking through first 50 records only, picking first 5 public ones
(recID, score) = recID_score_list[nb_records_seen]
nb_records_seen += 1
if record_public_p(recID):
nb_records_to_be_printed += 1
recID_score_list_to_be_printed.append([recID,score])
# secondly print them:
if nb_records_to_be_printed > 0:
req.write("""
""")
req.write("""
%s
""" % title)
req.write("""
""")
for (recID, score) in recID_score_list_to_be_printed:
req.write("""
""")
return
def print_records(req, recIDs, jrec=1, rg=10, format='hb', ot='', ln=cdslang, relevances=[], relevances_prologue="(", relevances_epilogue="%%)", decompress=zlib.decompress):
"""Prints list of records 'recIDs' formatted accoding to 'format' in groups of 'rg' starting from 'jrec'.
Assumes that the input list 'recIDs' is sorted in reverse order, so it counts records from tail to head.
A value of 'rg=-9999' means to print all records: to be used with care.
Print also list of RELEVANCES for each record (if defined), in between RELEVANCE_PROLOGUE and RELEVANCE_EPILOGUE.
"""
# load the right message language
_ = gettext_set_language(ln)
# sanity checking:
if req == None:
return
if len(recIDs):
nb_found = len(recIDs)
if rg == -9999: # print all records
rg = nb_found
else:
rg = abs(rg)
if jrec < 1: # sanity checks
jrec = 1
if jrec > nb_found:
jrec = max(nb_found-rg+1, 1)
# will print records from irec_max to irec_min excluded:
irec_max = nb_found - jrec
irec_min = nb_found - jrec - rg
if irec_min < 0:
irec_min = -1
if irec_max >= nb_found:
irec_max = nb_found - 1
#req.write("%s:%d-%d" % (recIDs, irec_min, irec_max))
if format.startswith('x'):
# we are doing XML output:
for irec in range(irec_max,irec_min,-1):
req.write(print_record(recIDs[irec], format, ot, ln))
elif format.startswith('t') or str(format[0:3]).isdigit():
# we are doing plain text output:
for irec in range(irec_max,irec_min,-1):
x = print_record(recIDs[irec], format, ot, ln)
req.write(x)
if x:
req.write('\n')
else:
# we are doing HTML output:
if format == 'hp' or format.startswith("hb_") or format.startswith("hd_"):
# portfolio and on-the-fly formats:
for irec in range(irec_max,irec_min,-1):
req.write(print_record(recIDs[irec], format, ot, ln))
elif format.startswith("hb"):
# HTML brief format:
rows = []
for irec in range(irec_max,irec_min,-1):
temp = {
'number' : jrec+irec_max-irec,
'recid' : recIDs[irec],
}
if relevances and relevances[irec]:
temp['relevance'] = relevances[irec]
else:
temp['relevance'] = ''
temp['record'] = print_record(recIDs[irec], format, ot, ln)
rows.append(temp)
req.write(websearch_templates.tmpl_records_format_htmlbrief(
ln = ln,
weburl = weburl,
rows = rows,
relevances_prologue = relevances_prologue,
relevances_epilogue = relevances_epilogue,
))
else:
# HTML detailed format:
# print other formatting choices:
rows = []
for irec in range(irec_max,irec_min,-1):
temp = {
'record' : print_record(recIDs[irec], format, ot, ln),
'recid' : recIDs[irec],
'creationdate': '',
'modifydate' : '',
}
if record_exists(recIDs[irec])==1:
temp['creationdate'] = get_creation_date(recIDs[irec])
temp['modifydate'] = get_modification_date(recIDs[irec])
if cfg_experimental_features:
r = calculate_cited_by_list(recIDs[irec])
if r:
temp ['citinglist'] = r
temp ['citationhistory'] = create_citation_history_graph_and_box(recIDs[irec], ln)
r = calculate_co_cited_with_list(recIDs[irec])
if r: temp ['cociting'] = r
r = calculate_reading_similarity_list(recIDs[irec], "downloads")
if r:
temp ['downloadsimilarity'] = r
temp ['downloadhistory'] = create_download_history_graph_and_box(recIDs[irec], ln)
# Get comments and reviews for this record if exist
# FIXME: templatize me
if cfg_webcomment_allow_comments or cfg_webcomment_allow_reviews:
from invenio.webcomment import get_first_comments_or_remarks
(comments, reviews) = get_first_comments_or_remarks(recID=recIDs[irec], ln=ln,
nb_comments=cfg_webcomment_nb_comments_in_detailed_view,
nb_reviews=cfg_webcomment_nb_reviews_in_detailed_view)
temp['comments'] = comments
temp['reviews'] = reviews
r = calculate_reading_similarity_list(recIDs[irec], "pageviews")
if r: temp ['viewsimilarity'] = r
rows.append(temp)
req.write(websearch_templates.tmpl_records_format_other(
ln = ln,
weburl = weburl,
url_argd = req.argd,
rows = rows,
format = format,
))
else:
print_warning(req, _("Use different search terms."))
def print_record(recID, format='hb', ot='', ln=cdslang, decompress=zlib.decompress):
"Prints record 'recID' formatted accoding to 'format'."
_ = gettext_set_language(ln)
out = ""
# sanity check:
record_exist_p = record_exists(recID)
if record_exist_p == 0: # doesn't exist
return out
# print record opening tags, if needed:
if format == "marcxml" or format == "oai_dc":
out += " \n"
out += " \n"
for id in get_fieldvalues(recID,cfg_oai_id_field):
out += " %s\n" % id
out += " %s\n" % get_modification_date(recID)
out += " \n"
out += " \n"
if format.startswith("xm") or format == "marcxml":
# look for detailed format existence:
query = "SELECT value FROM bibfmt WHERE id_bibrec='%s' AND format='%s'" % (recID, format)
res = run_sql(query, None, 1)
if res and record_exist_p==1:
# record 'recID' is formatted in 'format', so print it
out += "%s" % decompress(res[0][0])
else:
# record 'recID' is not formatted in 'format' -- they are not in "bibfmt" table; so fetch all the data from "bibXXx" tables:
if format == "marcxml":
out += """ \n"""
out += " %d\n" % int(recID)
elif format.startswith("xm"):
out += """ \n"""
out += " %d\n" % int(recID)
if record_exist_p == -1:
# deleted record, so display only OAI ID and 980:
oai_ids = get_fieldvalues(recID, cfg_oaiidtag)
if oai_ids:
out += "%s\n" % \
(cfg_oaiidtag[0:3], cfg_oaiidtag[3:4], cfg_oaiidtag[4:5], cfg_oaiidtag[5:6], oai_ids[0])
out += "DELETED\n"
else:
for digit1 in range(0,10):
for digit2 in range(0,10):
bx = "bib%d%dx" % (digit1, digit2)
bibx = "bibrec_bib%d%dx" % (digit1, digit2)
query = "SELECT b.tag,b.value,bb.field_number FROM %s AS b, %s AS bb "\
"WHERE bb.id_bibrec='%s' AND b.id=bb.id_bibxxx AND b.tag LIKE '%s%%' "\
"ORDER BY bb.field_number, b.tag ASC" % (bx, bibx, recID, str(digit1)+str(digit2))
res = run_sql(query)
field_number_old = -999
field_old = ""
for row in res:
field, value, field_number = row[0], row[1], row[2]
ind1, ind2 = field[3], field[4]
if ind1 == "_":
ind1 = ""
if ind2 == "_":
ind2 = ""
# print field tag
if field_number != field_number_old or field[:-1] != field_old[:-1]:
if format.startswith("xm") or format == "marcxml":
fieldid = encode_for_xml(field[0:3])
if field_number_old != -999:
out += """ \n"""
out += """ \n""" % \
(encode_for_xml(field[0:3]), encode_for_xml(ind1), encode_for_xml(ind2))
field_number_old = field_number
field_old = field
# print subfield value
if format.startswith("xm") or format == "marcxml":
value = encode_for_xml(value)
out += """ %s\n""" % (encode_for_xml(field[-1:]), value)
# all fields/subfields printed in this run, so close the tag:
if (format.startswith("xm") or format == "marcxml") and field_number_old != -999:
out += """ \n"""
# we are at the end of printing the record:
if format.startswith("xm") or format == "marcxml":
out += " \n"
elif format == "xd" or format == "oai_dc":
# XML Dublin Core format, possibly OAI -- select only some bibXXx fields:
out += """ \n"""
if record_exist_p == -1:
out += ""
else:
for f in get_fieldvalues(recID, "041__a"):
out += " %s\n" % f
for f in get_fieldvalues(recID, "100__a"):
out += " %s\n" % encode_for_xml(f)
for f in get_fieldvalues(recID, "700__a"):
out += " %s\n" % encode_for_xml(f)
for f in get_fieldvalues(recID, "245__a"):
out += " %s\n" % encode_for_xml(f)
for f in get_fieldvalues(recID, "65017a"):
out += " %s\n" % encode_for_xml(f)
for f in get_fieldvalues(recID, "8564_u"):
out += " %s\n" % encode_for_xml(f)
for f in get_fieldvalues(recID, "520__a"):
out += " %s\n" % encode_for_xml(f)
out += " %s\n" % get_creation_date(recID)
out += " \n"
elif str(format[0:3]).isdigit():
# user has asked to print some fields only
if format == "001":
out += "%s\n" % (format, recID, format)
else:
vals = get_fieldvalues(recID, format)
for val in vals:
out += "%s\n" % (format, val, format)
elif format.startswith('t'):
## user directly asked for some tags to be displayed only
if record_exist_p == -1:
out += get_fieldvalues_alephseq_like(recID, "001,%s,980" % cfg_oaiidtag)
else:
out += get_fieldvalues_alephseq_like(recID, ot)
elif format == "hm":
if record_exist_p == -1:
out += "
"
elif format == "hd":
# HTML detailed format
if record_exist_p == -1:
out += _("The record has been deleted.")
else:
# look for detailed format existence:
query = "SELECT value FROM bibfmt WHERE id_bibrec='%s' AND format='%s'" % (recID, format)
res = run_sql(query, None, 1)
if res:
# record 'recID' is formatted in 'format', so print it
out += "%s" % decompress(res[0][0])
else:
# record 'recID' is not formatted in 'format', so try to call BibFormat on the fly or use default format:
out_record_in_format = call_bibformat(recID, format)
if out_record_in_format:
out += out_record_in_format
else:
out += websearch_templates.tmpl_print_record_detailed(
ln = ln,
recID = recID,
weburl = weburl,
)
elif format.startswith("hb_") or format.startswith("hd_"):
# underscore means that HTML brief/detailed formats should be called on-the-fly; suitable for testing formats
if record_exist_p == -1:
out += _("The record has been deleted.")
else:
out += call_bibformat(recID, format)
elif format.startswith("hx"):
# BibTeX format, called on the fly:
if record_exist_p == -1:
out += _("The record has been deleted.")
else:
out += call_bibformat(recID, format)
elif format.startswith("hs"):
# for citation/download similarity navigation links:
if record_exist_p == -1:
out += _("The record has been deleted.")
else:
out += '' % websearch_templates.build_search_url(recid=recID, ln=ln)
# firstly, title:
titles = get_fieldvalues(recID, "245__a")
if titles:
for title in titles:
out += "%s" % title
else:
# usual title not found, try conference title:
titles = get_fieldvalues(recID, "111__a")
if titles:
for title in titles:
out += "%s" % title
else:
# just print record ID:
out += "%s %d" % (get_field_i18nname("record ID", ln), recID)
out += ""
# secondly, authors:
authors = get_fieldvalues(recID, "100__a") + get_fieldvalues(recID, "700__a")
if authors:
out += " - %s" % authors[0]
if len(authors) > 1:
out += " et al"
# thirdly publication info:
publinfos = get_fieldvalues(recID, "773__s")
if not publinfos:
publinfos = get_fieldvalues(recID, "909C4s")
if not publinfos:
publinfos = get_fieldvalues(recID, "037__a")
if not publinfos:
publinfos = get_fieldvalues(recID, "088__a")
if publinfos:
out += " - %s" % publinfos[0]
else:
# fourthly publication year (if not publication info):
years = get_fieldvalues(recID, "773__y")
if not years:
years = get_fieldvalues(recID, "909C4y")
if not years:
years = get_fieldvalues(recID, "260__c")
if years:
out += " (%s)" % years[0]
else:
# HTML brief format by default
if record_exist_p == -1:
out += _("The record has been deleted.")
else:
query = "SELECT value FROM bibfmt WHERE id_bibrec='%s' AND format='%s'" % (recID, format)
res = run_sql(query)
if res:
# record 'recID' is formatted in 'format', so print it
out += "%s" % decompress(res[0][0])
else:
# record 'recID' is not formatted in 'format', so try to call BibFormat on the fly: or use default format:
if cfg_call_bibformat:
out_record_in_format = call_bibformat(recID, format)
if out_record_in_format:
out += out_record_in_format
else:
out += websearch_templates.tmpl_print_record_brief(
ln = ln,
recID = recID,
weburl = weburl,
)
else:
out += websearch_templates.tmpl_print_record_brief(
ln = ln,
recID = recID,
weburl = weburl,
)
# at the end of HTML brief mode, print the "Detailed record" functionality:
if format == 'hp' or format.startswith("hb_") or format.startswith("hd_"):
pass # do nothing for portfolio and on-the-fly formats
else:
out += websearch_templates.tmpl_print_record_brief_links(
ln = ln,
recID = recID,
weburl = weburl,
)
# print record closing tags, if needed:
if format == "marcxml" or format == "oai_dc":
out += " \n"
out += " \n"
return out
def encode_for_xml(s):
"Encode special chars in string so that it would be XML-compliant."
s = string.replace(s, '&', '&')
s = string.replace(s, '<', '<')
return s
def call_bibformat(recID, format="HD"):
"""Calls BibFormat for the record RECID in the desired output format FORMAT.
This function is mainly used to display all but brief formats, if they are
not stored in the 'bibfmt' table.
Note: this functions always try to return HTML, so when
bibformat returns XML with embedded HTML format inside the tag
FMT $g, as is suitable for prestoring output formats, we
perform un-XML-izing here in order to return HTML body only.
"""
out = ""
pipe_input, pipe_output, pipe_error = os.popen3(["%s/bibformat" % bindir, "otype=%s" % format], 'rw')
pipe_input.write(print_record(recID, "xm"))
pipe_input.close()
bibformat_output = pipe_output.read()
pipe_output.close()
pipe_error.close()
if bibformat_output.startswith(""):
dom = minidom.parseString(bibformat_output)
for e in dom.getElementsByTagName('subfield'):
if e.getAttribute('code') == 'g':
for t in e.childNodes:
out += t.data.encode('utf-8')
else:
out = bibformat_output
return out
def log_query(hostname, query_args, uid=-1):
"""Log query into the query and user_query tables."""
if uid > 0:
# log the query only if uid is reasonable
res = run_sql("SELECT id FROM query WHERE urlargs=%s", (query_args,), 1)
try:
id_query = res[0][0]
except:
id_query = run_sql("INSERT INTO query (type, urlargs) VALUES ('r', %s)", (query_args,))
if id_query:
run_sql("INSERT INTO user_query (id_user, id_query, hostname, date) VALUES (%s, %s, %s, %s)",
(uid, id_query, hostname,
time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())))
return
def log_query_info(action, p, f, colls, nb_records_found_total=-1):
"""Write some info to the log file for later analysis."""
try:
log = open(logdir + "/search.log", "a")
log.write(time.strftime("%Y%m%d%H%M%S#", time.localtime()))
log.write(action+"#")
log.write(p+"#")
log.write(f+"#")
for coll in colls[:-1]:
log.write("%s," % coll)
log.write("%s#" % colls[-1])
log.write("%d" % nb_records_found_total)
log.write("\n")
log.close()
except:
pass
return
def wash_url_argument(var, new_type):
"""Wash list argument into 'new_type', that can be 'list',
'str', or 'int'. Useful for washing mod_python passed
arguments, that are all lists of strings (URL args may be
multiple), but we sometimes want only to take the first value,
and sometimes to represent it as string or numerical value."""
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 = string.atoi(var[0])
except:
out = 0
elif type(var) is int:
out = var
elif type(var) is str:
try:
out = string.atoi(var)
except:
out = 0
else:
out = 0
return out
### CALLABLES
def perform_request_search(req=None, cc=cdsname, c=None, p="", f="", rg=10, sf="", so="d", sp="", rm="", of="id", ot="", as=0,
p1="", f1="", m1="", op1="", p2="", f2="", m2="", op2="", p3="", f3="", m3="", sc=0, jrec=0,
recid=-1, recidb=-1, sysno="", id=-1, idb=-1, sysnb="", action="",
d1y=0, d1m=0, d1d=0, d2y=0, d2m=0, d2d=0, verbose=0, ap=0, ln=cdslang):
"""Perform search or browse request, without checking for
authentication. Return list of recIDs found, if of=id.
Otherwise create web page.
The arguments are as follows:
req - mod_python Request class instance.
cc - current collection (e.g. "ATLAS"). The collection the
user started to search/browse from.
c - collectin list (e.g. ["Theses", "Books"]). The
collections user may have selected/deselected when
starting to search from 'cc'.
p - pattern to search for (e.g. "ellis and muon or kaon").
f - field to search within (e.g. "author").
rg - records in groups of (e.g. "10"). Defines how many hits
per collection in the search results page are
displayed.
sf - sort field (e.g. "title").
so - sort order ("a"=ascending, "d"=descending).
sp - sort pattern (e.g. "CERN-") -- in case there are more
values in a sort field, this argument tells which one
to prefer
rm - ranking method (e.g. "jif"). Defines whether results
should be ranked by some known ranking method.
of - output format (e.g. "hb"). Usually starting "h" means
HTML output (and "hb" for HTML brief, "hd" for HTML
detailed), "x" means XML output, "t" means plain text
output, "id" means no output at all but to return list
of recIDs found. (Suitable for high-level API.)
ot - output only these MARC tags (e.g. "100,700,909C0b").
Useful if only some fields are to be shown in the
output, e.g. for library to control some fields.
as - advanced search ("0" means no, "1" means yes). Whether
search was called from within the advanced search
interface.
p1 - first pattern to search for in the advanced search
interface. Much like 'p'.
f1 - first field to search within in the advanced search
interface. Much like 'f'.
m1 - first matching type in the advanced search interface.
("a" all of the words, "o" any of the words, "e" exact
phrase, "p" partial phrase, "r" regular expression).
op1 - first operator, to join the first and the second unit
in the advanced search interface. ("a" add, "o" or,
"n" not).
p2 - second pattern to search for in the advanced search
interface. Much like 'p'.
f2 - second field to search within in the advanced search
interface. Much like 'f'.
m2 - second matching type in the advanced search interface.
("a" all of the words, "o" any of the words, "e" exact
phrase, "p" partial phrase, "r" regular expression).
op2 - second operator, to join the second and the third unit
in the advanced search interface. ("a" add, "o" or,
"n" not).
p3 - third pattern to search for in the advanced search
interface. Much like 'p'.
f3 - third field to search within in the advanced search
interface. Much like 'f'.
m3 - third matching type in the advanced search interface.
("a" all of the words, "o" any of the words, "e" exact
phrase, "p" partial phrase, "r" regular expression).
sc - split by collection ("0" no, "1" yes). Governs whether
we want to present the results in a single huge list,
or splitted by collection.
jrec - jump to record (e.g. "234"). Used for navigation
inside the search results.
recid - display record ID (e.g. "20000"). Do not
search/browse but go straight away to the Detailed
record page for the given recID.
recidb - display record ID bis (e.g. "20010"). If greater than
'recid', then display records from recid to recidb.
Useful for example for dumping records from the
database for reformatting.
sysno - display old system SYS number (e.g. ""). If you
migrate to CDS Invenio from another system, and store your
old SYS call numbers, you can use them instead of recid
if you wish so.
id - the same as recid, in case recid is not set. For
backwards compatibility.
idb - the same as recid, in case recidb is not set. For
backwards compatibility.
sysnb - the same as sysno, in case sysno is not set. For
backwards compatibility.
action - action to do. "SEARCH" for searching, "Browse" for
browsing. Default is to search.
d1y - first date year (e.g. "1998"). Useful for search
limits on creation date.
d1m - first date month (e.g. "08"). Useful for search
limits on creation date.
d1d - first date day (e.g. "23"). Useful for search
limits on creation date.
d2y - second date year (e.g. "1998"). Useful for search
limits on creation date.
d2m - second date month (e.g. "09"). Useful for search
limits on creation date.
d2d - second date day (e.g. "02"). Useful for search limits
on creation date.
verbose - verbose level (0=min, 9=max). Useful to print some
internal information on the searching process in case
something goes wrong.
ap - alternative patterns (0=no, 1=yes). In case no exact
match is found, the search engine can try alternative
patterns e.g. to replace non-alphanumeric characters by
a boolean query. ap defines if this is wanted.
ln - language of the search interface (e.g. "en"). Useful
for internationalization.
"""
# wash all arguments requiring special care
(cc, colls_to_display, colls_to_search) = wash_colls(cc, c, sc) # which colls to search and to display?
p = wash_pattern(p)
f = wash_field(f)
p1 = wash_pattern(p1)
f1 = wash_field(f1)
p2 = wash_pattern(p2)
f2 = wash_field(f2)
p3 = wash_pattern(p3)
f3 = wash_field(f3)
day1, day2 = wash_dates(d1y, d1m, d1d, d2y, d2m, d2d)
_ = gettext_set_language(ln)
# backwards compatibility: id, idb, sysnb -> recid, recidb, sysno (if applicable)
if sysnb != "" and sysno == "":
sysno = sysnb
if id > 0 and recid == -1:
recid = id
if idb > 0 and recidb == -1:
recidb = idb
# TODO deduce passed search limiting criterias (if applicable)
pl, pl_in_url = "", "" # no limits by default
if action != "browse" and req and req.args: # we do not want to add options while browsing or while calling via command-line
fieldargs = cgi.parse_qs(req.args)
for fieldcode in get_fieldcodes():
if fieldargs.has_key(fieldcode):
for val in fieldargs[fieldcode]:
pl += "+%s:\"%s\" " % (fieldcode, val)
pl_in_url += "&%s=%s" % (urllib.quote(fieldcode), urllib.quote(val))
# deduce recid from sysno argument (if applicable):
if sysno: # ALEPH SYS number was passed, so deduce DB recID for the record:
recid = get_mysql_recid_from_aleph_sysno(sysno)
# deduce collection we are in (if applicable):
if recid>0:
cc = guess_primary_collection_of_a_record(recid)
# deduce user id (if applicable):
try:
uid = getUid(req)
except:
uid = 0
## 0 - start output
if recid>0:
## 1 - detailed record display
title, description, keywords = \
websearch_templates.tmpl_record_page_header_content(req, recid, ln)
page_start(req, of, cc, as, ln, uid, title, description, keywords)
if of == "hb":
of = "hd"
if record_exists(recid):
if recidb<=recid: # sanity check
recidb=recid+1
print_records(req, range(recid,recidb), -1, -9999, of, ot, ln)
if req and of.startswith("h"): # register detailed record page view event
client_ip_address = str(req.get_remote_host(apache.REMOTE_NOLOOKUP))
register_page_view_event(recid, uid, client_ip_address)
else: # record does not exist
if of.startswith("h"):
print_warning(req, "Requested record does not seem to exist.")
elif action == "browse":
## 2 - browse needed
page_start(req, of, cc, as, ln, uid, _("Browse"))
if of.startswith("h"):
req.write(create_search_box(cc, colls_to_display, p, f, rg, sf, so, sp, rm, of, ot, as, ln, p1, f1, m1, op1,
p2, f2, m2, op2, p3, f3, m3, sc, pl, d1y, d1m, d1d, d2y, d2m, d2d, jrec, action))
try:
if as==1 or (p1 or p2 or p3):
browse_pattern(req, colls_to_search, p1, f1, rg)
browse_pattern(req, colls_to_search, p2, f2, rg)
browse_pattern(req, colls_to_search, p3, f3, rg)
else:
browse_pattern(req, colls_to_search, p, f, rg)
except:
if of.startswith("h"):
req.write(create_error_box(req, verbose=verbose, ln=ln))
return page_end(req, of, ln)
elif rm and p.startswith("recid:"):
## 3-ter - similarity search needed
page_start(req, of, cc, as, ln, uid, _("Search Results"))
if of.startswith("h"):
req.write(create_search_box(cc, colls_to_display, p, f, rg, sf, so, sp, rm, of, ot, as, ln, p1, f1, m1, op1,
p2, f2, m2, op2, p3, f3, m3, sc, pl, d1y, d1m, d1d, d2y, d2m, d2d, jrec, action))
if record_exists(p[6:]) != 1:
# record does not exist
if of.startswith("h"):
print_warning(req, "Requested record does not seem to exist.")
if of == "id":
return []
else:
# record well exists, so find similar ones to it
t1 = os.times()[4]
results_similar_recIDs, results_similar_relevances, results_similar_relevances_prologue, results_similar_relevances_epilogue, results_similar_comments = \
rank_records(rm, 0, get_collection_reclist(cdsname), string.split(p), verbose)
if results_similar_recIDs:
t2 = os.times()[4]
cpu_time = t2 - t1
if of.startswith("h"):
req.write(print_search_info(p, f, sf, so, sp, rm, of, ot, cdsname, len(results_similar_recIDs),
jrec, rg, as, ln, p1, p2, p3, f1, f2, f3, m1, m2, m3, op1, op2,
sc, pl_in_url,
d1y, d1m, d1d, d2y, d2m, d2d, cpu_time))
print_warning(req, results_similar_comments)
print_records(req, results_similar_recIDs, jrec, rg, of, ot, ln,
results_similar_relevances, results_similar_relevances_prologue, results_similar_relevances_epilogue)
elif of=="id":
return results_similar_recIDs
else:
# rank_records failed and returned some error message to display:
if of.startswith("h"):
print_warning(req, results_similar_relevances_prologue)
print_warning(req, results_similar_relevances_epilogue)
print_warning(req, results_similar_comments)
if of == "id":
return []
elif cfg_experimental_features and p.startswith("cocitedwith:"):
## 3-terter - cited by search needed
page_start(req, of, cc, as, ln, uid, _("Search Results"))
if of.startswith("h"):
req.write(create_search_box(cc, colls_to_display, p, f, rg, sf, so, sp, rm, of, ot, as, ln, p1, f1, m1, op1,
p2, f2, m2, op2, p3, f3, m3, sc, pl, d1y, d1m, d1d, d2y, d2m, d2d, jrec, action))
recID = p[12:]
if record_exists(recID) != 1:
# record does not exist
if of.startswith("h"):
print_warning(req, "Requested record does not seem to exist.")
if of == "id":
return []
else:
# record well exists, so find co-cited ones:
t1 = os.times()[4]
results_cocited_recIDs = map(lambda x: x[0], calculate_co_cited_with_list(int(recID)))
if results_cocited_recIDs:
t2 = os.times()[4]
cpu_time = t2 - t1
if of.startswith("h"):
req.write(print_search_info(p, f, sf, so, sp, rm, of, ot, cdsname, len(results_cocited_recIDs),
jrec, rg, as, ln, p1, p2, p3, f1, f2, f3, m1, m2, m3, op1, op2,
sc, pl_in_url,
d1y, d1m, d1d, d2y, d2m, d2d, cpu_time))
print_records(req, results_cocited_recIDs, jrec, rg, of, ot, ln)
elif of=="id":
return results_cocited_recIDs
else:
# cited rank_records failed and returned some error message to display:
if of.startswith("h"):
print_warning(req, "nothing found")
if of == "id":
return []
else:
## 3 - common search needed
page_start(req, of, cc, as, ln, uid, _("Search Results"))
if of.startswith("h"):
req.write(create_search_box(cc, colls_to_display, p, f, rg, sf, so, sp, rm, of, ot, as, ln, p1, f1, m1, op1,
p2, f2, m2, op2, p3, f3, m3, sc, pl, d1y, d1m, d1d, d2y, d2m, d2d, jrec, action))
t1 = os.times()[4]
results_in_any_collection = HitSet()
if as == 1 or (p1 or p2 or p3):
## 3A - advanced search
try:
results_in_any_collection = search_pattern(req, p1, f1, m1, ap=ap, of=of, verbose=verbose, ln=ln)
if results_in_any_collection._nbhits == 0:
if of.startswith("h"):
req.write(create_google_box(cc, p, f, p1, p2, p3, ln))
return page_end(req, of, ln)
if p2:
results_tmp = search_pattern(req, p2, f2, m2, ap=ap, of=of, verbose=verbose, ln=ln)
if op1 == "a": # add
results_in_any_collection.intersect(results_tmp)
elif op1 == "o": # or
results_in_any_collection.union(results_tmp)
elif op1 == "n": # not
results_in_any_collection.difference(results_tmp)
else:
if of.startswith("h"):
print_warning(req, "Invalid set operation %s." % op1, "Error")
results_in_any_collection.calculate_nbhits()
if results_in_any_collection._nbhits == 0:
if of.startswith("h"):
req.write(create_google_box(cc, p, f, p1, p2, p3, ln))
return page_end(req, of, ln)
if p3:
results_tmp = search_pattern(req, p3, f3, m3, ap=ap, of=of, verbose=verbose, ln=ln)
if op2 == "a": # add
results_in_any_collection.intersect(results_tmp)
elif op2 == "o": # or
results_in_any_collection.union(results_tmp)
elif op2 == "n": # not
results_in_any_collection.difference(results_tmp)
else:
if of.startswith("h"):
print_warning(req, "Invalid set operation %s." % op2, "Error")
results_in_any_collection.calculate_nbhits()
except:
if of.startswith("h"):
req.write(create_error_box(req, verbose=verbose, ln=ln))
req.write(create_google_box(cc, p, f, p1, p2, p3, ln))
return page_end(req, of, ln)
else:
## 3B - simple search
try:
results_in_any_collection = search_pattern(req, p, f, ap=ap, of=of, verbose=verbose, ln=ln)
except:
if of.startswith("h"):
req.write(create_error_box(req, verbose=verbose, ln=ln))
req.write(create_google_box(cc, p, f, p1, p2, p3, ln))
return page_end(req, of, ln)
if results_in_any_collection._nbhits == 0:
if of.startswith("h"):
req.write(create_google_box(cc, p, f, p1, p2, p3, ln))
return page_end(req, of, ln)
# search_cache_key = p+"@"+f+"@"+string.join(colls_to_search,",")
# if search_cache.has_key(search_cache_key): # is the result in search cache?
# results_final = search_cache[search_cache_key]
# else:
# results_final = search_pattern(req, p, f, colls_to_search)
# search_cache[search_cache_key] = results_final
# if len(search_cache) > cfg_search_cache_size: # is the cache full? (sanity cleaning)
# search_cache.clear()
# search stage 4: intersection with collection universe:
try:
results_final = intersect_results_with_collrecs(req, results_in_any_collection, colls_to_search, ap, of, verbose, ln)
except:
if of.startswith("h"):
req.write(create_error_box(req, verbose=verbose, ln=ln))
req.write(create_google_box(cc, p, f, p1, p2, p3, ln))
return page_end(req, of, ln)
if results_final == {}:
if of.startswith("h"):
req.write(create_google_box(cc, p, f, p1, p2, p3, ln))
return page_end(req, of, ln)
# search stage 5: apply search option limits and restrictions:
if day1 != "":
try:
results_final = intersect_results_with_hitset(req,
results_final,
search_unit_in_bibrec(day1, day2),
ap,
aptext= _("No match within your time limits, "
"discarding this condition..."),
of=of)
except:
if of.startswith("h"):
req.write(create_error_box(req, verbose=verbose, ln=ln))
req.write(create_google_box(cc, p, f, p1, p2, p3, ln))
return page_end(req, of, ln)
if results_final == {}:
if of.startswith("h"):
req.write(create_google_box(cc, p, f, p1, p2, p3, ln))
return page_end(req, of, ln)
if pl:
try:
results_final = intersect_results_with_hitset(req,
results_final,
search_pattern(req, pl, ap=0, ln=ln),
ap,
aptext=_("No match within your search limits, "
"discarding this condition..."),
of=of)
except:
if of.startswith("h"):
req.write(create_error_box(req, verbose=verbose, ln=ln))
req.write(create_google_box(cc, p, f, p1, p2, p3, ln))
return page_end(req, of, ln)
if results_final == {}:
if of.startswith("h"):
req.write(create_google_box(cc, p, f, p1, p2, p3, ln))
return page_end(req, of, ln)
t2 = os.times()[4]
cpu_time = t2 - t1
## search stage 6: display results:
results_final_nb_total = 0
results_final_nb = {} # will hold number of records found in each collection
# (in simple dict to display overview more easily; may refactor later)
for coll in results_final.keys():
results_final_nb[coll] = results_final[coll]._nbhits
results_final_nb_total += results_final_nb[coll]
if results_final_nb_total == 0:
if of.startswith('h'):
print_warning(req, "No match found, please enter different search terms.")
else:
# yes, some hits found: good!
# collection list may have changed due to not-exact-match-found policy so check it out:
for coll in results_final.keys():
if coll not in colls_to_search:
colls_to_search.append(coll)
# print results overview:
if of == "id":
# we have been asked to return list of recIDs
results_final_for_all_colls = HitSet()
for coll in results_final.keys():
results_final_for_all_colls.union(results_final[coll])
recIDs = results_final_for_all_colls.items().tolist()
if sf: # do we have to sort?
recIDs = sort_records(req, recIDs, sf, so, sp, verbose, of)
elif rm: # do we have to rank?
results_final_for_all_colls_rank_records_output = rank_records(rm, 0, results_final_for_all_colls,
string.split(p) + string.split(p1) +
string.split(p2) + string.split(p3), verbose)
if results_final_for_all_colls_rank_records_output[0]:
recIDs = results_final_for_all_colls_rank_records_output[0]
return recIDs
elif of.startswith("h"):
req.write(print_results_overview(req, colls_to_search, results_final_nb_total, results_final_nb, cpu_time, ln))
# print records:
if len(colls_to_search)>1:
cpu_time = -1 # we do not want to have search time printed on each collection
for coll in colls_to_search:
if results_final.has_key(coll) and results_final[coll]._nbhits:
if of.startswith("h"):
req.write(print_search_info(p, f, sf, so, sp, rm, of, ot, coll, results_final_nb[coll],
jrec, rg, as, ln, p1, p2, p3, f1, f2, f3, m1, m2, m3, op1, op2,
sc, pl_in_url,
d1y, d1m, d1d, d2y, d2m, d2d, cpu_time))
results_final_recIDs = results_final[coll].items()
results_final_relevances = []
results_final_relevances_prologue = ""
results_final_relevances_epilogue = ""
if sf: # do we have to sort?
results_final_recIDs = sort_records(req, results_final_recIDs, sf, so, sp, verbose, of)
elif rm: # do we have to rank?
results_final_recIDs_ranked, results_final_relevances, results_final_relevances_prologue, results_final_relevances_epilogue, results_final_comments = \
rank_records(rm, 0, results_final[coll],
string.split(p) + string.split(p1) +
string.split(p2) + string.split(p3), verbose)
if of.startswith("h"):
print_warning(req, results_final_comments)
if results_final_recIDs_ranked:
results_final_recIDs = results_final_recIDs_ranked
else:
# rank_records failed and returned some error message to display:
print_warning(req, results_final_relevances_prologue)
print_warning(req, results_final_relevances_epilogue)
print_records(req, results_final_recIDs, jrec, rg, of, ot, ln,
results_final_relevances, results_final_relevances_prologue, results_final_relevances_epilogue)
if of.startswith("h"):
req.write(print_search_info(p, f, sf, so, sp, rm, of, ot, coll, results_final_nb[coll],
jrec, rg, as, ln, p1, p2, p3, f1, f2, f3, m1, m2, m3, op1, op2,
sc, pl_in_url,
d1y, d1m, d1d, d2y, d2m, d2d, cpu_time, 1))
if f == "author" and of.startswith("h"):
req.write(create_similarly_named_authors_link_box(p, ln))
# log query:
try:
log_query(req.get_remote_host(), req.args, uid)
except:
# do not log query if req is None (used by CLI interface)
pass
log_query_info("ss", p, f, colls_to_search, results_final_nb_total)
## 4 - write footer:
if of.startswith("h"):
req.write(create_google_box(cc, p, f, p1, p2, p3, ln))
return page_end(req, of, ln)
def perform_request_cache(req, action="show"):
"""Manipulates the search engine cache."""
global search_cache
global collection_reclist_cache
global collection_reclist_cache_timestamp
global field_i18nname_cache
global field_i18nname_cache_timestamp
global collection_i18nname_cache
global collection_i18nname_cache_timestamp
req.content_type = "text/html"
req.send_http_header()
out = ""
out += "
Search Cache
"
# clear cache if requested:
if action == "clear":
search_cache = {}
collection_reclist_cache = create_collection_reclist_cache()
# show collection reclist cache:
out += "
Collection reclist cache
"
res = run_sql("SHOW TABLE STATUS LIKE 'collection'")
out += "- collection table last updated: %s" % str(res[0][11])
out += " - reclist cache timestamp: %s" % collection_reclist_cache_timestamp
out += " - reclist cache contents:"
out += "
"
for coll in collection_reclist_cache.keys():
if collection_reclist_cache[coll]:
out += "%s (%d) " % (coll, get_collection_reclist(coll)._nbhits)
out += "
"
# show search cache:
out += "
Search Cache
"
out += "
"
if len(search_cache):
out += """
"""
out += "
%s
%s
%s
%s
" % ("Pattern","Field","Collection","Number of Hits")
for search_cache_key in search_cache.keys():
p, f, c = string.split(search_cache_key, "@", 2)
# find out about length of cached data:
l = 0
for coll in search_cache[search_cache_key]:
l += search_cache[search_cache_key][coll]._nbhits
out += "
%s
%s
%s
%d
" % (p, f, c, l)
out += "
"
else:
out += "
Search cache is empty."
out += "
"
out += """
clear cache""" % weburl
# show field i18nname cache:
out += "
Field I18N names cache
"
res = run_sql("SHOW TABLE STATUS LIKE 'fieldname'")
out += "- fieldname table last updated: %s" % str(res[0][11])
out += " - i18nname cache timestamp: %s" % field_i18nname_cache_timestamp
out += " - i18nname cache contents:"
out += "
"
for field in field_i18nname_cache.keys():
for ln in field_i18nname_cache[field].keys():
out += "%s, %s = %s " % (field, ln, field_i18nname_cache[field][ln])
out += "
"
# show collection i18nname cache:
out += "
Collection I18N names cache
"
res = run_sql("SHOW TABLE STATUS LIKE 'collectionname'")
out += "- collectionname table last updated: %s" % str(res[0][11])
out += " - i18nname cache timestamp: %s" % collection_i18nname_cache_timestamp
out += " - i18nname cache contents:"
out += "
"
for coll in collection_i18nname_cache.keys():
for ln in collection_i18nname_cache[coll].keys():
out += "%s, %s = %s " % (coll, ln, collection_i18nname_cache[coll][ln])
out += "
"
req.write(out)
return "\n"
def perform_request_log(req, date=""):
"""Display search log information for given date."""
req.content_type = "text/html"
req.send_http_header()
req.write("
Search Log
")
if date: # case A: display stats for a day
yyyymmdd = string.atoi(date)
req.write("
Date: %d
" % yyyymmdd)
req.write("""
""")
req.write("
%s
%s
%s
%s
%s
%s
" % ("No.","Time", "Pattern","Field","Collection","Number of Hits"))
# read file:
p = os.popen("grep ^%d %s/search.log" % (yyyymmdd,logdir), 'r')
lines = p.readlines()
p.close()
# process lines:
i = 0
for line in lines:
try:
datetime, as, p, f, c, nbhits = string.split(line,"#")
i += 1
req.write("
")
else: # case B: display summary stats per day
yyyymm01 = int(time.strftime("%Y%m01", time.localtime()))
yyyymmdd = int(time.strftime("%Y%m%d", time.localtime()))
req.write("""
""")
req.write("
%s
%s
" % ("Day", "Number of Queries"))
for day in range(yyyymm01,yyyymmdd+1):
p = os.popen("grep -c ^%d %s/search.log" % (day,logdir), 'r')
for line in p.readlines():
req.write("""
")
return "\n"
def profile(p="", f="", c=cdsname):
"""Profile search time."""
import profile
import pstats
profile.run("perform_request_search(p='%s',f='%s', c='%s')" % (p, f, c), "perform_request_search_profile")
p = pstats.Stats("perform_request_search_profile")
p.strip_dirs().sort_stats("cumulative").print_stats()
return 0
## test cases:
#print wash_colls(cdsname,"Library Catalogue", 0)
#print wash_colls("Periodicals & Progress Reports",["Periodicals","Progress Reports"], 0)
#print wash_field("wau")
#print print_record(20,"tm","001,245")
#print create_opft_search_units(None, "PHE-87-13","reportnumber")
#print ":"+wash_pattern("* and % doo * %")+":\n"
#print ":"+wash_pattern("*")+":\n"
#print ":"+wash_pattern("ellis* ell* e*%")+":\n"
#print run_sql("SELECT name,dbquery from collection")
#print get_index_id("author")
#print get_coll_ancestors("Theses")
#print get_coll_sons("Articles & Preprints")
#print get_coll_real_descendants("Articles & Preprints")
#print get_collection_reclist("Theses")
#print log(sys.stdin)
#print search_unit_in_bibrec('2002-12-01','2002-12-12')
#print type(wash_url_argument("-1",'int'))
#print get_nearest_terms_in_bibxxx("ellis", "author", 5, 5)
#print call_bibformat(68, "HB_FLY")
#print create_collection_i18nname_cache()
#print get_fieldvalues_alephseq_like(11,"980__a")
## profiling:
#profile("of the this")
#print perform_request_search(p="ellis")
diff --git a/modules/websearch/lib/websearch_templates.py b/modules/websearch/lib/websearch_templates.py
index 30a283a5c..6c269d4b8 100644
--- a/modules/websearch/lib/websearch_templates.py
+++ b/modules/websearch/lib/websearch_templates.py
@@ -1,2469 +1,2465 @@
# -*- coding: utf-8 -*-
## $Id$
## This file is part of CDS Invenio.
## Copyright (C) 2002, 2003, 2004, 2005, 2006 CERN.
##
## CDS Invenio is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License as
## published by the Free Software Foundation; either version 2 of the
## License, or (at your option) any later version.
##
## CDS Invenio is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
import urllib
import time
import cgi
import gettext
import string
import locale
import sre
from invenio.config import *
from invenio.dbquery import run_sql
from invenio.messages import gettext_set_language
from invenio.search_engine_config import *
from invenio.urlutils import make_canonical_urlargd, drop_default_urlargd, a_href
def get_fieldvalues(recID, tag):
"""Return list of field values for field TAG inside record RECID.
FIXME: should be imported commonly for search_engine too."""
out = []
if tag == "001___":
# we have asked for recID that is not stored in bibXXx tables
out.append(str(recID))
else:
# we are going to look inside bibXXx tables
digit = tag[0:2]
bx = "bib%sx" % digit
bibx = "bibrec_bib%sx" % digit
query = "SELECT bx.value FROM %s AS bx, %s AS bibx WHERE bibx.id_bibrec='%s' AND bx.id=bibx.id_bibxxx AND bx.tag LIKE '%s'" \
"ORDER BY bibx.field_number, bx.tag ASC" % (bx, bibx, recID, tag)
res = run_sql(query)
for row in res:
out.append(row[0])
return out
class Template:
# This dictionary maps CDS Invenio language code to locale codes (ISO 639)
tmpl_localemap = {
'bg': 'bg_BG',
'ca': 'ca_ES',
'de': 'de_DE',
'el': 'el_GR',
'en': 'en_US',
'es': 'es_ES',
'pt': 'pt_BR',
'fr': 'fr_FR',
'it': 'it_IT',
'ru': 'ru_RU',
'sk': 'sk_SK',
'cs': 'cs_CZ',
'no': 'no_NO',
'sv': 'sv_SE',
'uk': 'uk_UA',
'ja': 'ja_JA',
'pl': 'pl_PL'
}
tmpl_default_locale = "en_US" # which locale to use by default, useful in case of failure
# Type of the allowed parameters for the web interface for search results
search_results_default_urlargd = {
'cc': (str, cdsname), 'c': (list, []),
'p': (str, ""), 'f': (str, ""),
'rg': (int, 10),
'sf': (str, ""),
'so': (str, "d"),
'sp': (str, ""),
'rm': (str, ""),
'of': (str, "hb"),
'ot': (list, []),
'as': (int, 0),
'p1': (str, ""), 'f1': (str, ""), 'm1': (str, ""), 'op1':(str, ""),
'p2': (str, ""), 'f2': (str, ""), 'm2': (str, ""), 'op2':(str, ""),
'p3': (str, ""), 'f3': (str, ""), 'm3': (str, ""),
'sc': (int, 0),
'jrec': (int, 0),
'recid': (int, -1), 'recidb': (int, -1), 'sysno': (str, ""),
'id': (int, -1), 'idb': (int, -1), 'sysnb': (str, ""),
'action': (str, "search"),
'action_search': (str, ""),
'action_browse': (str, ""),
'd1y': (int, 0), 'd1m': (int, 0), 'd1d': (int, 0),
'd2y': (int, 0), 'd2m': (int, 0), 'd2d': (int, 0),
'ap': (int, 1),
'verbose': (int, 0),
}
# ...and for search interfaces
search_interface_default_urlargd = {
'as': (int, 0),
'verbose': (int, 0)}
def build_search_url(self, known_parameters={}, **kargs):
""" Helper for generating a canonical search
url. 'known_parameters' is the list of query parameters you
inherit from your current query. You can then pass keyword
arguments to modify this query.
build_search_url(known_parameters, of="xm")
The generated URL is absolute.
"""
parameters = {}
parameters.update(known_parameters)
parameters.update(kargs)
# Now, we only have the arguments which have _not_ their default value
parameters = drop_default_urlargd(parameters, self.search_results_default_urlargd)
# Asking for a recid? Return a /record/ URL
if 'recid' in parameters:
target = "%s/record/%d" % (weburl, parameters['recid'])
del parameters['recid']
target += make_canonical_urlargd(parameters, self.search_results_default_urlargd)
return target
return "%s/search%s" % (weburl, make_canonical_urlargd(parameters, self.search_results_default_urlargd))
def build_search_interface_url(self, known_parameters={}, **kargs):
""" Helper for generating a canonical search interface URL."""
parameters = {}
parameters.update(known_parameters)
parameters.update(kargs)
c = parameters['c']
del parameters['c']
# Now, we only have the arguments which have _not_ their default value
if c and c != cdsname:
base = weburl + '/collection/' + urllib.quote(c)
else:
base = weburl
return base + make_canonical_urlargd(parameters, self.search_results_default_urlargd)
def tmpl_record_page_header_content(self, req, recid, ln):
""" Provide extra information in the header of /record pages """
_ = gettext_set_language(ln)
title = get_fieldvalues(recid, "245__a")
if title:
title = _("Record") + '#%d: %s' %(recid, title[0])
else:
title = _("Record") + ' #%d' % recid
keywords = ', '.join(get_fieldvalues(recid, "6531_a"))
description = ' '.join(get_fieldvalues(recid, "520__a"))
description += "\n"
description += '; '.join(get_fieldvalues(recid, "100__a") + get_fieldvalues(recid, "700__a"))
return [cgi.escape(x, True) for x in (title, description, keywords)]
def tmpl_navtrail_links(self, as, ln, dads):
"""
Creates the navigation bar at top of each search page (*Home > Root collection > subcollection > ...*)
Parameters:
- 'as' *bool* - Should we display an advanced search box?
- 'ln' *string* - The language to display
- 'weburl' *string* - The base URL for the site
- 'separator' *string* - The separator between two consecutive collections
- 'dads' *list* - A list of parent links, eachone being a dictionary of ('name', 'longname')
"""
out = []
for url, name in dads:
out.append(a_href(name, href=self.build_search_interface_url(c=url, as=as, ln=ln), _class='navtrail'))
return ' > '.join(out)
def tmpl_webcoll_body(self, ln, collection, te_portalbox,
searchfor, np_portalbox, narrowsearch,
focuson, instantbrowse, ne_portalbox):
""" Creates the body of the main search page.
Parameters:
- 'ln' *string* - language of the page being generated
- 'collection' - collection id of the page being generated
- 'te_portalbox' *string* - The HTML code for the portalbox on top of search
- 'searchfor' *string* - The HTML code for the search options
- 'np_portalbox' *string* - The HTML code for the portalbox on bottom of search
- 'searchfor' *string* - The HTML code for the search categories (left bottom of page)
- 'focuson' *string* - The HTML code for the "focuson" categories (right bottom of page)
- 'ne_portalbox' *string* - The HTML code for the bottom of the page
"""
if not narrowsearch:
narrowsearch = instantbrowse
body = '''
""" % {'ne_portalbox' : ne_portalbox}
return body
def tmpl_portalbox(self, title, body):
"""Creates portalboxes based on the parameters
Parameters:
- 'title' *string* - The title of the box
- 'body' *string* - The HTML code for the body of the box
"""
out = """
%(title)s
%(body)s
""" % {'title' : title, 'body' : body}
return out
def tmpl_searchfor_simple(self, ln, collection_id, collection_name, record_count, middle_option):
"""Produces simple *Search for* box for the current collection.
Parameters:
- 'ln' *string* - The language to display
- 'header' *string* - header of search form
- 'middle_option' *string* - HTML code for the options (any field, specific fields ...)
"""
# load the right message language
_ = gettext_set_language(ln)
out = '''
'''
argd = drop_default_urlargd({'ln': ln, 'cc': collection_id, 'sc': 1},
self.search_results_default_urlargd)
# Only add non-default hidden values
for field, value in argd.items():
out += self.tmpl_input_hidden(field, value)
header = _("Search %s records for:") % \
self.tmpl_nbrecs_info(record_count, "","")
asearchurl = self.build_search_interface_url(c=collection_id, as=1, ln=ln)
# print commentary start:
out += '''
''' % {'ln' : ln,
'weburl' : weburl,
'asearch' : a_href(_('Advanced Search'), href=asearchurl),
'header' : header,
'middle_option' : middle_option,
'msg_search' : _('Search'),
'msg_browse' : _('Browse'),
'msg_search_tips' : _('Search Tips')}
return out
def tmpl_searchfor_advanced(self,
ln, # current language
collection_id,
collection_name,
record_count,
middle_option_1, middle_option_2, middle_option_3,
searchoptions,
sortoptions,
rankoptions,
displayoptions,
formatoptions
):
"""
Produces advanced *Search for* box for the current collection.
Parameters:
- 'ln' *string* - The language to display
- 'weburl' *string* - The base URL for the site
- 'ssearchurl' *string* - The URL to simple search form
- 'header' *string* - header of search form
- 'middle_option_1' *string* - HTML code for the first row of options (any field, specific fields ...)
- 'middle_option_2' *string* - HTML code for the second row of options (any field, specific fields ...)
- 'middle_option_3' *string* - HTML code for the third row of options (any field, specific fields ...)
- 'searchoptions' *string* - HTML code for the search options
- 'sortoptions' *string* - HTML code for the sort options
- 'rankoptions' *string* - HTML code for the rank options
- 'displayoptions' *string* - HTML code for the display options
- 'formatoptions' *string* - HTML code for the format options
"""
# load the right message language
_ = gettext_set_language(ln)
out = '''
'''
argd = drop_default_urlargd({'ln': ln, 'as': 1, 'cc': collection_id, 'sc': 1},
self.search_results_default_urlargd)
# Only add non-default hidden values
for field, value in argd.items():
out += self.tmpl_input_hidden(field, value)
header = _("Search %s records for") % \
self.tmpl_nbrecs_info(record_count, "","")
header += ':'
ssearchurl = self.build_search_interface_url(c=collection_id, as=0, ln=ln)
out += '''
""" % {
'added' : _("Added since:"),
'until' : _("until:"),
'date_added' : self.tmpl_inputdate("d1", ln=ln),
'date_until' : self.tmpl_inputdate("d2", ln=ln),
'msg_sort' : _("Sort by:"),
'msg_display' : _("Display results:"),
'msg_format' : _("Output format:"),
'sortoptions' : sortoptions,
'rankoptions' : rankoptions,
'displayoptions' : displayoptions,
'formatoptions' : formatoptions
}
return out
def tmpl_matchtype_box(self, name='m', value='', ln='en'):
"""Returns HTML code for the 'match type' selection box.
Parameters:
- 'name' *string* - The name of the produced select
- 'value' *string* - The selected value (if any value is already selected)
- 'ln' *string* - the language to display
"""
# load the right message language
_ = gettext_set_language(ln)
out = """
""" % {'name' : name,
'sela' : self.tmpl_is_selected('a', value),
'opta' : _("All of the words:"),
'selo' : self.tmpl_is_selected('o', value),
'opto' : _("Any of the words:"),
'sele' : self.tmpl_is_selected('e', value),
'opte' : _("Exact phrase:"),
'selp' : self.tmpl_is_selected('p', value),
'optp' : _("Partial phrase:"),
'selr' : self.tmpl_is_selected('r', value),
'optr' : _("Regular expression:")
}
return out
def tmpl_is_selected(self, var, fld):
"""
Checks if *var* and *fld* are equal, and if yes, returns ' selected'. Useful for select boxes.
Parameters:
- 'var' *string* - First value to compare
- 'fld' *string* - Second value to compare
"""
if var == fld:
return " selected"
else:
return ""
def tmpl_andornot_box(self, name='op', value='', ln='en'):
"""
Returns HTML code for the AND/OR/NOT selection box.
Parameters:
- 'name' *string* - The name of the produced select
- 'value' *string* - The selected value (if any value is already selected)
- 'ln' *string* - the language to display
"""
# load the right message language
_ = gettext_set_language(ln)
out = """
""" % {'name' : name,
'sela' : self.tmpl_is_selected('a', value), 'opta' : _("AND"),
'selo' : self.tmpl_is_selected('o', value), 'opto' : _("OR"),
'seln' : self.tmpl_is_selected('n', value), 'optn' : _("AND NOT")
}
return out
def tmpl_inputdate(self, name, ln, sy = 0, sm = 0, sd = 0):
"""
Produces *From Date*, *Until Date* kind of selection box. Suitable for search options.
Parameters:
- 'name' *string* - The base name of the produced selects
- 'ln' *string* - the language to display
"""
# load the right message language
_ = gettext_set_language(ln)
box = """
"""
# month
box += """
"""
# year
box += """
"""
return box
def tmpl_narrowsearch(self, as, ln, type, father,
has_grandchildren, sons, display_grandsons,
grandsons):
"""
Creates list of collection descendants of type *type* under title *title*.
If as==1, then links to Advanced Search interfaces; otherwise Simple Search.
Suitable for 'Narrow search' and 'Focus on' boxes.
Parameters:
- 'as' *bool* - Should we display an advanced search box?
- 'ln' *string* - The language to display
- 'weburl' *string* - The base URL for the site
- 'title' *string* - The title of the produced box
- 'type' *string* - The type of the produced box (virtual collections or normal collections)
- 'father' *collection* - The current collection
- 'has_grandchildren' *bool* - If the current collection has grand children
- 'sons' *list* - The list of the sub-collections (first level)
- 'display_grandsons' *bool* - If the grand children collections should be displayed (2 level deep display)
- 'grandsons' *list* - The list of sub-collections (second level)
"""
# load the right message language
_ = gettext_set_language(ln)
title = {'r': _("Narrow by collection:"),
'v': _("Focus on:")}[type]
if has_grandchildren:
style_prolog = ""
style_epilog = ""
else:
style_prolog = ""
style_epilog = ""
out = """
%(title)s
""" % {'title' : title}
# iterate through sons:
i = 0
for son in sons:
out += """
"""
if type=='r':
if son.restricted_p() and son.restricted_p() != father.restricted_p():
out += """
""" % {'name' : son.name }
else:
out += """ """ % {'name' : son.name }
out += """
%(link)s%(recs)s """ % {
'link': a_href(style_prolog + son.get_name(ln) + style_epilog,
href=self.build_search_interface_url(c=son.name, ln=ln, as=as)),
'recs' : self.tmpl_nbrecs_info(son.nbrecs, ln=ln)}
if son.restricted_p():
out += """ [%(msg)s]""" % { 'msg' : _("restricted") }
if display_grandsons and len(grandsons[i]):
# iterate trough grandsons:
out += """ """
for grandson in grandsons[i]:
out += """ %(link)s%(nbrec)s """ % {
'link': a_href(grandson.get_name(ln),
href=self.build_search_interface_url(c=grandson.name, ln=ln, as=as)),
'nbrec' : self.tmpl_nbrecs_info(grandson.nbrecs, ln=ln)}
out += """
"""
i += 1
out += "
"
return out
def tmpl_nbrecs_info(self, number, prolog=None, epilog=None, ln=cdslang):
"""
Return information on the number of records.
Parameters:
- 'number' *string* - The number of records
- 'prolog' *string* (optional) - An HTML code to prefix the number (if **None**, will be
'(')
- 'epilog' *string* (optional) - An HTML code to append to the number (if **None**, will be
')')
"""
if number is None: return ''
if prolog is None:
prolog = ''' ('''
if epilog is None:
epilog = ''')'''
return prolog + self.tmpl_nice_number(number, ln) + epilog
def tmpl_box_restricted_content(self, ln):
"""
Displays a box containing a *restricted content* message
Parameters:
- 'ln' *string* - The language to display
"""
# load the right message language
_ = gettext_set_language(ln)
return _("The contents of this collection is restricted.")
def tmpl_box_no_records(self, ln):
"""
Displays a box containing a *no content* message
Parameters:
- 'ln' *string* - The language to display
"""
# load the right message language
_ = gettext_set_language(ln)
return _("This collection does not contain any document yet.")
def tmpl_instant_browse(self, as, ln, recids, more_link = None):
"""
Formats a list of records (given in the recids list) from the database.
Parameters:
- 'as' *int* - Advanced Search interface or not (0 or 1)
- 'ln' *string* - The language to display
- 'recids' *list* - the list of records from the database
- 'more_link' *string* - the "More..." link for the record. If not given, will not be displayed
"""
# load the right message language
_ = gettext_set_language(ln)
body = '''
'''
for recid in recids:
body += '''
%(date)s
%(body)s
''' % {'date': recid['date'],
'body': recid['body']
}
body += "
''' % {'header' : _("Latest additions:"),
'body' : body,
}
def tmpl_searchwithin_select(self, ln, fieldname, selected, values):
"""
Produces 'search within' selection box for the current collection.
Parameters:
- 'ln' *string* - The language to display
- 'fieldname' *string* - the name of the select box produced
- 'selected' *string* - which of the values is selected
- 'values' *list* - the list of values in the select
"""
out = '"""
return out
def tmpl_select(self, fieldname, values, selected=None, css_class=''):
"""
Produces a generic select box
Parameters:
- 'css_class' *string* - optional, a css class to display this select with
- 'fieldname' *list* - the name of the select box produced
- 'selected' *string* - which of the values is selected
- 'values' *list* - the list of values in the select
"""
if css_class != '':
class_field = ' class="%s"' % css_class
else:
class_field = ''
out = '"""
return out
def tmpl_record_links(self, weburl, recid, ln):
"""
Displays the *More info* and *Find similar* links for a record
Parameters:
- 'ln' *string* - The language to display
- 'weburl' *string* - The base URL for the site
- 'recid' *string* - the id of the displayed record
"""
# load the right message language
_ = gettext_set_language(ln)
out = ''' %(detailed)s - %(similar)s''' % {
'detailed': a_href(_("Detailed record"), _class="moreinfo",
href=self.build_search_url(recid=recid, ln=ln)),
'similar': a_href(_("Similar records"), _class="moreinfo",
href=self.build_search_url(p="recid:%d" % recid, rm='wrd', ln=ln))}
if cfg_experimental_features:
out += ''' - %s ''' % \
a_href(_("Cited by"), _class="moreinfo",
href=self.build_search_url(p='recid:%d' % recid, rm='cit', ln=ln))
return out
def tmpl_record_body(self, weburl, titles, authors, dates, rns, abstracts, urls_u, urls_z, ln):
"""
Displays the "HTML basic" format of a record
Parameters:
- 'weburl' *string* - The base URL for the site
- 'authors' *list* - the authors (as strings)
- 'dates' *list* - the dates of publication
- 'rns' *list* - the quicknotes for the record
- 'abstracts' *list* - the abstracts for the record
- 'urls_u' *list* - URLs to the original versions of the notice
- 'urls_z' *list* - Not used
"""
out = ""
for title in titles:
out += "%(title)s " % {
'title' : cgi.escape(title)
}
if authors:
out += " / "
for author in authors[:cfg_author_et_al_threshold]:
out += '%s; ' % \
a_href(cgi.escape(author),
href=self.build_search_url(p=author, f='author', ln=ln))
if len(authors) > cfg_author_et_al_threshold:
out += "et al"
for date in dates:
out += " %s." % cgi.escape(date)
for rn in rns:
out += """ [%(rn)s]""" % {'rn' : cgi.escape(rn)}
for abstract in abstracts:
out += " %(abstract)s [...]" % {'abstract' : cgi.escape(abstract[:1+string.find(abstract, '.')]) }
for idx in range(0,len(urls_u)):
out += """ %(name)s""" % {
'url' : urls_u[idx],
'name' : urls_u[idx]
}
return out
def tmpl_search_in_bibwords(self, p, f, ln, nearest_box):
"""
Displays the *Words like current ones* links for a search
Parameters:
- 'p' *string* - Current search words
- 'f' *string* - the fields in which the search was done
- 'nearest_box' *string* - the HTML code for the "nearest_terms" box - most probably from a create_nearest_terms_box call
"""
# load the right message language
_ = gettext_set_language(ln)
-
- out = "
'
if f:
- out += "%(inside)s %(f)s " %{
- 'inside' : _("inside"),
- 'f' : f,
- }
- out += _("in any collection are:") + " "
- out += nearest_box
+ out += _("Words nearest to %(x_words)s inside %(x_fields)s in any collection are:") % {'x_words': '' + p + '',
+ 'x_fields': '' + f + ''}
+ else:
+ out += _("Words nearest to %(x_words)s in any collection are:") % {'x_words': '' + p + ''}
+ out += ' ' + nearest_box + '
'
return out
def tmpl_nearest_term_box(self, p, ln, f, terminfo, intro):
"""
Displays the *Nearest search terms* box
Parameters:
- 'p' *string* - Current search words
- 'f' *string* - a collection description (if the search has been completed in a collection)
- 'ln' *string* - The language to display
- 'weburl' *string* - The base URL for the site
- 'terminfo': tuple (term, hits, argd) for each near term
- 'intro' *string* - the intro HTML to prefix the box with
"""
out = '''
'''
for term, hits, argd in terminfo:
if hits:
hitsinfo = str(hits)
else:
hitsinfo = '-'
term = cgi.escape(term)
if term == p: # print search word for orientation:
nearesttermsboxbody_class = "nearesttermsboxbodyselected"
if hits > 0:
term = a_href(term, href=self.build_search_url(argd),
_class="nearesttermsselected")
else:
nearesttermsboxbody_class = "nearesttermsboxbody"
term = a_href(term, href=self.build_search_url(argd),
_class="nearestterms")
out += '''\
"
def tmpl_browse_pattern(self, f, ln, browsed_phrases_in_colls, colls):
"""
Displays the *Nearest search terms* box
Parameters:
- 'f' *string* - a field name (i18nized)
- 'ln' *string* - The language to display
- 'weburl' *string* - The base URL for the site
- 'browsed_phrases_in_colls' *array* - the phrases to display
- 'colls' *array* - the list of collection parameters of the search (c's)
"""
# load the right message language
_ = gettext_set_language(ln)
out = """
%(hits)s
%(f)s
""" % {
'hits' : _("Hits"),
'f' : f
}
if len(browsed_phrases_in_colls) == 1:
# one hit only found:
phrase, nbhits = browsed_phrases_in_colls[0][0], browsed_phrases_in_colls[0][1]
query = {'c': colls,
'ln': ln,
'p': '"%s"' % phrase,
'f': f}
out += """
%(nbhits)s
%(link)s
""" % {'nbhits': nbhits,
'link': a_href(phrase, href=self.build_search_url(query))}
elif len(browsed_phrases_in_colls) > 1:
# first display what was found but the last one:
for phrase, nbhits in browsed_phrases_in_colls[:-1]:
query = {'c': colls,
'ln': ln,
'p': '"%s"' % phrase,
'f': f}
out += """
%(nbhits)s
%(link)s
""" % {'nbhits' : nbhits,
'link': a_href(phrase, href=self.build_search_url(query))}
# now display last hit as "next term":
phrase, nbhits = browsed_phrases_in_colls[-1]
query = {'c': colls,
'ln': ln,
'p': phrase,
'f': f}
out += """
"""
return out
def tmpl_search_box(self, ln, as, cc, cc_intl, ot, sp,
action, fieldslist, f1, f2, f3, m1, m2, m3,
p1, p2, p3, op1, op2, rm, p, f, coll_selects,
d1y, d2y, d1m, d2m, d1d, d2d, sort_formats,
sf, so, ranks, sc, rg, formats, of, pl, jrec):
"""
Displays the *Nearest search terms* box
Parameters:
- 'ln' *string* - The language to display
- 'weburl' *string* - The base URL for the site
- 'as' *bool* - Should we display an advanced search box?
- 'cc_intl' *string* - the i18nized current collection name
- 'cc' *string* - the internal current collection name
- 'ot', 'sp' *string* - hidden values
- 'action' *string* - the action demanded by the user
- 'fieldlist' *list* - the list of all fields available in CDSWare, for use in select within boxes in advanced search
- 'p, f, f1, f2, f3, m1, m2, m3, p1, p2, p3, op1, op2, op3, rm' *strings* - the search parameters
- 'coll_selects' *array* - a list of lists, each containing the collections selects to display
- 'd1y, d2y, d1m, d2m, d1d, d2d' *int* - the search between dates
- 'sort_formats' *array* - the select information for the sorting format
- 'sf' *string* - the currently selected sort format
- 'so' *string* - the currently selected sort order ("a" or "d")
- 'ranks' *array* - ranking methods
- 'rm' *string* - selected ranking method
- 'sc' *string* - split by collection or not
- 'rg' *string* - selected results/page
- 'formats' *array* - available output formats
- 'of' *string* - the selected output format
- 'pl' *string* - `limit to' search pattern
"""
# load the right message language
_ = gettext_set_language(ln)
# These are hidden fields the user does not manipulate
# directly
argd = drop_default_urlargd({
'ln': ln, 'as': as,
'cc': cc, 'ot': ot, 'sp': sp,
}, self.search_results_default_urlargd)
out = '''
%(ccname)s
''' % {'ccname' : cc_intl,
'weburl' : weburl}
# Only add non-default hidden values
for field, value in argd.items():
out += self.tmpl_input_hidden(field, value)
leadingtext = _("Search")
if action == 'browse':
leadingtext = _("Browse")
if as == 1:
# print Advanced Search form:
google = ''
if cfg_google_box and (p1 or p2 or p3):
google = ' :: %(search_smwhere)s' % {
'search_smwhere' : _("Try your search on...")
}
# define search box elements:
out += '''
""" % {
'leading' : leadingtext,
'msg_coll' : _("collections"),
'colls' : selects,
}
## thirdly, print search limits, if applicable:
if action != _("Browse") and pl:
out += """
- %(limitto)s:
+ %(limitto)s
""" % {
- 'limitto' : _("Limit to"),
+ 'limitto' : _("Limit to:"),
'sizepattern' : cfg_advancedsearch_pattern_box_width,
'pl' : cgi.escape(pl, 1),
}
## fourthly, print from/until date boxen, if applicable:
if action == _("Browse") or (d1y==0 and d1m==0 and d1d==0 and d2y==0 and d2m==0 and d2d==0):
pass # do not need it
else:
cell_6_a = self.tmpl_inputdate("d1", ln, d1y, d1m, d1d)
cell_6_b = self.tmpl_inputdate("d2", ln, d2y, d2m, d2d)
out += """
%(added)s
%(until)s
%(date1)s
%(date2)s
""" % {
'added' : _("Added since:"),
'until' : _("until:"),
'date1' : self.tmpl_inputdate("d1", ln, d1y, d1m, d1d),
'date2' : self.tmpl_inputdate("d2", ln, d2y, d2m, d2d),
}
## fifthly, print Display results box, including sort/rank, formats, etc:
if action != _("Browse"):
rgs = []
for i in [10, 25, 50, 100, 250, 500]:
rgs.append({ 'value' : i, 'text' : "%d %s" % (i, _("results"))})
# sort by:
out += """
"""
return out
def tmpl_input_hidden(self, name, value):
"Produces the HTML code for a hidden field "
return """""" % {
'name' : cgi.escape(str(name), 1),
'value' : cgi.escape(str(value), 1),
}
def _add_mark_to_field(self, value, fields, ln, chars = 1):
"""Adds the current value as a MARC tag in the fields array
Useful for advanced search"""
# load the right message language
_ = gettext_set_language(ln)
out = fields
if value and str(value[0:chars]).isdigit():
out.append({'value' : value,
'text' : str(value) + " " + _("MARC tag")
})
return out
def tmpl_google_box(self, ln, cc, p, f, prolog_start, prolog_end, column_separator, link_separator, epilog):
"""Creates the box that proposes links to other useful search engines like Google.
Parameters:
- 'ln' *string* - The language to display in
- 'cc' *string* - the internal current collection name
- 'p' *string* - the search query
- 'f' *string* - the current field
- 'prolog_start, prolog_end, column_separator, link_separator, epilog' *strings* - default HTML code for the specified position in the box
"""
# load the right message language
_ = gettext_set_language(ln)
out_links = []
p_quoted = urllib.quote(p)
# Amazon
if cfg_google_box_servers.get('Amazon', 0):
if string.find(cc, "Book") >= 0:
if f == "author":
out_links.append("""%s %s Amazon""" % (p_quoted, p, _('in')))
else:
out_links.append("""%s %s Amazon""" % (p_quoted, p, _('in')))
# CERN Intranet:
if cfg_google_box_servers.get('CERN Intranet', 0):
out_links.append("""%s %s CERN Intranet""" % (urllib.quote(string.replace(p, ' ', ' +')), p, _('in')))
# CERN Agenda:
if cfg_google_box_servers.get('CERN Agenda', 0):
if f == "author":
out_links.append("""%s %s CERN Agenda""" % (p_quoted, p, _('in')))
elif f == "title":
out_links.append("""%s %s CERN Agenda""" % (p_quoted, p, _('in')))
# CERN EDMS:
if cfg_google_box_servers.get('CERN Agenda', 0):
# FIXME: reusing CERN Agenda config variable until we can enter CERN EDMS into config.wml
if f == "author":
out_links.append("""%s %s CERN EDMS""" % (p_quoted, p, _("in")))
elif f == "title" or f == "abstract" or f == "keyword":
out_links.append("""%s %s CERN EDMS""" % (p_quoted, p, _("in")))
elif f == "reportnumber":
out_links.append("""%s %s CERN EDMS""" % (p_quoted, p, _("in")))
else:
out_links.append("""%s %s CERN EDMS""" % (p_quoted, p, _("in")))
# CiteSeer:
if cfg_google_box_servers.get('CiteSeer', 0):
out_links.append("""%s %s CiteSeer""" % (p_quoted, p, _('in')))
# Google Print:
if cfg_google_box_servers.get('Google Scholar', 0):
# FIXME: reusing Google Scholar config variable until we can enter Google Print into config.wml
if string.find(cc, "Book") >= 0:
out_links.append("""%s %s Google Print""" % (p_quoted, p, _("in")))
# Google Scholar:
if cfg_google_box_servers.get('Google Scholar', 0):
if f == "author":
out_links.append("""%s %s Google Scholar""" % (p_quoted, p, _('in')))
else:
out_links.append("""%s %s Google Scholar""" % (p_quoted, p, _('in')))
# Google Web:
if cfg_google_box_servers.get('Google Web', 0):
if f == "author":
p_google = p
if string.find(p, ",") >= 0 and (not p.startswith('"')) and (not p.endswith('"')):
p_lastname, p_firstnames = string.split(p, ",", 1)
p_google = '"%s %s" OR "%s %s"' % (p_lastname, p_firstnames, p_firstnames, p_lastname)
out_links.append("""%s %s Google Web""" % (urllib.quote(p_google), p_google, _('in')))
else:
out_links.append("""%s %s Google Web""" % (p_quoted, p, _('in')))
# IEC
if cfg_google_box_servers.get('IEC', 0):
if string.find(cc, "Standard") >= 0:
out_links.append("""%s %s IEC""" % (p_quoted, p, _('in')))
# IHS
if cfg_google_box_servers.get('IHS', 0):
if string.find(cc, "Standard") >= 0:
out_links.append("""%s %s IHS""" % (p_quoted, p, _('in')))
# INSPEC
if cfg_google_box_servers.get('INSPEC', 0):
if f == "author":
p_inspec = sre.sub(r'(, )| ', '-', p)
p_inspec = sre.sub(r'(-\w)\w+$', '\\1', p_inspec)
out_links.append("""%s %s INSPEC""" % (urllib.quote(p_inspec), p_inspec, _('in')))
elif f == "title":
out_links.append("""%s %s INSPEC""" % (p_quoted, p, _('in')))
elif f == "abstract":
out_links.append("""%s %s INSPEC""" % (p_quoted, p, _('in')))
elif f == "year":
out_links.append("""%s %s INSPEC""" % (p_quoted, p, _('in')))
# ISO
if cfg_google_box_servers.get('ISO', 0):
if string.find(cc, "Standard") >= 0:
out_links.append("""%s %s ISO""" % (p_quoted, p, _('in')))
# KEK
if cfg_google_box_servers.get('KEK', 0):
kek_search_title = "KEK KISS Preprints"
kek_search_baseurl = "http://www-lib.kek.jp/cgi-bin/kiss_prepri?"
if string.find(cc, "Book") >= 0:
kek_search_title = "KEK Library Books"
kek_search_baseurl = "http://www-lib.kek.jp/cgi-bin/kiss_book?DSP=1&"
elif string.find(cc, "Periodical") >= 0:
kek_search_title = "KEK Library Journals"
kek_search_baseurl = "http://www-lib.kek.jp/cgi-bin/kiss_book?DSP=2&"
if f == "author":
out_links.append("""%s %s %s""" % \
(kek_search_baseurl, p_quoted, p, _('in'), kek_search_title))
elif f == "title":
out_links.append("""%s %s %s""" % \
(kek_search_baseurl, p_quoted, p, _('in'), kek_search_title))
elif f == "reportnumber":
out_links.append("""%s %s %s""" % \
(kek_search_baseurl, p_quoted, p, _('in'), kek_search_title))
# NEBIS
if cfg_google_box_servers.get('NEBIS', 0):
if string.find(cc, "Book") >= 0:
if f == "author":
out_links.append("""%s %s NEBIS""" % (p_quoted, p, _('in')))
elif f == "title":
out_links.append("""%s %s NEBIS""" % (p_quoted, p, _('in')))
else:
out_links.append("""%s %s NEBIS""" % (p_quoted, p, _('in')))
# Scirus:
if cfg_google_box_servers.get('Google Scholar', 0):
# FIXME: reusing Google Scholar config variable until we can enter Scirus into config.wml
if f == "author":
out_links.append("""%s %s Scirus""" % (p_quoted, p, _("in")))
elif f == "title":
out_links.append("""%s %s Scirus""" % (p_quoted, p, _("in")))
elif f == "keyword":
out_links.append("""%s %s Scirus""" % (p_quoted, p, _("in")))
else:
out_links.append("""%s %s Scirus""" % (p_quoted, p, _("in")))
# SPIRES
if cfg_google_box_servers.get('SPIRES', 0):
spires_search_title = "SLAC SPIRES HEP"
spires_search_baseurl = "http://www.slac.stanford.edu/spires/find/hep/"
if string.find(cc, "Book") >= 0:
spires_search_title = "SLAC Library Books"
spires_search_baseurl = "http://www.slac.stanford.edu/spires/find/books/"
elif string.find(cc, "Periodical") >= 0:
spires_search_title = "SLAC Library Journals"
spires_search_baseurl = "http://www.slac.stanford.edu/spires/find/tserials/"
if f == "author":
out_links.append("""%s %s %s""" % \
(spires_search_baseurl, p_quoted, p, _('in'), spires_search_title))
elif f == "title":
out_links.append("""%s %s %s""" % \
(spires_search_baseurl, p_quoted, p, _('in'), spires_search_title))
elif f == "reportnumber":
out_links.append("""%s %s %s""" % \
(spires_search_baseurl, p_quoted, p, _('in'), spires_search_title))
elif f == "keyword":
out_links.append("""%s %s %s""" % \
(spires_search_baseurl, p_quoted, p, _('in'), spires_search_title))
else: # invent a poor man's any field search since SPIRES doesn't support one
out_links.append("""%s %s %s""" % \
(spires_search_baseurl, p_quoted, p_quoted, p_quoted, p_quoted, p_quoted, p, _('in'), spires_search_title))
# okay, so print the box now:
out = ""
if out_links:
out += """"""
out += prolog_start + _("Haven't found what you were looking for? Try your search on other servers:") + prolog_end
nb_out_links_in_one_column = len(out_links)/2
out += string.join(out_links[:nb_out_links_in_one_column], link_separator)
out += column_separator
out += string.join(out_links[nb_out_links_in_one_column:], link_separator)
out += epilog
return out
def tmpl_search_pagestart(self, ln) :
"page start for search page. Will display after the page header"
return """
"""
def tmpl_search_pageend(self, ln) :
"page end for search page. Will display just before the page footer"
return """
"""
def tmpl_print_warning(self, msg, type, prologue, epilogue):
"""Prints warning message and flushes output.
Parameters:
- 'msg' *string* - The message string
- 'type' *string* - the warning type
- 'prologue' *string* - HTML code to display before the warning
- 'epilogue' *string* - HTML code to display after the warning
"""
out = '\n%s' % (prologue)
if type:
out += '%s: ' % type
out += '%s%s' % (msg, epilogue)
return out
def tmpl_print_search_info(self, ln, weburl, middle_only,
collection, collection_name, collection_id,
as, sf, so, rm, rg, nb_found, of, ot, p, f, f1,
f2, f3, m1, m2, m3, op1, op2, p1, p2,
p3, d1y, d1m, d1d, d2y, d2m, d2d,
all_fieldcodes, cpu_time, pl_in_url,
jrec, sc, sp):
"""Prints stripe with the information on 'collection' and 'nb_found' results and CPU time.
Also, prints navigation links (beg/next/prev/end) inside the results set.
If middle_only is set to 1, it will only print the middle box information (beg/netx/prev/end/etc) links.
This is suitable for displaying navigation links at the bottom of the search results page.
Parameters:
- 'ln' *string* - The language to display
- 'weburl' *string* - The base URL for the site
- 'middle_only' *bool* - Only display parts of the interface
- 'collection' *string* - the collection name
- 'collection_name' *string* - the i18nized current collection name
- 'as' *bool* - if we display the advanced search interface
- 'sf' *string* - the currently selected sort format
- 'so' *string* - the currently selected sort order ("a" or "d")
- 'rm' *string* - selected ranking method
- 'rg' *int* - selected results/page
- 'nb_found' *int* - number of results found
- 'of' *string* - the selected output format
- 'ot' *string* - hidden values
- 'p' *string* - Current search words
- 'f' *string* - the fields in which the search was done
- 'f1, f2, f3, m1, m2, m3, p1, p2, p3, op1, op2' *strings* - the search parameters
- 'jrec' *int* - number of first record on this page
- 'd1y, d2y, d1m, d2m, d1d, d2d' *int* - the search between dates
- 'all_fieldcodes' *array* - all the available fields
- 'cpu_time' *float* - the time of the query in seconds
"""
# load the right message language
_ = gettext_set_language(ln)
out = ""
# left table cells: print collection name
if not middle_only:
out += '''
%(collection_name)s
""" % { 'weburl' : weburl }
# middle table cell: print beg/next/prev/end arrows:
if not middle_only:
out += """
%(recs_found)s """ % {
'recs_found' : _("%s records found") % ('' + self.tmpl_nice_number(nb_found, ln) + '')
}
else:
out += ""
if nb_found > rg:
out += "" + collection_name + " : " + _("%s records found") % ('' + self.tmpl_nice_number(nb_found, ln) + '') + " "
if nb_found > rg: # navig.arrows are needed, since we have many hits
query = {'p': p, 'f': f,
'cc': collection,
'sf': sf, 'so': so,
'sp': sp, 'rm': rm,
'of': of, 'ot': ot,
'as': as, 'ln': ln,
'p1': p1, 'p2': p2, 'p3': p3,
'f1': f1, 'f2': f2, 'f3': f3,
'm1': m1, 'm2': m2, 'm3': m3,
'op1': op1, 'op2': op2,
'sc': 0,
'd1y': d1y, 'd1m': d1m, 'd1d': d1d,
'd2y': d2y, 'd2m': d2m, 'd2d': d2d,
}
# @todo here
def img(gif, txt):
return '' % {
'txt': txt, 'gif': gif, 'weburl': weburl}
if jrec-rg > 1:
out += a_href(img('sb', _("begin")), _class='img',
href=self.build_search_url(query, jrec=1, rg=rg))
if jrec > 1:
out += a_href(img('sp', _("previous")), _class='img',
href=self.build_search_url(query, jrec=max(jrec-rg, 1), rg=rg))
if jrec+rg-1 < nb_found:
out += "%d - %d" % (jrec, jrec+rg-1)
else:
out += "%d - %d" % (jrec, nb_found)
if nb_found >= jrec+rg:
out += a_href(img('sn', _("next")), _class='img',
href=self.build_search_url(query, jrec=jrec+rg, rg=rg))
if nb_found >= jrec+rg+rg:
out += a_href(img('se', _("end")), _class='img',
href=self.build_search_url(query, jrec=nb_found-rg+1, rg=rg))
# still in the navigation part
cc = collection
sc = 0
for var in ['p', 'cc', 'f', 'sf', 'so', 'of', 'rg', 'as', 'ln', 'p1', 'p2', 'p3', 'f1', 'f2', 'f3', 'm1', 'm2', 'm3', 'op1', 'op2', 'sc', 'd1y', 'd1m', 'd1d', 'd2y', 'd2m', 'd2d']:
out += self.tmpl_input_hidden(name = var, value = vars()[var])
for var in ['ot', 'sp', 'rm']:
if vars()[var]:
out += self.tmpl_input_hidden(name = var, value = vars()[var])
if pl_in_url:
fieldargs = cgi.parse_qs(pl_in_url)
for fieldcode in all_fieldcodes:
# get_fieldcodes():
if fieldargs.has_key(fieldcode):
for val in fieldargs[fieldcode]:
out += self.tmpl_input_hidden(name = fieldcode, value = val)
out += """ %(jump)s """ % {
'jump' : _("jump to record:"),
'jrec' : jrec,
}
if not middle_only:
out += "
"
else:
out += ""
# right table cell: cpu time info
if not middle_only:
if cpu_time > -1:
out += """
%(time)s
""" % {
'time' : _("Search took %s seconds.") % ('%.2f' % cpu_time),
}
out += "
"
else:
out += ""
out += "
"
return out
def tmpl_nice_number(self, number, ln=cdslang):
"Returns nicely printed number NUM in language LN using the locale."
if number is None:
return None
# Temporarily switch the numeric locale to the requeted one, and format the number
# In case the system has no locale definition, use the vanilla form
ol = locale.getlocale(locale.LC_NUMERIC)
try:
locale.setlocale(locale.LC_NUMERIC, self.tmpl_localemap.get(ln, self.tmpl_default_locale))
except locale.Error:
return str(number)
number = locale.format('%d', number, True)
locale.setlocale(locale.LC_NUMERIC, ol)
return number
def tmpl_records_format_htmlbrief(self, ln, weburl, rows, relevances_prologue, relevances_epilogue):
"""Returns the htmlbrief format of the records
Parameters:
- 'ln' *string* - The language to display
- 'weburl' *string* - The base URL for the site
- 'rows' *array* - Parts of the interface to display, in the format:
- 'rows[number]' *int* - The order number
- 'rows[recid]' *int* - The recID
- 'rows[relevance]' *string* - The relevance of the record
- 'rows[record]' *string* - The formatted record
- 'relevances_prologue' *string* - HTML code to prepend the relevance indicator
- 'relevances_epilogue' *string* - HTML code to append to the relevance indicator (used mostly for formatting)
"""
# load the right message language
_ = gettext_set_language(ln)
out = """
""" % {
'weburl' : weburl,
}
for row in rows:
out += """
%(number)s.
""" % row
if row['relevance']:
out += """
""" % {
'basket' : _("ADD TO BASKET")
}
return out
def tmpl_records_format_other(self, ln, weburl, rows, format, url_argd):
"""Returns other formats of the records
Parameters:
- 'ln' *string* - The language to display
- 'weburl' *string* - The base URL for the site
- 'rows' *array* - Parts of the interface to display, in the format:
- 'rows[record]' *string* - The formatted record
- 'rows[number]' *int* - The order number
- 'rows[recid]' *int* - The recID
- 'rows[relevance]' *string* - The relevance of the record
- 'format' *string* - The current format
- 'url_argd' *string* - Parameters of the search query
"""
# load the right message language
_ = gettext_set_language(ln)
- out = """
%(format)s """ % {
+ 'format' : _("Format:")
}
result = []
for abbrev, name in (('hd', 'HTML'),
('hx', 'BibTeX'),
('xd', 'DC'),
('hm', 'MARC'),
('xm', 'MARCXML')):
if format == abbrev:
result.append(name)
else:
result.append(a_href(name, href=self.build_search_url(url_argd, of=abbrev)))
out += " | ".join(result)
out += "
"
for row in rows:
out += row ['record']
if format.startswith("hd"):
# do not print further information but for HTML detailed formats
if row ['creationdate']:
out += '''
%(dates)s
%(similar)s
''' % {
- 'dates': _("Record created %s, last modified %s") % (row['creationdate'],
- row['modifydate']),
+ 'dates': _("Record created %(x_date_creation)s, last modified %(x_date_modification)s") % {'x_date_creation': row['creationdate'],
+ 'x_date_modification': row['modifydate']},
'weburl': weburl,
'recid': row['recid'],
'ln': ln,
'similar': a_href(_("Similar records"), _class="moreinfo",
href=self.build_search_url(p='recid:%d' % row['recid'], rm='wrd', ln=ln)),
'basket' : _("ADD TO BASKET")
}
out += '
'
if row.has_key ('citinglist'):
cs = row ['citinglist']
similar = self.tmpl_print_record_list_for_similarity_boxen(
_("Cited by: %s records") % len (cs), cs, ln)
out += '''
%(similar)s %(more)s
''' % {
'more': a_href(_("more"),
href=self.build_search_url(p='recid:%d' % row['recid'], rm='cit', ln=ln)),
'similar': similar}
if row.has_key ('cociting'):
cs = row ['cociting']
similar = self.tmpl_print_record_list_for_similarity_boxen (
_("Co-cited with: %s records") % len (cs), cs, ln)
out += '''
%(similar)s %(more)s
''' % { 'more': a_href(_("more"),
href=self.build_search_url(p='cocitedwith:%d' % row['recid'], ln=ln)),
'similar': similar}
if row.has_key ('citationhistory'):
out += '
%s
' % row ['citationhistory']
if row.has_key ('downloadsimilarity'):
cs = row ['downloadsimilarity']
similar = self.tmpl_print_record_list_for_similarity_boxen (
_("People who downloaded this document also downloaded:"), cs, ln)
out += '''
 '
out += self.tmpl_print_record_list_for_similarity_boxen (
_("People who viewed this page also viewed:"), row ['viewsimilarity'], ln)
if row.has_key ('reviews'):
out += '
 '
out += row['reviews']
if row.has_key ('comments'):
out += row['comments']
out += "
"
return out
def tmpl_print_results_overview(self, ln, weburl, results_final_nb_total, cpu_time, results_final_nb, colls):
"""Prints results overview box with links to particular collections below.
Parameters:
- 'ln' *string* - The language to display
- 'weburl' *string* - The base URL for the site
- 'results_final_nb_total' *int* - The total number of hits for the query
- 'colls' *array* - The collections with hits, in the format:
- 'coll[code]' *string* - The code of the collection (canonical name)
- 'coll[name]' *string* - The display name of the collection
- 'results_final_nb' *array* - The number of hits, indexed by the collection codes:
- 'cpu_time' *string* - The time the query took
- 'url_args' *string* - The rest of the search query
"""
if len(colls) == 1:
# if one collection only, print nothing:
return ""
# load the right message language
_ = gettext_set_language(ln)
# first find total number of hits:
out = """
%(founds)s
""" % {
- 'founds' : _("%sResults overview:%s Found %s records in %s seconds.") % ('',
- '',
- '' + self.tmpl_nice_number(results_final_nb_total, ln) + '',
- '%.2f' % cpu_time)
+ 'founds' : _("%(x_fmt_open)sResults overview:%(x_fmt_close)s Found %(x_nb_records)s records in %(x_nb_seconds)s seconds.") %\
+ {'x_fmt_open': '',
+ 'x_fmt_close': '',
+ 'x_nb_records': '' + self.tmpl_nice_number(results_final_nb_total, ln) + '',
+ 'x_nb_seconds': '%.2f' % cpu_time}
}
# then print hits per collection:
for coll in colls:
if results_final_nb.has_key(coll['code']) and results_final_nb[coll['code']] > 0:
out += '''%(coll_name)s,
%(number)s ''' % {
'coll' : urllib.quote(coll['code']),
'coll_name' : coll['name'],
'number' : _("%s records found") % ('' + self.tmpl_nice_number(results_final_nb[coll['code']], ln) + '')
}
out += "
"
return out
def tmpl_search_no_boolean_hits(self, ln, nearestterms):
"""No hits found, proposes alternative boolean queries
Parameters:
- 'ln' *string* - The language to display
- 'weburl' *string* - The base URL for the site
- 'nearestterms' *array* - Parts of the interface to display, in the format:
- 'nearestterms[nbhits]' *int* - The resulting number of hits
- 'nearestterms[url_args]' *string* - The search parameters
- 'nearestterms[p]' *string* - The search terms
"""
# load the right message language
_ = gettext_set_language(ln)
out = _("Boolean query returned no hits. Please combine your search terms differently.")
out += '''
'''
for term, hits, argd in nearestterms:
out += '''\
"""
return out
def tmpl_similar_author_names(self, authors, ln):
"""No hits found, proposes alternative boolean queries
Parameters:
- 'authors': a list of (name, hits) tuples
- 'ln' *string* - The language to display
"""
# load the right message language
_ = gettext_set_language(ln)
out = '''
%(similar)s
''' % {
'similar' : _("See also: similar author names")
}
for author, hits in authors:
out += '''\
"""
return out
def tmpl_print_record_detailed(self, recID, ln, weburl):
"""Displays a detailed on-the-fly record
Parameters:
- 'ln' *string* - The language to display
- 'weburl' *string* - The base URL for the site
- 'recID' *int* - The record id
"""
# okay, need to construct a simple "Detailed record" format of our own:
out = "
"
# secondly, title:
titles = get_fieldvalues(recID, "245__a")
for title in titles:
out += "
%s
" % title
# thirdly, authors:
authors = get_fieldvalues(recID, "100__a") + get_fieldvalues(recID, "700__a")
if authors:
out += "
"
for author in authors:
out += '%s; ' % a_href(cgi.escape(author),
href=self.build_search_url(ln=ln, p=author, f='author'))
out += "
"
# fourthly, date of creation:
dates = get_fieldvalues(recID, "260__c")
for date in dates:
out += "
%s
" % date
# fifthly, abstract:
abstracts = get_fieldvalues(recID, "520__a")
for abstract in abstracts:
out += """
Abstract: %s
""" % abstract
# fifthly bis, keywords:
keywords = get_fieldvalues(recID, "6531_a")
if len(keywords):
out += """
Keyword(s):"""
for keyword in keywords:
out += '%s; ' % a_href(cgi.escape(keyword),
href=self.build_search_url(ln=ln, p=keyword, f='keyword'))
out += ''
# fifthly bis bis, published in:
prs_p = get_fieldvalues(recID, "909C4p")
prs_v = get_fieldvalues(recID, "909C4v")
prs_y = get_fieldvalues(recID, "909C4y")
prs_n = get_fieldvalues(recID, "909C4n")
prs_c = get_fieldvalues(recID, "909C4c")
for idx in range(0,len(prs_p)):
out += """
Publ. in: %s""" % prs_p[idx]
if prs_v and prs_v[idx]:
out += """%s""" % prs_v[idx]
if prs_y and prs_y[idx]:
out += """(%s)""" % prs_y[idx]
if prs_n and prs_n[idx]:
out += """, no.%s""" % prs_n[idx]
if prs_c and prs_c[idx]:
out += """, p.%s""" % prs_c[idx]
out += """."""
# sixthly, fulltext link:
urls_z = get_fieldvalues(recID, "8564_z")
urls_u = get_fieldvalues(recID, "8564_u")
for idx in range(0,len(urls_u)):
link_text = "URL"
try:
if urls_z[idx]:
link_text = urls_z[idx]
except IndexError:
pass
out += """
%s:%s""" % (link_text, urls_u[idx], urls_u[idx])
# print some white space at the end:
out += "
"
return out
def tmpl_print_record_list_for_similarity_boxen(self, title, score_list, ln=cdslang):
"""Print list of records in the "hs" (HTML Similarity) format for similarity boxes.
FIXME: bad symbol names again, e.g. SCORE_LIST is *not* a list of scores. Humph.
"""
from invenio.search_engine import print_record
out = '''
%(title)s
''' % { 'title': title }
for recid, score in score_list [:5]:
out += '''
"""
return out
def tmpl_print_record_brief(self, ln, recID, weburl):
"""Displays a brief record on-the-fly
Parameters:
- 'ln' *string* - The language to display
- 'weburl' *string* - The base URL for the site
- 'recID' *int* - The record id
"""
out = ""
# record 'recID' does not exist in format 'format', so print some default format:
# firstly, title:
titles = get_fieldvalues(recID, "245__a")
# secondly, authors:
authors = get_fieldvalues(recID, "100__a") + get_fieldvalues(recID, "700__a")
# thirdly, date of creation:
dates = get_fieldvalues(recID, "260__c")
# thirdly bis, report numbers:
rns = get_fieldvalues(recID, "037__a")
rns = get_fieldvalues(recID, "088__a")
# fourthly, beginning of abstract:
abstracts = get_fieldvalues(recID, "520__a")
# fifthly, fulltext link:
urls_z = get_fieldvalues(recID, "8564_z")
urls_u = get_fieldvalues(recID, "8564_u")
return self.tmpl_record_body(
weburl = weburl,
titles = titles,
authors = authors,
dates = dates,
rns = rns,
abstracts = abstracts,
urls_u = urls_u,
urls_z = urls_z,
ln=ln)
def tmpl_print_record_brief_links(self, ln, recID, weburl):
"""Displays links for brief record on-the-fly
Parameters:
- 'ln' *string* - The language to display
- 'weburl' *string* - The base URL for the site
- 'recID' *int* - The record id
"""
# load the right message language
_ = gettext_set_language(ln)
out = ""
if cfg_use_aleph_sysnos:
alephsysnos = get_fieldvalues(recID, "970__a")
if len(alephsysnos)>0:
alephsysno = alephsysnos[0]
out += ' %s' % \
a_href(_("Detailed record"), _class="moreinfo",
href=self.build_search_url(sysno=alephsysno, ln=ln))
else:
out += ' %s' % \
a_href(_("Detailed record"), _class="moreinfo",
href=self.build_search_url(recid=recID, ln=ln))
else:
out += ' %s' % \
a_href(_("Detailed record"), _class="moreinfo",
href=self.build_search_url(recid=recID, ln=ln))
out += ' - %s' % \
a_href(_("Similar records"), _class="moreinfo",
href=self.build_search_url(p="recid:%d" % recID, rm="wrd", ln=ln))
if cfg_experimental_features:
out += ' - %s' % \
a_href(_("Cited by"), _class="moreinfo",
href=self.build_search_url(p="recid:%d" % recID, rm="cit", ln=ln))
return out
diff --git a/modules/websession/lib/webaccount.py b/modules/websession/lib/webaccount.py
index ad26b1738..8fb90fa8f 100644
--- a/modules/websession/lib/webaccount.py
+++ b/modules/websession/lib/webaccount.py
@@ -1,252 +1,255 @@
## $Id$
## This file is part of CDS Invenio.
## Copyright (C) 2002, 2003, 2004, 2005, 2006 CERN.
##
## CDS Invenio is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License as
## published by the Free Software Foundation; either version 2 of the
## License, or (at your option) any later version.
##
## CDS Invenio is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
import sys
import string
import cgi
from invenio.config import *
from invenio.webpage import page
from invenio.dbquery import run_sql
from invenio.webuser import getUid,isGuestUser, get_user_preferences, set_user_preferences
from invenio.access_control_admin import acc_findUserRoleActions
from invenio.access_control_config import CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS, CFG_EXTERNAL_AUTHENTICATION
from invenio.messages import gettext_set_language
import invenio.template
websession_templates = invenio.template.load('websession')
# perform_info(): display the main features of CDS personalize
def perform_info(req, ln):
out = ""
uid = getUid(req)
return websession_templates.tmpl_account_info(
ln = ln,
uid = uid,
guest = isGuestUser(uid),
cfg_cern_site = cfg_cern_site,
);
def perform_youradminactivities(uid, ln):
"""Return text for the `Your Admin Activities' box. Analyze
whether user UID has some admin roles, and if yes, then print
suitable links for the actions he can do. If he's not admin,
print a simple non-authorized message."""
your_role_actions = acc_findUserRoleActions(uid)
your_roles = []
your_admin_activities = []
guest = isGuestUser(uid)
for (role, action) in your_role_actions:
if role not in your_roles:
your_roles.append(role)
if action not in your_admin_activities:
your_admin_activities.append(action)
if "superadmin" in your_roles:
for action in ["runbibedit", "cfgbibformat", "cfgbibharvest", "cfgbibrank", "cfgbibindex", "cfgwebaccess", "cfgwebcomment", "cfgwebsearch", "cfgwebsubmit"]:
if action not in your_admin_activities:
your_admin_activities.append(action)
return websession_templates.tmpl_account_adminactivities(
ln = ln,
uid = uid,
guest = guest,
roles = your_roles,
activities = your_admin_activities,
weburl = weburl,
)
# perform_display_account(): display a dynamic page that shows the user's account
def perform_display_account(req,username,bask,aler,sear,msgs,grps,ln):
# load the right message language
_ = gettext_set_language(ln)
uid = getUid(req)
#your account
if isGuestUser(uid):
user = "guest"
login = "%s/youraccount/login?ln=%s" % (sweburl, ln)
- accBody = _("You are logged in as guest. You may want to %slogin%s as a regular user.") % ('', '')
+ accBody = _("You are logged in as guest. You may want to %(x_url_open)slogin%(x_url_close)s as a regular user.") %\
+ {'x_url_open': '',
+ 'x_url_close': ''}
accBody += "
"
- bask=aler=msgs= _("The %sguest%s users need to %sregister%s first") % ('',
- '',
- '',
- '')
+ bask=aler=msgs= _("The %(x_fmt_open)sguest%(x_fmt_close)s users need to %(x_url_open)sregister%(x_url_close)s first") %\
+ {'x_fmt_open': '',
+ 'x_fmt_close': '',
+ 'x_url_open': '',
+ 'x_url_close': ''}
sear= _("No queries found")
else:
user = username
accBody = websession_templates.tmpl_account_body(
ln = ln,
user = user,
)
return websession_templates.tmpl_account_page(
ln = ln,
weburl = weburl,
accBody = accBody,
baskets = bask,
alerts = aler,
searches = sear,
messages = msgs,
groups = grps,
administrative = perform_youradminactivities(uid, ln)
)
# template_account() : it is a template for print each of the options from the user's account
def template_account(title, body, ln):
return websession_templates.tmpl_account_template(
ln = ln,
title = title,
body = body
)
# warning_guest_user(): It returns an alert message,showing that the user is a guest user and should log into the system
def warning_guest_user(type, ln=cdslang):
# load the right message language
_ = gettext_set_language(ln)
return websession_templates.tmpl_warning_guest_user(
ln = ln,
type = type,
)
## perform_delete():delete the account of the user, not implement yet
def perform_delete(ln):
return websession_templates.tmpl_account_delete(ln = ln)
## perform_set(email,password): edit your account parameters, email and password.
def perform_set(email,password, ln):
try:
res = run_sql("SELECT id, nickname FROM user WHERE email=%s", (email,))
uid = res[0][0]
nickname = res[0][1]
except:
uid = 0
nickname = ""
CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS_LOCAL = CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS
prefs = get_user_preferences(uid)
if CFG_EXTERNAL_AUTHENTICATION.has_key(prefs['login_method']) and CFG_EXTERNAL_AUTHENTICATION[prefs['login_method']][1] != True:
CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS_LOCAL = 3
out = websession_templates.tmpl_user_preferences(
ln = ln,
email = email,
email_disabled = (CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS_LOCAL >= 2),
password = password,
password_disabled = (CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS_LOCAL >= 3),
nickname = nickname,
)
if len(CFG_EXTERNAL_AUTHENTICATION) >= 1:
try:
uid = run_sql("SELECT id FROM user where email=%s", (email,))
uid = uid[0][0]
except:
uid = 0
prefs = get_user_preferences(uid)
current_login_method = prefs['login_method']
methods = CFG_EXTERNAL_AUTHENTICATION.keys()
methods.sort()
out += websession_templates.tmpl_user_external_auth(
ln = ln,
methods = methods,
current = current_login_method,
method_disabled = (CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS >= 4)
)
return out
## create_register_page_box(): register a new account
def create_register_page_box(referer='', ln=cdslang):
return websession_templates.tmpl_register_page(
referer = referer,
ln = ln,
level = CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS,
supportemail = supportemail,
cdsname = cdsname
)
## create_login_page_box(): ask for the user's email and password, for login into the system
def create_login_page_box(referer='', ln=cdslang):
internal = None
for system in CFG_EXTERNAL_AUTHENTICATION.keys():
if not CFG_EXTERNAL_AUTHENTICATION[system][0]:
internal = system
break
register_available = CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS <= 1 and internal
methods = CFG_EXTERNAL_AUTHENTICATION.keys()
methods.sort()
selected = ''
for method in methods:
if CFG_EXTERNAL_AUTHENTICATION[method][1] == True:
selected = method
break
return websession_templates.tmpl_login_form(
ln = ln,
referer = referer,
internal = internal,
register_available = register_available,
methods = methods,
selected_method = selected,
supportemail = supportemail,
)
# perform_logout: display the message of not longer authorized,
def perform_logout(req, ln):
return websession_templates.tmpl_account_logout(ln = ln)
#def perform_lost: ask the user for his email, in order to send him the lost password
def perform_lost(ln):
return websession_templates.tmpl_lost_password_form(
ln = ln,
msg = websession_templates.tmpl_lost_password_message(ln = ln, supportemail = supportemail),
)
# perform_emailSent(email): confirm that the password has been emailed to 'email' address
def perform_emailSent(email, ln):
return websession_templates.tmpl_account_emailSent(ln = ln, email = email)
# peform_emailMessage : display a error message when the email introduced is not correct, and sugest to try again
def perform_emailMessage(eMsg, ln):
return websession_templates.tmpl_account_emailMessage( ln = ln,
msg = eMsg
)
# perform_back(): template for return to a previous page, used for login,register and setting
def perform_back(mess,act,linkname='', ln='en'):
if not linkname:
linkname = act
return websession_templates.tmpl_back_form(
ln = ln,
message = mess,
act = act,
link = linkname,
)
diff --git a/modules/websession/lib/webgroup.py b/modules/websession/lib/webgroup.py
index cf615400b..e4cb5a89b 100644
--- a/modules/websession/lib/webgroup.py
+++ b/modules/websession/lib/webgroup.py
@@ -1,718 +1,718 @@
## $Id$
## This file is part of CDS Invenio.
## Copyright (C) 2002, 2003, 2004, 2005, 2006 CERN.
##
## CDS Invenio is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License as
## published by the Free Software Foundation; either version 2 of the
## License, or (at your option) any later version.
##
## CDS Invenio is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
"""Group features."""
from invenio.config import cdslang
from invenio.messages import gettext_set_language
from invenio.websession_config import cfg_websession_info_messages, cfg_websession_usergroup_status, cfg_websession_group_join_policy, cfg_websession_warning_messages
from invenio.webuser import nickname_valid_p, get_user_info
from invenio.webmessage import perform_request_send
import invenio.webgroup_dblayer as db
try:
import invenio.template
websession_templates = invenio.template.load('websession')
except ImportError:
pass
def perform_request_group_display(uid, infos=[], errors = [], warnings = [], ln=cdslang):
"""Display all the groups the user belong to
@param uid: user id
@param info: info about last user action
@param ln: language
@return a (body, errors[], warnings[]) formed tuple
"""
_ = gettext_set_language(ln)
body = ""
(body_admin, errors_admin) = display_admin_group(uid)
(body_member, errors_member) = display_member_group(uid)
if errors_admin:
errors.extend(errors_admin)
if errors_member:
errors.extend(errors_member)
body = websession_templates.tmpl_display_all_groups(infos=infos,
admin_group_html=body_admin,
member_group_html=body_member,
warnings=warnings,
ln=ln)
return (body, errors, warnings)
def display_admin_group(uid, ln=cdslang):
"""Display groups the user is admin of
@param uid: user id
@param ln: language
@return a (body, errors[]) formed tuple
return html groups representation the user is admin of"""
body = ""
errors = []
record = db.get_groups_by_user_status(uid=uid,
user_status=cfg_websession_usergroup_status["ADMIN"])
body = websession_templates.tmpl_display_admin_group(groups=record,
ln=ln)
return (body, errors)
def display_member_group(uid, ln=cdslang):
"""Display groups the user is member of
@param uid: user id
@param ln: language
@return a (body, errors[]) formed tuple
body : html groups representation the user is member of"""
body = ""
errors = []
records = db.get_groups_by_user_status(uid,
user_status=cfg_websession_usergroup_status["MEMBER"] )
body = websession_templates.tmpl_display_member_group(groups=records,
ln=ln)
return (body, errors)
def perform_request_input_create_group(group_name,
group_description,
join_policy,
warnings=[],
ln=cdslang):
"""Display form for creating new group.
@param group_name: name of the group entered if the page has been reloaded
@param group_description: description entered if the page has been reloaded
@param join_policy: join policy chosen if the page has been reloaded
@param warnings: warnings
@param ln: language
@return a (body, errors[], warnings[]) formed tuple
body: html for group creation page"""
body = ""
errors = []
body = websession_templates.tmpl_display_input_group_info(group_name,
group_description,
join_policy,
act_type="create",
warnings=warnings,
ln=ln)
return (body, errors, warnings)
def perform_request_create_group(uid,
group_name,
group_description,
join_policy,
ln=cdslang):
"""Create new group
@param group_name: name of the group entered
@param group_description: description of the group entered
@param join_policy: join policy of the group entered
@param ln: language
@return a (body, errors, warnings) formed tuple
warning != [] if group_name or join_policy are not valid
or if the name already exists in the database
body="1" if succeed in order to display info on the main page
"""
_ = gettext_set_language(ln)
body = ""
warnings = []
errors = []
infos = []
if group_name == "":
warnings.append(('WRN_WEBSESSION_NO_GROUP_NAME',))
(body, errors, warnings) = perform_request_input_create_group(group_name,
group_description,
join_policy,
warnings=warnings)
elif not group_name_valid_p(group_name):
warnings.append('WRN_WEBSESSION_NOT_VALID_GROUP_NAME')
(body, errors, warnings) = perform_request_input_create_group(group_name,
group_description,
join_policy,
warnings=warnings)
elif join_policy=="-1":
warnings.append('WRN_WEBSESSION_NO_JOIN_POLICY')
(body, errors, warnings) = perform_request_input_create_group(group_name,
group_description,
join_policy,
warnings=warnings)
elif db.group_name_exist(group_name):
warnings.append('WRN_WEBSESSION_GROUP_NAME_EXISTS')
(body, errors, warnings) = perform_request_input_create_group(group_name,
group_description,
join_policy,
warnings=warnings)
else:
db.insert_new_group(uid,
group_name,
group_description,
join_policy)
infos.append(_(cfg_websession_info_messages["GROUP_CREATED"]))
(body, errors, warnings) = perform_request_group_display(uid,
infos=infos,
errors=errors,
warnings=warnings,
ln=cdslang)
return (body, errors, warnings)
def perform_request_input_join_group(uid,
group_name,
search,
warnings=[],
ln=cdslang):
"""Return html for joining new group
@param group_name: name of the group entered if user is looking for a group
@param search=1 if search performed else 0
@param warnings: warnings coming from perform_request_join_group
@param ln: language
@return a (body, errors[], warnings[]) formed tuple
"""
errors = []
group_from_search = {}
records = db.get_visible_group_list(uid=uid)
if search:
group_from_search = db.get_visible_group_list(uid, group_name)
body = websession_templates.tmpl_display_input_join_group(records.items(),
group_name,
group_from_search.items(),
search,
warnings=warnings,
ln=ln)
return (body, errors, warnings)
def perform_request_join_group(uid,
grpID,
group_name,
search,
ln=cdslang):
"""Join group
@param grpID: list of the groups the user wants to join,
only one value must be selected among the two group lists
(default group list, group list resulting from the search)
@param group_name: name of the group entered if search on name performed
@param search=1 if search performed else 0
@param ln: language
@return a (body, errors[], warnings[]) formed tuple
warnings != [] if 0 or more than one group is selected
"""
_ = gettext_set_language(ln)
body = ""
warnings = []
errors = []
infos = []
if "-1" in grpID:
grpID.remove("-1")
if len(grpID)==1 :
grpID = grpID[0]
"""test if user is already member or pending"""
status = db.get_user_status(uid, grpID)
if status:
warnings.append('WRN_WEBSESSION_ALREADY_MEMBER')
(body, errors, warnings) = perform_request_group_display(uid,
infos=infos,
errors=errors,
warnings=warnings,
ln=cdslang)
"""insert new user of group"""
else:
group_infos = db.get_group_infos(grpID)
group_type = group_infos[0][3]
if group_type == cfg_websession_group_join_policy["VISIBLEMAIL"]:
db.insert_new_member(uid,
grpID,
cfg_websession_usergroup_status["PENDING"])
admin = db.get_users_by_status(grpID,
cfg_websession_usergroup_status["ADMIN"])[0][1]
group_name = group_infos[0][1]
msg_subjet, msg_body = websession_templates.tmpl_admin_msg(group_name=group_name,
grpID=grpID,
ln=ln)
(body, errors, warnings, title, navtrail) = perform_request_send(uid,
msg_to_user=admin,
msg_to_group="",
msg_subject=msg_subjet,
msg_body=msg_body,
ln=ln)
infos.append(_(cfg_websession_info_messages["JOIN_REQUEST"]))
elif group_type == cfg_websession_group_join_policy["VISIBLEOPEN"]:
db.insert_new_member(uid,
grpID,
cfg_websession_usergroup_status["MEMBER"])
infos.append(_(cfg_websession_info_messages["JOIN_GROUP"]))
(body, errors, warnings) = perform_request_group_display(uid,
infos=infos,
errors=errors,
warnings=warnings,
ln=cdslang)
else:
warnings.append('WRN_WEBSESSION_MULTIPLE_GROUPS')
(body, errors, warnings) = perform_request_input_join_group(uid,
group_name,
search,
warnings,
ln)
return (body, errors, warnings)
def perform_request_input_leave_group(uid,
warnings=[],
ln=cdslang):
"""Return html for leaving group
@param uid: user ID
@param warnings: warnings != [] if 0 group is selected or if not admin of the
@param ln: language
@return a (body, errors[], warnings[]) formed tuple
"""
body = ""
errors = []
groups = []
records = db.get_groups_by_user_status(uid=uid,
user_status=cfg_websession_usergroup_status["MEMBER"])
map(lambda x: groups.append((x[0], x[1])), records)
body = websession_templates.tmpl_display_input_leave_group(groups,
warnings=warnings,
ln=ln)
return (body, errors, warnings)
def perform_request_leave_group(uid,
grpID,
confirmed=0,
ln=cdslang):
"""Leave group
@param uid: user ID
@param grpID: ID of the group the user wants to leave
@param warnings: warnings != [] if 0 group is selected
@param confirmed: a confirmed page is first displayed
@param ln: language
@return a (body, errors[], warnings[]) formed tuple
"""
_ = gettext_set_language(ln)
body = ""
warnings = []
errors = []
infos = []
if not grpID == "-1":
if confirmed:
db.leave_group(grpID, uid)
infos.append(_(cfg_websession_info_messages["LEAVE_GROUP"]))
(body, errors, warnings) = perform_request_group_display(uid,
infos=infos,
errors=errors,
warnings=warnings,
ln=cdslang)
else:
body = websession_templates.tmpl_confirm_leave(uid, grpID, ln)
else:
warnings.append('WRN_WEBSESSION_NO_GROUP_SELECTED')
(body, errors, warnings) = perform_request_input_leave_group(uid,
warnings= warnings,
ln=ln)
return (body, errors, warnings)
def perform_request_edit_group(uid,
grpID,
warnings=[],
ln=cdslang):
"""Return html for group editing
@param uid: user ID
@param grpID: ID of the group
@param warnings: warnings
@param ln: language
@return a (body, errors[], warnings[]) formed tuple
"""
body = ''
errors = []
user_status = db.get_user_status(uid, grpID)
if not len(user_status):
errors.append('ERR_WEBSESSION_DB_ERROR')
return (body, errors, warnings)
elif user_status[0][0] != cfg_websession_usergroup_status['ADMIN']:
errors.append(('ERR_WEBSESSION_GROUP_NO_RIGHTS',))
return (body, errors, warnings)
group_infos = db.get_group_infos(grpID)[0]
if not len(group_infos):
errors.append('ERR_WEBSESSION_DB_ERROR')
return (body, errors, warnings)
body = websession_templates.tmpl_display_input_group_info(group_name=group_infos[1],
group_description=group_infos[2],
join_policy=group_infos[3],
act_type="update",
grpID=grpID,
warnings=warnings,
ln=ln)
return (body, errors, warnings)
def perform_request_update_group(uid,
grpID,
group_name,
group_description,
join_policy,
ln=cdslang):
"""Update group datas in database
@param uid: user ID
@param grpID: ID of the group
@param group_name: name of the group
@param group_description: description of the group
@param join_policy: join policy of the group
@param ln: language
@return a (body, errors[], warnings[]) formed tuple
"""
body = ''
errors = []
warnings = []
infos = []
_ = gettext_set_language(ln)
group_name_available = db.group_name_exist(group_name)
if group_name == "":
warnings.append('WRN_WEBSESSION_NO_GROUP_NAME')
(body, errors, warnings) = perform_request_edit_group(uid,
grpID,
warnings=warnings,
ln=ln)
elif not group_name_valid_p(group_name):
warnings.append('WRN_WEBSESSION_NOT_VALID_GROUP_NAME')
(body, errors, warnings) = perform_request_edit_group(uid,
grpID,
warnings=warnings,
ln=ln)
elif join_policy == "-1":
warnings.append('WRN_WEBSESSION_NO_JOIN_POLICY')
(body, errors, warnings) = perform_request_edit_group(uid,
grpID,
warnings=warnings,
ln=ln)
elif (group_name_available and group_name_available[0][0]!= int(grpID)):
warnings.append('WRN_WEBSESSION_GROUP_NAME_EXISTS')
(body, errors, warnings) = perform_request_edit_group(uid,
grpID,
warnings=warnings,
ln=ln)
else:
grpID = db.update_group_infos(grpID,
group_name,
group_description,
join_policy)
infos.append(_(cfg_websession_info_messages["GROUP_UPDATED"]))
(body, errors, warnings) = perform_request_group_display(uid,
infos=infos,
errors=errors,
warnings=warnings,
ln=cdslang)
return (body, errors, warnings)
def perform_request_delete_group(uid,
grpID,
confirmed=0,
ln=cdslang):
"""First display confirm message(confirmed=0)
then(confirmed=1) delete group and all its members
@param uid: user ID
@param grpID: ID of the group
@param confirmed =1 if confirmed message has been previously displayed
@param ln: language
@return a (body, errors[], warnings[]) formed tuple
"""
body = ""
warnings = []
errors = []
infos = []
_ = gettext_set_language(ln)
group_infos = db.get_group_infos(grpID)
user_status = db.get_user_status(uid, grpID)
if not group_infos:
warnings.append('WRN_WEBSESSION_GROUP_ALREADY_DELETED')
(body, errors, warnings) = perform_request_group_display(uid,
infos=infos,
errors=errors,
warnings=warnings,
ln=cdslang)
else:
if not len(user_status):
errors.append('ERR_WEBSESSION_DB_ERROR')
elif confirmed:
group_infos = db.get_group_infos(grpID)
group_name = group_infos[0][1]
msg_subjet, msg_body = websession_templates.tmpl_delete_msg(group_name=group_name,
ln=ln)
(body, errors, warnings, title, navtrail) = perform_request_send(uid,
msg_to_user="",
msg_to_group=group_name,
msg_subject=msg_subjet,
msg_body=msg_body,
ln=ln)
db.delete_group_and_members(grpID)
infos.append(_(cfg_websession_info_messages["GROUP_DELETED"]))
(body, errors, warnings) = perform_request_group_display(uid,
infos=infos,
errors=errors,
warnings=warnings,
ln=cdslang)
else:
body = websession_templates.tmpl_confirm_delete(grpID, ln)
return (body, errors, warnings)
def perform_request_manage_member(uid,
grpID,
infos=[],
warnings=[],
ln=cdslang):
"""Return html for managing group's members
@param uid: user ID
@param grpID: ID of the group
@param info: info about last user action
@param warnings: warnings
@param ln: language
@return a (body, errors[], warnings[]) formed tuple
"""
body = ''
errors = []
_ = gettext_set_language(ln)
user_status = db.get_user_status(uid, grpID)
if not len(user_status):
errors.append('ERR_WEBSESSION_DB_ERROR')
return (body, errors, warnings)
elif user_status[0][0] != cfg_websession_usergroup_status['ADMIN']:
errors.append(('ERR_WEBSESSION_GROUP_NO_RIGHTS',))
return (body, errors, warnings)
group_infos = db.get_group_infos(grpID)
if not len(group_infos):
errors.append('ERR_WEBSESSION_DB_ERROR')
return (body, errors, warnings)
members = db.get_users_by_status(grpID, cfg_websession_usergroup_status["MEMBER"])
pending_members = db.get_users_by_status(grpID, cfg_websession_usergroup_status["PENDING"])
body = websession_templates.tmpl_display_manage_member(grpID=grpID,
group_name=group_infos[0][1],
members=members,
pending_members=pending_members,
warnings=warnings,
infos=infos,
ln=ln)
return (body, errors, warnings)
def perform_request_remove_member(uid,
grpID,
member_id,
ln=cdslang):
"""Remove member from a group
@param uid: user ID
@param grpID: ID of the group
@param member_id: selected member ID
@param ln: language
@return a (body, errors[], warnings[]) formed tuple
"""
body = ''
errors = []
warnings = []
infos = []
_ = gettext_set_language(ln)
user_status = db.get_user_status(uid, grpID)
if not len(user_status):
errors.append('ERR_WEBSESSION_DB_ERROR')
return (body, errors, warnings)
if member_id == -1:
warnings.append('WRN_WEBSESSION_NO_MEMBER_SELECTED')
(body, errors, warnings) = perform_request_manage_member(uid,
grpID,
warnings=warnings,
ln=ln)
else:
db.delete_member(grpID, member_id)
infos.append(_(cfg_websession_info_messages["MEMBER_DELETED"]))
(body, errors, warnings) = perform_request_manage_member(uid,
grpID,
infos=infos,
warnings=warnings,
ln=ln)
return (body, errors, warnings)
def perform_request_add_member(uid,
grpID,
user_id,
ln=cdslang):
"""Add waiting member to a group
@param uid: user ID
@param grpID: ID of the group
@param user_id: selected member ID
@param ln: language
@return a (body, errors[], warnings[]) formed tuple
"""
body = ''
errors = []
warnings = []
infos = []
_ = gettext_set_language(ln)
user_status = db.get_user_status(uid, grpID)
if not len(user_status):
errors.append('ERR_WEBSESSION_DB_ERROR')
return (body, errors, warnings)
if user_id == -1:
warnings.append('WRN_WEBSESSION_NO_USER_SELECTED_ADD')
(body, errors, warnings) = perform_request_manage_member(uid,
grpID,
warnings=warnings,
ln=ln)
else :
"""test if user is already member or pending"""
status = db.get_user_status(user_id, grpID)
if status and status[0][0] == 'M':
warnings.append('WRN_WEBSESSION_ALREADY_MEMBER_ADD')
(body, errors, warnings) = perform_request_manage_member(uid,
grpID,
infos=infos,
warnings=warnings,
ln=ln)
else:
db.add_pending_member(grpID,
user_id,
cfg_websession_usergroup_status["MEMBER"])
infos.append(_(cfg_websession_info_messages["MEMBER_ADDED"]))
group_infos = db.get_group_infos(grpID)
group_name = group_infos[0][1]
user = get_user_info(user_id, ln)[2]
msg_subjet, msg_body = websession_templates.tmpl_member_msg(group_name=group_name,
- status=_("accepted"),
+ accepted=1,
ln=ln)
(body, errors, warnings, title, navtrail) = perform_request_send(uid,
msg_to_user=user,
msg_to_group="",
msg_subject=msg_subjet,
msg_body=msg_body,
ln=ln)
(body, errors, warnings) = perform_request_manage_member(uid,
grpID,
infos=infos,
warnings=warnings,
ln=ln)
return (body, errors, warnings)
def perform_request_reject_member(uid,
grpID,
user_id,
ln=cdslang):
"""Reject waiting member and delete it from the list
@param uid: user ID
@param grpID: ID of the group
@param member_id: selected member ID
@param ln: language
@return a (body, errors[], warnings[]) formed tuple
"""
body = ''
errors = []
warnings = []
infos = []
_ = gettext_set_language(ln)
user_status = db.get_user_status(uid, grpID)
if not len(user_status):
errors.append('ERR_WEBSESSION_DB_ERROR')
return (body, errors, warnings)
if user_id == -1:
warnings.append('WRN_WEBSESSION_NO_USER_SELECTED_DEL')
(body, errors, warnings) = perform_request_manage_member(uid,
grpID,
warnings=warnings,
ln=ln)
else :
"""test if user is already member or pending"""
status = db.get_user_status(user_id, grpID)
if not status:
warnings.append('WRN_WEBSESSION_ALREADY_MEMBER_REJECT')
(body, errors, warnings) = perform_request_manage_member(uid,
grpID,
infos=infos,
warnings=warnings,
ln=ln)
else:
db.delete_member(grpID,
user_id)
group_infos = db.get_group_infos(grpID)
group_name = group_infos[0][1]
user = get_user_info(user_id, ln)[2]
msg_subjet, msg_body = websession_templates.tmpl_member_msg(group_name=group_name,
- status=_("rejected"),
+ accepted=0,
ln=ln)
(body, errors, warnings, title, navtrail) = perform_request_send(uid,
msg_to_user=user,
msg_to_group="",
msg_subject=msg_subjet,
msg_body=msg_body,
ln=ln)
infos.append(_(cfg_websession_info_messages["MEMBER_REJECTED"]))
(body, errors, warnings) = perform_request_manage_member(uid,
grpID,
infos=infos,
warnings=warnings,
ln=ln)
return (body, errors, warnings)
def account_group(uid, ln=cdslang):
"""
display group info for myaccount.py page.
@param uid: user id (int)
@param ln: language
@return html body
"""
nb_admin_groups = db.count_nb_group_user(uid, cfg_websession_usergroup_status["ADMIN"])
nb_member_groups = db.count_nb_group_user(uid, cfg_websession_usergroup_status["MEMBER"])
nb_total_groups = nb_admin_groups + nb_member_groups
return websession_templates.tmpl_group_info(nb_admin_groups,
nb_member_groups,
nb_total_groups,
ln=ln)
def get_navtrail(ln=cdslang, title=""):
"""
gets the navtrail for title...
@param title: title of the page
@param ln: language
@return HTML output
"""
navtrail = websession_templates.tmpl_navtrail(ln, title)
return navtrail
def group_name_valid_p(group_name):
"""Test if the group's name is valid"""
return nickname_valid_p(group_name)
diff --git a/modules/websession/lib/websession_templates.py b/modules/websession/lib/websession_templates.py
index 8ebf130ba..ada5014db 100644
--- a/modules/websession/lib/websession_templates.py
+++ b/modules/websession/lib/websession_templates.py
@@ -1,1797 +1,1815 @@
## $Id$
## This file is part of CDS Invenio.
## Copyright (C) 2002, 2003, 2004, 2005, 2006 CERN.
##
## CDS Invenio is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License as
## published by the Free Software Foundation; either version 2 of the
## License, or (at your option) any later version.
##
## CDS Invenio is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
import urllib
import time
import cgi
import gettext
import string
import locale
from invenio.config import *
from invenio.messages import gettext_set_language
from invenio.textutils import indent_text
from invenio.websession_config import cfg_websession_group_join_policy
class Template:
def tmpl_lost_password_message(self, ln, supportemail):
"""
Defines the text that will be displayed on the 'lost password' page
Parameters:
- 'ln' *string* - The language to display the interface in
- 'supportemail' *string* - The email of the support team
"""
# load the right message language
_ = gettext_set_language(ln)
return _("If you have lost password for your CDS Invenio internal account, then please enter your email address below and the lost password will be emailed to you.") +\
"
" +\
_("Note that if you have been using an external login system (such as CERN NICE), then we cannot do anything and you have to ask there.") +\
_("Alternatively, you can ask %s to change your login system from external to internal.") % ("""%(email)s""" % { 'email' : supportemail }) +\
"
"
def tmpl_back_form(self, ln, message, act, link):
"""
A standard one-message-go-back-link page.
Parameters:
- 'ln' *string* - The language to display the interface in
- 'message' *string* - The message to display
- 'act' *string* - The action to accomplish when going back
- 'link' *string* - The link text
"""
out = """
"""% {
'message' : message,
'act' : act,
'link' : link
}
return out
def tmpl_user_preferences(self, ln, email, email_disabled, password, password_disabled, nickname):
"""
Displays a form for the user to change his email/password.
Parameters:
- 'ln' *string* - The language to display the interface in
- 'email' *string* - The email of the user
- 'email_disabled' *boolean* - If the user has the right to edit his email
- 'password' *string* - The password of the user
- 'password_disabled' *boolean* - If the user has the right to edit his password
- 'nickname' *string* - The nickname of the user (empty string if user does not have it)
"""
# load the right message language
_ = gettext_set_language(ln)
out = """
""" % {
'change_user_pass' : _("If you want to change your email address or password, please set new values in the form below."),
'edit_params' : _("Edit parameters"),
'nickname_label' : _("Nickname"),
'nickname' : nickname,
'nickname_prefix' : nickname=='' and ' '+_("Example")+':johnd' or '',
'new_email' : _("New email address"),
'mandatory' : _("mandatory"),
'example' : _("Example"),
'new_password' : _("New password"),
'optional' : _("optional"),
'note' : _("Note"),
'password_note' : _("The password phrase may contain punctuation, spaces, etc."),
'retype_password' : _("Retype password"),
'set_values' : _("Set new values"),
'email' : email,
'email_disabled' : email_disabled and "disabled" or "",
'password' : password,
'password_disabled' : password_disabled and "disabled" or "",
'sweburl': sweburl,
}
return out
def tmpl_user_external_auth(self, ln, methods, current, method_disabled):
"""
Displays a form for the user to change his authentication method.
Parameters:
- 'ln' *string* - The language to display the interface in
- 'methods' *array* - The methods of authentication
- 'method_disabled' *boolean* - If the user has the right to change this
- 'current' *string* - The currently selected method
"""
# load the right message language
_ = gettext_set_language(ln)
out = """
%(edit_method)s
%(explain_method)s:
%(select_method)s:
""" % {
'edit_method' : _("Edit login method"),
'explain_method' : _("Please select which login method you would like to use to authenticate yourself"),
'select_method' : _("Select method"),
'sweburl': sweburl,
}
for system in methods:
out += """%(system)s """ % {
'system' : system,
'disabled' : method_disabled and "disabled" or "",
'selected' : current == system and "disabled" or "",
}
out += """
""" % {
'select_method' : _("Select method"),
}
return out
def tmpl_lost_password_form(self, ln, msg):
"""
Displays a form for the user to ask for his password sent by email.
Parameters:
- 'ln' *string* - The language to display the interface in
- 'msg' *string* - Explicative message on top of the form.
"""
# load the right message language
_ = gettext_set_language(ln)
out = """
%(msg)s
%(email)s:
""" % {
'msg' : msg,
'email' : _("Email address"),
'send' : _("Send lost password"),
}
return out
def tmpl_account_info(self, ln, uid, guest, cfg_cern_site):
"""
Displays the account information
Parameters:
- 'ln' *string* - The language to display the interface in
- 'uid' *string* - The user id
- 'guest' *boolean* - If the user is guest
- 'cfg_cern_site' *boolean* - If the site is a CERN site
"""
# load the right message language
_ = gettext_set_language(ln)
out = """
%(account_offer)s
""" % {
'account_offer' : _("%s offers you the possibility to personalize the interface, to set up your own personal library of documents, or to set up an automatic alert query that would run periodically and would notify you of search results by email.") % cdsnameintl[ln],
}
if not guest:
out += """
%(change_account)s""" % {
'ln' : ln,
'your_settings' : _("Your Settings"),
'change_account' : _("Set or change your account email address or password. Specify your preferences about the look and feel of the interface.")
}
out += """
%(basket_explain)s""" % {
'ln' : ln,
'your_searches' : _("Your Searches"),
'search_explain' : _("View all the searches you performed during the last 30 days."),
'your_baskets' : _("Your Baskets"),
'basket_explain' : _("With baskets you can define specific collections of items, store interesting records you want to access later or share with others."),
}
if guest:
out += self.tmpl_warning_guest_user(ln = ln, type = "baskets")
out += """
%(explain_alerts)s""" % {
'ln' : ln,
'your_alerts' : _("Your Alerts"),
'explain_alerts' : _("Subscribe to a search which will be run periodically by our service. The result can be sent to you via Email or stored in one of your baskets."),
}
if guest:
out += self.tmpl_warning_guest_user(type="alerts", ln = ln)
if cfg_cern_site:
out += """
%(explain_loans)s""" % {
'your_loans' : _("Your Loans"),
'explain_loans' : _("Check out book you have on loan, submit borrowing requests, etc. Requires CERN ID."),
}
out += """
"""
return out
def tmpl_warning_guest_user(self, ln, type):
"""
Displays a warning message about the specified type
Parameters:
- 'ln' *string* - The language to display the interface in
- - 'type' *string* - The type of data that will get lost in case of guest account
+ - 'type' *string* - The type of data that will get lost in case of guest account (for the moment: 'alerts' or 'baskets')
"""
# load the right message language
_ = gettext_set_language(ln)
-
- msg = _("You are logged in as a guest user, so your %s will disappear at the end of the current session. If you wish you can %slogin or register here%s.")
- msg %= (type, '', '')
+ if (type=='baskets'):
+ msg = _("You are logged in as a guest user, so your baskets will disappear at the end of the current session.") + ' '
+ elif (type=='alerts'):
+ msg = _("You are logged in as a guest user, so your alerts will disappear at the end of the current session.") + ' '
+ msg += _("If you wish you can %(x_url_open)slogin or register here%(x_url_close)s.") % {'x_url_open': '',
+ 'x_url_close': ''}
return """
%s
""" % msg
def tmpl_account_body(self, ln, user):
"""
Displays the body of the actions of the user
Parameters:
- 'ln' *string* - The language to display the interface in
- 'user' *string* - The username (nickname or email)
"""
# load the right message language
_ = gettext_set_language(ln)
- return _("You are logged in as %(x_user)s. You may want to a) %(x_link1_begin)slogout%(x_link_end)s; b) edit your %(x_link2_begin)saccount settings%(x_link_end)s.") % {
- 'x_user': user,
- 'x_link1_begin': '',
- 'x_link_end': '',
- 'x_link2_begin': ''} + "
""" % (title, body)
return out
def tmpl_account_page(self, ln, weburl, accBody, baskets, alerts, searches, messages, groups, administrative):
"""
Displays the your account page
Parameters:
- 'ln' *string* - The language to display the interface in
- 'weburl' *string* - The URL of CDS Invenio
- 'accBody' *string* - The body of the heading block
- 'baskets' *string* - The body of the baskets block
- 'alerts' *string* - The body of the alerts block
- 'searches' *string* - The body of the searches block
- 'messages' *string* - The body of the messages block
- 'groups' *string* - The body of the groups block
- 'administrative' *string* - The body of the administrative block
"""
# load the right message language
_ = gettext_set_language(ln)
out = ""
out += self.tmpl_account_template(_("Your Account"), accBody, ln)
out += self.tmpl_account_template(_("Your Messages"), messages, ln)
out += self.tmpl_account_template(_("Your Baskets"), baskets, ln)
out += self.tmpl_account_template(_("Your Alert Searches"), alerts, ln)
out += self.tmpl_account_template(_("Your Searches"), searches, ln)
- out += self.tmpl_account_template(_("Your Groups"), groups, ln)
- submission_description = _("You can consult the list of %syour submissions%s and inquire about their status.")
- submission_description %= ('', '')
+ groups_description = _("You can consult the list of %(x_url_open)syour groups%(x_url_close)s you are administering or are a member of.")
+ groups_description %= {'x_url_open': '',
+ 'x_url_close': ''}
+ out += self.tmpl_account_template(_("Your Groups"), groups_description, ln)
+ submission_description = _("You can consult the list of %(x_url_open)syour submissions%(x_url_close)s and inquire about their status.")
+ submission_description %= {'x_url_open': '',
+ 'x_l_c': ''}
out += self.tmpl_account_template(_("Your Submissions"), submission_description, ln)
- approval_description = _("You can consult the list of %syour approvals%s with the documents you approved or refereed.")
- approval_description %= ('', '')
+ approval_description = _("You can consult the list of %(x_url_open)syour approvals%(x_url_close)s with the documents you approved or refereed.")
+ approval_description %= {'x_url_open': '',
+ 'x_url_close': ''}
out += self.tmpl_account_template(_("Your Approvals"), approval_description, ln)
out += self.tmpl_account_template(_("Your Administrative Activities"), administrative, ln)
return out
def tmpl_account_emailMessage(self, ln, msg):
"""
Displays a link to retrieve the lost password
Parameters:
- 'ln' *string* - The language to display the interface in
- 'msg' *string* - Explicative message on top of the form.
"""
# load the right message language
_ = gettext_set_language(ln)
out =""
out +="""
%(msg)s %(try_again)s
""" % {
'ln' : ln,
'msg' : msg,
'try_again' : _("Try again")
}
return out
def tmpl_account_emailSent(self, ln, email):
"""
Displays a confirmation message for an email sent
Parameters:
- 'ln' *string* - The language to display the interface in
- 'email' *string* - The email to which the message has been sent
"""
# load the right message language
_ = gettext_set_language(ln)
out =""
out += _("Okay, password has been emailed to %s.") % email
return out
def tmpl_account_delete(self, ln):
"""
Displays a confirmation message about deleting the account
Parameters:
- 'ln' *string* - The language to display the interface in
"""
# load the right message language
_ = gettext_set_language(ln)
out = "
" + _("""Deleting your account""")
return out
def tmpl_account_logout(self, ln):
"""
Displays a confirmation message about logging out
Parameters:
- 'ln' *string* - The language to display the interface in
"""
# load the right message language
_ = gettext_set_language(ln)
-
- out = ""
- out += _("You are no longer recognized. If you wish you can %slogin here%s.") % ('', '')
+ out = _("You are no longer recognized.") + ' '
+ out += _("If you wish you can %(x_url_open)slogin here%(x_url_close)s.") % {'x_url_open': '',
+ 'x_url_close': ''}
return out
def tmpl_login_form(self, ln, referer, internal, register_available, methods, selected_method, supportemail):
"""
Displays a login form
Parameters:
- 'ln' *string* - The language to display the interface in
- 'referer' *string* - The referer URL - will be redirected upon after login
- 'internal' *boolean* - If we are producing an internal authentication
- 'register_available' *boolean* - If users can register freely in the system
- 'methods' *array* - The available authentication methods
- 'selected_method' *string* - The default authentication method
- 'supportemail' *string* - The email of the support team
"""
# load the right message language
_ = gettext_set_language(ln)
out = "
%(please_login)s " % {
'please_login' : _("If you already have an account, please login using the form below.")
}
if register_available:
- out += _("If you don't own an account yet, please %sregister%s an internal account.") % ('', '')
+ out += _("If you don't own an account yet, please %(x_url_open)sregister%(x_url_close)s an internal account.") %\
+ {'x_url_open': '',
+ 'x_url_close': ''}
else:
out += _("It is not possible to create an account yourself. Contact %s if you want an account.") % ('%s' % (supportemail, supportemail))
out += """
"""
if len(methods) > 1:
# more than one method, must make a select
login_select = """"
out += """
%(login_title)s
%(login_select)s
""" % {
'login_title' : _("Login via:"),
'login_select' : login_select,
}
else:
# only one login method available
out += """""" % (methods[0])
out += """
%(username)s:
%(password)s:
""" % {
'ln': ln,
'referer' : cgi.escape(referer),
'username' : _("Username"),
'password' : _("Password"),
'login' : _("login"),
}
if internal:
out += """ (%(lost_pass)s)""" % {
'ln' : ln,
'lost_pass' : _("Lost your password?")
}
out += """
"""
return out
def tmpl_lost_your_password_teaser(self, ln=cdslang):
"""Displays a short sentence to attract user to the fact that
maybe he lost his password. Used by the registration page.
"""
_ = gettext_set_language(ln)
out = ""
out += """%(maybe_lost_pass)s""" % {
'ln' : ln,
'maybe_lost_pass': ("Maybe you have lost your password?")
}
return out
def tmpl_register_page(self, ln, referer, level, supportemail, cdsname):
"""
Displays a login form
Parameters:
- 'ln' *string* - The language to display the interface in
- 'referer' *string* - The referer URL - will be redirected upon after login
- 'level' *int* - Login level (0 - all access, 1 - accounts activated, 2+ - no self-registration)
- 'supportemail' *string* - The email of the support team
- 'cdsname' *string* - The name of the installation
"""
# load the right message language
_ = gettext_set_language(ln)
out = ""
if level <= 1:
out += _("Please enter your email address and desired nickname and password:")
if level == 1:
out += _("It will not be possible to use the account before it has been verified and activated.")
out += """
%(email_address)s: (%(mandatory)s)
%(example)s:john.doe@example.com
%(nickname)s: (%(mandatory)s)
%(example)s:johnd
%(password)s: (%(optional)s)
%(note)s: %(password_contain)s
%(retype)s:
%(note)s: %(explain_acc)s""" % {
'referer' : cgi.escape(referer),
'email_address' : _("Email address"),
'nickname' : _("Nickname"),
'password' : _("Password"),
'mandatory' : _("mandatory"),
'optional' : _("optional"),
'example' : _("Example"),
'note' : _("Note"),
'password_contain' : _("The password phrase may contain punctuation, spaces, etc."),
'retype' : _("Retype Password"),
'register' : _("register"),
'explain_acc' : _("Please do not use valuable passwords such as your Unix, AFS or NICE passwords with this service. Your email address will stay strictly confidential and will not be disclosed to any third party. It will be used to identify you for personal services of %s. For example, you may set up an automatic alert search that will look for new preprints and will notify you daily of new arrivals by email.") % cdsname,
}
return out
def tmpl_account_adminactivities(self, ln, weburl, uid, guest, roles, activities):
"""
Displays the admin activities block for this user
Parameters:
- 'ln' *string* - The language to display the interface in
- 'weburl' *string* - The address of the site
- 'uid' *string* - The used id
- 'guest' *boolean* - If the user is guest
- 'roles' *array* - The current user roles
- 'activities' *array* - The user allowed activities
"""
# load the right message language
_ = gettext_set_language(ln)
out = ""
# guest condition
if guest:
- return _("You seem to be a guest user. You have to %slogin%s first.") % ('', '')
+ return _("You seem to be a guest user. You have to %(x_url_open)slogin%(x_url_close)s first.") % ('', '')
# no rights condition
if not roles:
return "
" + _("You are not authorized to access administrative functions.") + "
"
# displaying form
- out += "
" + (_("You seem to be %s.") % ('' + string.join(roles, ", ") + " ")) + '
'
+ out += "
" + (_("You seem to be %(x_role)s.") % ('' + string.join(roles, ", ") + " ")) + '
'
out += _("Here are some interesting web admin links for you:")
# print proposed links:
activities.sort(lambda x, y: cmp(string.lower(x), string.lower(y)))
for action in activities:
if action == "runbibedit":
out += """ %s""" % (weburl, ln, _("Run BibEdit"))
if action == "cfgbibformat":
out += """ %s""" % (weburl, ln, _("Configure BibFormat"))
if action == "cfgbibharvest":
out += """ %s""" % (weburl, ln, _("Configure BibHarvest"))
if action == "cfgbibindex":
out += """ %s""" % (weburl, ln, _("Configure BibIndex"))
if action == "cfgbibrank":
out += """ %s""" % (weburl, ln, _("Configure BibRank"))
if action == "cfgwebaccess":
out += """ %s""" % (weburl, ln, _("Configure WebAccess"))
if action == "cfgwebcomment":
out += """ %s""" % (weburl, ln, _("Configure WebComment"))
if action == "cfgwebsearch":
out += """ %s""" % (weburl, ln, _("Configure WebSearch"))
if action == "cfgwebsubmit":
out += """ %s""" % (weburl, ln, _("Configure WebSubmit"))
- out += " " + _("For more admin-level activities, see the complete %sAdmin Area%s.""") %\
- ('' % (weburl, ln), '')
+ out += " " + _("For more admin-level activities, see the complete %(x_url_open)sAdmin Area%(x_url_close)s.") %\
+ {'x_url_open': '',
+ 'x_url_close': ''}
return out
def tmpl_create_userinfobox(self, ln, url_referer, guest, username, submitter, referee, admin):
"""
Displays the user block
Parameters:
- 'ln' *string* - The language to display the interface in
- 'url_referer' *string* - URL of the page being displayed
- 'guest' *boolean* - If the user is guest
- 'username' *string* - The username (nickname or email)
- 'submitter' *boolean* - If the user is submitter
- 'referee' *boolean* - If the user is referee
- 'admin' *boolean* - If the user is admin
"""
# load the right message language
_ = gettext_set_language(ln)
out = """""" % weburl
if guest:
out += """%(guest_msg)s ::
%(session)s ::
%(baskets)s ::
%(alerts)s ::
%(login)s""" % {
'weburl' : weburl,
'sweburl': sweburl,
'ln' : ln,
'guest_msg' : _("guest"),
'session' : _("session"),
'alerts' : _("alerts"),
'baskets' : _("baskets"),
'login' : _("login"),
}
else:
out += """%(username)s ::
%(account)s ::
%(messages)s ::
%(baskets)s ::
%(alerts)s ::
%(groups)s :: """ % {
'username' : username,
'weburl' : weburl,
'sweburl' : sweburl,
'ln' : ln,
'account' : _("account"),
'alerts' : _("alerts"),
'messages': _("messages"),
'baskets' : _("baskets"),
'groups' : _("groups"),
}
if submitter:
out += """%(submission)s :: """ % {
'weburl' : weburl,
'ln' : ln,
'submission' : _("submissions"),
}
if referee:
out += """%(approvals)s :: """ % {
'weburl' : weburl,
'ln' : ln,
'approvals' : _("approvals"),
}
if admin:
out += """%(administration)s :: """ % {
'sweburl' : sweburl,
'ln' : ln,
'administration' : _("administration"),
}
out += """%(logout)s""" % {
'sweburl' : sweburl,
'ln' : ln,
'logout' : _("logout"),
}
return out
def tmpl_warning(self, warnings, ln=cdslang):
"""
Prepare the warnings list
@param warnings: list of warning tuples (warning_msg, arg1, arg2, etc)
@return html string of warnings
"""
from invenio.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', ln)
for (warning_code, warning_text) in warnings_parsed:
if not warning_code.startswith('WRN'):
#display only warnings that begin with WRN to user
continue
span_class = 'important'
out += '''
%(warning)s ''' % \
{ 'span_class' : span_class,
'warning' : warning_text }
return out
else:
return ""
def tmpl_warnings(self, warnings, ln=cdslang):
"""
Display len(warnings) warning fields
@param infos: list of strings
@param ln=language
@return html output
"""
if not((type(warnings) is list) or (type(warnings) is tuple)):
warnings = [warnings]
warningbox = ""
if warnings != []:
warningbox = "
\n Warning:\n"
for warning in warnings:
lines = warning.split("\n")
warningbox += "
"
for line in lines[0:-1]:
warningbox += line + " \n"
warningbox += lines[-1] + "
"
warningbox += "
\n"
return warningbox
def tmpl_display_all_groups(self,
infos,
admin_group_html,
member_group_html,
warnings=[],
ln=cdslang):
"""
Displays the 2 tables of groups: admin and member
Parameters:
- 'ln' *string* - The language to display the interface in
- 'admin_group_html' *string* - Html code for displaying all the groups
the user is the administrator of
- 'member_group_html' *string* - Html code for displaying all the groups
the user is member of
"""
_ = gettext_set_language(ln)
group_text = self.tmpl_infobox(infos)
group_text += self.tmpl_warning(warnings)
group_text += """
%s
%s
""" %(admin_group_html, member_group_html)
return group_text
def tmpl_display_admin_group(self, groups, ln=cdslang):
"""
Display the groups the user is admin of.
Parameters:
- 'ln' *string* - The language to display the interface in
- 'groups' *list* - All the group the user is admin of
- 'infos' *list* - Display infos on top of admin group table
"""
_ = gettext_set_language(ln)
img_link = """
%(text)s
"""
out = self.tmpl_group_table_title(img="/img/group_admin.png",
text=_("You are an administrator of the following groups:") )
out += """
%s
%s
""" %(_("Group"), _("Description"))
if len(groups) == 0:
out += """
%s
""" %(_("You are not an administrator of any groups."),)
for group_data in groups:
(grpID, name, description) = group_data
edit_link = img_link % {'weburl' : weburl,
'grpID' : grpID,
'ln': ln,
'img':"webbasket_create_small.png",
'text':_("Edit group"),
'action':"edit"
}
members_link = img_link % {'weburl' : weburl,
'grpID' : grpID,
'ln': ln,
'img':"webbasket_usergroup.png",
'text':_("Edit %s members") % ' ',
'action':"members"
}
out += """
%s
%s
%s
%s
""" %(name, description, edit_link, members_link)
out += """
""" % {'ln': ln,
'write_label': _("Create new group"),
}
return indent_text(out, 2)
def tmpl_display_member_group(self, groups, ln=cdslang):
"""
Display the groups the user is member of.
Parameters:
- 'ln' *string* - The language to display the interface in
- 'groups' *list* - All the group the user is member of
"""
_ = gettext_set_language(ln)
group_text = self.tmpl_group_table_title(img="/img/webbasket_us.png", text=_("You are a member of the following groups:"))
group_text += """
""" %(_("You are not a member of any groups."),)
for group_data in groups:
(id, name, description) = group_data
group_text += """
%s
%s
""" %(name, description)
group_text += """
""" % {'ln': ln,
'join_label': _("Join new group"),
'leave_label':_("Leave group")
}
return indent_text(group_text, 2)
def tmpl_display_input_group_info(self,
group_name,
group_description,
join_policy,
act_type="create",
grpID="",
warnings=[],
ln=cdslang):
"""
Display group data when creating or updating a group:
Name, description, join_policy.
Parameters:
- 'ln' *string* - The language to display the interface in
- 'group_name' *string* - name of the group
- 'group_description' *string* - description of the group
- 'join_policy' *string* - join policy
- 'act_type' *string* - info about action : create or edit(update)
- 'grpID' *string* - ID of the group(not null in case of group editing)
- 'warnings' *list* - Display warning if values are not correct
"""
_ = gettext_set_language(ln)
#default
hidden_id =""
form_name = "create_group"
action = weburl + '/yourgroups/create'
button_label = _("Create new group")
button_name = "create_button"
label = _("Create new group")
delete_text = ""
if act_type == "update":
form_name = "update_group"
action = weburl + '/yourgroups/edit'
button_label = _("Update group")
button_name = "update"
label = _('Edit group %s') % group_name
delete_text = """"""
delete_text %= (_("Delete group"),"delete")
if grpID != "":
hidden_id = """"""
hidden_id %= grpID
out = self.tmpl_warning(warnings)
out += """
%(label)s
%(name_label)s
%(description_label)s
%(join_policy_label)s
%(join_policy)s
%(hidden_id)s
%(delete_text)s
"""
out %= {'action' : action,
'logo': weburl + '/img/webbasket_create.png',
'label': label,
'form_name' : form_name,
'name_label': _("Group name:"),
'delete_text': delete_text,
'description_label': _("Group description:"),
'join_policy_label': _("Group join policy:"),
'group_name': group_name,
'group_description': group_description,
'button_label': button_label,
'button_name':button_name,
'cancel_label':_("Cancel"),
'hidden_id':hidden_id,
'ln': ln,
'join_policy' :self.__create_join_policy_selection_menu("join_policy",
join_policy,
ln)
}
return indent_text(out, 2)
def tmpl_display_input_join_group(self,
group_list,
group_name,
group_from_search,
search,
warnings=[],
ln=cdslang):
"""
Display the groups the user can join.
He can use default select list or the search box
Parameters:
- 'ln' *string* - The language to display the interface in
- 'group_list' *list* - All the group the user can join
- 'group_name' *string* - Name of the group the user is looking for
- 'group_from search' *list* - List of the group the user can join matching group_name
- 'search' *int* - User is looking for group using group_name
- 'warnings' *list* - Display warning if two group are selected
"""
_ = gettext_set_language(ln)
out = self.tmpl_warning(warnings)
search_content = ""
if search:
search_content = """
"""
out %= {'action' : weburl + '/yourgroups/join',
'logo': weburl + '/img/webbasket_create.png',
'label': _("Join group"),
'group_name': group_name,
'label2':_("or find it") + ': ',
'list_label':_("Choose group:"),
'ln': ln,
'find_label': _("Find group"),
'cancel_label':_("Cancel"),
'group_list' :self.__create_select_menu("grpID",group_list, _("Please select:")),
'search_content' : search_content
}
return indent_text(out, 2)
def tmpl_display_manage_member(self,
grpID,
group_name,
members,
pending_members,
infos=[],
warnings=[],
ln=cdslang):
"""Display current members and waiting members of a group.
Parameters:
- 'ln' *string* - The language to display the interface in
- 'grpID *string* - ID of the group
- 'group_name' *string* - Name of the group
- 'members' *list* - List of the current members
- 'pending_members' *list* - List of the waiting members
- 'infos' *tuple of 2 lists* - Message to inform user about his last action
- 'warnings' *list* - Display warning if two group are selected
"""
_ = gettext_set_language(ln)
out = self.tmpl_warning(warnings)
out += self.tmpl_infobox(infos)
out += """
%(title)s
%(header1)s
%(member_text)s
%(header2)s
%(pending_text)s
%(header3)s
%(invite_text)s
"""
if members :
member_list = self.__create_select_menu("member_id", members, _("Please select:"))
member_text = """
""" % _("No members awaiting approval.")
header1 = self.tmpl_group_table_title(text=_("Current members"))
header2 = self.tmpl_group_table_title(text=_("Members awaiting approval"))
header3 = _("Invite new members")
link_open = ''
link_open %= (weburl, ln)
- invite_text = _("If you want to invite new members to join your group, please use the %sweb message%s system.") % (link_open, '')
+ invite_text = _("If you want to invite new members to join your group, please use the %(x_url_open)sweb message%(x_url_close)s system.") % \
+ {'x_url_open': link_open,
+ 'x_url_close': ''}
action = weburl + '/yourgroups/members?ln=' + ln
out %= {'title':_('Group: %s') % group_name,
'member_text' : member_text,
'pending_text' :pending_text,
'action':action,
'grpID':grpID,
'header1': header1,
'header2': header2,
'header3': header3,
'invite_text': invite_text,
'cancel_label':_("Cancel"),
'ln':ln
}
return indent_text(out, 2)
def tmpl_display_input_leave_group(self,
groups,
warnings=[],
ln=cdslang):
"""Display groups the user can leave.
Parameters:
- 'ln' *string* - The language to display the interface in
- 'groups' *list* - List of groups the user is currently member of
- 'warnings' *list* - Display warning if no group is selected
"""
_ = gettext_set_language(ln)
out = self.tmpl_warning(warnings)
out += """
%(label)s
%(list_label)s
%(groups)s
%(submit)s
"""
if groups:
groups = self.__create_select_menu("grpID", groups, _("Please select:"))
list_label = _("Group list")
submit = """""" % _("Leave group")
else :
groups = _("You are not member of any group.")
list_label = ""
submit = ""
action = weburl + '/yourgroups/leave?ln=%s'
action %= (ln)
out %= {'groups' : groups,
'list_label' : list_label,
'action':action,
'logo': weburl + '/img/webbasket_create.png',
'label' : _("Leave group"),
'cancel_label':_("Cancel"),
'ln' :ln,
'submit' : submit
}
return indent_text(out, 2)
def tmpl_confirm_delete(self, grpID, ln=cdslang):
"""
display a confirm message when deleting a group
@param ln: language
@return html output
"""
_ = gettext_set_language(ln)
action = weburl + '/yourgroups/edit'
out = """
%(message)s
"""% {'message': _("Are you sure you want to delete this group?"),
'ln':ln,
'yes_label': _("Yes"),
'no_label': _("No"),
'grpID':grpID,
'action': action
}
return indent_text(out, 2)
def tmpl_confirm_leave(self, uid, grpID, ln=cdslang):
"""
display a confirm message
@param ln: language
@return html output
"""
_ = gettext_set_language(ln)
action = weburl + '/yourgroups/leave'
out = """
%(message)s
"""% {'message': _("Are you sure you want to leave this group?"),
'ln':ln,
'yes_label': _("Yes"),
'no_label': _("No"),
'grpID':grpID,
'action': action
}
return indent_text(out, 2)
def __create_join_policy_selection_menu(self, name, current_join_policy, ln=cdslang):
"""Private function. create a drop down menu for selection of join policy
@param current_join_policy: join policy as defined in cfg_websession_group_join_policy
@param ln: language
"""
_ = gettext_set_language(ln)
elements = [(cfg_websession_group_join_policy['VISIBLEOPEN'],
_("Visible and open for new members")),
(cfg_websession_group_join_policy['VISIBLEMAIL'],
_("Visible but new members need approval"))
]
select_text = _("Please select:")
return self.__create_select_menu(name, elements, select_text, selected_key=current_join_policy)
def __create_select_menu(self, name, elements, select_text, multiple=0, selected_key=None):
""" private function, returns a popup menu
@param name: name of HTML control
@param elements: list of (key, value)
"""
if multiple :
out = """
""" % {
'back' : _("Back to main menu"),
'images' : images,
'mainmenu' : mainmenu,
}
return out
def tmpl_function_output(self, ln, display_on, action, doctype, step, functions):
"""
Produces the output of the functions.
Parameters:
- 'ln' *string* - The language to display the interface in
- 'display_on' *bool* - If debug information should be displayed
- 'doctype' *string* - The document type
- 'action' *string* - The action
- 'step' *int* - The current step in submission
- 'functions' *aray* - HTML code produced by functions executed and informations about the functions
- 'name' *string* - the name of the function
- 'score' *string* - the score of the function
- 'error' *bool* - if the function execution produced errors
- 'text' *string* - the HTML code produced by the function
"""
# load the right message language
_ = gettext_set_language(ln)
out = ""
if display_on:
out += """
%(function_list)s
%(function)s
%(score)s
%(running)s
""" % {
'function_list' : _("Here is the %(x_action)s function list for %(x_doctype)s documents at level %(x_step)s") % {
'x_action' : action,
'x_doctype' : doctype,
'x_step' : step,
},
'function' : _("Function"),
'score' : _("Score"),
'running' : _("Running function"),
}
for function in functions:
out += """
%(name)s
%(score)s
%(result)s
""" % {
'name' : function['name'],
'score' : function['score'],
'result' : function['error'] and (_("Function %s does not exist.") % function['name'] + " ") or function['text']
}
out += "
"
else:
for function in functions:
if not function['error']:
out += function['text']
return out
def tmpl_next_action(self, ln, actions):
"""
Produces the output of the functions.
Parameters:
- 'ln' *string* - The language to display the interface in
- 'actions' *array* - The actions to display, in the structure
- 'page' *string* - the starting page
- 'action' *string* - the action (in terms of submission)
- 'doctype' *string* - the doctype
- 'nextdir' *string* - the path to the submission data
- 'access' *string* - the submission number
- 'indir' *string* - ??
- 'name' *string* - the name of the action
"""
# load the right message language
_ = gettext_set_language(ln)
out = "
%(haveto)s
" % {
'haveto' : _("You must now"),
}
i = 0
for action in actions:
if i > 0:
out += " " + _("or") + " "
i += 1
out += """
"
return out
def tmpl_filelist(self, ln, filelist, recid, docid, version):
"""
Displays the file list for a record.
Parameters:
- 'ln' *string* - The language to display the interface in
- 'recid' *string* - The record id
- 'docid' *string* - The document id
- 'version' *string* - The version of the document
- 'filelist' *string* - The HTML string of the filelist (produced by the BibDoc classes)
"""
# load the right message language
_ = gettext_set_language(ln)
title = _("record") + ' #' + '%s' % (weburl, recid, recid)
if docid != "":
title += ' ' + _("document") + ' #' + str(docid)
if version != "":
title += ' ' + _("version") + ' #' + str(version)
out = """
Access to Fulltext [%s]
%s
""" % (title, filelist)
return out
def tmpl_bibrecdoc_filelist(self, ln, types):
"""
Displays the file list for a record.
Parameters:
- 'ln' *string* - The language to display the interface in
- 'types' *array* - The different types to display, each record in the format:
- 'name' *string* - The name of the format
- 'content' *array of string* - The HTML code produced by tmpl_bibdoc_filelist, for the right files
"""
# load the right message language
_ = gettext_set_language(ln)
out = ""
for mytype in types:
out += "%s %s:" % (mytype['name'], _("file(s)"))
out += "
"
for content in mytype['content']:
out += content
out += "
"
return out
def tmpl_bibdoc_filelist(self, ln, weburl, versions, imagepath, docname, id):
"""
Displays the file list for a record.
Parameters:
- 'ln' *string* - The language to display the interface in
- 'weburl' *string* - The url of CDS Invenio
- 'versions' *array* - The different versions to display, each record in the format:
- 'version' *string* - The version
- 'content' *string* - The HTML code produced by tmpl_bibdocfile_filelist, for the right file
- 'previous' *bool* - If the file has previous versions
- 'imagepath' *string* - The path to the image of the file
- 'docname' *string* - The name of the document
- 'id' *int* - The id of the document
"""
# load the right message language
_ = gettext_set_language(ln)
out = """
%(docname)s
""" % {
'imagepath' : imagepath,
'docname' : docname
}
for version in versions:
if version['previous']:
versiontext = """ (%(see)s %(previous)s)""" % {
'see' : _("see"),
'weburl' : weburl,
'id' : id,
'previous': _("previous"),
}
else:
versiontext = ""
out += """
%(version)s %(ver)s%(text)s
""" % {
'version' : _("version"),
'ver' : version['version'],
'text' : versiontext,
}
for content in version['content']:
out += content
out += "
"
out += "
"
return out
def tmpl_bibdocfile_filelist(self, ln, weburl, id, name, selfformat, version, format, size):
"""
Displays a file in the file list.
Parameters:
- 'ln' *string* - The language to display the interface in
- 'weburl' *string* - The url of CDS Invenio
- 'id' *int* - The id of the document
- 'name' *string* - The name of the file
- 'selfformat' *string* - The format to pass in parameter
- 'version' *string* - The version
- 'format' *string* - The display format
- 'size' *string* - The size of the file
"""
# load the right message language
_ = gettext_set_language(ln)
return """
""" % {
'weburl' : weburl,
'docid' : id,
'quotedname' : urllib.quote(name),
'selfformat' : urllib.quote(selfformat),
'version' : version,
'name' : name,
'format' : format,
'size' : size
}
def tmpl_submit_summary (self, ln, values, images):
"""
Displays the summary for the submit procedure.
Parameters:
- 'ln' *string* - The language to display the interface in
- 'values' *array* - The values of submit. Each of the records contain the following fields:
- 'name' *string* - The name of the field
- 'mandatory' *bool* - If the field is mandatory or not
- 'value' *string* - The inserted value
- 'page' *int* - The submit page on which the field is entered
- 'images' *string* - the path to the images
"""
# load the right message language
_ = gettext_set_language(ln)
out = """
""" % \
{ 'images' : images }
for value in values:
if value['mandatory']:
color = "red"
else:
color = ""
out += """
"
return out
def tmpl_yoursubmissions(self, ln, images, weburl, order, doctypes, submissions):
"""
Displays the list of the user's submissions.
Parameters:
- 'ln' *string* - The language to display the interface in
- 'images' *string* - the path to the images
- 'weburl' *string* - The url of CDS Invenio
- 'order' *string* - The ordering parameter
- 'doctypes' *array* - All the available doctypes, in structures:
- 'id' *string* - The doctype id
- 'name' *string* - The display name of the doctype
- 'selected' *bool* - If the doctype should be selected
- 'submissions' *array* - The available submissions, in structures:
- 'docname' *string* - The document name
- 'actname' *string* - The action name
- 'status' *string* - The status of the document
- 'cdate' *string* - Creation date
- 'mdate' *string* - Modification date
- 'id' *string* - The id of the submission
- 'reference' *string* - The display name of the doctype
- 'pending' *bool* - If the submission is pending
- 'act' *string* - The action code
- 'doctype' *string* - The doctype code
"""
# load the right message language
_ = gettext_set_language(ln)
out = ""
out += """
%(for)s
""" % {
'order' : order,
'for' : _("For"),
'alltype' : _("all types of document"),
}
for doctype in doctypes:
out += """""" % {
'id' : doctype['id'],
'name' : doctype['name'],
'sel' : doctype['selected'] and "SELECTED=\"SELECTED\"" or ""
}
out += """
"""
num = 0
docname = ""
for submission in submissions:
if submission['docname'] != docname:
docname = submission['docname']
out += """
%(docname)s
%(action)s
%(status)s
%(id)s
%(reference)s
%(first)s
%(last)s
""" % {
'docname' : submission['docname'],
'action' : _("Action"),
'status' : _("Status"),
'id' : _("Id"),
'reference' : _("Reference"),
'images' : images,
'first' : _("First access"),
'last' : _("Last access"),
}
if submission['pending']:
idtext = """%(id)s
""" % {
'images' : images,
'id' : submission['id'],
'action' : submission['act'],
'doctype' : submission['doctype'],
'sure' : _("Are you sure you want to delete this submission?"),
'delete' : _("Delete submission %(x_id)s in %(x_docname)s") % {
'x_id' : str(submission['id']),
'x_docname' : str(submission['docname'])
}
}
else:
idtext = submission['id']
if operator.mod(num,2) == 0:
color = "#e0e0e0"
else:
color = "#eeeeee"
if submission['reference']:
reference = submission['reference']
else:
reference = """%s""" % _("Reference not yet given")
cdate = str(submission['cdate']).replace(" "," ")
mdate= str(submission['mdate']).replace(" "," ")
out += """
"
return out
def tmpl_yourapprovals(self, ln, referees):
"""
Displays the doctypes and categories for which the user is referee
Parameters:
- 'ln' *string* - The language to display the interface in
- 'referees' *array* - All the doctypes for which the user is referee:
- 'doctype' *string* - The doctype
- 'docname' *string* - The display name of the doctype
- 'categories' *array* - The specific categories for which the user is referee:
- 'id' *string* - The category id
- 'name' *string* - The display name of the category
"""
# load the right message language
_ = gettext_set_language(ln)
out = """
%(refdocs)s
""" % {
'refdocs' : _("Refereed Documents"),
}
for doctype in referees:
out += """
%(docname)s
""" % doctype
if doctype ['categories'] is None:
out += '''
%(generalref)s ''' % {
'docname' : doctype['docname'],
'doctype' : doctype['doctype'],
'generalref' : _("You are a general referee")}
else:
for category in doctype['categories']:
out += """
%(referee)s """ % {
- 'referee' : _("You are a referee for category") + ': ' + str(category['name']) + ' (' + str(category['id']) + ')',
+ 'referee' : _("You are a referee for category:") + ' ' + str(category['name']) + ' (' + str(category['id']) + ')',
'doctype' : doctype['doctype'],
'categ' : category['id']}
out += "
"
out += "
"
return out
def tmpl_publiline_selectdoctype(self, ln, docs):
"""
Displays the doctypes that the user can select
Parameters:
- 'ln' *string* - The language to display the interface in
- 'docs' *array* - All the doctypes that the user can select:
- 'doctype' *string* - The doctype
- 'docname' *string* - The display name of the doctype
"""
# load the right message language
_ = gettext_set_language(ln)
out = """
%(list)s
%(select)s:
""" % {
'list' : _("List of refereed types of documents"),
'select' : _("Select one of the following types of documents to check the documents status."),
}
for doc in docs:
out += "
"""
return out
def tmpl_publiline_selectcateg(self, ln, doctype, title, categories, images):
"""
Displays the categories from a doctype that the user can select
Parameters:
- 'ln' *string* - The language to display the interface in
- 'doctype' *string* - The doctype
- 'title' *string* - The doctype name
- 'images' *string* - the path to the images
- 'categories' *array* - All the categories that the user can select:
- 'id' *string* - The id of the category
- 'waiting' *int* - The number of documents waiting
- 'approved' *int* - The number of approved documents
- 'rejected' *int* - The number of rejected documents
"""
# load the right message language
_ = gettext_set_language(ln)
out = """
%(title)s: %(list_categ)s
%(choose_categ)s
""" % {
'title' : title,
'doctype' : doctype,
'list_categ' : _("List of refereed categories"),
'choose_categ' : _("Please choose a category"),
}
for categ in categories:
num = categ['waiting'] + categ['approved'] + categ['rejected']
if categ['waiting'] != 0:
classtext = "class=\"blocknote\""
else:
classtext = ""
out += """%(id)s (%(num)s document(s)""" % {
'id' : categ['id'],
'classtext' : classtext,
'num' : num,
}
if categ['waiting'] != 0:
out += """| %(waiting)s """ % {
'waiting' : categ['waiting'],
'pending' : _("Pending"),
'images' : images,
}
if categ['approved'] != 0:
out += """| %(approved)s""" % {
'approved' : categ['approved'],
'approved_text' : _("Approved"),
'images' : images,
}
if categ['rejected'] != 0:
out += """| %(rejected)s""" % {
'rejected' : categ['rejected'],
'rejected_text' : _("Rejected"),
'images' : images,
}
out += ") "
out += """
""" % {
'key' : _("Key"),
'pending' : _("Pending"),
'images' : images,
'waiting' : _("Waiting for approval"),
'approved' : _("Approved"),
'already_approved' : _("Already approved"),
'rejected' : _("Rejected"),
'rejected_text' : _("Rejected"),
'somepending' : _("Some documents are pending."),
}
return out
def tmpl_publiline_selectdocument(self, ln, doctype, title, categ, images, docs):
"""
Displays the documents that the user can select in the specified category
Parameters:
- 'ln' *string* - The language to display the interface in
- 'doctype' *string* - The doctype
- 'title' *string* - The doctype name
- 'images' *string* - the path to the images
- 'categ' *string* - the category
- 'docs' *array* - All the categories that the user can select:
- 'RN' *string* - The id of the document
- 'status' *string* - The status of the document
"""
# load the right message language
_ = gettext_set_language(ln)
out = """
%(title)s - %(categ)s: %(list)s
%(choose_report)s
%(report_no)s
%(pending)s
%(approved)s
%(rejected)s
""" % {
'doctype' : doctype,
'title' : title,
'categ' : categ,
'list' : _("List of refereed documents"),
'choose_report' : _("Click on a report number for more information."),
'report_no' : _("Report Number"),
'pending' : _("Pending"),
'approved' : _("Approved"),
'rejected' : _("Rejected"),
}
for doc in docs:
status = doc ['status']
if status == "waiting":
out += """
"""
return out
def tmpl_publiline_displaydoc(self, ln, doctype, docname, categ, rn, status, dFirstReq, dLastReq, dAction, access, images, accessurl, confirm_send, auth_code, auth_message, authors, title, sysno, newrn):
"""
Displays the categories from a doctype that the user can select
Parameters:
- 'ln' *string* - The language to display the interface in
- 'doctype' *string* - The doctype
- 'docname' *string* - The doctype name
- 'categ' *string* - the category
- 'rn' *string* - The document RN (id number)
- 'status' *string* - The status of the document
- 'dFirstReq' *string* - The date of the first approval request
- 'dLastReq' *string* - The date of the last approval request
- 'dAction' *string* - The date of the last action (approval or rejection)
- 'images' *string* - the path to the images
- 'accessurl' *string* - the URL of the publications
- 'confirm_send' *bool* - must display a confirmation message about sending approval email
- 'auth_code' *bool* - authorised to referee this document
- 'auth_message' *string* - ???
- 'authors' *string* - the authors of the submission
- 'title' *string* - the title of the submission
- 'sysno' *string* - the unique database id for the record
- 'newrn' *string* - the record number assigned to the submission
"""
# load the right message language
_ = gettext_set_language(ln)
if status == "waiting":
image = """""" % images
elif status == "approved":
image = """""" % images
elif status == "rejected":
image = """""" % images
else:
image = ""
out = """
%(image)s %(rn)s
""" % {
'image' : image,
'rn' : rn,
}
if confirm_send:
out += """%(requestsent)s
""" % {
'requestsent' : _("Your request has been sent to the referee."),
}
out += """
""" % {
'rn' : rn,
'categ' : categ,
'doctype' : doctype,
}
if title != "unknown":
- out += """%(title_text)s:%(title)s
""" % {
+ 'author_text' : _("Author:"),
'authors' : authors,
}
if sysno != "":
- out += """%(more)s:
+ out += """%(more)s%(click)s
""" % {
- 'more' : _("More information"),
+ 'more' : _("More information:"),
'click' : _("Click here"),
'url' : accessurl,
'sysno' : sysno,
}
if status == "waiting":
- out += _("This document is still %swaiting for approval%s.") % ('', '')
+ out += _("This document is still %(x_fmt_open)swaiting for approval%(x_fmt_close)s.") % {'x_fmt_open': '',
+ 'x_fmt_close': ''}
out += "
"
- out += _("It was first sent for approval on") + ': ' + str(dFirstReq) + ' '
+ out += _("It was first sent for approval on:") + ' ' + str(dFirstReq) + ' '
if dLastReq == "0000-00-00 00:00:00":
- out += _("Last approval email was sent on") + ': ' + str(dFirstReq) + ' '
+ out += _("Last approval email was sent on:") + ' ' + str(dFirstReq) + ' '
else:
- out += _("Last approval email was sent on") + ': ' + str(dLastReq) + ' '
- out += " " + _("You can send an approval request email again by clicking the following button.") + ": " +\
+ out += _("Last approval email was sent on:") + ' ' + str(dLastReq) + ' '
+ out += " " + _("You can send an approval request email again by clicking the following button:") + " " +\
"""""" % {
'send' : _("Send Again"),
'warning' : _("WARNING! Upon confirmation, an email will be sent to the referee.")
}
if auth_code == 0:
out += " " + _("As a referee for this document, you may click this button to approve or reject it.") + ": " +\
"""""" % {
'approve' : _("Approve/Reject"),
'access' : access
}
if status == "approved":
- out += _("This document has been %sapproved%s.") % ('', '')
- out += ' ' + _("Its approved reference is") + ': ' + str(newrn) + '
'
- out += _("It was first sent for approval on") + ': ' + str(dFirstReq) + ' '
+ out += _("This document has been %(x_fmt_open)sapproved%(x_fmt_close)s.") % {'x_fmt_open': '',
+ 'x_fmt_close': ''}
+ out += ' ' + _("Its approved reference is:") + ' ' + str(newrn) + '
'
+ out += _("It was first sent for approval on:") + ' ' + str(dFirstReq) + ' '
if dLastReq == "0000-00-00 00:00:00":
- out += _("Last approval email was sent on") + ': ' + str(dFirstReq) + ' '
+ out += _("Last approval email was sent on:") + ' ' + str(dFirstReq) + ' '
else:
- out += _("Last approval email was sent on") + ': ' + str(dLastReq) + ' ' +\
- _("It was approved on") + ': ' + str(dAction) + ' '
+ out += _("Last approval email was sent on:") + ' ' + str(dLastReq) + ' ' +\
+ _("It was approved on:") + ' ' + str(dAction) + ' '
if status == "rejected":
- out += _("This document has been %srejected%s.") % ('', '')
+ out += _("This document has been %(x_fmt_open)srejected%(x_fmt_close)s.") % {'x_fmt_open': '',
+ 'x_fmt_close': ''}
out += "
"
- out += _("It was first sent for approval on") + ': ' + str(dFirstReq) +' '
+ out += _("It was first sent for approval on:") + ' ' + str(dFirstReq) +' '
if dLastReq == "0000-00-00 00:00:00":
- out += _("Last approval email was sent on") + ': ' + str(dFirstReq) + ' '
+ out += _("Last approval email was sent on:") + ' ' + str(dFirstReq) + ' '
else:
- out += _("Last approval email was sent on") + ': ' + str(dLastReq) +' '
- out += _("It was rejected on") + ': ' + str(dAction) + ' '
+ out += _("Last approval email was sent on:") + ' ' + str(dLastReq) +' '
+ out += _("It was rejected on:") + ' ' + str(dAction) + ' '
out += """
%(body)s
""" if user_can_add_comment: out += """ %(reply_label)s""" if user_can_delete_comment: out += """ | %(delete_label)s""" out += """