diff --git a/modules/webaccess/doc/hacking/admin-internals.html.wml b/modules/webaccess/doc/hacking/admin-internals.html.wml
index 8b1d1c769..0e06661d1 100644
--- a/modules/webaccess/doc/hacking/admin-internals.html.wml
+++ b/modules/webaccess/doc/hacking/admin-internals.html.wml
@@ -1,161 +1,161 @@
## $Id$
## This file is part of CDS Invenio.
## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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.
#include "cdspage.wml" \
title="Access Control Admin Internals" \
navbar_name="hacking-webaccess" \
navtrail_previous_links="/hacking/>Hacking CDS Invenio > /hacking/webaccess/index.html>WebAccess Internals " \
navbar_select="hacking-webaccess-admin-internals"
Version <: print generate_pretty_revision_date_string('$Id$'); :>
These are the functions called by the WebAccess Web Admin Interface to administrate
the wanted authorizations. This listing is of the most important functions.
For more information look in the source code or at the signatures.
CONTENTS
1. Adding Information
2. Finding Information
3. Deleting Information
1. Adding Information
-acc_addAction(name_action='', description='', optional='no', *allowedkeywords)
+acc_add_action(name_action='', description='', optional='no', *allowedkeywords)
function to create new entry in accACTION for an action
name_action - name of the new action, must be unique
keyvalstr - string with allowed keywords
allowedkeywords - a list of allowedkeywords
keyvalstr and allowedkeywordsdict can not be in use simultanously
success -> return id_action, name_action, description and allowedkeywords
failure -> return 0
-acc_addRole(name_role, description, firerole_def_ser, firerole_def_src)
+acc_add_role(name_role, description, firerole_def_ser, firerole_def_src)
add a new role to accROLE in the database.
name_role - name of the role, must be unique
description - text to describe the role
firerole_def_ser - precompiled serialized firewall like role definition (firerole)
firerole_def_src - definition text source for repairing after Python upgrades
-acc_addUserRole(id_user=0, id_role=0, email='', name_role='')
+acc_add_user_role(id_user=0, id_role=0, email='', name_role='')
this function adds a new entry to table user_accROLE and returns it
id_user, id_role - self explanatory
email - email of the user
name_role - name of the role, to be used instead of id.
-acc_addRoleActionArguments_names(name_role='', name_action='', arglistid=-1, optional=0, verbose=0, **keyval)
+acc_add_role_action_arguments_names(name_role='', name_action='', arglistid=-1, optional=0, verbose=0, **keyval)
this function makes it possible to pass names when creating new entries instead of ids.
get ids for all the names,
create entries in accARGUMENT that does not exist,
pass on to id based function.
name_role, name_action - self explanatory
arglistid - add entries to or create group with arglistid, default -1 create new.
optional - create entry with optional keywords, **keyval is ignored, but should be empty
verbose - used to print extra information
**keyval - dictionary of keyword=value pairs, used to find ids.
2. Finding Information
-acc_findPossibleActions(id_role, id_action)
+acc_find_possible_actions(id_role, id_action)
Role based function to find all action combinations for a
give role and action.
id_role - id of role in the database
id_action - id of the action in the database
returns a list with all the combinations.
first row is used for header.
3. Deleting Information
-acc_deleteAction(id_action=0, name_action=0)
+acc_deletea_ction(id_action=0, name_action=0)
delete action in accACTION according to id, or secondly name.
entries in accROLE_accACTION_accARGUMENT will also be removed.
id_action - id of action to be deleted, prefered variable
name_action - this is used if id_action is not given
if the name or id is wrong, the function does nothing
-acc_deleteRole(id_role=0, name_role=0)
+acc_delete_role(id_role=0, name_role=0)
delete role entry in table accROLE and all references from other tables.
id_role - id of role to be deleted, prefered variable
name_role - this is used if id_role is not given
-acc_deleteUserRole(id_user, id_role=0, name_role=0)
+acc_delete_user_role(id_user, id_role=0, name_role=0)
function deletes entry from user_accROLE and reports the success.
id_user - user in database
id_role - role in the database, prefered parameter
name_role - can also delete role on background of role name.
-acc_deleteRoleActionArguments_names(name_role='', name_action='', arglistid=1, **keyval)
+acc_delete_role_action_arguments_names(name_role='', name_action='', arglistid=1, **keyval)
utilize the function on ids by first finding all ids and redirecting the function call.
break of and return 0 if any of the ids can't be found.
name_role = name of the role
name_action - name of the action
arglistid - the argumentlistid, all keyword=value pairs must be in this same group.
**keyval - dictionary of keyword=value pairs for the arguments.
diff --git a/modules/webaccess/lib/access_control_admin.py b/modules/webaccess/lib/access_control_admin.py
index 7073112f8..26446e9b9 100644
--- a/modules/webaccess/lib/access_control_admin.py
+++ b/modules/webaccess/lib/access_control_admin.py
@@ -1,1517 +1,1779 @@
# $Id$
## CDS Invenio Access Control Engine in mod_python.
## This file is part of CDS Invenio.
## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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 Access Control Admin."""
__revision__ = "$Id$"
-# check this: def acc_addUserRole(id_user, id_role=0, name_role=0):
+# check this: def acc_add_user_role(id_user, id_role=0, name_role=0):
## import interesting modules:
-import sys
-import time
-
from invenio.config import \
- supportemail, \
- version
-from invenio.access_control_config import *
+ supportemail
+from invenio.access_control_config import CFG_ACC_EMPTY_ROLE_DEFINITION_SER, \
+ CFG_ACC_EMPTY_ROLE_DEFINITION_SRC, DELEGATEADDUSERROLE, SUPERADMINROLE, \
+ DEF_USERS, DEF_ROLES, DEF_ACTIONS, DEF_AUTHS
from invenio.dbquery import run_sql, ProgrammingError
-from invenio.access_control_firerole import compile_role_definition, acc_firerole_check_user, serialize, deserialize
+from invenio.access_control_firerole import compile_role_definition, \
+ acc_firerole_check_user, serialize, deserialize
from sets import Set
# ACTIONS
-def acc_addAction(name_action='', description='', optional='no', *allowedkeywords):
+def acc_add_action(name_action='', description='', optional='no',
+ *allowedkeywords):
"""function to create new entry in accACTION for an action
name_action - name of the new action, must be unique
keyvalstr - string with allowed keywords
allowedkeywords - a list of allowedkeywords
keyvalstr and allowedkeywordsdict can not be in use simultanously
success -> return id_action, name_action, description and allowedkeywords
failure -> return 0 """
keystr = ''
# action with this name all ready exists, return 0
- if run_sql("""SELECT * FROM accACTION WHERE name = '%s'""" % (name_action, )):
+ if run_sql("""SELECT * FROM accACTION WHERE name = %s""",
+ (name_action, )):
return 0
# create keyword string
for value in allowedkeywords:
- if keystr: keystr += ','
+ if keystr:
+ keystr += ','
keystr += value
- if not allowedkeywords: optional = 'no'
+ if not allowedkeywords:
+ optional = 'no'
# insert the new entry
- try: res = run_sql("""INSERT INTO accACTION (name, description, allowedkeywords, optional) VALUES ('%s', '%s', '%s', '%s')""" % (name_action, description, keystr, optional))
- except ProgrammingError: return 0
+ try:
+ res = run_sql("""INSERT INTO accACTION (name, description,
+ allowedkeywords, optional) VALUES (%s, %s, %s, %s)""",
+ (name_action, description, keystr, optional))
+ except ProgrammingError:
+ return 0
- if res: return res, name_action, description, keystr, optional
+ if res:
+ return res, name_action, description, keystr, optional
return 0
-def acc_deleteAction(id_action=0, name_action=0):
+def acc_delete_action(id_action=0, name_action=0):
"""delete action in accACTION according to id, or secondly name.
entries in accROLE_accACTION_accARGUMENT will also be removed.
id_action - id of action to be deleted, prefered variable
name_action - this is used if id_action is not given
if the name or id is wrong, the function does nothing
"""
if id_action and name_action:
return 0
# delete the action
- if run_sql("""DELETE FROM accACTION WHERE id = %s OR name = '%s'""" % (id_action, name_action)):
+ if run_sql("""DELETE FROM accACTION WHERE id = %s OR name = %s""",
+ (id_action, name_action)):
# delete all entries related
- return 1 + run_sql("""DELETE FROM accROLE_accACTION_accARGUMENT WHERE id_accACTION = %s """ % (id_action, ))
+ return 1 + run_sql("""DELETE FROM accROLE_accACTION_accARGUMENT WHERE
+ id_accACTION = %s """, (id_action, ))
else:
return 0
-def acc_verifyAction(name_action='', description='', allowedkeywords='', optional=''):
+def acc_verify_action(name_action='', description='', allowedkeywords='',
+ dummy=''):
"""check if all the values of a given action are the same as
those in accACTION in the database. self explanatory parameters.
return id if identical, 0 if not. """
- id_action = acc_getActionId(name_action=name_action)
+ id_action = acc_get_action_id(name_action=name_action)
- if not id_action: return 0
+ if not id_action:
+ return 0
- res_desc = acc_getActionDescription(id_action=id_action)
- res_keys = acc_getActionKeywordsString(id_action=id_action)
+ res_desc = acc_get_action_description(id_action=id_action)
+ res_keys = acc_get_action_keywords_string(id_action=id_action)
bool_desc = res_desc == description and 1 or 0
bool_keys = res_keys == allowedkeywords and 1 or 0
- bool_opti = acc_getActionIsOptional(id_action=id_action)
+ bool_opti = acc_get_action_is_optional(id_action=id_action)
return bool_desc and bool_keys and bool_opti and id_action or 0
-def acc_updateAction(id_action=0, name_action='', verbose=0, **update):
+def acc_update_action(id_action=0, name_action='', verbose=0, **update):
"""try to change the values of given action details.
if there is no change nothing is done.
some changes require to update other parts of the database.
id_action - id of the action to change
name_action - if no id_action is given try to find it using this name
**update - dictionary containg keywords: description,
allowedkeywords and/or
optional
other keywords are ignored """
- id_action = id_action or acc_getActionId(name_action=name_action)
+ id_action = id_action or acc_get_action_id(name_action=name_action)
- if not id_action: return 0
+ if not id_action:
+ return 0
try:
if update.has_key('description'):
# change the description, no other effects
- if verbose: print 'desc'
- run_sql("""UPDATE accACTION SET description = '%s' WHERE id = %s"""
- % (update['description'], id_action))
+ if verbose:
+ print 'desc'
+ run_sql("""UPDATE accACTION SET description = %s WHERE id = %s""",
+ (update['description'], id_action))
if update.has_key('allowedkeywords'):
# change allowedkeywords
- if verbose: print 'keys'
+ if verbose:
+ print 'keys'
# check if changing allowedkeywords or not
if run_sql("""SELECT * FROM accACTION
- WHERE id = %s AND allowedkeywords != '%s' """ % (id_action, update['allowedkeywords'])):
+ WHERE id = %s AND allowedkeywords != %s """,
+ (id_action, update['allowedkeywords'])):
# change allowedkeywords
- if verbose: print ' changing'
- run_sql("""UPDATE accACTION SET allowedkeywords = '%s' WHERE id = %s"""
- % (update['allowedkeywords'], id_action))
- # delete entries, but keep optional authorizations if there still is keywords
- if verbose: print ' deleting auths'
+ if verbose:
+ print ' changing'
+ run_sql("""UPDATE accACTION SET allowedkeywords = %s
+ WHERE id = %s""", (update['allowedkeywords'], id_action))
+ # delete entries, but keep optional authorizations
+ # if there still is keywords
+ if verbose:
+ print ' deleting auths'
run_sql("""DELETE FROM accROLE_accACTION_accARGUMENT
- WHERE id_accACTION = %s %s """ % (id_action, update['allowedkeywords'] and 'AND id_accARGUMENT != -1' or ''))
+ WHERE id_accACTION = %s %s """,
+ (id_action, update['allowedkeywords'] and
+ 'AND id_accARGUMENT != -1' or ''))
if update.has_key('optional'):
# check if there changing optional or not
- if verbose: print 'optional'
+ if verbose:
+ print 'optional'
if run_sql("""SELECT * FROM accACTION
- WHERE id = %s AND optional != '%s' """ % (id_action, update['optional'])):
+ WHERE id = %s AND optional != %s """,
+ (id_action, update['optional'])):
# change optional
- if verbose: print ' changing'
- run_sql("""UPDATE accACTION SET optional = '%s' WHERE id = %s"""
- % (update['optional'], id_action))
- # setting it to no, delete authorizations with optional arguments
+ if verbose:
+ print ' changing'
+ run_sql("""UPDATE accACTION SET optional = %s WHERE id = %s""",
+ (update['optional'], id_action))
+ # setting it to no, delete authorizations with
+ # optional arguments
if update['optional'] == 'no':
- if verbose: print ' deleting optional'
+ if verbose:
+ print ' deleting optional'
run_sql("""DELETE FROM accROLE_accACTION_accARGUMENT
- WHERE id_accACTION = %s AND
- id_accARGUMENT = -1 AND
- argumentlistid = -1 """ % (id_action, ))
+ WHERE id_accACTION = %s AND
+ id_accARGUMENT = -1 AND
+ argumentlistid = -1 """, (id_action, ))
except ProgrammingError:
return 0
return 1
# ROLES
-def acc_addRole(name_role, description, firerole_def_ser = CFG_ACC_EMPTY_ROLE_DEFINITION_SER, firerole_def_src = CFG_ACC_EMPTY_ROLE_DEFINITION_SRC):
+def acc_add_role(name_role, description,
+ firerole_def_ser = CFG_ACC_EMPTY_ROLE_DEFINITION_SER,
+ firerole_def_src = CFG_ACC_EMPTY_ROLE_DEFINITION_SRC):
"""add a new role to accROLE in the database.
name_role - name of the role, must be unique
description - text to describe the role
firerole_def_ser - compiled firewall like role definition
firerole_def_src - firewall like role definition sources
"""
- if not run_sql("""SELECT * FROM accROLE WHERE name = '%s'""" % (name_role, )):
- res = run_sql("""INSERT INTO accROLE (name, description, firerole_def_ser, firerole_def_src) VALUES (%s, %s, %s, %s)""", (name_role, description, firerole_def_ser, firerole_def_src))
+ if not run_sql("""SELECT * FROM accROLE WHERE name = %s""", (name_role, )):
+ res = run_sql("""INSERT INTO accROLE
+ (name, description, firerole_def_ser, firerole_def_src)
+ VALUES (%s, %s, %s, %s)""",
+ (name_role, description, firerole_def_ser, firerole_def_src))
return res, name_role, description, firerole_def_src
return 0
-def acc_isRole(name_action,**arguments):
- """ check whether the role which allows action name_action on arguments exists
+def acc_is_role(name_action, **arguments):
+ """ check whether the role which allows action name_action on arguments
+ exists
action_name - name of the action
arguments - arguments for authorization"""
# first check if an action exists with this name
query1 = """select a.id, a.allowedkeywords, a.optional
from accACTION a
- where a.name = '%s'""" % (name_action)
+ where a.name = %s"""
- try: id_action, aallowedkeywords, optional = run_sql(query1)[0]
- except (ProgrammingError, IndexError): return 0
+ try:
+ id_action, aallowedkeywords, dummy = run_sql(query1,
+ (name_action,))[0]
+ except (ProgrammingError, IndexError):
+ return 0
defkeys = aallowedkeywords.split(',')
for key in arguments.keys():
- if key not in defkeys: return 0
+ if key not in defkeys:
+ return 0
# then check if a role giving this authorization exists
- # create dictionary with default values and replace entries from input arguments
+ # create dictionary with default values and replace entries from input
+ # arguments
defdict = {}
for key in defkeys:
- try: defdict[key] = arguments[key]
- except KeyError: return 0 # all keywords must be present
- # except KeyError: defdict[key] = 'x' # default value, this is not in use...
+ try:
+ defdict[key] = arguments[key]
+ except KeyError:
+ return 0 # all keywords must be present
+ # except KeyError: defdict[key] = 'x' # default value,
+ # this is not in use...
# create or-string from arguments
str_args = ''
for key in defkeys:
- if str_args: str_args += ' OR '
- str_args += """(arg.keyword = '%s' AND arg.value = '%s')""" % (key, defdict[key])
-
- query4 = """SELECT DISTINCT raa.id_accROLE, raa.id_accACTION, raa.argumentlistid,
- raa.id_accARGUMENT, arg.keyword, arg.value
- FROM accROLE_accACTION_accARGUMENT raa, accARGUMENT arg
- WHERE raa.id_accACTION = %s AND
- (%s) AND
- raa.id_accARGUMENT = arg.id """ % (id_action, str_args)
+ if str_args:
+ str_args += ' OR '
+ str_args += """(arg.keyword = '%s' AND arg.value = '%s')""" % \
+ (key, defdict[key])
+
+ query4 = """SELECT DISTINCT raa.id_accROLE, raa.id_accACTION,
+ raa.argumentlistid, raa.id_accARGUMENT,
+ arg.keyword, arg.value
+ FROM accROLE_accACTION_accARGUMENT raa, accARGUMENT arg
+ WHERE raa.id_accACTION = %s AND
+ (%s) AND
+ raa.id_accARGUMENT = arg.id """ % (id_action, str_args)
- try: res4 = run_sql(query4)
- except ProgrammingError: return 0
+ try:
+ res4 = run_sql(query4)
+ except ProgrammingError:
+ return 0
- if not res4: return 0 # no entries at all
+ if not res4:
+ return 0 # no entries at all
res5 = []
for res in res4:
res5.append(res)
res5.sort()
- if len(defdict) == 1: return 1
+ if len(defdict) == 1:
+ return 1
cur_role = cur_action = cur_arglistid = 0
booldict = {}
- for key in defkeys: booldict[key] = 0
+ for key in defkeys:
+ booldict[key] = 0
# run through the results
- for (role, action, arglistid, arg, keyword, val) in res5 + [(-1, -1, -1, -1, -1, -1)]:
- # not the same role or argumentlist (authorization group), i.e. check if thing are satisfied
- # if cur_arglistid != arglistid or cur_role != role or cur_action != action:
+ for (role, action, arglistid, dummy, keyword, dummy) in res5 + \
+ [(-1, -1, -1, -1, -1, -1)]:
+ # not the same role or argumentlist (authorization group),
+ # i.e. check if thing are satisfied
+ # if cur_arglistid != arglistid or cur_role != role or
+ # cur_action != action:
if (cur_arglistid, cur_role, cur_action) != (arglistid, role, action):
# test if all keywords are satisfied
for value in booldict.values():
- if not value: break
+ if not value:
+ break
else:
return 1 # USER AUTHENTICATED TO PERFORM ACTION
# assign the values for the current tuple from the query
cur_arglistid, cur_role, cur_action = arglistid, role, action
for key in booldict.keys():
booldict[key] = 0
# set keyword qualified for the action, (whatever result of the test)
booldict[keyword] = 1
# matching failed
return 0
-def acc_deleteRole(id_role=0, name_role=0):
- """ delete role entry in table accROLE and all references from other tables.
+def acc_delete_role(id_role=0, name_role=0):
+ """ delete role entry in table accROLE and all references from
+ other tables.
id_role - id of role to be deleted, prefered variable
name_role - this is used if id_role is not given """
count = 0
- id_role = id_role or acc_getRoleId(name_role=name_role)
+ id_role = id_role or acc_get_role_id(name_role=name_role)
# try to delete
if run_sql("""DELETE FROM accROLE WHERE id = %s """ % (id_role, )):
# delete everything related
# authorization entries
- count += 1 + run_sql("""DELETE FROM accROLE_accACTION_accARGUMENT WHERE id_accROLE = %s""" % (id_role, ))
+ count += 1 + run_sql("""DELETE FROM
+ accROLE_accACTION_accARGUMENT WHERE id_accROLE = %s""",
+ (id_role, ))
# connected users
- count += run_sql("""DELETE FROM user_accROLE WHERE id_accROLE = %s """ % (id_role, ))
+ count += run_sql("""DELETE FROM user_accROLE WHERE id_accROLE = %s""",
+ (id_role, ))
# delegated rights over the role
rolenames = run_sql("""SELECT name FROM accROLE""")
# string of rolenames
roles_str = ''
- for (name, ) in rolenames: roles_str += (roles_str and ',' or '') + '"%s"' % (name, )
+ for (name, ) in rolenames:
+ roles_str += (roles_str and ',' or '') + \
+ '"%s"' % (name, )
# arguments with non existing rolenames
- not_valid = run_sql("""SELECT ar.id FROM accARGUMENT ar WHERE keyword = 'role' AND value NOT IN (%s)""" % (roles_str, ))
+ not_valid = run_sql("""SELECT ar.id FROM accARGUMENT ar
+ WHERE keyword = 'role' AND value NOT IN (%s)""" % (roles_str, ))
if not_valid:
nv_str = ''
- for (id, ) in not_valid: nv_str += (nv_str and ',' or '') + '%s' % (id, )
+ for (id_value, ) in not_valid:
+ nv_str += (nv_str and ',' or '') + \
+ '%s' % (id_value, )
# delete entries
count += run_sql("""DELETE FROM accROLE_accACTION_accARGUMENT
- WHERE id_accACTION = %s AND id_accARGUMENT IN (%s) """ % (acc_getActionId(name_action=DELEGATEADDUSERROLE), nv_str))
+ WHERE id_accACTION = %s AND id_accARGUMENT IN (%s) """ %
+ (acc_get_action_id(name_action=DELEGATEADDUSERROLE), nv_str))
# return number of deletes
return count
-def acc_updateRole(id_role=0, name_role='', verbose=0, description='', \
+def acc_update_role(id_role=0, name_role='', dummy=0, description='', \
firerole_def_ser=CFG_ACC_EMPTY_ROLE_DEFINITION_SER, \
firerole_def_src=CFG_ACC_EMPTY_ROLE_DEFINITION_SRC):
"""try to change the description.
id_role - id of the role to change
name_role - use this to find id if not present
verbose - extra output
description - new description
firerole_def_ser - compiled firewall like role definition
firerole_def_src - firewall like role definition
"""
- id_role = id_role or acc_getRoleId(name_role=name_role)
+ id_role = id_role or acc_get_role_id(name_role=name_role)
- if not id_role: return 0
+ if not id_role:
+ return 0
- return run_sql("""UPDATE accROLE SET description = %s, firerole_def_ser = %s, firerole_def_src = %s
- WHERE id = %s""", (description, firerole_def_ser, firerole_def_src, id_role))
+ return run_sql("""UPDATE accROLE SET description = %s,
+ firerole_def_ser = %s, firerole_def_src = %s
+ WHERE id = %s""", (description, firerole_def_ser,
+ firerole_def_src, id_role))
# CONNECTIONS BETWEEN USER AND ROLE
-def acc_addUserRole(id_user=0, id_role=0, email='', name_role='', expiration='9999-12-31 23:59:59'):
+def acc_add_user_role(id_user=0, id_role=0, email='', name_role='',
+ expiration='9999-12-31 23:59:59'):
""" this function adds a new entry to table user_accROLE and returns it
id_user, id_role - self explanatory
email - email of the user
name_role - name of the role, to be used instead of id. """
- id_user = id_user or acc_getUserId(email=email)
- id_role = id_role or acc_getRoleId(name_role=name_role)
+ id_user = id_user or acc_get_user_id(email=email)
+ id_role = id_role or acc_get_role_id(name_role=name_role)
# check if the id_role exists
- if id_role and not acc_getRoleName(id_role=id_role): return 0
+ if id_role and not acc_get_role_name(id_role=id_role):
+ return 0
# check that the user actually exist
- if not acc_getUserEmail(id_user=id_user): return 0
+ if not acc_get_user_email(id_user=id_user):
+ return 0
# control if existing entry
- if run_sql("""SELECT * FROM user_accROLE WHERE id_user = %s AND id_accROLE = %s""" % (id_user, id_role)):
- run_sql("""UPDATE user_accROLE SET expiration=%s WHERE id_user=%s AND id_accROLE=%s AND expiration<%s""", (expiration, id_user, id_role, expiration) )
+ if run_sql("""SELECT * FROM user_accROLE WHERE id_user = %s AND
+ id_accROLE = %s""", (id_user, id_role)):
+ run_sql("""UPDATE user_accROLE SET expiration=%s WHERE id_user=%s AND
+ id_accROLE=%s AND expiration<%s""",
+ (expiration, id_user, id_role, expiration) )
return id_user, id_role, 0
else:
- run_sql("""INSERT INTO user_accROLE (id_user, id_accROLE, expiration) VALUES (%s, %s, %s) """ % (id_user, id_role, expiration))
+ run_sql("""INSERT INTO user_accROLE (id_user, id_accROLE, expiration)
+ VALUES (%s, %s, %s) """, (id_user, id_role, expiration))
return id_user, id_role, 1
-def acc_deleteUserRole(id_user, id_role=0, name_role=0):
+def acc_delete_user_role(id_user, id_role=0, name_role=0):
""" function deletes entry from user_accROLE and reports the success.
id_user - user in database
id_role - role in the database, prefered parameter
name_role - can also delete role on background of role name. """
# need to find id of the role
- id_role = id_role or acc_getRoleId(name_role=name_role)
+ id_role = id_role or acc_get_role_id(name_role=name_role)
# number of deleted entries will be returned (0 or 1)
- return run_sql("""DELETE FROM user_accROLE WHERE id_user = %s AND id_accROLE = %s """ % (id_user, id_role))
+ return run_sql("""DELETE FROM user_accROLE WHERE id_user = %s
+ AND id_accROLE = %s """, (id_user, id_role))
# ARGUMENTS
-def acc_addArgument(keyword='', value=''):
+def acc_add_argument(keyword='', value=''):
""" function to insert an argument into table accARGUMENT.
- if it exists the old id is returned, if it does not the entry is created and the new id is returned.
+ if it exists the old id is returned, if it does not the entry is
+ created and the new id is returned.
keyword - inserted in keyword column
value - inserted in value column. """
# if one of the values are missing, return 0
- if not keyword or not value: return 0
+ if not keyword or not value:
+ return 0
# try to return id of existing argument
- try: return run_sql("""SELECT id from accARGUMENT where keyword = '%s' and value = '%s'""" % (keyword, value))[0][0]
+ try:
+ return run_sql("""SELECT id from accARGUMENT where keyword = %s and
+ value = %s""", (keyword, value))[0][0]
# return id of newly added argument
- except IndexError: return run_sql("""INSERT INTO accARGUMENT (keyword, value) values ('%s', '%s') """ % (keyword, value))
+ except IndexError:
+ return run_sql("""INSERT INTO accARGUMENT
+ (keyword, value) values (%s, %s) """, (keyword, value))
-def acc_deleteArgument(id_argument):
+def acc_delete_argument(id_argument):
""" functions deletes one entry in table accARGUMENT.
the success of the operation is returned.
id_argument - id of the argument to be deleted"""
# return number of deleted entries, 1 or 0
- return run_sql("""DELETE FROM accARGUMENT WHERE id = %s """ % (id_argument, ))
+ return run_sql("""DELETE FROM accARGUMENT WHERE id = %s """,
+ (id_argument, ))
-def acc_deleteArgument_names(keyword='', value=''):
+def acc_delete_argument_names(keyword='', value=''):
"""delete argument according to keyword and value,
send call to another function..."""
# one of the values is missing
- if not keyword or not value: return 0
+ if not keyword or not value:
+ return 0
# find id of the entry
- try: return run_sql("""SELECT id from accARGUMENT where keyword = '%s' and value = '%s'""" % (keyword, value))[0][0]
- except IndexError: return 0
+ try:
+ return run_sql("""SELECT id from accARGUMENT where keyword = %s
+ and value = %s""", (keyword, value))[0][0]
+ except IndexError:
+ return 0
# AUTHORIZATIONS
# ADD WITH names and keyval list
-def acc_addAuthorization(name_role='', name_action='', optional=0, **keyval):
- """ function inserts entries in accROLE_accACTION_accARGUMENT if all references are valid.
+def acc_add_authorization(name_role='', name_action='', optional=0, **keyval):
+ """ function inserts entries in accROLE_accACTION_accARGUMENT if all
+ references are valid.
this function is made specially for the webaccessadmin web interface.
always inserting only one authorization.
id_role, id_action - self explanatory, preferably used
name_role, name_action - self explanatory, used if id not given
optional - if this is set to 1, check that function can have optional
arguments and add with arglistid -1 and id_argument -1
**keyval - dictionary of keyword=value pairs, used to find ids. """
inserted = []
# check that role and action exist
- id_role = run_sql("""SELECT id FROM accROLE where name = '%s'""" % (name_role, ))
- action_details = run_sql("""SELECT * from accACTION where name = '%s' """ % (name_action, ))
- if not id_role or not action_details: return []
+ id_role = run_sql("""SELECT id FROM accROLE where name = %s""",
+ (name_role, ))
+ action_details = run_sql("""SELECT * from accACTION where name = %s """,
+ (name_action, ))
+ if not id_role or not action_details:
+ return []
# get role id and action id and details
id_role, id_action = id_role[0][0], action_details[0][0]
allowedkeywords_str = action_details[0][3]
- allowedkeywords_lst = acc_getActionKeywords(id_action=id_action)
+ allowedkeywords_lst = acc_get_action_keywords(id_action=id_action)
optional_action = action_details[0][4] == 'yes' and 1 or 0
optional = int(optional)
# this action does not take arguments
if not optional and not keyval:
# can not add if user is doing a mistake
- if allowedkeywords_str: return []
+ if allowedkeywords_str:
+ return []
# check if entry exists
if not run_sql("""SELECT * FROM accROLE_accACTION_accARGUMENT
- WHERE id_accROLE = %s AND id_accACTION = %s AND argumentlistid = %s AND id_accARGUMENT = %s"""
- % (id_role, id_action, 0, 0)):
+ WHERE id_accROLE = %s AND id_accACTION = %s AND
+ argumentlistid = %s AND id_accARGUMENT = %s""",
+ (id_role, id_action, 0, 0)):
# insert new authorization
- run_sql("""INSERT INTO accROLE_accACTION_accARGUMENT values (%s, %s, %s, %s)""" % (id_role, id_action, 0, 0))
+ run_sql("""INSERT INTO accROLE_accACTION_accARGUMENT values
+ (%s, %s, %s, %s)""", (id_role, id_action, 0, 0))
return [[id_role, id_action, 0, 0], ]
return []
# try to add authorization without the optional arguments
elif optional:
# optional not allowed for this action
- if not optional_action: return []
+ if not optional_action:
+ return []
# check if authorization already exists
if not run_sql("""SELECT * FROM accROLE_accACTION_accARGUMENT
WHERE id_accROLE = %s AND
id_accACTION = %s AND
id_accARGUMENT = -1 AND
argumentlistid = -1""" % (id_role, id_action, )):
# insert new authorization
- run_sql("""INSERT INTO accROLE_accACTION_accARGUMENT (id_accROLE, id_accACTION, id_accARGUMENT, argumentlistid) VALUES (%s, %s, -1, -1) """ % (id_role, id_action))
+ run_sql("""INSERT INTO accROLE_accACTION_accARGUMENT (id_accROLE,
+ id_accACTION, id_accARGUMENT, argumentlistid)
+ VALUES (%s, %s, -1, -1) """, (id_role, id_action))
return [[id_role, id_action, -1, -1], ]
return []
else:
# regular authorization
# get list of ids, if they don't exist, create arguments
id_arguments = []
argstr = ''
for key in keyval.keys():
- if key not in allowedkeywords_lst: return []
- id_argument = (acc_getArgumentId(key, keyval[key])
- or
- run_sql("""INSERT INTO accARGUMENT (keyword, value) values ('%s', '%s') """ % (key, keyval[key])))
+ if key not in allowedkeywords_lst:
+ return []
+ id_argument = (acc_get_argument_id(key, keyval[key])
+ or
+ run_sql("""INSERT INTO accARGUMENT (keyword, value) values
+ (%s, %s) """, (key, keyval[key])))
id_arguments.append(id_argument)
argstr += (argstr and ',' or '') + str(id_argument)
# check if equal authorization exists
- for (id_trav, ) in run_sql("""SELECT DISTINCT argumentlistid FROM accROLE_accACTION_accARGUMENT WHERE id_accROLE = '%s' AND id_accACTION = '%s' """% (id_role, id_action)):
- listlength = run_sql("""SELECT COUNT(*) FROM accROLE_accACTION_accARGUMENT
- WHERE id_accROLE = '%s' AND id_accACTION = '%s' AND argumentlistid = '%s' AND
- id_accARGUMENT IN (%s) """ % (id_role, id_action, id_trav, argstr))[0][0]
- notlist = run_sql("""SELECT COUNT(*) FROM accROLE_accACTION_accARGUMENT
- WHERE id_accROLE = '%s' AND id_accACTION = '%s' AND argumentlistid = '%s' AND
- id_accARGUMENT NOT IN (%s) """ % (id_role, id_action, id_trav, argstr))[0][0]
+ for (id_trav, ) in run_sql("""SELECT DISTINCT argumentlistid FROM
+ accROLE_accACTION_accARGUMENT WHERE id_accROLE = %s AND
+ id_accACTION = %s """, (id_role, id_action)):
+ listlength = run_sql("""SELECT COUNT(*) FROM
+ accROLE_accACTION_accARGUMENT WHERE id_accROLE = %%s AND
+ id_accACTION = %%s AND argumentlistid = %%s AND
+ id_accARGUMENT IN (%s) """ % (argstr),
+ (id_role, id_action, id_trav))[0][0]
+ notlist = run_sql("""SELECT COUNT(*) FROM
+ accROLE_accACTION_accARGUMENT WHERE id_accROLE = %%s AND
+ id_accACTION = %%s AND argumentlistid = %%s AND
+ id_accARGUMENT NOT IN (%s) """ % (argstr),
+ (id_role, id_action, id_trav))[0][0]
# this means that a duplicate already exists
- if not notlist and listlength == len(id_arguments): return []
+ if not notlist and listlength == len(id_arguments):
+ return []
# find new arglistid, highest + 1
- try: arglistid = 1 + run_sql("""SELECT MAX(argumentlistid) FROM accROLE_accACTION_accARGUMENT WHERE id_accROLE = %s AND id_accACTION = %s """
- % (id_role, id_action))[0][0]
- except (IndexError, TypeError): arglistid = 1
- if arglistid <= 0: arglistid = 1
+ try:
+ arglistid = 1 + run_sql("""SELECT MAX(argumentlistid) FROM
+ accROLE_accACTION_accARGUMENT WHERE id_accROLE = %s
+ AND id_accACTION = %s""", (id_role, id_action))[0][0]
+ except (IndexError, TypeError):
+ arglistid = 1
+ if arglistid <= 0:
+ arglistid = 1
# insert
for id_argument in id_arguments:
- run_sql("""INSERT INTO accROLE_accACTION_accARGUMENT values (%s, %s, %s, %s) """
- % (id_role, id_action, id_argument, arglistid))
+ run_sql("""INSERT INTO accROLE_accACTION_accARGUMENT values
+ (%s, %s, %s, %s) """,
+ (id_role, id_action, id_argument, arglistid))
inserted.append([id_role, id_action, id_argument, arglistid])
return inserted
-def acc_addRoleActionArguments(id_role=0, id_action=0, arglistid=-1, optional=0, verbose=0, id_arguments=[]):
- """ function inserts entries in accROLE_accACTION_accARGUMENT if all references are valid.
+def acc_add_role_action_arguments(id_role=0, id_action=0, arglistid=-1,
+ optional=0, verbose=0, id_arguments=[]):
+ """ function inserts entries in accROLE_accACTION_accARGUMENT if all
+ references are valid.
id_role, id_action - self explanatory
arglistid - argumentlistid for the inserted entries
if -1: create new group
other values: add to this group, if it exists or not
optional - if this is set to 1, check that function can have
optional arguments and add with arglistid -1 and
id_argument -1
verbose - extra output
id_arguments - list of arguments to add to group."""
inserted = []
- if verbose: print 'ids: starting'
- if verbose: print 'ids: checking ids'
+ if verbose:
+ print 'ids: starting'
+ if verbose:
+ print 'ids: checking ids'
# check that all the ids are valid and reference something...
- if not run_sql("""SELECT * FROM accROLE WHERE id = %s""" % (id_role, )):
+ if not run_sql("""SELECT * FROM accROLE WHERE id = %s""", (id_role, )):
return 0
- if verbose: print 'ids: get allowed keywords'
+ if verbose:
+ print 'ids: get allowed keywords'
# check action exist and get allowed keywords
try:
- allowedkeys = acc_getActionKeywords(id_action=id_action)
- # allowedkeys = run_sql("""SELECT * FROM accACTION WHERE id = %s""" % (id_action, ))[0][3].split(',')
+ allowedkeys = acc_get_action_keywords(id_action=id_action)
+ # allowedkeys = run_sql("""SELECT * FROM accACTION WHERE id = %s""" %
+ # (id_action, ))[0][3].split(',')
except (IndexError, AttributeError):
return 0
- if verbose: print 'ids: is it optional'
+ if verbose:
+ print 'ids: is it optional'
# action with optional arguments
if optional:
- if verbose: print 'ids: yes - optional'
- if not acc_getActionIsOptional(id_action=id_action):
+ if verbose:
+ print 'ids: yes - optional'
+ if not acc_get_action_is_optional(id_action=id_action):
return []
- if verbose: print 'ids: run query to check if exists'
+ if verbose:
+ print 'ids: run query to check if exists'
if not run_sql("""SELECT * FROM accROLE_accACTION_accARGUMENT
- WHERE id_accROLE = %s AND
- id_accACTION = %s AND
- id_accARGUMENT = -1 AND
- argumentlistid = -1""" %
- (id_role, id_action, )):
- if verbose: print 'ids: does not exist'
- run_sql("""INSERT INTO accROLE_accACTION_accARGUMENT (id_accROLE, id_accACTION, id_accARGUMENT, argumentlistid) VALUES (%s, %s, -1, -1) """
- % (id_role, id_action))
+ WHERE id_accROLE = %s AND
+ id_accACTION = %s AND
+ id_accARGUMENT = -1 AND
+ argumentlistid = -1""", (id_role, id_action, )):
+ if verbose:
+ print 'ids: does not exist'
+ run_sql("""INSERT INTO accROLE_accACTION_accARGUMENT
+ (id_accROLE, id_accACTION, id_accARGUMENT, argumentlistid)
+ VALUES (%s, %s, -1, -1) """, (id_role, id_action))
return ((id_role, id_action, -1, -1), )
- if verbose: print 'ids: exists'
+ if verbose:
+ print 'ids: exists'
return []
- if verbose: print 'ids: check if not arguments'
+ if verbose:
+ print 'ids: check if not arguments'
# action without arguments
if not allowedkeys:
- if verbose: print 'ids: not arguments'
+ if verbose:
+ print 'ids: not arguments'
if not run_sql("""SELECT * FROM accROLE_accACTION_accARGUMENT
- WHERE id_accROLE = %s AND id_accACTION = %s AND argumentlistid = %s AND id_accARGUMENT = %s"""
- % (id_role, id_action, 0, 0)):
- if verbose: print 'ids: try to insert'
- result = run_sql("""INSERT INTO accROLE_accACTION_accARGUMENT values (%s, %s, %s, %s)""" % (id_role, id_action, 0, 0))
+ WHERE id_accROLE = %s AND id_accACTION = %s AND
+ argumentlistid = %s AND id_accARGUMENT = %s""",
+ (id_role, id_action, 0, 0)):
+ if verbose:
+ print 'ids: try to insert'
+ run_sql("""INSERT INTO accROLE_accACTION_accARGUMENT
+ values (%s, %s, %s, %s)""", (id_role, id_action, 0, 0))
return ((id_role, id_action, 0, 0), )
else:
- if verbose: print 'ids: already existed'
+ if verbose:
+ print 'ids: already existed'
return 0
else:
- if verbose: print 'ids: arguments exist'
+ if verbose:
+ print 'ids: arguments exist'
argstr = ''
# check that the argument exists, and that it is a valid key
- if verbose: print 'ids: checking all the arguments'
+ if verbose:
+ print 'ids: checking all the arguments'
for id_argument in id_arguments:
- res_arg = run_sql("""SELECT * FROM accARGUMENT WHERE id = %s""" % (id_argument, ))
+ res_arg = run_sql("""SELECT * FROM accARGUMENT WHERE id = %s""",
+ (id_argument, ))
if not res_arg or res_arg[0][1] not in allowedkeys:
return 0
else:
- if argstr: argstr += ','
+ if argstr:
+ argstr += ','
argstr += '%s' % (id_argument, )
# arglistid = -1 means that the user wants a new group
- if verbose: print 'ids: find arglistid'
+ if verbose:
+ print 'ids: find arglistid'
if arglistid < 0:
# check if such single group already exists
- for (id_trav, ) in run_sql("""SELECT DISTINCT argumentlistid FROM accROLE_accACTION_accARGUMENT WHERE id_accROLE = '%s' AND id_accACTION = '%s' """
- % (id_role, id_action)):
- listlength = run_sql("""SELECT COUNT(*) FROM accROLE_accACTION_accARGUMENT
- WHERE id_accROLE = '%s' AND id_accACTION = '%s' AND argumentlistid = '%s' AND
- id_accARGUMENT IN (%s) """ % (id_role, id_action, id_trav, argstr))[0][0]
- notlist = run_sql("""SELECT COUNT(*) FROM accROLE_accACTION_accARGUMENT
- WHERE id_accROLE = '%s' AND id_accACTION = '%s' AND argumentlistid = '%s' AND
- id_accARGUMENT NOT IN (%s) """ % (id_role, id_action, id_trav, argstr))[0][0]
+ for (id_trav, ) in run_sql("""SELECT DISTINCT argumentlistid FROM
+ accROLE_accACTION_accARGUMENT WHERE id_accROLE = %s AND
+ id_accACTION = %s""", (id_role, id_action)):
+ listlength = run_sql("""SELECT COUNT(*) FROM
+ accROLE_accACTION_accARGUMENT WHERE id_accROLE = %%s AND
+ id_accACTION = %%s AND argumentlistid = %%s AND
+ id_accARGUMENT IN (%s)""" % (argstr),
+ (id_role, id_action, id_trav))[0][0]
+ notlist = run_sql("""SELECT COUNT(*) FROM
+ accROLE_accACTION_accARGUMENT WHERE id_accROLE = %%s AND
+ id_accACTION = %%s AND argumentlistid = %%s AND
+ id_accARGUMENT NOT IN (%s)""" % (argstr),
+ (id_role, id_action, id_trav))[0][0]
# this means that a duplicate already exists
- if not notlist and listlength == len(id_arguments): return 0
+ if not notlist and listlength == len(id_arguments):
+ return 0
# find new arglistid
try:
- arglistid = run_sql("""SELECT MAX(argumentlistid) FROM accROLE_accACTION_accARGUMENT WHERE id_accROLE = %s AND id_accACTION = %s """ %
- (id_role, id_action))[0][0] + 1
- except ProgrammingError: return 0
- except (IndexError, TypeError): arglistid = 1
+ arglistid = run_sql("""SELECT MAX(argumentlistid) FROM
+ accROLE_accACTION_accARGUMENT WHERE id_accROLE = %s AND
+ id_accACTION = %s""", (id_role, id_action))[0][0] + 1
+ except ProgrammingError:
+ return 0
+ except (IndexError, TypeError):
+ arglistid = 1
- if arglistid <= 0: arglistid = 1
+ if arglistid <= 0:
+ arglistid = 1
- if verbose: print 'ids: insert all the entries'
+ if verbose:
+ print 'ids: insert all the entries'
# all references are valid, insert: one entry in raa for each argument
for id_argument in id_arguments:
- if not run_sql("""SELECT * FROM accROLE_accACTION_accARGUMENT WHERE id_accROLE = %s AND id_accACTION = %s AND id_accARGUMENT = %s AND argumentlistid = %s""" %
- (id_role, id_action, id_argument, arglistid)):
- run_sql("""INSERT INTO accROLE_accACTION_accARGUMENT (id_accROLE, id_accACTION, id_accARGUMENT, argumentlistid) VALUES (%s, %s, %s, %s) """
- % (id_role, id_action, id_argument, arglistid))
+ if not run_sql("""SELECT * FROM accROLE_accACTION_accARGUMENT
+ WHERE id_accROLE = %s AND id_accACTION = %s AND
+ id_accARGUMENT = %s AND argumentlistid = %s""",
+ (id_role, id_action, id_argument, arglistid)):
+ run_sql("""INSERT INTO accROLE_accACTION_accARGUMENT
+ (id_accROLE, id_accACTION, id_accARGUMENT, argumentlistid)
+ VALUES (%s, %s, %s, %s)""",
+ (id_role, id_action, id_argument, arglistid))
inserted.append((id_role, id_action, id_argument, arglistid))
# [(r, ac, ar1, aid), (r, ac, ar2, aid)]
if verbose:
print 'ids: inside add function'
- for r in acc_findPossibleActions(id_role=id_role, id_action=id_action):
+ for r in acc_find_possible_actions(id_role=id_role,
+ id_action=id_action):
print 'ids: ', r
return inserted
-def acc_addRoleActionArguments_names(name_role='', name_action='', arglistid=-1, optional=0, verbose=0, **keyval):
- """ this function makes it possible to pass names when creating new entries instead of ids.
+def acc_add_role_action_arguments_names(name_role='', name_action='',
+ arglistid=-1, optional=0, verbose=0, **keyval):
+ """ this function makes it possible to pass names when creating new entries
+ instead of ids.
get ids for all the names,
create entries in accARGUMENT that does not exist,
pass on to id based function.
name_role, name_action - self explanatory
- arglistid - add entries to or create group with arglistid, default -1 create new.
+ arglistid - add entries to or create group with arglistid, default -1
+ create new.
- optional - create entry with optional keywords, **keyval is ignored, but should be empty
+ optional - create entry with optional keywords, **keyval is ignored, but
+ should be empty
verbose - used to print extra information
**keyval - dictionary of keyword=value pairs, used to find ids. """
- if verbose: print 'names: starting'
- if verbose: print 'names: checking ids'
+ if verbose:
+ print 'names: starting'
+ if verbose:
+ print 'names: checking ids'
# find id of the role, return 0 if it doesn't exist
- id_role = run_sql("""SELECT id FROM accROLE where name = '%s'""" % (name_role, ))
- if id_role: id_role = id_role[0][0]
- else: return 0
+ id_role = run_sql("""SELECT id FROM accROLE where name = %s""",
+ (name_role, ))
+ if id_role:
+ id_role = id_role[0][0]
+ else:
+ return 0
# find id of the action, return 0 if it doesn't exist
- res = run_sql("""SELECT * from accACTION where name = '%s'""" % (name_action, ))
- if res: id_action = res[0][0]
- else: return 0
+ res = run_sql("""SELECT * from accACTION where name = %s""",
+ (name_action, ))
+ if res:
+ id_action = res[0][0]
+ else:
+ return 0
- if verbose: print 'names: checking arguments'
+ if verbose:
+ print 'names: checking arguments'
id_arguments = []
if not optional:
- if verbose: print 'names: not optional'
+ if verbose:
+ print 'names: not optional'
# place to keep ids of arguments and list of allowed keywords
- allowedkeys = acc_getActionKeywords(id_action=id_action) # res[0][3].split(',')
+ allowedkeys = acc_get_action_keywords(id_action=id_action)
+ # res[0][3].split(',')
# find all the id_arguments and create those that does not exist
for key in keyval.keys():
# this key does not exist
if key not in allowedkeys:
return 0
- id_argument = acc_getArgumentId(key, keyval[key])
- id_argument = id_argument or run_sql("""INSERT INTO accARGUMENT (keyword, value) values ('%s', '%s') """ % (key, keyval[key]))
+ id_argument = acc_get_argument_id(key, keyval[key])
+ id_argument = id_argument or run_sql("""INSERT INTO accARGUMENT
+ (keyword, value) values (%s, %s) """, (key, keyval[key]))
id_arguments.append(id_argument) # append the id to the list
else:
- if verbose: print 'names: optional'
+ if verbose:
+ print 'names: optional'
# use the other function
- return acc_addRoleActionArguments(id_role=id_role,
+ return acc_add_role_action_arguments(id_role=id_role,
id_action=id_action,
arglistid=arglistid,
optional=optional,
verbose=verbose,
id_arguments=id_arguments)
# DELETE WITH ID OR NAMES
-def acc_deleteRoleActionArguments(id_role, id_action, arglistid=1, auths=[[]]):
- """delete all entries in accROLE_accACTION_accARGUMENT that satisfy the parameters.
+def acc_delete_role_action_arguments(id_role, id_action, arglistid=1,
+ auths=[[]]):
+ """delete all entries in accROLE_accACTION_accARGUMENT that satisfy the
+ parameters.
return number of actual deletes.
- this function relies on the id-lists in auths to have the same order has the possible actions...
+ this function relies on the id-lists in auths to have the same order has
+ the possible actions...
id_role, id_action - self explanatory
arglistid - group to delete from.
if more entries than deletes, split the group before delete.
id_arguments - list of ids to delete."""
keepauths = [] # these will be kept
# find all possible actions
- pas = acc_findPossibleActions_ids(id_role, id_action)
- header = pas[0]
+ pas = acc_find_possible_actions_ids(id_role, id_action)
+ dummy = pas[0]
# decide which to keep or throw away
for pa in pas[1:]:
if pa[0] == arglistid and pa[1:] not in auths:
keepauths.append(pa[1:])
# delete everything
run_sql("""DELETE FROM accROLE_accACTION_accARGUMENT
- WHERE id_accROLE = %s AND
- id_accACTION = %s AND
- argumentlistid = %s """
- % (id_role, id_action, arglistid))
+ WHERE id_accROLE = %s AND
+ id_accACTION = %s AND
+ argumentlistid = %s""", (id_role, id_action, arglistid))
# insert those to be kept
for auth in keepauths:
- acc_addRoleActionArguments(id_role=id_role,
+ acc_add_role_action_arguments(id_role=id_role,
id_action=id_action,
arglistid=-1,
id_arguments=auth)
return 1
-def acc_deleteRoleActionArguments_names(name_role='', name_action='', arglistid=1, **keyval):
- """utilize the function on ids by first finding all ids and redirecting the function call.
+def acc_delete_role_action_arguments_names(name_role='', name_action='',
+ arglistid=1, **keyval):
+ """utilize the function on ids by first finding all ids and redirecting the
+ function call.
break of and return 0 if any of the ids can't be found.
name_role = name of the role
name_action - name of the action
- arglistid - the argumentlistid, all keyword=value pairs must be in this same group.
+ arglistid - the argumentlistid, all keyword=value pairs must be in this
+ same group.
**keyval - dictionary of keyword=value pairs for the arguments."""
# find ids for role and action
- id_role = acc_getRoleId(name_role=name_role)
- id_action = acc_getActionId(name_action=name_action)
+ id_role = acc_get_role_id(name_role=name_role)
+ id_action = acc_get_action_id(name_action=name_action)
# create string with the ids
idstr = ''
idlist = []
for key in keyval.keys():
- id = acc_getArgumentId(key, keyval[key])
- if not id: return 0
+ argument_id = acc_get_argument_id(key, keyval[key])
+ if not argument_id:
+ return 0
- if idstr: idstr += ','
- idstr += '%s' % id
- idlist.append(id)
+ if idstr:
+ idstr += ','
+ idstr += '%s' % argument_id
+ idlist.append(argument_id)
# control that a fitting group exists
- try: count = run_sql("""SELECT COUNT(*) FROM accROLE_accACTION_accARGUMENT
- WHERE id_accROLE = %s AND
- id_accACTION = %s AND
- argumentlistid = %s AND
- id_accARGUMENT IN (%s)""" % (id_role, id_action, arglistid, idstr))[0][0]
- except IndexError: return 0
+ try:
+ count = run_sql("""SELECT COUNT(*) FROM accROLE_accACTION_accARGUMENT
+ WHERE id_accROLE = %%s AND
+ id_accACTION = %%s AND
+ argumentlistid = %%s AND
+ id_accARGUMENT IN (%s)""" % (idstr),
+ (id_role, id_action, arglistid))[0][0]
+ except IndexError:
+ return 0
- if count < len(keyval): return 0
+ if count < len(keyval):
+ return 0
# call id based function
- return acc_deleteRoleActionArguments(id_role, id_action, arglistid, [idlist])
+ return acc_delete_role_action_arguments(id_role, id_action, arglistid,
+ [idlist])
-def acc_deleteRoleActionArguments_group(id_role=0, id_action=0, arglistid=0):
- """delete entire group of arguments for connection between role and action."""
+def acc_delete_role_action_arguments_group(id_role=0, id_action=0, arglistid=0):
+ """delete entire group of arguments for connection between
+ role and action."""
- if not id_role or not id_action: return []
+ if not id_role or not id_action:
+ return []
return run_sql("""DELETE FROM accROLE_accACTION_accARGUMENT
WHERE id_accROLE = %s AND
id_accACTION = %s AND
- argumentlistid = %s """ % (id_role, id_action, arglistid))
+ argumentlistid = %s """, (id_role, id_action, arglistid))
-def acc_deletePossibleActions(id_role=0, id_action=0, authids=[]):
- """delete authorizations in selected rows. utilization of the delete function.
+def acc_delete_possible_actions(id_role=0, id_action=0, authids=[]):
+ """delete authorizations in selected rows. utilization of the
+ delete function.
id_role - id of role to be connected to action.
id_action - id of action to be connected to role
authids - list of row indexes to be removed. """
# find all authorizations
- pas = acc_findPossibleActions(id_role=id_role, id_action=id_action)
+ pas = acc_find_possible_actions(id_role=id_role, id_action=id_action)
# get the keys
keys = pas[0][1:]
# create dictionary for all the argumentlistids
ald = {}
for authid in authids:
- if authid > len(pas): return authid, len(pas)
+ if authid > len(pas):
+ return authid, len(pas)
# get info from possible action
- id = pas[authid][0]
+ pas_auth_id = pas[authid][0]
values = pas[authid][1:]
# create list of authids for each authorization
- auth = [acc_getArgumentId(keys[0], values[0])]
+ auth = [acc_get_argument_id(keys[0], values[0])]
for i in range(1, len(keys)):
- auth.append(acc_getArgumentId(keys[i], values[i]))
+ auth.append(acc_get_argument_id(keys[i], values[i]))
# create entries in the dictionary for each argumentlistid
- try: ald[id].append(auth)
- except KeyError: ald[id] = [auth]
+ try:
+ ald[pas_auth_id].append(auth)
+ except KeyError:
+ ald[pas_auth_id] = [auth]
# do the deletes
result = 1
for key in ald.keys():
- result = 1 and acc_deleteRoleActionArguments(id_role=id_role,
+ result = 1 and acc_delete_role_action_arguments(id_role=id_role,
id_action=id_action,
arglistid=key,
auths=ald[key])
return result
-def acc_deleteRoleAction(id_role=0, id_action=0):
+def acc_delete_role_action(id_role=0, id_action=0):
"""delete all connections between a role and an action. """
count = run_sql("""DELETE FROM accROLE_accACTION_accARGUMENT
- WHERE id_accROLE = '%s' AND id_accACTION = '%s' """ % (id_role, id_action))
+ WHERE id_accROLE = %s AND id_accACTION = %s """, (id_role, id_action))
return count
# GET FUNCTIONS
# ACTION RELATED
-def acc_getActionId(name_action):
+def acc_get_action_id(name_action):
"""get id of action when name is given
name_action - name of the wanted action"""
- try: return run_sql("""SELECT id FROM accACTION WHERE name = '%s'""" % (name_action, ))[0][0]
- except IndexError: return 0
+ try:
+ return run_sql("""SELECT id FROM accACTION WHERE name = %s""",
+ (name_action, ))[0][0]
+ except IndexError:
+ return 0
-def acc_getActionName(id_action):
+def acc_get_action_name(id_action):
"""get name of action when id is given. """
try:
- return run_sql("""SELECT name FROM accACTION WHERE id = %s""" % (id_action, ))[0][0]
+ return run_sql("""SELECT name FROM accACTION WHERE id = %s""",
+ (id_action, ))[0][0]
except (ProgrammingError, IndexError):
return ''
-def acc_getActionDescription(id_action):
+def acc_get_action_description(id_action):
"""get description of action when id is given. """
try:
- return run_sql("""SELECT description FROM accACTION WHERE id = %s""" % (id_action, ))[0][0]
+ return run_sql("""SELECT description FROM accACTION WHERE id = %s""",
+ (id_action, ))[0][0]
except (ProgrammingError, IndexError):
return ''
-def acc_getActionKeywords(id_action=0, name_action=''):
+def acc_get_action_keywords(id_action=0, name_action=''):
"""get list of keywords for action when id is given.
empty list if no keywords."""
- result = acc_getActionKeywordsString(id_action=id_action, name_action=name_action)
+ result = acc_get_action_keywords_string(id_action=id_action,
+ name_action=name_action)
- if result: return result.split(',')
- else: return []
+ if result:
+ return result.split(',')
+ else:
+ return []
-def acc_getActionKeywordsString(id_action=0, name_action=''):
+def acc_get_action_keywords_string(id_action=0, name_action=''):
"""get keywordstring when id is given. """
- id_action = id_action or acc_getActionId(name_action)
- try: result = run_sql("""SELECT allowedkeywords from accACTION where id = %s """ % (id_action, ))[0][0]
- except IndexError: return ''
+ id_action = id_action or acc_get_action_id(name_action)
+ try:
+ result = run_sql("""SELECT allowedkeywords from accACTION
+ where id = %s """, (id_action, ))[0][0]
+ except IndexError:
+ return ''
return result
-def acc_getActionIsOptional(id_action=0):
+def acc_get_action_is_optional(id_action=0):
"""get if the action arguments are optional or not.
return 1 if yes, 0 if no."""
- result = acc_getActionOptional(id_action=id_action)
+ result = acc_get_action_optional(id_action=id_action)
return result == 'yes' and 1 or 0
-def acc_getActionOptional(id_action=0):
+def acc_get_action_optional(id_action=0):
"""get if the action arguments are optional or not.
return result, but 0 if action does not exist. """
- try: result = run_sql("""SELECT optional from accACTION where id = %s """ % (id_action, ))[0][0]
- except IndexError: return 0
+ try:
+ result = run_sql("""SELECT optional from accACTION where id = %s""",
+ (id_action, ))[0][0]
+ except IndexError:
+ return 0
return result
-def acc_getActionDetails(id_action=0):
+def acc_get_action_details(id_action=0):
"""get all the fields for an action."""
details = []
- try: result = run_sql("""SELECT * FROM accACTION WHERE id = %s """ % (id_action, ))[0]
- except IndexError: return details
+ try:
+ result = run_sql("""SELECT * FROM accACTION WHERE id = %s""",
+ (id_action, ))[0]
+ except IndexError:
+ return details
if result:
- for r in result: details.append(r)
+ for r in result:
+ details.append(r)
return details
-def acc_getAllActions():
+def acc_get_all_actions():
"""returns all entries in accACTION."""
- return run_sql("""SELECT a.id, a.name, a.description FROM accACTION a ORDER BY a.name""")
+ return run_sql("""SELECT a.id, a.name, a.description
+ FROM accACTION a ORDER BY a.name""")
-def acc_getActionRoles(id_action):
+def acc_get_action_roles(id_action):
+ """Returns all the roles connected with an action."""
return run_sql("""SELECT DISTINCT(r.id), r.name, r.description
- FROM accROLE_accACTION_accARGUMENT raa LEFT JOIN accROLE r
- ON raa.id_accROLE = r.id
- WHERE raa.id_accACTION = %s
- ORDER BY r.name """ % (id_action, ))
+ FROM accROLE_accACTION_accARGUMENT raa LEFT JOIN accROLE r
+ ON raa.id_accROLE = r.id
+ WHERE raa.id_accACTION = %s
+ ORDER BY r.name """, (id_action, ))
# ROLE RELATED
-def acc_getRoleId(name_role):
+def acc_get_role_id(name_role):
"""get id of role, name given. """
- try: return run_sql("""SELECT id FROM accROLE WHERE name = %s""", (name_role, ))[0][0]
- except IndexError: return 0
+ try:
+ return run_sql("""SELECT id FROM accROLE WHERE name = %s""",
+ (name_role, ))[0][0]
+ except IndexError:
+ return 0
-def acc_getRoleName(id_role):
+def acc_get_role_name(id_role):
"""get name of role, id given. """
- try: return run_sql("""SELECT name FROM accROLE WHERE id = %s""", (id_role, ))[0][0]
- except IndexError: return ''
+ try:
+ return run_sql("""SELECT name FROM accROLE WHERE id = %s""",
+ (id_role, ))[0][0]
+ except IndexError:
+ return ''
-def acc_getRoleDefinition(id_role=0):
+def acc_get_role_definition(id_role=0):
"""get firewall like role definition object for a role."""
- try: return run_sql("""SELECT firerole_def_ser FROM accROLE WHERE id = %s""", (id_role, ))[0][0]
- except IndexError: return ''
+ try:
+ return run_sql("""SELECT firerole_def_ser FROM accROLE
+ WHERE id = %s""", (id_role, ))[0][0]
+ except IndexError:
+ return ''
-def acc_getRoleDetails(id_role=0):
+def acc_get_role_details(id_role=0):
"""get all the fields for an action."""
details = []
- try: result = run_sql("""SELECT id, name, description, firerole_def_src FROM accROLE WHERE id = %s """, (id_role, ))[0]
- except IndexError: return details
+ try:
+ result = run_sql("""SELECT id, name, description, firerole_def_src
+ FROM accROLE WHERE id = %s """, (id_role, ))[0]
+ except IndexError:
+ return details
if result:
- for r in result: details.append(r)
+ for r in result:
+ details.append(r)
return details
-def acc_getAllRoles():
+def acc_get_all_roles():
"""get all entries in accROLE."""
- return run_sql("""SELECT r.id, r.name, r.description, r.firerole_def_ser, r.firerole_def_src FROM accROLE r ORDER BY r.name""")
+ return run_sql("""SELECT r.id, r.name, r.description,
+ r.firerole_def_ser, r.firerole_def_src
+ FROM accROLE r ORDER BY r.name""")
-def acc_getRoleActions(id_role):
+def acc_get_role_actions(id_role):
"""get all actions connected to a role. """
return run_sql("""SELECT DISTINCT(a.id), a.name, a.description
- FROM accROLE_accACTION_accARGUMENT raa, accACTION a
- WHERE raa.id_accROLE = %s and
- raa.id_accACTION = a.id
- ORDER BY a.name """, (id_role, ))
+ FROM accROLE_accACTION_accARGUMENT raa, accACTION a
+ WHERE raa.id_accROLE = %s and
+ raa.id_accACTION = a.id
+ ORDER BY a.name """, (id_role, ))
-def acc_getRoleUsers(id_role):
+def acc_get_role_users(id_role):
"""get all users that have access to a role. """
return run_sql("""SELECT DISTINCT(u.id), u.email, u.settings
- FROM user_accROLE ur, user u
- WHERE ur.id_accROLE = %s AND
- ur.expiration >= NOW() AND
- u.id = ur.id_user
- ORDER BY u.email""", (id_role, ))
+ FROM user_accROLE ur, user u
+ WHERE ur.id_accROLE = %s AND
+ ur.expiration >= NOW() AND
+ u.id = ur.id_user
+ ORDER BY u.email""", (id_role, ))
# ARGUMENT RELATED
-def acc_getArgumentId(keyword, value):
+def acc_get_argument_id(keyword, value):
"""get id of argument, keyword=value pair given.
value = 'optional value' is replaced for id_accARGUMENT = -1."""
- try: return run_sql("""SELECT DISTINCT id FROM accARGUMENT WHERE keyword = %s and value = %s""", (keyword, value))[0][0]
+ try:
+ return run_sql("""SELECT DISTINCT id FROM accARGUMENT
+ WHERE keyword = %s and value = %s""", (keyword, value))[0][0]
except IndexError:
- if value == 'optional value': return -1
+ if value == 'optional value':
+ return -1
return 0
# USER RELATED
-def acc_getUserEmail(id_user=0):
+def acc_get_user_email(id_user=0):
"""get email of user, id given."""
- try: return run_sql("""SELECT email FROM user WHERE id = %s """, (id_user, ))[0][0]
- except IndexError: return ''
+ try:
+ return run_sql("""SELECT email FROM user WHERE id = %s """,
+ (id_user, ))[0][0]
+ except IndexError:
+ return ''
-def acc_getUserId(email=''):
+def acc_get_user_id(email=''):
"""get id of user, email given."""
- try: return run_sql("""SELECT id FROM user WHERE email = %s """, (email, ))[0][0]
- except IndexError: return 0
+ try:
+ return run_sql("""SELECT id FROM user WHERE email = %s """,
+ (email, ))[0][0]
+ except IndexError:
+ return 0
-def acc_getUserRoles(id_user=0):
+def acc_get_user_roles(id_user=0):
"""get all roles a user is connected to."""
res = run_sql("""SELECT ur.id_accROLE
- FROM user_accROLE ur
- WHERE ur.id_user = %s AND ur.expiration >= NOW()
- ORDER BY ur.id_accROLE""", (id_user, ))
+ FROM user_accROLE ur
+ WHERE ur.id_user = %s AND ur.expiration >= NOW()
+ ORDER BY ur.id_accROLE""", (id_user, ))
return res
-def acc_findUserInfoIds(id_user=0):
- """find all authorization entries for all the roles a user is connected to."""
+def acc_find_user_info_ids(id_user=0):
+ """find all authorization entries for all the roles a user
+ is connected to."""
res1 = run_sql("""SELECT ur.id_user, raa.*
- FROM user_accROLE ur LEFT JOIN accROLE_accACTION_accARGUMENT raa
- ON ur.id_accROLE = raa.id_accROLE
- WHERE ur.id_user = %s AND ur.expiration >= NOW()""", (id_user, ))
+ FROM user_accROLE ur LEFT JOIN accROLE_accACTION_accARGUMENT raa
+ ON ur.id_accROLE = raa.id_accROLE
+ WHERE ur.id_user = %s AND ur.expiration >= NOW()""", (id_user, ))
res2 = []
- for res in res1: res2.append(res)
+ for res in res1:
+ res2.append(res)
res2.sort()
return res2
-def acc_findUserInfoNames(id_user=0):
- query = """ SELECT ur.id_user, r.name, ac.name, raa.argumentlistid, ar.keyword, ar.value
- FROM accROLE_accACTION_accARGUMENT raa, user_accROLE ur, accROLE r, accACTION ac, accARGUMENT ar
- WHERE ur.id_user = %s and ur.expiration >= NOW() and
- ur.id_accROLE = raa.id_accROLE and
- raa.id_accROLE = r.id and
- raa.id_accACTION = ac.id and
- raa.id_accARGUMENT = ar.id """ % (id_user, )
+def acc_find_user_info_names(id_user=0):
+ """Find all the info about a user #FIXME"""
+ query = """ SELECT ur.id_user, r.name, ac.name, raa.argumentlistid,
+ ar.keyword, ar.value FROM accROLE_accACTION_accARGUMENT raa,
+ user_accROLE ur, accROLE r, accACTION ac, accARGUMENT ar
+ WHERE ur.id_user = %s and ur.expiration >= NOW() and
+ ur.id_accROLE = raa.id_accROLE and
+ raa.id_accROLE = r.id and
+ raa.id_accACTION = ac.id and
+ raa.id_accARGUMENT = ar.id """, (id_user, )
res1 = run_sql(query)
res2 = []
- for res in res1: res2.append(res)
+ for res in res1:
+ res2.append(res)
res2.sort()
return res2
-def acc_findUserRoleActions(user_info):
- """find name of all roles and actions connected to user_info (or uid), id given."""
+def acc_find_user_role_actions(user_info):
+ """find name of all roles and actions connected to user_info (or uid), id
+ given."""
if type(user_info) in [type(1), type(1L)]:
uid = user_info
else:
uid = user_info['uid']
query = """SELECT DISTINCT r.name, a.name
- FROM user_accROLE ur, accROLE_accACTION_accARGUMENT raa, accACTION a, accROLE r
- WHERE ur.id_user = %s and
- ur.expiration >= NOW() and
- ur.id_accROLE = raa.id_accROLE and
- raa.id_accACTION = a.id and
- raa.id_accROLE = r.id """ % (uid, )
+ FROM user_accROLE ur, accROLE_accACTION_accARGUMENT raa, accACTION a,
+ accROLE r
+ WHERE ur.id_user = %s and
+ ur.expiration >= NOW() and
+ ur.id_accROLE = raa.id_accROLE and
+ raa.id_accACTION = a.id and
+ raa.id_accROLE = r.id """
- res1 = run_sql(query)
+ res1 = run_sql(query, (uid, ))
res2 = []
- for res in res1: res2.append(res)
+ for res in res1:
+ res2.append(res)
res2.sort()
if type(user_info) == type({}):
query = """SELECT DISTINCT r.name, a.name, r.firerole_def_ser
- FROM accROLE_accACTION_accARGUMENT raa, accACTION a, accROLE r
- WHERE raa.id_accACTION = a.id and
- raa.id_accROLE = r.id """
+ FROM accROLE_accACTION_accARGUMENT raa, accACTION a, accROLE r
+ WHERE raa.id_accACTION = a.id and
+ raa.id_accROLE = r.id """
res3 = run_sql(query)
res4 = []
for role_name, action_name, role_definition in res3:
- if acc_firerole_check_user(user_info, deserialize(role_definition)):
+ if acc_firerole_check_user(user_info,
+ deserialize(role_definition)):
res4.append((role_name, action_name))
return list(Set(res2) or Set(res4))
else:
return res2
# POSSIBLE ACTIONS / AUTHORIZATIONS
-def acc_findPossibleActionsAll(id_role):
+def acc_find_possible_actions_all(id_role):
"""find all the possible actions for a role.
- the function utilizes acc_findPossibleActions to find
+ the function utilizes acc_find_possible_actions to find
all the entries from each of the actions under the given role
id_role - role to find all actions for
returns a list with headers"""
query = """SELECT DISTINCT(aar.id_accACTION)
FROM accROLE_accACTION_accARGUMENT aar
WHERE aar.id_accROLE = %s
ORDER BY aar.id_accACTION""" % (id_role, )
res = []
for (id_action, ) in run_sql(query):
- hlp = acc_findPossibleActions(id_role, id_action)
+ hlp = acc_find_possible_actions(id_role, id_action)
if hlp:
res.append(['role', 'action'] + hlp[0])
for row in hlp[1:]:
res.append([id_role, id_action] + row)
return res
-def acc_findPossibleActionsArgumentlistid(id_role, id_action, arglistid):
+def acc_find_possible_actions_argument_listid(id_role, id_action, arglistid):
"""find all possible actions with the given arglistid only."""
# get all, independent of argumentlistid
- res1 = acc_findPossibleActions_ids(id_role, id_action)
+ res1 = acc_find_possible_actions_ids(id_role, id_action)
# create list with only those with the right arglistid
res2 = []
for row in res1[1:]:
- if row[0] == arglistid: res2.append(row)
+ if row[0] == arglistid:
+ res2.append(row)
# return this list
return res2
-def acc_findPossibleActionsUser(id_user, id_action):
+def acc_find_possible_actions_user(id_user, id_action):
"""user based function to find all action combination for a given
- user and action. find all the roles and utilize findPossibleActions for all these.
+ user and action. find all the roles and utilize findPossibleActions
+ for all these.
id_user - user id, used to find roles
id_action - action id. """
res = []
- for (id_role, ) in acc_getUserRoles(id_user):
- hlp = acc_findPossibleActions(id_role, id_action)
- if hlp and not res: res.append(['role'] + hlp[0])
+ for (id_role, ) in acc_get_user_roles(id_user):
+ hlp = acc_find_possible_actions(id_role, id_action)
+ if hlp and not res:
+ res.append(['role'] + hlp[0])
for row in hlp[1:]:
res.append([id_role] + row)
return res
-def acc_findPossibleActions_ids(id_role, id_action):
+def acc_find_possible_actions_ids(id_role, id_action):
"""finds the ids of the possible actions.
- utilization of acc_getArgumentId and acc_findPossibleActions. """
+ utilization of acc_get_argument_id and acc_find_possible_actions. """
- pas = acc_findPossibleActions(id_role, id_action)
+ pas = acc_find_possible_actions(id_role, id_action)
- if not pas: return []
+ if not pas:
+ return []
keys = pas[0]
pas_ids = [pas[0:1]]
for pa in pas[1:]:
auth = [pa[0]]
for i in range(1, len(pa)):
- auth.append(acc_getArgumentId(keys[i], pa[i]))
+ auth.append(acc_get_argument_id(keys[i], pa[i]))
pas_ids.append(auth)
return pas_ids
-def acc_findPossibleActions(id_role, id_action):
+def acc_find_possible_actions(id_role, id_action):
"""Role based function to find all action combinations for a
give role and action.
id_role - id of role in the database
id_action - id of the action in the database
returns a list with all the combinations.
first row is used for header."""
# query to find all entries for user and action
res1 = run_sql(""" SELECT raa.argumentlistid, ar.keyword, ar.value
- FROM accROLE_accACTION_accARGUMENT raa, accARGUMENT ar
- WHERE raa.id_accROLE = %s and
- raa.id_accACTION = %s and
- raa.id_accARGUMENT = ar.id """, (id_role, id_action))
+ FROM accROLE_accACTION_accARGUMENT raa, accARGUMENT ar
+ WHERE raa.id_accROLE = %s and
+ raa.id_accACTION = %s and
+ raa.id_accARGUMENT = ar.id """, (id_role, id_action))
# find needed keywords, create header
- keywords = acc_getActionKeywords(id_action=id_action)
+ keywords = acc_get_action_keywords(id_action=id_action)
keywords.sort()
if not keywords:
# action without arguments
- if run_sql("""SELECT * FROM accROLE_accACTION_accARGUMENT WHERE id_accROLE = %s AND id_accACTION = %s AND id_accARGUMENT = 0 AND argumentlistid = 0""", (id_role, id_action)):
- return [['#', 'argument keyword'], ['0', 'action without arguments']]
+ if run_sql("""SELECT * FROM accROLE_accACTION_accARGUMENT
+ WHERE id_accROLE = %s AND id_accACTION = %s AND id_accARGUMENT = 0
+ AND argumentlistid = 0""", (id_role, id_action)):
+ return [['#', 'argument keyword'],
+ ['0', 'action without arguments']]
# tuples into lists
res2, arglistids = [], {}
for res in res1:
res2.append([])
- for r in res: res2[-1].append(r)
+ for r in res:
+ res2[-1].append(r)
res2.sort()
# create multilevel dictionary
for res in res2:
a, kw, value = res # rolekey, argumentlistid, keyword, value
- if kw not in keywords: continue
+ if kw not in keywords:
+ continue
if not arglistids.has_key(a):
arglistids[a] = {}
# fill dictionary
- if not arglistids[a].has_key(kw): arglistids[a][kw] = [value]
- elif not value in arglistids[a][kw]: arglistids[a][kw] = arglistids[a][kw] + [value]
+ if not arglistids[a].has_key(kw):
+ arglistids[a][kw] = [value]
+ elif not value in arglistids[a][kw]:
+ arglistids[a][kw] = arglistids[a][kw] + [value]
# fill list with all possible combinations
res3 = []
# rolekeys = roles2.keys(); rolekeys.sort()
for a in arglistids.keys(): # argumentlistids
- # fill a list with the new entries, shortcut and copying first keyword list
+ # fill a list with the new entries, shortcut and copying first
+ # keyword list
next_arglistid = []
- for row in arglistids[a][keywords[0]]: next_arglistid.append([a, row[:] ])
+ for row in arglistids[a][keywords[0]]:
+ next_arglistid.append([a, row[:] ])
# run through the rest of the keywords
for kw in keywords[1:]:
- if not arglistids[a].has_key(kw): arglistids[a][kw] = ['optional value']
+ if not arglistids[a].has_key(kw):
+ arglistids[a][kw] = ['optional value']
new_list = arglistids[a][kw][:]
new_len = len(new_list)
# duplicate the list
temp_list = []
for row in next_arglistid:
- for i in range(new_len): temp_list.append(row[:])
+ for i in range(new_len):
+ temp_list.append(row[:])
# append new values
for i in range(len(temp_list)):
new_item = new_list[i % new_len][:]
temp_list[i].append( new_item )
next_arglistid = temp_list[:]
res3.extend(next_arglistid)
res3.sort()
# if optional allowed, put on top
opt = run_sql("""SELECT * FROM accROLE_accACTION_accARGUMENT
- WHERE id_accROLE = %s AND
- id_accACTION = %s AND
- id_accARGUMENT = -1 AND
- argumentlistid = -1""" % (id_role, id_action))
+ WHERE id_accROLE = %s AND
+ id_accACTION = %s AND
+ id_accARGUMENT = -1 AND
+ argumentlistid = -1""", (id_role, id_action))
- if opt: res3.insert(0, [-1] + ['optional value'] * len(keywords))
+ if opt:
+ res3.insert(0, [-1] + ['optional value'] * len(keywords))
# put header on top
if res3:
res3.insert(0, ['#'] + keywords)
return res3
-def acc_splitArgumentGroup(id_role=0, id_action=0, arglistid=0):
+def acc_split_argument_group(id_role=0, id_action=0, arglistid=0):
"""collect the arguments, find all combinations, delete original entries
and insert the new ones with different argumentlistids for each group
id_role - id of the role
id_action - id of the action
arglistid - argumentlistid to be splittetd"""
- if not id_role or not id_action or not arglistid: return []
+ if not id_role or not id_action or not arglistid:
+ return []
# don't split if none or one possible actions
- res = acc_findPossibleActionsArgumentlistid(id_role, id_action, arglistid)
- if not res or len(res) <= 1: return 0
+ res = acc_find_possible_actions_argument_listid(id_role, id_action,
+ arglistid)
+ if not res or len(res) <= 1:
+ return 0
# delete the existing group
- delete = acc_deleteRoleActionArguments_group(id_role, id_action, arglistid)
+ acc_delete_role_action_arguments_group(id_role, id_action,
+ arglistid)
# add all authorizations with new and different argumentlistid
addlist = []
for row in res:
argids = row[1:]
- addlist.append(acc_addRoleActionArguments(id_role=id_role,
+ addlist.append(acc_add_role_action_arguments(id_role=id_role,
id_action=id_action,
arglistid=-1,
id_arguments=argids))
# return list of added authorizations
return addlist
-def acc_mergeArgumentGroups(id_role=0, id_action=0, arglistids=[]):
+def acc_merge_argument_groups(id_role=0, id_action=0, arglistids=[]):
"""merge the authorizations from groups with different argumentlistids
into one single group.
this can both save entries in the database and create extra authorizations.
id_role - id of the role
id_action - role of the action
arglistids - list of groups to be merged together into one."""
- if len(arglistids) < 2: return []
+ if len(arglistids) < 2:
+ return []
argstr = ''
- for id in arglistids:
- argstr += 'raa.argumentlistid = %s or ' % (id, )
+ for arglist_id in arglistids:
+ argstr += 'raa.argumentlistid = %s or ' % (arglist_id, )
argstr = '(%s)' % (argstr[:-4], )
# query to find all entries that will be merged
query = """ SELECT ar.keyword, ar.value, raa.id_accARGUMENT
- FROM accROLE_accACTION_accARGUMENT raa, accARGUMENT ar
- WHERE raa.id_accROLE = %s and
- raa.id_accACTION = %s and
- %s and
- raa.id_accARGUMENT = ar.id """ % (id_role, id_action, argstr)
+ FROM accROLE_accACTION_accARGUMENT raa, accARGUMENT ar
+ WHERE raa.id_accROLE = %%s and
+ raa.id_accACTION = %%s and
+ %s and
+ raa.id_accARGUMENT = ar.id """ % argstr
q_del = """DELETE FROM accROLE_accACTION_accARGUMENT
- WHERE id_accROLE = %s and
- id_accACTION = %s and
- %s """ % (id_role, id_action, argstr.replace('raa.', ''))
+ WHERE id_accROLE = %%s and
+ id_accACTION = %%s and
+ %s """ % (argstr.replace('raa.', ''))
- res = run_sql(query)
- if not res: return []
+ res = run_sql(query, (id_role, id_action))
+ if not res:
+ return []
- run_sql(q_del)
+ run_sql(q_del, (id_role, id_action))
# list of entire entries
old = []
# list of only the ids
ids = []
- for (k, v, id) in res:
- if [k, v, id] not in old:
- old.append([k, v, id])
- ids.append(id)
+ for (keyword, value, argument_id) in res:
+ if [keyword, value, argument_id] not in old:
+ old.append([keyword, value, argument_id])
+ ids.append(argument_id)
# for (k, v, id) in res: if id not in ids: ids.append(id)
- return acc_addRoleActionArguments(id_role=id_role,
+ return acc_add_role_action_arguments(id_role=id_role,
id_action=id_action,
arglistid=-1,
id_arguments=ids)
def acc_reset_default_settings(superusers=[]):
"""reset to default by deleting everything and adding default.
superusers - list of superuser emails """
remove = acc_delete_all_settings()
add = acc_add_default_settings(superusers=superusers)
return remove, add
def acc_delete_all_settings():
"""simply remove all data affiliated with webaccess by truncating
tables accROLE, accACTION, accARGUMENT and those connected. """
run_sql("""TRUNCATE accROLE""")
run_sql("""TRUNCATE accACTION""")
run_sql("""TRUNCATE accARGUMENT""")
run_sql("""TRUNCATE user_accROLE""")
run_sql("""TRUNCATE accROLE_accACTION_accARGUMENT""")
return 1
def acc_add_default_settings(superusers=[]):
"""add the default settings if they don't exist.
superusers - list of superuser emails """
- # imported from config
- global supportemail
- # imported from access_control_config
- global DEF_ROLES
- global DEF_USERS
- global DEF_ACTIONS
- global DEF_AUTHS
-
- # from superusers: allow input formats ['email1', 'email2'] and [['email1'], ['email2']] and [['email1', id], ['email2', id]]
+ # from superusers: allow input formats ['email1', 'email2'] and
+ # [['email1'], ['email2']] and [['email1', id], ['email2', id]]
for user in superusers:
- if type(user) is str: user = [user]
+ if type(user) is str:
+ user = [user]
DEF_USERS.append(user[0])
- if supportemail not in DEF_USERS: DEF_USERS.append(supportemail)
+ if supportemail not in DEF_USERS:
+ DEF_USERS.append(supportemail)
# add data
# add roles
insroles = []
for (name, description, firerole_def_src) in DEF_ROLES:
# try to add, don't care if description is different
- id = acc_addRole(name_role=name,
- description=description, firerole_def_ser=serialize(compile_role_definition(firerole_def_src)), firerole_def_src=firerole_def_src)
- if not id:
- id = acc_getRoleId(name_role=name)
- acc_updateRole(id_role=id, description=description, firerole_def_ser=serialize(compile_role_definition(firerole_def_src)), firerole_def_src=firerole_def_src)
- insroles.append([id, name, description, firerole_def_src])
+ role_id = acc_add_role(name_role=name,
+ description=description, firerole_def_ser=serialize(
+ compile_role_definition(firerole_def_src)),
+ firerole_def_src=firerole_def_src)
+ if not role_id:
+ role_id = acc_get_role_id(name_role=name)
+ acc_update_role(id_role=role_id, description=description,
+ firerole_def_ser=serialize(compile_role_definition(
+ firerole_def_src)), firerole_def_src=firerole_def_src)
+ insroles.append([role_id, name, description, firerole_def_src])
# add users to superadmin
insuserroles = []
for user in DEF_USERS:
- insuserroles.append(acc_addUserRole(email=user,
+ insuserroles.append(acc_add_user_role(email=user,
name_role=SUPERADMINROLE))
# add actions
insactions = []
for (name, description, allkeys, optional) in DEF_ACTIONS:
# try to add action as new
- id = acc_addAction(name, description, optional, allkeys)
+ action_id = acc_add_action(name, description, optional, allkeys)
# action with the name exist
- if not id:
- id = acc_getActionId(name_action=name)
- # update the action, necessary updates to the database will also be done
- acc_updateAction(id_action=id, optional=optional, allowedkeywords=allkeys)
+ if not action_id:
+ action_id = acc_get_action_id(name_action=name)
+ # update the action, necessary updates to the database
+ # will also be done
+ acc_update_action(id_action=action_id, optional=optional,
+ allowedkeywords=allkeys)
# keep track of inserted actions
- insactions.append([id, name, description, allkeys])
+ insactions.append([action_id, name, description, allkeys])
# add authorizations
insauths = []
for (name_role, name_action, arglistid, optional, args) in DEF_AUTHS:
# add the authorization
- acc_addRoleActionArguments_names(name_role=name_role,
+ acc_add_role_action_arguments_names(name_role=name_role,
name_action=name_action,
arglistid=arglistid,
optional=optional,
**args)
# keep track of inserted authorizations
insauths.append([name_role, name_action, arglistid, optional, args])
return insroles, insactions, insuserroles, insauths
def acc_find_delegated_roles(id_role_admin=0):
"""find all the roles the admin role has delegation rights over.
return tuple of all the roles.
id_role_admin - id of the admin role """
- id_action_delegate = acc_getActionId(name_action=DELEGATEADDUSERROLE)
+ id_action_delegate = acc_get_action_id(name_action=DELEGATEADDUSERROLE)
rolenames = run_sql("""SELECT DISTINCT(ar.value)
- FROM accROLE_accACTION_accARGUMENT raa LEFT JOIN accARGUMENT ar
- ON raa.id_accARGUMENT = ar.id
- WHERE raa.id_accROLE = '%s' AND
- raa.id_accACTION = '%s'
- """ % (id_role_admin, id_action_delegate))
+ FROM accROLE_accACTION_accARGUMENT raa LEFT JOIN accARGUMENT ar
+ ON raa.id_accARGUMENT = ar.id
+ WHERE raa.id_accROLE = '%s AND
+ raa.id_accACTION = %s""", (id_role_admin, id_action_delegate))
result = []
for (name_role, ) in rolenames:
- roledetails = run_sql("""SELECT * FROM accROLE WHERE name = %s """, (name_role, ))
- if roledetails: result.append(roledetails)
+ roledetails = run_sql("""SELECT * FROM accROLE WHERE name = %s """,
+ (name_role, ))
+ if roledetails:
+ result.append(roledetails)
return result
-def acc_cleanupArguments():
- """function deletes all accARGUMENTs that are not referenced by accROLE_accACTION_accARGUMENT.
- returns how many arguments where deleted and a list of the deleted id_arguments"""
+def acc_cleanup_arguments():
+ """function deletes all accARGUMENTs that are not referenced by
+ accROLE_accACTION_accARGUMENT.
+ returns how many arguments where deleted and a list of the deleted
+ id_arguments"""
# find unreferenced arguments
ids1 = run_sql("""SELECT DISTINCT ar.id
- FROM accARGUMENT ar LEFT JOIN accROLE_accACTION_accARGUMENT raa ON ar.id = raa.id_accARGUMENT
- WHERE raa.id_accARGUMENT IS NULL """)
+ FROM accARGUMENT ar LEFT JOIN accROLE_accACTION_accARGUMENT raa ON
+ ar.id = raa.id_accARGUMENT WHERE raa.id_accARGUMENT IS NULL """)
# it is clean
- if not ids1: return 1
+ if not ids1:
+ return 1
# create list and string of the ids
ids2 = []
idstr = ''
- for (id, ) in ids1:
- ids2.append(id)
- if idstr: idstr += ','
- idstr += '%s' % id
+ for (argument_id, ) in ids1:
+ ids2.append(argument_id)
+ if idstr:
+ idstr += ','
+ idstr += '%s' % argument_id
# delete unreferenced arguments
count = run_sql("""DELETE FROM accARGUMENT
WHERE id in (%s)""" % (idstr, ))
# return count and ids of deleted arguments
return (count, ids2)
diff --git a/modules/webaccess/lib/access_control_engine.py b/modules/webaccess/lib/access_control_engine.py
index 9c17dc5a7..4f3b0805c 100644
--- a/modules/webaccess/lib/access_control_engine.py
+++ b/modules/webaccess/lib/access_control_engine.py
@@ -1,351 +1,353 @@
## $Id$
## CDS Invenio Access Control Engine in mod_python.
## This file is part of CDS Invenio.
## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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 Access Control Engine in mod_python."""
__revision__ = "$Id$"
from invenio.config import \
CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS, \
version, sweburl
from invenio.dbquery import run_sql_cached, ProgrammingError
import invenio.access_control_admin as aca
from invenio.access_control_config import SUPERADMINROLE, CFG_WEBACCESS_WARNING_MSGS, CFG_WEBACCESS_MSGS
from invenio import webuser
from invenio import access_control_firerole
from invenio.urlutils import make_canonical_urlargd
called_from = 1 #1=web,0=cli
try:
import _apache
except ImportError, e:
called_from = 0
def _make_list_apache_firerole(name_action):
res = run_sql_cached('SELECT r.name, r.description, r.firerole_def_ser FROM accACTION a JOIN accROLE_accACTION_accARGUMENT raa ON a.id=raa.id_accACTION JOIN accROLE r ON raa.id_accROLE=r.id WHERE a.name=%s', (name_action, ), affected_tables=['accACTION', 'accROLE_accACTION_accARGUMENT', 'accROLE'])
if res:
roles = [(row[0], row[1]) for row in res if access_control_firerole.acc_firerole_suggest_apache_p(access_control_firerole.deserialize(row[2]))]
return roles
else:
return []
def _format_list_of_apache_firerole(roles, referer):
out = ""
if roles:
out += "
Here's a list of administrative roles you may have " \
"received authorization to, via an Apache password. If you are aware " \
"of such a password, please follow the corresponding link."
out += "
"
out += ""
return out
-def make_apache_message(name_action, referer='%s/youraccount/youradminactivities' % sweburl):
+def make_apache_message(name_action, referer=None):
+ if not referer:
+ referer = '%s/youraccount/youradminactivities' % sweburl
roles = _make_list_apache_firerole(name_action)
if roles:
return _format_list_of_apache_firerole(roles, referer)
else:
return ""
## access controle engine function
def acc_authorize_action(req, name_action, verbose=0, check_only_uid_p=False, **arguments):
"""Check if user is allowed to perform action
with given list of arguments.
Return (0, message) if authentication succeeds, (error code, error message) if it fails.
The arguments are as follows:
req - could be either one of these three things:
id_user of the current user
user_info dictionary built against the user details
req mod_python request object
name_action - the name of the action
arguments - dictionary with keyword=value pairs created automatically
by python on the extra arguments. these depend on the
given action.
check_only_uid_p - hidden parameter needed to only check against uids without
looking at role definitions
"""
#TASK -1: Checking external source if user is authorized:
#if CFG_:
# em_pw = run_sql("SELECT email, FROM user WHERE id=%s", (id_user,))
# if em_pw:
# if not CFG_EXTERNAL_ACCESS_CONTROL.loginUser(em_pw[0][0], em_pw[0][1]):
# return (10, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[10], (called_from and CFG_WEBACCESS_MSGS[1] or "")))
# TASK 0: find id and allowedkeywords of action
if check_only_uid_p:
id_user = req
else:
if type(req) in [type(1), type(1L)]: # req is id_user
id_user = req
user_info = webuser.collect_user_info(id_user)
elif type(req) == type({}): # req is user_info
user_info = req
if user_info.has_key('uid'):
id_user = user_info['uid']
else:
return (4, CFG_WEBACCESS_WARNING_MSGS[4])
else: # req is req
user_info = webuser.collect_user_info(req)
if user_info.has_key('uid'):
id_user = user_info['uid']
else:
return (4, CFG_WEBACCESS_WARNING_MSGS[4])
# Check if just the userid is enough to execute this action
(auth_code, auth_message) = acc_authorize_action(id_user, name_action, verbose, check_only_uid_p=True, **arguments)
if auth_code == 0:
return (auth_code, auth_message)
if verbose: print 'task 0 - get action info'
query1 = """select a.id, a.allowedkeywords, a.optional
from accACTION a
where a.name = '%s'""" % (name_action)
try: id_action, aallowedkeywords, optional = run_sql_cached(query1, affected_tables=['accACTION'])[0]
except (ProgrammingError, IndexError): return (3, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[3] % name_action, (called_from and CFG_WEBACCESS_MSGS[1] or "")))
defkeys = aallowedkeywords.split(',')
for key in arguments.keys():
if key not in defkeys: return (8, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[8], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or ""))) #incorrect arguments?
# -------------------------------------------
# TASK 1: check if user is a superadmin
# we know the action exists. no connection with role is necessary
# passed arguments must have allowed keywords
# no check to see if the argument exists
if verbose: print 'task 1 - is user %s' % (SUPERADMINROLE, )
if check_only_uid_p:
if run_sql_cached("""SELECT *
FROM accROLE r LEFT JOIN user_accROLE ur
ON r.id = ur.id_accROLE
WHERE r.name = '%s' AND
ur.id_user = '%s' AND ur.expiration>=NOW()""" % (SUPERADMINROLE, id_user), affected_tables=['accROLE', 'user_accROLE']):
return (0, CFG_WEBACCESS_WARNING_MSGS[0])
else:
- if access_control_firerole.acc_firerole_check_user(user_info, access_control_firerole.load_role_definition(aca.acc_getRoleId(SUPERADMINROLE))):
+ if access_control_firerole.acc_firerole_check_user(user_info, access_control_firerole.load_role_definition(aca.acc_get_role_id(SUPERADMINROLE))):
return (0, CFG_WEBACCESS_WARNING_MSGS[0])
# TASK 2: check if user exists and find all the user's roles and create or-string
if verbose: print 'task 2 - find user and userroles'
try:
query2 = """SELECT email, note from user where id=%s""" % id_user
res2 = run_sql_cached(query2, affected_tables=['user'])
if check_only_uid_p:
if not res2:
raise Exception
if res2:
if CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS >= 1 and res2[0][1] not in [1, "1"]:
if res2[0][0]:
return (9, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[9] % res2[0][0], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or "")))
else:
raise Exception
if check_only_uid_p:
query2 = """SELECT ur.id_accROLE FROM user_accROLE ur WHERE ur.id_user=%s AND ur.expiration>=NOW() ORDER BY ur.id_accROLE """ % id_user
res2 = run_sql_cached(query2, affected_tables=['user_accROLE'])
except Exception: return (6, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[6], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or "")))
if check_only_uid_p:
if not res2:
return (2, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[2], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or ""))) #user has no roles
# -------------------------------------------
# create role string (add default value? roles='(raa.id_accROLE='def' or ')
str_roles = ''
for (role, ) in res2:
if str_roles: str_roles += ','
str_roles += '%s' % (role, )
# TASK 3: authorizations with no arguments given
if verbose: print 'task 3 - checks with no arguments'
if not arguments:
# 3.1
if optional == 'no':
if verbose: print ' - action with zero arguments'
if check_only_uid_p:
connection = run_sql_cached("""SELECT * FROM accROLE_accACTION_accARGUMENT
WHERE id_accROLE IN (%s) AND
id_accACTION = %s AND
argumentlistid = 0 AND
id_accARGUMENT = 0 """ % (str_roles, id_action), affected_tables=['accROLE_accACTION_accARGUMENT'])
if connection and 1:
return (0, CFG_WEBACCESS_WARNING_MSGS[0])
else:
return (1, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[1], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or "")))
else:
connection = run_sql_cached("""SELECT id_accROLE FROM
accROLE_accACTION_accARGUMENT
WHERE id_accACTION = %s AND
argumentlistid = 0 AND
id_accARGUMENT = 0 """ % id_action, affected_tables=['accROLE_accACTION_accARGUMENT'])
for id_accROLE in connection:
if access_control_firerole.acc_firerole_check_user(user_info, access_control_firerole.load_role_definition(id_accROLE[0])):
return (0, CFG_WEBACCESS_WARNING_MSGS[0])
- return (1, "%s %s %s" % (CFG_WEBACCESS_WARNING_MSGS[1], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or ""), make_apache_message(name_action, user_info['referer'])))
+ return (1, "%s %s %s" % (CFG_WEBACCESS_WARNING_MSGS[1], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or ""), make_apache_message(name_action, user_info.get('referer', None))))
# 3.2
if optional == 'yes':
if verbose: print ' - action with optional arguments'
if check_only_uid_p:
connection = run_sql_cached("""SELECT * FROM accROLE_accACTION_accARGUMENT
WHERE id_accROLE IN (%s) AND
id_accACTION = %s AND
id_accARGUMENT = -1 AND
argumentlistid = -1 """ % (str_roles, id_action), affected_tables=['accROLE_accACTION_accARGUMENT'])
if connection and 1:
return (0, CFG_WEBACCESS_WARNING_MSGS[0])
else:
return (1, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[1], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or "")))
else:
connection = run_sql_cached("""SELECT id_accROLE FROM
accROLE_accACTION_accARGUMENT
WHERE id_accACTION = %s AND
id_accARGUMENT = -1 AND
argumentlistid = -1 """ % id_action, affected_tables=['accROLE_accACTION_accARGUMENT'])
for id_accROLE in connection:
if access_control_firerole.acc_firerole_check_user(user_info, access_control_firerole.load_role_definition(id_accROLE[0])):
return (0, CFG_WEBACCESS_WARNING_MSGS[0])
- return (1, "%s %s %s" % (CFG_WEBACCESS_WARNING_MSGS[1], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or ""), make_apache_message(name_action, user_info['referer'])))
+ return (1, "%s %s %s" % (CFG_WEBACCESS_WARNING_MSGS[1], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or ""), make_apache_message(name_action, user_info('referer', None))))
# none of the zeroargs tests succeded
if verbose: print ' - not authorization without arguments'
return (5, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[5], (called_from and "%s" % (CFG_WEBACCESS_MSGS[1] or ""))))
# TASK 4: create list of keyword and values that satisfy part of the authentication and create or-string
if verbose: print 'task 4 - create keyword=value pairs'
# create dictionary with default values and replace entries from input arguments
defdict = {}
for key in defkeys:
try: defdict[key] = arguments[key]
except KeyError: return (5, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[5], (called_from and "%s" % (CFG_WEBACCESS_MSGS[1] or "")))) # all keywords must be present
# except KeyError: defdict[key] = 'x' # default value, this is not in use...
# create or-string from arguments
str_args = ''
for key in defkeys:
if str_args: str_args += ' OR '
str_args += """(arg.keyword = '%s' AND arg.value = '%s')""" % (key, defdict[key])
# TASK 5: find all the table entries that partially authorize the action in question
if verbose: print 'task 5 - find table entries that are part of the result'
if check_only_uid_p:
query4 = """SELECT DISTINCT raa.id_accROLE, raa.id_accACTION, raa.argumentlistid,
raa.id_accARGUMENT, arg.keyword, arg.value
FROM accROLE_accACTION_accARGUMENT raa, accARGUMENT arg
WHERE raa.id_accACTION = %s AND
raa.id_accROLE IN (%s) AND
(%s) AND
raa.id_accARGUMENT = arg.id """ % (id_action, str_roles, str_args)
else:
query4 = """SELECT DISTINCT raa.id_accROLE, raa.id_accACTION, raa.argumentlistid,
raa.id_accARGUMENT, arg.keyword, arg.value, ar.firerole_def_ser
FROM accROLE_accACTION_accARGUMENT raa INNER JOIN accROLE ar ON
raa.id_accROLE = ar.id, accARGUMENT arg
WHERE raa.id_accACTION = %s AND
(%s) AND
raa.id_accARGUMENT = arg.id """ % (id_action, str_args)
try: res4 = run_sql_cached(query4, affected_tables=['accROLE_accACTION_accARGUMENT', 'accARGUMENT', 'accROLE'])
except ProgrammingError:
raise query4
return (3, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[3] % id_action, (called_from and "%s" % (CFG_WEBACCESS_MSGS[1] or ""))))
res5 = []
if check_only_uid_p:
if not res4: return (1, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[1], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or ""))) # no entries at all
res5 = []
for res in res4:
res5.append(res)
else:
for row in res4:
if access_control_firerole.acc_firerole_check_user(user_info, access_control_firerole.load_role_definition(row[0])):
res5.append(row)
if not res5:
- return (1, "%s %s %s" % (CFG_WEBACCESS_WARNING_MSGS[1], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or ""), make_apache_message(name_action, user_info['referer']))) # no entries at all
+ return (1, "%s %s %s" % (CFG_WEBACCESS_WARNING_MSGS[1], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or ""), make_apache_message(name_action, user_info.get('referer', None)))) # no entries at all
res5.sort()
# USER AUTHENTICATED TO PERFORM ACTION WITH ONE ARGUMENT
if len(defdict) == 1: return (0, CFG_WEBACCESS_WARNING_MSGS[0])
# CHECK WITH MORE THAN 1 ARGUMENT
# TASK 6: run through the result and try to satisfy authentication
if verbose: print 'task 6 - combine results and try to satisfy'
cur_role = cur_action = cur_arglistid = 0
booldict = {}
for key in defkeys: booldict[key] = 0
# run through the results
for (role, action, arglistid, arg, keyword, val) in res5 + [(-1, -1, -1, -1, -1, -1)]:
# not the same role or argumentlist (authorization group), i.e. check if thing are satisfied
# if cur_arglistid != arglistid or cur_role != role or cur_action != action:
if (cur_arglistid, cur_role, cur_action) != (arglistid, role, action):
if verbose: print ' : checking new combination',
# test if all keywords are satisfied
for value in booldict.values():
if not value: break
else:
if verbose: print '-> found satisfying combination'
return (0, CFG_WEBACCESS_WARNING_MSGS[0]) # USER AUTHENTICATED TO PERFORM ACTION
if verbose: print '-> not this one'
# assign the values for the current tuple from the query
cur_arglistid, cur_role, cur_action = arglistid, role, action
for key in booldict.keys():
booldict[key] = 0
# set keyword qualified for the action, (whatever result of the test)
booldict[keyword] = 1
if verbose: print 'finished'
# authentication failed
return (4, "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[4], (called_from and "%s %s" % (CFG_WEBACCESS_MSGS[0] % name_action[3:], CFG_WEBACCESS_MSGS[1]) or "")))
diff --git a/modules/webaccess/lib/access_control_mailcookie.py b/modules/webaccess/lib/access_control_mailcookie.py
index 2a4dd4e20..4cd77bcd1 100644
--- a/modules/webaccess/lib/access_control_mailcookie.py
+++ b/modules/webaccess/lib/access_control_mailcookie.py
@@ -1,164 +1,164 @@
## $Id$
## Administrator interface for WebAccess
## This file is part of CDS Invenio.
## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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 Access Control MailCookie."""
__revision__ = "$Id$"
__lastupdated__ = """$Date$"""
"""These functions are temporaly managing roles and other authorization via
unique urls sent by email.
"""
from invenio.config import cdslang, sweburl
from invenio.dbquery import run_sql
-from invenio.access_control_admin import acc_getRoleId, acc_addUserRole
+from invenio.access_control_admin import acc_get_role_id, acc_add_user_role
from datetime import datetime, timedelta
from random import random
from cPickle import dumps, loads
import md5
_authorizations_kind = ('pw_reset', 'mail_activation', 'role')
_datetime_format = "%Y-%m-%d %H:%M:%S"
def mail_cookie_create_generic(kind, params, cookie_timeout=timedelta(days=1), onetime=False):
"""Create a unique url to be sent via email to access this authorization
@param kind kind of authorization (e.g. 'pw_reset', 'mail_activation', 'role')
@param params whatever parameters are needed
@param cookie_timeout for how long the url will be valid
@param onetime whetever to remove the cookie after it has used.
"""
assert(kind in _authorizations_kind)
expiration = datetime.today()+cookie_timeout
data = (kind, params, expiration, onetime)
password = md5.new(str(random())).hexdigest()
cookie_id = run_sql('INSERT INTO accMAILCOOKIE (data,expiration,kind,onetime) VALUES '
'(AES_ENCRYPT(%s, %s),%s,%s,%s)',
(dumps(data), password, expiration.strftime(_datetime_format), kind, onetime))
cookie = password[:16]+hex(cookie_id)[2:-1]+password[-16:]
return cookie
def mail_cookie_create_role(role_name, role_timeout=timedelta(hours=3), cookie_timeout=timedelta(days=1), onetime=True):
"""Create a unique url to be sent via email to belong temporaly to a role."""
- assert(acc_getRoleId(role_name) != 0)
+ assert(acc_get_role_id(role_name) != 0)
kind = 'role'
params = (role_name, role_timeout)
return mail_cookie_create_generic(kind, params, cookie_timeout, onetime)
def mail_cookie_create_pw_reset(email, cookie_timeout=timedelta(days=1)):
"""Create a unique url to be sent via email to reset the local password."""
kind = 'pw_reset'
if (run_sql('SELECT * FROM user WHERE email=%s', (email, ))):
params = email
return mail_cookie_create_generic(kind, params, cookie_timeout, False)
else:
return None
def mail_cookie_create_mail_activation(email, cookie_timeout=timedelta(days=1)):
"""Create a unique url to be sent via email to activate an email address"""
kind = 'mail_activation'
params = email
return mail_cookie_create_generic(kind, params, cookie_timeout, True)
def mail_cookie_retrieve_kind(cookie):
"""Retrieve if it exists the kind of a cookie."""
try:
password = cookie[:16]+cookie[-16:]
cookie_id = int(cookie[16:-16], 16)
res = run_sql("SELECT kind FROM accMAILCOOKIE WHERE id=%s", (cookie_id, ))
if res:
kind = res[0][0]
assert(kind in _authorizations_kind)
return kind
except StandardError:
return None
def mail_cookie_check_generic(cookie, delete=False):
"""Retrieve data pointed by a cookie, returning a tuple (kind, params) or None
if the cookie is not valid or is expired"""
password = cookie[:16]+cookie[-16:]
cookie_id = int(cookie[16:-16], 16)
try:
res = run_sql("SELECT kind, AES_DECRYPT(data,%s), onetime FROM accMAILCOOKIE WHERE "
"id=%s AND expiration>=NOW()", (password, cookie_id))
if not res:
raise StandardError
except StandardError:
return None
(kind, data, onetime) = res[0]
(kind_check, params, expiration, onetime_check) = loads(data)
if not (kind == kind_check and onetime == onetime_check):
return None
if onetime or delete:
run_sql("DELETE FROM accMAILCOOKIE WHERE id=%s", (cookie_id, ))
return (kind, params)
def mail_cookie_check_role(cookie, uid):
"""Check a given cookie for a valid authorization to a particular role and
temporaly add the given uid to the role specified."""
try:
(kind, params) = mail_cookie_check_generic(cookie)
assert(kind == 'role')
(role_name, role_timeout) = params
- role_id = acc_getRoleId(role_name)
+ role_id = acc_get_role_id(role_name)
assert(role_id != 0)
assert(type(role_timeout) is timedelta)
except (TypeError, AssertionError, StandardError):
return None
expiration = (datetime.today()+role_timeout).strftime(_datetime_format)
- acc_addUserRole(uid, role_id, expiration)
+ acc_add_user_role(uid, role_id, expiration)
return (role_name, expiration)
def mail_cookie_check_pw_reset(cookie):
"""Check a given cookie for a valid authorization to reset the password of
a particular email address. Return the name of a valid email to reset
it's password or None otherwise"""
try:
(kind, email) = mail_cookie_check_generic(cookie)
assert(kind == 'pw_reset')
return email
except (TypeError, AssertionError, StandardError):
return None
def mail_cookie_check_mail_activation(cookie):
"""Check a given cookie for a valid authorization to activate a particular email address."""
try:
(kind, email) = mail_cookie_check_generic(cookie)
assert(kind == 'mail_activation')
res = run_sql('SELECT note FROM user WHERE email=%s', (email, ))
if res:
note = res[0][0]
if note > 1:
res = run_sql('UPDATE user SET note=note & 1 WHERE email=%s', (email))
return email
else:
return None
except (TypeError, AssertionError):
return None
def mail_cookie_delete_cookie(cookie):
"""Remove a particular cookie."""
mail_cookie_check_generic(cookie, delete=True)
def mail_cookie_gc():
"""Clean the table for expired cookies"""
return run_sql("DELETE FROM accMAILCOOKIE WHERE expirationAdmin Area > WebAccess Admin """ % (weburl, weburl)
if body:
if adminarea == 1: navtrail_previous_links += '> Delegate Rights ' % (weburl, )
if adminarea >= 2 and adminarea < 7: navtrail_previous_links += '> Manage WebAccess ' % (weburl, )
if adminarea == 3: navtrail_previous_links += '> Role Administration ' % (weburl, )
elif adminarea == 4: navtrail_previous_links += '> Action Administration ' % (weburl, )
elif adminarea == 5: navtrail_previous_links += '> User Administration ' % (weburl, )
elif adminarea == 6: navtrail_previous_links += '> Reset Authorizations ' % (weburl, )
elif adminarea == 7: navtrail_previous_links += '> Manage Accounts ' % (weburl, )
id_user = getUid(req)
(auth_code, auth_message) = is_adminuser(req)
if not authorized and auth_code != 0: return mustloginpage(req, auth_message)
elif not body:
title = 'Manage WebAccess'
body = startpage()
elif type(body) != str: body = addadminbox(subtitle, datalist=body)
return page(title=title,
uid=id_user,
req=req,
body=body,
navtrail=navtrail_previous_links,
lastupdated=__lastupdated__)
def mustloginpage(req, message):
"""show a page asking the user to login."""
navtrail_previous_links = """Admin Area > WebAccess Admin """ % (weburl, weburl)
return page_not_authorized(req=req, text=message, navtrail=navtrail_previous_links)
def is_adminuser(req):
"""check if user is a registered administrator. """
return acce.acc_authorize_action(req, WEBACCESSACTION)
def perform_rolearea(req):
"""create the role area menu page."""
(auth_code, auth_message) = is_adminuser(req)
if auth_code != 0: return mustloginpage(req, auth_message)
header = ['id', 'name', 'description', 'firewall like role definition', 'users', 'authorizations / actions', 'role', '']
- roles = acca.acc_getAllRoles()
+ roles = acca.acc_get_all_roles()
roles2 = []
for (id, name, desc, dummy, firerole_def_src) in roles:
if len(desc) > 30: desc = desc[:30] + '...'
if firerole_def_src and len(firerole_def_src) > 30: firerole_def_src = firerole_def_src[:30] + '...'
roles2.append([id, name, desc, firerole_def_src])
for col in [(('add', 'adduserrole'),
('delete', 'deleteuserrole'),),
(('add', 'addauthorization'),
('modify', 'modifyauthorizations'),
('remove', 'deleteroleaction')),
(('modify', 'modifyrole'),
('delete', 'deleterole')),
(('show details', 'showroledetails'), )]:
roles2[-1].append('%s' % (col[0][1], id, col[0][0]))
for (str, function) in col[1:]:
roles2[-1][-1] += ' / %s' % (function, id, str)
output = """
Users:
add or remove users from the access to a role and its priviliges.
Authorizations/Actions:
these terms means almost the same, but an authorization is a
connection between a role and an action (possibly) containing arguments.
Roles:
see all the information attached to a role and decide if you want to delete it.
"""
output += tupletotable(header=header, tuple=roles2)
extra = """
"""
return index(req=req,
title='Action Administration',
subtitle='administration with actions as access point',
body=[output, extra],
adminarea=2)
def perform_userarea(req, email_user_pattern=''):
"""create area to show info about users. """
(auth_code, auth_message) = is_adminuser(req)
if auth_code != 0: return mustloginpage(req, auth_message)
subtitle = 'step 1 - search for users'
output = """
search for users to display.
"""
# remove letters not allowed in an email
email_user_pattern = cleanstring_email(email_user_pattern)
text = ' 1. search for user\n'
text += ' \n' % (email_user_pattern, )
output += createhiddenform(action="userarea",
text=text,
button="search for users")
if email_user_pattern:
users1 = run_sql("""SELECT id, email FROM user WHERE email RLIKE '%s' ORDER BY email LIMIT %s""" % (email_user_pattern, MAXPAGEUSERS+1))
if not users1:
output += '
no matching users
'
else:
subtitle = 'step 2 - select what to do with user'
users = []
for (id, email) in users1[:MAXPAGEUSERS]:
users.append([id, email])
for col in [(('add', 'addroleuser'),
('remove', 'deleteuserrole')),
(('show details', 'showuserdetails'), )]:
users[-1].append('%s' % (col[0][1], email_user_pattern, id, col[0][0]))
for (str, function) in col[1:]:
users[-1][-1] += ' / %s' % (function, email_user_pattern, id, str)
output += '
keep all changes and add the default authorization settings.
"""
return index(req=req,
title='Reset Authorizations',
subtitle='reseting to or adding default authorizations',
body=[output],
adminarea=2)
def perform_resetdefaultsettings(req, superusers=[], confirm=0):
"""delete all roles, actions and authorizations presently in the database
and add only the default roles.
only selected users will be added to superadmin, rest is blank """
(auth_code, auth_message) = is_adminuser(req)
if auth_code != 0: return mustloginpage(req, auth_message)
# cleaning input
if type(superusers) == str: superusers = [superusers]
# remove not valid e-mails
for email in superusers:
if not check_email(email): superusers.remove(email)
# instructions
output = """
before you reset the settings, we need some users
to connect to %s.
enter as many e-mail addresses you want and press reset. confirm reset settings when you have added enough e-mails. %s is added as default.
'
output += tupletotable(header=['e-mail address'],
tuple=superusers,
start=start,
extracolumn=extra,
end=end)
if confirm in [1, "1"]:
res = acca.acc_reset_default_settings(superusers)
if res:
output += '
successfully reset default settings
'
else:
output += '
sorry, could not reset default settings
'
return index(req=req,
title='Reset Default Settings',
subtitle='reset settings',
body=[output],
adminarea=6)
def perform_adddefaultsettings(req, superusers=[], confirm=0):
"""add the default settings, and keep everything else.
probably nothing will be deleted, except if there has been made changes to the defaults."""
(auth_code, auth_message) = is_adminuser(req)
if auth_code != 0: return mustloginpage(req, auth_message)
# cleaning input
if type(superusers) == str: superusers = [superusers]
# remove not valid e-mails
for email in superusers:
if not check_email(email): superusers.remove(email)
# instructions
output = """
before you add the settings, we need some users
to connect to %s.
enter as many e-mail addresses you want and press add. confirm add settings when you have added enough e-mails. %s is added as default.
""" % (weburl, weburl, weburl, weburl, weburl)
if mtype == "perform_accesspolicy" and content:
fin_output += content
elif mtype == "perform_accesspolicy" or mtype == "perform_showall":
fin_output += perform_accesspolicy(req, callback='')
fin_output += " "
if mtype == "perform_accountoverview" and content:
fin_output += content
elif mtype == "perform_accountoverview" or mtype == "perform_showall":
fin_output += perform_accountoverview(req, callback='')
fin_output += " "
if mtype == "perform_createaccount" and content:
fin_output += content
elif mtype == "perform_createaccount" or mtype == "perform_showall":
fin_output += perform_createaccount(req, callback='')
fin_output += " "
if mtype == "perform_modifyaccounts" and content:
fin_output += content
elif mtype == "perform_modifyaccounts" or mtype == "perform_showall":
fin_output += perform_modifyaccounts(req, callback='')
fin_output += " "
return index(req=req,
title='Manage Accounts',
subtitle=subtitle,
body=[fin_output],
adminarea=0,
authorized=1)
def perform_accesspolicy(req, callback='yes', confirm=0):
"""Modify default behaviour of a guest user or if new accounts should automatically/manually be modified."""
(auth_code, auth_message) = is_adminuser(req)
if auth_code != 0: return mustloginpage(req, auth_message)
subtitle = """1. Access policy. [?]""" % weburl
account_policy = {}
account_policy[0] = "Users can register new accounts. New accounts automatically activated."
account_policy[1] = "Users can register new accounts. Admin users must activate the accounts."
account_policy[2] = "Only admin can register new accounts. User cannot edit email address."
account_policy[3] = "Only admin can register new accounts. User cannot edit email address or password."
account_policy[4] = "Only admin can register new accounts. User cannot edit email address,password or login method."
site_policy = {}
site_policy[0] = "Normal operation of the site."
site_policy[1] = "Read-only site, all write operations temporarily closed."
site_policy[2] = "Site fully closed."
output = "(Modifications must be done in access_control_config.py) "
output += " Current settings: "
output += "Site status: %s " % (site_policy[CFG_ACCESS_CONTROL_LEVEL_SITE])
output += "Guest accounts allowed: %s " % (CFG_ACCESS_CONTROL_LEVEL_GUESTS == 0 and "Yes" or "No")
output += "Account policy: %s " % (account_policy[CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS])
output += "Allowed email addresses limited: %s " % (CFG_ACCESS_CONTROL_LIMIT_REGISTRATION_TO_DOMAIN and CFG_ACCESS_CONTROL_LIMIT_REGISTRATION_TO_DOMAIN or "Not limited")
output += "Send email to admin when new account: %s " % (CFG_ACCESS_CONTROL_NOTIFY_ADMIN_ABOUT_NEW_ACCOUNTS == 1 and "Yes" or "No")
output += "Send email to user after creating new account: %s " % (CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_NEW_ACCOUNT == 1 and "Yes" or "No")
output += "Send email to user when account is activated: %s " % (CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_ACTIVATION == 1 and "Yes" or "No")
output += "Send email to user when account is deleted/rejected: %s " % (CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_DELETION == 1 and "Yes" or "No")
output += " "
output += "Available 'login via' methods: "
methods = CFG_EXTERNAL_AUTHENTICATION.keys()
methods.sort()
for system in methods:
output += """%s %s """ % (system, (CFG_EXTERNAL_AUTHENTICATION[system][1] and "(Default)" or ""))
output += " Changing the settings: "
output += "Currently, all changes must be done using your favourite editor, and the webserver restarted for changes to take effect. For the settings to change, either look in the guide or in access_control_config.py ."
body = [output]
if callback:
return perform_manageaccounts(req, "perform_accesspolicy", addadminbox(subtitle, body))
else:
return addadminbox(subtitle, body)
def perform_accountoverview(req, callback='yes', confirm=0):
"""Modify default behaviour of a guest user or if new accounts should automatically/manually be modified."""
(auth_code, auth_message) = is_adminuser(req)
if auth_code != 0: return mustloginpage(req, auth_message)
subtitle = """2. Account overview. [?]""" % weburl
output = ""
res = run_sql("SELECT COUNT(*) FROM user WHERE email=''")
output += "Guest accounts: %s " % res[0][0]
res = run_sql("SELECT COUNT(*) FROM user WHERE email!=''")
output += "Registered accounts: %s " % res[0][0]
res = run_sql("SELECT COUNT(*) FROM user WHERE email!='' AND note='0' OR note IS NULL")
output += "Inactive accounts: %s " % res[0][0]
if res[0][0] > 0:
output += ' [Activate/Reject accounts]'
res = run_sql("SELECT COUNT(*) FROM user")
output += " Total nr of accounts: %s " % res[0][0]
body = [output]
if callback:
return perform_manageaccounts(req, "perform_accountoverview", addadminbox(subtitle, body))
else:
return addadminbox(subtitle, body)
def perform_createaccount(req, email='', password='', callback='yes', confirm=0):
"""Modify default behaviour of a guest user or if new accounts should automatically/manually be modified."""
(auth_code, auth_message) = is_adminuser(req)
if auth_code != 0: return mustloginpage(req, auth_message)
subtitle = """3. Create account. [?]""" % weburl
output = ""
text = ' Email:\n'
text += ' ' % (email, )
text += ' Password:\n'
text += ' ' % (password, )
output += createhiddenform(action="createaccount",
text=text,
confirm=1,
button="Create")
if confirm in [1, "1"] and email and email_valid_p(email):
res = run_sql("SELECT * FROM user WHERE email='%s'" % escape_string(email))
if not res:
res = run_sql("INSERT INTO user (email,password, note) values(%s,AES_ENCRYPT(email,%s), '1')", (email, password))
if CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_NEW_ACCOUNT == 1:
emailsent = sendNewUserAccountWarning(email, email, password)
if password:
output += 'Account created with password and activated.'
else:
output += 'Account created without password and activated.'
if CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_NEW_ACCOUNT == 1:
if emailsent:
output += ' An email has been sent to the owner of the account.'
else:
output += ' Could not send an email to the owner of the account.'
else:
output += 'An account with the same email already exists.'
elif confirm in [1, "1"]:
output += 'Please specify an valid email-address.'
body = [output]
if callback:
return perform_manageaccounts(req, "perform_createaccount", addadminbox(subtitle, body))
else:
return addadminbox(subtitle, body)
def perform_modifyaccountstatus(req, userID, email_user_pattern, limit_to, maxpage, page, callback='yes', confirm=0):
"""set a disabled account to enabled and opposite"""
(auth_code, auth_message) = is_adminuser(req)
if auth_code != 0: return mustloginpage(req, auth_message)
res = run_sql("SELECT id, email, note FROM user WHERE id=%s", (userID, ))
subtitle = ""
output = ""
if res:
if res[0][2] in [0, "0", None]:
res2 = run_sql("UPDATE user SET note=1 WHERE id=%s" % userID)
output += """The account '%s' has been activated.""" % res[0][1]
if CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_ACTIVATION == 1:
password = int(random.random() * 1000000)
run_sql("UPDATE user SET password=AES_ENCRYPT(email, %s) "
"WHERE id=%s", (password, userID))
emailsent = sendAccountActivatedMessage(res[0][1], res[0][1], password)
if emailsent:
output += """ An email has been sent to the owner of the account."""
else:
output += """ Could not send an email to the owner of the account."""
elif res[0][2] in [1, "1"]:
res2 = run_sql("UPDATE user SET note=0 WHERE id=%s" % userID)
output += """The account '%s' has been set inactive.""" % res[0][1]
else:
output += 'The account id given does not exist.'
body = [output]
if callback:
return perform_modifyaccounts(req, email_user_pattern, limit_to, maxpage, page, content=output, callback='yes')
else:
return addadminbox(subtitle, body)
def perform_editaccount(req, userID, mtype='', content='', callback='yes', confirm=-1):
"""form to modify an account. this method is calling other methods which again is calling this and sending back the output of the method.
if callback, the method will call perform_editcollection, if not, it will just return its output.
userID - id of the user
mtype - the method that called this method.
content - the output from that method."""
(auth_code, auth_message) = is_adminuser(req)
if auth_code != 0: return mustloginpage(req, auth_message)
res = run_sql("SELECT id, email FROM user WHERE id=%s" % userID)
if not res:
if mtype == "perform_deleteaccount":
text = """The selected account has been deleted, to continue editing, go back to 'Manage Accounts'."""
if CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_DELETION == 1:
text += """ An email has been sent to the owner of the account."""
else:
text = """The selected accounts does not exist, please go back and select an account to edit."""
return index(req=req,
title='Edit Account',
subtitle="Edit account",
body=[text],
adminarea=7,
authorized=1)
fin_output = """
" % (name, (public=="y" and "Yes" or "No"))
## basket_records = run_sql("SELECT id_record, nb_order FROM basket_record WHERE id_basket=%s" % id)
## for (id_record, nb_order) in basket_records:
## output += "
"
#else:
#output += 'The account id given does not exist.'
#body = [output]
#if callback:
#return perform_editaccount(req, userID, mtype='perform_modifybasket', content=addadminbox(subtitle, body), callback='yes')
#else:
#return addadminbox(subtitle, body)
def perform_modifylogindata(req, userID, email='', password='', callback='yes', confirm=0):
"""modify email and password of an account"""
(auth_code, auth_message) = is_adminuser(req)
if auth_code != 0: return mustloginpage(req, auth_message)
subtitle = """1. Edit login-data. [?]""" % weburl
res = run_sql("SELECT id, email FROM user WHERE id=%s" % userID)
output = ""
if res:
if not email and not password:
email = res[0][1]
#password = res[0][2]
text = ' Account id:%s \n' % userID
text += ' Email:\n'
text += ' ' % (email, )
text += ' Password:\n'
text += ' ' % (password, )
output += createhiddenform(action="modifylogindata",
text=text,
userID=userID,
confirm=1,
button="Modify")
if confirm in [1, "1"] and email and email_valid_p(email):
res = run_sql("UPDATE user SET email=%s WHERE id=%s", (email, userID))
res = run_sql("UPDATE user SET password=AES_ENCRYPT(email,%s) WHERE id=%s", (password, userID))
output += 'Email and/or password modified.'
elif confirm in [1, "1"]:
output += 'Please specify an valid email-address.'
else:
output += 'The account id given does not exist.'
body = [output]
if callback:
return perform_editaccount(req, userID, mtype='perform_modifylogindata', content=addadminbox(subtitle, body), callback='yes')
else:
return addadminbox(subtitle, body)
# Disabled because not secure and maybe not needed.
#def perform_modifyalerts(req, userID, callback='yes', confirm=0):
#"""modify email and password of an account"""
#(auth_code, auth_message) = is_adminuser(req)
#if auth_code != 0: return mustloginpage(req, auth_message)
#subtitle = """3. Modify alerts. [?]""" % weburl
#res = run_sql("SELECT id, email, password FROM user WHERE id=%s" % userID)
#output = ""
#if res:
#text = """To modify the alerts for this account, you have to login as the user."""
#output += createhiddenform(action="%s/youraccount/login?" % sweburl,
#text=text,
#p_email=res[0][1],
#p_pw=res[0][2],
#referer="%s/youralerts/display" % weburl,
#button="Login")
#output += "Remember that you will be logged out as the current user."
#res = """ SELECT q.id, q.urlargs, 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')
#FROM query q, user_query_basket a
#WHERE a.id_user='%s' AND a.id_query=q.id
#ORDER BY a.alert_name ASC """ % userID
##res = run_sql(res)
##for (qID, qurlargs, id_basket, alertname, frequency, notification, date_creation, date_lastrun) in res:
## output += "%s - %s - %s - %s - %s - %s - %s " % (qID, id_basket, alertname, frequency, notification, date_creation, date_lastrun)
#else:
#output += 'The account id given does not exist.'
#body = [output]
#if callback:
#return perform_editaccount(req, userID, mtype='perform_modifyalerts', content=addadminbox(subtitle, body), callback='yes')
#else:
#return addadminbox(subtitle, body)
def perform_modifypreferences(req, userID, login_method='', callback='yes', confirm=0):
"""modify email and password of an account"""
(auth_code, auth_message) = is_adminuser(req)
if auth_code != 0: return mustloginpage(req, auth_message)
subtitle = """4. Modify preferences. [?]""" % weburl
res = run_sql("SELECT id, email, FROM user WHERE id=%s" % userID)
output = ""
if res:
user_pref = get_user_preferences(userID)
if confirm in [1, "1"]:
if login_method:
user_pref['login_method'] = login_method
set_user_preferences(userID, user_pref)
output += "Select default login method: "
text = ""
methods = CFG_EXTERNAL_AUTHENTICATION.keys()
methods.sort()
for system in methods:
text += """%s """ % (system, (user_pref['login_method'] == system and "checked" or ""), system)
output += createhiddenform(action="modifypreferences",
text=text,
confirm=1,
userID=userID,
button="Select")
if confirm in [1, "1"]:
if login_method:
output += """The login method has been changed"""
else:
output += """Nothing to update"""
else:
output += 'The account id given does not exist.'
body = [output]
if callback:
return perform_editaccount(req, userID, mtype='perform_modifypreferences', content=addadminbox(subtitle, body), callback='yes')
else:
return addadminbox(subtitle, body)
def perform_deleteaccount(req, userID, callback='yes', confirm=0):
"""delete account"""
(auth_code, auth_message) = is_adminuser(req)
if auth_code != 0: return mustloginpage(req, auth_message)
subtitle = """5. Delete account. [?]""" % weburl
res = run_sql("SELECT id, email, FROM user WHERE id=%s" % userID)
output = ""
if res:
if confirm in [0, "0"]:
text = 'Are you sure you want to delete the account with email: "%s"?' % res[0][1]
output += createhiddenform(action="deleteaccount",
text=text,
userID=userID,
confirm=1,
button="Delete")
elif confirm in [1, "1"]:
res2 = run_sql("DELETE FROM user WHERE id=%s" % userID)
output += 'Account deleted.'
if CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_DELETION == 1:
emailsent = sendAccountDeletedMessage(res[0][1], res[0][1])
else:
output += 'The account id given does not exist.'
body = [output]
if callback:
return perform_editaccount(req, userID, mtype='perform_deleteaccount', content=addadminbox(subtitle, body), callback='yes')
else:
return addadminbox(subtitle, body)
def perform_rejectaccount(req, userID, email_user_pattern, limit_to, maxpage, page, callback='yes', confirm=0):
"""Delete account and send an email to the owner."""
(auth_code, auth_message) = is_adminuser(req)
if auth_code != 0: return mustloginpage(req, auth_message)
res = run_sql("SELECT id, email, note FROM user WHERE id=%s" % userID)
output = ""
subtitle = ""
if res:
res2 = run_sql("DELETE FROM user WHERE id=%s" % userID)
output += 'Account rejected and deleted.'
if CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_DELETION == 1:
if not res[0][2] or res[0][2] == "0":
emailsent = sendAccountRejectedMessage(res[0][1], res[0][1])
elif res[0][2] == "1":
emailsent = sendAccountDeletedMessage(res[0][1], res[0][1])
if emailsent:
output += """ An email has been sent to the owner of the account."""
else:
output += """ Could not send an email to the owner of the account."""
else:
output += 'The account id given does not exist.'
body = [output]
if callback:
return perform_modifyaccounts(req, email_user_pattern, limit_to, maxpage, page, content=output, callback='yes')
else:
return addadminbox(subtitle, body)
def perform_modifyaccounts(req, email_user_pattern='', limit_to=-1, maxpage=MAXPAGEUSERS, page=1, content='', callback='yes', confirm=0):
"""Modify default behaviour of a guest user or if new accounts should automatically/manually be modified."""
(auth_code, auth_message) = is_adminuser(req)
if auth_code != 0: return mustloginpage(req, auth_message)
subtitle = """4. Edit accounts. [?]""" % weburl
output = ""
# remove letters not allowed in an email
email_user_pattern = cleanstring_email(email_user_pattern)
try:
maxpage = int(maxpage)
except:
maxpage = MAXPAGEUSERS
try:
page = int(page)
if page < 1:
page = 1
except:
page = 1
text = ' Email (part of):\n'
text += ' ' % (email_user_pattern, )
text += """Limit to: """ % ((limit_to=="all" and "selected" or ""), (limit_to=="enabled" and "selected" or ""), (limit_to=="disabled" and "selected" or ""))
text += """Accounts per page: """ % ((maxpage==25 and "selected" or ""), (maxpage==50 and "selected" or ""), (maxpage==100 and "selected" or ""), (maxpage==250 and "selected" or ""), (maxpage==500 and "selected" or ""), (maxpage==1000 and "selected" or ""))
output += createhiddenform(action="modifyaccounts",
text=text,
button="search for accounts")
if limit_to not in [-1, "-1"] and maxpage:
users1 = "SELECT id,email,note FROM user WHERE "
if limit_to == "enabled":
users1 += " email!='' AND note=1"
elif limit_to == "disabled":
users1 += " email!='' AND note=0 OR note IS NULL"
elif limit_to == "guest":
users1 += " email=''"
else:
users1 += " email!=''"
if email_user_pattern:
users1 += " AND email RLIKE '%s'" % (email_user_pattern)
users1 += " ORDER BY email LIMIT %s" % (maxpage * page + 1)
users1 = run_sql(users1)
if not users1:
output += 'There are no accounts matching the email given.'
else:
users = []
if maxpage * (page - 1) > len(users1):
page = len(users1) / maxpage + 1
for (id, email, note) in users1[maxpage * (page - 1):(maxpage * page)]:
users.append(['', id, email, (note=="1" and 'Active' or 'Inactive')])
for col in [(((note=="1" and 'Inactivate' or 'Activate'), 'modifyaccountstatus'), ((note == "0" and 'Reject' or 'Delete'), 'rejectaccount'), ),
(('Edit account', 'editaccount'), ),]:
users[-1].append('%s' % (col[0][1], id, email_user_pattern, limit_to, maxpage, page, random.randint(0, 1000), col[0][0]))
for (str, function) in col[1:]:
users[-1][-1] += ' / %s' % (function, id, email_user_pattern, limit_to, maxpage, page, random.randint(0, 1000), str)
last = ""
next = ""
if len(users1) > maxpage:
if page > 1:
last += 'Last Page' % (email_user_pattern, limit_to, maxpage, (page - 1))
if len(users1[maxpage * (page - 1):(maxpage * page)]) == maxpage:
next += 'Next page' % (email_user_pattern, limit_to, maxpage, (page + 1))
output += 'Showing accounts %s-%s:' % (1 + maxpage * (page - 1), maxpage * page)
else:
output += '%s matching account(s):' % len(users1)
output += tupletotable(header=[last, 'id', 'email', 'Status', '', '', next], tuple=users)
else:
output += 'Please select which accounts to find and how many to show per page.'
if content:
output += " %s" % content
body = [output]
if callback:
return perform_manageaccounts(req, "perform_modifyaccounts", addadminbox(subtitle, body))
else:
return addadminbox(subtitle, body)
def perform_delegate_startarea(req):
"""start area for lower level delegation of rights."""
# refuse access to guest users:
uid = getUid(req)
if isGuestUser(uid):
return index(req=req,
title='Delegate Rights',
adminarea=0,
authorized=0)
subtitle = 'select what to do'
output = ''
if is_adminuser(req)[0] == 0:
output += """
You are also allowed to be in the Main Admin Area which gives you
the access to the full functionality of WebAccess.
specialized area to set up the delegation rights used in the areas above.
you need to be a web administrator to access the area.
"""
return index(req=req,
title='Delegate Rights',
subtitle=subtitle,
body=[output],
adminarea=0,
authorized=1)
def perform_delegate_adminsetup(req, id_role_admin=0, id_role_delegate=0, confirm=0):
"""lets the webadmins set up the delegation rights for the other roles
id_role_admin - the role to be given delegation rights
id_role_delegate - the role over which the delegation rights are given
confirm - make the connection happen """
subtitle = 'step 1 - select admin role'
- admin_roles = acca.acc_getAllRoles()
+ admin_roles = acca.acc_get_all_roles()
output = """
This is a specialized area to handle a task that also can be handled
from the "add authorization" interface.
By handling the delegation rights here you get the advantage of
not having to select the correct action (%s) or
remembering the names of available roles.
""" % (DELEGATEADDUSERROLE, )
output += createroleselect(id_role=id_role_admin,
step=1,
button='select admin role',
name='id_role_admin',
action='delegate_adminsetup',
roles=admin_roles)
if str(id_role_admin) != '0':
subtitle = 'step 2 - select delegate role'
- name_role_admin = acca.acc_getRoleName(id_role=id_role_admin)
+ name_role_admin = acca.acc_get_role_name(id_role=id_role_admin)
delegate_roles_old = acca.acc_find_delegated_roles(id_role_admin=id_role_admin)
delegate_roles = []
delegate_roles_old_names = []
for role in admin_roles:
if (role,) not in delegate_roles_old:
delegate_roles.append(role)
else:
delegate_roles_old_names.append(role[1])
if delegate_roles_old_names:
delegate_roles_old_names.sort()
names_str = ''
for name in delegate_roles_old_names:
if names_str: names_str += ', '
names_str += name
output += '
Warning: don't hand out delegation rights that can harm the system (e.g. delegating superrole).
"""
output += createhiddenform(action="delegate_adminsetup",
text='let role %s delegate rights over role %s?' % (name_role_admin, name_role_delegate),
id_role_admin=id_role_admin,
id_role_delegate=id_role_delegate,
confirm=1)
if int(confirm):
subtitle = 'step 4 - confirm delegation right added'
- # res1 = acca.acc_addRoleActionArguments_names(name_role=name_role_admin,
+ # res1 = acca.acc_add_role_action_arguments_names(name_role=name_role_admin,
# name_action=DELEGATEADDUSERROLE,
# arglistid=-1,
# optional=0,
# role=name_role_delegate)
- res1 = acca.acc_addAuthorization(name_role=name_role_admin,
+ res1 = acca.acc_add_authorization(name_role=name_role_admin,
name_action=DELEGATEADDUSERROLE,
optional=0,
role=name_role_delegate)
if res1:
output += '
confirm: role %s delegates role %s.' % (name_role_admin, name_role_delegate)
else: output += '
sorry, delegation right could not be added, it probably already exists.
'
# see if right hand menu is available
try: body = [output, extra]
except NameError: body = [output]
return index(req=req,
title='Delegate Rights',
subtitle=subtitle,
body=body,
adminarea=1)
def perform_delegate_adduserrole(req, id_role=0, email_user_pattern='', id_user=0, confirm=0):
"""let a lower level web admin add users to a limited set of roles.
id_role - the role to connect to a user
id_user - the user to connect to a role
confirm - make the connection happen """
# finding the allowed roles for this user
id_admin = getUid(req)
- id_action = acca.acc_getActionId(name_action=DELEGATEADDUSERROLE)
- actions = acca.acc_findPossibleActionsUser(id_user=id_admin, id_action=id_action)
+ id_action = acca.acc_get_action_id(name_action=DELEGATEADDUSERROLE)
+ actions = acca.acc_find_possible_actions_user(id_user=id_admin, id_action=id_action)
allowed_roles = []
allowed_id_roles = []
for (id, arglistid, name_role_help) in actions[1:]:
- id_role_help = acca.acc_getRoleId(name_role=name_role_help)
+ id_role_help = acca.acc_get_role_id(name_role=name_role_help)
if id_role_help and [id_role_help, name_role_help, ''] not in allowed_roles:
allowed_roles.append([id_role_help, name_role_help, ''])
allowed_id_roles.append(str(id_role_help))
output = ''
if not allowed_roles:
subtitle = 'no delegation rights'
output += """
You do not have the delegation rights over any roles.
If you think you should have such rights, contact a WebAccess Administrator.
Lower level delegation of access rights to roles.
An administrator with all rights have to give you these rights.
"""
- email_out = acca.acc_getUserEmail(id_user=id_user)
- name_role = acca.acc_getRoleName(id_role=id_role)
+ email_out = acca.acc_get_user_email(id_user=id_user)
+ name_role = acca.acc_get_role_name(id_role=id_role)
output += createroleselect(id_role=id_role, step=1, name='id_role',
action='delegate_adduserrole', roles=allowed_roles)
if str(id_role) != '0' and str(id_role) in allowed_id_roles:
subtitle = 'step 2 - search for users'
# remove letters not allowed in an email
email_user_pattern = cleanstring_email(email_user_pattern)
text = ' 2. search for user \n'
text += ' \n' % (email_user_pattern, )
output += createhiddenform(action="delegate_adduserrole",
text=text,
button="search for users",
id_role=id_role)
# pattern is entered
if email_user_pattern:
# users with matching email-address
users1 = run_sql("""SELECT id, email FROM user WHERE email RLIKE '%s' ORDER BY email """ % (email_user_pattern, ))
# users that are connected
users2 = run_sql("""SELECT DISTINCT u.id, u.email
FROM user u LEFT JOIN user_accROLE ur ON u.id = ur.id_user
WHERE ur.id_accROLE = '%s' AND u.email RLIKE '%s'
ORDER BY u.email """ % (id_role, email_user_pattern))
# no users that match the pattern
if not (users1 or users2):
output += '
no qualified users, try new search.
'
# too many matching users
elif len(users1) > MAXSELECTUSERS:
output += '
%s hits, too many qualified users, specify more narrow search. (limit %s)
' % (len(users1), MAXSELECTUSERS)
# show matching users
else:
subtitle = 'step 3 - select a user'
users = []
extrausers = []
for (id, email) in users1:
if (id, email) not in users2: users.append([id,email,''])
for (id, email) in users2:
extrausers.append([-id, email,''])
output += createuserselect(id_user=id_user,
action="delegate_adduserrole",
step=3,
users=users,
extrausers=extrausers,
button="add this user",
id_role=id_role,
email_user_pattern=email_user_pattern)
try: id_user = int(id_user)
except ValueError: pass
# user selected already connected to role
if id_user < 0:
output += '
users in brackets are already attached to the role, try another one...
'
# a user is selected
elif email_out:
subtitle = "step 4 - confirm to add user"
output += createhiddenform(action="delegate_adduserrole",
text='add user %s to role %s?' % (email_out, name_role),
id_role=id_role,
email_user_pattern=email_user_pattern,
id_user=id_user,
confirm=1)
# it is confirmed that this user should be added
if confirm:
# add user
- result = acca.acc_addUserRole(id_user=id_user, id_role=id_role)
+ result = acca.acc_add_user_role(id_user=id_user, id_role=id_role)
if result and result[2]:
subtitle = 'step 5 - confirm user added'
output += '
confirm: user %s added to role %s.
' % (email_out, name_role)
else:
subtitle = 'step 5 - user could not be added'
output += '
remove users from the roles you have delegating rights to.
""" % (id_role, )
return index(req=req,
title='Connect users to roles',
subtitle=subtitle,
body=[output, extra],
adminarea=1,
authorized=1)
def perform_delegate_deleteuserrole(req, id_role=0, id_user=0, confirm=0):
"""let a lower level web admin remove users from a limited set of roles.
id_role - the role to connect to a user
id_user - the user to connect to a role
confirm - make the connection happen """
subtitle = 'in progress...'
output = '
in progress...
'
# finding the allowed roles for this user
id_admin = getUid(req)
- id_action = acca.acc_getActionId(name_action=DELEGATEADDUSERROLE)
- actions = acca.acc_findPossibleActionsUser(id_user=id_admin, id_action=id_action)
+ id_action = acca.acc_get_action_id(name_action=DELEGATEADDUSERROLE)
+ actions = acca.acc_find_possible_actions_user(id_user=id_admin, id_action=id_action)
output = ''
if not actions:
subtitle = 'no delegation rights'
output += """
You do not have the delegation rights over any roles.
If you think you should have such rights, contact a WebAccess Administrator.
Lower level delegation of access rights to roles.
An administrator with all rights have to give you these rights.
"""
- email_out = acca.acc_getUserEmail(id_user=id_user)
- name_role = acca.acc_getRoleName(id_role=id_role)
+ email_out = acca.acc_get_user_email(id_user=id_user)
+ name_role = acca.acc_get_role_name(id_role=id_role)
# create list of allowed roles
allowed_roles = []
allowed_id_roles = []
for (id, arglistid, name_role_help) in actions[1:]:
- id_role_help = acca.acc_getRoleId(name_role=name_role_help)
+ id_role_help = acca.acc_get_role_id(name_role=name_role_help)
if id_role_help and [id_role_help, name_role_help, ''] not in allowed_roles:
allowed_roles.append([id_role_help, name_role_help, ''])
allowed_id_roles.append(str(id_role_help))
output += createroleselect(id_role=id_role, step=1,
action='delegate_deleteuserrole', roles=allowed_roles)
if str(id_role) != '0' and str(id_role) in allowed_id_roles:
subtitle = 'step 2 - select user'
- users = acca.acc_getRoleUsers(id_role)
+ users = acca.acc_get_role_users(id_role)
output += createuserselect(id_user=id_user,
step=2,
action='delegate_deleteuserrole',
users=users,
id_role=id_role)
if str(id_user) != '0':
subtitle = 'step 3 - confirm delete of user'
- email_user = acca.acc_getUserEmail(id_user=id_user)
+ email_user = acca.acc_get_user_email(id_user=id_user)
output += createhiddenform(action="delegate_deleteuserrole",
text='delete user %s from %s?'
% (headerstrong(user=id_user), headerstrong(role=id_role)),
id_role=id_role,
id_user=id_user,
confirm=1)
if confirm:
- res = acca.acc_deleteUserRole(id_user=id_user, id_role=id_role)
+ res = acca.acc_delete_user_role(id_user=id_user, id_role=id_role)
if res:
subtitle = 'step 4 - confirm user deleted from role'
output += '
confirm: deleted user %s from role %s.
' % (email_user, name_role)
else:
subtitle = 'step 4 - user could not be deleted'
output += 'sorry, but user could not be deleted user is probably already deleted.'
extra = """
""" % (id_role, name_role, id_role, name_role)
try: body = [output, extra]
except NameError: body = [output]
return index(req=req,
title=title,
body=body,
subtitle=subtitle,
adminarea=3)
def perform_modifyrole(req, id_role='0', name_role='', description='put description here.', firerole_def_src='', modified='0', confirm=0):
"""form to add a new role with these values:
name_role - name of the role to be changed
description - optional description of the role
firerole_def_src - optional firerole like definition of the role
"""
(auth_code, auth_message) = is_adminuser(req)
if auth_code != 0: return mustloginpage(req, auth_message)
- ret = acca.acc_getRoleDetails(id_role)
+ ret = acca.acc_get_role_details(id_role)
if ret and modified =='0':
name_role = ret[1]
description = ret[2]
firerole_def_src = ret[3]
if not firerole_def_src or firerole_def_src == '' or firerole_def_src is None:
firerole_def_src = 'deny any'
name_role = cleanstring(name_role)
title='Modify Role'
subtitle = 'step 1 - give values to the requested fields and confirm to modify role'
output = """
""" % (id_role, escape_string(name_role), escape(description), escape(firerole_def_src))
if modified in [1, '1']:
# description must be changed before submitting
internaldesc = ''
if description != 'put description here.':
internaldesc = description
text = """
modify role with: \n
name: %s """ % (name_role, )
if internaldesc:
text += 'description: %s? ' % (description, )
text += 'firewall like role definition: %s' % firerole_def_src.replace('\n', ' ')
try:
firerole_def_ser = serialize(compile_role_definition(firerole_def_src))
except InvenioWebAccessFireroleError, msg:
subtitle = 'step 2 - role could not be modified'
output += '
sorry, could not modify role because of troubles with its definition: %s
' % msg
else:
output += createhiddenform(action="modifyrole",
text=text,
id_role = id_role,
name_role=escape(name_role, True),
description=escape(description, True),
firerole_def_src=escape(firerole_def_src, True),
modified=1,
confirm=1)
if confirm not in ["0", 0]:
- result = acca.acc_updateRole(id_role, name_role=name_role,
+ result = acca.acc_update_role(id_role, name_role=name_role,
description=internaldesc, firerole_def_ser=firerole_def_ser, firerole_def_src=firerole_def_src)
if result:
subtitle = 'step 2 - role modified'
output += '
role modified:
'
output += tupletotable(header=['id', 'role name',
'description', 'firewall like role definition'],
tuple=[(id_role, name_role, description, firerole_def_src.replace('\n', ' '))])
else:
subtitle = 'step 2 - role could not be modified'
output += '
sorry, could not modify role, please contact the administrator.
'
body = [output]
return index(req=req,
title=title,
body=body,
subtitle=subtitle,
adminarea=3)
def perform_deleterole(req, id_role="0", confirm=0):
"""select a role and show all connected information,
users - users that can access the role.
actions - actions with possible authorizations."""
(auth_code, auth_message) = is_adminuser(req)
if auth_code != 0: return mustloginpage(req, auth_message)
title = 'Delete role'
subtitle = 'step 1 - select role to delete'
- name_role = acca.acc_getRoleName(id_role=id_role)
+ name_role = acca.acc_get_role_name(id_role=id_role)
output = createroleselect(id_role=id_role,
action="deleterole",
step=1,
- roles=acca.acc_getAllRoles(),
+ roles=acca.acc_get_all_roles(),
button="delete role")
if id_role != "0" and name_role:
subtitle = 'step 2 - confirm delete of role'
output += roledetails(id_role=id_role)
output += createhiddenform(action="deleterole",
text='delete role %s and all connections?' % (name_role, ),
id_role=id_role,
confirm=1)
if confirm:
- res = acca.acc_deleteRole(id_role=id_role)
+ res = acca.acc_delete_role(id_role=id_role)
subtitle = 'step 3 - confirm role deleted'
if res:
output += "
confirm: role %s deleted. " % (name_role, )
output += "%s entries were removed.
" % (res, )
else:
output += "
sorry, the role could not be deleted.
"
elif id_role != "0":
output += '
the role has been deleted...
'
return index(req=req,
title=title,
subtitle=subtitle,
body=[output],
adminarea=3)
def perform_showroledetails(req, id_role):
"""show the details of a role."""
(auth_code, auth_message) = is_adminuser(req)
if auth_code != 0: return mustloginpage(req, auth_message)
output = createroleselect(id_role=id_role,
action="showroledetails",
step=1,
- roles=acca.acc_getAllRoles(),
+ roles=acca.acc_get_all_roles(),
button="select role")
if id_role not in [0, '0']:
- name_role = acca.acc_getRoleName(id_role=id_role)
+ name_role = acca.acc_get_role_name(id_role=id_role)
output += roledetails(id_role=id_role)
extra = """
'
return details
def perform_adduserrole(req, id_role='0', email_user_pattern='', id_user='0', confirm=0):
"""create connection between user and role.
id_role - id of the role to add user to
email_user_pattern - search for users using this pattern
id_user - id of user to add to the role. """
(auth_code, auth_message) = is_adminuser(req)
if auth_code != 0: return mustloginpage(req, auth_message)
- email_out = acca.acc_getUserEmail(id_user=id_user)
- name_role = acca.acc_getRoleName(id_role=id_role)
+ email_out = acca.acc_get_user_email(id_user=id_user)
+ name_role = acca.acc_get_role_name(id_role=id_role)
title = 'Connect user to role '
subtitle = 'step 1 - select a role'
output = createroleselect(id_role=id_role,
action="adduserrole",
step=1,
- roles=acca.acc_getAllRoles())
+ roles=acca.acc_get_all_roles())
# role is selected
if id_role != "0":
title += name_role
subtitle = 'step 2 - search for users'
# remove letters not allowed in an email
email_user_pattern = cleanstring_email(email_user_pattern)
text = ' 2. search for user \n'
text += ' \n' % (email_user_pattern, )
output += createhiddenform(action="adduserrole",
text=text,
button="search for users",
id_role=id_role)
# pattern is entered
if email_user_pattern:
# users with matching email-address
users1 = run_sql("""SELECT id, email FROM user WHERE email RLIKE '%s' ORDER BY email """ % (email_user_pattern, ))
# users that are connected
users2 = run_sql("""SELECT DISTINCT u.id, u.email
FROM user u LEFT JOIN user_accROLE ur ON u.id = ur.id_user
WHERE ur.id_accROLE = '%s' AND u.email RLIKE '%s'
ORDER BY u.email """ % (id_role, email_user_pattern))
# no users that match the pattern
if not (users1 or users2):
output += '
no qualified users, try new search.
'
elif len(users1) > MAXSELECTUSERS:
output += '
%s hits, too many qualified users, specify more narrow search. (limit %s)
' % (len(users1), MAXSELECTUSERS)
# show matching users
else:
subtitle = 'step 3 - select a user'
users = []
extrausers = []
for (user_id, email) in users1:
if (user_id, email) not in users2: users.append([user_id,email,''])
for (user_id, email) in users2:
extrausers.append([-user_id, email,''])
output += createuserselect(id_user=id_user,
action="adduserrole",
step=3,
users=users,
extrausers=extrausers,
button="add this user",
id_role=id_role,
email_user_pattern=email_user_pattern)
try: id_user = int(id_user)
except ValueError: pass
# user selected already connected to role
if id_user < 0:
output += '
users in brackets are already attached to the role, try another one...
'
# a user is selected
elif email_out:
subtitle = "step 4 - confirm to add user"
output += createhiddenform(action="adduserrole",
text='add user %s to role %s?' % (email_out, name_role),
id_role=id_role,
email_user_pattern=email_user_pattern,
id_user=id_user,
confirm=1)
# it is confirmed that this user should be added
if confirm:
# add user
- result = acca.acc_addUserRole(id_user=id_user, id_role=id_role)
+ result = acca.acc_add_user_role(id_user=id_user, id_role=id_role)
if result and result[2]:
subtitle = 'step 5 - confirm user added'
output += '
confirm: user %s added to role %s.
' % (email_out, name_role)
else:
subtitle = 'step 5 - user could not be added'
output += '
""" % (id_role, name_role, id_role, name_role, id_role, name_role)
return index(req=req,
title=title,
subtitle=subtitle,
body=[output, extra],
adminarea=3)
def perform_addroleuser(req, email_user_pattern='', id_user='0', id_role='0', confirm=0):
"""delete connection between role and user.
id_role - id of role to disconnect
id_user - id of user to disconnect. """
(auth_code, auth_message) = is_adminuser(req)
if auth_code != 0: return mustloginpage(req, auth_message)
- email_out = acca.acc_getUserEmail(id_user=id_user)
- name_role = acca.acc_getRoleName(id_role=id_role)
+ email_out = acca.acc_get_user_email(id_user=id_user)
+ name_role = acca.acc_get_role_name(id_role=id_role)
# used to sort roles, and also to determine right side links
con_roles = []
not_roles = []
title = 'Connect user to roles'
subtitle = 'step 1 - search for users'
# clean email search string
email_user_pattern = cleanstring_email(email_user_pattern)
text = ' 1. search for user \n'
text += ' \n' % (email_user_pattern, )
output = createhiddenform(action='addroleuser',
text=text,
button='search for users',
id_role=id_role)
if email_user_pattern:
subtitle = 'step 2 - select user'
users1 = run_sql("""SELECT id, email FROM user WHERE email RLIKE '%s' ORDER BY email """ % (email_user_pattern, ))
users = []
for (id, email) in users1: users.append([id, email, ''])
# no users
if not users:
output += '
no qualified users, try new search.
'
# too many users
elif len(users) > MAXSELECTUSERS:
output += '
%s hits, too many qualified users, specify more narrow search. (limit %s)
' % (len(users), MAXSELECTUSERS)
# ok number of users
else:
output += createuserselect(id_user=id_user,
action='addroleuser',
step=2,
users=users,
button='select user',
email_user_pattern=email_user_pattern)
if int(id_user):
subtitle = 'step 3 - select role'
# roles the user is connected to
- role_ids = acca.acc_getUserRoles(id_user=id_user)
+ role_ids = acca.acc_get_user_roles(id_user=id_user)
# all the roles, lists are sorted on the background of these...
- all_roles = acca.acc_getAllRoles()
+ all_roles = acca.acc_get_all_roles()
# sort the roles in connected and not connected roles
for (id, name, description) in all_roles:
if (id, ) in role_ids: con_roles.append([-id, name, description])
else: not_roles.append([id, name, description])
# create roleselect
output += createroleselect(id_role=id_role,
action='addroleuser',
step=3,
roles=not_roles,
extraroles=con_roles,
extrastamp='(connected)',
button='add this role',
email_user_pattern=email_user_pattern,
id_user=id_user)
if int(id_role) < 0:
- name_role = acca.acc_getRoleName(id_role=-int(id_role))
+ name_role = acca.acc_get_role_name(id_role=-int(id_role))
output += '
role %s already connected to the user, try another one...
' % (name_role, )
elif int(id_role):
subtitle = 'step 4 - confirm to add role to user'
output += createhiddenform(action='addroleuser',
text='add role %s to user %s?' % (name_role, email_out),
email_user_pattern=email_user_pattern,
id_user=id_user,
id_role=id_role,
confirm=1)
if confirm:
# add role
- result = acca.acc_addUserRole(id_user=id_user, id_role=id_role)
+ result = acca.acc_add_user_role(id_user=id_user, id_role=id_role)
if result and result[2]:
subtitle = 'step 5 - confirm role added'
output += '
confirm: role %s added to user %s.
' % (name_role, email_out)
else:
subtitle = 'step 5 - role could not be added'
output += '
""" % (id_role, name_role)
return index(req=req,
title=title,
subtitle=subtitle,
body=[output, extra],
adminarea=5)
def perform_deleteuserrole(req, id_role='0', id_user='0', reverse=0, confirm=0):
"""delete connection between role and user.
id_role - id of role to disconnect
id_user - id of user to disconnect. """
(auth_code, auth_message) = is_adminuser(req)
if auth_code != 0: return mustloginpage(req, auth_message)
title = 'Remove user from role'
- email_user = acca.acc_getUserEmail(id_user=id_user)
- name_role = acca.acc_getRoleName(id_role=id_role)
+ email_user = acca.acc_get_user_email(id_user=id_user)
+ name_role = acca.acc_get_role_name(id_role=id_role)
output = ''
if reverse in [0, '0']:
adminarea = 3
subtitle = 'step 1 - select the role'
output += createroleselect(id_role=id_role,
action="deleteuserrole",
step=1,
- roles=acca.acc_getAllRoles())
+ roles=acca.acc_get_all_roles())
if id_role != "0":
subtitle = 'step 2 - select the user'
output += createuserselect(id_user=id_user,
action="deleteuserrole",
step=2,
- users=acca.acc_getRoleUsers(id_role=id_role),
+ users=acca.acc_get_role_users(id_role=id_role),
id_role=id_role)
else:
adminarea = 5
# show only if user is connected to a role, get users connected to roles
users = run_sql("""SELECT DISTINCT(u.id), u.email, u.note
FROM user u LEFT JOIN user_accROLE ur
ON u.id = ur.id_user
WHERE ur.id_accROLE != 'NULL' AND u.email != ''
ORDER BY u.email """)
has_roles = 1
# check if the user is connected to any roles
for (id, email, note) in users:
if str(id) == str(id_user): break
# user not connected to a role
else:
subtitle = 'step 1 - user not connected'
output += '
no need to remove roles from user %s, user is not connected to any roles.
' % (email_user, )
has_roles, id_user = 0, '0' # stop the rest of the output below...
# user connected to roles
if has_roles:
output += createuserselect(id_user=id_user,
action="deleteuserrole",
step=1,
users=users,
reverse=reverse)
if id_user != "0":
subtitle = 'step 2 - select the role'
- role_ids = acca.acc_getUserRoles(id_user=id_user)
- all_roles = acca.acc_getAllRoles()
+ role_ids = acca.acc_get_user_roles(id_user=id_user)
+ all_roles = acca.acc_get_all_roles()
roles = []
for (id, name, desc) in all_roles:
if (id, ) in role_ids: roles.append([id, name, desc])
output += createroleselect(id_role=id_role,
action="deleteuserrole",
step=2,
roles=roles,
id_user=id_user,
reverse=reverse)
if id_role != '0' and id_user != '0':
subtitle = 'step 3 - confirm delete of user'
output += createhiddenform(action="deleteuserrole",
text='delete user %s from %s?' % (headerstrong(user=id_user), headerstrong(role=id_role)),
id_role=id_role,
id_user=id_user,
reverse=reverse,
confirm=1)
if confirm:
- res = acca.acc_deleteUserRole(id_user=id_user, id_role=id_role)
+ res = acca.acc_delete_user_role(id_user=id_user, id_role=id_role)
if res:
subtitle = 'step 4 - confirm delete of user'
output += '
confirm: deleted user %s from role %s.
' % (email_user, name_role)
else:
subtitle = 'step 4 - user could not be deleted'
output += 'sorry, but user could not be deleted user is probably already deleted.'
extra = ''
if str(id_role) != "0":
extra += """
' % (email_user, )
return details
def perform_addauthorization(req, id_role="0", id_action="0", optional=0, reverse="0", confirm=0, **keywords):
""" form to add new connection between user and role:
id_role - role to connect
id_action - action to connect
reverse - role or action first? """
(auth_code, auth_message) = is_adminuser(req)
if auth_code != 0: return mustloginpage(req, auth_message)
# values that might get used
- name_role = acca.acc_getRoleName(id_role=id_role) or id_role
- name_action = acca.acc_getActionName(id_action=id_action) or id_action
+ name_role = acca.acc_get_role_name(id_role=id_role) or id_role
+ name_action = acca.acc_get_action_name(id_action=id_action) or id_action
optional = optional == 'on' and 1 or int(optional)
extra = """
"""
# create the page according to which step the user is on
# role -> action -> arguments
if reverse in ["0", 0]:
adminarea = 3
subtitle = 'step 1 - select role'
output = createroleselect(id_role=id_role,
action="addauthorization",
step=1,
- roles=acca.acc_getAllRoles(),
+ roles=acca.acc_get_all_roles(),
reverse=reverse)
if str(id_role) != "0":
subtitle = 'step 2 - select action'
- rolacts = acca.acc_getRoleActions(id_role)
- allhelp = acca.acc_getAllActions()
+ rolacts = acca.acc_get_role_actions(id_role)
+ allhelp = acca.acc_get_all_actions()
allacts = []
for r in allhelp:
if r not in rolacts: allacts.append(r)
output += createactionselect(id_action=id_action,
action="addauthorization",
step=2,
actions=rolacts,
extraactions=allacts,
id_role=id_role,
reverse=reverse)
# action -> role -> arguments
else:
adminarea = 4
subtitle = 'step 1 - select action'
output = createactionselect(id_action=id_action,
action="addauthorization",
step=1,
- actions=acca.acc_getAllActions(),
+ actions=acca.acc_get_all_actions(),
reverse=reverse)
if str(id_action) != "0":
subtitle = 'step 2 - select role'
- actroles = acca.acc_getActionRoles(id_action)
- allhelp = acca.acc_getAllRoles()
+ actroles = acca.acc_get_action_roles(id_action)
+ allhelp = acca.acc_get_all_roles()
allroles = []
for r in allhelp:
if r not in actroles: allroles.append(r)
output += createroleselect(id_role=id_role,
action="addauthorization",
step=2,
roles=actroles,
extraroles=allroles,
id_action=id_action,
reverse=reverse)
# ready for step 3 no matter which direction we took to get here
if id_action != "0" and id_role != "0":
# links to adding authorizations in the other direction
if str(reverse) == "0":
extra += """
sorry, authorization could not be added, it probably already exists
'
# trying to put extra link on the right side
try: body = [output, extra]
except NameError: body = [output]
return index(req=req,
title = 'Create entry for new authorization',
subtitle=subtitle,
body=body,
adminarea=adminarea)
def perform_deleteroleaction(req, id_role="0", id_action="0", reverse=0, confirm=0):
"""delete all connections between a role and an action.
id_role - id of the role
id_action - id of the action
reverse - 0: ask for role first
1: ask for action first"""
(auth_code, auth_message) = is_adminuser(req)
if auth_code != 0: return mustloginpage(req, auth_message)
title = 'Remove action from role '
if reverse in ["0", 0]:
# select role -> action
adminarea = 3
subtitle = 'step 1 - select a role'
output = createroleselect(id_role=id_role,
action="deleteroleaction",
step=1,
- roles=acca.acc_getAllRoles(),
+ roles=acca.acc_get_all_roles(),
reverse=reverse)
if id_role != "0":
- rolacts = acca.acc_getRoleActions(id_role=id_role)
+ rolacts = acca.acc_get_role_actions(id_role=id_role)
subtitle = 'step 2 - select the action'
output += createactionselect(id_action=id_action,
action="deleteroleaction",
step=2,
actions=rolacts,
reverse=reverse,
id_role=id_role,
button="remove connection and all authorizations")
else:
# select action -> role
adminarea = 4
subtitle = 'step 1 - select an action'
output = createactionselect(id_action=id_action,
action="deleteroleaction",
step=1,
- actions=acca.acc_getAllActions(),
+ actions=acca.acc_get_all_actions(),
reverse=reverse)
if id_action != "0":
- actroles = acca.acc_getActionRoles(id_action=id_action)
+ actroles = acca.acc_get_action_roles(id_action=id_action)
subtitle = 'step 2 - select the role'
output += createroleselect(id_role=id_role,
action="deleteroleaction",
step=2,
roles=actroles,
button="remove connection and all authorizations",
id_action=id_action,
reverse=reverse)
if id_action != "0" and id_role != "0":
subtitle = 'step 3 - confirm to remove authorizations'
# ask for confirmation
- res = acca.acc_findPossibleActions(id_role, id_action)
+ res = acca.acc_find_possible_actions(id_role, id_action)
if res:
output += '
authorizations that will be deleted:
'
output += tupletotable(header=res[0], tuple=res[1:])
output += createhiddenform(action="deleteroleaction",
text='remove %s from %s' % (headerstrong(action=id_action), headerstrong(role=id_role)),
confirm=1,
id_role=id_role,
id_action=id_action,
reverse=reverse)
else:
output += 'no authorizations'
# confirmation is given
if confirm:
subtitle = 'step 4 - confirm authorizations removed '
- res = acca.acc_deleteRoleAction(id_role=id_role, id_action=id_action)
+ res = acca.acc_delete_role_action(id_role=id_role, id_action=id_action)
if res:
output += '
confirm: removed %s from %s ' % (headerstrong(action=id_action), headerstrong(role=id_role))
output += '%s entries were removed.
' % (res, )
else:
output += '
sorry, no entries could be removed.
'
return index(req=req,
title=title,
subtitle=subtitle,
body=[output],
adminarea=adminarea)
def perform_modifyauthorizations(req, id_role="0", id_action="0", reverse=0, confirm=0, errortext='', sel='', authids=[]):
"""given ids of a role and an action, show all possible action combinations
with checkboxes and allow user to access other functions.
id_role - id of the role
id_action - id of the action
reverse - 0: ask for role first
1: ask for action first
sel - which button and modification that is selected
errortext - text to print when no connection exist between role and action
authids - ids of checked checkboxes """
(auth_code, auth_message) = is_adminuser(req)
if auth_code != 0: return mustloginpage(req, auth_message)
- name_role = acca.acc_getRoleName(id_role)
- name_action = acca.acc_getActionName(id_action)
+ name_role = acca.acc_get_role_name(id_role)
+ name_action = acca.acc_get_action_name(id_action)
output = ''
try: id_role, id_action, reverse = int(id_role), int(id_action), int(reverse)
except ValueError: pass
extra = """
' % (errortext, )
if id_role and id_action:
# adding to main area
if type(authids) is not list: authids = [authids]
subtitle = 'step 3 - select groups and modification'
# get info
- res = acca.acc_findPossibleActions(id_role, id_action)
+ res = acca.acc_find_possible_actions(id_role, id_action)
# clean the authids
hiddenids = []
if sel in ['delete selected']:
hiddenids = authids[:]
elif sel in ['split groups', 'merge groups']:
for authid in authids:
arghlp = res[int(authid)][0]
if authid not in hiddenids and arghlp not in [-1, '-1', 0, '0']: hiddenids.append(authid)
authids = hiddenids[:]
if confirm:
# do selected modification and output with new authorizations
if sel == 'split groups':
res = splitgroups(id_role, id_action, authids)
elif sel == 'merge groups':
res = mergegroups(id_role, id_action, authids)
elif sel == 'delete selected':
res = deleteselected(id_role, id_action, authids)
authids = []
- res = acca.acc_findPossibleActions(id_role, id_action)
+ res = acca.acc_find_possible_actions(id_role, id_action)
output += 'authorizations after %s. \n' % (sel, )
elif sel and authids:
output += 'confirm choice of authorizations and modification. \n'
else:
output += 'select authorizations and perform modification. \n'
if not res:
errortext='all connections deleted, try different '
if reverse in ["0", 0]:
return perform_modifyauthorizations(req=req, id_role=id_role, errortext=errortext + 'action.')
else:
return perform_modifyauthorizations(req=req, id_action=id_action, reverse=reverse, errortext=errortext + 'role.')
# display
output += modifyauthorizationsmenu(id_role, id_action, header=res[0], tuple=res[1:], checked=authids, reverse=reverse)
if sel and authids:
subtitle = 'step 4 - confirm to perform modification'
# form with hidden authids
output += ''
# tried to perform modification without something selected
elif sel and not authids and not confirm:
output += '
no valid groups selected
'
# trying to put extra link on the right side
try: body = [output, extra]
except NameError: body = [output]
# Display the page
return index(req=req,
title='Modify Authorizations',
subtitle=subtitle,
body=body,
adminarea=adminarea)
def modifyauthorizationsmenu(id_role, id_action, tuple=[], header=[], checked=[], reverse=0):
"""create table with header and checkboxes, used for multiple choice.
makes use of tupletotable to add the actual table
id_role - selected role, hidden value in the form
id_action - selected action, hidden value in the form
tuple - all rows to be put in the table (with checkboxes)
header - column headers, empty strings added at start and end
checked - ids of rows to be checked """
if not tuple:
return 'no authorisations...'
- argnum = len(acca.acc_getActionKeywords(id_action=id_action))
+ argnum = len(acca.acc_get_action_keywords(id_action=id_action))
tuple2 = []
for t in tuple: tuple2.append(t[:])
tuple2 = addcheckboxes(datalist=tuple2, name='authids', startindex=1, checked=checked)
hidden = ' \n' % (id_role, )
hidden += ' \n' % (id_action, )
hidden += ' \n' % (reverse, )
button = '\n'
if argnum > 1:
button += '\n'
button += '\n'
hdrstr = ''
for h in [''] + header + ['']: hdrstr += '
%s
\n' % (h, )
if hdrstr: hdrstr = '
\n%s\n
\n' % (hdrstr, )
output = '\n'
return output
def splitgroups(id_role=0, id_action=0, authids=[]):
"""get all the old ones, gather up the arglistids find a list of
arglistidgroups to be split, unique get all actions in groups outside
of the old ones, (old arglistid is allowed).
show them like in showselect. """
if not id_role or not id_action or not authids:
return 0
# find all the actions
- datalist = acca.acc_findPossibleActions(id_role, id_action)
+ datalist = acca.acc_find_possible_actions(id_role, id_action)
if type(authids) is str: authids = [authids]
for i in range(len(authids)): authids[i] = int(authids[i])
# argumentlistids of groups to be split
splitgrps = []
for authid in authids:
hlp = datalist[authid][0]
if hlp not in splitgrps and authid in range(1,len(datalist)):
splitgrps.append(hlp)
# split groups and return success or failure
result = 1
for splitgroup in splitgrps:
- result = 1 and acca.acc_splitArgumentGroup(id_role, id_action, splitgroup)
+ result = 1 and acca.acc_split_argument_group(id_role, id_action, splitgroup)
return result
def mergegroups(id_role=0, id_action=0, authids=[]):
"""get all the old ones, gather up the argauthids find a list
of arglistidgroups to be split, unique get all actions in groups
outside of the old ones, (old arglistid is allowed).
show them like in showselect."""
if not id_role or not id_action or not authids:
return 0
- datalist = acca.acc_findPossibleActions(id_role, id_action)
+ datalist = acca.acc_find_possible_actions(id_role, id_action)
if type(authids) is str: authids = [authids]
for i in range(len(authids)): authids[i] = int(authids[i])
# argumentlistids of groups to be merged
mergegroups = []
for authid in authids:
hlp = datalist[authid][0]
if hlp not in mergegroups and authid in range(1, len(datalist)):
mergegroups.append(hlp)
# merge groups and return success or failure
- if acca.acc_mergeArgumentGroups(id_role, id_action, mergegroups):
+ if acca.acc_merge_argument_groups(id_role, id_action, mergegroups):
return 1
else:
return 0
def deleteselected(id_role=0, id_action=0, authids=[]):
"""delete checked authorizations/possible actions, ids in authids.
id_role - role to delete from
id_action - action to delete from
authids - listids for which possible actions to delete."""
if not id_role or not id_action or not authids:
return 0
if type(authids) in [str, int]: authids = [authids]
for i in range(len(authids)): authids[i] = int(authids[i])
- result = acca.acc_deletePossibleActions(id_role=id_role,
+ result = acca.acc_delete_possible_actions(id_role=id_role,
id_action=id_action,
authids=authids)
return result
def headeritalic(**ids):
"""transform keyword=value pairs to string with value in italics.
**ids - a dictionary of pairs to create string from """
output = ''
value = ''
table = ''
for key in ids.keys():
if key in ['User', 'user']:
value, table = 'email', 'user'
elif key in ['Role', 'role']:
value, table = 'name', 'accROLE'
elif key in ['Action', 'action']:
value, table = 'name', 'accACTION'
else:
if output: output += ' and '
output += ' %s %s' % (key, ids[key])
continue
res = run_sql("""SELECT %s FROM %s WHERE id = %s""" % (value, table, ids[key]))
if res:
if output: output += ' and '
output += ' %s %s' % (key, res[0][0])
return output
def headerstrong(query=1, **ids):
"""transform keyword=value pairs to string with value in strong text.
**ids - a dictionary of pairs to create string from
query - 1 -> try to find names to ids of role, user and action.
0 -> do not try to find names, use the value passed on """
output = ''
value = ''
table = ''
for key in ids.keys():
if key in ['User', 'user']:
value, table = 'email', 'user'
elif key in ['Role', 'role']:
value, table = 'name', 'accROLE'
elif key in ['Action', 'action']:
value, table = 'name', 'accACTION'
else:
if output: output += ' and '
output += ' %s %s' % (key, ids[key])
continue
if query:
res = run_sql("""SELECT %s FROM %s WHERE id = %s""" % (value, table, ids[key]))
if res:
if output: output += ' and '
output += ' %s %s' % (key, res[0][0])
else:
if output: output += ' and '
output += ' %s %s' % (key, ids[key])
return output
def startpage():
"""create the menu for the startpage"""
body = """
"""
return body
def rankarea():
return "Rankmethod area"
def perform_simpleauthorization(req, id_role=0, id_action=0):
"""show a page with simple overview of authorizations between a
connected role and action. """
(auth_code, auth_message) = is_adminuser(req)
if auth_code != 0: return mustloginpage(req, auth_message)
- res = acca.acc_findPossibleActions(id_role, id_action)
+ res = acca.acc_find_possible_actions(id_role, id_action)
if res:
extra = createhiddenform(action='modifyauthorizations',
button='modify authorizations',
id_role=id_role,
id_action=id_action)
output = '
authorizations for %s:
' % (headerstrong(action=id_action, role=id_role), )
output += tupletotable(header=res[0], tuple=res[1:], extracolumn=extra)
else:
output = 'no details to show'
return index(req=req,
title='Simple authorization details',
subtitle='simple authorization details',
body=[output],
adminarea=3)
def perform_showroleusers(req, id_role=0):
"""show a page with simple overview of a role and connected users. """
(auth_code, auth_message) = is_adminuser(req)
if auth_code != 0: return mustloginpage(req, auth_message)
- res = acca.acc_getRoleUsers(id_role=id_role)
- name_role = acca.acc_getRoleName(id_role=id_role)
+ res = acca.acc_get_role_users(id_role=id_role)
+ name_role = acca.acc_get_role_name(id_role=id_role)
if res:
users = []
for (role_id, name, dummy) in res: users.append([role_id, name, 'show user details'
% (role_id, )])
output = '
users connected to %s:
' % (headerstrong(role=id_role), )
output += tupletotable(header=['id', 'name', ''], tuple=users)
else:
output = 'no users connected to role %s' % (name_role, )
extra = """
""" % (id_role, )
return index(req=req,
title='Users connected to role %s' % (name_role, ),
subtitle='simple details',
body=[output, extra],
adminarea=3)
def createselect(id_input="0", label="", step=0, name="",
action="", list=[], extralist=[], extrastamp='',
button="", **hidden):
"""create form with select and hidden values
id - the one to choose as selected if exists
label - label shown to the left of the select
name - the name of the select on which to reference it
list - primary list to select from
extralist - list of options to be put in paranthesis
extrastamp - stamp extralist entries with this if not ''
usually paranthesis around the entry
button - the value/text to be put on the button
**hidden - name=value pairs to be put as hidden in the form. """
step = step and '%s. ' % step or ''
output = '\n'
return output
def createactionselect(id_action="0", label="select action", step=0, name="id_action",
action="", actions=[], extraactions=[], extrastamp='',
button="select action", **hidden):
"""create a select for roles in a form. see createselect."""
return createselect(id_input=id_action, label=label, step=step, name=name,
action=action, list=actions, extralist=extraactions, extrastamp=extrastamp,
button=button, **hidden)
def createroleselect(id_role="0", label="select role", step=0, name="id_role",
action="", roles=[], extraroles=[], extrastamp='',
button="select role", **hidden):
"""create a select for roles in a form. see createselect."""
return createselect(id_input=id_role, label=label, step=step, name=name,
action=action, list=roles, extralist=extraroles, extrastamp=extrastamp,
button=button, **hidden)
def createuserselect(id_user="0", label="select user", step=0, name="id_user",
action="", users=[], extrausers=[], extrastamp='(connected)',
button="select user", **hidden):
"""create a select for users in a form.see createselect."""
return createselect(id_input=id_user, label=label, step=step, name=name,
action=action, list=users, extralist=extrausers, extrastamp=extrastamp,
button=button, **hidden)
def cleanstring(txt='', comma=0):
"""clean all the strings before submitting to access control admin.
remove characters not letter, number or underscore, also remove leading
underscores and numbers. return cleaned string.
str - string to be cleaned
comma - 1 -> allow the comma to divide multiple arguments
0 -> wash commas as well """
# remove not allowed characters
txt = re.sub(r'[^a-zA-Z0-9_,]', '', txt)
# split string on commas
items = txt.split(',')
txt = ''
for item in items:
if not item: continue
if comma and txt: txt += ','
# create valid variable names
txt += re.sub(r'^([0-9_])*', '', item)
return txt
def cleanstring_argumentvalue(txt=''):
"""clean the value of an argument before submitting it.
allowed characters: a-z A-Z 0-9 _ and space
txt - string to be cleaned """
# remove not allowed characters
txt = re.sub(r'[^a-zA-Z0-9_ .]', '', txt)
# trim leading and ending spaces
txt = re.sub(r'^ *| *$', '', txt)
return txt
def cleanstring_email(txt=''):
"""clean the string and return a valid email address.
txt - string to be cleaned """
# remove not allowed characters
txt = re.sub(r'[^a-zA-Z0-9_.@-]', '', txt)
return txt
def check_email(txt=''):
"""control that submitted emails are correct.
this little check is not very good, but better than nothing. """
r = re.compile(r'(.)+\@(.)+\.(.)+')
return r.match(txt) and 1 or 0
def sendAccountActivatedMessage(AccountEmail, sendTo, password, ln=cdslang):
"""Send an email to the address given by sendTo about the new activated account."""
fromaddr = "From: %s" % supportemail
toaddrs = "To: %s" % sendTo
to = toaddrs + "\n"
sub = "Subject: Your account on '%s' has been activated\n\n" % cdsname
body = "Your account earlier created on '%s' has been activated:\n\n" % cdsname
body += " Username/Email: %s\n" % AccountEmail
body += " Password: %s\n" % ("*" * len(password))
body += "\n---------------------------------"
body += "\n%s" % cdsname
body += "\nContact: %s" % supportemail
msg = to + sub + body
server = smtplib.SMTP('localhost')
server.set_debuglevel(1)
try:
server.sendmail(fromaddr, toaddrs, msg)
except smtplib.SMTPRecipientsRefused,e:
return 0
server.quit()
return 1
def sendNewUserAccountWarning(newAccountEmail, sendTo, password, ln=cdslang):
"""Send an email to the address given by sendTo about the new account newAccountEmail."""
fromaddr = "From: %s" % supportemail
toaddrs = "To: %s" % sendTo
to = toaddrs + "\n"
sub = "Subject: Account created on '%s'\n\n" % cdsname
body = "An account has been created for you on '%s':\n\n" % cdsname
body += " Username/Email: %s\n" % newAccountEmail
body += " Password: %s\n" % ("*" * len(password))
body += "\n---------------------------------"
body += "\n%s" % cdsname
body += "\nContact: %s" % supportemail
msg = to + sub + body
server = smtplib.SMTP('localhost')
server.set_debuglevel(1)
try:
server.sendmail(fromaddr, toaddrs, msg)
except smtplib.SMTPRecipientsRefused,e:
return 0
server.quit()
return 1
def sendAccountRejectedMessage(newAccountEmail, sendTo, ln=cdslang):
"""Send an email to the address given by sendTo about the new account newAccountEmail."""
fromaddr = "From: %s" % supportemail
toaddrs = "To: %s" % sendTo
to = toaddrs + "\n"
sub = "Subject: Account rejected on '%s'\n\n" % cdsname
body = "Your request for an account has been rejected on '%s':\n\n" % cdsname
body += " Username/Email: %s\n" % newAccountEmail
body += "\n---------------------------------"
body += "\n%s" % cdsname
body += "\nContact: %s" % supportemail
msg = to + sub + body
server = smtplib.SMTP('localhost')
server.set_debuglevel(1)
try:
server.sendmail(fromaddr, toaddrs, msg)
except smtplib.SMTPRecipientsRefused,e:
return 0
server.quit()
return 1
def sendAccountDeletedMessage(newAccountEmail, sendTo, ln=cdslang):
"""Send an email to the address given by sendTo about the new account newAccountEmail."""
fromaddr = "From: %s" % supportemail
toaddrs = "To: %s" % sendTo
to = toaddrs + "\n"
sub = "Subject: Account deleted on '%s'\n\n" % cdsname
body = "Your account on '%s' has been deleted:\n\n" % cdsname
body += " Username/Email: %s\n" % newAccountEmail
body += "\n---------------------------------"
body += "\n%s" % cdsname
body += "\nContact: %s" % supportemail
msg = to + sub + body
server = smtplib.SMTP('localhost')
server.set_debuglevel(1)
try:
server.sendmail(fromaddr, toaddrs, msg)
except smtplib.SMTPRecipientsRefused,e:
return 0
server.quit()
return 1
def usage(exitcode=1, msg=""):
"""Prints usage info."""
if msg:
sys.stderr.write("Error: %s.\n" % msg)
sys.stderr.write("Usage: %s [options]\n" % sys.argv[0])
sys.stderr.write("Command options:\n")
sys.stderr.write(" -a, --add\t\t add default settings\n")
sys.stderr.write(" -c, --compile\t\t compile role definitions\n")
sys.stderr.write(" -h, --help\t\t Print this help.\n")
sys.stderr.write(" -r, --reset\t\t reset default settings\n")
sys.stderr.write(" -u, --user=USER\t User name to submit the task as, password needed.\n")
sys.stderr.write(" -V, --version\t\t Print version information.\n")
sys.stderr.write("""Description: %s is used to reset the access settings,
or to just add default values, or to compile firewall like
role definition manually set in the accROLE table in the firerole_def_src field.\n""" % sys.argv[0])
sys.exit(exitcode)
def main():
"""Main function that analyzes command line input and calls whatever is appropriate.
"""
## parse command line:
# set user-defined options:
options = {'user' : '', 'reset' : 0, 'compile' : 0, 'add' : 0}
try:
opts, args = getopt.getopt(sys.argv[1:], "hVu:rac",
["help", "version", "user=",
"reset", "add", "compile"])
except getopt.GetoptError, err:
usage(1, err)
try:
for opt in opts:
if opt[0] in ["-h", "--help"]:
usage(0)
elif opt[0] in ["-V", "--version"]:
print __revision__
sys.exit(0)
elif opt[0] in ["-u", "--user"]:
options["user"] = opt[1]
elif opt[0] in ["-r", "--reset"]:
options["reset"] = 1
elif opt[0] in ["-a", "--add"]:
options["add"] = 1
elif opt[0] in ["-c", "--compile"]:
options["compile"] = 1
else:
usage(1)
if options['add'] or options['reset'] or options['compile']:
options['user'] = authenticate(options['user'], authorization_msg="WebAccess Administration", authorization_action="cfgwebaccess")
if options['reset']:
acca.acc_reset_default_settings([supportemail])
print "Reset default settings."
if options['add']:
acca.acc_add_default_settings([supportemail])
print "Added default settings."
if options['compile']:
repair_role_definitions()
print "Compiled firewall like role definitions."
else:
usage(1, "You must specify at least one command")
except StandardError, e:
usage(e)
return
### okay, here we go:
if __name__ == '__main__':
main()
diff --git a/modules/websearch/lib/search_engine.py b/modules/websearch/lib/search_engine.py
index a92cf00e7..32075c67f 100644
--- a/modules/websearch/lib/search_engine.py
+++ b/modules/websearch/lib/search_engine.py
@@ -1,3792 +1,3792 @@
# -*- coding: utf-8 -*-
## $Id$
## This file is part of CDS Invenio.
## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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.
# pylint: disable-msg=C0301
"""CDS Invenio Search Engine in mod_python."""
__lastupdated__ = """$Date$"""
__revision__ = "$Id$"
## import general modules:
import cgi
import copy
import string
import os
import re
import time
import urllib
import zlib
import Numeric
## import CDS Invenio stuff:
from invenio.config import \
CFG_CERN_SITE, \
CFG_MAX_RECID, \
CFG_OAI_ID_FIELD, \
CFG_WEBCOMMENT_ALLOW_COMMENTS, \
CFG_WEBCOMMENT_ALLOW_REVIEWS, \
CFG_WEBCOMMENT_NB_COMMENTS_IN_DETAILED_VIEW, \
CFG_WEBCOMMENT_NB_REVIEWS_IN_DETAILED_VIEW, \
CFG_WEBSEARCH_CALL_BIBFORMAT, \
CFG_WEBSEARCH_CREATE_SIMILARLY_NAMED_AUTHORS_LINK_BOX, \
CFG_WEBSEARCH_FIELDS_CONVERT, \
CFG_WEBSEARCH_NB_RECORDS_TO_SORT, \
CFG_WEBSEARCH_SEARCH_CACHE_SIZE, \
CFG_BIBRANK_SHOW_DOWNLOAD_GRAPHS, \
cdslang, \
cdsname, \
cdsnameintl, \
logdir, \
weburl
from invenio.search_engine_config import CFG_EXPERIMENTAL_FEATURES, InvenioWebSearchUnknownCollectionError
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
from invenio.bibindex_engine_stemmer import stem
from invenio.bibformat import format_record, format_records, get_output_format_content_type, create_excel
from invenio.bibformat_config import CFG_BIBFORMAT_USE_OLD_BIBFORMAT
from invenio.bibrank_downloads_grapher import create_download_history_graph_and_box
from invenio.data_cacher import DataCacher
from invenio.websearch_external_collections import print_external_results_overview, perform_external_collection_search
-from invenio.access_control_admin import acc_getActionId
+from invenio.access_control_admin import acc_get_action_id
from invenio.access_control_config import VIEWRESTRCOLL
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.dbquery import run_sql, get_table_update_time, escape_string, Error
try:
from mod_python import apache
from invenio.webuser import getUid
from invenio.webpage import page, 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
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?
collection_reclist_cache_timestamp = 0
field_i18nname_cache_timestamp = 0
collection_i18nname_cache_timestamp = 0
## precompile some often-used regexp for speed reasons:
re_word = re.compile('[\s]')
re_quotes = re.compile('[\'\"]')
re_doublequote = re.compile('\"')
re_equal = re.compile('\=')
re_logical_and = re.compile('\sand\s', re.I)
re_logical_or = re.compile('\sor\s', re.I)
re_logical_not = re.compile('\snot\s', re.I)
re_operators = re.compile(r'\s([\+\-\|])\s')
re_pattern_wildcards_at_beginning = re.compile(r'(\s)[\*\%]+')
re_pattern_single_quotes = re.compile("'(.*?)'")
re_pattern_double_quotes = re.compile("\"(.*?)\"")
re_pattern_regexp_quotes = re.compile("\/(.*?)\/")
re_pattern_short_words = re.compile(r'([\s\"]\w{1,3})[\*\%]+')
re_pattern_space = re.compile("__SPACE__")
re_pattern_today = re.compile("\$TODAY\$")
re_unicode_lowercase_a = re.compile(unicode(r"(?u)[áàäâãå]", "utf-8"))
re_unicode_lowercase_ae = re.compile(unicode(r"(?u)[æ]", "utf-8"))
re_unicode_lowercase_e = re.compile(unicode(r"(?u)[éèëê]", "utf-8"))
re_unicode_lowercase_i = re.compile(unicode(r"(?u)[íìïî]", "utf-8"))
re_unicode_lowercase_o = re.compile(unicode(r"(?u)[óòöôõø]", "utf-8"))
re_unicode_lowercase_u = re.compile(unicode(r"(?u)[úùüû]", "utf-8"))
re_unicode_lowercase_y = re.compile(unicode(r"(?u)[ýÿ]", "utf-8"))
re_unicode_lowercase_c = re.compile(unicode(r"(?u)[çć]", "utf-8"))
re_unicode_lowercase_n = re.compile(unicode(r"(?u)[ñ]", "utf-8"))
re_unicode_uppercase_a = re.compile(unicode(r"(?u)[ÁÀÄÂÃÅ]", "utf-8"))
re_unicode_uppercase_ae = re.compile(unicode(r"(?u)[Æ]", "utf-8"))
re_unicode_uppercase_e = re.compile(unicode(r"(?u)[ÉÈËÊ]", "utf-8"))
re_unicode_uppercase_i = re.compile(unicode(r"(?u)[ÍÌÏÎ]", "utf-8"))
re_unicode_uppercase_o = re.compile(unicode(r"(?u)[ÓÒÖÔÕØ]", "utf-8"))
re_unicode_uppercase_u = re.compile(unicode(r"(?u)[ÚÙÜÛ]", "utf-8"))
re_unicode_uppercase_y = re.compile(unicode(r"(?u)[Ý]", "utf-8"))
re_unicode_uppercase_c = re.compile(unicode(r"(?u)[ÇĆ]", "utf-8"))
re_unicode_uppercase_n = re.compile(unicode(r"(?u)[Ñ]", "utf-8"))
class RestrictedCollectionDataCacher(DataCacher):
def __init__(self):
def cache_filler():
ret = []
try:
- viewcollid = acc_getActionId(VIEWRESTRCOLL)
+ viewcollid = acc_get_action_id(VIEWRESTRCOLL)
res = run_sql("""SELECT DISTINCT ar.value
FROM accROLE_accACTION_accARGUMENT raa JOIN accARGUMENT ar ON raa.id_accARGUMENT = ar.id
WHERE ar.keyword = 'collection' AND raa.id_accACTION = %s""", (viewcollid,))
except Exception:
# database problems, return empty cache
return []
for coll in res:
ret.append(coll[0])
return ret
def timestamp_getter():
return max(get_table_update_time('accROLE_accACTION_accARGUMENT'), get_table_update_time('accARGUMENT'))
DataCacher.__init__(self, cache_filler, timestamp_getter)
def collection_restricted_p(collection):
cache = restricted_collection_cache.get_cache()
return collection in cache
try:
restricted_collection_cache.is_ok_p
except Exception:
restricted_collection_cache = RestrictedCollectionDataCacher()
class FieldI18nNameDataCacher(DataCacher):
def __init__(self):
def cache_filler():
ret = {}
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 Exception:
# database problems, return empty cache
return {}
for f, ln, i18nname in res:
if i18nname:
if not ret.has_key(f):
ret[f] = {}
ret[f][ln] = i18nname
return ret
def timestamp_getter():
return get_table_update_time('fieldname')
DataCacher.__init__(self, cache_filler, timestamp_getter)
def get_field_i18nname(self, f, ln=cdslang):
out = f
try:
out = self.get_cache()[f][ln]
except KeyError:
pass # translation in LN does not exist
return out
try:
if not field_i18n_name_cache.is_ok_p:
raise Exception
except Exception:
field_i18n_name_cache = FieldI18nNameDataCacher()
class CollectionRecListDataCacher(DataCacher):
def __init__(self):
def cache_filler():
ret = {}
try:
res = run_sql("SELECT name,reclist FROM collection")
except Exception:
# database problems, return empty cache
return {}
for name, reclist in res:
ret[name] = None # this will be filled later during runtime by calling get_collection_reclist(coll)
return ret
def timestamp_getter():
return get_table_update_time('collection')
DataCacher.__init__(self, cache_filler, timestamp_getter)
def get_collection_reclist(self, coll):
cache = self.get_cache()
if not 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
self.cache[coll] = set
cache[coll] = set
# finally, return reclist:
return cache[coll]
try:
if not collection_reclist_cache.is_ok_p:
raise Exception
except Exception:
collection_reclist_cache = CollectionRecListDataCacher()
class CollectionI18nDataCacher(DataCacher):
def __init__(self):
def cache_filler():
ret = {}
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 Exception:
# database problems,
return {}
for c, ln, i18nname in res:
if i18nname:
if not ret.has_key(c):
ret[c] = {}
ret[c][ln] = i18nname
return ret
def timestamp_getter():
return get_table_update_time('collectionname')
DataCacher.__init__(self, cache_filler, timestamp_getter)
def get_coll_i18nname(self, c, ln=cdslang):
"""Return nicely formatted collection name (of name type 'ln',
'long name') for collection C in language LN."""
cache = self.get_cache()
out = c
try:
out = cache[c][ln]
except KeyError:
pass # translation in LN does not exist
return out
try:
if not collection_i18n_name_cache.is_ok_p:
raise Exception
except Exception:
collection_i18n_name_cache = CollectionI18nDataCacher()
def get_alphabetically_ordered_collection_list(level=0, ln=cdslang):
"""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
# long collection names in given language):
c_printable = get_coll_i18nname(c_name, ln)
if len(c_printable)>30:
c_printable = c_printable[:30] + "..."
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, ln=cdslang):
"""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
# long collection names in given language):
c_printable = get_coll_i18nname(c, ln)
if len(c_printable)>30:
c_printable = c_printable[:30] + "..."
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, ln=ln)
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 string.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 = re_pattern_single_quotes.sub(lambda x: "'"+string.replace(x.group(1), ' ', '__SPACE__')+"'", p)
p = re_pattern_double_quotes.sub(lambda x: "\""+string.replace(x.group(1), ' ', '__SPACE__')+"\"", p)
p = re_pattern_regexp_quotes.sub(lambda x: "/"+string.replace(x.group(1), ' ', '__SPACE__')+"/", p)
# wash argument:
p = re_equal.sub(":", p)
p = re_logical_and.sub(" ", p)
p = re_logical_or.sub(" |", p)
p = re_logical_not.sub(" -", p)
p = re_operators.sub(r' \1', p)
for pi in string.split(p): # iterate through separated units (or items, as "pi" stands for "p item")
pi = re_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 = string.split(pi, ":", 1)
else:
fi, pi = f, pi
# look also for old ALEPH field names:
if fi and CFG_WEBSEARCH_FIELDS_CONVERT.has_key(string.lower(fi)):
fi = CFG_WEBSEARCH_FIELDS_CONVERT[string.lower(fi)]
# wash 'pi' argument:
if re_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
content_type = get_output_format_content_type(of)
if of.startswith('x'):
if of == 'xr':
# we are doing RSS output
req.content_type = "application/rss+xml"
req.send_http_header()
req.write("""\n""")
else:
# we are doing XML output:
req.content_type = "text/xml"
req.send_http_header()
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
elif content_type == 'text/html':
# 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 = "%s, WebSearch, %s" % (cdsnameintl.get(ln, cdsname), cc)
req.write(pageheaderonly(req=req, title=title_message,
navtrail=create_navtrail_links(cc, as, ln),
description=description,
keywords=keywords,
uid=uid,
language=ln,
navmenuid='search'))
req.write(websearch_templates.tmpl_search_pagestart(ln=ln))
#else:
# req.send_http_header()
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))
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_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, ec,
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.get(ln, cdsname)
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(ln=ln)
else:
colls_nicely_ordered = get_alphabetically_ordered_collection_list(ln=ln)
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 == re.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,
ec = ec,
)
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 ""
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;
The function raises exception
InvenioWebSearchUnknownCollectionError
if cc or one of c collections is not known.
"""
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):
if cc:
raise InvenioWebSearchUnknownCollectionError(cc)
else:
cc = cdsname # cc is not set, 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)
else:
if coll:
raise InvenioWebSearchUnknownCollectionError(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 = re_unicode_lowercase_a.sub("a", y)
y = re_unicode_lowercase_ae.sub("ae", y)
y = re_unicode_lowercase_e.sub("e", y)
y = re_unicode_lowercase_i.sub("i", y)
y = re_unicode_lowercase_o.sub("o", y)
y = re_unicode_lowercase_u.sub("u", y)
y = re_unicode_lowercase_y.sub("y", y)
y = re_unicode_lowercase_c.sub("c", y)
y = re_unicode_lowercase_n.sub("n", y)
# asciify Latin-1 uppercase characters:
y = re_unicode_uppercase_a.sub("A", y)
y = re_unicode_uppercase_ae.sub("AE", y)
y = re_unicode_uppercase_e.sub("E", y)
y = re_unicode_uppercase_i.sub("I", y)
y = re_unicode_uppercase_o.sub("O", y)
y = re_unicode_uppercase_u.sub("U", y)
y = re_unicode_uppercase_y.sub("Y", y)
y = re_unicode_uppercase_c.sub("C", y)
y = re_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 = re_pattern_wildcards_at_beginning.sub("\\1", p)
# replace spaces within quotes by __SPACE__ temporarily:
p = re_pattern_single_quotes.sub(lambda x: "'"+string.replace(x.group(1), ' ', '__SPACE__')+"'", p)
p = re_pattern_double_quotes.sub(lambda x: "\""+string.replace(x.group(1), ' ', '__SPACE__')+"\"", p)
p = re_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 = re_pattern_short_words.sub("\\1", p)
# replace back __SPACE__ by spaces:
p = re_pattern_space.sub(" ", p)
# replace special terms:
p = re_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_WEBSEARCH_FIELDS_CONVERT.has_key(string.lower(f)):
f = CFG_WEBSEARCH_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:
if get_table_update_time('collectionname') > 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:
if get_table_update_time('fieldname') > 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:
if get_table_update_time('collection') > 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] is not 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:
if not names.has_key(c):
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:
if not names.has_key(f):
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 %(x_query1)s, using %(x_query2)s instead...") % {'x_query1': "" + cgi.escape(bsu_p) + "",
'x_query2': "" + cgi.escape(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 = re_word.sub('', words[0])
word1 = re_word.sub('', words[1])
word0 = stem(word0)
word1 = stem(word1)
query = "SELECT term,hitlist FROM %s WHERE term BETWEEN '%s' AND '%s'" % (bibwordsX, escape_string(word0[:50]), escape_string(word1[:50]))
else:
word = re_word.sub('', word)
word = stem(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_WEBSEARCH_FIELDS_CONVERT.has_key(string.lower(f)):
f = CFG_WEBSEARCH_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 %(x_collection)s. Other public collections gave %(x_url_open)s%(x_nb_hits)d hits%(x_url_close)s.") %\
{'x_collection': '' + string.join([get_coll_i18nname(coll, ln) for coll in 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_WEBSEARCH_CREATE_SIMILARLY_NAMED_AUTHORS_LINK_BOX == 0:
return ""
# return empty box if there is no initial:
if re.match(r'[^ ,]+, [^ ]', author_name) is None:
return ""
# firstly find name comma initial:
author_name_to_search = re.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 (px, fx) in ('p', 'f'), ('p1', 'f1'), ('p2', 'f2'), ('p3', 'f3'):
if px in argd:
if f == argd[fx] or f == "anyfield" or f == "":
if string.find(argd[px], p) > -1:
argd[px] = string.replace(argd[px], p, term)
break
else:
if string.find(argd[px], f+':'+p) > -1:
argd[px] = string.replace(argd[px], f+':'+p, f+':'+term)
break
elif string.find(argd[px], f+':"'+p+'"') > -1:
argd[px] = string.replace(argd[px], f+':"'+p+'"', f+':"'+term+'"')
break
terminfo.append((term, hits, argd))
intro = ""
if intro_text_p: # add full leading introductory text
if f:
intro = _("Search term %(x_term)s inside index %(x_index)s did not match any record. Nearest terms in any collection are:") % \
{'x_term': "" + cgi.escape(p.startswith("%") and p.endswith("%") and p[1:-1] or p) + "",
'x_index': "" + cgi.escape(get_field_i18nname(f, ln)) + ""}
else:
intro = _("Search term %s did not match any record. Nearest terms in any collection are:") % \
("" + cgi.escape(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 = string.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 = string.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
digits = tag[0:2]
try:
intdigits = int(digits)
if intdigits < 0 or intdigits > 99:
raise ValueError
except ValueError:
# invalid tag value asked for
return []
bx = "bib%sx" % digits
bibx = "bibrec_bib%sx" % digits
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 buffer of ALEPH sequential-like textual format with fields found in the list TAGS_IN for record RECID."""
out = ""
if type(tags_in) is not list:
tags_in = [tags_in,]
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]
try:
intdigits = int(digits)
if intdigits < 0 or intdigits > 99:
raise ValueError
except ValueError:
# invalid tag value asked for
continue
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
if field[0:2] == "00" and field[-1:] == "_":
out += value
else:
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, ec=[]):
"""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,
ec = ec,
)
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_WEBSEARCH_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_WEBSEARCH_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.lower().startswith(sort_pattern.lower()): # 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 = strip_accents(val.lower()) # sort values regardless of accents and case
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_records(req, recIDs, jrec=1, rg=10, format='hb', ot='', ln=cdslang, relevances=[], relevances_prologue="(", relevances_epilogue="%%)", decompress=zlib.decompress, search_pattern='', print_records_prologue_p=True, print_records_epilogue_p=True, verbose=0):
"""
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.
Print prologue and/or epilogue specific to 'format' if
'print_records_prologue_p' and/or print_records_epilogue_p' are
True.
"""
# load the right message language
_ = gettext_set_language(ln)
# sanity checking:
if req is None:
return
# get user id (for formatting based on priviledge)
uid = getUid(req)
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'):
# print header if needed
if print_records_prologue_p:
print_records_prologue(req, format)
# print records
recIDs_to_print = [recIDs[x] for x in range(irec_max, irec_min, -1)]
req.write(format_records(recIDs_to_print,
format,
ln=ln,
search_pattern=search_pattern,
record_separator="\n",
uid=uid))
# print footer if needed
if print_records_epilogue_p:
print_records_epilogue(req, format)
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, search_pattern=search_pattern,
uid=uid, verbose=verbose)
req.write(x)
if x:
req.write('\n')
elif format == 'excel':
recIDs_to_print = [recIDs[x] for x in range(irec_max, irec_min, -1)]
create_excel(recIDs=recIDs_to_print, req=req, ln=ln)
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, search_pattern=search_pattern,
uid=uid, verbose=verbose))
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, search_pattern=search_pattern,
uid=uid, verbose=verbose)
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, search_pattern=search_pattern, uid=uid, verbose=verbose),
'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
if CFG_BIBRANK_SHOW_DOWNLOAD_GRAPHS:
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_records_prologue(req, format):
"""
Print the appropriate prologue for list of records in the given
format.
"""
prologue = "" # no prologue needed for HTML or Text formats
if format.startswith('xm'):
prologue = websearch_templates.tmpl_xml_marc_prologue()
elif format.startswith('xn'):
prologue = websearch_templates.tmpl_xml_nlm_prologue()
elif format.startswith('xr'):
prologue = websearch_templates.tmpl_xml_rss_prologue()
elif format.startswith('x'):
prologue = websearch_templates.tmpl_xml_default_prologue()
req.write(prologue)
def print_records_epilogue(req, format):
"""
Print the appropriate epilogue for list of records in the given
format.
"""
epilogue = "" # no epilogue needed for HTML or Text formats
if format.startswith('xm'):
epilogue = websearch_templates.tmpl_xml_marc_epilogue()
elif format.startswith('xn'):
epilogue = websearch_templates.tmpl_xml_nlm_epilogue()
elif format.startswith('xr'):
epilogue = websearch_templates.tmpl_xml_rss_epilogue()
elif format.startswith('x'):
epilogue = websearch_templates.tmpl_xml_default_epilogue()
req.write(epilogue)
def print_record(recID, format='hb', ot='', ln=cdslang, decompress=zlib.decompress,
search_pattern=None, uid=None, verbose=0):
"""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
# New Python BibFormat procedure for formatting
# Old procedure follows further below
# We must still check some special formats, but these
# should disappear when BibFormat improves.
if not (CFG_BIBFORMAT_USE_OLD_BIBFORMAT \
or format.lower().startswith('t') \
or format.lower().startswith('hm') \
or str(format[0:3]).isdigit() \
or ot):
# Unspecified format is hd
if format == '':
format = 'hd'
if record_exist_p == -1 and get_output_format_content_type(format) == 'text/html':
# HTML output displays a default value for deleted records.
# Other format have to deal with it.
out += _("The record has been deleted.")
else:
out += call_bibformat(recID, format, ln, search_pattern=search_pattern,
uid=uid, verbose=verbose)
# at the end of HTML brief mode, print the "Detailed record" functionality:
if format.lower().startswith('hb') and \
format.lower() != 'hb_p':
out += websearch_templates.tmpl_print_record_brief_links(
ln = ln,
recID = recID,
weburl = weburl
)
return out
# Old PHP BibFormat procedure for formatting
# print record opening tags, if needed:
if format == "marcxml" or format == "oai_dc":
out += " \n"
out += " \n"
for oai_id in get_fieldvalues(recID, CFG_OAI_ID_FIELD):
out += " %s\n" % oai_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_OAI_ID_FIELD)
if oai_ids:
out += "%s\n" % \
(CFG_OAI_ID_FIELD[0:3], CFG_OAI_ID_FIELD[3:4], CFG_OAI_ID_FIELD[4:5], CFG_OAI_ID_FIELD[5:6], oai_ids[0])
out += "DELETED\n"
else:
# controlfields
query = "SELECT b.tag,b.value,bb.field_number FROM bib00x AS b, bibrec_bib00x AS bb "\
"WHERE bb.id_bibrec='%s' AND b.id=bb.id_bibxxx AND b.tag LIKE '00%%' "\
"ORDER BY bb.field_number, b.tag ASC" % recID
res = run_sql(query)
for row in res:
field, value = row[0], row[1]
value = encode_for_xml(value)
out += """ %s\n""" % \
(encode_for_xml(field[0:3]), value)
# datafields
i = 1 # Do not process bib00x and bibrec_bib00x, as
# they are controlfields. So start at bib01x and
# bibrec_bib00x (and set i = 0 at the end of
# first loop)
for digit1 in range(0, 10):
for digit2 in range(i, 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 == "_" or ind1 == "":
ind1 = " "
if ind2 == "_" or ind2 == "":
ind2 = " "
# print field tag
if field_number != field_number_old or field[:-1] != field_old[:-1]:
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
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 field_number_old != -999:
out += """ \n"""
i = 0 # Next loop should start looking at bib%0 and bibrec_bib00x
# we are at the end of printing the record:
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", CFG_OAI_ID_FIELD, "980"])
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, ln, search_pattern=search_pattern,
uid=uid, verbose=verbose)
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, ln, search_pattern=search_pattern,
uid=uid, verbose=verbose)
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, ln, search_pattern=search_pattern,
uid=uid, verbose=verbose)
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_WEBSEARCH_CALL_BIBFORMAT:
out_record_in_format = call_bibformat(recID, format, ln, search_pattern=search_pattern,
uid=uid, verbose=verbose)
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", ln=cdslang, search_pattern=None, uid=None, verbose=0):
"""
Calls BibFormat and returns formatted record.
BibFormat will decide by itself if old or new BibFormat must be used.
"""
keywords = []
if search_pattern is not None:
units = create_basic_search_units(None, str(search_pattern), None)
keywords = [unit[1] for unit in units if unit[0] != '-']
return format_record(recID,
of=format,
ln=ln,
search_pattern=keywords,
uid=uid,
verbose=verbose)
def log_query(hostname, query_args, uid=-1):
"""
Log query into the query and user_query tables.
Return id_query or None in case of problems.
"""
id_query = None
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 id_query
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, ec = None):
"""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.
ec - List of external search engines enabled.
"""
selected_external_collections_infos = None
# wash all arguments requiring special care
try:
(cc, colls_to_display, colls_to_search) = wash_colls(cc, c, sc) # which colls to search and to display?
except InvenioWebSearchUnknownCollectionError, exc:
colname = exc.colname
if of.startswith("h"):
page_start(req, of, cc, as, ln, getUid(req),
websearch_templates.tmpl_collection_not_found_page_title(colname, ln))
req.write(websearch_templates.tmpl_collection_not_found_page_body(colname, ln))
return page_end(req, of, ln)
elif of == "id":
return []
else:
return page_end(req, of, ln)
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)
# Default format is hb but we are in detailed -> change 'of'
if of == "hb":
of = "hd"
if record_exists(recid):
if recidb <= recid: # sanity check
recidb = recid + 1
if of == "id":
return [recidx for recidx in range(recid, recidb) if record_exists(recidx)]
else:
print_records(req, range(recid, recidb), -1, -9999, of, ot, ln, search_pattern=p, verbose=verbose)
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 == "id":
return []
elif 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, ec, 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, ec, 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, search_pattern=p, verbose=verbose)
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, ec, 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, search_pattern=p, verbose=verbose)
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, ec, 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"):
perform_external_collection_search(req, cc, [p, p1, p2, p3], f, ec, verbose, ln, selected_external_collections_infos)
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"):
perform_external_collection_search(req, cc, [p, p1, p2, p3], f, ec, verbose, ln, selected_external_collections_infos)
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))
perform_external_collection_search(req, cc, [p, p1, p2, p3], f, ec, verbose, ln, selected_external_collections_infos)
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))
perform_external_collection_search(req, cc, [p, p1, p2, p3], f, ec, verbose, ln, selected_external_collections_infos)
return page_end(req, of, ln)
if results_in_any_collection._nbhits == 0:
if of.startswith("h"):
perform_external_collection_search(req, cc, [p, p1, p2, p3], f, ec, verbose, ln, selected_external_collections_infos)
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_WEBSEARCH_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))
perform_external_collection_search(req, cc, [p, p1, p2, p3], f, ec, verbose, ln, selected_external_collections_infos)
return page_end(req, of, ln)
if results_final == {}:
if of.startswith("h"):
perform_external_collection_search(req, cc, [p, p1, p2, p3], f, ec, verbose, ln, selected_external_collections_infos)
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))
perform_external_collection_search(req, cc, [p, p1, p2, p3], f, ec, verbose, ln, selected_external_collections_infos)
return page_end(req, of, ln)
if results_final == {}:
if of.startswith("h"):
perform_external_collection_search(req, cc, [p, p1, p2, p3], f, ec, verbose, ln, selected_external_collections_infos)
return page_end(req, of, ln)
if pl:
pl = wash_pattern(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))
perform_external_collection_search(req, cc, [p, p1, p2, p3], f, ec, verbose, ln, selected_external_collections_infos)
return page_end(req, of, ln)
if results_final == {}:
if of.startswith("h"):
perform_external_collection_search(req, cc, [p, p1, p2, p3], f, ec, verbose, ln, selected_external_collections_infos)
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)
for coll in results_final.keys():
results_final_nb[coll] = results_final[coll]._nbhits
#results_final_nb_total += results_final_nb[coll]
# Now let us calculate results_final_nb_total more precisely,
# in order to get the total number of "distinct" hits across
# searched collections; this is useful because a record might
# have been attributed to more than one primary collection; so
# we have to avoid counting it multiple times. The price to
# pay for this accuracy of results_final_nb_total is somewhat
# increased CPU time.
if results_final.keys() == 1:
# only one collection; no need to union them
results_final_for_all_selected_colls = results_final.values()[0]
results_final_nb_total = results_final_nb.values()[0]
else:
# okay, some work ahead to union hits across collections:
results_final_for_all_selected_colls = HitSet()
for coll in results_final.keys():
results_final_for_all_selected_colls.union(results_final[coll])
results_final_for_all_selected_colls.calculate_nbhits()
results_final_nb_total = results_final_for_all_selected_colls._nbhits
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
recIDs = results_final_for_all_selected_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, ec))
selected_external_collections_infos = print_external_results_overview(req, cc, [p, p1, p2, p3], f, ec, verbose, ln)
# print records:
if len(colls_to_search)>1:
cpu_time = -1 # we do not want to have search time printed on each collection
print_records_prologue(req, of)
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,
search_pattern=p,
print_records_prologue_p=False,
print_records_epilogue_p=False,
verbose=verbose)
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))
print_records_epilogue(req, of)
if f == "author" and of.startswith("h"):
req.write(create_similarly_named_authors_link_box(p, ln))
# log query:
try:
id_query = log_query(req.get_remote_host(), req.args, uid)
if of.startswith("h") and id_query:
# Alert/RSS teaser:
req.write(websearch_templates.tmpl_alert_rss_teaser_box_for_query(id_query, ln=ln))
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)
# External searches
if of.startswith("h"):
perform_external_collection_search(req, cc, [p, p1, p2, p3], f, ec, verbose, ln, selected_external_collections_infos)
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
"
out += "- collection table last updated: %s" % get_table_update_time('collection')
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
"
out += "- fieldname table last updated: %s" % get_table_update_time('fieldname')
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
"
out += "- collectionname table last updated: %s" % get_table_update_time('collectionname')
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("")
req.write(out)
req.write("")
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("")
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("""
")
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(10, "980__a")
#print get_fieldvalues_alephseq_like(10,"001___")
#print get_fieldvalues_alephseq_like(10,"980__a")
#print get_fieldvalues_alephseq_like(10,"foo")
#print get_fieldvalues_alephseq_like(10,"-1")
#print get_fieldvalues_alephseq_like(10,"99")
#print get_fieldvalues_alephseq_like(10,["001", "980"])
## profiling:
#profile("of the this")
#print perform_request_search(p="ellis")
diff --git a/modules/websession/lib/webaccount.py b/modules/websession/lib/webaccount.py
index 0fb712256..eb8f2c8de 100644
--- a/modules/websession/lib/webaccount.py
+++ b/modules/websession/lib/webaccount.py
@@ -1,335 +1,335 @@
## $Id$
## This file is part of CDS Invenio.
## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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.
__revision__ = "$Id$"
import sys
import string
import cgi
import re
from invenio.config import \
CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS, \
CFG_CERN_SITE, \
cdslang, \
cdsname, \
supportemail, \
sweburl, \
version, \
weburl
from invenio.access_control_config import CFG_EXTERNAL_AUTHENTICATION
from invenio.webpage import page
from invenio.dbquery import run_sql
from invenio.webuser import getUid,isGuestUser, get_user_preferences, \
set_user_preferences, collect_user_info
-from invenio.access_control_admin import acc_findUserRoleActions
+from invenio.access_control_admin import acc_find_user_role_actions
from invenio.messages import gettext_set_language
from invenio.external_authentication import WebAccessExternalAuthError
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_display_external_user_settings(settings, ln):
"""show external user settings which is a dictionary."""
_ = gettext_set_language(ln)
html_settings = ""
print_settings = False
settings_keys = settings.keys()
settings_keys.sort()
for key in settings_keys:
value = settings[key]
if key.startswith("EXTERNAL_") and not "HIDDEN_" in key:
print_settings = True
key = key[9:].capitalize()
html_settings += websession_templates.tmpl_external_setting(ln, key, value)
return print_settings and websession_templates.tmpl_external_user_settings(ln, html_settings) or ""
def perform_youradminactivities(user_info, 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(user_info)
+ your_role_actions = acc_find_user_role_actions(user_info)
your_roles = []
your_admin_activities = []
guest = isGuestUser(user_info['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 = user_info['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)
user_info = collect_user_info(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 %(x_url_open)slogin%(x_url_close)s as a regular user.") %\
{'x_url_open': '',
'x_url_close': ''}
accBody += "
"
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(user_info, 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)
def perform_set(email, ln, verbose=0):
"""Perform_set(email,password): edit your account parameters, email and
password.
"""
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']][0]:
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_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
current_login_method = prefs['login_method']
methods = CFG_EXTERNAL_AUTHENTICATION.keys()
# Filtering out methods that don't provide user_exists to check if
# a user exists in the external auth method before letting him/her
# to switch.
for method in methods:
if CFG_EXTERNAL_AUTHENTICATION[method][0]:
try:
if not CFG_EXTERNAL_AUTHENTICATION[method][0].user_exists(email):
methods.remove(method)
except (AttributeError, WebAccessExternalAuthError):
methods.remove(method)
methods.sort()
if len(methods) > 1:
out += websession_templates.tmpl_user_external_auth(
ln = ln,
methods = methods,
current = current_login_method,
method_disabled = (CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS >= 4)
)
try:
current_group_records = prefs['websearch_group_records']
except KeyError:
current_group_records = 10
try:
show_latestbox = prefs['websearch_latestbox']
except KeyError:
show_latestbox = True
try:
show_helpbox = prefs['websearch_helpbox']
except KeyError:
show_helpbox = True
out += websession_templates.tmpl_user_websearch_edit(
ln = ln,
current = current_group_records,
show_latestbox = show_latestbox,
show_helpbox = show_helpbox,
)
if verbose >= 9:
for key, value in prefs.items():
out += "%s:%s " % (key, value)
out += perform_display_external_user_settings(prefs, ln)
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='', apache_msg="", ln=cdslang):
# List of referer regexep and message to print
_ = gettext_set_language(ln)
login_referrer2msg = (
(re.compile(r"/search"), "
" + _("This collection is restricted. If you think you have right to access it, please authenticate yourself.") + "
"),
)
msg = ""
for regexp, txt in login_referrer2msg:
if regexp.search(referer):
msg = txt
break
if apache_msg:
msg += apache_msg + "
Otherwise please, provide the correct authorization" \
" data in the following form.
"
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]:
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,
msg = msg,
)
# 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)
#def perform_reset_password: ask the user for a new password to reset the lost one
def perform_reset_password(ln, email, reset_key, msg=''):
return websession_templates.tmpl_reset_password_form(ln, email, reset_key, msg)
# 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/websession_templates.py b/modules/websession/lib/websession_templates.py
index 32a2c0f68..596ef685f 100644
--- a/modules/websession/lib/websession_templates.py
+++ b/modules/websession/lib/websession_templates.py
@@ -1,2109 +1,2108 @@
## $Id$
## This file is part of CDS Invenio.
## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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.
__revision__ = "$Id$"
import urllib
import time
import cgi
import gettext
import string
import locale
from invenio.config import \
CFG_CERN_SITE, \
bibformat, \
cdslang, \
cdsname, \
cdsnameintl, \
supportemail, \
sweburl, \
version, \
weburl
from invenio.access_control_config import CFG_EXTERNAL_AUTH_USING_SSO, \
CFG_EXTERNAL_AUTH_LOGOUT_SSO
from invenio.websession_config import CFG_WEBSESSION_RESET_PASSWORD_EXPIRE_IN_DAYS
from invenio.urlutils import make_canonical_urlargd
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_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 = """
""" % (key, value)
return out
def tmpl_external_user_settings(self, ln, html_settings):
_ = gettext_set_language(ln)
out = """
%(external_user_settings)s
%(html_settings)s
%(external_user_groups)s
%(consult_external_groups)s
""" % {
'external_user_settings' : _('External account settings'),
'html_settings' : html_settings,
'consult_external_groups' : _('You can consult the list of your external groups directly in the %(x_url_open)sgroups page%(x_url_close)s.') % {
'x_url_open' : '' % ln,
'x_url_close' : ''
},
'external_user_groups' : _('External user groups'),
}
return out
def tmpl_user_preferences(self, ln, email, email_disabled, 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_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 = """
%(edit_params)s
""" % {
'change_user' : _("If you want to change your email or set for the first time your nickname, please set new values in the form below."),
'edit_params' : _("Edit login credentials"),
'nickname_label' : _("Nickname"),
'nickname' : nickname,
'nickname_prefix' : nickname=='' and ' '+_("Example")+':johnd' or '',
'new_email' : _("New email address"),
'mandatory' : _("mandatory"),
'example' : _("Example"),
'note' : _("Note"),
'set_values' : _("Set new values"),
'email' : email,
'email_disabled' : email_disabled and "readonly" or "",
'sweburl': sweburl,
}
if not password_disabled and not CFG_EXTERNAL_AUTH_USING_SSO:
out += """
""" % {
'change_pass' : _("If you want to change your password, please enter the old one and set the new value in the form below."),
'mandatory' : _("mandatory"),
'old_password' : _("Old password"),
'new_password' : _("New password"),
'optional' : _("optional"),
'note' : _("Note"),
'password_note' : _("The password phrase may contain punctuation, spaces, etc."),
'old_password_note' : _("You must fill the old password in order to set a new one."),
'retype_password' : _("Retype password"),
'set_values' : _("Set new password"),
'password_disabled' : password_disabled and "disabled" or "",
'sweburl': sweburl,
}
elif not CFG_EXTERNAL_AUTH_USING_SSO and CFG_CERN_SITE:
out += "
"
elif CFG_EXTERNAL_AUTH_USING_SSO and CFG_CERN_SITE:
out += "
" + _("""You can change or reset your CERN account password by means of the %(x_url_open)sCERN account system%(x_url_close)s.""") % \
{'x_url_open' : '', 'x_url_close' : ''} + "
"
return out
def tmpl_user_websearch_edit(self, ln, current = 10, show_latestbox = True, show_helpbox = True):
_ = gettext_set_language(ln)
out = """
""" % {
'update_settings' : _("Update settings"),
'select_group_records' : _("Number of search results per page"),
}
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 = """
""" % {
'select_method' : _("Select method"),
}
return out
def tmpl_lost_password_form(self, ln):
"""
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 = "
" + _("If you have lost password for your %(cdsname)s %(x_fmt_open)sinternal account%(x_fmt_close)s, then please enter your email address in the following form and having a request link for a new password emailed to you.") % {'x_fmt_open' : '', 'x_fmt_close' : '', 'cdsname' : cdsnameintl[ln]} + "
"
out += """
""" % {
'ln': ln,
'email' : _("Email address"),
'send' : _("Send new password"),
}
if CFG_CERN_SITE:
out += "
" + _("Note that if you have been using an external login system, then we cannot do anything and you have to ask there.") + " "
out += _("Alternatively, you can ask %s to change your login system from external to internal.") % ("""%(email)s""" % { 'email' : supportemail }) + "
"
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 += """
""" % {
'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)
out += "
""" % {
'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 (for the moment: 'alerts' or 'baskets')
"""
# load the right message language
_ = gettext_set_language(ln)
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)
out = _("You are logged in as %(x_user)s. You may want to a) %(x_url1_open)slogout%(x_url1_close)s; b) edit your %(x_url2_open)saccount settings%(x_url2_close)s.") %\
{'x_user': user,
'x_url1_open': '',
'x_url1_close': '',
'x_url2_open': '',
'x_url2_close': '',
}
return out + "
"
def tmpl_account_template(self, title, body, ln):
"""
Displays a block of the your account page
Parameters:
- 'ln' *string* - The language to display the interface in
- 'title' *string* - The title of the block
- 'body' *string* - The body of the block
"""
out =""
out +="""
%s
%s
""" % (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)
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_url_close': ''}
out += self.tmpl_account_template(_("Your Submissions"), submission_description, ln)
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_reset_password_email_body(self, email, reset_key, ip_address, ln=cdslang):
"""
The body of the email that sends lost internal account
passwords to users.
"""
_ = gettext_set_language(ln)
out = """\
%(intro)s
%(intro2)s
<%(link)s>
%(outro)s
%(outro2)s
""" % {
- 'hello': _("Hello"),
'intro': _("Somebody (possibly you) coming from %(ip_address)s "
"have asked for a\npassword reset for %(cdsname)s for "
"the account \"%(email)s\"." % {
'cdsname' :cdsnameintl.get(ln, cdsname),
'email' : email,
'ip_address' : ip_address,
}
),
'intro2' : _("If you want to reset the password for this account, please go to:"),
- 'link' : "%s/youraccount/mailcookie%s" %
+ 'link' : "%s/youraccount/access%s" %
(sweburl, make_canonical_urlargd({
'ln' : ln,
- 'cookie' : reset_key
+ 'mailcookie' : reset_key
}, {})),
'outro' : _("and follow the instructions presented there."),
'outro2' : _("Please note that this URL will remain valid only for about %(days)s day(s).") % {'days' : CFG_WEBSESSION_RESET_PASSWORD_EXPIRE_IN_DAYS},
'best_regards': _("Best regards"),
'cdsnameintl' :cdsnameintl.get(ln, cdsname),
'weburl': weburl,
'need_intervention_please_contact': _("Need human intervention? Contact"),
'supportemail': supportemail
}
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, request for a new 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 = _("You are no longer recognized by our system.") + ' '
if CFG_EXTERNAL_AUTH_USING_SSO and CFG_EXTERNAL_AUTH_LOGOUT_SSO:
out += _("""You are still recognized by the centralized
%(x_fmt_open)sSSO%(x_fmt_close)s system. You can
%(x_url_open)slogout from SSO%(x_url_close)s, too.""") % \
{'x_fmt_open' : '', 'x_fmt_close' : '',
'x_url_open' : '' % CFG_EXTERNAL_AUTH_LOGOUT_SSO,
'x_url_close' : ''}
out += ' '
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, msg=None):
"""
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
- 'msg' *string* - The message to print before the form, if needed
"""
# load the right message language
_ = gettext_set_language(ln)
- if msg is None:
+ if msg is "":
out = "
%(please_login)s" % {
'please_login' : _("If you already have an account, please login using the form below.")
}
if CFG_CERN_SITE:
out += "
" + _("If you don't own a CERN account yet, you can register a %(x_url_open)snew CERN external account%(x_url_close)s.") % {'x_url_open' : '', 'x_url_close' : ''} + "
"
else:
if register_available:
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)) + "
"
else:
out = "
%s
" % msg
out += """"""
out += """
%(note)s: %(note_text)s
""" % {
'note' : _("Note"),
'note_text': _("You can use your nickname or your email address to login.")}
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_reset_password_form(self, ln, email, reset_key, msg=''):
"""Display a form to reset the password."""
_ = gettext_set_language(ln)
out = ""
out = "
%s
" % _("Your request is valid. Please set the new "
"desired password in the following form.")
if msg:
out += """
%s
""" % msg
out += """
""" % {
'ln' : ln,
'reset_key' : reset_key,
'email' : email,
'set_password_for' : _('Set a new password for'),
'type_new_password' : _('Type the new password'),
'type_it_again' : _('Type again the new password'),
'set_new_password' : _('Set the new 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 += """
%(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 %(x_url_open)slogin%(x_url_close)s first.") % \
{'x_url_open': '',
'x_url_close': ''}
# no rights condition
if not roles:
return "
" + _("You are not authorized to access administrative functions.") + "
"
# displaying form
out += "
" + _("You seem to be %(x_role)s.") % {'x_role': ('' + 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, _("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 %(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 ::
%(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,
external_group_html = None,
warnings=[],
ln=cdslang):
"""
Displays the 3 tables of groups: admin, member and external
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
- 'external_group_html' *string* - HTML code for displaying all the
external groups the user is member of
"""
_ = gettext_set_language(ln)
group_text = self.tmpl_infobox(infos)
group_text += self.tmpl_warning(warnings)
if external_group_html:
group_text += """
""" %(admin_group_html, member_group_html)
return group_text
def tmpl_display_admin_groups(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
""" % (cgi.escape(name), cgi.escape(description), edit_link, members_link)
out += """
""" % {'ln': ln,
'write_label': _("Create new group"),
}
return indent_text(out, 2)
def tmpl_display_member_groups(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 += """
""" % {'ln': ln,
'join_label': _("Join new group"),
'leave_label':_("Leave group")
}
return indent_text(group_text, 2)
def tmpl_display_external_groups(self, groups, ln=cdslang):
"""
Display the external 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 external groups:"))
group_text += """
"""
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') % cgi.escape(group_name)
delete_text = """"""
delete_text %= (_("Delete group"),"delete")
if grpID != "":
hidden_id = """"""
hidden_id %= grpID
out = self.tmpl_warning(warnings)
out += """
"""
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': cgi.escape(group_name, 1),
'group_description': cgi.escape(group_description, 1),
'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 += """
"""
out %= {'action' : weburl + '/yourgroups/join',
'logo': weburl + '/img/webbasket_create.png',
'label': _("Join group"),
'group_name': cgi.escape(group_name, 1),
'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 += """
"""
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 %(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,
'img_alt_header1': _("Current members"),
'img_alt_header2': _("Members awaiting approval"),
'img_alt_header3': _("Invite new members"),
'invite_text': invite_text,
'imgurl': weburl + '/img',
'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 += """
"""
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': _("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': _("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 = """
""" % (p_email, _("Send Password"))
else:
query = """SELECT email FROM user
WHERE id = %i"""
res = run_sql(query % uid)
if res:
email = res[0][0]
else:
email = None
if not email:
mess = _("Unable to switch to external login method %s, because your email address is unknown.") % args['login_method']
else:
try:
if not CFG_EXTERNAL_AUTHENTICATION[args['login_method']][0].user_exists(email):
mess = _("Unable to switch to external login method %s, because your email address is unknown to the external login system.") % args['login_method']
else:
prefs['login_method'] = args['login_method']
webuser.set_user_preferences(uid, prefs)
mess = _("Login method successfully selected.")
except AttributeError:
mess = _("The external login method %s does not support email address based logins. Please contact the site administrators.") % args['login_method']
elif args['login_method'] and CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS >= 4:
return webuser.page_not_authorized(req, "../youraccount/change",
navmenuid='youraccount')
elif args['email']:
# We should ignore the password if the authentication method is an
# external one.
ignore_password_p = CFG_EXTERNAL_AUTHENTICATION[prefs['login_method']][0] != None
uid2 = webuser.emailUnique(args['email'])
uid_with_the_same_nickname = webuser.nicknameUnique(args['nickname'])
if (CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS >= 2 or (CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS <= 1 and \
webuser.email_valid_p(args['email']))) \
and (args['nickname'] is None or webuser.nickname_valid_p(args['nickname'])) \
and uid2 != -1 and (uid2 == uid or uid2 == 0) \
and uid_with_the_same_nickname != -1 and (uid_with_the_same_nickname == uid or uid_with_the_same_nickname == 0):
if CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS < 3:
change = webuser.updateDataUser(uid,
args['email'],
args['nickname'])
else:
return webuser.page_not_authorized(req, "../youraccount/change",
navmenuid='youraccount')
if change:
mess = _("Settings successfully edited.")
act = "display"
linkname = _("Show account")
title = _("Settings edited")
elif args['nickname'] is not None and not webuser.nickname_valid_p(args['nickname']):
mess = _("Desired nickname %s is invalid.") % args['nickname']
mess += " " + _("Please try again.")
act = "edit"
linkname = _("Edit settings")
title = _("Editing settings failed")
elif not webuser.email_valid_p(args['email']):
mess = _("Supplied email address %s is invalid.") % args['email']
mess += " " + _("Please try again.")
act = "edit"
linkname = _("Edit settings")
title = _("Editing settings failed")
elif uid2 == -1 or uid2 != uid and not uid2 == 0:
mess = _("Supplied email address %s already exists in the database.") % args['email']
mess += " " + websession_templates.tmpl_lost_your_password_teaser(args['ln'])
mess += " " + _("Or please try again.")
act = "edit"
linkname = _("Edit settings")
title = _("Editing settings failed")
elif uid_with_the_same_nickname == -1 or uid_with_the_same_nickname != uid and not uid_with_the_same_nickname == 0:
mess = _("Desired nickname %s is already in use.") % args['nickname']
mess += " " + _("Please try again.")
act = "edit"
linkname = _("Edit settings")
title = _("Editing settings failed")
elif args['old_password'] != None and CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS < 3:
res = run_sql("SELECT id FROM user "
"WHERE AES_ENCRYPT(email,%s)=password AND id=%s",
(args['old_password'], uid))
if res:
if args['password'] == args['password2']:
webuser.updatePasswordUser(uid, args['password'])
mess = _("Password successfully edited.")
act = "display"
linkname = _("Show account")
title = _("Password edited")
else:
mess = _("Both passwords must match.")
mess += " " + _("Please try again.")
act = "edit"
linkname = _("Edit settings")
title = _("Editing password failed")
else:
mess = _("Wrong old password inserted.")
mess += " " + _("Please try again.")
act = "edit"
linkname = _("Edit settings")
title = _("Editing password failed")
elif args['group_records']:
prefs = webuser.get_user_preferences(uid)
prefs['websearch_group_records'] = args['group_records']
prefs['websearch_latestbox'] = args['latestbox']
prefs['websearch_helpbox'] = args['helpbox']
webuser.set_user_preferences(uid, prefs)
title = _("Settings edited")
act = "display"
linkname = _("Show account")
mess = _("User settings saved correctly.")
else:
mess = _("Unable to update settings.")
act = "edit"
linkname = _("Edit settings")
title = _("Editing settings failed")
return page(title=title,
body=webaccount.perform_back(mess, act, linkname, args['ln']),
navtrail="""""" % (sweburl, args['ln']) + _("Your Account") + """""",
description=_("%s Personalize, Main page") % cdsnameintl.get(args['ln'], cdsname),
keywords=_("%s, personalize") % cdsnameintl.get(args['ln'], cdsname),
uid=uid,
req=req,
secure_page_p = 1,
language=args['ln'],
lastupdated=__lastupdated__,
navmenuid='youraccount')
def lost(self, req, form):
args = wash_urlargd(form, {})
uid = webuser.getUid(req)
# load the right message language
_ = gettext_set_language(args['ln'])
if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
return webuser.page_not_authorized(req, "../youraccount/lost",
navmenuid='login')
return page(title=_("Lost your password?"),
body=webaccount.perform_lost(args['ln']),
navtrail="""""" % (sweburl, args['ln']) + _("Your Account") + """""",
description=_("%s Personalize, Main page") % cdsnameintl.get(args['ln'], cdsname),
keywords=_("%s, personalize") % cdsnameintl.get(args['ln'], cdsname),
uid=uid,
req=req,
secure_page_p = 1,
language=args['ln'],
lastupdated=__lastupdated__,
navmenuid='login')
def send_email(self, req, form):
# set all the declared query fields as local variables
args = wash_urlargd(form, {'p_email': (str, None)})
uid = webuser.getUid(req)
# load the right message language
_ = gettext_set_language(args['ln'])
if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
return webuser.page_not_authorized(req, "../youraccount/send_email",
navmenuid='login')
user_prefs = webuser.get_user_preferences(webuser.emailUnique(args['p_email']))
if user_prefs:
if CFG_EXTERNAL_AUTHENTICATION.has_key(user_prefs['login_method']) and \
CFG_EXTERNAL_AUTHENTICATION[user_prefs['login_method']][0] is not None:
eMsg = _("Cannot send password by email since you are using external authentication system.")
return page(title=_("Your Account"),
body=webaccount.perform_emailMessage(eMsg, args['ln']),
description=_("%s Personalize, Main page") % cdsnameintl.get(args['ln'], cdsname),
keywords=_("%s, personalize" % cdsnameintl.get(args['ln'], cdsname)),
uid=uid, req=req,
secure_page_p = 1,
language=args['ln'],
lastupdated=__lastupdated__,
navmenuid='login')
reset_key = mail_cookie_create_pw_reset(args['p_email'], cookie_timeout=timedelta(days=CFG_WEBSESSION_RESET_PASSWORD_EXPIRE_IN_DAYS))
if reset_key is None:
eMsg = _("The entered email address does not exist in the database.")
return page(title=_("Your Account"),
body=webaccount.perform_emailMessage(eMsg, args['ln']),
description=_("%s Personalize, Main page") % cdsnameintl.get(args['ln'], cdsname),
keywords=_("%s, personalize") % cdsnameintl.get(args['ln'], cdsname),
uid=uid, req=req,
secure_page_p = 1,
language=args['ln'],
lastupdated=__lastupdated__,
navmenuid='login')
ip_address = req.connection.remote_host or req.connection.remote_ip
if not send_email(supportemail, args['p_email'], "%s %s"
% (_("Password reset request for"),
cdsnameintl.get(args['ln'], cdsname)),
websession_templates.tmpl_account_reset_password_email_body(
args['p_email'], reset_key, ip_address, args['ln']),
header='', footer=''):
eMsg = _("The entered email address is incorrect, please check that it is written correctly (e.g. johndoe@example.com).")
return page(title=_("Incorrect email address"),
body=webaccount.perform_emailMessage(eMsg, args['ln']),
description=_("%s Personalize, Main page") % cdsnameintl.get(args['ln'], cdsname),
keywords=_("%s, personalize") % cdsnameintl.get(args['ln'], cdsname),
uid=uid,
req=req,
secure_page_p = 1,
language=args['ln'],
lastupdated=__lastupdated__,
navmenuid='login')
return page(title=_("Reset password link sent"),
body=webaccount.perform_emailSent(args['p_email'], args['ln']),
description=_("%s Personalize, Main page") % cdsnameintl.get(args['ln'], cdsname),
keywords=_("%s, personalize") % cdsnameintl.get(args['ln'], cdsname),
uid=uid, req=req,
secure_page_p = 1,
language=args['ln'],
lastupdated=__lastupdated__,
navmenuid='login')
def youradminactivities(self, req, form):
args = wash_urlargd(form, {})
uid = webuser.getUid(req)
user_info = webuser.collect_user_info(req)
# load the right message language
_ = gettext_set_language(args['ln'])
if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
return webuser.page_not_authorized(req, "../youraccount/youradminactivities",
navmenuid='admin')
return page(title=_("Your Administrative Activities"),
body=webaccount.perform_youradminactivities(user_info, args['ln']),
navtrail="""""" % (sweburl, args['ln']) + _("Your Account") + """""",
description=_("%s Personalize, Main page") % cdsnameintl.get(args['ln'], cdsname),
keywords=_("%s, personalize") % cdsnameintl.get(args['ln'], cdsname),
uid=uid,
req=req,
secure_page_p = 1,
language=args['ln'],
lastupdated=__lastupdated__,
navmenuid='admin')
def delete(self, req, form):
args = wash_urlargd(form, {})
uid = webuser.getUid(req)
# load the right message language
_ = gettext_set_language(args['ln'])
if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
return webuser.page_not_authorized(req, "../youraccount/delete",
navmenuid='login')
return page(title=_("Delete Account"),
body=webaccount.perform_delete(args['ln']),
navtrail="""""" % (sweburl, args['ln']) + _("Your Account") + """""",
description=_("%s Personalize, Main page") % cdsnameintl.get(args['ln'], cdsname),
keywords=_("%s, personalize") % cdsnameintl.get(args['ln'], cdsname),
uid=uid,
req=req,
secure_page_p = 1,
language=args['ln'],
lastupdated=__lastupdated__,
navmenuid='login')
def logout(self, req, form):
args = wash_urlargd(form, {})
uid = webuser.logoutUser(req)
# load the right message language
_ = gettext_set_language(args['ln'])
if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
return webuser.page_not_authorized(req, "../youraccount/logout",
navmenuid='login')
return page(title=_("Logout"),
body=webaccount.perform_logout(req, args['ln']),
navtrail="""""" % (sweburl, args['ln']) + _("Your Account") + """""",
description=_("%s Personalize, Main page") % cdsnameintl.get(args['ln'], cdsname),
keywords=_("%s, personalize") % cdsnameintl.get(args['ln'], cdsname),
uid=uid,
req=req,
secure_page_p = 1,
language=args['ln'],
lastupdated=__lastupdated__,
navmenuid='login')
def login(self, req, form):
args = wash_urlargd(form, {
'p_un': (str, None),
'p_pw': (str, None),
'login_method': (str, None),
'action': (str, None),
'referer': (str, '')})
locals().update(args)
if CFG_ACCESS_CONTROL_LEVEL_SITE > 0:
return webuser.page_not_authorized(req, "../youraccount/login?ln=%s" % args['ln'],
navmenuid='login')
uid = webuser.getUid(req)
# load the right message language
_ = gettext_set_language(args['ln'])
apache_msg = ""
if args['action']:
apache_msg = make_apache_message(args['action'], args['referer'])
if not CFG_EXTERNAL_AUTH_USING_SSO:
if args['p_un'] is None or not args['login_method']:
return page(title=_("Login"),
body=webaccount.create_login_page_box(args['referer'], apache_msg, args['ln']),
navtrail="""""" % (sweburl, args['ln']) + _("Your Account") + """""",
description=_("%s Personalize, Main page") % cdsnameintl.get(args['ln'], cdsname),
keywords=_("%s , personalize") % cdsnameintl.get(args['ln'], cdsname),
uid=uid,
req=req,
secure_page_p = 1,
language=args['ln'],
lastupdated=__lastupdated__,
navmenuid='login')
(iden, args['p_un'], args['p_pw'], msgcode) = webuser.loginUser(req, args['p_un'], args['p_pw'], args['login_method'])
else:
# Fake parameters for p_un & p_pw because SSO takes them from the environment
(iden, args['p_un'], args['p_pw'], msgcode) = webuser.loginUser(req, '', '', 'SSO')
if len(iden)>0:
uid = webuser.update_Uid(req, args['p_un'])
uid2 = webuser.getUid(req)
if uid2 == -1:
webuser.logoutUser(req)
return webuser.page_not_authorized(req, "../youraccount/login?ln=%s" % args['ln'], uid=uid,
navmenuid='login')
# login successful!
if args['referer']:
req.err_headers_out.add("Location", args['referer'])
raise apache.SERVER_RETURN, apache.HTTP_MOVED_PERMANENTLY
else:
return self.display(req, form)
else:
mess = CFG_WEBACCESS_WARNING_MSGS[msgcode] % args['login_method']
if msgcode == 14:
if webuser.username_exists_p(args['p_un']):
mess = CFG_WEBACCESS_WARNING_MSGS[15] % args['login_method']
act = "login"
return page(title=_("Login"),
body=webaccount.perform_back(mess, act, _("login"), args['ln']),
navtrail="""""" % (sweburl, args['ln']) + _("Your Account") + """""",
description=_("%s Personalize, Main page") % cdsnameintl.get(args['ln'], cdsname),
keywords=_("%s , personalize") % cdsnameintl.get(args['ln'], cdsname),
uid=uid,
req=req,
secure_page_p = 1,
language=args['ln'],
lastupdated=__lastupdated__,
navmenuid='login')
def register(self, req, form):
args = wash_urlargd(form, {
'p_nickname': (str, None),
'p_email': (str, None),
'p_pw': (str, None),
'p_pw2': (str, None),
'action': (str, "login"),
'referer': (str, "")})
if CFG_ACCESS_CONTROL_LEVEL_SITE > 0:
return webuser.page_not_authorized(req, "../youraccount/register?ln=%s" % args['ln'],
navmenuid='login')
uid = webuser.getUid(req)
# load the right message language
_ = gettext_set_language(args['ln'])
if args['p_nickname'] is None or args['p_email'] is None:
return page(title=_("Register"),
body=webaccount.create_register_page_box(args['referer'], args['ln']),
navtrail="""""" % (sweburl, args['ln']) + _("Your Account") + """""",
description=_("%s Personalize, Main page") % cdsnameintl.get(args['ln'], cdsname),
keywords=_("%s , personalize") % cdsnameintl.get(args['ln'], cdsname),
uid=uid,
req=req,
secure_page_p = 1,
language=args['ln'],
lastupdated=__lastupdated__,
navmenuid='login')
mess = ""
act = ""
if args['p_pw'] == args['p_pw2']:
ruid = webuser.registerUser(req, args['p_email'], args['p_pw'], args['p_nickname'])
else:
ruid = -2
if ruid == 0:
uid = webuser.update_Uid(req, args['p_email'])
mess = _("Your account has been successfully created.")
title = _("Account created")
if CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_NEW_ACCOUNT == 1:
mess += _("An email has been sent to the given address with the account information.")
if CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS >= 1:
mess += _("A second email will be sent when the account has been activated and can be used.")
else:
mess += " " + _("You can now access your %(x_url_open)saccount%(x_url_close)s.") %\
{'x_url_open': '',
'x_url_close': ''}
elif ruid == -2:
mess = _("Both passwords must match.")
mess += " " + _("Please try again.")
act = "register"
title = _("Registration failure")
elif ruid == 1:
mess = _("Supplied email address %s is invalid.") % args['p_email']
mess += " " + _("Please try again.")
act = "register"
title = _("Registration failure")
elif ruid == 2:
mess = _("Desired nickname %s is invalid.") % args['p_nickname']
mess += " " + _("Please try again.")
act = "register"
title = _("Registration failure")
elif ruid == 3:
mess = _("Supplied email address %s already exists in the database.") % args['p_email']
mess += " " + websession_templates.tmpl_lost_your_password_teaser(args['ln'])
mess += " " + _("Or please try again.")
act = "register"
title = _("Registration failure")
elif ruid == 4:
mess = _("Desired nickname %s already exists in the database.") % args['p_nickname']
mess += " " + _("Please try again.")
act = "register"
title = _("Registration failure")
elif ruid == 5:
mess = _("Users cannot register themselves, only admin can register them.")
act = "register"
title = _("Registration failure")
else:
# this should never happen
mess = _("Internal Error")
act = "register"
title = _("Registration failure")
return page(title=title,
body=webaccount.perform_back(mess,act, (act == 'register' and _("register") or ""), args['ln']),
navtrail="""""" % (sweburl, args['ln']) + _("Your Account") + """""",
description=_("%s Personalize, Main page") % cdsnameintl.get(args['ln'], cdsname),
keywords=_("%s , personalize") % cdsnameintl.get(args['ln'], cdsname),
uid=uid,
req=req,
secure_page_p = 1,
language=args['ln'],
lastupdated=__lastupdated__,
navmenuid='login')
class WebInterfaceYourGroupsPages(WebInterfaceDirectory):
_exports = ['', 'display', 'create', 'join', 'leave', 'edit', 'members']
def index(self, req, form):
redirect_to_url(req, '/yourgroups/display')
def display(self, req, form):
"""
Displays groups the user is admin of
and the groups the user is member of(but not admin)
@param ln: language
@return the page for all the groups
"""
argd = wash_urlargd(form, {})
uid = webuser.getUid(req)
# load the right message language
_ = gettext_set_language(argd['ln'])
if uid == -1 or webuser.isGuestUser(uid) or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
return webuser.page_not_authorized(req, "../yourgroups/display",
navmenuid='yourgroups')
(body, errors, warnings) = webgroup.perform_request_groups_display(uid=uid,
ln=argd['ln'])
return page(title = _("Your Groups"),
body = body,
navtrail = webgroup.get_navtrail(argd['ln']),
uid = uid,
req = req,
language = argd['ln'],
lastupdated = __lastupdated__,
errors = errors,
warnings = warnings,
navmenuid = 'yourgroups')
def create(self, req, form):
"""create(): interface for creating a new group
@param group_name : name of the new webgroup.Must be filled
@param group_description : description of the new webgroup.(optionnal)
@param join_policy : join policy of the new webgroup.Must be chosen
@param *button: which button was pressed
@param ln: language
@return the compose page Create group
"""
argd = wash_urlargd(form, {'group_name': (str, ""),
'group_description': (str, ""),
'join_policy': (str, ""),
'create_button':(str, ""),
'cancel':(str, "")
})
uid = webuser.getUid(req)
# load the right message language
_ = gettext_set_language(argd['ln'])
if uid == -1 or webuser.isGuestUser(uid) or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
return webuser.page_not_authorized(req, "../yourgroups/create",
navmenuid='yourgroups')
if argd['cancel']:
url = weburl + '/yourgroups/display?ln=%s'
url %= argd['ln']
redirect_to_url(req, url)
if argd['create_button'] :
(body, errors, warnings)= webgroup.perform_request_create_group(uid=uid,
group_name=argd['group_name'],
group_description=argd['group_description'],
join_policy=argd['join_policy'],
ln = argd['ln'])
else:
(body, errors, warnings) = webgroup.perform_request_input_create_group(group_name=argd['group_name'],
group_description=argd['group_description'],
join_policy=argd['join_policy'],
ln=argd['ln'])
title = _("Create new group")
return page(title = title,
body = body,
navtrail = webgroup.get_navtrail(argd['ln'], title),
uid = uid,
req = req,
language = argd['ln'],
lastupdated = __lastupdated__,
errors = errors,
warnings = warnings,
navmenuid = 'yourgroups')
def join(self, req, form):
"""join(): interface for joining a new group
@param grpID : list of the group the user wants to become a member.
The user must select only one group.
@param group_name : will search for groups matching group_name
@param *button: which button was pressed
@param ln: language
@return the compose page Join group
"""
argd = wash_urlargd(form, {'grpID':(list, []),
'group_name':(str, ""),
'find_button':(str, ""),
'join_button':(str, ""),
'cancel':(str, "")
})
uid = webuser.getUid(req)
# load the right message language
_ = gettext_set_language(argd['ln'])
if uid == -1 or webuser.isGuestUser(uid) or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
return webuser.page_not_authorized(req, "../yourgroups/join",
navmenuid='yourgroups')
if argd['cancel']:
url = weburl + '/yourgroups/display?ln=%s'
url %= argd['ln']
redirect_to_url(req, url)
if argd['join_button']:
search = 0
if argd['group_name']:
search = 1
(body, errors, warnings) = webgroup.perform_request_join_group(uid,
argd['grpID'],
argd['group_name'],
search,
argd['ln'])
else:
search = 0
if argd['find_button']:
search = 1
(body, errors, warnings) = webgroup.perform_request_input_join_group(uid,
argd['group_name'],
search,
ln=argd['ln'])
title = _("Join New Group")
return page(title = title,
body = body,
navtrail = webgroup.get_navtrail(argd['ln'], title),
uid = uid,
req = req,
language = argd['ln'],
lastupdated = __lastupdated__,
errors = errors,
warnings = warnings,
navmenuid = 'yourgroups')
def leave(self, req, form):
"""leave(): interface for leaving a group
@param grpID : group the user wants to leave.
@param group_name : name of the group the user wants to leave
@param *button: which button was pressed
@param confirmed : the user is first asked to confirm
@param ln: language
@return the compose page Leave group
"""
argd = wash_urlargd(form, {'grpID':(str, ""),
'group_name':(str, ""),
'leave_button':(str, ""),
'cancel':(str, ""),
'confirmed': (int, 0)
})
uid = webuser.getUid(req)
# load the right message language
_ = gettext_set_language(argd['ln'])
if uid == -1 or webuser.isGuestUser(uid) or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
return webuser.page_not_authorized(req, "../yourgroups/leave",
navmenuid='yourgroups')
if argd['cancel']:
url = weburl + '/yourgroups/display?ln=%s'
url %= argd['ln']
redirect_to_url(req, url)
if argd['leave_button']:
(body, errors, warnings) = webgroup.perform_request_leave_group(uid,
argd['grpID'],
argd['confirmed'],
argd['ln'])
else:
(body, errors, warnings) = webgroup.perform_request_input_leave_group(uid=uid,
ln=argd['ln'])
title = _("Leave Group")
return page(title = title,
body = body,
navtrail = webgroup.get_navtrail(argd['ln'], title),
uid = uid,
req = req,
language = argd['ln'],
lastupdated = __lastupdated__,
errors = errors,
warnings = warnings,
navmenuid = 'yourgroups')
def edit(self, req, form):
"""edit(): interface for editing group
@param grpID : group ID
@param group_name : name of the new webgroup.Must be filled
@param group_description : description of the new webgroup.(optionnal)
@param join_policy : join policy of the new webgroup.Must be chosen
@param update: button update group pressed
@param delete: button delete group pressed
@param cancel: button cancel pressed
@param confirmed : the user is first asked to confirm before deleting
@param ln: language
@return the main page displaying all the groups
"""
argd = wash_urlargd(form, {'grpID': (str, ""),
'update': (str, ""),
'cancel': (str, ""),
'delete': (str, ""),
'group_name': (str, ""),
'group_description': (str, ""),
'join_policy': (str, ""),
'confirmed': (int, 0)
})
uid = webuser.getUid(req)
# load the right message language
_ = gettext_set_language(argd['ln'])
if uid == -1 or webuser.isGuestUser(uid) or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
return webuser.page_not_authorized(req, "../yourgroups/display",
navmenuid='yourgroups')
if argd['cancel']:
url = weburl + '/yourgroups/display?ln=%s'
url %= argd['ln']
redirect_to_url(req, url)
elif argd['delete']:
(body, errors, warnings) = webgroup.perform_request_delete_group(uid=uid,
grpID=argd['grpID'],
confirmed=argd['confirmed'])
elif argd['update']:
(body, errors, warnings) = webgroup.perform_request_update_group(uid= uid,
grpID=argd['grpID'],
group_name=argd['group_name'],
group_description=argd['group_description'],
join_policy=argd['join_policy'],
ln=argd['ln'])
else :
(body, errors, warnings)= webgroup.perform_request_edit_group(uid=uid,
grpID=argd['grpID'],
ln=argd['ln'])
title = _("Edit Group")
return page(title = title,
body = body,
navtrail = webgroup.get_navtrail(argd['ln'], title),
uid = uid,
req = req,
language = argd['ln'],
lastupdated = __lastupdated__,
errors = errors,
warnings = warnings,
navmenuid = 'yourgroups')
def members(self, req, form):
"""member(): interface for managing members of a group
@param grpID : group ID
@param add_member: button add_member pressed
@param remove_member: button remove_member pressed
@param reject_member: button reject__member pressed
@param delete: button delete group pressed
@param member_id : ID of the existing member selected
@param pending_member_id : ID of the pending member selected
@param cancel: button cancel pressed
@param info : info about last user action
@param ln: language
@return the same page with data updated
"""
argd = wash_urlargd(form, {'grpID': (int, 0),
'cancel': (str, ""),
'add_member': (str, ""),
'remove_member': (str, ""),
'reject_member': (str, ""),
'member_id': (int, 0),
'pending_member_id': (int, 0)
})
uid = webuser.getUid(req)
# load the right message language
_ = gettext_set_language(argd['ln'])
if uid == -1 or webuser.isGuestUser(uid) or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
return webuser.page_not_authorized(req, "../yourgroups/display",
navmenuid='yourgroups')
if argd['cancel']:
url = weburl + '/yourgroups/display?ln=%s'
url %= argd['ln']
redirect_to_url(req, url)
if argd['remove_member']:
(body, errors, warnings) = webgroup.perform_request_remove_member(uid=uid,
grpID=argd['grpID'],
member_id=argd['member_id'],
ln=argd['ln'])
elif argd['reject_member']:
(body, errors, warnings) = webgroup.perform_request_reject_member(uid=uid,
grpID=argd['grpID'],
user_id=argd['pending_member_id'],
ln=argd['ln'])
elif argd['add_member']:
(body, errors, warnings) = webgroup.perform_request_add_member(uid=uid,
grpID=argd['grpID'],
user_id=argd['pending_member_id'],
ln=argd['ln'])
else:
(body, errors, warnings)= webgroup.perform_request_manage_member(uid=uid,
grpID=argd['grpID'],
ln=argd['ln'])
title = _("Edit group members")
return page(title = title,
body = body,
navtrail = webgroup.get_navtrail(argd['ln'], title),
uid = uid,
req = req,
language = argd['ln'],
lastupdated = __lastupdated__,
errors = errors,
warnings = warnings,
navmenuid = 'yourgroups')
diff --git a/modules/websession/lib/webuser.py b/modules/websession/lib/webuser.py
index 9cf75919f..cdfda396a 100644
--- a/modules/websession/lib/webuser.py
+++ b/modules/websession/lib/webuser.py
@@ -1,852 +1,852 @@
# -*- coding: utf-8 -*-
##
## $Id$
##
## This file is part of CDS Invenio.
## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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.
"""
This file implements all methods necessary for working with users and
sessions in CDS Invenio. Contains methods for logging/registration
when a user log/register into the system, checking if it is a guest
user or not.
At the same time this presents all the stuff it could need with
sessions managements, working with websession.
It also contains Apache-related user authentication stuff.
"""
__revision__ = "$Id$"
import marshal
from zlib import compress, decompress
from socket import gethostbyname
import time
import os
import crypt
import string
import smtplib
import re
import random
from invenio.config import \
CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS, \
CFG_ACCESS_CONTROL_LEVEL_GUESTS, \
CFG_ACCESS_CONTROL_LEVEL_SITE, \
CFG_ACCESS_CONTROL_LIMIT_REGISTRATION_TO_DOMAIN, \
CFG_ACCESS_CONTROL_NOTIFY_ADMIN_ABOUT_NEW_ACCOUNTS, \
CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_NEW_ACCOUNT, \
CFG_APACHE_GROUP_FILE, \
CFG_APACHE_PASSWORD_FILE, \
adminemail, \
cdslang, \
cdsname, \
supportemail, \
sweburl, \
tmpdir, \
version, \
weburl
from invenio import session, websession
from invenio.dbquery import run_sql, escape_string, OperationalError
from invenio.websession import pSession, pSessionMapping
from invenio.session import SessionError
from invenio.access_control_config import *
-from invenio.access_control_admin import acc_findUserRoleActions
+from invenio.access_control_admin import acc_find_user_role_actions
from invenio.messages import gettext_set_language
from invenio.webinterface_handler import http_get_credentials
from invenio.webgroup_dblayer import get_groups
from invenio.external_authentication import WebAccessExternalAuthError
import invenio.template
tmpl = invenio.template.load('websession')
re_invalid_nickname = re.compile(""".*[,'@]+.*""")
# pylint: disable-msg=C0301
def createGuestUser():
"""Create a guest user , insert into user null values in all fields
createGuestUser() -> GuestUserID
"""
if CFG_ACCESS_CONTROL_LEVEL_GUESTS == 0:
try:
return run_sql("insert into user (email, note) values ('', '1')")
except OperationalError:
return None
elif CFG_ACCESS_CONTROL_LEVEL_GUESTS >= 1:
try:
return run_sql("insert into user (email, note) values ('', '0')")
except OperationalError:
return None
def page_not_authorized(req, referer='', uid='', text='', navtrail='', ln=cdslang,
navmenuid=""):
"""Show error message when account is not activated"""
from invenio.webpage import page
_ = gettext_set_language(ln)
if not CFG_ACCESS_CONTROL_LEVEL_SITE:
title = CFG_WEBACCESS_MSGS[5]
if not uid:
uid = getUid(req)
try:
res = run_sql("SELECT email FROM user WHERE id=%s" % uid)
if res and res[0][0]:
if text:
body = text
else:
body = "%s %s" % (CFG_WEBACCESS_WARNING_MSGS[9] % res[0][0],
("%s %s" % (CFG_WEBACCESS_MSGS[0] % referer, CFG_WEBACCESS_MSGS[1])))
else:
if text:
body = text
else:
if CFG_ACCESS_CONTROL_LEVEL_GUESTS == 1:
body = CFG_WEBACCESS_MSGS[3]
else:
body = CFG_WEBACCESS_WARNING_MSGS[4] + CFG_WEBACCESS_MSGS[2]
except OperationalError, e:
body = _("Database problem") + ': ' + str(e)
elif CFG_ACCESS_CONTROL_LEVEL_SITE == 1:
title = CFG_WEBACCESS_MSGS[8]
body = "%s %s" % (CFG_WEBACCESS_MSGS[7], CFG_WEBACCESS_MSGS[2])
elif CFG_ACCESS_CONTROL_LEVEL_SITE == 2:
title = CFG_WEBACCESS_MSGS[6]
body = "%s %s" % (CFG_WEBACCESS_MSGS[4], CFG_WEBACCESS_MSGS[2])
return page(title=title,
uid=getUid(req),
body=body,
navtrail=navtrail,
req=req,
navmenuid=navmenuid)
def getApacheUser(req):
"""Return the ApacheUser taking it from the cookie of the request."""
sm = session.MPSessionManager(pSession, pSessionMapping())
try:
s = sm.get_session(req)
except SessionError:
sm.revoke_session_cookie (req)
s = sm.get_session(req)
apache_user = s.getApacheUser()
sm.maintain_session(req, s)
return apache_user
def getUid (req):
"""Return user ID taking it from the cookie of the request.
Includes control mechanism for the guest users, inserting in
the database table when need be, raising the cookie back to the
client.
User ID is set to 0 when client refuses cookie or we are in the
read-only site operation mode.
User ID is set to -1 when we are in the permission denied site
operation mode.
getUid(req) -> userId
"""
if CFG_ACCESS_CONTROL_LEVEL_SITE == 1: return 0
if CFG_ACCESS_CONTROL_LEVEL_SITE == 2: return -1
guest = 0
sm = session.MPSessionManager(pSession, pSessionMapping())
try:
s = sm.get_session(req)
except SessionError:
sm.revoke_session_cookie (req)
s = sm.get_session(req)
userId = s.getUid()
if userId == -1: # first time, so create a guest user
s.setUid(createGuestUser())
userId = s.getUid()
guest = 1
sm.maintain_session(req, s)
if guest == 0:
guest = isGuestUser(userId)
if guest:
if CFG_ACCESS_CONTROL_LEVEL_GUESTS == 0:
return userId
elif CFG_ACCESS_CONTROL_LEVEL_GUESTS >= 1:
return -1
else:
res = run_sql("SELECT note FROM user WHERE id=%s" % userId)
if CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS == 0:
return userId
elif CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS >= 1 and res and res[0][0] in [1, "1"]:
return userId
else:
return -1
def setApacheUser(req, apache_user):
"""It sets the apache_user into the session, and raise the cookie to the client.
"""
sm = session.MPSessionManager(pSession, pSessionMapping())
try:
s = sm.get_session(req)
except SessionError:
sm.revoke_session_cookie(req)
s = sm.get_session(req)
s.setApacheUser(apache_user)
sm.maintain_session(req, s)
return apache_user
def setUid(req, uid):
"""It sets the userId into the session, and raise the cookie to the client.
"""
sm = session.MPSessionManager(pSession, pSessionMapping())
try:
s = sm.get_session(req)
except SessionError:
sm.revoke_session_cookie(req)
s = sm.get_session(req)
s.setUid(uid)
sm.maintain_session(req, s)
return uid
def get_user_info(uid, ln=cdslang):
"""Get infos for a given user.
@param uid: user id (int)
@return tuple: (uid, nickname, display_name)
"""
_ = gettext_set_language(ln)
query = """SELECT id, nickname
FROM user
WHERE id=%i"""
res = run_sql(query%uid)
if res:
if res[0]:
user = list(res[0])
if user[1]:
user.append(user[1])
else:
user[1] = str(user[0])
user.append(_("user") + ' #' + str(user[0]))
return tuple(user)
return (uid, '', _("N/A"))
def isGuestUser(uid):
"""It Checks if the userId corresponds to a guestUser or not
isGuestUser(uid) -> boolean
"""
out = 1
try:
res = run_sql("select email from user where id=%s", (uid,))
if res:
if res[0][0]:
out = 0
except OperationalError:
pass
return out
def isUserSubmitter(user_info):
"""Return True if the user is a submitter for something; False otherwise."""
u_email = get_email(user_info['uid'])
res = run_sql("select * from sbmSUBMISSIONS where email=%s", (u_email,))
return len(res) > 0
def isUserReferee(user_info):
"""Return True if the user is a referee for something; False otherwise."""
from invenio.access_control_engine import acc_authorize_action
res = run_sql("select sdocname from sbmDOCTYPE")
for row in res:
doctype = row[0]
categ = "*"
(auth_code, auth_message) = acc_authorize_action(user_info, "referee", doctype=doctype, categ=categ)
if auth_code == 0:
return 1
res2 = run_sql("select sname from sbmCATEGORIES where doctype=%s", (doctype,))
for row2 in res2:
categ = row2[0]
(auth_code, auth_message) = acc_authorize_action(user_info, "referee", doctype=doctype, categ=categ)
if auth_code == 0:
return 1
return 0
def isUserAdmin(user_info):
"""Return True if the user has some admin rights; False otherwise."""
- return acc_findUserRoleActions(user_info)
+ return acc_find_user_role_actions(user_info)
def nickname_valid_p(nickname):
"""Check whether wanted NICKNAME supplied by the user is valid.
At the moment we just check whether it is not empty, does not
contain blanks or @, is not equal to `guest', etc.
This check relies on re_invalid_nickname regexp (see above)
Return 1 if nickname is okay, return 0 if it is not.
"""
if nickname and \
not(nickname.startswith(' ') or nickname.endswith(' ')) and \
nickname.lower() != 'guest':
if not re_invalid_nickname.match(nickname):
return 1
return 0
def email_valid_p(email):
"""Check whether wanted EMAIL address supplied by the user is valid.
At the moment we just check whether it contains '@' and whether
it doesn't contain blanks. We also check the email domain if
CFG_ACCESS_CONTROL_LIMIT_REGISTRATION_TO_DOMAIN is set.
Return 1 if email is okay, return 0 if it is not.
"""
if (string.find(email, "@") <= 0) or (string.find(email, " ") > 0):
return 0
elif CFG_ACCESS_CONTROL_LIMIT_REGISTRATION_TO_DOMAIN:
if not email.endswith(CFG_ACCESS_CONTROL_LIMIT_REGISTRATION_TO_DOMAIN):
return 0
return 1
def registerUser(req, email, passw, nickname, register_without_nickname=False):
"""Register user with the desired values of NICKNAME, EMAIL and
PASSW.
If REGISTER_WITHOUT_NICKNAME is set to True, then ignore
desired NICKNAME and do not set any. This is suitable for
external authentications so that people can login without
having to register an internal account first.
Return 0 if the registration is successful, 1 if email is not
valid, 2 if nickname is not valid, 3 if email is already in the
database, 4 if nickname is already in the database, 5 when
users cannot register themselves because of the site policy.
"""
# is email valid?
email = email.lower()
if not email_valid_p(email):
return 1
# is email already taken?
res = run_sql("SELECT * FROM user WHERE email=%s", (email,))
if len(res) > 0:
return 3
if register_without_nickname:
# ignore desired nick and use default empty string one:
nickname = ""
else:
# is nickname valid?
if not nickname_valid_p(nickname):
return 2
# is nickname already taken?
res = run_sql("SELECT * FROM user WHERE nickname=%s", (nickname,))
if len(res) > 0:
return 4
# okay, go on and register the user:
if CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS == 0:
activated = 1
elif CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS == 1:
activated = 0
elif CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS >= 2:
return 5
user_preference = get_default_user_preferences()
setUid(req, run_sql("INSERT INTO user (nickname, email, password, note, settings) VALUES (%s,%s,AES_ENCRYPT(email,%s),%s,%s)",
(nickname, email, passw, activated, serialize_via_marshal(user_preference),)))
if CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_NEW_ACCOUNT:
sendNewUserAccountWarning(email, email, passw)
if CFG_ACCESS_CONTROL_NOTIFY_ADMIN_ABOUT_NEW_ACCOUNTS:
sendNewAdminAccountWarning(email, adminemail)
return 0
def updateDataUser(uid, email, nickname):
"""
Update user data. Used when a user changed his email or password
or nickname.
"""
email = email.lower()
if email == 'guest':
return 0
if CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS < 2:
run_sql("update user set email=%s where id=%s", (email, uid))
if nickname and nickname != '':
run_sql("update user set nickname=%s where id=%s", (nickname, uid))
return 1
def updatePasswordUser(uid, password):
"""Update the password of a user."""
if CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS < 3:
run_sql("update user set password=AES_ENCRYPT(email,%s) where id=%s", (password, uid))
return 1
def loginUser(req, p_un, p_pw, login_method):
"""It is a first simple version for the authentication of user. It returns the id of the user,
for checking afterwards if the login is correct
"""
# p_un passed may be an email or a nickname:
p_email = get_email_from_username(p_un)
# go on with the old stuff based on p_email:
if not CFG_EXTERNAL_AUTHENTICATION.has_key(login_method):
return ([], p_email, p_pw, 12)
if CFG_EXTERNAL_AUTHENTICATION[login_method][0]: # External Authenthication
try:
p_email = CFG_EXTERNAL_AUTHENTICATION[login_method][0].auth_user(p_email, p_pw, req)
except WebAccessExternalAuthError:
return([], p_email, p_pw, 16)
if p_email: # Authenthicated externally
query_result = run_sql("SELECT id from user where email=%s", (p_email,))
if not query_result: # First time user
p_pw_local = int(random.random() * 1000000)
p_nickname = ''
if CFG_EXTERNAL_AUTHENTICATION[login_method][0].enforce_external_nicknames:
try: # Let's discover the external nickname!
p_nickname = CFG_EXTERNAL_AUTHENTICATION[login_method][0].fetch_user_nickname(p_email, p_pw, req)
except (AttributeError, NotImplementedError):
pass
res = registerUser(req, p_email, p_pw_local, p_nickname, \
register_without_nickname=p_nickname == '')
if res == 4 or res == 2: # The nickname was already taken
res = registerUser(req, p_email, p_pw_local, '', register_without_nickname=True)
if res == 0: # Everything was ok, with or without nickname.
query_result = run_sql("SELECT id from user where email=%s", (p_email,))
else:
return([], p_email, p_pw_local, 13)
try:
groups = CFG_EXTERNAL_AUTHENTICATION[login_method][0].fetch_user_groups_membership(p_email, p_pw, req)
# groups is a dictionary {group_name : group_description,}
new_groups = {}
for key, value in groups.items():
new_groups[key + " [" + str(login_method) + "]"] = value
groups = new_groups
except (AttributeError, NotImplementedError):
pass
except WebAccessExternalAuthError:
return([], p_email, p_pw, 16)
else: # Groups synchronization
if groups != 0:
userid = query_result[0][0]
from invenio.webgroup import synchronize_external_groups
synchronize_external_groups(userid, groups, login_method)
user_prefs = get_user_preferences(query_result[0][0])
if CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS >= 4:
# Let's prevent the user to switch login_method
if user_prefs.has_key("login_method") and \
user_prefs["login_method"] != login_method:
return([], p_email, p_pw, 11)
user_prefs["login_method"] = login_method
# Cleaning external settings
for key in user_prefs.keys():
if key.startswith('EXTERNAL_'):
del user_prefs[key]
try:
# Importing external settings
new_prefs = CFG_EXTERNAL_AUTHENTICATION[login_method][0].fetch_user_preferences(p_email, p_pw, req)
for key, value in new_prefs.items():
user_prefs['EXTERNAL_' + key] = value
except (AttributeError, NotImplementedError):
pass
except WebAccessExternalAuthError:
return([], p_email, p_pw, 16)
# Storing settings
set_user_preferences(query_result[0][0], user_prefs)
else:
return ([], p_un, p_pw, 10)
else: # Internal Authenthication
if not p_pw:
p_pw = ''
query_result = run_sql("SELECT id,email from user where email=%s and password=AES_ENCRYPT(email,%s)", (p_email, p_pw,))
if query_result:
#FIXME drop external groups and settings
preferred_login_method = get_user_preferences(query_result[0][0])['login_method']
p_email = query_result[0][1]
if login_method != preferred_login_method:
if CFG_EXTERNAL_AUTHENTICATION.has_key(preferred_login_method):
return ([], p_email, p_pw, 11)
else:
return ([], p_email, p_pw, 14)
# Login successful! Updating the last access time
run_sql("UPDATE user SET last_login=NOW() WHERE email=%s", (p_email, ))
return (query_result, p_email, p_pw, 0)
def drop_external_settings(userId):
"""Drop the external (EXTERNAL_) settings of userid."""
prefs = get_user_preferences(userId)
for key in prefs.keys():
if key.startswith('EXTERNAL_'):
del prefs[key]
set_user_preferences(userId, prefs)
def logoutUser(req):
"""It logout the user of the system, creating a guest user.
"""
getUid(req)
sm = session.MPSessionManager(pSession, pSessionMapping())
try:
s = sm.get_session(req)
except SessionError:
sm.revoke_session_cookie(req)
s = sm.get_session(req)
id1 = createGuestUser()
s.setUid(id1)
sm.maintain_session(req, s)
return id1
def username_exists_p(username):
"""Check if USERNAME exists in the system. Username may be either
nickname or email.
Return 1 if it does exist, 0 if it does not.
"""
if username == "":
# return not exists if asked for guest users
return 0
res = run_sql("SELECT email FROM user WHERE email=%s", (username,)) + \
run_sql("SELECT email FROM user WHERE nickname=%s", (username,))
if len(res) > 0:
return 1
return 0
def emailUnique(p_email):
"""Check if the email address only exists once. If yes, return userid, if not, -1
"""
query_result = run_sql("select id, email from user where email=%s", (p_email,))
if len(query_result) == 1:
return query_result[0][0]
elif len(query_result) == 0:
return 0
return -1
def nicknameUnique(p_nickname):
"""Check if the nickname only exists once. If yes, return userid, if not, -1
"""
query_result = run_sql("select id, nickname from user where nickname=%s", (p_nickname,))
if len(query_result) == 1:
return query_result[0][0]
elif len(query_result) == 0:
return 0
return -1
def update_Uid(req, p_email):
"""It updates the userId of the session. It is used when a guest user is logged in succesfully in the system
with a given email and password
"""
query_ID = int(run_sql("select id from user where email=%s",
(p_email,))[0][0])
setUid(req, query_ID)
return query_ID
def sendNewAdminAccountWarning(newAccountEmail, sendTo, ln=cdslang):
"""Send an email to the address given by sendTo about the new account newAccountEmail."""
_ = gettext_set_language(ln)
fromaddr = "From: %s" % supportemail
toaddrs = "To: %s" % sendTo
to = toaddrs + "\n"
sub = "Subject: New account on '%s'" % cdsname
if CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS == 1:
sub += " - PLEASE ACTIVATE"
sub += "\n\n"
body = "A new account has been created on '%s'" % cdsname
if CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS == 1:
body += " and is awaiting activation"
body += ":\n\n"
body += " Username/Email: %s\n\n" % newAccountEmail
body += "You can approve or reject this account request at: %s/admin/webaccess/webaccessadmin.py/manageaccounts\n" % weburl
body += "\n---------------------------------"
body += "\n%s" % cdsname
body += "\nContact: %s" % supportemail
msg = to + sub + body
server = smtplib.SMTP('localhost')
server.set_debuglevel(1)
try:
server.sendmail(fromaddr, toaddrs, msg)
except smtplib.SMTPRecipientsRefused:
return 0
server.quit()
return 1
def sendNewUserAccountWarning(newAccountEmail, sendTo, password, ln=cdslang):
"""Send an email to the address given by sendTo about the new account newAccountEmail."""
_ = gettext_set_language(ln)
fromaddr = "From: %s" % supportemail
toaddrs = "To: %s" % sendTo
to = toaddrs + "\n"
sub = "Subject: Your account created on '%s'\n\n" % cdsname
body = "You have created a new account on '%s':\n\n" % cdsname
body += " Username/Email: %s\n" % newAccountEmail
body += " Password: %s\n\n" % ("*" * len(password))
if CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS >= 1:
body += "This account is awaiting approval by the site administrators and therefore cannot be used as of yet.\nYou will receive an email notification as soon as your account request has been processed.\n"
body += "\n---------------------------------"
body += "\n%s" % cdsname
body += "\nContact: %s" % supportemail
msg = to + sub + body
server = smtplib.SMTP('localhost')
server.set_debuglevel(1)
try:
server.sendmail(fromaddr, toaddrs, msg)
except smtplib.SMTPRecipientsRefused:
return 0
server.quit()
return 1
def get_email(uid):
"""Return email address of the user uid. Return string 'guest' in case
the user is not found."""
out = "guest"
res = run_sql("SELECT email FROM user WHERE id=%s", (uid,), 1)
if res and res[0][0]:
out = res[0][0]
return out
def get_email_from_username(username):
"""Return email address of the user corresponding to USERNAME.
The username may be either nickname or email. Return USERNAME
untouched if not found in the database or if found several
matching entries.
"""
out = username
res = run_sql("SELECT email FROM user WHERE email=%s", (username,), 1) + \
run_sql("SELECT email FROM user WHERE nickname=%s", (username,), 1)
if res and len(res) == 1:
out = res[0][0]
return out
#def get_password(uid):
#"""Return password of the user uid. Return None in case
#the user is not found."""
#out = None
#res = run_sql("SELECT password FROM user WHERE id=%s", (uid,), 1)
#if res and res[0][0] != None:
#out = res[0][0]
#return out
def get_nickname(uid):
"""Return nickname of the user uid. Return None in case
the user is not found."""
out = None
res = run_sql("SELECT nickname FROM user WHERE id=%s", (uid,), 1)
if res and res[0][0]:
out = res[0][0]
return out
def get_nickname_or_email(uid):
"""Return nickname (preferred) or the email address of the user uid.
Return string 'guest' in case the user is not found."""
out = "guest"
res = run_sql("SELECT nickname, email FROM user WHERE id=%s", (uid,), 1)
if res and res[0]:
if res[0][0]:
out = res[0][0]
elif res[0][1]:
out = res[0][1]
return out
def create_userinfobox_body(req, uid, language="en"):
"""Create user info box body for user UID in language LANGUAGE."""
if req:
if req.subprocess_env.has_key('HTTPS') \
and req.subprocess_env['HTTPS'] == 'on':
url_referer = sweburl + req.unparsed_uri
else:
url_referer = weburl + req.unparsed_uri
else:
url_referer = weburl
try:
return tmpl.tmpl_create_userinfobox(ln=language,
url_referer=url_referer,
guest = isGuestUser(uid),
username = get_nickname_or_email(uid),
submitter = True, # FIXME isUserSubmitter(uid),
referee = True, # FIXME isUserReferee(req),
admin = True # FIXME isUserAdmin(req),
)
except OperationalError:
return ""
def list_registered_users():
"""List all registered users."""
return run_sql("SELECT id,email FROM user where email!=''")
def list_users_in_role(role):
"""List all users of a given role (see table accROLE)
@param role: role of user (string)
@return list of uids
"""
query = """SELECT uacc.id_user
FROM user_accROLE uacc JOIN accROLE acc
ON uacc.id_accROLE=acc.id
WHERE acc.name='%s'"""
res = run_sql(query% escape_string(role))
if res:
return map(lambda x: int(x[0]), res)
return []
def list_users_in_roles(role_list):
"""List all users of given roles (see table accROLE)
@param role_list: list of roles [string]
@return list of uids
"""
if not(type(role_list) is list or type(role_list) is tuple):
role_list = [role_list]
params = ''
query = """SELECT distinct(uacc.id_user)
FROM user_accROLE uacc JOIN accROLE acc
ON uacc.id_accROLE=acc.id
%s"""
if len(role_list) > 0:
params = 'WHERE '
for role in role_list[:-1]:
params += "acc.name='%s' OR " % escape_string(role)
params += "acc.name='%s'" % escape_string(role_list[-1])
res = run_sql(query% params)
if res:
return map(lambda x: int(x[0]), res)
return []
def get_user_preferences(uid):
pref = run_sql("SELECT id, settings FROM user WHERE id=%s", (uid,))
if pref:
try:
return deserialize_via_marshal(pref[0][1])
except:
pass
return get_default_user_preferences() # empty dict mean no preferences
def set_user_preferences(uid, pref):
assert(type(pref) == type({}))
run_sql("UPDATE user SET settings=%s WHERE id=%s",
(serialize_via_marshal(pref), uid))
def get_default_user_preferences():
user_preference = {
'login_method': ''}
for system in CFG_EXTERNAL_AUTHENTICATION.keys():
if CFG_EXTERNAL_AUTHENTICATION[system][1]:
user_preference['login_method'] = system
break
return user_preference
def collect_user_info(req):
"""Given the mod_python request object rec or a uid it returns a dictionary
containing at least the keys uid, nickname, email, groups, plus any external keys in
the user preferences (collected at login time and built by the different
external authentication plugins) and if the mod_python request object is
provided, also the remote_ip, remote_host, referer, agent fields.
If the user is authenticated with Apache should provide also
apache_user and apache_group.
"""
user_info = {}
if type(req) in [type(1), type(1L)]:
uid = req
else:
uid = getUid(req)
user_info['remote_ip'] = gethostbyname(req.connection.remote_ip)
user_info['remote_host'] = req.connection.remote_host or None
user_info['referer'] = req.headers_in.get('Referer', None)
user_info['uri'] = req.unparsed_uri or None
user_info['agent'] = req.headers_in.get('User-Agent', None)
try:
user_info['apache_user'] = getApacheUser(req)
if user_info['apache_user']:
user_info['apache_group'] = auth_apache_user_in_groups(user_info['apache_user'])
except AttributeError:
pass
user_info['uid'] = uid
user_info['nickname'] = get_nickname(uid) or None
user_info['email'] = get_email(uid) or None
user_info['group'] = []
user_info['guest'] = isGuestUser(uid)
if uid:
user_info['group'] = [group[1] for group in get_groups(uid)]
prefs = get_user_preferences(uid)
if prefs:
for key, value in prefs.items():
user_info[key.lower()] = value
return user_info
## --- follow some functions for Apache user/group authentication
def auth_apache_user_p(user, password, apache_password_file=CFG_APACHE_PASSWORD_FILE):
"""Check whether user-supplied credentials correspond to valid
Apache password data file. Return 0 in case of failure, 1 in case
of success."""
try:
if not apache_password_file.startswith("/"):
apache_password_file = tmpdir + "/" + apache_password_file
dummy, pipe_output = os.popen2(["grep", "^" + user + ":", apache_password_file], 'r')
line = pipe_output.readlines()[0]
password_apache = string.split(string.strip(line),":")[1]
except: # no pw found, so return not-allowed status
return False
salt = password_apache[:2]
if crypt.crypt(password, salt) == password_apache:
return True
else:
return False
def auth_apache_user_in_groups(user, apache_group_file=CFG_APACHE_GROUP_FILE):
"""Return list of Apache groups to which Apache user belong."""
out = []
try:
if not apache_group_file.startswith("/"):
apache_group_file = tmpdir + "/" + apache_group_file
dummy, pipe_output = os.popen2(["grep", user, apache_group_file], 'r')
for line in pipe_output.readlines():
out.append(string.split(string.strip(line),":")[0])
except: # no groups found, so return empty list
pass
return out
def serialize_via_marshal(obj):
"""Serialize Python object via marshal into a compressed string."""
return compress(marshal.dumps(obj))
def deserialize_via_marshal(string):
"""Decompress and deserialize string into a Python object via marshal."""
return marshal.loads(decompress(string))
diff --git a/modules/websubmit/lib/file.py b/modules/websubmit/lib/file.py
index d7fc054c2..ff5a295e3 100644
--- a/modules/websubmit/lib/file.py
+++ b/modules/websubmit/lib/file.py
@@ -1,618 +1,618 @@
## $Id$
## This file is part of CDS Invenio.
## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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.
__revision__ = "$Id$"
## import interesting modules:
import string
import os
import sys
import time
import types
import re
import mimetypes
import shutil
import md5
import urllib
from xml.sax.saxutils import quoteattr
from invenio.config import \
cdslang, \
filedir, \
filedirsize, \
images, \
storage, \
version, \
weburl
from invenio.access_control_engine import acc_authorize_action
-from invenio.access_control_admin import acc_isRole
+from invenio.access_control_admin import acc_is_role
from invenio.webpage import page, create_error_box
from invenio.webuser import getUid, get_email
from invenio.dbquery import run_sql
from invenio.websubmit_config import *
from invenio.messages import gettext_set_language
import invenio.template
websubmit_templates = invenio.template.load('websubmit')
archivepath = filedir
archivesize = filedirsize
# sort compressed file extensions list to get lengthy ones first:
CFG_COMPRESSED_FILE_EXTENSIONS_SORTED = CFG_COMPRESSED_FILE_EXTENSIONS
CFG_COMPRESSED_FILE_EXTENSIONS_SORTED.sort()
def file_strip_ext(file):
for c_ext in CFG_KNOWN_FILE_EXTENSIONS:
if file[-len(c_ext):len(file)]==c_ext and file[-len(c_ext)-1]==".":
file = file[0:-len(c_ext)-1]
return file
class BibRecDocs:
"""this class represents all the files attached to one record"""
def __init__(self,recid):
self.id = recid
self.bibdocs = []
self.buildBibDocList()
def buildBibDocList(self):
self.bibdocs = []
res = run_sql("select id_bibdoc,type,status from bibrec_bibdoc,bibdoc where id=id_bibdoc and id_bibrec=%s", (self.id,))
for row in res:
if row[2] == "":
status = 0
else:
status = int(row[2])
if status & 1 == 0:
self.bibdocs.append(BibDoc(bibdocid=row[0],recid=self.id))
def listBibDocs(self,type=""):
"""Returns the list all bibdocs object belonging to a recid.
If type is set, it returns just the bibdocs of that type.
"""
tmp=[]
for bibdoc in self.bibdocs:
if type=="" or type == bibdoc.getType():
tmp.append(bibdoc)
return tmp
def getBibDocNames(self,type="Main"):
"""Returns the names of the files associated with the bibdoc of a paritcular type"""
names = []
for bibdoc in self.listBibDocs(type):
names.append(bibdoc.getDocName())
return names
def getBibDoc(self,bibdocid):
"""Returns the bibdoc with a particular bibdocid associated with this recid"""
for bibdoc in self.bibdocs:
if bibdoc.getId() == bibdocid:
return bibdoc
return None
def deleteBibDoc(self,bibdocid):
"""Delete a bibdocid associated with the recid."""
for bibdoc in self.bibdocs:
if bibdoc.getId() == bibdocid:
bibdoc.delete()
self.buildBibDocList()
def addBibDoc(self,type="Main",docname="file"):
"""Creates a new bibdoc associated with the recid, with a file called docname
and a paritcular type. It returns the bibdoc object which was just created.
If it already exists a bibdoc with docname name, it appends _2 the necessary
number of times for having a unique name.
"""
while docname in self.getBibDocNames(type):
match = re.match("(.*_)([^_]*)",docname)
if match:
try:
docname = match.group(1)+str(int(match.group(2)) + 1)
except:
docname = docname + "_2"
else:
docname = docname + "_2"
bibdoc = BibDoc(recid=self.id,type=type,docname=docname)
if bibdoc is not None:
self.bibdocs.append(bibdoc)
return bibdoc
def addNewFile(self,fullpath,type="Main"):
"""Creates a new bibdoc given a fullpath file and store the file in it.
It returns the bibdoc object.
"""
filename = re.sub("\..*","",re.sub(r".*[\\/:]", "", fullpath))
bibdoc = self.addBibDoc(type,filename)
if bibdoc is not None:
bibdoc.addFilesNewVersion(files=[fullpath])
return bibdoc
return None
def addNewVersion(self,fullpath,bibdocid):
"""Adds a new fullpath file to an already existent bibdocid making the previous
files associated with the same bibdocids obsolete.
It returns the bibdoc object.
"""
bibdoc = self.getBibDoc(bibdocid)
if bibdoc is not None:
bibdoc.addFilesNewVersion(files=[fullpath])
docname = re.sub("\..*","",re.sub(r".*[\\/:]", "", fullpath))
if docname != bibdoc.getDocName():
while docname in self.getBibDocNames(bibdoc.getType()):
match = re.match("(.*_)([^_]*)",docname)
if match:
try:
docname = match.group(1)+str(int(match.group(2)) + 1)
except:
docname = docname + "_2"
else:
docname = docname + "_2"
bibdoc.changeName(docname)
return bibdoc
return None
def addNewFormat(self,fullpath,bibdocid):
"""Adds a new format for a fullpath file to an already existent bibdocid
along side already there files.
It returns the bibdoc object.
"""
bibdoc = self.getBibDoc(bibdocid)
if bibdoc is not None:
bibdoc.addFilesNewFormat(files=[fullpath])
return bibdoc
return None
def listLatestFiles(self,type=""):
docfiles = []
for bibdoc in self.listBibDocs(type):
for docfile in bibdoc.listLatestFiles():
docfiles.append(docfile)
return docfiles
def checkFileExists(self,fullpath,type=""):
if os.path.exists(fullpath):
docfiles = self.listLatestFiles(type)
for docfile in docfiles:
if md5.new(readfile(fullpath)).digest() == md5.new(readfile(docfile.getPath())).digest():
return docfile.getBibDocId()
else:
return 0
def display(self,bibdocid="",version="",type="", ln = cdslang):
t=""
bibdocs = []
if bibdocid!="":
for bibdoc in self.bibdocs:
if bibdoc.getId() == bibdocid:
bibdocs.append(bibdoc)
else:
bibdocs = self.listBibDocs(type)
if len(bibdocs) > 0:
types = listTypesFromArray(bibdocs)
fulltypes = []
for mytype in types:
fulltype = {
'name' : mytype,
'content' : [],
}
for bibdoc in bibdocs:
if mytype == bibdoc.getType():
fulltype['content'].append(bibdoc.display(version, ln = ln))
fulltypes.append(fulltype)
t = websubmit_templates.tmpl_bibrecdoc_filelist(
ln = ln,
types = fulltypes,
)
return t
class BibDoc:
"""this class represents one file attached to a record
there is a one to one mapping between an instance of this class and
an entry in the bibdoc db table"""
def __init__ (self,bibdocid="",recid="",docname="file",type="Main"):
# bibdocid is known, the document already exists
if bibdocid != "":
if recid == "":
res = run_sql("select id_bibrec,type from bibrec_bibdoc where id_bibdoc=%s",(bibdocid,))
if len(res) > 0:
recid = res[0][0]
self.type = res[0][1]
else:
recid = None
self.type = ""
else:
res = run_sql("select type from bibrec_bibdoc where id_bibrec=%s and id_bibdoc=%s",(recid,bibdocid,))
self.type = res[0][0]
# gather the other information
res = run_sql("select * from bibdoc where id=%s", (bibdocid,))
self.cd = res[0][3]
self.md = res[0][4]
self.recid = recid
self.docname = res[0][2]
self.id = bibdocid
self.status = int(res[0][1])
group = "g"+str(int(int(self.id)/archivesize))
self.basedir = "%s/%s/%s" % (archivepath,group,self.id)
# else it is a new document
else:
if docname == "" or type == "":
return None
else:
self.recid = recid
self.type = type
self.docname = docname
self.status = 0
self.id = run_sql("insert into bibdoc (status,docname,creation_date,modification_date) values(%s,%s,NOW(),NOW())", (str(self.status), docname,))
if self.id is not None:
#we link the document to the record if a recid was specified
if self.recid != "":
run_sql("insert into bibrec_bibdoc values(%s,%s,%s)", (recid,self.id,self.type,))
else:
return None
group = "g"+str(int(int(self.id)/archivesize))
self.basedir = "%s/%s/%s" % (archivepath,group,self.id)
# we create the corresponding storage directory
if not os.path.exists(self.basedir):
os.makedirs(self.basedir)
# and save the father record id if it exists
if self.recid!="":
fp = open("%s/.recid" % self.basedir,"w")
fp.write(str(self.recid))
fp.close()
# build list of attached files
self.docfiles = {}
self.BuildFileList()
# link with relatedFiles
self.relatedFiles = {}
self.BuildRelatedFileList()
def addFilesNewVersion(self,files=[]):
"""add a new version of a file to an archive"""
latestVersion = self.getLatestVersion()
if latestVersion == "0":
myversion = "1"
else:
myversion = str(int(latestVersion)+1)
for file in files:
if os.path.exists(file):
filename = re.sub(r".*[\\/:]", "", file)
shutil.copy(file,"%s/%s;%s" % (self.basedir,filename,myversion))
self.BuildFileList()
def addFilesNewFormat(self,files=[],version=""):
"""add a new format of a file to an archive"""
if version == "":
version = self.getLatestVersion()
for file in files:
if os.path.exists(file):
filename = re.sub(r".*[\\/:]", "", file)
shutil.copy(file,"%s/%s;%s" % (self.basedir,filename,version))
self.BuildFileList()
def getIcon(self):
if self.relatedFiles.has_key('Icon'):
return self.relatedFiles['Icon'][0]
else:
return None
def addIcon(self,file):
"""link an icon with the bibdoc object"""
#first check if an icon already exists
existingIcon = self.getIcon()
if existingIcon is not None:
existingIcon.delete()
#then add the new one
filename = re.sub("\..*","",re.sub(r".*[\\/:]", "", file))
newicon = BibDoc(type='Icon',docname=filename)
if newicon is not None:
newicon.addFilesNewVersion(files=[file])
run_sql("insert into bibdoc_bibdoc values(%s,%s,'Icon')", (self.id,newicon.getId(),))
if os.path.exists(newicon.getBaseDir()):
fp = open("%s/.docid" % newicon.getBaseDir(),"w")
fp.write(str(self.id))
fp.close()
self.BuildRelatedFileList()
def deleteIcon(self):
existingIcon = self.getIcon()
if existingIcon is not None:
existingIcon.delete()
self.BuildRelatedFileList()
def display(self,version="", ln = cdslang):
t=""
if version == "all":
docfiles = self.listAllFiles()
elif version != "":
docfiles = self.listVersionFiles(version)
else:
docfiles = self.listLatestFiles()
existingIcon = self.getIcon()
if existingIcon is not None:
imagepath = "%s/getfile.py?docid=%s&name=%s&format=gif" % (weburl,existingIcon.getId(),urllib.quote(existingIcon.getDocName()))
else:
imagepath = "%s/smallfiles.gif" % images
versions = []
for version in listVersionsFromArray(docfiles):
currversion = {
'version' : version,
'previous' : 0,
'content' : []
}
if version == self.getLatestVersion() and version != "1":
currversion['previous'] = 1
for docfile in docfiles:
if docfile.getVersion() == version:
currversion['content'].append(docfile.display(ln = ln))
versions.append(currversion)
t = websubmit_templates.tmpl_bibdoc_filelist(
ln = ln,
weburl = weburl,
versions = versions,
imagepath = imagepath,
docname = self.docname,
id = self.id,
)
return t
def changeName(self,newname):
run_sql("update bibdoc set docname=%s where id=%s",(newname,self.id,))
self.docname = newname
def getDocName(self):
"""retrieve bibdoc name"""
return self.docname
def getBaseDir(self):
"""retrieve bibdoc base directory"""
return self.basedir
def getType(self):
"""retrieve bibdoc type"""
return self.type
def getRecid(self):
"""retrieve bibdoc recid"""
return self.recid
def getId(self):
"""retrieve bibdoc id"""
return self.id
def getFile(self,name,format,version):
if version == "":
docfiles = self.listLatestFiles()
else:
docfiles = self.listVersionFiles(version)
for docfile in docfiles:
if docfile.getName()==name and docfile.getFormat()==format:
return docfile
return None
def listVersions(self):
versions = []
for docfile in self.docfiles:
if not docfile.getVersion() in versions:
versions.append(docfile.getVersion())
return versions
def delete(self):
"""delete the current bibdoc instance"""
self.status = self.status | 1
run_sql("update bibdoc set status='" + str(self.status) + "' where id=%s",(self.id,))
def BuildFileList(self):
"""lists all files attached to the bibdoc"""
self.docfiles = []
if os.path.exists(self.basedir):
for fil in os.listdir(self.basedir):
if fil != ".recid" and fil != ".docid" and fil != "." and fil != "..":
filepath = "%s/%s" % (self.basedir,fil)
fileversion = re.sub(".*;","",fil)
fullname = fil.replace(";%s" % fileversion,"")
# detect fullname's basename and extension:
fullname_lowercase = fullname.lower()
fullname_extension_postition = -1
# first try to detect compressed file extensions:
for compressed_file_extension in CFG_COMPRESSED_FILE_EXTENSIONS_SORTED:
if fullname_lowercase.endswith("." + compressed_file_extension):
fullname_extension_postition = fullname[:-len(compressed_file_extension)-1].rfind(".")
break
if fullname_extension_postition == -1:
# okay, no compressed extension found, so try to find last dot:
fullname_extension_postition = len(file_strip_ext(fullname))
# okay, fullname_extension_postition should now indicate where extension starts (incl. compressed ones)
if fullname_extension_postition == -1:
fullname_basename = fullname
fullname_extension = ""
else:
fullname_basename = fullname[:fullname_extension_postition]
fullname_extension = fullname[fullname_extension_postition+1:]
# we can append file:
self.docfiles.append(BibDocFile(filepath,self.type,fileversion,fullname_basename,fullname_extension,self.id,self.status))
def BuildRelatedFileList(self):
res = run_sql("select ln.id_bibdoc2,ln.type,bibdoc.status from bibdoc_bibdoc as ln,bibdoc where id=ln.id_bibdoc2 and ln.id_bibdoc1=%s",(self.id,))
for row in res:
bibdocid = row[0]
type = row[1]
if row[2] == "":
status = 0
else:
status = int(row[2])
if status & 1 == 0:
if not self.relatedFiles.has_key(type):
self.relatedFiles[type] = []
self.relatedFiles[type].append(BibDoc(bibdocid=bibdocid))
def listAllFiles(self):
return self.docfiles
def listLatestFiles(self):
return self.listVersionFiles(self.getLatestVersion())
def listVersionFiles(self,version):
tmp = []
for docfile in self.docfiles:
if docfile.getVersion() == version:
tmp.append(docfile)
return tmp
def getLatestVersion(self):
if len(self.docfiles) > 0:
self.docfiles.sort(orderFilesWithVersion)
return self.docfiles[0].getVersion()
else:
return 0
def getFileNumber(self):
return len(self.files)
def registerDownload(self,addressIp,version,format,userid=0):
return run_sql("INSERT INTO rnkDOWNLOADS (id_bibrec,id_bibdoc,file_version,file_format,id_user,client_host,download_time) VALUES (%s,%s,%s,%s,%s,INET_ATON(%s),NOW())",
(self.recid,self.id,version,string.upper(format),userid,addressIp,))
class BibDocFile:
"""this class represents a physical file in the CDS Invenio filesystem"""
def __init__(self,fullpath,type,version,name,format,bibdocid,status):
self.fullpath = fullpath
self.type = type
self.bibdocid = bibdocid
self.version = version
self.status = status
self.size = os.path.getsize(fullpath)
self.md = os.path.getmtime(fullpath)
try:
self.cd = os.path.getctime(fullpath)
except:
self.cd = self.md
self.name = name
self.format = format
self.dir = os.path.dirname(fullpath)
if format == "":
self.mime = "text/plain"
self.encoding = ""
self.fullname = name
else:
self.fullname = "%s.%s" % (name,format)
(self.mime,self.encoding) = mimetypes.guess_type(self.fullname)
if self.mime is None:
self.mime = "text/plain"
def display(self, ln = cdslang):
if self.format != "":
format = ".%s" % self.format
else:
format = ""
return websubmit_templates.tmpl_bibdocfile_filelist(
ln = ln,
weburl = weburl,
id = self.bibdocid,
selfformat = self.format,
version = self.version,
name = self.name,
format = format,
size = self.size,
)
def isRestricted(self):
"""return restriction state"""
if int(self.status) & 10 == 10:
return 1
return 0
def getType(self):
return self.type
def getPath(self):
return self.fullpath
def getBibDocId(self):
return self.bibdocid
def getName(self):
return self.name
def getFormat(self):
return self.format
def getSize(self):
return self.size
def getVersion(self):
return self.version
def getRecid(self):
return run_sql("select id_bibrec from bibrec_bibdoc where id_bibdoc=%s",(self.bibdocid,))[0][0]
def stream(self,req):
if os.path.exists(self.fullpath):
req.content_type = self.mime
req.encoding = self.encoding
req.filename = self.fullname
req.headers_out["Content-Disposition"] = "attachment; filename=%s" % quoteattr(self.fullname)
req.send_http_header()
fp = file(self.fullpath,"r")
content = fp.read()
fp.close()
return content
def readfile(path):
"""Read the contents of a text file and return them as a string.
Return an empty string if unable to access the file for reading.
@param path: (string) - path to the file
@return: (string) contents of file or empty string
"""
content = ""
if os.access(path, os.F_OK|os.R_OK):
try:
fp = open(path, "r")
except IOError:
pass
else:
content = fp.read()
fp.close()
return content
def listTypesFromArray(bibdocs):
types = []
for bibdoc in bibdocs:
if not bibdoc.getType() in types:
types.append(bibdoc.getType())
return types
def listVersionsFromArray(docfiles):
versions = []
for docfile in docfiles:
if not docfile.getVersion() in versions:
versions.append(docfile.getVersion())
return versions
def orderFilesWithVersion(docfile1,docfile2):
"""order docfile objects according to their version"""
version1 = int(docfile1.getVersion())
version2 = int(docfile2.getVersion())
return cmp(version2,version1)
diff --git a/modules/websubmit/lib/functions/Send_APP_Mail.py b/modules/websubmit/lib/functions/Send_APP_Mail.py
index 17fca8533..2bfb43781 100644
--- a/modules/websubmit/lib/functions/Send_APP_Mail.py
+++ b/modules/websubmit/lib/functions/Send_APP_Mail.py
@@ -1,121 +1,121 @@
## $Id$
## This file is part of CDS Invenio.
## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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.
__revision__ = "$Id$"
## Description: function Send_APP_Mail
## This function send an email informing the original
## submitter of a document that the referee has approved/
## rejected the document. The email is also sent to the
## referee for checking.
## Author: T.Baron
## PARAMETERS:
## newrnin: name of the file containing the 2nd reference
## addressesAPP: email addresses to which the email will
## be sent (additionally to the author)
## categformatAPP: variable needed to derive the addresses
## mentioned above
import os
import re
from invenio.config import \
adminemail, \
cdsname, \
htdocsurl, \
supportemail
-from invenio.access_control_admin import acc_getRoleUsers,acc_getRoleId
+from invenio.access_control_admin import acc_get_role_users,acc_getRoleId
from invenio.dbquery import run_sql
from invenio.websubmit_config import CFG_WEBSUBMIT_COPY_MAILS_TO_ADMIN
from invenio.mailutils import send_email
def Send_APP_Mail (parameters,curdir,form):
global emailvalue,titlevalue,authorvalue,sysno,rn
FROMADDR = '%s Submission Engine <%s>' % (cdsname,supportemail)
doctype = form['doctype']
emailvalue = emailvalue.replace("\n","")
titlevalue = titlevalue.replace("\n","")
authorvalue = authorvalue.replace("\n","")
# variables declaration
categformat = parameters['categformatAPP']
otheraddresses = parameters['addressesAPP']
newrnpath = parameters['newrnin']
# retrieve values stored into files
if os.path.exists("%s/COM" % curdir):
fp = open("%s/COM" % curdir, "r")
comment = fp.read()
fp.close()
else:
comment = ""
if os.path.exists("%s/decision" % curdir):
fp = open("%s/decision" % curdir,"r")
decision = fp.read()
fp.close()
else:
decision = ""
if os.path.exists("%s/%s" % (curdir,newrnpath)):
fp = open("%s/%s" % (curdir,newrnpath) , "r")
newrn = fp.read()
fp.close()
else:
newrn = ""
# Document name
res = run_sql("SELECT ldocname FROM sbmDOCTYPE WHERE sdocname=%s", (doctype,))
docname = res[0][0]
# retrieve category
categformat = categformat.replace("","([^-]*)")
categs = re.match(categformat,rn)
if categs is not None:
category = categs.group(1)
else:
category = "unknown"
# Build referee's email address
refereeaddress = ""
# Try to retrieve the referee's email from the referee's database
- for user in acc_getRoleUsers(acc_getRoleId("referee_%s_%s" % (doctype,category))):
+ for user in acc_get_role_users(acc_getRoleId("referee_%s_%s" % (doctype,category))):
refereeaddress += user[1] + ","
# And if there is a general referee
- for user in acc_getRoleUsers(acc_getRoleId("referee_%s_*" % doctype)):
+ for user in acc_get_role_users(acc_getRoleId("referee_%s_*" % doctype)):
refereeaddress += user[1] + ","
refereeaddress = re.sub(",$","",refereeaddress)
# Creation of the mail for the referee
otheraddresses = otheraddresses.replace("",category)
addresses = ""
if refereeaddress != "":
addresses = refereeaddress + ","
if otheraddresses != "":
addresses += otheraddresses
else:
addresses = re.sub(",$","",addresses)
if decision == "approve":
mailtitle = "%s has been approved" % rn
mailbody = "The %s %s has been approved." % (docname,rn)
mailbody += "\nIt will soon be accessible here:\n<%s/record/%s>" % (htdocsurl,sysno)
else:
mailtitle = "%s has been rejected" % rn
mailbody = "The %s %s has been rejected." % (docname,rn)
if rn != newrn and decision == "approve" and newrn != "":
mailbody += "Its new reference number is: %s" % newrn
mailbody += "\n\nTitle: %s\n\nAuthor(s): %s\n\n" % (titlevalue,authorvalue)
if comment != "":
mailbody += "Comments from the referee:\n%s\n" % comment
mailbody += "---------------------------------------------\nBest regards.\nThe submission team.\n"
# Send mail to referee
send_email(FROMADDR,addresses,mailtitle,mailbody, copy_to_admin=CFG_WEBSUBMIT_COPY_MAILS_TO_ADMIN)
return ""
diff --git a/modules/websubmit/lib/functions/Send_Approval_Request.py b/modules/websubmit/lib/functions/Send_Approval_Request.py
index d7cab5549..5b37948c8 100644
--- a/modules/websubmit/lib/functions/Send_Approval_Request.py
+++ b/modules/websubmit/lib/functions/Send_Approval_Request.py
@@ -1,113 +1,113 @@
## $Id$
## This file is part of CDS Invenio.
## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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.
__revision__ = "$Id$"
## Description: function Send_Approval_Request
## This function sends an email to the referee asking him/her
## to approve/reject a document
## Author: T.Baron
## PARAMETERS: directory: parameter to the link manager program
## addressesDAM: address of the referee(s)
## categformatDAM: variable needed to extract the category
## of the document and use it to derive the
## address.
## authorfile: name of the file containing the author list
## titleFile: name of the file containing the title
import os
import re
from invenio.config import \
adminemail, \
cdsname, \
htdocsurl, \
supportemail, \
urlpath
from invenio.dbquery import run_sql
-from invenio.access_control_admin import acc_getRoleUsers,acc_getRoleId
+from invenio.access_control_admin import acc_get_role_users,acc_getRoleId
from invenio.websubmit_config import CFG_WEBSUBMIT_COPY_MAILS_TO_ADMIN
from invenio.mailutils import send_email
def Send_Approval_Request (parameters,curdir,form):
global rn,sysno
# variables declaration
doctype = re.search(".*/([^/]*)/([^/]*)/[^/]*$",curdir).group(2)
FROMADDR = '%s Submission Engine <%s>' % (cdsname,supportemail)
otheraddresses = parameters['addressesDAM']
categformat = parameters['categformatDAM']
# retrieve category
categformat = categformat.replace("","([^-]*)")
categs = re.match(categformat,rn)
if categs is not None:
category = categs.group(1)
else:
category = "unknown"
# create TI
if os.path.exists("%s/date" % curdir):
fp = open("%s/date" % curdir, "r")
date = fp.read()
fp.close()
else:
date = ""
if os.path.exists("%s/%s" % (curdir,parameters['titleFile'])):
fp = open("%s/%s" % (curdir,parameters['titleFile']),"r")
title = fp.read()
fp.close()
title = title.replace("\n","")
else:
title = ""
title += " - %s" % date
# create AU
if os.path.exists("%s/%s" % (curdir,parameters['authorfile'])):
fp = open("%s/%s" % (curdir,parameters['authorfile']), "r")
author = fp.read()
fp.close()
else:
author = ""
# we get the referee password
sth = run_sql("SELECT access FROM sbmAPPROVAL WHERE rn=%s", (rn,))
if len(sth) >0:
access = sth[0][0]
# Build referee's email address
refereeaddress = ""
# Try to retrieve the referee's email from the referee's database
- for user in acc_getRoleUsers(acc_getRoleId("referee_%s_%s" % (doctype,category))):
+ for user in acc_get_role_users(acc_getRoleId("referee_%s_%s" % (doctype,category))):
refereeaddress += user[1] + ","
# And if there are general referees
- for user in acc_getRoleUsers(acc_getRoleId("referee_%s_*" % doctype)):
+ for user in acc_get_role_users(acc_getRoleId("referee_%s_*" % doctype)):
refereeaddress += user[1] + ","
refereeaddress = re.sub(",$","",refereeaddress)
# Creation of the mail for the referee
addresses = ""
if refereeaddress != "":
addresses = refereeaddress + ","
if otheraddresses != "":
addresses += otheraddresses
else:
addresses = re.sub(",$","",addresses)
title_referee = "Request for approval of %s" % rn
mail_referee = "The document %s has been submitted to the %s Server..\nYour approval is requested on it.\n\n" % (rn,cdsname)
mail_referee +="Title: %s\n\nAuthor(s): %s\n\n" % (title,author)
mail_referee +="To access the document(s), select the file(s) from the location:<%s/getfile.py?recid=%s>\n\n" % (htdocsurl,sysno)
mail_referee +="To approve/reject the document, you should go to this URL:\n<%s/approve.py?%s>\n" % (urlpath,access)
mail_referee +="---------------------------------------------\nBest regards.\nThe submission team.\n"
#Send mail to referee
send_email(FROMADDR, addresses, title_referee, mail_referee, copy_to_admin=CFG_WEBSUBMIT_COPY_MAILS_TO_ADMIN)
return ""
diff --git a/modules/websubmit/lib/websubmit_engine.py b/modules/websubmit/lib/websubmit_engine.py
index 8feab0c3e..8251f9e64 100644
--- a/modules/websubmit/lib/websubmit_engine.py
+++ b/modules/websubmit/lib/websubmit_engine.py
@@ -1,1473 +1,1473 @@
## $Id$
## This file is part of CDS Invenio.
## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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.
"""WebSubmit: the mechanism for the submission of new records into CDS Invenio
via a Web interface.
"""
__revision__ = "$Id$"
## import interesting modules:
import string
import os
import sys
import time
import types
import re
import shutil
from mod_python import apache
from invenio.config import \
bibconvert, \
cdslang, \
cdsname, \
images, \
pylibdir, \
storage, \
urlpath, \
version, \
weburl
from invenio.dbquery import run_sql, Error
from invenio.access_control_engine import acc_authorize_action
-from invenio.access_control_admin import acc_isRole
+from invenio.access_control_admin import acc_is_role
from invenio.webpage import page, create_error_box
from invenio.webuser import getUid, get_email, collect_user_info
from invenio.websubmit_config import *
from invenio.file import *
from invenio.messages import gettext_set_language, wash_language
from websubmit_dblayer import \
get_storage_directory_of_action, \
get_longname_of_doctype, \
get_longname_of_action, \
get_num_pages_of_submission, \
get_parameter_value_for_doctype, \
submission_exists_in_log, \
log_new_pending_submission, \
log_new_completed_submission, \
update_submission_modified_date_in_log, \
update_submission_reference_in_log, \
update_submission_reference_and_status_in_log, \
get_form_fields_on_submission_page, \
get_element_description, \
get_element_check_description, \
get_form_fields_not_on_submission_page, \
function_step_is_last, \
get_collection_children_of_submission_collection, \
get_submission_collection_name, \
get_doctype_children_of_submission_collection, \
get_categories_of_doctype, \
get_doctype_details, \
get_actions_on_submission_page_for_doctype, \
get_action_details, \
get_parameters_of_function, \
get_details_of_submission, \
get_functions_for_submission_step, \
get_submissions_at_level_X_with_score_above_N, \
submission_is_finished
import invenio.template
websubmit_templates = invenio.template.load('websubmit')
def interface(req,
c=cdsname,
ln=cdslang,
doctype="",
act="",
startPg=1,
indir="",
access="",
mainmenu="",
fromdir="",
file="",
nextPg="",
nbPg="",
curpage=1):
"""This function is called after a user has visited a document type's
"homepage" and selected the type of "action" to perform. Having
clicked an action-button (e.g. "Submit a New Record"), this function
will be called . It performs the task of initialising a new submission
session (retrieving information about the submission, creating a
working submission-directory, etc), and "drawing" a submission page
containing the WebSubmit form that the user uses to input the metadata
to be submitted.
When a user moves between pages in the submission interface, this
function is recalled so that it can save the metadata entered into the
previous page by the user, and draw the current submission-page.
Note: During a submission, for each page refresh, this function will be
called while the variable "step" (a form variable, seen by
websubmit_webinterface, which calls this function) is 0 (ZERO).
In other words, this function handles the FRONT-END phase of a
submission, BEFORE the WebSubmit functions are called.
@param req: (apache request object) *** NOTE: Added into this object, is
a variable called "form" (req.form). This is added into the object in
the index function of websubmit_webinterface. It contains a
"mod_python.util.FieldStorage" instance, that contains the form-fields
found on the previous submission page.
@param c: (string), defaulted to cdsname. The name of the CDS Invenio
installation.
@param ln: (string), defaulted to cdslang. The language in which to
display the pages.
@param doctype: (string) - the doctype ID of the doctype for which the
submission is being made.
@param act: (string) - The ID of the action being performed (e.g.
submission of bibliographic information; modification of bibliographic
information, etc).
@param startPg: (integer) - Starting page for the submission? Defaults
to 1.
@param indir: (string) - the directory used to store all submissions
of the given "type" of this submission. For example, if the submission
is of the type "modify bibliographic information", this variable would
contain "modify".
@param access: (string) - the "access" number for the submission
(e.g. 1174062451_7010). This number is also used as the name for the
current working submission directory.
@param mainmenu: (string) - contains the URL (minus the CDS Invenio
home stem) for the submission's home-page. (E.g. If this submission
is "PICT", the "mainmenu" file would contain "/submit?doctype=PICT".
@param fromdir: (integer)
@param file: (string)
@param nextPg: (string)
@param nbPg: (string)
@param curpage: (integer) - the current submission page number. Defaults
to 1.
"""
ln = wash_language(ln)
# load the right message language
_ = gettext_set_language(ln)
sys.stdout = req
# get user ID:
try:
uid = getUid(req)
uid_email = get_email(uid)
except Error, e:
return errorMsg(e, req, c, ln)
# variable initialisation
t = ""
field = []
fieldhtml = []
level = []
fullDesc = []
text = []
check = []
select = []
radio = []
upload = []
txt = []
noPage = []
# Preliminary tasks
# check that the user is logged in
if uid_email == "" or uid_email == "guest":
return warningMsg(websubmit_templates.tmpl_warning_message(
ln = ln,
msg = _("Sorry, you must log in to perform this action.")
), req, ln)
# warningMsg("""
""",req, ln)
# check we have minimum fields
if "" in (doctype, act, access):
## We don't have all the necessary information to go ahead
## with this submission:
return errorMsg(_("Invalid parameter"), req, c, ln)
## Before continuing to display the submission form interface,
## verify that this submission has not already been completed:
if submission_is_finished(doctype, act, access, uid_email):
## This submission has already been completed.
## This situation can arise when, having completed a submission,
## the user uses the browser's back-button to go back to the form
## stage of the submission and then tries to submit once more.
## This is unsafe and should not be allowed. Instead of re-displaying
## the submission forms, display an error message to the user:
wrnmsg = """This submission has been completed. Please go to the""" \
""" """ \
"""main menu to start a new submission.""" \
% { 'doctype' : doctype, 'ln' : ln }
return warningMsg(wrnmsg, req)
## retrieve the action and doctype data:
## Concatenate action ID and doctype ID to make the submission ID:
subname = "%s%s" % (act, doctype)
if indir == "":
## Get the submission storage directory from the DB:
submission_dir = get_storage_directory_of_action(act)
if submission_dir not in ("", None):
indir = submission_dir
else:
## Unable to determine the submission-directory:
return errorMsg(_("Unable to find the submission directory."), req, c, ln)
## get the document type's long-name:
doctype_lname = get_longname_of_doctype(doctype)
if doctype_lname is not None:
## Got the doctype long-name: replace spaces with HTML chars:
docname = doctype_lname.replace(" ", " ")
else:
## Unknown document type:
return errorMsg(_("Unknown document type"), req, c, ln)
## get the action's long-name:
action_lname = get_longname_of_action(act)
if action_lname is not None:
## Got the action long-name: replace spaces with HTML chars:
actname = action_lname.replace(" ", " ")
else:
## Unknown action:
return errorMsg(_("Unknown action"), req, c, ln)
## Get the number of pages for this submission:
num_submission_pages = get_num_pages_of_submission(subname)
if num_submission_pages is not None:
nbpages = num_submission_pages
else:
## Unable to determine the number of pages for this submission:
return errorMsg(_("Unable to determine the number of submission pages."), req, c, ln)
## If unknown, get the current page of submission:
if startPg != "" and curpage in ("", 0):
curpage = startPg
## retrieve the name of the file in which the reference of
## the submitted document will be stored
rn_filename = get_parameter_value_for_doctype(doctype, "edsrn")
if rn_filename is not None:
edsrn = rn_filename
else:
## Unknown value for edsrn - set it to an empty string:
edsrn = ""
## This defines the path to the directory containing the action data
curdir = "%s/%s/%s/%s" % (storage, indir, doctype, access)
## if this submission comes from another one (fromdir is then set)
## We retrieve the previous submission directory and put it in the proper one
if fromdir != "":
olddir = "%s/%s/%s/%s" % (storage, fromdir, doctype, access)
if os.path.exists(olddir):
os.rename(olddir, curdir)
## If the submission directory still does not exist, we create it
if not os.path.exists(curdir):
try:
os.makedirs(curdir)
except:
return errorMsg(_("Unable to create a directory for this submission."), req, c, ln)
# retrieve the original main menu url and save it in the "mainmenu" file
if mainmenu != "":
fp = open("%s/mainmenu" % curdir, "w")
fp.write(mainmenu)
fp.close()
# and if the file containing the URL to the main menu exists
# we retrieve it and store it in the $mainmenu variable
if os.path.exists("%s/mainmenu" % curdir):
fp = open("%s/mainmenu" % curdir, "r");
mainmenu = fp.read()
fp.close()
else:
mainmenu = "%s/submit" % (urlpath,)
# various authentication related tasks...
if uid_email != "guest" and uid_email != "":
#First save the username (email address) in the SuE file. This way bibconvert will be able to use it if needed
fp = open("%s/SuE" % curdir, "w")
fp.write(uid_email)
fp.close()
# is user authorized to perform this action?
(auth_code, auth_message) = acc_authorize_action(req, "submit", verbose=0, doctype=doctype, act=act)
- if acc_isRole("submit", doctype=doctype, act=act) and auth_code != 0:
+ if acc_is_role("submit", doctype=doctype, act=act) and auth_code != 0:
return warningMsg("""
%s
""" % auth_message, req)
## update the "journal of submission":
## Does the submission already exist in the log?
submission_exists = \
submission_exists_in_log(doctype, act, access, uid_email)
if submission_exists == 1:
## update the modification-date of this submission in the log:
update_submission_modified_date_in_log(doctype, act, access, uid_email)
else:
## Submission doesn't exist in log - create it:
log_new_pending_submission(doctype, act, access, uid_email)
# Save the form fields entered in the previous submission page
# If the form was sent with the GET method
form = req.form
value = ""
# we parse all the form variables
for key in form.keys():
formfields = form[key]
if re.search("\[\]", key):
filename = key.replace("[]", "")
else:
filename = key
# the field is an array
if isinstance(formfields, types.ListType):
fp = open("%s/%s" % (curdir, filename), "w")
for formfield in formfields:
#stripslashes(value)
value = specialchars(formfield)
fp.write(value+"\n")
fp.close()
# the field is a normal string
elif isinstance(formfields, types.StringTypes) and formfields != "":
value = formfields
fp = open("%s/%s" % (curdir, filename), "w")
fp.write(specialchars(value))
fp.close()
# the field is a file
elif hasattr(formfields,"filename") and formfields.filename is not None:
if not os.path.exists("%s/files/%s" % (curdir, key)):
try:
os.makedirs("%s/files/%s" % (curdir, key))
except:
return errorMsg(_("Cannot create submission directory."), req, c, ln)
filename = formfields.filename
if filename != "":
# This may be dangerous if the file size is bigger than the available memory
data = formfields.file.read()
fp = open("%s/files/%s/%s" % (curdir, key, filename), "w")
fp.write(data)
fp.close()
fp = open("%s/lastuploadedfile" % curdir, "w")
fp.write(filename)
fp.close()
fp = open("%s/%s" % (curdir, key), "w")
fp.write(filename)
fp.close()
## if the found field is the reference of the document,
## save this value in the "journal of submissions":
if uid_email != "" and uid_email != "guest":
if key == edsrn:
update_submission_reference_in_log(doctype, access, uid_email, value)
## create the interface:
subname = "%s%s" % (act, doctype)
## Get all of the form fields that appear on this page, ordered by fieldnum:
form_fields = get_form_fields_on_submission_page(subname, curpage)
full_fields = []
values = []
for field_instance in form_fields:
full_field = {}
## Retrieve the field's description:
element_descr = get_element_description(field_instance[3])
if element_descr is None:
## The form field doesn't seem to exist - return with error message:
return \
errorMsg(_("Unknown form field found on submission page."), \
req, c, ln)
if element_descr[8] is None:
val = ""
else:
val = element_descr[8]
## we also retrieve and add the javascript code of the checking function, if needed
## Set it to empty string to begin with:
full_field['javascript'] = ''
if field_instance[7] != '':
check_descr = get_element_check_description(field_instance[7])
if check_descr is not None:
## Retrieved the check description:
full_field['javascript'] = check_descr
full_field['type'] = element_descr[3]
full_field['name'] = field_instance[3]
full_field['rows'] = element_descr[5]
full_field['cols'] = element_descr[6]
full_field['val'] = val
full_field['size'] = element_descr[4]
full_field['maxlength'] = element_descr[7]
full_field['htmlcode'] = element_descr[9]
full_field['typename'] = field_instance[1] ## TODO: Investigate this, Not used?
## It also seems to refer to pagenum.
# The 'R' fields must be executed in the engine's environment,
# as the runtime functions access some global and local
# variables.
if full_field ['type'] == 'R':
co = compile (full_field ['htmlcode'].replace("\r\n","\n"), "", "exec")
exec(co)
else:
text = websubmit_templates.tmpl_submit_field (ln = ln, field = full_field)
# we now determine the exact type of the created field
if full_field['type'] not in [ 'D','R']:
field.append(full_field['name'])
level.append(field_instance[5])
fullDesc.append(field_instance[4])
txt.append(field_instance[6])
check.append(field_instance[7])
# If the field is not user-defined, we try to determine its type
# (select, radio, file upload...)
# check whether it is a select field or not
if re.search("SELECT", text, re.IGNORECASE) is not None:
select.append(1)
else:
select.append(0)
# checks whether it is a radio field or not
if re.search(r"TYPE=[\"']?radio", text, re.IGNORECASE) is not None:
radio.append(1)
else:
radio.append(0)
# checks whether it is a file upload or not
if re.search(r"TYPE=[\"']?file", text, re.IGNORECASE) is not None:
upload.append(1)
else:
upload.append(0)
# if the field description contains the "" string, replace
# it by the category selected on the document page submission page
combofile = "combo%s" % doctype
if os.path.exists("%s/%s" % (curdir, combofile)):
f = open("%s/%s" % (curdir, combofile), "r")
combo = f.read()
f.close()
else:
combo=""
text = text.replace("", combo)
# if there is a tag in it, replace it by the current year
year = time.strftime("%Y");
text = text.replace("", year)
# if there is a tag in it, replace it by the current year
today = time.strftime("%d/%m/%Y");
text = text.replace("", today)
fieldhtml.append(text)
else:
select.append(0)
radio.append(0)
upload.append(0)
# field.append(value) - initial version, not working with JS, taking a submitted value
field.append(field_instance[3])
level.append(field_instance[5])
txt.append(field_instance[6])
fullDesc.append(field_instance[4])
check.append(field_instance[7])
fieldhtml.append(text)
full_field['fullDesc'] = field_instance[4]
full_field['text'] = text
# If a file exists with the name of the field we extract the saved value
text = ''
if os.path.exists("%s/%s" % (curdir, full_field['name'])):
file = open("%s/%s" % (curdir, full_field['name']), "r");
text = file.read()
text = re.compile("[\n\r]*$").sub("", text)
text = re.compile("\n").sub("\\n", text)
text = re.compile("\r").sub("", text)
file.close()
values.append(text)
full_fields.append(full_field)
returnto = {}
if int(curpage) == int(nbpages):
subname = "%s%s" % (act, doctype)
other_form_fields = \
get_form_fields_not_on_submission_page(subname, curpage)
nbFields = 0
message = ""
fullcheck_select = []
fullcheck_radio = []
fullcheck_upload = []
fullcheck_field = []
fullcheck_level = []
fullcheck_txt = []
fullcheck_noPage = []
fullcheck_check = []
for field_instance in other_form_fields:
if field_instance[5] == "M":
## If this field is mandatory, get its description:
element_descr = get_element_description(field_instance[3])
if element_descr is None:
## The form field doesn't seem to exist - return with error message:
return \
errorMsg(_("Unknown form field found on one of the submission pages."), \
req, c, ln)
if element_descr[3] in ['D', 'R']:
if element_descr[3] == "D":
text = element_descr[9]
else:
text = eval(element_descr[9])
formfields = text.split(">")
for formfield in formfields:
match = re.match("name=([^ <>]+)", formfield, re.IGNORECASE)
if match is not None:
names = match.groups
for value in names:
if value != "":
value = re.compile("[\"']+").sub("", value)
fullcheck_field.append(value)
fullcheck_level.append(field_instance[5])
fullcheck_txt.append(field_instance[6])
fullcheck_noPage.append(field_instance[1])
fullcheck_check.append(field_instance[7])
nbFields = nbFields + 1
else:
fullcheck_noPage.append(field_instance[1])
fullcheck_field.append(field_instance[3])
fullcheck_level.append(field_instance[5])
fullcheck_txt.append(field_instance[6])
fullcheck_check.append(field_instance[7])
nbFields = nbFields+1
# tests each mandatory field
fld = 0
res = 1
for i in range (0, nbFields):
res = 1
if not os.path.exists("%s/%s" % (curdir, fullcheck_field[i])):
res=0
else:
file = open("%s/%s" % (curdir, fullcheck_field[i]), "r")
text = file.read()
if text == '':
res=0
else:
if text == "Select:":
res=0
if res == 0:
fld = i
break
if not res:
returnto = {
'field' : fullcheck_txt[fld],
'page' : fullcheck_noPage[fld],
}
t += websubmit_templates.tmpl_page_interface(
ln = ln,
docname = docname,
actname = actname,
curpage = curpage,
nbpages = nbpages,
file = file,
nextPg = nextPg,
access = access,
nbPg = nbPg,
doctype = doctype,
act = act,
indir = indir,
fields = full_fields,
javascript = websubmit_templates.tmpl_page_interface_js(
ln = ln,
upload = upload,
field = field,
fieldhtml = fieldhtml,
txt = txt,
check = check,
level = level,
curdir = curdir,
values = values,
select = select,
radio = radio,
curpage = curpage,
nbpages = nbpages,
images = images,
returnto = returnto,
),
images = images,
mainmenu = mainmenu,
)
# start display:
req.content_type = "text/html"
req.send_http_header()
p_navtrail = """%(submit)s > %(docname)s """ % {
'submit' : _("Submit"),
'doctype' : doctype,
'docname' : docname,
}
return page(title= actname,
body = t,
navtrail = p_navtrail,
description = "submit documents",
keywords = "submit",
uid = uid,
language = ln,
req = req,
navmenuid='submit')
def endaction(req,
c=cdsname,
ln=cdslang,
doctype="",
act="",
startPg=1,
indir="",
access="",
mainmenu="",
fromdir="",
file="",
nextPg="",
nbPg="",
curpage=1,
step=1,
mode="U"):
"""Having filled-in the WebSubmit form created for metadata by the interface
function, the user clicks a button to either "finish the submission" or
to "proceed" to the next stage of the submission. At this point, a
variable called "step" will be given a value of 1 or above, which means
that this function is called by websubmit_webinterface.
So, during all non-zero steps of the submission, this function is called.
In other words, this function is called during the BACK-END phase of a
submission, in which WebSubmit *functions* are being called.
The function first ensures that all of the WebSubmit form field values
have been saved in the current working submission directory, in text-
files with the same name as the field elements have. It then determines
the functions to be called for the given step of the submission, and
executes them.
Following this, if this is the last step of the submission, it logs the
submission as "finished" in the journal of submissions.
@param req: (apache request object) *** NOTE: Added into this object, is
a variable called "form" (req.form). This is added into the object in
the index function of websubmit_webinterface. It contains a
"mod_python.util.FieldStorage" instance, that contains the form-fields
found on the previous submission page.
@param c: (string), defaulted to cdsname. The name of the CDS Invenio
installation.
@param ln: (string), defaulted to cdslang. The language in which to
display the pages.
@param doctype: (string) - the doctype ID of the doctype for which the
submission is being made.
@param act: (string) - The ID of the action being performed (e.g.
submission of bibliographic information; modification of bibliographic
information, etc).
@param startPg: (integer) - Starting page for the submission? Defaults
to 1.
@param indir: (string) - the directory used to store all submissions
of the given "type" of this submission. For example, if the submission
is of the type "modify bibliographic information", this variable would
contain "modify".
@param access: (string) - the "access" number for the submission
(e.g. 1174062451_7010). This number is also used as the name for the
current working submission directory.
@param mainmenu: (string) - contains the URL (minus the CDS Invenio
home stem) for the submission's home-page. (E.g. If this submission
is "PICT", the "mainmenu" file would contain "/submit?doctype=PICT".
@param fromdir:
@param file:
@param nextPg:
@param nbPg:
@param curpage: (integer) - the current submission page number. Defaults
to 1.
@param step: (integer) - the current step of the submission. Defaults to
1.
@param mode:
"""
global rn, sysno, dismode, curdir, uid, uid_email, last_step, action_score
# load the right message language
_ = gettext_set_language(ln)
try:
rn
except NameError:
rn = ""
dismode = mode
ln = wash_language(ln)
sys.stdout = req
t = ""
# get user ID:
try:
uid = getUid(req)
uid_email = get_email(uid)
except Error, e:
return errorMsg(e, req, c, ln)
# Preliminary tasks
# check that the user is logged in
if uid_email == "" or uid_email == "guest":
return warningMsg(websubmit_templates.tmpl_warning_message(
ln = ln,
msg = _("Sorry, you must log in to perform this action.")
), req, ln)
## check we have minimum fields
if "" in (doctype, act, access):
## We don't have all the necessary information to go ahead
## with this submission:
return errorMsg(_("Invalid parameter"), req, c, ln)
## Before continuing to process the submitted data, verify that
## this submission has not already been completed:
if submission_is_finished(doctype, act, access, uid_email):
## This submission has already been completed.
## This situation can arise when, having completed a submission,
## the user uses the browser's back-button to go back to the form
## stage of the submission and then tries to submit once more.
## This is unsafe and should not be allowed. Instead of re-processing
## the submitted data, display an error message to the user:
wrnmsg = """This submission has been completed. Please go to the""" \
""" """ \
"""main menu to start a new submission.""" \
% { 'doctype' : doctype, 'ln' : ln }
return warningMsg(wrnmsg, req)
## retrieve the action and doctype data
if indir == "":
## Get the submission storage directory from the DB:
submission_dir = get_storage_directory_of_action(act)
if submission_dir not in ("", None):
indir = submission_dir
else:
## Unable to determine the submission-directory:
return errorMsg(_("Unable to find the submission directory."), \
req, c, ln)
# The following words are reserved and should not be used as field names
reserved_words = ["stop", "file", "nextPg", "startPg", "access", "curpage", "nbPg", "act", \
"indir", "doctype", "mode", "step", "deleted", "file_path", "userfile_name"]
# This defines the path to the directory containing the action data
curdir = "%s/%s/%s/%s" % (storage, indir, doctype, access)
# If the submission directory still does not exist, we create it
if not os.path.exists(curdir):
try:
os.makedirs(curdir)
except:
return errorMsg(_("Cannot create submission directory."), req, c, ln)
# retrieve the original main menu url ans save it in the "mainmenu" file
if mainmenu != "":
fp = open("%s/mainmenu" % curdir, "w")
fp.write(mainmenu)
fp.close()
# and if the file containing the URL to the main menu exists
# we retrieve it and store it in the $mainmenu variable
if os.path.exists("%s/mainmenu" % curdir):
fp = open("%s/mainmenu" % curdir, "r");
mainmenu = fp.read()
fp.close()
else:
mainmenu = "%s/submit" % (urlpath,)
## retrieve the name of the file in which the reference of
## the submitted document will be stored
rn_filename = get_parameter_value_for_doctype(doctype, "edsrn")
if rn_filename is not None:
edsrn = rn_filename
else:
## Unknown value for edsrn - set it to an empty string:
edsrn = ""
## Determine whether the action is finished
## (ie there are no other steps after the current one):
finished = function_step_is_last(doctype, act, step)
# Save the form fields entered in the previous submission page
# If the form was sent with the GET method
form = req.form
value = ""
# we parse all the form variables
for key in form.keys():
formfields = form[key]
if re.search("\[\]", key):
filename = key.replace("[]", "")
else:
filename = key
# the field is an array
if isinstance(formfields,types.ListType):
fp = open("%s/%s" % (curdir, filename), "w")
for formfield in formfields:
#stripslashes(value)
value = specialchars(formfield)
fp.write(value+"\n")
fp.close()
# the field is a normal string
elif isinstance(formfields, types.StringTypes) and formfields != "":
value = formfields
fp = open("%s/%s" % (curdir, filename), "w")
fp.write(specialchars(value))
fp.close()
# the field is a file
elif hasattr(formfields, "filename") and formfields.filename is not None:
if not os.path.exists("%s/files/%s" % (curdir, key)):
try:
os.makedirs("%s/files/%s" % (curdir, key))
except:
return errorMsg("can't create submission directory", req, cdsname, ln)
filename = formfields.filename
if filename != "":
# This may be dangerous if the file size is bigger than the available memory
data = formfields.file.read()
fp = open("%s/files/%s/%s" % (curdir, key, filename), "w")
fp.write(data)
fp.close()
fp = open("%s/lastuploadedfile" % curdir, "w")
fp.write(filename)
fp.close()
fp = open("%s/%s" % (curdir, key), "w")
fp.write(filename)
fp.close()
## if the found field is the reference of the document
## we save this value in the "journal of submissions"
if uid_email != "" and uid_email != "guest":
if key == edsrn:
update_submission_reference_in_log(doctype, access, uid_email, value)
## get the document type's long-name:
doctype_lname = get_longname_of_doctype(doctype)
if doctype_lname is not None:
## Got the doctype long-name: replace spaces with HTML chars:
docname = doctype_lname.replace(" ", " ")
else:
## Unknown document type:
return errorMsg(_("Unknown document type"), req, c, ln)
## get the action's long-name:
action_lname = get_longname_of_action(act)
if action_lname is not None:
## Got the action long-name: replace spaces with HTML chars:
actname = action_lname.replace(" ", " ")
else:
## Unknown action:
return errorMsg(_("Unknown action"), req, c, ln)
## Get the number of pages for this submission:
subname = "%s%s" % (act, doctype)
num_submission_pages = get_num_pages_of_submission(subname)
if num_submission_pages is not None:
nbpages = num_submission_pages
else:
## Unable to determine the number of pages for this submission:
return errorMsg(_("Unable to determine the number of submission pages."), \
req, cdsname, ln)
## Determine whether the action is finished
## (ie there are no other steps after the current one):
last_step = function_step_is_last(doctype, act, step)
next_action = '' ## The next action to be proposed to the user
# Prints the action details, returning the mandatory score
action_score = action_details(doctype, act)
current_level = get_level(doctype, act)
# Calls all the function's actions
function_content = ''
try:
## Handle the execution of the functions for this
## submission/step:
function_content = print_function_calls(req=req, doctype=doctype,
action=act,
step=step,
form=form,
ln=ln)
except InvenioWebSubmitFunctionError, e:
## There was a serious function-error. Execution ends.
return errorMsg(e.value, req, c, ln)
except InvenioWebSubmitFunctionStop, e:
## For one reason or another, one of the functions has determined that
## the data-processing phase (i.e. the functions execution) should be
## halted and the user should be returned to the form interface once
## more. (NOTE: Redirecting the user to the Web-form interface is
## currently done using JavaScript. The "InvenioWebSubmitFunctionStop"
## exception contains a "value" string, which is effectively JavaScript
## - probably an alert box and a form that is submitted). **THIS WILL
## CHANGE IN THE FUTURE WHEN JavaScript IS REMOVED!**
if e.value is not None:
function_content = e.value
else:
function_content = e
else:
## No function exceptions (InvenioWebSubmitFunctionStop,
## InvenioWebSubmitFunctionError) were raised by the functions. Propose
## the next action (if applicable), and log the submission as finished:
## If the action was mandatory we propose the next
## mandatory action (if any)
if action_score != -1 and last_step == 1:
next_action = Propose_Next_Action(doctype, \
action_score, \
access, \
current_level, \
indir)
## If we are in the last step of an action, we can update
## the "journal of submissions"
if last_step == 1:
if uid_email != "" and uid_email != "guest" and rn != "":
## update the "journal of submission":
## Does the submission already exist in the log?
submission_exists = \
submission_exists_in_log(doctype, act, access, uid_email)
if submission_exists == 1:
## update the rn and status to finished for this submission
## in the log:
update_submission_reference_and_status_in_log(doctype, \
act, \
access, \
uid_email, \
rn, \
"finished")
else:
## Submission doesn't exist in log - create it:
log_new_completed_submission(doctype, \
act, \
access, \
uid_email, \
rn)
## Having executed the functions, create the page that will be displayed
## to the user:
t = websubmit_templates.tmpl_page_endaction(
ln = ln,
weburl = weburl,
# these fields are necessary for the navigation
file = file,
nextPg = nextPg,
startPg = startPg,
access = access,
curpage = curpage,
nbPg = nbPg,
nbpages = nbpages,
doctype = doctype,
act = act,
docname = docname,
actname = actname,
indir = indir,
mainmenu = mainmenu,
finished = finished,
images = images,
function_content = function_content,
next_action = next_action,
)
# start display:
req.content_type = "text/html"
req.send_http_header()
p_navtrail = """""" + _("Submit") +\
""" > %(docname)s""" % {
'doctype' : doctype,
'docname' : docname,
}
return page(title= actname,
body = t,
navtrail = p_navtrail,
description="submit documents",
keywords="submit",
uid = uid,
language = ln,
req = req,
navmenuid='submit')
def home(req, c=cdsname, ln=cdslang):
"""This function generates the WebSubmit "home page".
Basically, this page contains a list of submission-collections
in WebSubmit, and gives links to the various document-type
submissions.
Document-types only appear on this page when they have been
connected to a submission-collection in WebSubmit.
@param req: (apache request object)
@param c: (string) - defaults to cdsname
@param ln: (string) - The CDS Invenio interface language of choice.
Defaults to cdslang (the default language of the installation).
@return: (string) - the Web page to be displayed.
"""
ln = wash_language(ln)
# get user ID:
try:
uid = getUid(req)
except Error, e:
return errorMsg(e, req, c, ln)
# start display:
req.content_type = "text/html"
req.send_http_header()
# load the right message language
_ = gettext_set_language(ln)
finaltext = websubmit_templates.tmpl_submit_home_page(
ln = ln,
catalogues = makeCataloguesTable(ln)
)
return page(title=_("Submit"),
body=finaltext,
navtrail=[],
description="submit documents",
keywords="submit",
uid=uid,
language=ln,
req=req,
navmenuid='submit'
)
def makeCataloguesTable(ln=cdslang):
"""Build the 'catalogues' (submission-collections) tree for
the WebSubmit home-page. This tree contains the links to
the various document types in WebSubmit.
@param ln: (string) - the language of the interface.
(defaults to 'cdslang').
@return: (string) - the submission-collections tree.
"""
text = ""
catalogues = []
## Get the submission-collections attached at the top level
## of the submission-collection tree:
top_level_collctns = get_collection_children_of_submission_collection(0)
if len(top_level_collctns) != 0:
## There are submission-collections attatched to the top level.
## retrieve their details for displaying:
for child_collctn in top_level_collctns:
catalogues.append(getCatalogueBranch(child_collctn[0], 1))
text = websubmit_templates.tmpl_submit_home_catalogs(
ln=ln,
catalogs=catalogues
)
else:
text = websubmit_templates.tmpl_submit_home_catalog_no_content(ln=ln)
return text
def getCatalogueBranch(id_father, level):
"""Build up a given branch of the submission-collection
tree. I.e. given a parent submission-collection ID,
build up the tree below it. This tree will include
doctype-children, as well as other submission-
collections and their children.
Finally, return the branch as a dictionary.
@param id_father: (integer) - the ID of the submission-collection
from which to begin building the branch.
@param level: (integer) - the level of the current submission-
collection branch.
@return: (dictionary) - the branch and its sub-branches.
"""
elem = {} ## The dictionary to contain this branch of the tree.
## First, get the submission-collection-details:
collctn_name = get_submission_collection_name(id_father)
if collctn_name is not None:
## Got the submission-collection's name:
elem['name'] = collctn_name
else:
## The submission-collection is unknown to the DB
## set its name as empty:
elem['name'] = ""
elem['id'] = id_father
elem['level'] = level
## Now get details of the doctype-children of this
## submission-collection:
elem['docs'] = [] ## List to hold the doctype-children
## of the submission-collection
doctype_children = \
get_doctype_children_of_submission_collection(id_father)
for child_doctype in doctype_children:
elem['docs'].append(getDoctypeBranch(child_doctype[0]))
## Now, get the collection-children of this submission-collection:
elem['sons'] = []
collctn_children = \
get_collection_children_of_submission_collection(id_father)
for child_collctn in collctn_children:
elem['sons'].append(getCatalogueBranch(child_collctn[0], level + 1))
## Now return this branch of the built-up 'collection-tree':
return elem
def getDoctypeBranch(doctype):
"""Create a document-type 'leaf-node' for the submission-collections
tree. Basically, this leaf is a dictionary containing the name
and ID of the document-type submission to which it links.
@param doctype: (string) - the ID of the document type.
@return: (dictionary) - the document-type 'leaf node'. Contains
the following values:
+ id: (string) - the document-type ID.
+ name: (string) - the (long) name of the document-type.
"""
ldocname = get_longname_of_doctype(doctype)
if ldocname is None:
ldocname = "Unknown Document Type"
return { 'id' : doctype, 'name' : ldocname, }
def displayCatalogueBranch(id_father, level, catalogues):
text = ""
collctn_name = get_submission_collection_name(id_father)
if collctn_name is None:
## If this submission-collection wasn't known in the DB,
## give it the name "Unknown Submission-Collection" to
## avoid errors:
collctn_name = "Unknown Submission-Collection"
## Now, create the display for this submission-collection:
if level == 1:
text = "
%s\n" \
% collctn_name
else:
## TODO: These are the same (and the if is ugly.) Why?
if level == 2:
text = "
%s\n" % collctn_name
else:
if level > 2:
text = "
%s\n" % collctn_name
## Now display the children document-types that are attached
## to this submission-collection:
## First, get the children:
doctype_children = get_doctype_children_of_submission_collection(id_father)
collctn_children = get_collection_children_of_submission_collection(id_father)
if len(doctype_children) > 0 or len(collctn_children) > 0:
## There is something to display, so open a list:
text = text + "
\n"
## First, add the doctype leaves of this branch:
for child_doctype in doctype_children:
## Add the doctype 'leaf-node':
text = text + displayDoctypeBranch(child_doctype[0], catalogues)
## Now add the submission-collection sub-branches:
for child_collctn in collctn_children:
catalogues.append(child_collctn[0])
text = text + displayCatalogueBranch(child_collctn[0], level+1, catalogues)
## Finally, close up the list if there were nodes to display
## at this branch:
if len(doctype_children) > 0 or len(collctn_children) > 0:
text = text + "
\n"
return text
def displayDoctypeBranch(doctype, catalogues):
text = ""
ldocname = get_longname_of_doctype(doctype)
if ldocname is None:
ldocname = "Unknown Document Type"
text = "
%s\n" \
% (doctype, doctype, doctype, ldocname)
return text
def action(req, c=cdsname, ln=cdslang, doctype=""):
# load the right message language
_ = gettext_set_language(ln)
nbCateg = 0
snameCateg = []
lnameCateg = []
actionShortDesc = []
indir = []
actionbutton = []
statustext = []
t = ""
ln = wash_language(ln)
# get user ID:
try:
uid = getUid(req)
uid_email = get_email(uid)
except Error, e:
return errorMsg(e, req, c, ln)
#parses database to get all data
## first, get the list of categories
doctype_categs = get_categories_of_doctype(doctype)
for doctype_categ in doctype_categs:
nbCateg = nbCateg+1
snameCateg.append(doctype_categ[0])
lnameCateg.append(doctype_categ[1])
## Now get the details of the document type:
doctype_details = get_doctype_details(doctype)
if doctype_details is None:
## Doctype doesn't exist - raise error:
return errorMsg (_("Unable to find document type.") + str(doctype), req)
else:
docFullDesc = doctype_details[0]
docShortDesc = doctype_details[1]
description = doctype_details[4]
## Get the details of the actions supported by this document-type:
doctype_actions = get_actions_on_submission_page_for_doctype(doctype)
for doctype_action in doctype_actions:
## Get the details of this action:
action_details = get_action_details(doctype_action[0])
if action_details is not None:
actionShortDesc.append(doctype_action[0])
indir.append(action_details[1])
actionbutton.append(action_details[4])
statustext.append(action_details[5])
## Send the gathered information to the template so that the doctype's
## home-page can be displayed:
t = websubmit_templates.tmpl_action_page(
ln=ln,
uid=uid, guest=(uid_email == "" or uid_email == "guest"),
pid = os.getpid(),
now = time.time(),
doctype = doctype,
description = description,
docfulldesc = docFullDesc,
snameCateg = snameCateg,
lnameCateg = lnameCateg,
actionShortDesc = actionShortDesc,
indir = indir,
# actionbutton = actionbutton,
statustext = statustext,
)
p_navtrail = """%(submit)s""" % {'submit' : _("Submit")}
return page(title = docFullDesc,
body=t,
navtrail=p_navtrail,
description="submit documents",
keywords="submit",
uid=uid,
language=ln,
req=req,
navmenuid='submit'
)
def Request_Print(m, txt):
"""The argumemts to this function are the display mode (m) and the text
to be displayed (txt).
If the argument mode is 'ALL' then the text is unconditionally echoed
m can also take values S (Supervisor Mode) and U (User Mode). In these
circumstances txt is only echoed if the argument mode is the same as
the current mode
"""
global dismode
if m == "A" or m == dismode:
return txt
else:
return ""
def Evaluate_Parameter (field, doctype):
# Returns the literal value of the parameter. Assumes that the value is
# uniquely determined by the doctype, i.e. doctype is the primary key in
# the table
# If the table name is not null, evaluate the parameter
## TODO: The above comment looks like nonesense? This
## function only seems to get the values of parameters
## from the db...
## Get the value for the parameter:
param_val = get_parameter_value_for_doctype(doctype, field)
if param_val is None:
## Couldn't find a value for this parameter for this doctype.
## Instead, try with the default doctype (DEF):
param_val = get_parameter_value_for_doctype("DEF", field)
if param_val is None:
## There was no value for the parameter for the default doctype.
## Nothing can be done about it - return an empty string:
return ""
else:
## There was some kind of value for the parameter; return it:
return param_val
def Get_Parameters (function, doctype):
"""For a given function of a given document type, a dictionary
of the parameter names and values are returned.
@param function: (string) - the name of the function for which the
parameters are to be retrieved.
@param doctype: (string) - the ID of the document type.
@return: (dictionary) - of the parameters of the function.
Keyed by the parameter name, values are of course the parameter
values.
"""
parray = {}
## Get the names of the parameters expected by this function:
func_params = get_parameters_of_function(function)
for func_param in func_params:
## For each of the parameters, get its value for this document-
## type and add it into the dictionary of parameters:
parameter = func_param[0]
parray[parameter] = Evaluate_Parameter (parameter, doctype)
return parray
def get_level(doctype, action):
"""Get the level of a given submission. If unknown, return 0
as the level.
@param doctype: (string) - the ID of the document type.
@param action: (string) - the ID of the action.
@return: (integer) - the level of the submission; 0 otherwise.
"""
subm_details = get_details_of_submission(doctype, action)
if subm_details is not None:
## Return the level of this action
subm_level = subm_details[9]
try:
int(subm_level)
except ValueError:
return 0
else:
return subm_level
else:
return 0
def action_details (doctype, action):
# Prints whether the action is mandatory or optional. The score of the
# action is returned (-1 if the action was optional)
subm_details = get_details_of_submission(doctype, action)
if subm_details is not None:
if subm_details[9] != "0":
## This action is mandatory; return the score:
return subm_details[10]
else:
return -1
else:
return -1
def print_function_calls (req, doctype, action, step, form, ln=cdslang):
# Calls the functions required by an "action" action on a "doctype" document
# In supervisor mode, a table of the function calls is produced
global htdocsdir,storage,access,pylibdir,dismode,user_info
user_info = collect_user_info(req)
# load the right message language
_ = gettext_set_language(ln)
t = ""
## Get the list of functions to be called
funcs_to_call = get_functions_for_submission_step(doctype, action, step)
## If no functions are found at this step for this doctype,
## get the functions for the DEF(ault) doctype:
if len(funcs_to_call) == 0:
funcs_to_call = get_functions_for_submission_step("DEF", action, step)
if len(funcs_to_call) > 0:
# while there are functions left...
functions = []
for function in funcs_to_call:
function_name = function[0]
function_score = function[1]
currfunction = {
'name' : function_name,
'score' : function_score,
'error' : 0,
'text' : '',
}
if os.path.exists("%s/invenio/websubmit_functions/%s.py" % (pylibdir, function_name)):
# import the function itself
#function = getattr(invenio.websubmit_functions, function_name)
execfile("%s/invenio/websubmit_functions/%s.py" % (pylibdir, function_name), globals())
if not globals().has_key(function_name):
currfunction['error'] = 1
else:
function = globals()[function_name]
# Evaluate the parameters, and place them in an array
parameters = Get_Parameters(function_name, doctype)
# Call function:
func_returnval = function(parameters, curdir, form)
if func_returnval is not None:
## Append the returned value as a string:
currfunction['text'] = str(func_returnval)
else:
## The function the NoneType. Don't keep that value as
## the currfunction->text. Replace it with the empty
## string.
currfunction['text'] = ""
else:
currfunction['error'] = 1
functions.append(currfunction)
t = websubmit_templates.tmpl_function_output(
ln = ln,
display_on = (dismode == 'S'),
action = action,
doctype = doctype,
step = step,
functions = functions,
)
else :
if dismode == 'S':
t = "
" + _("The chosen action is not supported by the document type.") + ""
return t
def Propose_Next_Action (doctype, action_score, access, currentlevel, indir, ln=cdslang):
global machine, storage, act, rn
t = ""
next_submissions = \
get_submissions_at_level_X_with_score_above_N(doctype, currentlevel, action_score)
if len(next_submissions) > 0:
actions = []
first_score = next_submissions[0][10]
for action in next_submissions:
if action[10] == first_score:
## Get the submission directory of this action:
nextdir = get_storage_directory_of_action(action[1])
if nextdir is None:
nextdir = ""
curraction = {
'page' : action[11],
'action' : action[1],
'doctype' : doctype,
'nextdir' : nextdir,
'access' : access,
'indir' : indir,
'name' : action[12],
}
actions.append(curraction)
t = websubmit_templates.tmpl_next_action(
ln = ln,
actions = actions,
)
return t
def errorMsg(title, req, c=cdsname, ln=cdslang):
# load the right message language
_ = gettext_set_language(ln)
return page(title = _("Error"),
body = create_error_box(req, title=title, verbose=0, ln=ln),
description="%s - Internal Error" % c,
keywords="%s, Internal Error" % c,
language=ln,
req=req,
navmenuid='submit')
def warningMsg(title, req, c=cdsname, ln=cdslang):
# load the right message language
_ = gettext_set_language(ln)
return page(title = _("Warning"),
body = title,
description="%s - Internal Error" % c,
keywords="%s, Internal Error" % c,
language=ln,
req=req,
navmenuid='submit')
def specialchars(text):
text = string.replace(text, "", "\042");
text = string.replace(text, "", "\042");
text = string.replace(text, "", "\047");
text = string.replace(text, "", "\055");
text = string.replace(text, " ", "\056\056\056");
return text
diff --git a/modules/websubmit/lib/websubmit_webinterface.py b/modules/websubmit/lib/websubmit_webinterface.py
index 1a5f4dc2b..960419d15 100644
--- a/modules/websubmit/lib/websubmit_webinterface.py
+++ b/modules/websubmit/lib/websubmit_webinterface.py
@@ -1,418 +1,418 @@
## $Id$
##
## This file is part of CDS Invenio.
## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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.
__revision__ = "$Id$"
import string
import os
import time
import types
import re
from mod_python import apache
import sys
from urllib import quote
from invenio.config import \
CFG_ACCESS_CONTROL_LEVEL_SITE, \
cdslang, \
cdsname, \
images, \
storage, \
urlpath, \
version, \
weburl
from invenio.dbquery import run_sql, Error
from invenio.access_control_engine import acc_authorize_action
-from invenio.access_control_admin import acc_isRole
+from invenio.access_control_admin import acc_is_role
from invenio.webpage import page, create_error_box
from invenio.webuser import getUid, get_email, page_not_authorized
from invenio.websubmit_config import *
from invenio.file import *
from invenio.webinterface_handler import wash_urlargd, WebInterfaceDirectory
from invenio.urlutils import make_canonical_urlargd, redirect_to_url
from invenio.messages import gettext_set_language
import invenio.template
websubmit_templates = invenio.template.load('websubmit')
class WebInterfaceFilesPages(WebInterfaceDirectory):
def __init__(self,recid):
self.recid = recid
def _lookup(self, component, path):
# after /record//files/ every part is used as the file
# name (with possible path in the case of archives to be
# uncompressed)
filename = component
def getfile(req, form):
args = wash_urlargd(form, websubmit_templates.files_default_urlargd)
ln = args['ln']
_ = gettext_set_language(ln)
uid = getUid(req)
if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE > 1:
return page_not_authorized(req, "../getfile.py/index",
navmenuid='submit')
uid_email = get_email(uid)
readonly = CFG_ACCESS_CONTROL_LEVEL_SITE == 1
# From now on: either the user provided a specific file
# name (and a possible version), or we return a list of
# all the available files. In no case are the docids
# visible.
bibarchive = BibRecDocs(self.recid)
if filename:
# We know the complete file name, guess which docid it
# refers to
## TODO: Change the extension system according to ext.py from setlink
## and have a uniform extension mechanism...
name = file_strip_ext(filename)
format = filename[len(name):]
if format and format[0] == '.':
format = format[1:]
# search this filename in the complete list of files
for doc in bibarchive.listBibDocs():
if filename in [f.fullname for f in doc.listAllFiles()]:
docfile=doc.getFile(name,format,args['version'])
if docfile is None:
return warningMsg(_("Unable to find file."), req, cdsname, ln)
if docfile.isRestricted():
return warningMsg(_("This file is restricted!"), req, cdsname, ln)
if not readonly:
ip = str(req.get_remote_host(apache.REMOTE_NOLOOKUP))
res = doc.registerDownload(ip, version, format, uid)
return docfile.stream(req)
else:
return warningMsg(_("Unable to find file."), req, cdsname, ln)
filelist = bibarchive.display("", args['version'], ln=ln)
t = websubmit_templates.tmpl_filelist(
ln=ln,
recid=self.recid,
docid="",
version=args['version'],
filelist=filelist)
return page(title="",
body=t,
navtrail=_("Access to Fulltext"),
description="",
keywords="keywords",
uid=uid,
language=ln,
req=req,
navmenuid='submit')
return getfile, []
def __call__(self, req, form):
"""Called in case of URLs like /record/123/files without
trailing slash.
"""
return redirect_to_url(req, '%s/record/%s/files/' % (weburl, self.recid))
def websubmit_legacy_getfile(req, form):
""" Handle legacy /getfile.py URLs """
# FIXME: this should _redirect_ to the proper
# /record/.../files/... URL.
args = wash_urlargd(form, {
'c': (str, cdsname),
'recid': (str, ''),
'docid': (str, ''),
'version': (str, ''),
'name': (str, ''),
'format': (str, '')
})
def _getfile_py(req,c=cdsname,ln=cdslang,recid="",docid="",version="",name="",format=""):
_ = gettext_set_language(ln)
# get user ID:
try:
uid = getUid(req)
if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
return page_not_authorized(req, "../getfile.py/index",
navmenuid='submit')
uid_email = get_email(uid)
except Error, e:
return errorMsg(e.value,req)
filelist=""
# redirect to a canonical URL as far as it is possible (what
# if we only have a docid, and no file supplied?)
if name!="":
if docid=="":
return errorMsg(_("Parameter docid missing"), req, c, ln)
doc = BibDoc(bibdocid=docid)
docfile=doc.getFile(name,format,version)
if docfile is None:
return warningMsg(_("Unable to find file."),req, c, ln)
# redirect to this specific file, possibly dropping
# the version if we are referring to the latest one.
target = '%s/record/%d/files/%s.%s' % (
weburl, doc.recid, quote(docfile.name), docfile.format)
if version and int(version) == int(doc.getLatestVersion()):
version = ''
target += make_canonical_urlargd({
'version': version}, websubmit_templates.files_default_urlargd)
return redirect_to_url(req, target)
# all files attached to a record
elif recid!="":
return redirect_to_url(req, '%s/record/%s/files/' % (weburl, recid))
# a precise filename
elif docid!="":
bibdoc = BibDoc(bibdocid=docid)
recid = bibdoc.getRecid()
filelist = bibdoc.display(version, ln=ln)
t = websubmit_templates.tmpl_filelist(
ln = ln,
recid = recid,
docid = docid,
version = version,
filelist = filelist,
)
p_navtrail = _("Access to Fulltext")
return page(title="",
body=t,
navtrail = p_navtrail,
description="",
keywords="keywords",
uid=uid,
language=ln,
req=req,
navmenuid='submit')
return _getfile_py(req, **args)
# --------------------------------------------------
from invenio.websubmit_engine import home, action, interface, endaction
class WebInterfaceSubmitPages(WebInterfaceDirectory):
_exports = ['summary', 'sub', 'direct', '']
def direct(self, req, form):
args = wash_urlargd(form, {'sub': (str, '')})
sub = args['sub']
uid = getUid(req)
if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
return page_not_authorized(req, "../direct.py/index",
navmenuid='submit')
myQuery = req.args
if sub == "":
return errorMsg("Sorry parameter missing...",req)
res = run_sql("select docname,actname from sbmIMPLEMENT where subname=%s", (sub,))
if len(res)==0:
return errorMsg("Sorry. Cannot analyse parameter",req)
else:
# get document type
doctype = res[0][0]
# get action name
action = res[0][1]
# retrieve other parameter values
params = re.sub("sub=[^&]*","",myQuery)
# find existing access number
result = re.search("access=([^&]*)",params)
if result is not None:
access = result.group(1)
params = re.sub("access=[^&]*","",params)
else:
# create 'unique' access number
pid = os.getpid()
now = time.time()
access = "%i_%s" % (now,pid)
# retrieve 'dir' value
res = run_sql ("select dir from sbmACTION where sactname=%s",(action,))
dir = res[0][0]
try:
mainmenu = req.headers_in['Referer']
except:
mainmenu = ""
url = "/submit?doctype=%s&dir=%s&access=%s&act=%s&startPg=1%s&mainmenu=%s" % (
doctype,dir,access,action,params,quote(mainmenu))
req.err_headers_out.add("Location", url)
raise apache.SERVER_RETURN, apache.HTTP_MOVED_PERMANENTLY
return ""
def sub(self, req, form):
uid = getUid(req)
if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
return page_not_authorized(req, "../sub/",
navmenuid='submit')
myQuery = req.args
if myQuery:
if re.search("@",myQuery):
param = re.sub("@.*","",myQuery)
IN = re.sub(".*@","",myQuery)
else:
IN = myQuery
url = "%s/submit/direct?sub=%s&%s" % (urlpath,IN,param)
req.err_headers_out.add("Location", url)
raise apache.SERVER_RETURN, apache.HTTP_MOVED_PERMANENTLY
return ""
else:
return "Illegal page access"
def summary(self, req, form):
args = wash_urlargd(form, {
'doctype': (str, ''),
'act': (str, ''),
'access': (str, ''),
'indir': (str, '')})
uid = getUid(req)
if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
return page_not_authorized(req, "../summary.py/index",
navmenuid='submit')
t=""
curdir = "%s/%s/%s/%s" % (storage,args['indir'],args['doctype'],args['access'])
subname = "%s%s" % (args['act'], args['doctype'])
res = run_sql("select sdesc,fidesc,pagenb,level from sbmFIELD where subname=%s "
"order by pagenb,fieldnb", (subname,))
nbFields = 0
values = []
for arr in res:
if arr[0] != "":
val = {
'mandatory' : (arr[3] == 'M'),
'value' : '',
'page' : arr[2],
'name' : arr[0],
}
if os.path.exists("%s/%s" % (curdir,arr[1])):
fd = open("%s/%s" % (curdir,arr[1]),"r")
value = fd.read()
fd.close()
value = value.replace("\n"," ")
value = value.replace("Select:","")
else:
value = ""
val['value'] = value
values.append(val)
return websubmit_templates.tmpl_submit_summary(
ln = args['ln'],
values = values,
images = images,
)
def index(self, req, form):
args = wash_urlargd(form, {
'c': (str, cdsname),
'doctype': (str, ''),
'act': (str, ''),
'startPg': (str, "1"),
'indir': (str, ''),
'access': (str, ''),
'mainmenu': (str, ''),
'fromdir': (str, ''),
'file': (str, ''),
'nextPg': (str, ''),
'nbPg': (str, ''),
'curpage': (str, '1'),
'step': (str, '0'),
'mode': (str, 'U'),
})
req.form = form
def _index(req, c, ln, doctype, act, startPg, indir, access,
mainmenu, fromdir, file, nextPg, nbPg, curpage, step,
mode):
uid = getUid(req)
if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
return page_not_authorized(req, "../submit",
navmenuid='submit')
if doctype=="":
return home(req,c,ln)
elif act=="":
return action(req,c,ln,doctype)
elif int(step)==0:
return interface(req,c,ln, doctype, act, startPg, indir,
access, mainmenu, fromdir, file, nextPg,
nbPg, curpage)
else:
return endaction(req,c,ln, doctype, act, startPg, indir,
access,mainmenu, fromdir, file, nextPg,
nbPg, curpage, step, mode)
return _index(req, **args)
# Answer to both /submit/ and /submit
__call__ = index
def errorMsg(title,req,c=cdsname,ln=cdslang):
_ = gettext_set_language(ln)
return page(title=_("Error"),
body = create_error_box(req, title=title,verbose=0, ln=ln),
description=_("Internal Error"),
keywords="%s, Internal Error" % c,
language=ln,
req=req,
navmenuid='submit')
def warningMsg(title,req,c=cdsname,ln=cdslang):
_ = gettext_set_language(ln)
return page(title=_("Warning"),
body = title,
description=_("Internal Error"),
keywords="%s, Internal Error" % c,
language=ln,
req=req,
navmenuid='submit')
diff --git a/modules/websubmit/lib/websubmitadmin_engine.py b/modules/websubmit/lib/websubmitadmin_engine.py
index 653810a34..5a780fe56 100644
--- a/modules/websubmit/lib/websubmitadmin_engine.py
+++ b/modules/websubmit/lib/websubmitadmin_engine.py
@@ -1,4242 +1,4242 @@
# -*- coding: utf-8 -*-
## $Id$
##
## This file is part of CDS Invenio.
## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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.
__revision__ = "$Id$"
import re
from random import randint, seed
from os.path import split, basename, isfile
from os import access, F_OK, R_OK, W_OK, getpid, rename, unlink
from time import strftime, localtime
from invenio.websubmitadmin_dblayer import *
from invenio.websubmitadmin_config import *
-from invenio.access_control_admin import acc_getAllRoles, acc_getRoleUsers, acc_deleteUserRole
+from invenio.access_control_admin import acc_get_all_roles, acc_get_role_users, acc_delete_user_role
from invenio.config import cdslang, bibconvertconf
from invenio.access_control_engine import acc_authorize_action
import invenio.template
try:
websubmitadmin_templates = invenio.template.load('websubmitadmin')
except:
pass
## utility functions:
def is_adminuser(req, role):
"""check if user is a registered administrator. """
return acc_authorize_action(req, role)
def check_user(req, role, adminarea=2, authorized=0):
(auth_code, auth_message) = is_adminuser(req, role)
if not authorized and auth_code != 0:
return ("false", auth_message)
return ("", auth_message)
def get_navtrail(ln=cdslang):
"""gets the navtrail for title...
@param title: title of the page
@param ln: language
@return HTML output
"""
navtrail = websubmitadmin_templates.tmpl_navtrail(ln)
return navtrail
def stringify_listvars(mylist):
"""Accept a list (or a list of lists) (or tuples).
Convert each item in the list, into a string (replace None with the empty
string "").
@param mylist: A list/tuple of values, or a list/tuple of value list/tuples.
@return: a tuple of string values or a tuple of string value tuples
"""
string_list = []
try:
if type(mylist[0]) in (tuple,list):
for row in mylist:
string_list.append(map(lambda x: x is not None and str(x) or "", row))
else:
string_list = map(lambda x: x is not None and str(x) or "", mylist)
except IndexError:
pass
return string_list
def save_update_to_file(filepath, filecontent, notruncate=0, appendmode=0):
"""Save a string value to a file.
Save will create a new file if the file does not exist. Mode can be set to truncate an older file
or to refuse to create the file if it already exists. There is also a mode to "append" the string value
to a file.
@param filepath: (string) the full path to the file
@param filecontent: (string) the content to be written to the file
@param notruncate: (integer) should be 1 or 0, defaults to 0 (ZERO). If 0, existing file will be truncated;
if 1, file will not be written if it already exists
@param appendmode: (integer) should be 1 or 0, defaults to 0 (ZERO). If 1, data will be appended to the file
if it exists; if 0, file will be truncated (or not, depending on the notruncate mode) by new data.
@return: None
@exceptions raised:
- InvenioWebSubmitAdminWarningIOError: when operations involving writing to file failed.
"""
## sanity checking:
if notruncate not in (0, 1):
notruncate = 0
if appendmode not in (0, 1):
appendmode = 0
(fpath, fname) = split(filepath)
if fname == "":
## error opening file
msg = """Unable to open filepath [%s] - couldn't determine a valid filename""" % (filepath,)
raise InvenioWebSubmitAdminWarningIOError(msg)
## if fpath is not empty, append the trailing "/":
if fpath != "":
fpath += "/"
if appendmode == 0:
if notruncate != 0 and access("%s%s" % (fpath, fname), F_OK):
## in no-truncate mode, but file already exists!
msg = """Unable to write to file [%s] in "no-truncate mode" because file already exists"""\
% (fname,)
raise InvenioWebSubmitAdminWarningIOError(msg)
## file already exists, make temporary file first, then move it later
tmpfname = "%s_%s_%s" % (fname, strftime("%Y%m%d%H%M%S", localtime()), getpid())
## open temp file for writing:
try:
fp = open("%s%s" % (fpath, tmpfname), "w")
except IOError, e:
## cannot open file
msg = """Unable to write to file [%s%s] - cannot open file for writing""" % (fpath, fname)
raise InvenioWebSubmitAdminWarningIOError(msg)
## write contents to temp file:
try:
fp.write(filecontent)
fp.flush()
fp.close()
except IOError, e:
## could not write to temp file
msg = """Unable to write to file [%s]""" % (tmpfname,)
## remove the "temp file"
try:
fp.close()
unlink("%s%s" % (fpath, tmpfname))
except IOError:
pass
raise InvenioWebSubmitAdminWarningIOError(msg)
## rename temp file to final filename:
try:
rename("%s%s" % (fpath, tmpfname), "%s%s" % (fpath, fname))
except OSError:
## couldnt rename the tmp file to final file name
msg = """Unable to write to file [%s] - created temporary file [%s], but could not then rename it to [%s]"""\
% (fname, tmpfname, fname)
raise InvenioWebSubmitAdminWarningIOError(msg)
else:
## append mode:
try:
fp = open("%s%s" % (fpath, fname), "a")
except IOError, e:
## cannot open file
msg = """Unable to write to file [%s] - cannot open file for writing in append mode""" % (fname,)
raise InvenioWebSubmitAdminWarningIOError(msg)
## write contents to temp file:
try:
fp.write(filecontent)
fp.flush()
fp.close()
except IOError, e:
## could not write to temp file
msg = """Unable to write to file [%s] in append mode""" % (fname,)
## close the file
try:
fp.close()
except IOError:
pass
raise InvenioWebSubmitAdminWarningIOError(msg)
return
def string_is_alphanumeric_including_underscore(txtstring):
p_txtstring = re.compile(r'^\w*$')
m_txtstring = p_txtstring.search(txtstring)
if m_txtstring is not None:
return 1
else:
return 0
def function_name_is_valid(fname):
p_fname = re.compile(r'^(_|[a-zA-Z])\w*$')
m_fname = p_fname.search(fname)
if m_fname is not None:
return 1
else:
return 0
def wash_single_urlarg(urlarg, argreqdtype, argdefault, maxstrlen=None, minstrlen=None, truncatestr=0):
"""Wash a single argument according to some specifications.
@param urlarg: the argument to be tested, as passed from the form/url, etc
@param argreqdtype: (a python type) the type that the argument should conform to (argument required
type)
@argdefault: the default value that should be returned for the argument in the case that it
doesn't comply with the washing specifications
@param maxstrlen: (integer) the maximum length for a string argument; defaults to None, which means
that no maximum length is forced upon the string
@param minstrlen: (integer) the minimum length for a string argument; defaults to None, which means
that no minimum length is forced upon the string
@truncatestr: (integer) should be 1 or 0 (ZERO). A flag used to determine whether or not a string
argument that overstretches the maximum length (if one if provided) should be truncated, or reset
to the default for the argument. 0, means don't truncate and reset the argument; 1 means truncate
the string.
@return: the washed argument
@exceptions raised:
- ValueError: when it is not possible to cast an argument to the type passed as argreqdtype
"""
## sanity checking:
if maxstrlen is not None and type(maxstrlen) is not int:
maxstrlen = None
elif maxstrlen is int and maxstrlen < 1:
maxstrlen = None
if minstrlen is not None and type(minstrlen) is not int:
minstrlen = None
elif minstrlen is int and minstrlen < 1:
minstrlen = None
result = ""
arg_dst_type = argreqdtype
## if no urlarg, return the default for that argument:
if urlarg is None:
result = argdefault
return result
## get the type of the argument passed:
arg_src_type = type(urlarg)
value = urlarg
# First, handle the case where we want all the results. In
# this case, we need to ensure all the elements are strings,
# and not Field instances.
if arg_src_type in (list, tuple):
if arg_dst_type is list:
result = [str(x) for x in value]
return result
if arg_dst_type is tuple:
result = tuple([str(x) for x in value])
return result
# in all the other cases, we are only interested in the
# first value.
value = value[0]
# Maybe we already have what is expected? Then don't change
# anything.
if arg_src_type is arg_dst_type:
result = value
if arg_dst_type is str and maxstrlen is not None and len(result) > maxstrlen:
if truncatestr != 0:
result = result[0:maxstrlen]
else:
result = argdefault
elif arg_dst_type is str and minstrlen is not None and len(result) < minstrlen:
result = argdefault
return result
if arg_dst_type in (str, int):
try:
result = arg_dst_type(value)
if arg_dst_type is str and maxstrlen is not None and len(result) > maxstrlen:
if truncatestr != 0:
result = result[0:maxstrlen]
else:
result = argdefault
elif arg_dst_type is str and minstrlen is not None and len(result) < minstrlen:
result = argdefault
except:
result = argdefault
elif arg_dst_type is tuple:
result = (value,)
elif arg_dst_type is list:
result = [value]
elif arg_dst_type is dict:
result = {0: str(value)}
else:
raise ValueError('cannot cast form argument into type %r' % (arg_dst_type,))
return result
## Internal Business-Logic functions
## Functions for managing collection order, etc:
def build_submission_collection_tree(collection_id, has_brother_above=0, has_brother_below=0):
## get the name of this collection:
collection_name = get_collection_name(collection_id)
if collection_name is None:
collection_name = "Unknown Collection"
## make a data-structure containing the details of the collection:
collection_node = { 'collection_id' : collection_id, ## collection ID
'collection_name' : collection_name, ## collection Name
'collection_children' : [], ## list of 'collection' children nodes
'doctype_children' : [], ## list of 'doctype' children
'has_brother_above' : has_brother_above, ## has a sibling collection above in score
'has_brother_below' : has_brother_below, ## has a sibling collection below in score
}
## get the IDs and names of all doctypes attached to this collection:
res_doctype_children = get_doctype_children_of_collection(collection_id)
## for each child, add its details to the list of doctype children for this node:
for doctype in res_doctype_children:
doctype_node = { 'doctype_id' : doctype[0],
'doctype_lname' : doctype[1],
'catalogue_order' : doctype[2],
}
collection_node['doctype_children'].append(doctype_node)
## now get details of all collections attached to this one:
res_collection_children = get_collection_children_of_collection(collection_id)
num_collection_children = len(res_collection_children)
for child_num in xrange(0, num_collection_children):
brother_below = brother_above = 0
if child_num > 0:
## this is not the first brother - it has a brother above
brother_above = 1
if child_num < num_collection_children - 1:
## this is not the last brother - it has a brother below
brother_below = 1
collection_node['collection_children'].append(\
build_submission_collection_tree(collection_id=res_collection_children[child_num][0],
has_brother_above=brother_above,
has_brother_below=brother_below))
## return the built collection tree:
return collection_node
def _organise_submission_page_display_submission_tree(errors, warnings, user_msg=""):
title = "Organise WebSubmit Main Page"
body = ""
if user_msg == "" or type(user_msg) not in (list, tuple, str, unicode):
user_msg = []
## Get the submissions tree:
submission_collection_tree = build_submission_collection_tree(0)
## Get all 'submission collections':
submission_collections = get_details_of_all_submission_collections()
sub_col = [('0', 'Top Level')]
for collection in submission_collections:
sub_col.append((str(collection[0]), str(collection[1])))
## Get all document types:
doctypes = get_docid_docname_and_docid_alldoctypes()
## build the page:
body = websubmitadmin_templates.tmpl_display_submission_page_organisation(submission_collection_tree=submission_collection_tree,
submission_collections=sub_col,
doctypes=doctypes,
user_msg=user_msg)
return (title, body)
def _delete_submission_collection(sbmcolid):
"""Recursively calls itself to delete a submission-collection and all of its
attached children (and their children, etc) from the submission-tree.
@param sbmcolid: (integer) - the ID of the submission-collection to be deleted.
@return: None
@Exceptions raised: InvenioWebSubmitAdminWarningDeleteFailed when it was not
possible to delete the submission-collection or some of its children.
"""
## Get the collection-children of this submission-collection:
collection_children = get_collection_children_of_collection(sbmcolid)
## recursively move through each collection-child:
for collection_child in collection_children:
_delete_submission_collection(collection_child[0])
## delete all document-types attached to this submission-collection:
error_code = delete_doctype_children_from_submission_collection(sbmcolid)
if error_code != 0:
## Unable to delete all doctype-children:
err_msg = "Unable to delete doctype children of submission-collection [%s]" % sbmcolid
raise InvenioWebSubmitAdminWarningDeleteFailed(err_msg)
## delete this submission-collection's entry from the sbmCOLLECTION_sbmCOLLECTION table:
error_code = delete_submission_collection_from_submission_tree(sbmcolid)
if error_code != 0:
## Unable to delete submission-collection from the submission-tree:
err_msg = "Unable to delete submission-collection [%s] from submission-tree" % sbmcolid
raise InvenioWebSubmitAdminWarningDeleteFailed(err_msg)
## Now delete this submission-collection's details:
error_code = delete_submission_collection_details(sbmcolid)
if error_code != 0:
## Unable to delete the details of the submission-collection:
err_msg = "Unable to delete details of submission-collection [%s]" % sbmcolid
raise InvenioWebSubmitAdminWarningDeleteFailed(err_msg)
## return
return
def perform_request_organise_submission_page(doctype="",
sbmcolid="",
catscore="",
addsbmcollection="",
deletesbmcollection="",
addtosbmcollection="",
adddoctypes="",
movesbmcollectionup="",
movesbmcollectiondown="",
deletedoctypefromsbmcollection="",
movedoctypeupinsbmcollection="",
movedoctypedowninsbmcollection=""):
user_msg = []
errors = []
warnings = []
body = ""
if "" not in (deletedoctypefromsbmcollection, sbmcolid, catscore, doctype):
## delete a document type from it's position in the tree
error_code = delete_doctype_from_position_on_submission_page(doctype, sbmcolid, catscore)
if error_code == 0:
## doctype deleted - now normalize scores of remaining doctypes:
normalize_scores_of_doctype_children_for_submission_collection(sbmcolid)
user_msg.append("Document type successfully deleted from submissions tree")
else:
user_msg.append("Unable to delete document type from submission-collection")
## display submission-collections:
(title, body) = _organise_submission_page_display_submission_tree(errors, warnings, user_msg=user_msg)
elif "" not in (deletesbmcollection, sbmcolid):
## try to delete the submission-collection from the tree:
try:
_delete_submission_collection(sbmcolid)
user_msg.append("Submission-collection successfully deleted from submissions tree")
except InvenioWebSubmitAdminWarningDeleteFailed, excptn:
user_msg.append(str(excptn))
## re-display submission-collections:
(title, body) = _organise_submission_page_display_submission_tree(errors, warnings, user_msg=user_msg)
elif "" not in (movedoctypedowninsbmcollection, sbmcolid, doctype, catscore):
## move a doctype down in order for a submission-collection:
## normalize scores of all doctype-children of the submission-collection:
normalize_scores_of_doctype_children_for_submission_collection(sbmcolid)
## swap this doctype with that below it:
## Get score of doctype to move:
score_doctype_to_move = get_catalogue_score_of_doctype_child_of_submission_collection(sbmcolid, doctype)
## Get score of the doctype brother directly below the doctype to be moved:
score_brother_below = get_score_of_next_doctype_child_below(sbmcolid, score_doctype_to_move)
if None in (score_doctype_to_move, score_brother_below):
user_msg.append("Unable to move document type down")
else:
## update the brother below the doctype to be moved to have a score the same as the doctype to be moved:
update_score_of_doctype_child_of_submission_collection_at_scorex(sbmcolid, score_brother_below, score_doctype_to_move)
## Update the doctype to be moved to have a score of the brother directly below it:
update_score_of_doctype_child_of_submission_collection_with_doctypeid_and_scorex(sbmcolid,
doctype,
score_doctype_to_move,
score_brother_below)
user_msg.append("Document type moved down")
(title, body) = _organise_submission_page_display_submission_tree(errors, warnings, user_msg=user_msg)
elif "" not in (movedoctypeupinsbmcollection, sbmcolid, doctype, catscore):
## move a doctype up in order for a submission-collection:
## normalize scores of all doctype-children of the submission-collection:
normalize_scores_of_doctype_children_for_submission_collection(sbmcolid)
## swap this doctype with that above it:
## Get score of doctype to move:
score_doctype_to_move = get_catalogue_score_of_doctype_child_of_submission_collection(sbmcolid, doctype)
## Get score of the doctype brother directly above the doctype to be moved:
score_brother_above = get_score_of_previous_doctype_child_above(sbmcolid, score_doctype_to_move)
if None in (score_doctype_to_move, score_brother_above):
user_msg.append("Unable to move document type up")
else:
## update the brother above the doctype to be moved to have a score the same as the doctype to be moved:
update_score_of_doctype_child_of_submission_collection_at_scorex(sbmcolid, score_brother_above, score_doctype_to_move)
## Update the doctype to be moved to have a score of the brother directly above it:
update_score_of_doctype_child_of_submission_collection_with_doctypeid_and_scorex(sbmcolid,
doctype,
score_doctype_to_move,
score_brother_above)
user_msg.append("Document type moved up")
(title, body) = _organise_submission_page_display_submission_tree(errors, warnings, user_msg=user_msg)
elif "" not in (movesbmcollectiondown, sbmcolid):
## move a submission-collection down in order:
## Sanity checking:
try:
int(sbmcolid)
except ValueError:
sbmcolid = 0
if int(sbmcolid) != 0:
## Get father ID of submission-collection:
sbmcolidfather = get_id_father_of_collection(sbmcolid)
if sbmcolidfather is None:
user_msg.append("Unable to move submission-collection downwards")
else:
## normalize scores of all collection-children of the father submission-collection:
normalize_scores_of_collection_children_of_collection(sbmcolidfather)
## swap this collection with the one above it:
## get the score of the collection to move:
score_col_to_move = get_score_of_collection_child_of_submission_collection(sbmcolidfather, sbmcolid)
## get the score of the collection brother directly below the collection to be moved:
score_brother_below = get_score_of_next_collection_child_below(sbmcolidfather, score_col_to_move)
if None in (score_col_to_move, score_brother_below):
## Invalid movement
user_msg.append("Unable to move submission collection downwards")
else:
## update the brother below the collection to be moved to have a score the same as the collection to be moved:
update_score_of_collection_child_of_submission_collection_at_scorex(sbmcolidfather,
score_brother_below,
score_col_to_move)
## Update the collection to be moved to have a score of the brother directly below it:
update_score_of_collection_child_of_submission_collection_with_colid_and_scorex(sbmcolidfather,
sbmcolid,
score_col_to_move,
score_brother_below)
user_msg.append("Submission-collection moved downwards")
else:
## cannot move the master (0) collection
user_msg.append("Unable to move submission-collection downwards")
(title, body) = _organise_submission_page_display_submission_tree(errors, warnings, user_msg=user_msg)
elif "" not in (movesbmcollectionup, sbmcolid):
## move a submission-collection up in order:
## Sanity checking:
try:
int(sbmcolid)
except ValueError:
sbmcolid = 0
if int(sbmcolid) != 0:
## Get father ID of submission-collection:
sbmcolidfather = get_id_father_of_collection(sbmcolid)
if sbmcolidfather is None:
user_msg.append("Unable to move submission-collection upwards")
else:
## normalize scores of all collection-children of the father submission-collection:
normalize_scores_of_collection_children_of_collection(sbmcolidfather)
## swap this collection with the one above it:
## get the score of the collection to move:
score_col_to_move = get_score_of_collection_child_of_submission_collection(sbmcolidfather, sbmcolid)
## get the score of the collection brother directly above the collection to be moved:
score_brother_above = get_score_of_previous_collection_child_above(sbmcolidfather, score_col_to_move)
if None in (score_col_to_move, score_brother_above):
## Invalid movement
user_msg.append("Unable to move submission collection upwards")
else:
## update the brother above the collection to be moved to have a score the same as the collection to be moved:
update_score_of_collection_child_of_submission_collection_at_scorex(sbmcolidfather,
score_brother_above,
score_col_to_move)
## Update the collection to be moved to have a score of the brother directly above it:
update_score_of_collection_child_of_submission_collection_with_colid_and_scorex(sbmcolidfather,
sbmcolid,
score_col_to_move,
score_brother_above)
user_msg.append("Submission-collection moved upwards")
else:
## cannot move the master (0) collection
user_msg.append("Unable to move submission-collection upwards")
(title, body) = _organise_submission_page_display_submission_tree(errors, warnings, user_msg=user_msg)
elif "" not in (addsbmcollection, addtosbmcollection):
## Add a submission-collection, attached to a submission-collection:
## check that the collection to attach to exists:
parent_ok = 0
if int(addtosbmcollection) != 0:
parent_name = get_collection_name(addtosbmcollection)
if parent_name is not None:
parent_ok = 1
else:
parent_ok = 1
if parent_ok != 0:
## create the new collection:
id_son = insert_submission_collection(addsbmcollection)
## get the maximum catalogue score of the existing collection children:
max_child_score = \
get_maximum_catalogue_score_of_collection_children_of_submission_collection(addtosbmcollection)
## add it to the collection, at a higher score than the others have:
new_score = max_child_score + 1
insert_collection_child_for_submission_collection(addtosbmcollection, id_son, new_score)
user_msg.append("Submission-collection added to submissions tree")
else:
## Parent submission-collection does not exist:
user_msg.append("Unable to add submission-collection - parent unknown")
(title, body) = _organise_submission_page_display_submission_tree(errors, warnings, user_msg=user_msg)
elif "" not in (adddoctypes, addtosbmcollection):
## Add document type(s) to a submission-collection:
if type(adddoctypes) == str:
adddoctypes = [adddoctypes,]
## Does submission-collection exist?
num_collections_sbmcolid = get_number_of_rows_for_submission_collection(addtosbmcollection)
if num_collections_sbmcolid > 0:
for doctypeid in adddoctypes:
## Check that Doctype exists:
num_doctypes_doctypeid = get_number_doctypes_docid(doctypeid)
if num_doctypes_doctypeid < 1:
## Cannot connect an unknown doctype:
user_msg.append("Unable to connect unknown document-type [%s] to a submission-collection" \
% doctypeid)
continue
else:
## insert the submission-collection/doctype link:
## get the maximum catalogue score of the existing doctype children:
max_child_score = \
get_maximum_catalogue_score_of_doctype_children_of_submission_collection(addtosbmcollection)
## add it to the new doctype, at a higher score than the others have:
new_score = max_child_score + 1
insert_doctype_child_for_submission_collection(addtosbmcollection, doctypeid, new_score)
user_msg.append("Document-type added to submissions tree")
else:
## submission-collection didn't exist
user_msg.append("The selected submission-collection doesn't seem to exist")
## Check that submission-collection exists:
## insert
(title, body) = _organise_submission_page_display_submission_tree(errors, warnings, user_msg=user_msg)
else:
## default action - display submission-collections:
(title, body) = _organise_submission_page_display_submission_tree(errors, warnings, user_msg=user_msg)
return (title, body, errors, warnings)
## Functions for adding new catalgue to DB:
def _add_new_action(actid,actname,working_dir,status_text):
"""Insert the details of a new action into the websubmit system database.
@param actid: unique action id (sactname)
@param actname: action name (lactname)
@param working_dir: directory action works from (dir)
@param status_text: text string indicating action status (statustext)
"""
(actid,actname,working_dir,status_text) = (str(actid).upper(),str(actname),str(working_dir),str(status_text))
err_code = insert_action_details(actid,actname,working_dir,status_text)
return err_code
def perform_request_add_function(funcname=None, funcdescr=None, funcaddcommit=""):
user_msg = []
errors = []
warnings = []
body = ""
title = "Create New WebSubmit Function"
commit_error=0
## wash args:
if funcname is not None:
try:
funcname = wash_single_urlarg(urlarg=funcname, argreqdtype=str, argdefault="", maxstrlen=40, minstrlen=1)
if function_name_is_valid(fname=funcname) == 0:
funcname = ""
except ValueError, e:
funcname = ""
else:
funcname = ""
if funcdescr is not None:
try:
funcdescr = wash_single_urlarg(urlarg=funcdescr, argreqdtype=str, argdefault="")
except ValueError, e:
funcdescr = ""
else:
funcdescr = ""
## process request:
if funcaddcommit != "" and funcaddcommit is not None:
if funcname == "":
funcname = ""
user_msg.append("""Function name is mandatory and must be a string with no more than 40 characters""")
user_msg.append("""It must contain only alpha-numeric and underscore characters, beginning with a """\
"""letter or underscore""")
commit_error = 1
if commit_error != 0:
## don't commit - just re-display page with message to user
body = websubmitadmin_templates.tmpl_display_addfunctionform(funcdescr=funcdescr, user_msg=user_msg)
return (title, body, errors, warnings)
## Add a new function definition - IF it is not already present
err_code = insert_function_details(funcname, funcdescr)
## Handle error code - redisplay form with warning about no DB commit, or display with options
## to edit function:
if err_code == 0:
user_msg.append("""'%s' Function Added to WebSubmit""" % (funcname,))
all_function_parameters = get_distinct_paramname_all_websubmit_function_parameters()
body = websubmitadmin_templates.tmpl_display_addfunctionform(funcname=funcname,
funcdescr=funcdescr,
all_websubmit_func_parameters=all_function_parameters,
perform_act="functionedit",
user_msg=user_msg)
else:
## Could not commit function to WebSubmit DB - redisplay form with function description:
user_msg.append("""Could Not Add '%s' Function to WebSubmit""" % (funcname,))
body = websubmitadmin_templates.tmpl_display_addfunctionform(funcdescr=funcdescr, user_msg=user_msg)
else:
## Display Web form for new function addition:
body = websubmitadmin_templates.tmpl_display_addfunctionform()
return (title, body, errors, warnings)
def perform_request_add_action(actid=None, actname=None, working_dir=None, status_text=None, actcommit=""):
"""An interface for the addition of a new WebSubmit action.
If form fields filled, will insert new action into WebSubmit database, else will display
web form prompting for action details.
@param actid: unique id for new action
@param actname: name of new action
@param working_dir: action working directory for WebSubmit core
@param status_text: status text displayed at end of action
@return: tuple containing "title" (title of page), body (page body), errors (list of errors),
warnings (list of warnings).
"""
user_msg = []
errors = []
warnings = []
body = ""
title = "Create New WebSubmit Action"
commit_error=0
## wash args:
if actid is not None:
try:
actid = wash_single_urlarg(urlarg=actid, argreqdtype=str, argdefault="", maxstrlen=3, minstrlen=3)
if string_is_alphanumeric_including_underscore(txtstring=actid) == 0:
actid = ""
except ValueError, e:
actid = ""
else:
actid = ""
if actname is not None:
try:
actname = wash_single_urlarg(urlarg=actname, argreqdtype=str, argdefault="")
except ValueError, e:
actname = ""
else:
actname = ""
if working_dir is not None:
try:
working_dir = wash_single_urlarg(urlarg=working_dir, argreqdtype=str, argdefault="")
except ValueError, e:
working_dir = ""
else:
working_dir = ""
if status_text is not None:
try:
status_text = wash_single_urlarg(urlarg=status_text, argreqdtype=str, argdefault="")
except ValueError, e:
status_text = ""
else:
status_text = ""
## process request:
if actcommit != "" and actcommit is not None:
if actid in ("", None):
actid = ""
user_msg.append("""Action ID is mandatory and must be a 3 letter string""")
commit_error = 1
if actname in ("", None):
actname = ""
user_msg.append("""Action description is mandatory""")
commit_error = 1
if commit_error != 0:
## don't commit - just re-display page with message to user
body = websubmitadmin_templates.tmpl_display_addactionform(actid=actid, actname=actname, working_dir=working_dir,\
status_text=status_text, user_msg=user_msg)
return (title, body, errors, warnings)
## Commit new action to WebSubmit DB:
err_code = _add_new_action(actid,actname,working_dir,status_text)
## Handle error code - redisplay form with warning about no DB commit, or move to list
## of actions
if err_code == 0:
## Action added: show page listing WebSubmit actions
user_msg = """'%s' Action Added to WebSubmit""" % (actid,)
all_actions = get_actid_actname_allactions()
body = websubmitadmin_templates.tmpl_display_allactions(all_actions,user_msg=user_msg)
title = "Available WebSubmit Actions"
else:
## Could not commit action to WebSubmit DB redisplay form with completed details and error message
## warnings.append(('ERR_WEBSUBMIT_ADMIN_ADDACTIONFAILDUPLICATE',actid) ## TODO
user_msg = """Could Not Add '%s' Action to WebSubmit""" % (actid,)
body = websubmitadmin_templates.tmpl_display_addactionform(actid=actid, actname=actname, working_dir=working_dir, \
status_text=status_text, user_msg=user_msg)
else:
## Display Web form for new action details:
body = websubmitadmin_templates.tmpl_display_addactionform()
return (title, body, errors, warnings)
def perform_request_add_jscheck(chname=None, chdesc=None, chcommit=""):
"""An interface for the addition of a new WebSubmit JavaScript Check, as used on form elements.
If form fields filled, will insert new Check into WebSubmit database, else will display
Web form prompting for Check details.
@param chname: unique id/name for new Check
@param chdesc: description (JavaScript code body) of new Check
@return: tuple containing "title" (title of page), body (page body), errors (list of errors),
warnings (list of warnings).
"""
user_msg = []
errors = []
warnings = []
body = ""
title = "Create New WebSubmit Checking Function"
commit_error=0
## wash args:
if chname is not None:
try:
chname = wash_single_urlarg(urlarg=chname, argreqdtype=str, argdefault="", maxstrlen=15, minstrlen=1)
if function_name_is_valid(fname=chname) == 0:
chname = ""
except ValueError, e:
chname = ""
else:
chname = ""
if chdesc is not None:
try:
chdesc = wash_single_urlarg(urlarg=chdesc, argreqdtype=str, argdefault="")
except ValueError, e:
chdesc = ""
else:
chdesc = ""
## process request:
if chcommit != "" and chcommit is not None:
if chname in ("", None):
chname = ""
user_msg.append("""Check name is mandatory and must be a string with no more than 15 characters""")
user_msg.append("""It must contain only alpha-numeric and underscore characters, beginning with a """\
"""letter or underscore""")
commit_error = 1
if commit_error != 0:
## don't commit - just re-display page with message to user
body = websubmitadmin_templates.tmpl_display_addjscheckform(chname=chname, chdesc=chdesc, user_msg=user_msg)
return (title, body, errors, warnings)
## Commit new check to WebSubmit DB:
err_code = insert_jscheck_details(chname, chdesc)
## Handle error code - redisplay form wih warning about no DB commit, or move to list
## of checks
if err_code == 0:
## Check added: show page listing WebSubmit JS Checks
user_msg.append("""'%s' Checking Function Added to WebSubmit""" % (chname,))
all_jschecks = get_chname_alljschecks()
body = websubmitadmin_templates.tmpl_display_alljschecks(all_jschecks, user_msg=user_msg)
title = "Available WebSubmit Checking Functions"
else:
## Could not commit Check to WebSubmit DB: redisplay form with completed details and error message
## TODO : Warning Message
user_msg.append("""Could Not Add '%s' Checking Function to WebSubmit""" % (chname,))
body = websubmitadmin_templates.tmpl_display_addjscheckform(chname=chname, chdesc=chdesc, user_msg=user_msg)
else:
## Display Web form for new check details:
body = websubmitadmin_templates.tmpl_display_addjscheckform()
return (title, body, errors, warnings)
def perform_request_add_element(elname=None, elmarccode=None, eltype=None, elsize=None, elrows=None, \
elcols=None, elmaxlength=None, elval=None, elfidesc=None, \
elmodifytext=None, elcommit=""):
"""An interface for adding a new ELEMENT to the WebSubmit DB.
@param elname: (string) element name.
@param elmarccode: (string) element's MARC code.
@param eltype: (character) element type.
@param elsize: (integer) element size.
@param elrows: (integer) number of rows in element.
@param elcols: (integer) number of columns in element.
@param elmaxlength: (integer) maximum length of element
@param elval: (string) default value of element
@param elfidesc: (string) description of element
@param elmodifytext: (string) modification text of element
@param elcommit: (string) If this value is not empty, attempt to commit element details to WebSubmit DB
@return: tuple containing "title" (title of page), body (page body), errors (list of errors),
warnings (list of warnings).
"""
user_msg = []
errors = []
warnings = []
body = ""
title = "Create New WebSubmit Element"
commit_error=0
## wash args:
if elname is not None:
try:
elname = wash_single_urlarg(urlarg=elname, argreqdtype=str, argdefault="", maxstrlen=15, minstrlen=1)
if string_is_alphanumeric_including_underscore(txtstring=elname) == 0:
elname = ""
except ValueError, e:
elname = ""
else:
elname = ""
if elmarccode is not None:
try:
elmarccode = wash_single_urlarg(urlarg=elmarccode, argreqdtype=str, argdefault="")
except ValueError, e:
elmarccode = ""
else:
elmarccode = ""
if eltype is not None:
try:
eltype = wash_single_urlarg(urlarg=eltype, argreqdtype=str, argdefault="", maxstrlen=1, minstrlen=1)
except ValueError, e:
eltype = ""
else:
eltype = ""
if elsize is not None:
try:
elsize = wash_single_urlarg(urlarg=elsize, argreqdtype=int, argdefault="")
except ValueError, e:
elsize = ""
else:
elsize = ""
if elrows is not None:
try:
elrows = wash_single_urlarg(urlarg=elrows, argreqdtype=int, argdefault="")
except ValueError, e:
elrows = ""
else:
elrows = ""
if elcols is not None:
try:
elcols = wash_single_urlarg(urlarg=elcols, argreqdtype=int, argdefault="")
except ValueError, e:
elcols = ""
else:
elcols = ""
if elmaxlength is not None:
try:
elmaxlength = wash_single_urlarg(urlarg=elmaxlength, argreqdtype=int, argdefault="")
except ValueError, e:
elmaxlength = ""
else:
elmaxlength = ""
if elval is not None:
try:
elval = wash_single_urlarg(urlarg=elval, argreqdtype=str, argdefault="")
except ValueError, e:
elval = ""
else:
elval = ""
if elfidesc is not None:
try:
elfidesc = wash_single_urlarg(urlarg=elfidesc, argreqdtype=str, argdefault="")
except ValueError, e:
elfidesc = ""
else:
elfidesc = ""
if elmodifytext is not None:
try:
elmodifytext = wash_single_urlarg(urlarg=elmodifytext, argreqdtype=str, argdefault="")
except ValueError, e:
elmodifytext = ""
else:
elmodifytext = ""
## process request:
if elcommit != "" and elcommit is not None:
if elname == "":
elname = ""
user_msg.append("""The element name is mandatory and must be a string with no more than 15 characters""")
user_msg.append("""It must contain only alpha-numeric and underscore characters""")
commit_error = 1
if eltype == "" or eltype not in ("D", "F", "H", "I", "R", "S", "T"):
eltype = ""
user_msg.append("""The element type is mandatory and must be selected from the list""")
commit_error = 1
if commit_error != 0:
## don't commit - just re-display page with message to user
body = websubmitadmin_templates.tmpl_display_addelementform(elname=elname,
elmarccode=elmarccode,
eltype=eltype,
elsize=str(elsize),
elrows=str(elrows),
elcols=str(elcols),
elmaxlength=str(elmaxlength),
elval=elval,
elfidesc=elfidesc,
elmodifytext=elmodifytext,
user_msg=user_msg,
)
return (title, body, errors, warnings)
## Commit new element description to WebSubmit DB:
err_code = insert_element_details(elname=elname, elmarccode=elmarccode, eltype=eltype, \
elsize=elsize, elrows=elrows, elcols=elcols, \
elmaxlength=elmaxlength, elval=elval, elfidesc=elfidesc, \
elmodifytext=elmodifytext)
if err_code == 0:
## Element added: show page listing WebSubmit elements
user_msg.append("""'%s' Element Added to WebSubmit""" % (elname,))
title = "Available WebSubmit Elements"
all_elements = get_elename_allelements()
body = websubmitadmin_templates.tmpl_display_allelements(all_elements, user_msg=user_msg)
else:
## Could not commit element to WebSubmit DB: redisplay form with completed details and error message
## TODO : Warning Message
user_msg.append("""Could Not Add '%s' Element to WebSubmit""" % (elname,))
body = websubmitadmin_templates.tmpl_display_addelementform(elname=elname,
elmarccode=elmarccode,
eltype=eltype,
elsize=str(elsize),
elrows=str(elrows),
elcols=str(elcols),
elmaxlength=str(elmaxlength),
elval=elval,
elfidesc=elfidesc,
elmodifytext=elmodifytext,
user_msg=user_msg,
)
else:
## Display Web form for new element details:
body = websubmitadmin_templates.tmpl_display_addelementform()
return (title, body, errors, warnings)
def perform_request_edit_element(elname, elmarccode=None, eltype=None, elsize=None, \
elrows=None, elcols=None, elmaxlength=None, elval=None, \
elfidesc=None, elmodifytext=None, elcommit=""):
"""An interface for the editing and updating the details of a WebSubmit ELEMENT.
@param elname: element name.
@param elmarccode: element's MARC code.
@param eltype: element type.
@param elsize: element size.
@param elrows: number of rows in element.
@param elcols: number of columns in element.
@param elmaxlength: maximum length of element
@param elval: default value of element
@param elfidesc: description of element
@param elmodifytext: modification text of element
@param elcommit: If this value is not empty, attempt to commit element details to WebSubmit DB
@return: tuple containing "title" (title of page), body (page body), errors (list of errors),
warnings (list of warnings).
"""
user_msg = []
errors = []
warnings = []
body = ""
title = "Edit WebSubmit Element"
commit_error=0
## wash args:
if elname is not None:
try:
elname = wash_single_urlarg(urlarg=elname, argreqdtype=str, argdefault="", maxstrlen=15, minstrlen=1)
if string_is_alphanumeric_including_underscore(txtstring=elname) == 0:
elname = ""
except ValueError, e:
elname = ""
else:
elname = ""
if elmarccode is not None:
try:
elmarccode = wash_single_urlarg(urlarg=elmarccode, argreqdtype=str, argdefault="")
except ValueError, e:
elmarccode = ""
else:
elmarccode = ""
if eltype is not None:
try:
eltype = wash_single_urlarg(urlarg=eltype, argreqdtype=str, argdefault="", maxstrlen=1, minstrlen=1)
except ValueError, e:
eltype = ""
else:
eltype = ""
if elsize is not None:
try:
elsize = wash_single_urlarg(urlarg=elsize, argreqdtype=int, argdefault="")
except ValueError, e:
elsize = ""
else:
elsize = ""
if elrows is not None:
try:
elrows = wash_single_urlarg(urlarg=elrows, argreqdtype=int, argdefault="")
except ValueError, e:
elrows = ""
else:
elrows = ""
if elcols is not None:
try:
elcols = wash_single_urlarg(urlarg=elcols, argreqdtype=int, argdefault="")
except ValueError, e:
elcols = ""
else:
elcols = ""
if elmaxlength is not None:
try:
elmaxlength = wash_single_urlarg(urlarg=elmaxlength, argreqdtype=int, argdefault="")
except ValueError, e:
elmaxlength = ""
else:
elmaxlength = ""
if elval is not None:
try:
elval = wash_single_urlarg(urlarg=elval, argreqdtype=str, argdefault="")
except ValueError, e:
elval = ""
else:
elval = ""
if elfidesc is not None:
try:
elfidesc = wash_single_urlarg(urlarg=elfidesc, argreqdtype=str, argdefault="")
except ValueError, e:
elfidesc = ""
else:
elfidesc = ""
if elmodifytext is not None:
try:
elmodifytext = wash_single_urlarg(urlarg=elmodifytext, argreqdtype=str, argdefault="")
except ValueError, e:
elmodifytext = ""
else:
elmodifytext = ""
## process request:
if elcommit != "" and elcommit is not None:
if elname == "":
elname = ""
user_msg.append("""Invalid Element Name!""")
commit_error = 1
if eltype == "" or eltype not in ("D", "F", "H", "I", "R", "S", "T"):
eltype = ""
user_msg.append("""Invalid Element Type!""")
commit_error = 1
if commit_error != 0:
## don't commit - just re-display page with message to user
all_elements = get_elename_allelements()
user_msg.append("""Could Not Update Element""")
title = "Available WebSubmit Elements"
body = websubmitadmin_templates.tmpl_display_allelements(all_elements, user_msg=user_msg)
return (title, body, errors, warnings)
## Commit updated element description to WebSubmit DB:
err_code = update_element_details(elname=elname, elmarccode=elmarccode, eltype=eltype, \
elsize=elsize, elrows=elrows, elcols=elcols, \
elmaxlength=elmaxlength, elval=elval, elfidesc=elfidesc, \
elmodifytext=elmodifytext)
if err_code == 0:
## Element Updated: Show All Element Details Again
user_msg.append("""'%s' Element Updated""" % (elname,))
## Get submission page usage of element:
el_use = get_doctype_action_pagenb_for_submissions_using_element(elname)
element_dets = get_element_details(elname)
element_dets = stringify_listvars(element_dets)
## Take elements from results tuple:
(elmarccode, eltype, elsize, elrows, elcols, elmaxlength, \
elval, elfidesc, elcd, elmd, elmodifytext) = \
(element_dets[0][0], element_dets[0][1], element_dets[0][2], element_dets[0][3], \
element_dets[0][4], element_dets[0][5], element_dets[0][6], element_dets[0][7], \
element_dets[0][8], element_dets[0][9], element_dets[0][10])
## Pass to template:
body = websubmitadmin_templates.tmpl_display_addelementform(elname=elname,
elmarccode=elmarccode,
eltype=eltype,
elsize=elsize,
elrows=elrows,
elcols=elcols,
elmaxlength=elmaxlength,
elval=elval,
elfidesc=elfidesc,
elcd=elcd,
elmd=elmd,
elmodifytext=elmodifytext,
perform_act="elementedit",
user_msg=user_msg,
el_use_tuple=el_use
)
else:
## Could Not Update Element: Maybe Key Violation, or Invalid elname? Redisplay all elements.
## TODO : LOGGING
all_elements = get_elename_allelements()
user_msg.append("""Could Not Update Element '%s'""" % (elname,))
title = "Available WebSubmit Elements"
body = websubmitadmin_templates.tmpl_display_allelements(all_elements, user_msg=user_msg)
else:
## Display Web form containing existing details of element:
element_dets = get_element_details(elname)
## Get submission page usage of element:
el_use = get_doctype_action_pagenb_for_submissions_using_element(elname)
num_rows_ret = len(element_dets)
element_dets = stringify_listvars(element_dets)
if num_rows_ret == 1:
## Display Element details
## Take elements from results tuple:
(elmarccode, eltype, elsize, elrows, elcols, elmaxlength, \
elval, elfidesc, elcd, elmd, elmodifytext) = \
(element_dets[0][0], element_dets[0][1], element_dets[0][2], element_dets[0][3], \
element_dets[0][4], element_dets[0][5], element_dets[0][6], element_dets[0][7], \
element_dets[0][8], element_dets[0][9], element_dets[0][10])
## Pass to template:
body = websubmitadmin_templates.tmpl_display_addelementform(elname=elname,
elmarccode=elmarccode,
eltype=eltype,
elsize=elsize,
elrows=elrows,
elcols=elcols,
elmaxlength=elmaxlength,
elval=elval,
elfidesc=elfidesc,
elcd=elcd,
elmd=elmd,
elmodifytext=elmodifytext,
perform_act="elementedit",
el_use_tuple=el_use
)
else:
## Either no rows, or more than one row for ELEMENT: log error, and display all Elements
## TODO : LOGGING
title = "Available WebSubmit Elements"
all_elements = get_elename_allelements()
if num_rows_ret > 1:
## Key Error - duplicated elname
user_msg.append("""Found Several Rows for Element with Name '%s' - Inform Administrator""" % (elname,))
## LOG MESSAGE
else:
## No rows for ELEMENT
user_msg.append("""Could Not Find Any Rows for Element with Name '%s'""" % (elname,))
## LOG MESSAGE
body = websubmitadmin_templates.tmpl_display_allelements(all_elements, user_msg=user_msg)
return (title, body, errors, warnings)
def _display_edit_check_form(errors, warnings, chname, user_msg=""):
title = "Edit WebSubmit Checking Function"
if user_msg == "":
user_msg = []
jscheck_dets = get_jscheck_details(chname)
num_rows_ret = len(jscheck_dets)
if num_rows_ret == 1:
## Display Check details
body = websubmitadmin_templates.tmpl_display_addjscheckform(chname=jscheck_dets[0][0],
chdesc=jscheck_dets[0][1],
perform_act="jscheckedit",
cd=jscheck_dets[0][2],
md=jscheck_dets[0][3],
user_msg=user_msg)
else:
## Either no rows, or more than one row for Check: log error, and display all Checks
## TODO : LOGGING
title = "Available WebSubmit Checking Functions"
all_jschecks = get_chname_alljschecks()
if num_rows_ret > 1:
## Key Error - duplicated chname
user_msg.append("""Found Several Rows for Checking Function with Name '%s' - Inform Administrator""" % (chname,))
## LOG MESSAGE
else:
## No rows for action
user_msg.append("""Could Not Find Any Rows for Checking Function with Name '%s'""" % (chname,))
## LOG MESSAGE
body = websubmitadmin_templates.tmpl_display_alljschecks(all_jschecks, user_msg=user_msg)
return (title, body)
def perform_request_edit_jscheck(chname, chdesc=None, chcommit=""):
"""Interface for editing and updating the details of a WebSubmit Check.
If only "chname" provided, will display the details of a Check in a Web form.
If "chdesc" not empty, will assume that this is a call to commit update to Check details.
@param chname: unique id for Check
@param chdesc: modified value for WebSubmit Check description (code body) - (presence invokes update)
@return: tuple containing "title" (title of page), body (page body), errors (list of errors),
warnings (list of warnings).
"""
user_msg = []
errors = []
warnings = []
body = ""
title = "Edit WebSubmit Checking Function"
commit_error=0
## wash args:
if chname is not None:
try:
chname = wash_single_urlarg(urlarg=chname, argreqdtype=str, argdefault="", maxstrlen=15, minstrlen=1)
if function_name_is_valid(fname=chname) == 0:
chname = ""
except ValueError, e:
chname = ""
else:
chname = ""
if chdesc is not None:
try:
chdesc = wash_single_urlarg(urlarg=chdesc, argreqdtype=str, argdefault="")
except ValueError, e:
chdesc = ""
else:
chdesc = ""
(chname, chdesc) = (str(chname), str(chdesc))
if chcommit != "" and chcommit is not None:
if chname in ("", None):
chname = ""
user_msg.append("""Check name is mandatory and must be a string with no more than 15 characters""")
user_msg.append("""It must contain only alpha-numeric and underscore characters, beginning with a """\
"""letter or underscore""")
commit_error = 1
if commit_error != 0:
## don't commit - just re-display page with message to user
all_jschecks = get_chname_alljschecks()
user_msg.append("""Could Not Update Checking Function""")
body = websubmitadmin_templates.tmpl_display_alljschecks(all_jschecks, user_msg=user_msg)
title = "Available WebSubmit Checking Functions"
return (title, body, errors, warnings)
## Commit updated Check details to WebSubmit DB:
err_code = update_jscheck_details(chname, chdesc)
if err_code == 0:
## Check Updated: Show All Check Details Again
user_msg.append("""'%s' Check Updated""" % (chname,))
jscheck_dets = get_jscheck_details(chname)
body = websubmitadmin_templates.tmpl_display_addjscheckform(chname=jscheck_dets[0][0],
chdesc=jscheck_dets[0][1],
perform_act="jscheckedit",
cd=jscheck_dets[0][2],
md=jscheck_dets[0][3],
user_msg=user_msg
)
else:
## Could Not Update Check: Maybe Key Violation, or Invalid chname? Redisplay all Checks.
## TODO : LOGGING
all_jschecks = get_chname_alljschecks()
user_msg.append("""Could Not Update Checking Function '%s'""" % (chname,))
body = websubmitadmin_templates.tmpl_display_alljschecks(all_jschecks, user_msg=user_msg)
title = "Available WebSubmit Checking Functions"
else:
## Display Web form containing existing details of Check:
(title, body) = _display_edit_check_form(errors, warnings, chname=chname)
return (title, body, errors, warnings)
def _display_edit_action_form(errors, warnings, actid, user_msg=""):
title = "Edit WebSubmit Action"
if user_msg == "":
user_msg = []
action_dets = get_action_details(actid)
num_rows_ret = len(action_dets)
if num_rows_ret == 1:
## Display action details
body = websubmitadmin_templates.tmpl_display_addactionform(actid=action_dets[0][0],
actname=action_dets[0][1],
working_dir=action_dets[0][2],
status_text=action_dets[0][3],
perform_act="actionedit",
cd=action_dets[0][4],
md=action_dets[0][5],
user_msg=user_msg)
else:
## Either no rows, or more than one row for action: log error, and display all actions
## TODO : LOGGING
title = "Available WebSubmit Actions"
all_actions = get_actid_actname_allactions()
if num_rows_ret > 1:
## Key Error - duplicated actid
user_msg.append("""Found Several Rows for Action with ID '%s' - Inform Administrator""" % (actid,))
## LOG MESSAGE
else:
## No rows for action
user_msg.append("""Could Not Find Any Rows for Action with ID '%s'""" % (actid,))
## LOG MESSAGE
body = websubmitadmin_templates.tmpl_display_allactions(all_actions, user_msg=user_msg)
return (title, body)
def perform_request_edit_action(actid, actname=None, working_dir=None, status_text=None, actcommit=""):
"""Interface for editing and updating the details of a WebSubmit action.
If only "actid" provided, will display the details of an action in a Web form.
If "actname" not empty, will assume that this is a call to commit update to action details.
@param actid: unique id for action
@param actname: modified value for WebSubmit action name/description (presence invokes update)
@param working_dir: modified value for WebSubmit action working_dir
@param status_text: modified value for WebSubmit action status text
@return: tuple containing "title" (title of page), body (page body), errors (list of errors),
warnings (list of warnings).
"""
user_msg = []
errors = []
warnings = []
body = ""
title = "Edit WebSubmit Action"
commit_error = 0
## wash args:
if actid is not None:
try:
actid = wash_single_urlarg(urlarg=actid, argreqdtype=str, argdefault="", maxstrlen=3, minstrlen=3)
if string_is_alphanumeric_including_underscore(txtstring=actid) == 0:
actid = ""
except ValueError, e:
actid = ""
actid = actid.upper()
else:
actid = ""
if actname is not None:
try:
actname = wash_single_urlarg(urlarg=actname, argreqdtype=str, argdefault="")
except ValueError, e:
actname = ""
else:
actname = ""
if working_dir is not None:
try:
working_dir = wash_single_urlarg(urlarg=working_dir, argreqdtype=str, argdefault="")
except ValueError, e:
working_dir = ""
else:
working_dir = ""
if status_text is not None:
try:
status_text = wash_single_urlarg(urlarg=status_text, argreqdtype=str, argdefault="")
except ValueError, e:
status_text = ""
else:
status_text = ""
## process request:
if actcommit != "" and actcommit is not None:
if actname in ("", None):
actname = ""
user_msg.append("""Action description is mandatory""")
commit_error = 1
if commit_error != 0:
## don't commit - just re-display page with message to user
(title, body) = _display_edit_action_form(errors=errors, warnings=warnings, actid=actid, user_msg=user_msg)
return (title, body, errors, warnings)
## Commit updated action details to WebSubmit DB:
err_code = update_action_details(actid, actname, working_dir, status_text)
if err_code == 0:
## Action Updated: Show Action Details Again
user_msg.append("""'%s' Action Updated""" % (actid,))
action_dets = get_action_details(actid)
body = websubmitadmin_templates.tmpl_display_addactionform(actid=action_dets[0][0],
actname=action_dets[0][1],
working_dir=action_dets[0][2],
status_text=action_dets[0][3],
perform_act="actionedit",
cd=action_dets[0][4],
md=action_dets[0][5],
user_msg=user_msg
)
else:
## Could Not Update Action: Maybe Key Violation, or Invalid actid? Redisplay all actions.
## TODO : LOGGING
all_actions = get_actid_actname_allactions()
user_msg.append("""Could Not Update Action '%s'""" % (actid,))
body = websubmitadmin_templates.tmpl_display_allactions(all_actions, user_msg=user_msg)
title = "Available WebSubmit Actions"
else:
## Display Web form containing existing details of action:
(title, body) = _display_edit_action_form(errors=errors, warnings=warnings, actid=actid)
return (title, body, errors, warnings)
def _functionedit_display_function_details(errors, warnings, funcname, user_msg=""):
"""Display the details of a function, along with any message to the user that may have been provided.
@param errors: LIST of errors (passed by reference from caller) - errors will be appended to it
@param warnings: LIST of warnings (passed by reference from caller) - warnings will be appended to it
@param funcname: unique name of function to be updated
@param user_msg: Any message to the user that is to be displayed on the page.
@return: tuple containing (page title, HTML page body).
"""
if user_msg == "":
user_msg = []
title = "Edit WebSubmit Function"
func_descr_res = get_function_description(function=funcname)
num_rows_ret = len(func_descr_res)
if num_rows_ret == 1:
## Display action details
funcdescr = func_descr_res[0][0]
if funcdescr is None:
funcdescr = ""
## get parameters for this function:
this_function_parameters = get_function_parameters(function=funcname)
## get all function parameters in WebSubmit:
all_function_parameters = get_distinct_paramname_all_websubmit_function_parameters()
body = websubmitadmin_templates.tmpl_display_addfunctionform(funcname=funcname,
funcdescr=funcdescr,
func_parameters=this_function_parameters,
all_websubmit_func_parameters=all_function_parameters,
perform_act="functionedit",
user_msg=user_msg
)
else:
## Either no rows, or more than one row for function: log error, and display all functions
## TODO : LOGGING
title = "Available WebSubmit Functions"
all_functions = get_funcname_funcdesc_allfunctions()
if num_rows_ret > 1:
## Key Error - duplicated function name
user_msg.append("""Found Several Rows for Function with Name '%s' - Inform Administrator""" % (funcname,))
## LOG MESSAGE
else:
## No rows for function
user_msg.append("""Could Not Find Any Rows for Function with Name '%s'""" % (funcname,))
## LOG MESSAGE
body = websubmitadmin_templates.tmpl_display_allfunctions(all_functions, user_msg=user_msg)
return (title, body)
def _functionedit_update_description(errors, warnings, funcname, funcdescr):
"""Perform an update of the description for a given function.
@param errors: LIST of errors (passed by reference from caller) - errors will be appended to it
@param warnings: LIST of warnings (passed by reference from caller) - warnings will be appended to it
@param funcname: unique name of function to be updated
@param funcdescr: description to be updated for funcname
@return: a tuple containing (page title, HTML body content)
"""
user_msg = []
err_code = update_function_description(funcname, funcdescr)
if err_code == 0:
## Function updated - redisplay
user_msg.append("""'%s' Function Description Updated""" % (funcname,))
else:
## Could not update function description
## TODO : ERROR LIBS
user_msg.append("""Could Not Update Description for Function '%s'""" % (funcname,))
## Display function details
(title, body) = _functionedit_display_function_details(errors=errors, warnings=warnings, funcname=funcname, user_msg=user_msg)
return (title, body)
def _functionedit_delete_parameter(errors, warnings, funcname, deleteparam):
"""Delete a parameter from a given function.
Important: if any document types have been using the function from which this parameter will be deleted,
and therefore have values for this parameter, these values will not be deleted from the WebSubmit DB.
The deleted parameter therefore may continue to exist in the WebSubmit DB, but will be disassociated
from this function.
@param errors: LIST of errors (passed by reference from caller) - errors will be appended to it
@param warnings: LIST of warnings (passed by reference from caller) - warnings will be appended to it
@param funcname: unique name of the function from which the parameter is to be deleted.
@param deleteparam: the name of the parameter to be deleted from the function.
@return: tuple containing (title, HTML body content)
"""
user_msg = []
err_code = delete_function_parameter(function=funcname, parameter_name=deleteparam)
if err_code == 0:
## Parameter deleted - redisplay function details
user_msg.append("""'%s' Parameter Deleted from '%s' Function""" % (deleteparam, funcname))
else:
## could not delete param - it does not exist for this function
## TODO : ERROR LIBS
user_msg.append("""'%s' Parameter Does not Seem to Exist for Function '%s' - Could not Delete""" \
% (deleteparam, funcname))
## Display function details
(title, body) = _functionedit_display_function_details(errors=errors, warnings=warnings, funcname=funcname, user_msg=user_msg)
return (title, body)
def _functionedit_add_parameter(errors, warnings, funcname, funceditaddparam="", funceditaddparamfree=""):
"""Add (connect) a parameter to a given WebSubmit function.
@param errors: LIST of errors (passed by reference from caller) - errors will be appended to it
@param warnings: LIST of warnings (passed by reference from caller) - warnings will be appended to it
@param funcname: unique name of the function to which the parameter is to be added.
@param funceditaddparam: the value of a HTML select list: if present, will contain the name of the
parameter to be added to the function. May also be empty - the user may have used the free-text field
(funceditaddparamfree) to manually enter the name of a parameter. The important thing is that one
must be present for the parameter to be added sucessfully.
@param funceditaddparamfree: The name of the parameter to be added to the function, as taken from a free-
text HTML input field. May also be empty - the user may have used the HTML select-list (funceditaddparam)
field to choose the parameter. The important thing is that one must be present for the parameter to be
added sucessfully. The value "funceditaddparamfree" value will take priority over the "funceditaddparam"
list value.
@return: tuple containing (title, HTML body content)
"""
user_msg = []
if funceditaddparam in ("", None, "NO_VALUE") and funceditaddparamfree in ("", None):
## no parameter chosen
## TODO : ERROR LIBS
user_msg.append("""Unable to Find the Parameter to be Added to Function '%s' - Could not Add""" % (funcname,))
else:
add_parameter = ""
if funceditaddparam not in ("", None) and funceditaddparamfree not in ("", None):
## both select box and free-text values provided for parameter - prefer free-text
add_parameter = funceditaddparamfree
elif funceditaddparam not in ("", None):
## take add select-box chosen parameter
add_parameter = funceditaddparam
else:
## take add free-text chosen parameter
add_parameter = funceditaddparamfree
## attempt to commit parameter:
err_code = add_function_parameter(function=funcname, parameter_name=add_parameter)
if err_code == 0:
## Parameter added - redisplay function details
user_msg.append("""'%s' Parameter Added to '%s' Function""" % (add_parameter, funcname))
else:
## could not add param - perhaps it already exists for this function
## TODO : ERROR LIBS
user_msg.append("""Could not Add '%s' Parameter to Function '%s' - It Already Exists for this Function""" \
% (add_parameter, funcname))
## Display function details
(title, body) = _functionedit_display_function_details(errors=errors, warnings=warnings, funcname=funcname, user_msg=user_msg)
return (title, body)
def perform_request_edit_function(funcname, funcdescr=None, funceditaddparam=None, funceditaddparamfree=None,
funceditdelparam=None, funcdescreditcommit="", funcparamdelcommit="",
funcparamaddcommit=""):
"""Edit a WebSubmit function. 3 possibilities: edit the function description; delete a parameter from the
function; add a new parameter to the function.
@param funcname: the name of the function to be modified
@param funcdescr: the new function description
@param funceditaddparam: the name of the parameter to be added to the function (taken from HTML SELECT-list)
@param funceditaddparamfree: the name of the parameter to be added to the function (taken from free-text input)
@param funceditdelparam: the name of the parameter to be deleted from the function
@param funcdescreditcommit: a flag to indicate that this request is to update the description of a function
@param funcparamdelcommit: a flag to indicate that this request is to delete a parameter from a function
@param funcparamaddcommit: a flag to indicate that this request is to add a new parameter to a function
@return: tuple containing (page title, HTML page body, list of errors encountered, list of warnings)
"""
errors = []
warnings = []
body = ""
title = "Edit WebSubmit Function"
commit_error = 0
## wash args:
if funcname is not None:
try:
funcname = wash_single_urlarg(urlarg=funcname, argreqdtype=str, argdefault="")
if string_is_alphanumeric_including_underscore(txtstring=funcname) == 0:
funcname = ""
except ValueError, e:
funcname = ""
else:
funcname = ""
if funcdescr is not None:
try:
funcdescr = wash_single_urlarg(urlarg=funcdescr, argreqdtype=str, argdefault="")
except ValueError, e:
funcdescr = ""
else:
funcdescr = ""
if funceditaddparam is not None:
try:
funceditaddparam = wash_single_urlarg(urlarg=funceditaddparam, argreqdtype=str, argdefault="")
if string_is_alphanumeric_including_underscore(txtstring=funceditaddparam) == 0:
funceditaddparam = ""
except ValueError, e:
funceditaddparam = ""
else:
funceditaddparam = ""
if funceditaddparamfree is not None:
try:
funceditaddparamfree = wash_single_urlarg(urlarg=funceditaddparamfree, argreqdtype=str, argdefault="")
if string_is_alphanumeric_including_underscore(txtstring=funceditaddparamfree) == 0:
funceditaddparamfree = ""
except ValueError, e:
funceditaddparamfree = ""
else:
funceditaddparamfree = ""
if funceditdelparam is not None:
try:
funceditdelparam = wash_single_urlarg(urlarg=funceditdelparam, argreqdtype=str, argdefault="")
except ValueError, e:
funceditdelparam = ""
else:
funceditdelparam = ""
if funcname == "":
(title, body) = _functionedit_display_function_details(errors=errors, warnings=warnings, funcname=funcname)
return (title, body, errors, warnings)
if funcdescreditcommit != "" and funcdescreditcommit is not None:
## Update the definition of a function:
(title, body) = _functionedit_update_description(errors=errors, warnings=warnings, funcname=funcname, funcdescr=funcdescr)
elif funcparamaddcommit != "" and funcparamaddcommit is not None:
## Request to add a new parameter to a function
(title, body) = _functionedit_add_parameter(errors=errors, warnings=warnings, funcname=funcname,
funceditaddparam=funceditaddparam, funceditaddparamfree=funceditaddparamfree)
elif funcparamdelcommit != "" and funcparamdelcommit is not None:
## Request to delete a parameter from a function
(title, body) = _functionedit_delete_parameter(errors=errors, warnings=warnings, funcname=funcname, deleteparam=funceditdelparam)
else:
## Display Web form for new function addition:
(title, body) = _functionedit_display_function_details(errors=errors, warnings=warnings, funcname=funcname)
return (title, body, errors, warnings)
def perform_request_function_usage(funcname):
"""Display a page containing the usage details of a given function.
@param funcname: the function name
@return: page body
"""
errors = []
warnings = []
func_usage = get_function_usage_details(function=funcname)
func_usage = stringify_listvars(func_usage)
body = websubmitadmin_templates.tmpl_display_function_usage(funcname, func_usage)
return (body, errors, warnings)
def perform_request_list_actions():
"""Display a list of all WebSubmit actions.
@return: tuple: (body,errors,warnings), where errors and warnings are lists of errors/warnings
encountered along the way, and body is a string of HTML, which is a page body.
"""
errors = []
warnings = []
body = ""
all_actions = get_actid_actname_allactions()
body = websubmitadmin_templates.tmpl_display_allactions(all_actions)
return (body, errors, warnings)
def perform_request_list_doctypes():
"""Display a list of all WebSubmit document types.
@return: tuple:(body,errors,warnings), where errors and warnings are lists of errors/warnings
encountered along the way, and body is a string of HTML, which is a page body.
"""
errors = []
warnings = []
body = ""
all_doctypes = get_docid_docname_alldoctypes()
body = websubmitadmin_templates.tmpl_display_alldoctypes(all_doctypes)
return (body, errors, warnings)
def perform_request_list_jschecks():
"""Display a list of all WebSubmit JavaScript element checking functions.
@return: tuple:(body,errors,warnings), where errors and warnings are lists of errors/warnings
encountered along the way, and body is a string of HTML, which is a page body.
"""
errors = []
warnings = []
body = ""
all_jschecks = get_chname_alljschecks()
body = websubmitadmin_templates.tmpl_display_alljschecks(all_jschecks)
return (body, errors, warnings)
def perform_request_list_functions():
"""Display a list of all WebSubmit FUNCTIONS.
@return: tuple:(body,errors,warnings), where errors and warnings are lists of errors/warnings
encountered along the way, and body is a string of HTML, which is a page body.
"""
errors = []
warnings = []
body = ""
all_functions = get_funcname_funcdesc_allfunctions()
body = websubmitadmin_templates.tmpl_display_allfunctions(all_functions)
return (body, errors, warnings)
def perform_request_list_elements():
"""Display a list of all WebSubmit ELEMENTS.
@return: tuple:(body,errors,warnings), where errors and warnings are lists of errors/warnings
encountered along the way, and body is a string of HTML, which is a page body.
"""
errors = []
warnings = []
body = ""
all_elements = get_elename_allelements()
body = websubmitadmin_templates.tmpl_display_allelements(all_elements)
return (body, errors, warnings)
def _remove_doctype(errors, warnings, doctype):
"""Process removal of a document type.
@param errors: LIST of errors (passed by reference from caller) - errors will be appended to it
@param warnings: LIST of warnings (passed by reference from caller) - warnings will be appended to it
@param doctype: the document type to be removed.
@return: a tuple containing page title, and HTML page body)
"""
title = ""
body = ""
user_msg = []
numrows_doctype = get_number_doctypes_docid(docid=doctype)
if numrows_doctype == 1:
## Doctype is unique and can therefore be deleted:
## Delete any function parameters for this document type:
error_code = delete_all_parameters_doctype(doctype=doctype)
if error_code != 0:
## problem deleting some or all parameters - inform user and log error
## TODO : ERROR LOGGING
user_msg.append("""Unable to delete some or all function parameter values for document type "%s".""" % (doctype,))
## delete all functions called by this doctype's actions
error_code = delete_all_functions_doctype(doctype=doctype)
if error_code != 0:
## problem deleting some or all functions - inform user and log error
## TODO : ERROR LOGGING
user_msg.append("""Unable to delete some or all functions for document type "%s".""" % (doctype,))
## delete all categories of this doctype
error_code = delete_all_categories_doctype(doctype=doctype)
if error_code != 0:
## problem deleting some or all categories - inform user and log error
## TODO : ERROR LOGGING
user_msg.append("""Unable to delete some or all parameters for document type "%s".""" % (doctype,))
## delete all submission interface fields for this doctype
error_code = delete_all_submissionfields_doctype(doctype=doctype)
if error_code != 0:
## problem deleting some or all submission fields - inform user and log error
## TODO : ERROR LOGGING
user_msg.append("""Unable to delete some or all submission fields for document type "%s".""" % (doctype,))
## delete all submissions for this doctype
error_code = delete_all_submissions_doctype(doctype)
if error_code != 0:
## problem deleting some or all submissions - inform user and log error
## TODO : ERROR LOGGING
user_msg.append("""Unable to delete some or all submissions for document type "%s".""" % (doctype,))
## delete entry for this doctype in the collection-doctypes table
error_code = delete_collection_doctype_entry_doctype(doctype)
if error_code != 0:
## problem deleting this doctype from the collection-doctypes table
## TODO : ERROR LOGGING
user_msg.append("""Unable to delete document type "%s" from the collection-doctypes table.""" % (doctype,))
## delete the doctype itself
error_code = delete_doctype(doctype)
if error_code != 0:
## problem deleting this doctype from the doctypes table
## TODO : ERROR LOGGING
user_msg.append("""Unable to delete document type "%s" from the document types table.""" % (doctype,))
user_msg.append("""The "%s" document type should now have been deleted, but you should not ignore any warnings.""" % (doctype,))
title = """Available WebSubmit Document Types"""
all_doctypes = get_docid_docname_alldoctypes()
body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg)
else:
## doctype is not unique and cannot be deleted
if numrows_doctype > 1:
## doctype is duplicated - cannot delete - needs admin intervention
## TODO : LOG ERROR
user_msg.append("""%s WebSubmit document types have been identified for doctype id "%s" - unable to delete.""" \
""" Please inform administrator.""" % (numrows_doctype, doctype))
else:
## no document types found for this doctype id
## TODO : LOG ERROR
user_msg.append("""Unable to find any document types in the WebSubmit database for doctype id "%s" - unable to delete""" \
% (doctype,))
## get a list of all document types, and once more display the delete form, with the message
alldoctypes = get_docid_docname_and_docid_alldoctypes()
title = "Remove WebSubmit Doctument Type"
body = websubmitadmin_templates.tmpl_display_delete_doctype_form(doctype="", alldoctypes=alldoctypes, user_msg=user_msg)
return (title, body)
def perform_request_remove_doctype(doctype="", doctypedelete="", doctypedeleteconfirm=""):
"""Remove a document type from WebSubmit.
@param doctype: the document type to be removed
@doctypedelete: flag to signal that a confirmation for deletion should be displayed
@doctypedeleteconfirm: flag to signal that confirmation for deletion has been received and
the doctype should be removed
@return: a tuple (title, body, errors, warnings)
"""
errors = []
warnings = []
body = ""
title = "Remove WebSubmit Document Type"
if doctypedeleteconfirm not in ("", None):
## Delete the document type:
(title, body) = _remove_doctype(errors=errors, warnings=warnings, doctype=doctype)
else:
## Display "doctype delete form"
if doctypedelete not in ("", None) and doctype not in ("", None):
## don't bother to get list of doctypes - user will be prompted to confirm the deletion of "doctype"
alldoctypes = None
else:
## get list of all doctypes to pass to template so that it can prompt the user to choose a doctype to delete
## alldoctypes = get_docid_docname_alldoctypes()
alldoctypes = get_docid_docname_and_docid_alldoctypes()
body = websubmitadmin_templates.tmpl_display_delete_doctype_form(doctype=doctype, alldoctypes=alldoctypes)
return (title, body, errors, warnings)
def _create_add_doctype_form(doctype="", doctypename="", doctypedescr="", clonefrom="", user_msg=""):
"""Perform the steps necessary to create the "add a new doctype" form.
@param doctype: The unique ID that is to be used for the new doctype.
@param doctypename: the name that is to be given to a doctype.
@param doctypedescr: the description to be allocated to the new doctype.
@param user_msg: any message to be displayed to the user.
@return: a tuple containing page title and HTML body of page: (title, body)
"""
title = """Add New WebSubmit Document Type"""
alldoctypes = get_docid_docname_and_docid_alldoctypes()
body = websubmitadmin_templates.tmpl_display_doctypedetails_form(doctype=doctype,
doctypename=doctypename,
doctypedescr=doctypedescr,
clonefrom=clonefrom,
alldoctypes=alldoctypes,
user_msg=user_msg
)
return (title, body)
def _clone_categories_doctype(errors, warnings, user_msg, fromdoctype, todoctype):
"""Clone the categories of one document type, to another document type.
@param errors: a list of errors encountered while cloning categories
@param warnings: a list of warnings encountered while cloning categories
@param user_msg: any message to be displayed to the user (this is a list)
@param fromdoctype: the doctype from which categories are to be cloned
@param todoctype: the doctype into which categories are to be cloned
@return: integer value (0/1/2) - if doctype's categories couldn't be deleted, return 0 (cloning failed);
if some categories could be cloned, return 1 (cloning partially successful); if all categories could be
cloned, return 2 (cloning successful).
"""
error_code = clone_categories_fromdoctype_todoctype(fromdoctype=fromdoctype, todoctype=todoctype)
if error_code == 1:
## doctype had existing categories and they could not be deleted
## TODO : LOG ERRORS
user_msg.append("""Categories already existed for the document type "%s" but could not be deleted. Unable to clone""" \
""" categories of doctype "%s".""" % (todoctype, fromdoctype))
return 1 ## cloning failed
elif error_code == 2:
## could not clone all categories for new doctype
## TODO : LOG ERRORS
user_msg.append("""Unable to clone all categories from doctype "%s", for doctype "%s".""" % (fromdoctype, todoctype))
return 2 ## cloning at least partially successful
else:
return 0 ## cloning successful
def _clone_functions_foraction_doctype(errors, warnings, user_msg, fromdoctype, todoctype, action):
"""Clone the functions of a given action of one document type, to the same action on another document type.
@param errors: a list of errors encountered while cloning functions
@param warnings: a list of warnings encountered while cloning functions
@param user_msg: any message to be displayed to the user (this is a list)
@param fromdoctype: the doctype from which functions are to be cloned
@param todoctype: the doctype into which functions are to be cloned
@param action: the action for which functions are to be cloned
@return: an integer value (0/1/2). In the case that todoctype had existing functions for the given action and
they could not be deleted return 0, signalling that this is a serious problem; in the case that some
functions were cloned, return 1; in the case that all functions were cloned, return 2.
"""
error_code = clone_functions_foraction_fromdoctype_todoctype(fromdoctype=fromdoctype, todoctype=todoctype, action=action)
if error_code == 1:
## doctype had existing functions for the given action and they could not be deleted
## TODO : LOG ERRORS
user_msg.append("""Functions already existed for the "%s" action of the document type "%s" but they could not be """ \
"""deleted. Unable to clone the functions of Document Type "%s" for action "%s".""" \
% (action, todoctype, fromdoctype, action))
## critical - return 1 to signal this
return 1
elif error_code == 2:
## could not clone all functions for given action for new doctype
## TODO : LOG ERRORS
user_msg.append("""Unable to clone all functions for the "%s" action from doctype "%s", for doctype "%s".""" \
% (action, fromdoctype, todoctype))
return 2 ## not critical
else:
return 0 ## total success
def _clone_functionparameters_foraction_fromdoctype_todoctype(errors, warnings, user_msg, fromdoctype, todoctype, action):
"""Clone the parameters/values of a given action of one document type, to the same action on another document type.
@param errors: a list of errors encountered while cloning parameters
@param warnings: a list of warnings encountered while cloning parameters
@param user_msg: any message to be displayed to the user (this is a list)
@param fromdoctype: the doctype from which parameters are to be cloned
@param todoctype: the doctype into which parameters are to be cloned
@param action: the action for which parameters are to be cloned
@return: 0 if it was not possible to clone all parameters/values; 1 if all parameters/values were cloned successfully.
"""
error_code = clone_functionparameters_foraction_fromdoctype_todoctype(fromdoctype=fromdoctype, \
todoctype=todoctype, action=action)
if error_code in (1, 2):
## something went wrong and it was not possible to clone all parameters/values of "action"/"fromdoctype" for "action"/"todoctype"
## TODO : LOG ERRORS
user_msg.append("""It was not possible to clone all parameter values from the action "%(act)s" of the document type""" \
""" "%(fromdt)s" for the action "%(act)s" of the document type "%(todt)s".""" \
% { 'act' : action, 'fromdt' : fromdoctype, 'todt' : todoctype }
)
return 2 ## to signal that addition wasn't 100% successful
else:
return 0 ## all parameters were cloned
def _add_doctype(errors, warnings, doctype, doctypename, doctypedescr, clonefrom):
title = ""
body = ""
user_msg = []
commit_error = 0
if doctype == "":
user_msg.append("""The Document Type ID is mandatory and must be a string with no more than 10 alpha-numeric characters""")
commit_error = 1
if commit_error != 0:
## don't commit - just re-display page with message to user
(title, body) = _create_add_doctype_form(doctypename=doctypename, doctypedescr=doctypedescr, clonefrom=clonefrom, user_msg=user_msg)
return (title, body)
numrows_doctype = get_number_doctypes_docid(docid=doctype)
if numrows_doctype > 0:
## this document type already exists - do not add
## TODO : LOG ERROR
user_msg.append("""A document type identified by "%s" already seems to exist and there cannot be added. Choose another ID.""" \
% (doctype,))
(title, body) = _create_add_doctype_form(doctypename=doctypename, doctypedescr=doctypedescr, clonefrom=clonefrom, user_msg=user_msg)
else:
## proceed with addition
## add the document type details:
error_code = insert_doctype_details(doctype=doctype, doctypename=doctypename, doctypedescr=doctypedescr)
if error_code == 0:
## added successfully
if clonefrom not in ("", "None", None):
## document type should be cloned from "clonefrom"
## first, clone the categories from another doctype:
error_code = _clone_categories_doctype(errors=errors,
warnings=warnings,
user_msg=user_msg,
fromdoctype=clonefrom,
todoctype=doctype)
## get details of clonefrom's submissions
all_actnames_submissions_clonefrom = get_actname_all_submissions_doctype(doctype=clonefrom)
if len(all_actnames_submissions_clonefrom) > 0:
## begin cloning
for doc_submission_actname in all_actnames_submissions_clonefrom:
## clone submission details:
action_name = doc_submission_actname[0]
_clone_submission_fromdoctype_todoctype(errors=errors, warnings=errors, user_msg=user_msg,
todoctype=doctype, action=action_name, clonefrom=clonefrom)
user_msg.append("""The "%s" document type has been added.""" % (doctype,))
title = """Available WebSubmit Document Types"""
all_doctypes = get_docid_docname_alldoctypes()
body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg)
else:
## could not add document type details - do no more
## TODO : LOG ERROR!
user_msg.append("""Unable to add details for document type "%s".""" % (doctype,))
(title, body) = _create_add_doctype_form(user_msg=user_msg)
return (title, body)
def perform_request_add_doctype(doctype=None, doctypename=None, doctypedescr=None, clonefrom=None, doctypedetailscommit=""):
errors = []
warnings = []
body = ""
## wash args:
if doctype is not None:
try:
doctype = wash_single_urlarg(urlarg=doctype, argreqdtype=str, argdefault="", maxstrlen=10, minstrlen=1)
if string_is_alphanumeric_including_underscore(txtstring=doctype) == 0:
doctype = ""
except ValueError, e:
doctype = ""
else:
doctype = ""
if doctypename is not None:
try:
doctypename = wash_single_urlarg(urlarg=doctypename, argreqdtype=str, argdefault="")
except ValueError, e:
doctypename = ""
else:
doctypename = ""
if doctypedescr is not None:
try:
doctypedescr = wash_single_urlarg(urlarg=doctypedescr, argreqdtype=str, argdefault="")
except ValueError, e:
doctypedescr = ""
else:
doctypedescr = ""
if clonefrom is not None:
try:
clonefrom = wash_single_urlarg(urlarg=clonefrom, argreqdtype=str, argdefault="None")
except ValueError, e:
clonefrom = "None"
else:
clonefrom = "None"
if doctypedetailscommit not in ("", None):
(title, body) = _add_doctype(errors=errors, warnings=warnings, doctype=doctype,
doctypename=doctypename, doctypedescr=doctypedescr, clonefrom=clonefrom)
else:
(title, body) = _create_add_doctype_form()
return (title, body, errors, warnings)
def _delete_referee_doctype(errors, warnings, doctype, categid, refereeid):
"""Delete a referee from a given category of a document type.
@param doctype: the document type from whose category the referee is to be removed
@param categid: the name/ID of the category from which the referee is to be removed
@param refereeid: the id of the referee to be removed from the given category
@return: a tuple containing 2 strings: (page title, page body)
"""
user_msg = []
role_name = """referee_%s_%s""" % (doctype, categid)
- error_code = acc_deleteUserRole(id_user=refereeid, name_roll=role_name)
+ error_code = acc_delete_user_role(id_user=refereeid, name_roll=role_name)
if error_code > 0:
## referee was deleted from category
user_msg.append(""" "%s".""" % (doctype,))
def _create_list_referees_doctype(doctype):
referees = {}
referees_details = {}
## get all CDS Invenio roles:
- all_roles = acc_getAllRoles()
+ all_roles = acc_get_all_roles()
for role in all_roles:
(roleid, rolename) = (role[0], role[1])
if re.match("^referee_%s_" % (doctype,), rolename):
## this is a "referee" role - get users of this role:
- role_users = acc_getRoleUsers(roleid)
+ role_users = acc_get_role_users(roleid)
if role_users is not None and (type(role_users) in (tuple, list) and len(role_users) > 0):
## this role has users, record them in dictionary:
referees[rolename] = role_users
## for each "group" of referees:
for ref_role in referees.keys():
## get category ID for this referee-role:
try:
categid = re.match("^referee_%s_(.*)" % (doctype,), ref_role).group(1)
## from WebSubmit DB, get categ name for "categid":
if categid != "*":
categ_details = get_all_categories_sname_lname_for_doctype_categsname(doctype=doctype, categsname=categid)
if len(categ_details) > 0:
## if possible to receive details of this category, record them in a tuple in the format:
## ("categ name", (tuple of users details)):
referees_details[ref_role] = (categid, categ_details[0][1], referees[ref_role])
else:
## general referee entry:
referees_details[ref_role] = (categid, "General Referee(s)", referees[ref_role])
except AttributeError:
## there is no category for this role - it is broken, so pass it
pass
return referees_details
def _create_edit_doctype_details_form(errors, warnings, doctype, doctypename="", doctypedescr="", doctypedetailscommit="", user_msg=""):
if user_msg == "" or type(user_msg) not in (list, tuple, str, unicode):
user_msg = []
elif type(user_msg) in (str, unicode):
user_msg = [user_msg]
title = "Edit Document Type Details"
doctype_details = get_doctype_docname_descr_cd_md_fordoctype(doctype)
if len(doctype_details) == 1:
docname = doctype_details[0][1]
docdescr = doctype_details[0][2]
(cd, md) = (doctype_details[0][3], doctype_details[0][4])
if doctypedetailscommit != "":
## could not commit details
docname = doctypename
docdescr = doctypedescr
body = websubmitadmin_templates.tmpl_display_doctypedetails_form(doctype=doctype,
doctypename=docname,
doctypedescr=docdescr,
cd=cd,
md=md,
user_msg=user_msg,
perform_act="doctypeconfigure")
else:
## problem retrieving details of doctype:
user_msg.append("""Unable to retrieve details of doctype '%s' - cannot edit.""" % (doctype,),)
## TODO : LOG ERROR
all_doctypes = get_docid_docname_alldoctypes()
body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg)
title = "Available WebSubmit Document Types"
return (title, body)
def _create_add_submission_choose_clonefrom_form(errors, warnings, doctype, action, user_msg=""):
if user_msg == "" or type(user_msg) not in (list, tuple, str, unicode):
user_msg = []
elif type(user_msg) in (str, unicode):
user_msg = [user_msg]
if action in ("", None):
user_msg.append("""Unknown Submission""")
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body)
## does this doctype already have this action?
numrows_doctype_action = get_number_submissions_doctype_action(doctype=doctype, action=action)
if numrows_doctype_action < 1:
## action not present for this doctype - can be added
## get list of all doctypes implementing this action (for possible cloning purposes)
doctypes_implementing_action = get_doctypeid_doctypes_implementing_action(action=action)
## create form to display document types to clone from
title = "Add Submission '%s' to Document Type '%s'" % (action, doctype)
body = websubmitadmin_templates.tmpl_display_submission_clone_form(doctype=doctype,
action=action,
clonefrom_list=doctypes_implementing_action,
user_msg=user_msg
)
else:
## warn user that action already exists for doctype and canot be added, then display all
## details of doctype again
user_msg.append("The Document Type '%s' already implements the Submission '%s' - cannot add it again" \
% (doctype, action))
## TODO : LOG WARNING
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body)
def _create_add_submission_form(errors, warnings, doctype, action, displayed="", buttonorder="", statustext="",
level="", score="", stpage="", endtxt="", user_msg=""):
if user_msg == "" or type(user_msg) not in (list, tuple, str, unicode):
user_msg = []
elif type(user_msg) in (str, unicode):
user_msg = [user_msg]
if action in ("", None):
user_msg.append("""Unknown Submission""")
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body)
title = "Add Submission '%s' to Document Type '%s'" % (action, doctype)
body = websubmitadmin_templates.tmpl_display_submissiondetails_form(doctype=doctype,
action=action,
displayed=displayed,
buttonorder=buttonorder,
statustext=statustext,
level=level,
score=score,
stpage=stpage,
endtxt=endtxt,
user_msg=user_msg,
saveaction="add"
)
return (title, body)
def _create_delete_submission_form(errors, warnings, doctype, action):
user_msg = []
title = """Delete Submission "%s" from Document Type "%s" """ % (action, doctype)
numrows_doctypesubmission = get_number_submissions_doctype_action(doctype=doctype, action=action)
if numrows_doctypesubmission > 0:
## submission exists: create form to delete it:
body = websubmitadmin_templates.tmpl_display_delete_doctypesubmission_form(doctype=doctype, action=action)
else:
## submission doesn't seem to exist. Display details of doctype only:
user_msg.append("""The Submission "%s" doesn't seem to exist for the Document Type "%s" - unable to delete it""" % (action, doctype))
## TODO : LOG ERRORS
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body)
def _create_edit_submission_form(errors, warnings, doctype, action, user_msg=""):
if user_msg == "" or type(user_msg) not in (list, tuple, str, unicode):
user_msg = []
elif type(user_msg) in (str, unicode):
user_msg = [user_msg]
submission_details = get_submissiondetails_doctype_action(doctype=doctype, action=action)
numrows_submission_details = len(submission_details)
if numrows_submission_details == 1:
## correctly retrieved details of submission - display:
submission_details = stringify_listvars(submission_details)
displayed = submission_details[0][3]
buttonorder = submission_details[0][7]
statustext = submission_details[0][8]
level = submission_details[0][9]
score = submission_details[0][10]
stpage = submission_details[0][11]
endtxt = submission_details[0][12]
cd = submission_details[0][5]
md = submission_details[0][6]
title = "Edit Details of '%s' Submission of '%s' Document Type" % (action, doctype)
body = websubmitadmin_templates.tmpl_display_submissiondetails_form(doctype=doctype,
action=action,
displayed=displayed,
buttonorder=buttonorder,
statustext=statustext,
level=level,
score=score,
stpage=stpage,
endtxt=endtxt,
cd=cd,
md=md,
user_msg=user_msg
)
else:
if numrows_submission_details > 1:
## multiple rows for this submission - this is a key violation
user_msg.append("Found multiple rows for the Submission '%s' of the Document Type '%s'" \
% (action, doctype))
else:
## submission does not exist
user_msg.append("The Submission '%s' of the Document Type '%s' doesn't seem to exist." \
% (action, doctype))
## TODO : LOG ERROR
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body)
def _create_edit_category_form(errors, warnings, doctype, categid):
title = "Edit Category Description"
categ_details = get_all_categories_sname_lname_for_doctype_categsname(doctype=doctype, categsname=categid)
if len(categ_details) == 1:
## disaply details
retrieved_categid=categ_details[0][0]
retrieved_categdescr=categ_details[0][1]
body = websubmitadmin_templates.tmpl_display_edit_category_form(doctype=doctype,
categid=retrieved_categid,
categdescr=retrieved_categdescr
)
else:
## problem retrieving details of categ
user_msg = """Unable to retrieve details of category '%s'""" % (categid,)
## TODO : LOG ERRORS
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body)
def _create_configure_doctype_form(doctype, jumpcategout="", user_msg=""):
title = "Configure Document Type"
body = ""
if user_msg == "" or type(user_msg) not in (list, tuple, str, unicode):
user_msg = []
## get details of doctype:
doctype_details = get_doctype_docname_descr_cd_md_fordoctype(doctype)
docname = doctype_details[0][1]
docdescr = doctype_details[0][2]
(cd, md) = (doctype_details[0][3], doctype_details[0][4])
## get categories for doctype:
doctype_categs = get_all_category_details_for_doctype(doctype=doctype)
## get submissions for doctype:
doctype_submissions = get_submissiondetails_all_submissions_doctype(doctype=doctype)
## get list of actions that this doctype doesn't have:
unlinked_actions = get_actions_sname_lname_not_linked_to_doctype(doctype=doctype)
## get referees for doctype:
referees_dets = _create_list_referees_doctype(doctype=doctype)
body = websubmitadmin_templates.tmpl_configure_doctype_overview(doctype=doctype, doctypename=docname,
doctypedescr=docdescr, doctype_cdate=cd,
doctype_mdate=md, doctype_categories=doctype_categs,
jumpcategout=jumpcategout,
doctype_submissions=doctype_submissions,
doctype_referees=referees_dets,
add_actions_list=unlinked_actions,
user_msg=user_msg)
return (title, body)
def _clone_submission_fromdoctype_todoctype(errors, warnings, user_msg, todoctype, action, clonefrom):
## first, delete the submission from todoctype (if it exists):
error_code = delete_submissiondetails_doctype(doctype=todoctype, action=action)
if error_code == 0:
## could be deleted - now clone it
error_code = insert_submission_details_clonefrom_submission(addtodoctype=todoctype, action=action, clonefromdoctype=clonefrom)
if error_code == 0:
## submission inserted
## now clone functions:
error_code = _clone_functions_foraction_doctype(errors=errors, warnings=warnings, user_msg=user_msg, \
fromdoctype=clonefrom, todoctype=todoctype, action=action)
if error_code in (0, 2):
## no serious error - clone parameters:
error_code = _clone_functionparameters_foraction_fromdoctype_todoctype(errors=errors,
warnings=warnings,
user_msg=user_msg,
fromdoctype=clonefrom,
todoctype=todoctype,
action=action)
## now clone pages/elements
error_code = clone_submissionfields_from_doctypesubmission_to_doctypesubmission(fromsub="%s%s" % (action, clonefrom),
tosub="%s%s" % (action, todoctype))
if error_code == 1:
## could not delete all existing submission fields and therefore could no clone submission fields at all
## TODO : LOG ERROR
user_msg.append("""Unable to delete existing submission fields for Submission "%s" of Document Type "%s" - """ \
"""cannot clone submission fields!""" % (action, todoctype))
elif error_code == 2:
## could not clone all fields
## TODO : LOG ERROR
user_msg.append("""Unable to clone all submission fields for submission "%s" on Document Type "%s" from Document""" \
""" Type "%s" """ % (action, todoctype, clonefrom))
else:
## could not insert submission details!
user_msg.append("""Unable to successfully insert details of submission "%s" into Document Type "%s" - cannot clone from "%s" """ \
% (action, todoctype, clonefrom))
## TODO : LOG ERROR
else:
## could not delete details of existing submission (action) from 'todoctype' - cannot clone it as new
user_msg.append("""Unable to delete details of existing Submission "%s" from Document Type "%s" - cannot clone it from "%s" """ \
% (action, todoctype, clonefrom))
## TODO : LOG ERROR
def _add_submission_to_doctype_clone(errors, warnings, doctype, action, clonefrom):
user_msg = []
if action in ("", None) or clonefrom in ("", None):
user_msg.append("Unknown action or document type to clone from - cannot add submission")
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body)
## does action exist?
numrows_action = get_number_actions_with_actid(actid=action)
if numrows_action > 0:
## The action exists, but is it already implemented as a submission by doctype?
numrows_submission_doctype = get_number_submissions_doctype_action(doctype=doctype, action=action)
if numrows_submission_doctype > 0:
## this submission already exists for this document type - unable to add it again
user_msg.append("""The Submission "%s" already exists for Document Type "%s" - cannot add it again""" \
%(action, doctype))
## TODO : LOG ERROR
else:
## clone the submission
_clone_submission_fromdoctype_todoctype(errors=errors, warnings=errors, user_msg=user_msg,
todoctype=doctype, action=action, clonefrom=clonefrom)
user_msg.append("""Cloning of Submission "%s" from Document Type "%s" has been carried out. You should not""" \
""" ignore any warnings that you may have seen.""" % (action, clonefrom))
## TODO : LOG WARNING OF NEW SUBMISSION CREATION BY CLONING
else:
## this action doesn't exist! cannot add a submission based upon it!
user_msg.append("The Action '%s' does not seem to exist in WebSubmit. Cannot add it as a Submission!" \
% (action))
## TODO : LOG ERROR
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body)
def _add_submission_to_doctype(errors, warnings, doctype, action, displayed, buttonorder,
statustext, level, score, stpage, endtxt):
user_msg = []
## does "action" exist?
numrows_action = get_number_actions_with_actid(actid=action)
if numrows_action < 1:
## this action does not exist! Can't add a submission based upon it!
user_msg.append("'%s' does not exist in WebSubmit as an Action! Unable to add this submission."\
% (action,))
## TODO : LOG ERROR
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body)
## Insert the new submission
error_code = insert_submission_details(doctype=doctype, action=action, displayed=displayed,
nbpg="0", buttonorder=buttonorder, statustext=statustext,
level=level, score=score, stpage=stpage, endtext=endtxt)
if error_code == 0:
## successful insert
user_msg.append("""'%s' Submission Successfully Added to Document Type '%s'""" % (action, doctype))
else:
## could not insert submission into doctype
user_msg.append("""Unable to Add '%s' Submission to '%s' Document Type""" % (action, doctype))
## TODO : LOG ERROR
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body)
def _delete_submission_from_doctype(errors, warnings, doctype, action):
"""Delete a submission (action) from the document type identified by "doctype".
@param errors: a list of errors encountered while deleting the submission
@param warnings: a list of warnings encountered while deleting the submission
@param doctype: the unique ID of the document type from which the submission is to be deleted
@param categid: the action ID of the submission to be deleted from doctype
@return: a tuple containing 2 strings: (page title, page body)
"""
user_msg = []
if action in ("", None):
user_msg.append("Unknown action - cannot delete submission")
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body)
## delete fields for this submission:
error_code = delete_all_submissionfields_submission("""%s%s""" % (action, doctype) )
if error_code != 0:
## could not successfully delete all fields - report error
user_msg.append("""When deleting Submission "%s" from Document Type "%s", it wasn't possible to delete all Submission Fields""" \
% (action, doctype))
## TODO : LOG ERROR
## delete parameters for this submission:
error_code = delete_functionparameters_doctype_submission(doctype=doctype, action=action)
if error_code != 0:
## could not successfully delete all functions - report error
user_msg.append("""When deleting Submission "%s" from Document Type "%s", it wasn't possible to delete all Function Parameters""" \
% (action, doctype))
## TODO : LOG ERROR
## delete functions for this submission:
error_code = delete_all_functions_foraction_doctype(doctype=doctype, action=action)
if error_code != 0:
## could not successfully delete all functions - report error
user_msg.append("""When deleting Submission "%s" from Document Type "%s", it wasn't possible to delete all Functions""" \
% (action, doctype))
## TODO : LOG ERROR
## delete this submission itself:
error_code = delete_submissiondetails_doctype(doctype=doctype, action=action)
if error_code == 0:
## successful delete
user_msg.append("""The "%s" Submission has been deleted from the "%s" Document Type""" % (action, doctype))
else:
## could not delete category
user_msg.append("""Unable to successfully delete the "%s" Submission from the "%s" Document Type""" % (action, doctype))
## TODO : LOG ERROR
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body)
def _edit_submission_for_doctype(errors, warnings, doctype, action, displayed, buttonorder,
statustext, level, score, stpage, endtxt):
"""Update the details of a given submission belonging to the document type identified by "doctype".
@param errors: a list of errors encountered while updating the submission's details
@param warnings: a list of warnings encountered while updating the submission's details
@param doctype: the unique ID of the document type for which the submission is to be updated
@param action: action name of the submission to be updated
@param displayed: displayed on main submission page? (Y/N)
@param buttonorder: button order
@param statustext: statustext
@param level: level
@param score: score
@param stpage: stpage
@param endtxt: endtxt
@return: a tuple of 2 strings: (page title, page body)
"""
user_msg = []
commit_error = 0
if action in ("", None):
user_msg.append("Unknown Action - cannot update submission")
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body)
error_code = update_submissiondetails_doctype_action(doctype=doctype, action=action, displayed=displayed,
buttonorder=buttonorder, statustext=statustext, level=level,
score=score, stpage=stpage, endtxt=endtxt)
if error_code == 0:
## successful update
user_msg.append("'%s' Submission of '%s' Document Type updated." % (action, doctype) )
else:
## could not update
user_msg.append("Unable to update '%s' Submission of '%s' Document Type." % (action, doctype) )
## TODO : LOG ERROR
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body)
def _edit_doctype_details(errors, warnings, doctype, doctypename, doctypedescr):
"""Update the details (name and/or description) of a document type (identified by doctype.)
@param errors: a list of errors encountered while updating the doctype's details
@param warnings: a list of warnings encountered while updating the doctype's details
@param doctype: the unique ID of the document type to be updated
@param doctypename: the new/updated name for the doctype
@param doctypedescr: the new/updated description for the doctype
@return: a tuple containing 2 strings: (page title, page body)
"""
user_msg = []
error_code = update_doctype_details(doctype=doctype, doctypename=doctypename, doctypedescr=doctypedescr)
if error_code == 0:
## successful update
user_msg.append("""'%s' Document Type Updated""" % (doctype,))
else:
## could not update
user_msg.append("""Unable to Update Doctype '%s'""" % (doctype,))
## TODO : LOG ERROR
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body)
def _edit_category_for_doctype(errors, warnings, doctype, categid, categdescr):
"""Edit the description of a given category (identified by categid), belonging to
the document type identified by doctype.
@param errors: a list of errors encountered while modifying the category
@param warnings: a list of warnings encountered while modifying the category
@param doctype: the unique ID of the document type for which the category is to be modified
@param categid: the unique category ID of the category to be modified
@param categdescr: the new description for the category
@return: at tuple containing 2 strings: (page title, page body)
"""
user_msg = []
if categid in ("", None) or categdescr in ("", None):
## cannot edit unknown category!
user_msg.append("Category ID and Description are both mandatory")
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body)
error_code = update_category_description_doctype_categ(doctype=doctype, categ=categid, categdescr=categdescr)
if error_code == 0:
## successful update
user_msg.append("""'%s' Category Description Successfully Updated""" % (categid,))
else:
## could not update category description
user_msg.append("""Unable to Description for Category '%s'""" % (categid,))
## TODO : LOG ERROR
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body)
def _add_category_to_doctype(errors, warnings, doctype, categid, categdescr):
"""Add a new category to the document type identified by "doctype".
Category ID, and category description are both mandatory.
@param errors: a list of errors encountered while adding the category
@param warnings: a list of warnings encountered while adding the category
@param doctype: the unique ID of the document type to which the category is to be added
@param categid: the unique category ID of the category to be added to doctype
@param categdescr: the description of the category to be added
@return: at tuple containing 2 strings: (page title, page body)
"""
user_msg = []
if categid in ("", None) or categdescr in ("", None):
## cannot add unknown category!
user_msg.append("Category ID and Description are both mandatory")
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body)
error_code = insert_category_into_doctype(doctype=doctype, categ=categid, categdescr=categdescr)
if error_code == 0:
## successful insert
user_msg.append("""'%s' Category Successfully Added""" % (categid,))
else:
## could not insert category into doctype
user_msg.append("""Unable to Add '%s' Category""" % (categid,))
## TODO : LOG ERROR
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body)
def _delete_category_from_doctype(errors, warnings, doctype, categid):
"""Delete a category (categid) from the document type identified by "doctype".
@param errors: a list of errors encountered while deleting the category
@param warnings: a list of warnings encountered while deleting the category
@param doctype: the unique ID of the document type from which the category is to be deleted
@param categid: the unique category ID of the category to be deleted from doctype
@return: a tuple containing 2 strings: (page title, page body)
"""
user_msg = []
if categid in ("", None):
## cannot delete unknown category!
user_msg.append("Category ID is mandatory")
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body)
error_code = delete_category_doctype(doctype=doctype, categ=categid)
if error_code == 0:
## successful delete
user_msg.append("""'%s' Category Successfully Deleted""" % (categid,))
else:
## could not delete category
user_msg.append("""Unable to Delete '%s' Category""" % (categid,))
## TODO : LOG ERROR
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body)
def _jump_category_to_new_score(errors, warnings, doctype, jumpcategout, jumpcategin):
user_msg = []
if jumpcategout in ("", None) or jumpcategin in ("", None):
## need both jumpcategout and jumpcategin to move a category:
user_msg.append("Unable to move category - unknown source and/or destination score(s)")
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body)
## FIXME TODO:
error_code = move_category_to_new_score(doctype, jumpcategout, jumpcategin)
if error_code == 0:
## successful jump of category
user_msg.append("""Successfully Moved [%s] Category""" % (jumpcategout,))
else:
## could not delete category
user_msg.append("""Unable to Move [%s] Category""" % (jumpcategout,))
## TODO : LOG ERROR
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body)
def _move_category(errors, warnings, doctype, categid, movecategup=""):
user_msg = []
if categid in ("", None):
## cannot move unknown category!
user_msg.append("Cannot move an unknown category - category ID is mandatory")
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body)
if movecategup not in ("", None):
## move the category up in score:
error_code = move_category_by_one_place_in_score(doctype=doctype,
categsname=categid,
direction="up")
else:
## move the category down in score:
error_code = move_category_by_one_place_in_score(doctype=doctype,
categsname=categid,
direction="down")
if error_code == 0:
## successful move of category
user_msg.append("""[%s] Category Successfully Moved""" % (categid,))
else:
## could not delete category
user_msg.append("""Unable to Move [%s] Category""" % (categid,))
## TODO : LOG ERROR
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body)
def perform_request_configure_doctype(doctype,
doctypename=None,
doctypedescr=None,
doctypedetailsedit="",
doctypedetailscommit="",
doctypecategoryadd="",
doctypecategoryedit="",
doctypecategoryeditcommit="",
doctypecategorydelete="",
doctypesubmissionadd="",
doctypesubmissiondelete="",
doctypesubmissiondeleteconfirm="",
doctypesubmissionedit="",
doctypesubmissionaddclonechosen="",
doctypesubmissionadddetailscommit="",
doctypesubmissioneditdetailscommit="",
categid=None,
categdescr=None,
movecategup=None,
movecategdown=None,
jumpcategout=None,
jumpcategin=None,
action=None,
doctype_cloneactionfrom=None,
displayed=None,
buttonorder=None,
statustext=None,
level=None,
score=None,
stpage=None,
endtxt=None
):
user_msg = []
errors = []
warnings = []
body = ""
if doctype is not None:
try:
doctype = wash_single_urlarg(urlarg=doctype, argreqdtype=str, argdefault="", maxstrlen=10, minstrlen=1)
if string_is_alphanumeric_including_underscore(txtstring=doctype) == 0:
doctype = ""
except ValueError, e:
doctype = ""
else:
doctype = ""
if action is not None:
try:
action = wash_single_urlarg(urlarg=action, argreqdtype=str, argdefault="", maxstrlen=3, minstrlen=1)
if string_is_alphanumeric_including_underscore(txtstring=action) == 0:
action = ""
except ValueError, e:
action = ""
else:
action = ""
if doctypename is not None:
try:
doctypename = wash_single_urlarg(urlarg=doctypename, argreqdtype=str, argdefault="")
except ValueError, e:
doctypename = ""
else:
doctypename = ""
if doctypedescr is not None:
try:
doctypedescr = wash_single_urlarg(urlarg=doctypedescr, argreqdtype=str, argdefault="")
except ValueError, e:
doctypedescr = ""
else:
doctypedescr = ""
if categid is not None:
try:
categid = wash_single_urlarg(urlarg=categid, argreqdtype=str, argdefault="")
except ValueError, e:
categid = ""
else:
categid = ""
if categdescr is not None:
try:
categdescr = wash_single_urlarg(urlarg=categdescr, argreqdtype=str, argdefault="")
except ValueError, e:
categdescr = ""
else:
categdescr = ""
if doctype_cloneactionfrom is not None:
try:
doctype_cloneactionfrom = wash_single_urlarg(urlarg=doctype_cloneactionfrom, argreqdtype=str, argdefault="", maxstrlen=10, minstrlen=1)
if string_is_alphanumeric_including_underscore(txtstring=doctype_cloneactionfrom) == 0:
doctype_cloneactionfrom = ""
except ValueError, e:
doctype_cloneactionfrom = ""
else:
doctype_cloneactionfrom = ""
if displayed is not None:
try:
displayed = wash_single_urlarg(urlarg=displayed, argreqdtype=str, argdefault="Y", maxstrlen=1, minstrlen=1)
except ValueError, e:
displayed = "Y"
else:
displayed = "Y"
if buttonorder is not None:
try:
buttonorder = wash_single_urlarg(urlarg=buttonorder, argreqdtype=int, argdefault="")
except ValueError, e:
buttonorder = ""
else:
buttonorder = ""
if level is not None:
try:
level = wash_single_urlarg(urlarg=level, argreqdtype=str, argdefault="", maxstrlen=1, minstrlen=1)
except ValueError, e:
level = ""
else:
level = ""
if score is not None:
try:
score = wash_single_urlarg(urlarg=score, argreqdtype=int, argdefault="")
except ValueError, e:
score = ""
else:
score = ""
if stpage is not None:
try:
stpage = wash_single_urlarg(urlarg=stpage, argreqdtype=int, argdefault="")
except ValueError, e:
stpage = ""
else:
stpage = ""
if statustext is not None:
try:
statustext = wash_single_urlarg(urlarg=statustext, argreqdtype=str, argdefault="")
except ValueError, e:
statustext = ""
else:
statustext = ""
if endtxt is not None:
try:
endtxt = wash_single_urlarg(urlarg=endtxt, argreqdtype=str, argdefault="")
except ValueError, e:
endtxt = ""
else:
endtxt = ""
## ensure that there is only one doctype for this doctype ID - simply display all doctypes with warning if not
numrows_doctype = get_number_doctypes_docid(docid=doctype)
if numrows_doctype > 1:
## there are multiple doctypes with this doctype ID:
## TODO : LOG ERROR
user_msg.append("""Multiple document types identified by "%s" exist - cannot configure at this time.""" \
% (doctype,))
all_doctypes = get_docid_docname_alldoctypes()
body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg)
title = "Available WebSubmit Document Types"
return (title, body, errors, warnings)
elif numrows_doctype == 0:
## this doctype does not seem to exist:
user_msg.append("""The document type identified by "%s" doesn't exist - cannot configure at this time.""" \
% (doctype,))
## TODO : LOG ERROR
all_doctypes = get_docid_docname_alldoctypes()
body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg)
title = "Available WebSubmit Document Types"
return (title, body, errors, warnings)
## since doctype ID is OK, process doctype configuration request:
if doctypedetailsedit not in ("", None):
(title, body) = _create_edit_doctype_details_form(errors=errors, warnings=warnings, doctype=doctype)
elif doctypedetailscommit not in ("", None):
## commit updated document type details
(title, body) = _edit_doctype_details(errors=errors, warnings=warnings, doctype=doctype,
doctypename=doctypename, doctypedescr=doctypedescr)
elif doctypecategoryadd not in ("", None):
## add new category:
(title, body) = _add_category_to_doctype(errors=errors, warnings=warnings,
doctype=doctype, categid=categid, categdescr=categdescr)
elif doctypecategoryedit not in ("", None):
## create form to update category description:
(title, body) = _create_edit_category_form(errors=errors, warnings=warnings, doctype=doctype,
categid=categid)
elif doctypecategoryeditcommit not in ("", None):
## commit updated category description:
(title, body) = _edit_category_for_doctype(errors=errors, warnings=warnings,
doctype=doctype, categid=categid, categdescr=categdescr)
elif doctypecategorydelete not in ("", None):
## delete a category
(title, body) = _delete_category_from_doctype(errors=errors, warnings=warnings,
doctype=doctype, categid=categid)
elif movecategup not in ("", None) or movecategdown not in ("", None):
## move a category up or down in score:
(title, body) = _move_category(errors=errors, warnings=warnings,
doctype=doctype, categid=categid,
movecategup=movecategup)
elif jumpcategout not in ("", None) and jumpcategin not in ("", None):
## jump a category from one score to another:
(title, body) = _jump_category_to_new_score(errors=errors, warnings=warnings,
doctype=doctype, jumpcategout=jumpcategout,
jumpcategin=jumpcategin)
elif doctypesubmissionadd not in ("", None):
## form displaying option of adding doctype:
(title, body) = _create_add_submission_choose_clonefrom_form(errors=errors, warnings=warnings, doctype=doctype, action=action)
elif doctypesubmissionaddclonechosen not in ("", None):
## add a submission. if there is a document type to be cloned from, then process clone;
## otherwise, present form with details of doctype
if doctype_cloneactionfrom in ("", None, "None"):
## no clone - present form into which details of new submission should be entered
(title, body) = _create_add_submission_form(errors=errors, warnings=warnings, doctype=doctype, action=action)
else:
## new submission should be cloned from doctype_cloneactionfrom
(title, body) = _add_submission_to_doctype_clone(errors=errors, warnings=warnings,
doctype=doctype, action=action, clonefrom=doctype_cloneactionfrom)
elif doctypesubmissiondelete not in ("", None):
## create form to prompt for confirmation of deletion of a submission:
(title, body) = _create_delete_submission_form(errors=errors, warnings=warnings, doctype=doctype, action=action)
elif doctypesubmissiondeleteconfirm not in ("", None):
## process the deletion of a submission from the doctype concerned:
(title, body) = _delete_submission_from_doctype(errors=errors, warnings=warnings,
doctype=doctype, action=action)
elif doctypesubmissionedit not in ("", None):
## create form to update details of a submission
(title, body) = _create_edit_submission_form(errors=errors, warnings=warnings, doctype=doctype, action=action)
elif doctypesubmissioneditdetailscommit not in ("", None):
## commit updated submission details:
(title, body) = _edit_submission_for_doctype(errors=errors, warnings=warnings, doctype=doctype, action=action,
displayed=displayed, buttonorder=buttonorder, statustext=statustext,
level=level, score=score, stpage=stpage, endtxt=endtxt)
elif doctypesubmissionadddetailscommit not in ("", None):
## commit new submission to doctype (not by cloning)
(title, body) = _add_submission_to_doctype(errors=errors, warnings=warnings, doctype=doctype, action=action,
displayed=displayed, buttonorder=buttonorder, statustext=statustext,
level=level, score=score, stpage=stpage, endtxt=endtxt)
else:
## default - display root of edit doctype
(title, body) = _create_configure_doctype_form(doctype=doctype, jumpcategout=jumpcategout)
return (title, body, errors, warnings)
def _create_configure_doctype_submission_functions_form(doctype,
action,
movefromfunctionname="",
movefromfunctionstep="",
movefromfunctionscore="",
user_msg=""):
title = """Functions of the "%s" Submission of the "%s" Document Type:""" % (action, doctype)
submission_functions = get_functionname_step_score_allfunctions_doctypesubmission(doctype=doctype, action=action)
body = websubmitadmin_templates.tmpl_configuredoctype_display_submissionfunctions(doctype=doctype,
action=action,
movefromfunctionname=movefromfunctionname,
movefromfunctionstep=movefromfunctionstep,
movefromfunctionscore=movefromfunctionscore,
submissionfunctions=submission_functions,
user_msg=user_msg)
return (title, body)
def _create_configure_doctype_submission_functions_add_function_form(doctype, action, addfunctionname="",
addfunctionstep="", addfunctionscore="", user_msg=""):
"""Create a form that allows a user to add a function a submission.
@param doctype: (string) the unique ID of a document type
@param action: (string) the unique ID of an action
@param addfunctionname: (string) the name of the function to be added to the submission (passed in case of page refresh)
@param addfunctionstep: (integer) the step of the submission into which the function is to be added (passed in case of
page refresh)
@param addfunctionscore: (integer) the score at at which the function is to be added (passed in case of page refresh)
@param user_msg: (string or list of strings) any message(s) to be displayed to the user
@return: (tuple) containing 2 strings - (page-title, HTML page-body)
"""
title = """Add a function to the [%s] submission of the [%s] document type""" % (action, doctype)
submission_functions = get_functionname_step_score_allfunctions_doctypesubmission(doctype=doctype, action=action)
## get names of all WebSubmit functions:
all_websubmit_functions = get_names_of_all_functions()
## put names into a list of single-element tuples, so that template can make HTML select list with them:
all_websubmit_functions = map(lambda x: (str(x),), all_websubmit_functions)
## create page body:
body = websubmitadmin_templates.tmpl_configuredoctype_add_submissionfunction(doctype=doctype,
action=action,
cursubmissionfunctions=submission_functions,
allWSfunctions=all_websubmit_functions,
addfunctionname=addfunctionname,
addfunctionstep=addfunctionstep,
addfunctionscore=addfunctionscore,
user_msg=user_msg)
return (title, body)
def _create_configure_doctype_submission_functions_list_parameters_form(doctype,
action,
functionname,
user_msg=""):
title = """Parameters of the %s function, as used in the %s document type"""\
% (functionname, doctype)
funcparams = get_function_parameters(function=functionname)
if len(funcparams) > 0:
## get the values
paramslist = map(lambda x: str(x[0]), funcparams)
params = get_function_parameter_vals_doctype(doctype=doctype, paramlist=paramslist)
else:
params = ()
## params = get_parameters_name_and_value_for_function_of_doctype(doctype=doctype, function=functionname)
body = websubmitadmin_templates.tmpl_configuredoctype_list_functionparameters(doctype=doctype,
action=action,
function=functionname,
params=params,
user_msg=user_msg)
return (title, body)
def _update_submission_function_parameter_file(doctype, action, functionname,
paramname, paramfilecontent):
user_msg = []
## get the filename:
paramval_res = get_value_of_parameter_for_doctype(doctype=doctype, parameter=paramname)
if paramval_res is None:
## this parameter doesn't exist for this doctype!
user_msg.append("The parameter [%s] doesn't exist for the document type [%s]!" % (paramname, doctype))
(title, body) = _create_configure_doctype_submission_functions_list_parameters_form(doctype=doctype,
action=action,
functionname=functionname,
user_msg=user_msg)
return (title, body)
paramval = str(paramval_res)
filename = basename(paramval)
if filename == "":
## invalid filename
user_msg.append("[%s] is an invalid filename - cannot save details" % (paramval,))
(title, body) = _create_configure_doctype_submission_functions_list_parameters_form(doctype=doctype,
action=action,
functionname=functionname,
user_msg=user_msg)
return (title, body)
## save file:
try:
save_update_to_file(filepath="%s/%s" % (bibconvertconf, filename), filecontent=paramfilecontent)
except InvenioWebSubmitAdminWarningIOError, e:
## could not correctly update the file!
user_msg.append(str(e))
(title, body) = _create_configure_doctype_submission_functions_list_parameters_form(doctype=doctype,
action=action,
functionname=functionname,
user_msg=user_msg)
return (title, body)
## redisplay form
user_msg.append("""[%s] file updated""" % (filename,))
(title, body) = _create_configure_doctype_submission_functions_edit_parameter_file_form(doctype=doctype,
action=action,
functionname=functionname,
paramname=paramname,
user_msg=user_msg)
return (title, body)
def _create_configure_doctype_submission_functions_edit_parameter_file_form(doctype,
action,
functionname,
paramname,
user_msg=""):
if type(user_msg) is not list:
user_msg = []
paramval_res = get_value_of_parameter_for_doctype(doctype=doctype, parameter=paramname)
if paramval_res is None:
## this parameter doesn't exist for this doctype!
user_msg.append("The parameter [%s] doesn't exist for the document type [%s]!" % (paramname, doctype))
(title, body) = _create_configure_doctype_submission_functions_list_parameters_form(doctype=doctype,
action=action,
functionname=functionname)
return (title, body)
paramval = str(paramval_res)
title = "Edit the [%s] file for the [%s] document type" % (paramval, doctype)
## get basename of file:
filecontent = ""
filename = basename(paramval)
if filename == "":
## invalid filename
user_msg.append("[%s] is an invalid filename" % (paramval,))
(title, body) = _create_configure_doctype_submission_functions_list_parameters_form(doctype=doctype,
action=action,
functionname=functionname,
user_msg=user_msg)
return (title, body)
## try to read file contents:
if access("%s/%s" % (bibconvertconf, filename), F_OK):
## file exists
if access("%s/%s" % (bibconvertconf, filename), R_OK) and \
isfile("%s/%s" % (bibconvertconf, filename)):
## file is a regular file and is readable - get contents
filecontent = open("%s/%s" % (bibconvertconf, filename), "r").read()
else:
if not isfile("%s/%s" % (bibconvertconf, filename)):
## file is not a regular file
user_msg.append("The parameter file [%s] is not regular file - unable to read" % (filename,))
else:
## file is not readable - error message
user_msg.append("The parameter file [%s] could not be read - check permissions" % (filename,))
## display page listing the parameters of this function:
(title, body) = _create_configure_doctype_submission_functions_list_parameters_form(doctype=doctype,
action=action,
functionname=functionname,
user_msg=user_msg)
return (title, body)
else:
## file does not exist:
user_msg.append("The parameter file [%s] does not exist - it will be created" % (filename,))
## make page body:
body = websubmitadmin_templates.tmpl_configuredoctype_edit_functionparameter_file(doctype=doctype,
action=action,
function=functionname,
paramname=paramname,
paramfilename=filename,
paramfilecontent=filecontent,
user_msg=user_msg)
return (title, body)
def _create_configure_doctype_submission_functions_edit_parameter_value_form(doctype,
action,
functionname,
paramname,
paramval="",
user_msg=""):
title = """Edit the value of the [%s] Parameter""" % (paramname,)
## get the parameter's value from the DB:
paramval_res = get_value_of_parameter_for_doctype(doctype=doctype, parameter=paramname)
if paramval_res is None:
## this parameter doesn't exist for this doctype!
(title, body) = _create_configure_doctype_submission_functions_list_parameters_form(doctype=doctype,
action=action,
functionname=functionname)
if paramval == "":
## use whatever retrieved paramval_res contains:
paramval = str(paramval_res)
body = websubmitadmin_templates.tmpl_configuredoctype_edit_functionparameter_value(doctype=doctype,
action=action,
function=functionname,
paramname=paramname,
paramval=paramval)
return (title, body)
def _update_submissionfunction_parameter_value(doctype, action, functionname, paramname, paramval):
user_msg = []
try:
update_value_of_function_parameter_for_doctype(doctype=doctype, paramname=paramname, paramval=paramval)
user_msg.append("""The value of the parameter [%s] was updated for document type [%s]""" % (paramname, doctype))
except InvenioWebSubmitAdminWarningTooManyRows, e:
## multiple rows found for param - update not carried out
user_msg.append(str(e))
except InvenioWebSubmitAdminWarningNoRowsFound, e:
## no rows found - parameter does not exist for doctype, therefore no update
user_msg.append(str(e))
(title, body) = \
_create_configure_doctype_submission_functions_list_parameters_form(doctype=doctype, action=action,
functionname=functionname, user_msg=user_msg)
return (title, body)
def perform_request_configure_doctype_submissionfunctions_parameters(doctype,
action,
functionname,
functionstep,
functionscore,
paramname="",
paramval="",
editfunctionparametervalue="",
editfunctionparametervaluecommit="",
editfunctionparameterfile="",
editfunctionparameterfilecommit="",
paramfilename="",
paramfilecontent=""):
errors = []
warnings = []
body = ""
user_msg = []
## ensure that there is only one doctype for this doctype ID - simply display all doctypes with warning if not
if doctype in ("", None):
user_msg.append("""Unknown Document Type""")
## TODO : LOG ERROR
all_doctypes = get_docid_docname_alldoctypes()
body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg)
title = "Available WebSubmit Document Types"
return (title, body, errors, warnings)
numrows_doctype = get_number_doctypes_docid(docid=doctype)
if numrows_doctype > 1:
## there are multiple doctypes with this doctype ID:
## TODO : LOG ERROR
user_msg.append("""Multiple document types identified by "%s" exist - cannot configure at this time.""" \
% (doctype,))
all_doctypes = get_docid_docname_alldoctypes()
body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg)
title = "Available WebSubmit Document Types"
return (title, body, errors, warnings)
elif numrows_doctype == 0:
## this doctype does not seem to exist:
user_msg.append("""The document type identified by "%s" doesn't exist - cannot configure at this time.""" \
% (doctype,))
## TODO : LOG ERROR
all_doctypes = get_docid_docname_alldoctypes()
body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg)
title = "Available WebSubmit Document Types"
return (title, body, errors, warnings)
## ensure that this submission exists for this doctype:
numrows_submission = get_number_submissions_doctype_action(doctype=doctype, action=action)
if numrows_submission > 1:
## there are multiple submissions for this doctype/action ID:
## TODO : LOG ERROR
user_msg.append("""The Submission "%s" seems to exist multiple times for the Document Type "%s" - cannot configure at this time.""" \
% (action, doctype))
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body, errors, warnings)
elif numrows_submission == 0:
## this submission does not seem to exist for this doctype:
user_msg.append("""The Submission "%s" doesn't exist for the "%s" Document Type - cannot configure at this time.""" \
% (action, doctype))
## TODO : LOG ERROR
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body, errors, warnings)
if editfunctionparametervaluecommit not in ("", None):
## commit an update to a function parameter:
(title, body) = _update_submissionfunction_parameter_value(doctype=doctype, action=action, functionname=functionname,
paramname=paramname, paramval=paramval)
elif editfunctionparametervalue not in ("", None):
## display a form for editing the value of a parameter:
(title, body) = _create_configure_doctype_submission_functions_edit_parameter_value_form(doctype=doctype,
action=action,
functionname=functionname,
paramname=paramname,
paramval=paramval)
elif editfunctionparameterfile not in ("", None):
## display a form for editing the contents of a file, named by the parameter's value:
(title, body) = _create_configure_doctype_submission_functions_edit_parameter_file_form(doctype=doctype,
action=action,
functionname=functionname,
paramname=paramname)
elif editfunctionparameterfilecommit not in ("", None):
(title, body) = _update_submission_function_parameter_file(doctype=doctype, action=action, functionname=functionname,
paramname=paramname, paramfilecontent=paramfilecontent)
else:
## default - display list of parameters for function:
(title, body) = _create_configure_doctype_submission_functions_list_parameters_form(doctype=doctype,
action=action,
functionname=functionname)
return (title, body, errors, warnings)
def perform_request_configure_doctype_submissionfunctions(doctype,
action,
moveupfunctionname="",
moveupfunctionstep="",
moveupfunctionscore="",
movedownfunctionname="",
movedownfunctionstep="",
movedownfunctionscore="",
movefromfunctionname="",
movefromfunctionstep="",
movefromfunctionscore="",
movetofunctionname="",
movetofunctionstep="",
movetofunctionscore="",
deletefunctionname="",
deletefunctionstep="",
deletefunctionscore="",
configuresubmissionaddfunction="",
configuresubmissionaddfunctioncommit="",
addfunctionname="",
addfunctionstep="",
addfunctionscore=""):
errors = []
warnings = []
body = ""
user_msg = []
if addfunctionstep != "":
try:
addfunctionstep = str(wash_single_urlarg(urlarg=addfunctionstep, argreqdtype=int, argdefault=""))
except ValueError, e:
addfunctionstep = ""
if addfunctionscore != "":
try:
addfunctionscore = str(wash_single_urlarg(urlarg=addfunctionscore, argreqdtype=int, argdefault=""))
except ValueError, e:
addfunctionscore = ""
if deletefunctionstep != "":
try:
deletefunctionstep = str(wash_single_urlarg(urlarg=deletefunctionstep, argreqdtype=int, argdefault=""))
except ValueError, e:
deletefunctionstep = ""
if deletefunctionscore != "":
try:
deletefunctionscore = str(wash_single_urlarg(urlarg=deletefunctionscore, argreqdtype=int, argdefault=""))
except ValueError, e:
deletefunctionscore = ""
if movetofunctionstep != "":
try:
movetofunctionstep = str(wash_single_urlarg(urlarg=movetofunctionstep, argreqdtype=int, argdefault=""))
except ValueError, e:
movetofunctionstep = ""
if movetofunctionscore != "":
try:
movetofunctionscore = str(wash_single_urlarg(urlarg=movetofunctionscore, argreqdtype=int, argdefault=""))
except ValueError, e:
movetofunctionscore = ""
if moveupfunctionstep != "":
try:
moveupfunctionstep = str(wash_single_urlarg(urlarg=moveupfunctionstep, argreqdtype=int, argdefault=""))
except ValueError, e:
moveupfunctionstep = ""
if moveupfunctionscore != "":
try:
moveupfunctionscore = str(wash_single_urlarg(urlarg=moveupfunctionscore, argreqdtype=int, argdefault=""))
except ValueError, e:
moveupfunctionscore = ""
if movedownfunctionstep != "":
try:
movedownfunctionstep = str(wash_single_urlarg(urlarg=movedownfunctionstep, argreqdtype=int, argdefault=""))
except ValueError, e:
movedownfunctionstep = ""
if movedownfunctionscore != "":
try:
movedownfunctionscore = str(wash_single_urlarg(urlarg=movedownfunctionscore, argreqdtype=int, argdefault=""))
except ValueError, e:
movedownfunctionscore = ""
## ensure that there is only one doctype for this doctype ID - simply display all doctypes with warning if not
if doctype in ("", None):
user_msg.append("""Unknown Document Type""")
## TODO : LOG ERROR
all_doctypes = get_docid_docname_alldoctypes()
body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg)
title = "Available WebSubmit Document Types"
return (title, body, errors, warnings)
numrows_doctype = get_number_doctypes_docid(docid=doctype)
if numrows_doctype > 1:
## there are multiple doctypes with this doctype ID:
## TODO : LOG ERROR
user_msg.append("""Multiple document types identified by "%s" exist - cannot configure at this time.""" \
% (doctype,))
all_doctypes = get_docid_docname_alldoctypes()
body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg)
title = "Available WebSubmit Document Types"
return (title, body, errors, warnings)
elif numrows_doctype == 0:
## this doctype does not seem to exist:
user_msg.append("""The document type identified by "%s" doesn't exist - cannot configure at this time.""" \
% (doctype,))
## TODO : LOG ERROR
all_doctypes = get_docid_docname_alldoctypes()
body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg)
title = "Available WebSubmit Document Types"
return (title, body, errors, warnings)
## ensure that this submission exists for this doctype:
numrows_submission = get_number_submissions_doctype_action(doctype=doctype, action=action)
if numrows_submission > 1:
## there are multiple submissions for this doctype/action ID:
## TODO : LOG ERROR
user_msg.append("""The Submission "%s" seems to exist multiple times for the Document Type "%s" - cannot configure at this time.""" \
% (action, doctype))
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body, errors, warnings)
elif numrows_submission == 0:
## this submission does not seem to exist for this doctype:
user_msg.append("""The Submission "%s" doesn't exist for the "%s" Document Type - cannot configure at this time.""" \
% (action, doctype))
## TODO : LOG ERROR
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body, errors, warnings)
## submission valid
if movefromfunctionname != "" and movefromfunctionstep != "" and movefromfunctionscore != "" and \
movetofunctionname != "" and movetofunctionstep != "" and movetofunctionscore != "":
## process moving the function by jumping it to another position
try:
move_submission_function_from_one_position_to_another_position(doctype=doctype, action=action,
movefuncname=movefromfunctionname,
movefuncfromstep=movefromfunctionstep,
movefuncfromscore=movefromfunctionscore,
movefunctostep=movetofunctionstep,
movefunctoscore=movetofunctionscore)
user_msg.append("""The function [%s] at step [%s], score [%s] was successfully moved."""\
% (movefromfunctionname, movefromfunctionstep, movefromfunctionscore))
except Exception, e:
## there was a problem
user_msg.append(str(e))
(title, body) = _create_configure_doctype_submission_functions_form(doctype=doctype,
action=action,
user_msg=user_msg)
elif moveupfunctionname != "" and moveupfunctionstep != "" and moveupfunctionscore != "":
## process moving the function up one position
error_code = move_position_submissionfunction_up(doctype=doctype,
action=action,
function=moveupfunctionname,
funccurstep=moveupfunctionstep,
funccurscore=moveupfunctionscore)
if error_code == 0:
## success
user_msg.append("""The Function "%s" that was located at step %s, score %s, has been moved upwards""" \
% (moveupfunctionname, moveupfunctionstep, moveupfunctionscore))
else:
## could not move it
user_msg.append("""Unable to move the Function "%s" that is located at step %s, score %s""" \
% (moveupfunctionname, moveupfunctionstep, moveupfunctionscore))
(title, body) = _create_configure_doctype_submission_functions_form(doctype=doctype,
action=action,
user_msg=user_msg)
elif movedownfunctionname != "" and movedownfunctionstep != "" and movedownfunctionscore != "":
## process moving the function down one position
error_code = move_position_submissionfunction_down(doctype=doctype,
action=action,
function=movedownfunctionname,
funccurstep=movedownfunctionstep,
funccurscore=movedownfunctionscore)
if error_code == 0:
## success
user_msg.append("""The Function "%s" that was located at step %s, score %s, has been moved downwards""" \
% (movedownfunctionname, movedownfunctionstep, movedownfunctionscore))
else:
## could not move it
user_msg.append("""Unable to move the Function "%s" that is located at step %s, score %s""" \
% (movedownfunctionname, movedownfunctionstep, movedownfunctionscore))
(title, body) = _create_configure_doctype_submission_functions_form(doctype=doctype,
action=action,
user_msg=user_msg)
elif deletefunctionname != "" and deletefunctionstep != "" and deletefunctionscore != "":
## process deletion of function from the given position
(title, body) = _delete_submission_function(doctype=doctype, action=action, deletefunctionname=deletefunctionname,
deletefunctionstep=deletefunctionstep, deletefunctionscore=deletefunctionscore)
elif configuresubmissionaddfunction != "":
## display a form that allows the addition of a new WebSubmit function
(title, body) = _create_configure_doctype_submission_functions_add_function_form(doctype=doctype,
action=action)
elif configuresubmissionaddfunctioncommit != "":
## process the addition of the new WebSubmit function to the submission:
(title, body) = _add_function_to_submission(doctype=doctype, action=action, addfunctionname=addfunctionname,
addfunctionstep=addfunctionstep, addfunctionscore=addfunctionscore)
else:
## default - display functions for this submission
(title, body) = _create_configure_doctype_submission_functions_form(doctype=doctype,
action=action,
movefromfunctionname=movefromfunctionname,
movefromfunctionstep=movefromfunctionstep,
movefromfunctionscore=movefromfunctionscore
)
return (title, body, errors, warnings)
def _add_function_to_submission(doctype, action, addfunctionname, addfunctionstep, addfunctionscore):
"""Process the addition of a function to a submission.
The user can decide in which step and at which score to insert the function.
@param doctype: (string) the unique ID of a document type
@param action: (string) the unique ID of an action
@param addfunctionname: (string) the name of the function to be added to the submission
@param addfunctionstep: (integer) the step at which the function is to be added
@param addfunctionscore: (integer) the score at which the function is to be added
@return: a tuple containing 2 strings: (page-title, page-body)
"""
user_msg = []
if addfunctionname == "" or addfunctionstep == "" or addfunctionscore == "":
## invalid details!
user_msg.append("""Invalid function coordinates supplied!""")
(title, body) = _create_configure_doctype_submission_functions_add_function_form(doctype=doctype,
action=action,
user_msg=user_msg)
return (title, body)
try:
if int(addfunctionstep) < 1 or int(addfunctionscore) < 1:
## invalid details!
user_msg.append("""Invalid function step and/or score!""")
(title, body) = _create_configure_doctype_submission_functions_add_function_form(doctype=doctype,
action=action,
user_msg=user_msg)
return (title, body)
except ValueError:
user_msg.append("""Invalid function step and/or score!""")
(title, body) = _create_configure_doctype_submission_functions_add_function_form(doctype=doctype,
action=action,
user_msg=user_msg)
try:
insert_function_into_submission_at_step_and_score_then_regulate_scores_of_functions_in_step(doctype=doctype,
action=action,
function=addfunctionname,
step=addfunctionstep,
score=addfunctionscore)
except InvenioWebSubmitAdminWarningReferentialIntegrityViolation, e:
## Function didn't exist in WebSubmit! Not added to submission.
user_msg.append(str(e))
## TODO : LOG ERROR
(title, body) = _create_configure_doctype_submission_functions_add_function_form(doctype=doctype,
action=action,
addfunctionstep=addfunctionstep,
addfunctionscore=addfunctionscore,
user_msg=user_msg)
return (title, body)
except InvenioWebSubmitAdminWarningInsertFailed, e:
## insert failed - some functions within the step may have been corrupted!
user_msg.append(str(e))
## TODO : LOG ERROR
(title, body) = \
_create_configure_doctype_submission_functions_form(doctype=doctype, action=action, user_msg=user_msg)
return (title, body)
except InvenioWebSubmitAdminWarningDeleteFailed, e:
## when regulating the scores of functions within the step, could not delete some or all of the functions
## within the step that the function was added to. Some functions may have been lost!
user_msg.append(str(e))
## TODO : LOG ERROR
(title, body) = \
_create_configure_doctype_submission_functions_form(doctype=doctype, action=action, user_msg=user_msg)
return (title, body)
## Successfully added
user_msg.append("""The function [%s] has been added to submission [%s] at step [%s], score [%s]."""\
% (addfunctionname, "%s%s" % (action, doctype), addfunctionstep, addfunctionscore))
(title, body) = \
_create_configure_doctype_submission_functions_form(doctype=doctype, action=action, user_msg=user_msg)
return (title, body)
def _delete_submission_function(doctype, action, deletefunctionname, deletefunctionstep, deletefunctionscore):
"""Delete a submission function from a given submission. Re-order all functions below it (within the same step)
to fill the gap left by the deleted function.
@param doctype: (string) the unique ID of a document type
@param action: (string) the unique ID of an action
@param deletefunctionname: (string) the name of the function to be deleted from the submission
@param deletefunctionstep: (string) the step of the function to be deleted from the submission
@param deletefunctionscore: (string) the score of the function to be deleted from the submission
@return: tuple containing 2 strings: (page-title, page-body)
"""
user_msg = []
## first, delete the function:
try:
delete_function_at_step_and_score_from_submission(doctype=doctype, action=action,
function=deletefunctionname, step=deletefunctionstep,
score=deletefunctionscore)
except InvenioWebSubmitAdminWarningDeleteFailed, e:
## unable to delete function - error message and return
user_msg.append("""Unable to delete function [%s] at step [%s], score [%s] from submission [%s]""" \
% (deletefunctionname, deletefunctionstep, deletefunctionscore, "%s%s" % (action, doctype)))
## TODO : LOG ERROR
(title, body) = _create_configure_doctype_submission_functions_form(doctype=doctype, action=action, user_msg=user_msg)
return (title, body)
## now, correct the scores of all functions in the step from which a function was just deleted:
try:
regulate_score_of_all_functions_in_step_to_ascending_multiples_of_10_for_submission(doctype=doctype,
action=action,
step=deletefunctionstep)
except InvenioWebSubmitAdminWarningDeleteFailed, e:
## couldnt delete the functions before reordering them
user_msg.append("""Deleted function [%s] at step [%s], score [%s] from submission [%s], but could not re-order""" \
""" scores of remaining functions within step [%s]""" \
% (deletefunctionname, deletefunctionstep, deletefunctionscore,
"%s%s" % (action, doctype), deletefunctionstep))
## TODO : LOG ERROR
(title, body) = _create_configure_doctype_submission_functions_form(doctype=doctype, action=action, user_msg=user_msg)
return (title, body)
## update submission "last-modification" date:
update_modification_date_for_submission(doctype=doctype, action=action)
## success message:
user_msg.append("""Successfully deleted function [%s] at step [%s], score [%s] from submission [%s]""" \
% (deletefunctionname, deletefunctionstep, deletefunctionscore, "%s%s" % (action, doctype)))
## TODO : LOG function Deletion
(title, body) = _create_configure_doctype_submission_functions_form(doctype=doctype, action=action, user_msg=user_msg)
return (title, body)
def perform_request_configure_doctype_submissionpage_preview(doctype, action, pagenum):
"""Display a preview of a Submission Page and its fields.
@param doctype: (string) the unique ID of a document type
@param action: (string) the unique ID of an action
@param pagenum: (integer) the number of the submission page to be previewed
@return: a tuple of four elements. (page-title, page-body, errors, warnings)
"""
errors = []
warnings = []
body = ""
user_msg = []
try:
pagenum = str(pagenum)
except ValueError:
pagenum = ""
if pagenum != "":
try:
pagenum = str(wash_single_urlarg(urlarg=pagenum, argreqdtype=int, argdefault=""))
except ValueError, e:
pagenum = ""
## ensure that the page number for this submission is valid:
num_pages_submission = get_numbersubmissionpages_doctype_action(doctype=doctype, action=action)
try:
if not (int(pagenum) > 0 and int(pagenum) <= num_pages_submission):
user_msg.append("Invalid page number - out of range")
(title, body) = _create_configure_doctype_submission_pages_form(doctype=doctype, action=action, user_msg=user_msg)
return (title, body, errors, warnings)
except ValueError:
## invalid page number
user_msg.append("Invalid page number - must be an integer value!")
(title, body) = _create_configure_doctype_submission_pages_form(doctype=doctype, action=action, user_msg=user_msg)
return (title, body, errors, warnings)
## get details of all fields on submission page:
fields = get_details_and_description_of_all_fields_on_submissionpage(doctype=doctype, action=action, pagenum=pagenum)
## ensure all values for each field are strings:
string_fields = []
for field in fields:
string_fields.append(stringify_list_elements(field))
title = """A preview of Page %s of the %s Submission""" % (pagenum, "%s%s" % (action, doctype))
body = websubmitadmin_templates.tmpl_configuredoctype_display_submissionpage_preview(doctype=doctype,
action=action,
pagenum=pagenum,
fields=string_fields)
return (title, body, errors, warnings)
def perform_request_configure_doctype_submissionpage_elements(doctype, action, pagenum, movefieldfromposn="",
movefieldtoposn="", deletefieldposn="", editfieldposn="",
editfieldposncommit="", fieldname="", fieldtext="", fieldlevel="",
fieldshortdesc="", fieldcheck="", addfield="", addfieldcommit=""):
"""Process requests relating to the elements of a particular submission page"""
errors = []
warnings = []
body = ""
user_msg = []
try:
pagenum = str(pagenum)
except ValueError:
pagenum = ""
if pagenum != "":
try:
pagenum = str(wash_single_urlarg(urlarg=pagenum, argreqdtype=int, argdefault=""))
except ValueError, e:
pagenum = ""
if fieldname != "":
try:
fieldname = wash_single_urlarg(urlarg=fieldname, argreqdtype=str, argdefault="", maxstrlen=15, minstrlen=1)
if string_is_alphanumeric_including_underscore(txtstring=fieldname) == 0:
fieldname = ""
except ValueError, e:
fieldname = ""
if fieldtext != "":
try:
fieldtext = wash_single_urlarg(urlarg=fieldtext, argreqdtype=str, argdefault="")
except ValueError, e:
fieldtext = ""
if fieldlevel != "":
try:
fieldlevel = wash_single_urlarg(urlarg=fieldlevel, argreqdtype=str, argdefault="O", maxstrlen=1, minstrlen=1)
if string_is_alphanumeric_including_underscore(txtstring=fieldlevel) == 0:
fieldlevel = "O"
if fieldlevel not in ("m", "M", "o", "O"):
fieldlevel = "O"
fieldlevel = fieldlevel.upper()
except ValueError, e:
fieldlevel = "O"
if fieldshortdesc != "":
try:
fieldshortdesc = wash_single_urlarg(urlarg=fieldshortdesc, argreqdtype=str, argdefault="")
except ValueError, e:
fieldshortdesc = ""
if fieldcheck != "":
try:
fieldcheck = wash_single_urlarg(urlarg=fieldcheck, argreqdtype=str, argdefault="", maxstrlen=15, minstrlen=1)
if string_is_alphanumeric_including_underscore(txtstring=fieldcheck) == 0:
fieldcheck = ""
except ValueError, e:
fieldcheck = ""
if editfieldposn != "":
try:
editfieldposn = str(wash_single_urlarg(urlarg=editfieldposn, argreqdtype=int, argdefault=""))
except ValueError, e:
editfieldposn = ""
if deletefieldposn != "":
try:
deletefieldposn = str(wash_single_urlarg(urlarg=deletefieldposn, argreqdtype=int, argdefault=""))
except ValueError, e:
deletefieldposn = ""
if movefieldfromposn != "":
try:
movefieldfromposn = str(wash_single_urlarg(urlarg=movefieldfromposn, argreqdtype=int, argdefault=""))
except ValueError, e:
movefieldfromposn = ""
if movefieldtoposn != "":
try:
movefieldtoposn = str(wash_single_urlarg(urlarg=movefieldtoposn, argreqdtype=int, argdefault=""))
except ValueError, e:
movefieldtoposn = ""
## ensure that there is only one doctype for this doctype ID - simply display all doctypes with warning if not
if doctype in ("", None):
user_msg.append("""Unknown Document Type""")
## TODO : LOG ERROR
all_doctypes = get_docid_docname_alldoctypes()
body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg)
title = "Available WebSubmit Document Types"
return (title, body, errors, warnings)
numrows_doctype = get_number_doctypes_docid(docid=doctype)
if numrows_doctype > 1:
## there are multiple doctypes with this doctype ID:
## TODO : LOG ERROR
user_msg.append("""Multiple document types identified by "%s" exist - cannot configure at this time.""" \
% (doctype,))
all_doctypes = get_docid_docname_alldoctypes()
body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg)
title = "Available WebSubmit Document Types"
return (title, body, errors, warnings)
elif numrows_doctype == 0:
## this doctype does not seem to exist:
user_msg.append("""The document type identified by "%s" doesn't exist - cannot configure at this time.""" \
% (doctype,))
## TODO : LOG ERROR
all_doctypes = get_docid_docname_alldoctypes()
body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg)
title = "Available WebSubmit Document Types"
return (title, body, errors, warnings)
## ensure that this submission exists for this doctype:
numrows_submission = get_number_submissions_doctype_action(doctype=doctype, action=action)
if numrows_submission > 1:
## there are multiple submissions for this doctype/action ID:
## TODO : LOG ERROR
user_msg.append("""The Submission "%s" seems to exist multiple times for the Document Type "%s" - cannot configure at this time.""" \
% (action, doctype))
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body, errors, warnings)
elif numrows_submission == 0:
## this submission does not seem to exist for this doctype:
user_msg.append("""The Submission "%s" doesn't exist for the "%s" Document Type - cannot configure at this time.""" \
% (action, doctype))
## TODO : LOG ERROR
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body, errors, warnings)
## ensure that the page number for this submission is valid:
num_pages_submission = get_numbersubmissionpages_doctype_action(doctype=doctype, action=action)
try:
if not (int(pagenum) > 0 and int(pagenum) <= num_pages_submission):
user_msg.append("Invalid page number - out of range")
(title, body) = _create_configure_doctype_submission_pages_form(doctype=doctype, action=action, user_msg=user_msg)
return (title, body, errors, warnings)
except ValueError:
## invalid page number
user_msg.append("Invalid page number - must be an integer value!")
(title, body) = _create_configure_doctype_submission_pages_form(doctype=doctype, action=action, user_msg=user_msg)
return (title, body, errors, warnings)
## submission valid
if editfieldposn != "" and editfieldposncommit == "":
## display form for editing field
(title, body) = _configure_doctype_edit_field_on_submissionpage_display_field_details(errors=errors, warnings=warnings,
doctype=doctype, action=action,
pagenum=pagenum, fieldposn=editfieldposn)
elif editfieldposn != "" and editfieldposncommit != "":
## commit changes to element
(title, body) = _configure_doctype_edit_field_on_submissionpage(errors=errors, warnings=warnings, doctype=doctype, action=action,
pagenum=pagenum, fieldposn=editfieldposn, fieldtext=fieldtext,
fieldlevel=fieldlevel, fieldshortdesc=fieldshortdesc, fieldcheck=fieldcheck)
elif movefieldfromposn != "" and movefieldtoposn != "":
## move a field
(title, body) = _configure_doctype_move_field_on_submissionpage(errors=errors, warnings=warnings, doctype=doctype,
action=action, pagenum=pagenum, movefieldfromposn=movefieldfromposn,
movefieldtoposn=movefieldtoposn)
elif addfield != "":
## request to add a new field to a page - display form
(title, body) = _configure_doctype_add_field_to_submissionpage_display_form(doctype=doctype, action=action, pagenum=pagenum)
elif addfieldcommit != "":
## commit a new field to the page
(title, body) = _configure_doctype_add_field_to_submissionpage(errors=errors, warnings=warnings, doctype=doctype, action=action,
pagenum=pagenum, fieldname=fieldname, fieldtext=fieldtext,
fieldlevel=fieldlevel, fieldshortdesc=fieldshortdesc, fieldcheck=fieldcheck)
elif deletefieldposn != "":
## user wishes to delete a field from the page:
(title, body) = _configure_doctype_delete_field_from_submissionpage(errors=errors, warnings=warnings, doctype=doctype,
action=action, pagenum=pagenum, fieldnum=deletefieldposn)
else:
## default visit to page - list its elements:
(title, body) = _create_configure_doctype_submission_page_elements_form(doctype=doctype, action=action,
pagenum=pagenum, movefieldfromposn=movefieldfromposn)
return (title, body, errors, warnings)
def stringify_list_elements(elementslist):
o = []
for el in elementslist:
o.append(str(el))
return o
def _configure_doctype_edit_field_on_submissionpage(errors, warnings, doctype, action, pagenum, fieldposn,
fieldtext, fieldlevel, fieldshortdesc, fieldcheck):
"""Perform an update to the details of a field on a submission page.
@param doctype: (string) the unique ID of a document type
@param action: (string) the unique ID of an action
@param pagenum: (integer) the number of the page on which the element to be updated is found
@param fieldposn: (integer) the numeric position of the field to be editied
@param fieldtext: (string) the text label displayed with a field
@param fieldlevel: (char) M or O (whether the field is mandatory or optional)
@param fieldshortdesc: (string) the short description of a field
@param fieldcheck: (string) the name of a JavaScript check to be applied to a field
@return: a tuple containing 2 strings - (page-title, page-body)
"""
user_msg = []
if fieldcheck not in ("", None):
## ensure check exists:
checkres = get_number_jschecks_with_chname(chname=fieldcheck)
if checkres < 1:
user_msg.append("The Check '%s' does not exist in WebSubmit - changes to field not saved" % (fieldcheck,))
(title, body) = _configure_doctype_edit_field_on_submissionpage_display_field_details(errors=errors, warnings=warnings,
doctype=doctype, action=action,
pagenum=pagenum, fieldposn=fieldposn,
fieldtext=fieldtext, fieldlevel=fieldlevel,
fieldshortdesc=fieldshortdesc, user_msg=user_msg)
return (title, body)
try:
update_details_of_a_field_on_a_submissionpage(doctype=doctype, action=action, pagenum=pagenum, fieldposn=fieldposn,
fieldtext=fieldtext, fieldlevel=fieldlevel, fieldshortdesc=fieldshortdesc,
fieldcheck=fieldcheck)
user_msg.append("The details of the field at position %s have been updated successfully" % (fieldposn,))
update_modification_date_for_submission(doctype=doctype, action=action)
except InvenioWebSubmitAdminWarningTooManyRows, e:
## multiple rows found at page position - not safe to edit:
user_msg.append("Unable to update details of field at position %s on submission page %s - multiple fields found at this position" \
% (fieldposn, pagenum))
## TODO : LOG WARNING
except InvenioWebSubmitAdminWarningNoRowsFound, e:
## field not found - cannot edit
user_msg.append("Unable to update details of field at position %s on submission page %s - field doesn't seem to exist there!" \
% (fieldposn, pagenum))
## TODO : LOG WARNING
(title, body) = _create_configure_doctype_submission_page_elements_form(doctype=doctype, action=action, pagenum=pagenum, user_msg=user_msg)
return (title, body)
def _configure_doctype_edit_field_on_submissionpage_display_field_details(errors, warnings, doctype, action, pagenum, fieldposn,
fieldtext=None, fieldlevel=None, fieldshortdesc=None,
fieldcheck=None, user_msg=""):
"""Display a form used to edit a field on a submission page.
@param doctype: (string) the unique ID of a document type
@param action: (string) the unique ID of an action
@param pagenum: (integer) the number of the page on which the element to be updated is found
@param fieldposn: (integer) the numeric position of the field to be editied
@param fieldtext: (string) the text label displayed with a field
@param fieldlevel: (char) M or O (whether the field is mandatory or optional)
@param fieldshortdesc: (string) the short description of a field
@param fieldcheck: (string) the name of a JavaScript check to be applied to a field
@param user_msg: (list of strings, or string) any warning/error message to be displayed to the user
@return: a tuple containing 2 strings (page-title, page-body)
"""
if type(user_msg) not in (list, tuple) or user_msg == "":
user_msg = []
## get a list of all check names:
checks_res = get_all_jscheck_names()
allchecks=[]
for check in checks_res:
allchecks.append((check,))
## get the details for the field to be edited:
fielddets = get_details_of_field_at_positionx_on_submissionpage(doctype=doctype, action=action, pagenum=pagenum, fieldposition=fieldposn)
if len(fielddets) < 1:
(title, body) = _create_configure_doctype_submission_page_elements_form(doctype=doctype, action=action, pagenum=pagenum)
return (title, body)
fieldname = str(fielddets[2])
if fieldtext is not None:
fieldtext = str(fieldtext)
else:
fieldtext = str(fielddets[3])
if fieldlevel is not None:
fieldlevel = str(fieldlevel)
else:
fieldlevel = str(fielddets[4])
if fieldshortdesc is not None:
fieldshortdesc = str(fieldshortdesc)
else:
fieldshortdesc = str(fielddets[5])
if fieldcheck is not None:
fieldcheck = str(fieldcheck)
else:
fieldcheck = str(fielddets[6])
cd = str(fielddets[7])
md = str(fielddets[8])
title = """Edit the %(fieldname)s field as it appears at position %(fieldnum)s on Page %(pagenum)s of the %(submission)s Submission""" \
% { 'fieldname' : fieldname, 'fieldnum' : fieldposn, 'pagenum' : pagenum, 'submission' : "%s%s" % (action, doctype) }
body = websubmitadmin_templates.tmpl_configuredoctype_edit_submissionfield(doctype=doctype,
action=action,
pagenum=pagenum,
fieldnum=fieldposn,
fieldname=fieldname,
fieldtext=fieldtext,
fieldlevel=fieldlevel,
fieldshortdesc=fieldshortdesc,
fieldcheck=fieldcheck,
cd=cd,
md=md,
allchecks=allchecks,
user_msg=user_msg)
return (title, body)
def _configure_doctype_add_field_to_submissionpage(errors, warnings, doctype, action, pagenum, fieldname="",
fieldtext="", fieldlevel="", fieldshortdesc="", fieldcheck=""):
"""Add a field to a submission page.
@param doctype: (string) the unique ID of a document type
@param action: (string) the unique ID of an action
@param pagenum: (integer) the number of the page on which the element to be updated is found
@param fieldname: (string) the name of the field to be added to the page
@param fieldtext: (string) the text label displayed with a field
@param fieldlevel: (char) M or O (whether the field is mandatory or optional)
@param fieldshortdesc: (string) the short description of a field
@param fieldcheck: (string) the name of a JavaScript check to be applied to a field
@return: a tuple containing 2 strings - (page-title, page-body)
"""
user_msg = []
## ensure that a field "fieldname" actually exists:
if fieldname == "":
## the field to be added has no element description in the WebSubmit DB - cannot add
user_msg.append("""The field that you have chosen to add does not seem to exist in WebSubmit - cannot add""")
(title, body) = _configure_doctype_add_field_to_submissionpage_display_form(doctype, action, pagenum,
fieldtext=fieldtext,
fieldlevel=fieldlevel, fieldshortdesc=fieldshortdesc,
fieldcheck=fieldcheck, user_msg=user_msg)
return (title, body)
numelements_elname = get_number_elements_with_elname(elname=fieldname)
if numelements_elname < 1:
## the field to be added has no element description in the WebSubmit DB - cannot add
user_msg.append("""The field that you have chosen to add (%s) does not seem to exist in WebSubmit - cannot add""" % (fieldname,))
(title, body) = _configure_doctype_add_field_to_submissionpage_display_form(doctype, action, pagenum,
fieldtext=fieldtext,
fieldlevel=fieldlevel, fieldshortdesc=fieldshortdesc,
fieldcheck=fieldcheck, user_msg=user_msg)
return (title, body)
## if fieldcheck has been provided, ensure that it is a valid check name:
if fieldcheck not in ("", None):
## ensure check exists:
checkres = get_number_jschecks_with_chname(chname=fieldcheck)
if checkres < 1:
user_msg.append("The Check '%s' does not exist in WebSubmit - new field not saved to page" % (fieldcheck,))
(title, body) = _configure_doctype_add_field_to_submissionpage_display_form(doctype, action, pagenum,
fieldname=fieldname, fieldtext=fieldtext,
fieldlevel=fieldlevel, fieldshortdesc=fieldshortdesc,
user_msg=user_msg)
return (title, body)
## now add the new field to the page:
try:
insert_field_onto_submissionpage(doctype=doctype, action=action, pagenum=pagenum, fieldname=fieldname, fieldtext=fieldtext,
fieldlevel=fieldlevel, fieldshortdesc=fieldshortdesc, fieldcheck=fieldcheck)
user_msg.append("""Successfully added the field "%s" to the last position on page %s of submission %s""" \
% (fieldname, pagenum, "%s%s" % (action, doctype)))
update_modification_date_for_submission(doctype=doctype, action=action)
(title, body) = _create_configure_doctype_submission_page_elements_form(doctype=doctype, action=action, pagenum=pagenum, user_msg=user_msg)
except InvenioWebSubmitAdminWarningInsertFailed, e:
## the insert of the new field failed for some reason
## TODO : LOG ERROR
user_msg.append("""Couldn't add the field "%s" to page %s of submission %s - please try again""" \
% (fieldname, pagenum, "%s%s" % (action, doctype)))
(title, body) = _configure_doctype_add_field_to_submissionpage_display_form(doctype, action, pagenum,
fieldname=fieldname, fieldtext=fieldtext,
fieldlevel=fieldlevel, fieldshortdesc=fieldshortdesc,
fieldcheck=fieldcheck, user_msg=user_msg)
return (title, body)
def _configure_doctype_add_field_to_submissionpage_display_form(doctype, action, pagenum, fieldname="", fieldtext="",
fieldlevel="", fieldshortdesc="", fieldcheck="", user_msg=""):
title = """Add a Field to Page %(pagenum)s of the %(submission)s Submission""" \
% { 'pagenum' : pagenum, 'submission' : "%s%s" % (action, doctype) }
## sanity checking:
if type(user_msg) not in (list, tuple) or user_msg == "":
user_msg = []
## get a list of all check names:
checks_res = get_all_jscheck_names()
allchecks=[]
for check in checks_res:
allchecks.append((check,))
## get a list of all WebSubmit element names:
elements_res = get_all_element_names()
allelements = []
for el in elements_res:
allelements.append((el,))
## get form:
body = websubmitadmin_templates.tmpl_configuredoctype_add_submissionfield(doctype=doctype,
action=action,
pagenum=pagenum,
fieldname=fieldname,
fieldtext=fieldtext,
fieldlevel=fieldlevel,
fieldshortdesc=fieldshortdesc,
fieldcheck=fieldcheck,
allchecks=allchecks,
allelements=allelements,
user_msg=user_msg)
return (title, body)
def _configure_doctype_move_field_on_submissionpage(errors, warnings, doctype, action, pagenum, movefieldfromposn, movefieldtoposn):
user_msg = []
movefield_res = move_field_on_submissionpage_from_positionx_to_positiony(doctype=doctype, action=action, pagenum=pagenum,
movefieldfrom=movefieldfromposn, movefieldto=movefieldtoposn)
if movefield_res == \
'WRN_WEBSUBMITADMIN_INVALID_FIELD_NUMBERS_SUPPLIED_WHEN_TRYING_TO_MOVE_FIELD_ON_SUBMISSION_PAGE':
## invalid field numbers
warnings.append(('WRN_WEBSUBMITADMIN_INVALID_FIELD_NUMBERS_SUPPLIED_WHEN_TRYING_TO_MOVE_FIELD_ON_SUBMISSION_PAGE', \
movefieldfromposn, movefieldtoposn, pagenum, "%s%s" % (action, doctype)))
user_msg.append("""Unable to move field from position %s to position %s on page %s of submission %s%s - field position numbers invalid""" \
% (movefieldfromposn, movefieldtoposn, pagenum, action, doctype))
elif movefield_res == \
'WRN_WEBSUBMITADMIN_UNABLE_TO_SWAP_TWO_FIELDS_ON_SUBMISSION_PAGE_COULDNT_MOVE_FIELD1_TO_TEMP_POSITION':
## failed to swap 2 fields - couldn't move field1 to temp position
warnings.append(('WRN_WEBSUBMITADMIN_UNABLE_TO_SWAP_TWO_FIELDS_ON_SUBMISSION_PAGE_COULDNT_MOVE_FIELD1_TO_TEMP_POSITION', \
movefieldfromposn, movefieldtoposn, pagenum, "%s%s" % (action, doctype)))
user_msg.append("""Unable to move field from position %s to position %s on page %s of submission %s%s""" \
% (movefieldfromposn, movefieldtoposn, pagenum, action, doctype))
elif movefield_res == \
'WRN_WEBSUBMITADMIN_UNABLE_TO_SWAP_TWO_FIELDS_ON_SUBMISSION_PAGE_COULDNT_MOVE_FIELD2_TO_FIELD1_POSITION':
## failed to swap 2 fields on submission page - couldn't move field2 to field1 position
warnings.append(('WRN_WEBSUBMITADMIN_UNABLE_TO_SWAP_TWO_FIELDS_ON_SUBMISSION_PAGE_COULDNT_MOVE_FIELD2_TO_FIELD1_POSITION', \
movefieldfromposn, movefieldtoposn, pagenum, "%s%s" % (action, doctype), movefieldtoposn, movefieldfromposn))
user_msg.append("""Unable to move field from position %s to position %s on page %s of submission %s%s - See Admin if field order is broken""" \
% (movefieldfromposn, movefieldtoposn, pagenum, action, doctype))
elif movefield_res == \
'WRN_WEBSUBMITADMIN_UNABLE_TO_SWAP_TWO_FIELDS_ON_SUBMISSION_PAGE_COULDNT_MOVE_FIELD1_TO_POSITION_FIELD2_FROM_TEMPORARY_POSITION':
## failed to swap 2 fields in submission page - couldnt swap field at temp position to field2 position
warnings.append(('WRN_WEBSUBMITADMIN_UNABLE_TO_SWAP_TWO_FIELDS_ON_SUBMISSION_PAGE_COULDNT_MOVE_FIELD1_TO_POSITION_FIELD2_FROM_TEMPORARY_POSITION', \
movefieldfromposn, movefieldtoposn, pagenum, "%s%s" % (action, doctype), movefieldfromposn, movefieldtoposn))
user_msg.append("""Unable to move field from position %s to position %s on page %s of submission %s%s - Field-order is now broken and must be corrected by Admin""" \
% (movefieldfromposn, movefieldtoposn, pagenum, action, doctype))
elif movefield_res == \
'WRN_WEBSUBMITADMIN_UNABLE_TO_MOVE_FIELD_TO_NEW_POSITION_ON_SUBMISSION_PAGE_COULDNT_DECREMENT_POSITION_OF_FIELDS_BELOW_FIELD1':
## failed to decrement the position of all fields below the field that was moved to a temp position
warnings.append(('WRN_WEBSUBMITADMIN_UNABLE_TO_MOVE_FIELD_TO_NEW_POSITION_ON_SUBMISSION_PAGE_COULDNT_DECREMENT_POSITION_OF_FIELDS_BELOW_FIELD1', \
movefieldfromposn, movefieldtoposn, pagenum, "%s%s" % (action, doctype), movefieldfromposn))
user_msg.append("""Unable to move field from position %s to position %s on page %s of submission %s%s - See Admin if field-order is broken""" \
% (movefieldfromposn, movefieldtoposn, pagenum, action, doctype))
elif movefield_res == \
'WRN_WEBSUBMITADMIN_UNABLE_TO_MOVE_FIELD_TO_NEW_POSITION_ON_SUBMISSION_PAGE_COULDNT_INCREMENT_POSITION_OF_FIELDS_AT_AND_BELOW_FIELD2':
## failed to increment position of fields in and below position into which 'movefromfieldposn' is to be inserted
warnings.append(('WRN_WEBSUBMITADMIN_UNABLE_TO_MOVE_FIELD_TO_NEW_POSITION_ON_SUBMISSION_PAGE_COULDNT_INCREMENT_POSITION_OF_FIELDS_AT_AND_BELOW_FIELD2', \
movefieldfromposn, movefieldtoposn, pagenum, "%s%s" % (action, doctype), movefieldtoposn, movefieldfromposn))
user_msg.append("""Unable to move field from position %s to position %s on page %s of submission %s%s - Field-order is now broken and must be corrected by Admin""" \
% (movefieldfromposn, movefieldtoposn, pagenum, action, doctype))
else:
## successful update:
warnings.append(('WRN_WEBSUBMITADMIN_MOVED_FIELD_ON_SUBMISSION_PAGE', movefieldfromposn, movefieldtoposn, pagenum, "%s%s" % (action, doctype)))
user_msg.append("""Successfully moved field from position %s to position %s on page %s of submission %s%s""" \
% (movefieldfromposn, movefieldtoposn, pagenum, action, doctype))
(title, body) = _create_configure_doctype_submission_page_elements_form(doctype=doctype, action=action, pagenum=pagenum, user_msg=user_msg)
return (title, body)
def _configure_doctype_delete_field_from_submissionpage(errors, warnings, doctype, action, pagenum, fieldnum):
"""Delete a field from a submission page"""
user_msg = []
del_res = delete_a_field_from_submissionpage_then_reorder_fields_below_to_fill_vacant_position(doctype=doctype,
action=action,
pagenum=pagenum,
fieldposn=fieldnum)
if del_res == 'WRN_WEBSUBMITADMIN_UNABLE_TO_DELETE_FIELD_FROM_SUBMISSION_PAGE':
warnings.append(('WRN_WEBSUBMITADMIN_UNABLE_TO_DELETE_FIELD_FROM_SUBMISSION_PAGE', fieldnum, pagenum, "%s%s" % (action, doctype)))
user_msg.append("Unable to delete field at position %s from page number %s of submission %s%s" % (fieldnum, pagenum, action, doctype))
else:
## deletion was OK
user_msg.append("Field deleted")
warnings.append(('WRN_WEBSUBMITADMIN_DELETED_FIELD_FROM_SUBMISSION_PAGE', fieldnum, pagenum, "%s%s" % (action, doctype)))
(title, body) = _create_configure_doctype_submission_page_elements_form(doctype=doctype, action=action, pagenum=pagenum, user_msg=user_msg)
return (title, body)
def _create_configure_doctype_submission_page_elements_form(doctype, action, pagenum, movefieldfromposn="", user_msg=""):
## get list of elements for page:
title = """Submission Elements found on Page %s of the "%s" Submission of the "%s" Document Type:"""\
% (pagenum, action, doctype)
body = ""
raw_page_elements = get_details_allsubmissionfields_on_submission_page(doctype=doctype, action=action, pagenum=pagenum)
## correctly stringify page elements for the template:
page_elements = []
for element in raw_page_elements:
page_elements.append(stringify_list_elements(element))
body = websubmitadmin_templates.tmpl_configuredoctype_list_submissionelements(doctype=doctype,
action=action,
pagenum=pagenum,
page_elements=page_elements,
movefieldfromposn=movefieldfromposn,
user_msg=user_msg)
return (title, body)
def perform_request_configure_doctype_submissionpages(doctype,
action,
pagenum="",
movepage="",
movepagedirection="",
deletepage="",
deletepageconfirm="",
addpage=""):
"""Process requests relating to the submission pages of a doctype/submission"""
errors = []
warnings = []
body = ""
user_msg = []
try:
pagenum = int(pagenum)
except ValueError:
pagenum = ""
## ensure that there is only one doctype for this doctype ID - simply display all doctypes with warning if not
if doctype in ("", None):
user_msg.append("""Unknown Document Type""")
## TODO : LOG ERROR
all_doctypes = get_docid_docname_alldoctypes()
body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg)
title = "Available WebSubmit Document Types"
return (title, body, errors, warnings)
numrows_doctype = get_number_doctypes_docid(docid=doctype)
if numrows_doctype > 1:
## there are multiple doctypes with this doctype ID:
## TODO : LOG ERROR
user_msg.append("""Multiple document types identified by "%s" exist - cannot configure at this time.""" \
% (doctype,))
all_doctypes = get_docid_docname_alldoctypes()
body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg)
title = "Available WebSubmit Document Types"
return (title, body, errors, warnings)
elif numrows_doctype == 0:
## this doctype does not seem to exist:
user_msg.append("""The document type identified by "%s" doesn't exist - cannot configure at this time.""" \
% (doctype,))
## TODO : LOG ERROR
all_doctypes = get_docid_docname_alldoctypes()
body = websubmitadmin_templates.tmpl_display_alldoctypes(doctypes=all_doctypes, user_msg=user_msg)
title = "Available WebSubmit Document Types"
return (title, body, errors, warnings)
## ensure that this submission exists for this doctype:
numrows_submission = get_number_submissions_doctype_action(doctype=doctype, action=action)
if numrows_submission > 1:
## there are multiple submissions for this doctype/action ID:
## TODO : LOG ERROR
user_msg.append("""The Submission "%s" seems to exist multiple times for the Document Type "%s" - cannot configure at this time.""" \
% (action, doctype))
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body, errors, warnings)
elif numrows_submission == 0:
## this submission does not seem to exist for this doctype:
user_msg.append("""The Submission "%s" doesn't exist for the "%s" Document Type - cannot configure at this time.""" \
% (action, doctype))
## TODO : LOG ERROR
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body, errors, warnings)
## submission valid
if addpage != "":
## add a new page to a submission:
error_code = add_submission_page_doctype_action(doctype=doctype, action=action)
if error_code == 0:
## success
user_msg.append("""A new Submission Page has been added into the last position""")
else:
## could not move it
user_msg.append("""Unable to add a new Submission Page""")
(title, body) = _create_configure_doctype_submission_pages_form(doctype=doctype,
action=action,
user_msg=user_msg)
elif movepage != "":
## user wants to move a page upwards in the order
(title, body) = _configure_doctype_move_submission_page(errors=errors, warnings=warnings, doctype=doctype,
action=action, pagenum=pagenum, direction=movepagedirection)
elif deletepage != "":
## user wants to delete a page:
if deletepageconfirm != "":
## confirmation of deletion has been provided - proceed
(title, body) = _configure_doctype_delete_submission_page(errors=errors, warnings=warnings, doctype=doctype,
action=action, pagenum=pagenum)
else:
## user has not yet confirmed the deletion of a page - prompt for confirmation
(title, body) = _create_configure_doctype_submission_pages_form(doctype=doctype,
action=action,
deletepagenum=pagenum)
else:
## default - display details of submission pages for this submission:
(title, body) = _create_configure_doctype_submission_pages_form(doctype=doctype, action=action)
return (title, body, errors, warnings)
def _configure_doctype_move_submission_page(errors, warnings, doctype, action, pagenum, direction):
user_msg = []
## Sanity checking:
if direction.lower() not in ("up", "down"):
## invalid direction:
user_msg.append("""Invalid Page destination - no action was taken""")
(title, body) = _create_configure_doctype_submission_pages_form(doctype=doctype,
action=action,
user_msg=user_msg)
return (title, body)
## swap the pages:
if direction.lower() == "up":
error_code = swap_elements_adjacent_pages_doctype_action(doctype=doctype, action=action,
page1=pagenum, page2=pagenum-1)
else:
error_code = swap_elements_adjacent_pages_doctype_action(doctype=doctype, action=action,
page1=pagenum, page2=pagenum+1)
if error_code == 0:
## pages swapped successfully:
## TODO : LOG PAGE SWAP
user_msg.append("""Page %s was successfully moved %swards""" % (pagenum, direction.capitalize()))
elif error_code == 1:
## pages are not adjacent:
user_msg.append("""Unable to move page - only adjacent pages can be swapped around""")
elif error_code == 2:
## at least one page out of legal range (e.g. trying to move a page to a position higher or lower
## than the number of pages:
user_msg.append("""Unable to move page to illegal position""")
elif error_code in (3, 4):
## Some sort of problem moving fields around!
## TODO : LOG ERROR
user_msg.append("""Error: there was a problem swapping the submission elements to their new pages.""")
user_msg.append("""An attempt was made to return the elements to their original pages - you """\
"""should verify that this was successful, or ask your administrator"""\
""" to fix the problem manually""")
elif error_code == 5:
## the elements from the first page were left stranded in the temporary page!
## TODO : LOG ERROR
user_msg.append("""Error: there was a problem swapping the submission elements to their new pages.""")
user_msg.append("""Some elements were left stranded on a temporary page. Please ask your administrator to"""\
""" fix this problem manually""")
(title, body) = _create_configure_doctype_submission_pages_form(doctype=doctype, action=action, user_msg=user_msg)
return (title, body)
def _configure_doctype_delete_submission_page(errors, warnings, doctype, action, pagenum):
user_msg = []
num_pages = get_numbersubmissionpages_doctype_action(doctype=doctype, action=action)
if num_pages > 0:
## proceed with deletion
error_code = delete_allfields_submissionpage_doctype_action(doctype=doctype, action=action, pagenum=pagenum)
if error_code == 0:
## everything OK
## move elements from pages above the deleted page down by one page:
decrement_by_one_pagenumber_submissionelements_abovepage(doctype=doctype, action=action, frompage=pagenum)
## now decrement the number of pages associated with the submission:
error_code = decrement_by_one_number_submissionpages_doctype_action(doctype=doctype, action=action)
if error_code == 0:
## successfully deleted submission page
## TODO : LOG DELETION
user_msg.append("""Page number %s of Submission %s was successfully deleted."""\
% (pagenum, action))
(title, body) = _create_configure_doctype_submission_pages_form(doctype=doctype,
action=action,
user_msg=user_msg)
else:
## error - either submission didn't exist, or multiple instances found
## TODO : LOG ERROR
user_msg.append("""The Submission elements were deleted from Page %s of the Submission "%s"."""\
""" However, it was not possible to delete the page itself."""\
% (pagenum, action))
(title, body) = _create_configure_doctype_submission_pages_form(doctype=doctype,
action=action,
user_msg=user_msg)
else:
## unable to delete some or all fields from the page
## TODO : LOG ERROR
user_msg.append("""Error: Unable to delete some field elements from Page %s of Submission %s%s - """\
"""Page not deleted!""" % (pagenum, action, doctype))
(title, body) = _create_configure_doctype_submission_pages_form(doctype=doctype,
action=action,
user_msg=user_msg)
elif num_pages == 0:
## no pages to delete for this submission
user_msg.append("""This Submission has no Pages - Cannot delete a Page!""")
(title, body) = _create_configure_doctype_submission_pages_form(doctype=doctype,
action=action,
user_msg=user_msg)
else:
## error - couldn't determine the number of pages for submission
## TODO : LOG ERROR
user_msg.append("""Unable to determine number of Submission Pages for Submission "%s" - """\
"""Cannot delete page %s"""\
% (action, pagenum))
(title, body) = _create_configure_doctype_form(doctype=doctype, user_msg=user_msg)
return (title, body)
def _create_configure_doctype_submission_pages_form(doctype,
action,
deletepagenum="",
user_msg=""):
"""Perform the necessary steps in order to display a list of the pages belonging to a given
submission of a given document type.
@param doctype: (string) the unique ID of the document type.
@param action: (string) the unique name/ID of the action.
@param user_msg: (string, or list) any message(s) to be displayed to the user.
@return: a tuple containing 2 strings - the page title and the page body.
"""
title = """Details of the Pages of the "%s" Submission of the "%s" Document Type:""" % (action, doctype)
submission_dets = get_cd_md_numbersubmissionpages_doctype_action(doctype=doctype, action=action)
if len(submission_dets) > 0:
cd = str(submission_dets[0][0])
md = str(submission_dets[0][1])
num_pages = submission_dets[0][2]
else:
(cd, md, num_pages) = ("", "", "0")
body = websubmitadmin_templates.tmpl_configuredoctype_list_submissionpages(doctype=doctype,
action=action,
number_pages=num_pages,
cd=cd,
md=md,
deletepagenum=deletepagenum,
user_msg=user_msg)
return (title, body)
diff --git a/modules/websubmit/web/admin/referees.py b/modules/websubmit/web/admin/referees.py
index 107812b6b..3429951ab 100644
--- a/modules/websubmit/web/admin/referees.py
+++ b/modules/websubmit/web/admin/referees.py
@@ -1,227 +1,227 @@
## $Id$
##
## This file is part of CDS Invenio.
## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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.
__revision__ = "$Id$"
## import interesting modules:
import string
import os
import sys
import time
import types
import re
import shutil
from invenio.config import \
cdslang, \
cdsname, \
images, \
version, \
weburl
from invenio.dbquery import run_sql, Error
from invenio.access_control_engine import acc_authorize_action
from invenio.access_control_admin import *
from invenio.webpage import page, create_error_box
from invenio.webuser import getUid, get_email, list_registered_users
from invenio.messages import wash_language
from invenio.websubmit_config import *
def index(req,c=cdsname,ln=cdslang,todo="",id="",doctype="",categ="",addusers="",warningText="",role=""):
ln = wash_language(ln)
# get user ID:
try:
uid = getUid(req)
uid_email = get_email(uid)
except Error, e:
return errorMsg(e.value,req)
(auth_code, auth_message) = acc_authorize_action(req, "cfgwebsubmit",verbose=0)
if auth_code != 0:
return errorMsg(auth_message, req, uid)
# request for deleting a user
if todo == "deleteuser":
- acc_deleteUserRole(id,name_role=role)
+ acc_delete_user_role(id,name_role=role)
# request for adding user(s)
if todo == "adduser":
role = "referee_%s_%s" % (doctype,categ[1])
- roleId = acc_getRoleId(role)
+ roleId = acc_get_role_id(role)
# if the role does not exists, we create it
if roleId == 0:
- if acc_addRole(role,"referees for document type %s category %s" % (doctype,categ[1])) == 0:
+ if acc_add_role(role,"referees for document type %s category %s" % (doctype,categ[1])) == 0:
return errorMsg("Cannot create referee role",req)
else:
- roleId = acc_getRoleId(role)
+ roleId = acc_get_role_id(role)
# if the action does not exist, we create it
- actionId = acc_getActionId("referee")
+ actionId = acc_get_action_id("referee")
if actionId == 0:
- if acc_addAction("referee","","no",("doctype","categ")) == 0:
+ if acc_add_action("referee","","no",("doctype","categ")) == 0:
return errorMsg("Cannot create action 'referee'",req)
else:
- actionId = acc_getActionId("referee")
+ actionId = acc_get_action_id("referee")
#create arguments
- arg1Id = acc_addArgument("doctype",doctype)
- arg2Id = acc_addArgument("categ",categ[1])
+ arg1Id = acc_add_argument("doctype",doctype)
+ arg2Id = acc_add_argument("categ",categ[1])
# then link the role with the action
- if acc_addRoleActionArguments(roleId,actionId,-1,0,0,[arg1Id,arg2Id]) == 0:
+ if acc_add_role_action_arguments(roleId,actionId,-1,0,0,[arg1Id,arg2Id]) == 0:
return errorMsg("Cannot link role with action",req)
- roleId = acc_getRoleId(role)
+ roleId = acc_get_role_id(role)
# For each id in the array
if isinstance(addusers,types.ListType):
for adduser in addusers:
# First check whether this id is not already associated with this rule
- myRoles = acc_getUserRoles(adduser)
+ myRoles = acc_get_user_roles(adduser)
if not roleId in myRoles:
# Actually add the role to the user
- acc_addUserRole(adduser,roleId)
+ acc_add_user_role(adduser,roleId)
else:
warningText = "Sorry... This user is already a referee for this category."
else:
# First check whether this id is not already associated with this rule
- myRoles = acc_getUserRoles(addusers)
+ myRoles = acc_get_user_roles(addusers)
if not roleId in myRoles:
# Actually add the role to the user
- acc_addUserRole(addusers,roleId)
+ acc_add_user_role(addusers,roleId)
else:
warningText = "Sorry... This user is already a referee for this category."
return page(title="websubmit admin - referee selection",
body=displayRefereesPage(doctype,warningText),
description="",
keywords="",
uid=uid,
language=ln,
req=req)
def displayRefereesPage(doctype,warningText):
t=""
if doctype == "*":
docname = "all catalogues"
else:
res = run_sql("SELECT * FROM sbmDOCTYPE WHERE sdocname=%s", (doctype,))
docname = res[0][0]
t+=warningText
t+="""
""" % (weburl, doctype)
return t
def displayUserTable(doctype):
t=""
# start displaying the table which will contain the list of email addresses.
t+= """
Referees
"""
- roles = acc_getAllRoles()
+ roles = acc_get_all_roles()
referees = {}
for role in roles:
role_name = role[1]
role_id = role[0]
if re.match("^referee_%s_" % doctype,role_name):
# Try to retrieve the referee's email from the referee's database
- if acc_getRoleUsers(role_id) is not None:
- referees[role_name] = acc_getRoleUsers(role_id)
+ if acc_get_role_users(role_id) is not None:
+ referees[role_name] = acc_get_role_users(role_id)
if len(referees) == 0:
t+= "
" % images
i=0
for role in referees.keys():
categ = re.match("referee_%s_(.*)" % doctype,role).group(1)
res = run_sql("SELECT lname FROM sbmCATEGORIES WHERE sname=%s and doctype=%s", (categ,doctype,))
if len(res) > 0:
categname = "Referee(s) for category: %s" % res[0][0]
else:
categname = "General Referee(s)"
t+= "
%s
" % categname
for referee in referees[role]:
if int(i/2) == i/2:
bgcolor="#eeeeee"
else:
bgcolor="#dddddd"
t+= "
"
return t
def displayAddUser(doctype):
t=""
# start displaying the table which will contain the add form
t+= """
Add
User: """
users = list_registered_users()
if len(users) < 20:
numrows = len(users)
else:
numrows = 20
t+= "" % numrows
for user in users:
if user[1] != "":
t+= " "
t+= ""
t+= " "
t+= ""
t+= "
"
return t
def errorMsg(title,req,uid,c=cdsname,ln=cdslang):
return page(title="error",
body = create_error_box(req, title=title,verbose=0, ln=ln),
description="%s - Internal Error" % c,
keywords="%s, Internal Error" % c,
language=ln,
uid=uid,
req=req)
diff --git a/modules/websubmit/web/approve.py b/modules/websubmit/web/approve.py
index ba2761e2c..4081e212e 100644
--- a/modules/websubmit/web/approve.py
+++ b/modules/websubmit/web/approve.py
@@ -1,81 +1,81 @@
## $Id$
##
## This file is part of CDS Invenio.
## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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.
__revision__ = "$Id$"
## import interesting modules:
import string
import os
import sys
import time
import types
import re
from mod_python import apache
from invenio.config import \
CFG_ACCESS_CONTROL_LEVEL_SITE, \
cdslang, \
cdsname, \
urlpath, \
version
from invenio.dbquery import run_sql
from invenio.access_control_engine import acc_authorize_action
-from invenio.access_control_admin import acc_isRole
+from invenio.access_control_admin import acc_is_role
from invenio.websubmit_config import *
from invenio.webpage import page, create_error_box
from invenio.webuser import getUid, get_email, page_not_authorized
from invenio.messages import wash_language
def index(req,c=cdsname,ln=cdslang):
uid = getUid(req)
if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
return page_not_authorized(req, "../approve.py/index",
navmenuid='yourapprovals')
ln = wash_language(ln)
form = req.form
if form.keys():
access = form.keys()[0]
if access == "":
return errorMsg("approve.py: cannot determine document reference",req)
res = run_sql("select doctype,rn from sbmAPPROVAL where access=%s",(access,))
if len(res) == 0:
return errorMsg("approve.py: cannot find document in database",req)
else:
doctype = res[0][0]
rn = res[0][1]
res = run_sql("select value from sbmPARAMETERS where name='edsrn' and doctype=%s",(doctype,))
edsrn = res[0][0]
url = "%s/submit/sub?%s=%s&password=%s@APP%s" % (urlpath,edsrn,rn,access,doctype)
req.err_headers_out.add("Location", url)
raise apache.SERVER_RETURN, apache.HTTP_MOVED_PERMANENTLY
return ""
else:
return errorMsg("Sorry parameter missing...", req, c, ln)
def errorMsg(title,req,c=cdsname,ln=cdslang):
return page(title="error",
body = create_error_box(req, title=title,verbose=0, ln=ln),
description="%s - Internal Error" % c,
keywords="%s, Internal Error" % c,
language=ln,
req=req,
navmenuid='yourapprovals')
diff --git a/modules/websubmit/web/publiline.py b/modules/websubmit/web/publiline.py
index 7d7c6f3ea..820bb6eb5 100644
--- a/modules/websubmit/web/publiline.py
+++ b/modules/websubmit/web/publiline.py
@@ -1,381 +1,381 @@
## $Id$
## This file is part of CDS Invenio.
## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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.
__revision__ = "$Id$"
## import interesting modules:
import string
import os
import sys
import time
import types
import re
import shutil
from invenio.config import \
CFG_ACCESS_CONTROL_LEVEL_SITE, \
accessurl, \
adminemail, \
cdslang, \
cdsname, \
images, \
pylibdir, \
storage, \
supportemail, \
sweburl, \
urlpath, \
version
from invenio.dbquery import run_sql, Error
from invenio.access_control_engine import acc_authorize_action
from invenio.access_control_admin import *
from invenio.webpage import page, create_error_box
from invenio.webuser import getUid, get_email, list_registered_users, page_not_authorized
from invenio.messages import gettext_set_language, wash_language
from invenio.websubmit_config import *
from invenio.search_engine import search_pattern
from invenio.websubmit_functions.Retrieve_Data import Get_Field
from invenio.mailutils import send_email
execfile("%s/invenio/websubmit_functions/Retrieve_Data.py" % pylibdir)
execfile("%s/invenio/websubmit_functions/mail.py" % pylibdir)
import invenio.template
websubmit_templates = invenio.template.load('websubmit')
def index(req,c=cdsname,ln=cdslang,doctype="",categ="",RN="",send=""):
global uid
ln = wash_language(ln)
# load the right message language
_ = gettext_set_language(ln)
t=""
# get user ID:
try:
uid = getUid(req)
if uid == -1 or CFG_ACCESS_CONTROL_LEVEL_SITE >= 1:
return page_not_authorized(req, "../publiline.py/index",
navmenuid='yourapprovals')
uid_email = get_email(uid)
except Error, e:
return errorMsg(e.value,req, ln = ln)
if doctype == "":
t = selectDoctype(ln)
elif categ == "":
t = selectCateg(doctype, ln)
elif RN == "":
t = selectDocument(doctype,categ, ln)
else:
t = displayDocument(req, doctype,categ,RN,send, ln)
return page(title="publication line",
navtrail= """%(account)s""" % {
'sweburl' : sweburl,
'account' : _("Your Account"),
},
body=t,
description="",
keywords="",
uid=uid,
language=ln,
req=req,
navmenuid='yourapprovals')
def selectDoctype(ln = cdslang):
res = run_sql("select DISTINCT doctype from sbmAPPROVAL")
docs = []
for row in res:
res2 = run_sql("select ldocname from sbmDOCTYPE where sdocname=%s", (row[0],))
docs.append({
'doctype' : row[0],
'docname' : res2[0][0],
})
t = websubmit_templates.tmpl_publiline_selectdoctype(
ln = ln,
docs = docs,
)
return t
def selectCateg(doctype, ln = cdslang):
t=""
res = run_sql("select ldocname from sbmDOCTYPE where sdocname=%s",(doctype,))
title = res[0][0]
sth = run_sql("select * from sbmCATEGORIES where doctype=%s order by lname",(doctype,))
if len(sth) == 0:
categ = "unknown"
return selectDocument(doctype,categ, ln = ln)
categories = []
for arr in sth:
waiting = 0
rejected = 0
approved = 0
sth2 = run_sql("select COUNT(*) from sbmAPPROVAL where doctype=%s and categ=%s and status='waiting'", (doctype,arr[1],))
waiting = sth2[0][0]
sth2 = run_sql("select COUNT(*) from sbmAPPROVAL where doctype=%s and categ=%s and status='approved'",(doctype,arr[1],))
approved = sth2[0][0]
sth2 = run_sql("select COUNT(*) from sbmAPPROVAL where doctype=%s and categ=%s and status='rejected'",(doctype,arr[1],))
rejected = sth2[0][0]
categories.append({
'waiting' : waiting,
'approved' : approved,
'rejected' : rejected,
'id' : arr[1],
})
t = websubmit_templates.tmpl_publiline_selectcateg(
ln = ln,
categories = categories,
doctype = doctype,
title = title,
images = images,
)
return t
def selectDocument(doctype,categ, ln = cdslang):
t=""
res = run_sql("select ldocname from sbmDOCTYPE where sdocname=%s", (doctype,))
title = res[0][0]
if categ == "":
categ == "unknown"
docs = []
sth = run_sql("select rn,status from sbmAPPROVAL where doctype=%s and categ=%s order by status DESC,rn DESC",(doctype,categ))
for arr in sth:
docs.append({
'RN' : arr[0],
'status' : arr[1],
})
t = websubmit_templates.tmpl_publiline_selectdocument(
ln = ln,
doctype = doctype,
title = title,
categ = categ,
images = images,
docs = docs,
)
return t
def displayDocument(req, doctype,categ,RN,send, ln = cdslang):
# load the right message language
_ = gettext_set_language(ln)
t=""
res = run_sql("select ldocname from sbmDOCTYPE where sdocname=%s", (doctype,))
docname = res[0][0]
if categ == "":
categ = "unknown"
sth = run_sql("select rn,status,dFirstReq,dLastReq,dAction,access from sbmAPPROVAL where rn=%s",(RN,))
if len(sth) > 0:
arr = sth[0]
rn = arr[0]
status = arr[1]
dFirstReq = arr[2]
dLastReq = arr[3]
dAction = arr[4]
access = arr[5]
else:
return _("Approval has never been requested for this document.") + " "
try:
(authors,title,sysno,newrn) = getInfo(doctype,categ,RN)
except TypeError:
return _("Unable to display document.")
confirm_send = 0
if send == _("Send Again"):
if authors == "unknown" or title == "unknown":
SendWarning(doctype,categ,RN,title,authors,access, ln = ln)
else:
# @todo - send in different languages
SendEnglish(doctype,categ,RN,title,authors,access,sysno)
run_sql("update sbmAPPROVAL set dLastReq=NOW() where rn=%s",(RN,))
confirm_send = 1
if status == "waiting":
(auth_code, auth_message) = acc_authorize_action(req, "referee",verbose=0,doctype=doctype, categ=categ)
else:
(auth_code, auth_message) = (None, None)
t = websubmit_templates.tmpl_publiline_displaydoc(
ln = ln,
docname = docname,
doctype = doctype,
categ = categ,
rn = rn,
status = status,
dFirstReq = dFirstReq,
dLastReq = dLastReq,
dAction = dAction,
access = access,
images = images,
accessurl = accessurl,
confirm_send = confirm_send,
auth_code = auth_code,
auth_message = auth_message,
authors = authors,
title = title,
sysno = sysno,
newrn = newrn,
)
return t
# Retrieve info about document
def getInfo(doctype,categ,RN):
result = getInPending(doctype,categ,RN)
if not result:
result = getInAlice(doctype,categ,RN)
return result
#seek info in pending directory
def getInPending(doctype,categ,RN):
PENDIR="%s/pending" % storage
if os.path.exists("%s/%s/%s/AU" % (PENDIR,doctype,RN)):
fp = open("%s/%s/%s/AU" % (PENDIR,doctype,RN),"r")
authors=fp.read()
fp.close()
else:
authors = ""
if os.path.exists("%s/%s/%s/TI" % (PENDIR,doctype,RN)):
fp = open("%s/%s/%s/TI" % (PENDIR,doctype,RN),"r")
title=fp.read()
fp.close()
else:
title = ""
if os.path.exists("%s/%s/%s/SN" % (PENDIR,doctype,RN)):
fp = open("%s/%s/%s/SN" % (PENDIR,doctype,RN),"r")
sysno=fp.read()
fp.close()
else:
sysno = ""
if title == "" and os.path.exists("%s/%s/%s/TIF" % (PENDIR,doctype,RN)):
fp = open("%s/%s/%s/TIF" % (PENDIR,doctype,RN),"r")
title=fp.read()
fp.close()
if title == "":
return 0
else:
return (authors,title,sysno,"")
#seek info in Alice database
def getInAlice(doctype,categ,RN):
# initialize sysno variable
sysno = ""
searchresults = search_pattern(req=None, p=RN, f="reportnumber").items().tolist()
if len(searchresults) == 0:
return 0
sysno = searchresults[0]
if sysno != "":
title = Get_Field('245__a',sysno)
emailvalue = Get_Field('8560_f',sysno)
authors = Get_Field('100__a',sysno)
authors += "\n%s" % Get_Field('700__a',sysno)
newrn = Get_Field('037__a',sysno)
return (authors,title,sysno,newrn)
else:
return 0
def SendEnglish(doctype,categ,RN,title,authors,access,sysno):
FROMADDR = '%s Submission Engine <%s>' % (cdsname,supportemail)
# retrieve useful information from webSubmit configuration
res = run_sql("select value from sbmPARAMETERS where name='categformatDAM' and doctype=%s", (doctype,))
categformat = res[0][0]
categformat = re.sub("","([^-]*)",categformat)
categs = re.match(categformat,RN)
if categs is not None:
categ = categs.group(1)
else:
categ = "unknown"
res = run_sql("select value from sbmPARAMETERS where name='addressesDAM' and doctype=%s",(doctype,))
if len(res) > 0:
otheraddresses = res[0][0]
otheraddresses = otheraddresses.replace("",categ)
else:
otheraddresses = ""
# Build referee's email address
refereeaddress = ""
# Try to retrieve the referee's email from the referee's database
- for user in acc_getRoleUsers(acc_getRoleId("referee_%s_%s" % (doctype,categ))):
+ for user in acc_get_role_users(acc_getRoleId("referee_%s_%s" % (doctype,categ))):
refereeaddress += user[1] + ","
# And if there are general referees
- for user in acc_getRoleUsers(acc_getRoleId("referee_%s_*" % doctype)):
+ for user in acc_get_role_users(acc_getRoleId("referee_%s_*" % doctype)):
refereeaddress += user[1] + ","
refereeaddress = re.sub(",$","",refereeaddress)
# Creation of the mail for the referee
addresses = ""
if refereeaddress != "":
addresses = refereeaddress + ","
if otheraddresses != "":
addresses += otheraddresses
else:
addresses = re.sub(",$","",addresses)
if addresses=="":
SendWarning(doctype,categ,RN,title,authors,access)
return 0
if authors == "":
authors = "-"
res = run_sql("select value from sbmPARAMETERS where name='directory' and doctype=%s", (doctype,))
directory = res[0][0]
message = """
The document %s has been published as a Communication.
Your approval is requested for it to become an official Note.
Title: %s
Author(s): %s
To access the document(s), select the file(s) from the location:
<%s/record/%s/files/>
To approve/reject the document, you should go to this URL:
<%s/approve.py?%s>
---------------------------------------------
Best regards.
The submission team.""" % (RN,title,authors,urlpath,sysno,urlpath,access)
# send the mail
send_email(FROMADDR,addresses,"Request for Approval of %s" % RN, message,footer="")
return ""
def SendWarning(doctype,categ,RN,title,authors,access):
FROMADDR = '%s Submission Engine <%s>' % (cdsname,supportemail)
message = "Failed sending approval email request for %s" % RN
# send the mail
send_email(FROMADDR,adminemail,"Failed sending approval email request",message)
return ""
def errorMsg(title,req,c=cdsname,ln=cdslang):
return page(title="error",
body = create_error_box(req, title=title,verbose=0, ln=ln),
description="%s - Internal Error" % c,
keywords="%s, Internal Error" % c,
language=ln,
req=req,
navmenuid='yourapprovals')
def warningMsg(title,req,c=cdsname,ln=cdslang):
return page(title="warning",
body = title,
description="%s - Internal Error" % c,
keywords="%s, Internal Error" % c,
language=ln,
req=req,
navmenuid='yourapprovals')