diff --git a/modules/webaccess/lib/webaccessadmin_lib.py b/modules/webaccess/lib/webaccessadmin_lib.py index 223589f13..196c6b8a3 100644 --- a/modules/webaccess/lib/webaccessadmin_lib.py +++ b/modules/webaccess/lib/webaccessadmin_lib.py @@ -1,3516 +1,3539 @@ ## $Id$ ## Administrator interface for WebAccess ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 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 WebAccess Administrator Interface.""" __revision__ = "$Id$" __lastupdated__ = """$Date$""" ## fill config variables: import re import random import getopt import sys 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_ACTIVATION, \ CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_DELETION, \ CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_NEW_ACCOUNT, \ CFG_SITE_LANG, \ CFG_SITE_NAME, \ CFG_SITE_SUPPORT_EMAIL, \ CFG_SITE_ADMIN_EMAIL, \ CFG_SITE_SECURE_URL, \ CFG_SITE_URL import invenio.access_control_engine as acce import invenio.access_control_admin as acca from invenio.mailutils import send_email from invenio.bibrankadminlib import addadminbox, tupletotable, \ tupletotable_onlyselected, addcheckboxes, createhiddenform from invenio.access_control_firerole import compile_role_definition, \ repair_role_definitions, serialize from invenio.messages import gettext_set_language -from invenio.dbquery import run_sql +from invenio.dbquery import run_sql, OperationalError from invenio.webpage import page from invenio.webuser import getUid, isGuestUser, page_not_authorized from invenio.webuser import email_valid_p, get_user_preferences, \ set_user_preferences, setUid from invenio.urlutils import redirect_to_url from invenio.access_control_config import DEF_DEMO_USER_ROLES, \ DEF_DEMO_ROLES, DEF_DEMO_AUTHS, WEBACCESSACTION, MAXPAGEUSERS, \ SUPERADMINROLE, CFG_EXTERNAL_AUTHENTICATION, DELEGATEADDUSERROLE, \ CFG_ACC_EMPTY_ROLE_DEFINITION_SRC, InvenioWebAccessFireroleError, \ MAXSELECTUSERS from invenio.bibtask import authenticate from cgi import escape def index(req, title='', body='', subtitle='', adminarea=2, authorized=0): """main function to show pages for webaccessadmin. 1. if user not logged in and administrator, show the mustlogin page 2. if used without body argument, show the startpage 3. show admin page with title, body, subtitle and navtrail. adminarea - number codes that tell what extra info to put in the navtrail 0 - nothing extra 1 - add Delegate Rights 2 - add Manage WebAccess maybe add: 3: role admin 4: action admin 5: user area 6: reset area authorized - if 1, don't check if the user is allowed to be webadmin """ navtrail_previous_links = '<a class="navtrail" href="%s/help/admin">Admin Area' \ '</a>' % (CFG_SITE_URL,) if body: if adminarea == 1: navtrail_previous_links += '> <a class=navtrail ' \ ' href=%s/admin/webaccess/webaccessadmin.py/delegate_startarea>' \ 'Delegate Rights</a> ' % (CFG_SITE_URL, ) if adminarea >= 2 and adminarea < 7: navtrail_previous_links += '> ' \ '<a class="navtrail" href=%s/admin/webaccess/webaccessadmin.py>' \ 'WebAccess Admin</a> ' % (CFG_SITE_URL, ) if adminarea == 3: navtrail_previous_links += '> <a class=navtrail ' \ 'href=%s/admin/webaccess/webaccessadmin.py/rolearea>' \ 'Role Administration</a> ' % (CFG_SITE_URL, ) elif adminarea == 4: navtrail_previous_links += '> ' \ '<a class="navtrail" href=%s/admin/webaccess/webaccessadmin.py' \ '/actionarea>Action Administration</a> ' % (CFG_SITE_URL, ) elif adminarea == 5: navtrail_previous_links += '> ' \ '<a class="navtrail" href=%s/admin/webaccess/webaccessadmin.py' \ '/userarea>User Administration</a> ' % (CFG_SITE_URL, ) elif adminarea == 6: navtrail_previous_links += '> ' \ '<a class="navtrail" href=%s/admin/webaccess/webaccessadmin.py' \ '/resetarea>Reset Authorizations</a> ' % (CFG_SITE_URL, ) elif adminarea == 7: navtrail_previous_links += '> ' \ '<a class="navtrail" href=%s/admin/webaccess/webaccessadmin.py' \ '/manageaccounts>Manage Accounts</a> ' % (CFG_SITE_URL, ) elif adminarea == 8: navtrail_previous_links += '> ' \ '<a class="navtrail" href=%s/admin/webaccess/webaccessadmin.py' \ '/listgroups>List Groups</a> ' % (CFG_SITE_URL, ) 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 = 'WebAccess Admin' 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 = '<a class="navtrail" href="%s/admin/">' \ 'Admin Area</a> > <a class="navtrail" href="%s/admin/webaccess/">' \ 'WebAccess Admin</a> ' % (CFG_SITE_URL, CFG_SITE_URL) 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_listgroups(req): """List all the existing groups.""" (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) header = ['name'] groups = run_sql('select name from usergroup') output = tupletotable(header, groups) extra = """ <dl> <dt><a href="addrole">Create new role</a></dt> <dd>go here to add a new role.</dd> </dl> """ return index(req=req, title='Group list', subtitle='All the groups registered in the system', body=[output, extra], adminarea=2) 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_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('<a href="%s?id_role=%s">%s</a>' % (col[0][1], id, col[0][0])) for (str, function) in col[1:]: roles2[-1][-1] += ' / <a href="%s?id_role=%s">%s</a>' % \ (function, id, str) output = """ <dl> <dt>Users:</dt> <dd>add or remove users from the access to a role and its priviliges.</dd> <dt>Authorizations/Actions:</dt> <dd>these terms means almost the same, but an authorization is a <br /> connection between a role and an action (possibly) containing arguments. </dd> <dt>Roles:</dt> <dd>see all the information attached to a role and decide if you want to<br />delete it.</dd> </dl> """ output += tupletotable(header=header, tuple=roles2) extra = """ <dl> <dt><a href="addrole">Create new role</a></dt> <dd>go here to add a new role.</dd> </dl> """ return index(req=req, title='Role Administration', subtitle='administration with roles as access point', body=[output, extra], adminarea=2) def perform_actionarea(req): """create the action area menu page.""" (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) header = ['id', 'name', 'authorizations/roles', ''] actions = acca.acc_get_all_actions() actions2 = [] roles2 = [] for (id, name, dummy) in actions: actions2.append([id, name]) for col in [(('add', 'addauthorization'), ('modify', 'modifyauthorizations'), ('remove', 'deleteroleaction')), (('show details', 'showactiondetails'), )]: actions2[-1].append('<a href="%s?id_action=%s&reverse=1">%s' '</a>' % (col[0][1], id, col[0][0])) for (str, function) in col[1:]: actions2[-1][-1] += ' / <a href="%s?id_action=%s&' \ 'reverse=1">%s</a>' % (function, id, str) output = """ <dl> <dt>Authorizations/Roles:</dt> <dd>these terms means almost the same, but an authorization is a <br /> connection between a role and an action (possibly) containing arguments.</dd> <dt>Actions:</dt> <dd>see all the information attached to an action.</dd> </dl> """ output += tupletotable(header=header, tuple=actions2) extra = """ <dl> <dt><a href="addrole">Create new role</a> <dd>go here to add a new role. </dl> """ 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 = """ <p> search for users to display. </p> """ # remove letters not allowed in an email email_user_pattern = cleanstring_email(email_user_pattern) text = ' <span class="adminlabel">1. search for user</span>\n' text += ' <input class="admin_wvar" type="text" name="email_user_pattern"'\ ' value="%s" />\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<>'' AND email RLIKE %s - ORDER BY email LIMIT %s""", (email_user_pattern, MAXPAGEUSERS+1)) + try: + users1 = run_sql("""SELECT id, email FROM user WHERE email<>'' AND email RLIKE %s + ORDER BY email LIMIT %s""", (email_user_pattern, MAXPAGEUSERS+1)) + except OperationalError: + users1 = () if not users1: output += '<p>no matching users</p>' 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('<a href="%s?email_user_pattern=%s&' 'id_user=%s">%s</a>' % (col[0][1], email_user_pattern, id, col[0][0])) for (str, function) in col[1:]: users[-1][-1] += ' / <a href="%s?email_user_pattern' \ '=%s&id_user=%s&reverse=1">%s</a>' % \ (function, email_user_pattern, id, str) output += '<p>found <strong>%s</strong> matching users:</p>' % \ (len(users1), ) output += tupletotable(header=['id', 'email', 'roles', ''], tuple=users) if len(users1) > MAXPAGEUSERS: output += '<p><strong>only showing the first %s users, ' \ 'narrow your search...</strong></p>' % (MAXPAGEUSERS, ) return index(req=req, title='User Administration', subtitle=subtitle, body=[output], adminarea=2) def perform_resetarea(req): """create the reset area menu page.""" (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) output = """ <dl> <dt><a href="resetdefaultsettings">Reset to Default Authorizations</a> <dd>remove all changes that has been done to the roles and <br /> add only the default authorization settings. <dt><a href="adddefaultsettings">Add Default Authorizations</a> <dd>keep all changes and add the default authorization settings. </dl> """ 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 = """ <p> before you reset the settings, we need some users<br /> to connect to <strong>%s</strong>.<br /> enter as many e-mail addresses you want and press <strong>reset</strong>.<br /> <strong>confirm reset settings</strong> when you have added enough e-mails.<br /> <strong>%s</strong> is added as default. </p>""" % (SUPERADMINROLE, CFG_SITE_ADMIN_EMAIL) # add more superusers output += """ <p>enter user e-mail addresses: </p> <form action="resetdefaultsettings" method="POST">""" for email in superusers: output += ' <input type="hidden" name="superusers" value="%s" />' % (email, ) output += """ <span class="adminlabel">e-mail</span> <input class="admin_wvar" type="text" name="superusers" /> <input class="adminbutton" type="submit" value="add e-mail" /> </form>""" if superusers: # remove emails output += """ <form action="resetdefaultsettings" method="POST"> have you entered wrong data? <input class="adminbutton" type="submit" value="remove all e-mails" /> </form> """ # superusers confirm table start = '<form action="resetdefaultsettings" method="POST">' extra = ' <input type="hidden" name="confirm" value="1" />' for email in superusers: extra += '<input type="hidden" name="superusers" value="%s" />' % (email, ) extra += ' <input class="adminbutton" type="submit" value="confirm to reset settings" />' end = '</form>' output += '<p><strong>reset default settings</strong> with the users below? </p>' 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 += '<p>successfully reset default settings</p>' else: output += '<p>sorry, could not reset default settings</p>' 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 = """ <p> before you add the settings, we need some users<br /> to connect to <strong>%s</strong>.<br /> enter as many e-mail addresses you want and press <strong>add</strong>.<br /> <strong>confirm add settings</strong> when you have added enough e-mails.<br /> <strong>%s</strong> is added as default. </p>""" % (SUPERADMINROLE, CFG_SITE_ADMIN_EMAIL) # add more superusers output += """ <p>enter user e-mail addresses: </p> <form action="adddefaultsettings" method="POST">""" for email in superusers: output += ' <input type="hidden" name="superusers" value="%s" />' % (email, ) output += """ <span class="adminlabel">e-mail</span> <input class="admin_wvar" type="text" name="superusers" /> <input class="adminbutton" type="submit" value="add e-mail" /> </form> """ if superusers: # remove emails output += """ <form action="adddefaultsettings" method="POST"> have you entered wrong data? <input class="adminbutton" type="submit" value="remove all e-mails" /> </form> """ # superusers confirm table start = '<form action="adddefaultsettings" method="POST">' extra = ' <input type="hidden" name="confirm" value="1" />' for email in superusers: extra += '<input type="hidden" name="superusers" value="%s" />' % (email, ) extra += ' <input class="adminbutton" type="submit" value="confirm to add settings" />' end = '</form>' output += '<p><strong>add default settings</strong> with the users below? </p>' output += tupletotable(header=['e-mail address'], tuple=superusers, start=start, extracolumn=extra, end=end) if confirm in [1, "1"]: res = acca.acc_add_default_settings(superusers) if res: output += '<p>successfully added default settings</p>' else: output += '<p>sorry, could not add default settings</p>' return index(req=req, title='Add Default Settings', subtitle='add settings', body=[output], adminarea=6) def perform_manageaccounts(req, mtype='', content='', confirm=0): """start area for managing accounts.""" (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) subtitle = 'Overview' fin_output = '' fin_output += """ <table> <tr> <td><b>Menu</b></td> </tr> <tr> <td>0. <small><a href="%s/admin/webaccess/webaccessadmin.py/manageaccounts?mtype=perform_showall">Show all</a></small></td> <td>1. <small><a href="%s/admin/webaccess/webaccessadmin.py/manageaccounts?mtype=perform_accesspolicy#1">Access policy</a></small></td> <td>2. <small><a href="%s/admin/webaccess/webaccessadmin.py/manageaccounts?mtype=perform_accountoverview#2">Account overview</a></small></td> <td>3. <small><a href="%s/admin/webaccess/webaccessadmin.py/manageaccounts?mtype=perform_createaccount#3">Create account</a></small></td> <td>4. <small><a href="%s/admin/webaccess/webaccessadmin.py/manageaccounts?mtype=perform_modifyaccounts#4">Edit accounts</a></small></td> </tr> </table> """ % (CFG_SITE_URL, CFG_SITE_URL, CFG_SITE_URL, CFG_SITE_URL, CFG_SITE_URL) 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 += "<br />" 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 += "<br />" 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 += "<br />" 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 += "<br />" if mtype == "perform_becomeuser" and content: fin_output += content elif mtype == "perform_becomeuser" or mtype == "perform_showall": fin_output += perform_becomeuser(req, callback='') fin_output += "<br />" 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 = """<a name="1"></a>1. Access policy. <small>[<a title="See guide" href="%s/help/admin/webaccess-admin-guide#4">?</a>]</small>""" % CFG_SITE_URL 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)<br />" output += "<br /><b>Current settings:</b><br />" output += "Site status: %s<br />" % (site_policy[CFG_ACCESS_CONTROL_LEVEL_SITE]) output += "Guest accounts allowed: %s<br />" % (CFG_ACCESS_CONTROL_LEVEL_GUESTS == 0 and "Yes" or "No") output += "Account policy: %s<br />" % (account_policy[CFG_ACCESS_CONTROL_LEVEL_ACCOUNTS]) output += "Allowed email addresses limited: %s<br />" % (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<br />" % (CFG_ACCESS_CONTROL_NOTIFY_ADMIN_ABOUT_NEW_ACCOUNTS == 1 and "Yes" or "No") output += "Send email to user after creating new account: %s<br />" % (CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_NEW_ACCOUNT == 1 and "Yes" or "No") output += "Send email to user when account is activated: %s<br />" % (CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_ACTIVATION == 1 and "Yes" or "No") output += "Send email to user when account is deleted/rejected: %s<br />" % (CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_DELETION == 1 and "Yes" or "No") output += "<br />" output += "<b>Available 'login via' methods:</b><br />" methods = CFG_EXTERNAL_AUTHENTICATION.keys() methods.sort() for system in methods: output += """%s %s<br />""" % (system, (CFG_EXTERNAL_AUTHENTICATION[system][1] and "(Default)" or "")) output += "<br /><b>Changing the settings:</b><br />" 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 = """<a name="2"></a>2. Account overview. <small>[<a title="See guide" href="%s/help/admin/webaccess-admin-guide#4">?</a>]</small>""" % CFG_SITE_URL output = "" res = run_sql("SELECT COUNT(*) FROM user WHERE email=''") output += "Guest accounts: %s<br />" % res[0][0] res = run_sql("SELECT COUNT(*) FROM user WHERE email!=''") output += "Registered accounts: %s<br />" % 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 += ' [<a href="modifyaccounts?email_user_pattern=&limit_to=disabled&maxpage=25&page=1">Activate/Reject accounts</a>]' res = run_sql("SELECT COUNT(*) FROM user") output += "<br />Total nr of accounts: %s<br />" % 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 = """<a name="3"></a>3. Create account. <small>[<a title="See guide" href="%s/help/admin/webaccess-admin-guide#4">?</a>]</small>""" % CFG_SITE_URL output = "" text = ' <span class="adminlabel">Email:</span>\n' text += ' <input class="admin_wvar" type="text" name="email" value="%s" /><br />' % (email, ) text += ' <span class="adminlabel">Password:</span>\n' text += ' <input class="admin_wvar" type="text" name="password" value="%s" /><br />' % (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 email FROM user WHERE email=%s", (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 = send_new_user_account_warning(email, email, password) == 0 if password: output += '<b><span class="info">Account created with password and activated.</span></b>' else: output += '<b><span class="info">Account created without password and activated.</span></b>' if CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_NEW_ACCOUNT == 1: if emailsent: output += '<br /><b><span class="info">An email has been sent to the owner of the account.</span></b>' else: output += '<br /><b><span class="important">Could not send an email to the owner of the account.</span></b>' else: output += '<b><span class="info">An account with the same email already exists.</span></b>' elif confirm in [1, "1"]: output += '<b><span class="info">Please specify an valid email-address.</span></b>' 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 += """<b><span class="info">The account '%s' has been activated.</span></b>""" % 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 = send_account_activated_message(res[0][1], res[0][1], password) if emailsent: output += """<br /><b><span class="info">An email has been sent to the owner of the account.</span></b>""" else: output += """<br /><b><span class="info">Could not send an email to the owner of the account.</span></b>""" elif res[0][2] in [1, "1"]: res2 = run_sql("UPDATE user SET note=0 WHERE id=%s", (userID, )) output += """<b><span class="info">The account '%s' has been set inactive.</span></b>""" % res[0][1] else: output += '<b><span class="info">The account id given does not exist.</span></b>' 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 = """<b><span class="info">The selected account has been deleted, to continue editing, go back to 'Manage Accounts'.</span></b>""" if CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_DELETION == 1: text += """<br /><b><span class="info">An email has been sent to the owner of the account.</span></b>""" else: text = """<b><span class="info">The selected accounts does not exist, please go back and select an account to edit.</span></b>""" return index(req=req, title='Edit Account', subtitle="Edit account", body=[text], adminarea=7, authorized=1) fin_output = """ <table> <tr> <td><b>Menu</b></td> </tr> <tr> <td>0. <small><a href="%s/admin/webaccess/webaccessadmin.py/editaccount?userID=%s">Show all</a></small></td> <td>1. <small><a href="%s/admin/webaccess/webaccessadmin.py/editaccount?userID=%s&mtype=perform_modifylogindata">Modify login-data</a></small></td> <td>2. <small><a href="%s/admin/webaccess/webaccessadmin.py/editaccount?userID=%s&mtype=perform_modifypreferences">Modify preferences</a></small></td> </tr><tr> <td>3. <small><a href="%s/admin/webaccess/webaccessadmin.py/editaccount?userID=%s&mtype=perform_deleteaccount">Delete account</a></small></td> </tr> </table> """ % (CFG_SITE_URL, userID, CFG_SITE_URL, userID, CFG_SITE_URL, userID, CFG_SITE_URL, userID) if mtype == "perform_modifylogindata" and content: fin_output += content elif mtype == "perform_modifylogindata" or not mtype: fin_output += perform_modifylogindata(req, userID, callback='') if mtype == "perform_modifypreferences" and content: fin_output += content elif mtype == "perform_modifypreferences" or not mtype: fin_output += perform_modifypreferences(req, userID, callback='') if mtype == "perform_deleteaccount" and content: fin_output += content elif mtype == "perform_deleteaccount" or not mtype: fin_output += perform_deleteaccount(req, userID, callback='') return index(req=req, title='Edit Account', subtitle="Edit account '%s'" % res[0][1], body=[fin_output], adminarea=7, authorized=1) def perform_becomeuser(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 = """<a name="5"></a>5. Became user. <small>[<a title="See guide" href="%s/help/admin/webaccess-admin-guide#5">?</a>]</small>""" % CFG_SITE_URL res = run_sql("SELECT id FROM user WHERE id=%s", (userID, )) output = "" if res: setUid(req, res[0][0]) redirect_to_url(req, CFG_SITE_URL) else: output += '<b><span class="info">The account id given does not exist.</span></b>' body = [output] if callback: return perform_editaccount(req, userID, mtype='perform_becomeuser', content=addadminbox(subtitle, body), callback='yes') else: return addadminbox(subtitle, body) def perform_modifylogindata(req, userID, nickname='', 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 = """<a name="1"></a>1. Edit login-data. <small>[<a title="See guide" href="%s/help/admin/webaccess-admin-guide#4">?</a>]</small>""" % CFG_SITE_URL res = run_sql("SELECT id, email, nickname FROM user WHERE id=%s", (userID, )) output = "" if res: if not email and not password: email = res[0][1] nickname = res[0][2] text = ' <span class="adminlabel">Account id:</span>%s<br />\n' % userID text = ' <span class="adminlabel">Nickname:</span>\n' text += ' <input class="admin_wvar" type="text" name="nickname" value="%s" /><br />' % (nickname, ) text += ' <span class="adminlabel">Email:</span>\n' text += ' <input class="admin_wvar" type="text" name="email" value="%s" /><br />' % (email, ) text += ' <span class="adminlabel">Password:</span>\n' text += ' <input class="admin_wvar" type="text" name="password" value="%s" /><br />' % (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("SELECT nickname FROM user WHERE nickname=%s AND id<>%s", (nickname, userID)) if res: output += '<b><span class="info">Sorry, the specified nickname is already used.</span></b>' else: res = run_sql("UPDATE user SET email=%s WHERE id=%s", (email, userID)) if password: res = run_sql("UPDATE user SET password=AES_ENCRYPT(email,%s) WHERE id=%s", (password, userID)) else: output += '<b><span class="info">Password not modified.</span></b> ' res = run_sql("UPDATE user SET nickname=%s WHERE id=%s", (nickname, userID)) output += '<b><span class="info">Nickname/email and/or password modified.</span></b>' elif confirm in [1, "1"]: output += '<b><span class="info">Please specify an valid email-address.</span></b>' else: output += '<b><span class="info">The account id given does not exist.</span></b>' body = [output] if callback: return perform_editaccount(req, userID, mtype='perform_modifylogindata', 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 = """<a name="2"></a>2. Modify preferences. <small>[<a title="See guide" href="%s/help/admin/webaccess-admin-guide#4">?</a>]</small>""" % CFG_SITE_URL 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:<br />" text = "" methods = CFG_EXTERNAL_AUTHENTICATION.keys() methods.sort() for system in methods: text += """<input type="radio" name="login_method" value="%s" %s>%s<br />""" % (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 += """<b><span class="info">The login method has been changed</span></b>""" else: output += """<b><span class="info">Nothing to update</span></b>""" else: output += '<b><span class="info">The account id given does not exist.</span></b>' 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 = """<a name="3"></a>3. Delete account. <small>[<a title="See guide" href="%s/help/admin/webaccess-admin-guide#4">?</a>]</small>""" % CFG_SITE_URL res = run_sql("SELECT id, email FROM user WHERE id=%s", (userID, )) output = "" if res: if confirm in [0, "0"]: text = '<b><span class="important">Are you sure you want to delete the account with email: "%s"?</span></b>' % 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 += '<b><span class="info">Account deleted.</span></b>' if CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_DELETION == 1: emailsent = send_account_deleted_message(res[0][1], res[0][1]) else: output += '<b><span class="info">The account id given does not exist.</span></b>' 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 += '<b><span class="info">Account rejected and deleted.</span></b>' if CFG_ACCESS_CONTROL_NOTIFY_USER_ABOUT_DELETION == 1: if not res[0][2] or res[0][2] == "0": emailsent = send_account_rejected_message(res[0][1], res[0][1]) elif res[0][2] == "1": emailsent = send_account_deleted_message(res[0][1], res[0][1]) if emailsent: output += """<br /><b><span class="info">An email has been sent to the owner of the account.</span></b>""" else: output += """<br /><b><span class="info">Could not send an email to the owner of the account.</span></b>""" else: output += '<b><span class="info">The account id given does not exist.</span></b>' 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 = """<a name="4"></a>4. Edit accounts. <small>[<a title="See guide" href="%s/help/admin/webaccess-admin-guide#4">?</a>]</small>""" % CFG_SITE_URL 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 = ' <span class="adminlabel">Email (part of):</span>\n' text += ' <input class="admin_wvar" type="text" name="email_user_pattern" value="%s" /><br />' % (email_user_pattern, ) text += """<span class="adminlabel">Limit to:</span> <select name="limit_to" class="admin_w200"> <option value="all" %s>All accounts</option> <option value="enabled" %s>Active accounts</option> <option value="disabled" %s>Inactive accounts</option> </select><br />""" % ((limit_to=="all" and "selected" or ""), (limit_to=="enabled" and "selected" or ""), (limit_to=="disabled" and "selected" or "")) text += """<span class="adminlabel">Accounts per page:</span> <select name="maxpage" class="admin_wvar"> <option value="25" %s>25</option> <option value="50" %s>50</option> <option value="100" %s>100</option> <option value="250" %s>250</option> <option value="500" %s>500</option> <option value="1000" %s>1000</option> </select><br />""" % ((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: + options = [] 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) + users1 += " AND email RLIKE %s" + options += [email_user_pattern] + users1 += " ORDER BY email LIMIT %s" + options += [maxpage * page + 1] + try: + users1 = run_sql(users1, tuple(options)) + except OperationalError: + users1 = () if not users1: output += '<b><span class="info">There are no accounts matching the email given.</span></b>' 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 '<strong class="info">Active</strong>' or '<strong class="important">Inactive</strong>')]) for col in [(((note=="1" and 'Inactivate' or 'Activate'), 'modifyaccountstatus'), ((note == "0" and 'Reject' or 'Delete'), 'rejectaccount'), ), (('Edit account', 'editaccount'), ),]: users[-1].append('<a href="%s?userID=%s&email_user_pattern=%s&limit_to=%s&maxpage=%s&page=%s&rand=%s">%s</a>' % (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] += ' / <a href="%s?userID=%s&email_user_pattern=%s&limit_to=%s&maxpage=%s&page=%s&rand=%s">%s</a>' % (function, id, email_user_pattern, limit_to, maxpage, page, random.randint(0, 1000), str) users[-1].append('<a href=%s?userID=%s&email_user_pattern=%s&limit_to=%s&maxpage=%s&page=%s&rand=%s">%s</a>' % ('becomeuser', id, email_user_pattern, limit_to, maxpage, page, random.randint(0, 1000), 'Become user')) last = "" next = "" if len(users1) > maxpage: if page > 1: last += '<b><span class="info"><a href="modifyaccounts?email_user_pattern=%s&limit_to=%s&maxpage=%s&page=%s">Last Page</a></span></b>' % (email_user_pattern, limit_to, maxpage, (page - 1)) if len(users1[maxpage * (page - 1):(maxpage * page)]) == maxpage: next += '<b><span class="info"><a href="modifyaccounts?email_user_pattern=%s&limit_to=%s&maxpage=%s&page=%s">Next page</a></span></b>' % (email_user_pattern, limit_to, maxpage, (page + 1)) output += '<b><span class="info">Showing accounts %s-%s:</span></b>' % (1 + maxpage * (page - 1), maxpage * page) else: output += '<b><span class="info">%s matching account(s):</span></b>' % len(users1) output += tupletotable(header=[last, 'id', 'email', 'Status', '', '', next], tuple=users) else: output += '<b><span class="info">Please select which accounts to find and how many to show per page.</span></b>' if content: output += "<br />%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 += """ <p> You are also allowed to be in the <a href="../webaccessadmin.py">Main Admin Area</a> which gives you<br /> the access to the full functionality of WebAccess. </p> """ output += """ <dl> <dt><a href="delegate_adduserrole">Connect users to roles</a></dt> <dd>add users to the roles you have delegation rights to.</dd> <dt><a href="delegate_deleteuserrole">Remove users from roles</a></dt> <dd>remove users from the roles you have delegation rights to.</dd> </dl> <dl> <dt><a href="delegate_adminsetup">Set up delegation rights</a></dt> <dd>specialized area to set up the delegation rights used in the areas above. <br /> you need to be a web administrator to access the area.</dd> </dl> """ 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_get_all_roles() output = """ <p> This is a specialized area to handle a task that also can be handled<br /> from the "add authorization" interface. </p> <p> By handling the delegation rights here you get the advantage of<br /> not having to select the correct action <i>(%s)</i> or<br /> remembering the names of available roles. </p> """ % (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_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 += '<p>previously selected roles: <strong>%s</strong>.</p>' % (names_str, ) extra = """ <dl> <dt><a href="modifyauthorizations?id_role=%s&id_action=%s">Remove delegated roles</a></dt> <dd>use the standard administration area to remove delegation rights you no longer want to be available.</dd> </dl> """ % (id_role_admin, acca.acc_get_action_id(name_action=DELEGATEADDUSERROLE)) else: output += '<p>no previously selected roles.</p>' output += createroleselect(id_role=id_role_delegate, step=2, button='select delegate role', name='id_role_delegate', action='delegate_adminsetup', roles=delegate_roles, id_role_admin=id_role_admin) if str(id_role_delegate) != '0': subtitle = 'step 3 - confirm to add delegation right' name_role_delegate = acca.acc_get_role_name(id_role=id_role_delegate) output += """ <p> <span class="warning"><strong>Warning:</strong> don't hand out delegation rights that can harm the system (e.g. delegating superrole).</span> </p> """ output += createhiddenform(action="delegate_adminsetup", text='let role <strong>%s</strong> delegate rights over role <strong>%s</strong>?' % (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_add_role_action_arguments_names(name_role=name_role_admin, # name_action=DELEGATEADDUSERROLE, # arglistid=-1, # optional=0, # role=name_role_delegate) res1 = acca.acc_add_authorization(name_role=name_role_admin, name_action=DELEGATEADDUSERROLE, optional=0, role=name_role_delegate) if res1: output += '<p>confirm: role <strong>%s</strong> delegates role <strong>%s</strong>.' % (name_role_admin, name_role_delegate) else: output += '<p>sorry, delegation right could not be added,<br />it probably already exists.</p>' # 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_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_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 += """ <p> You do not have the delegation rights over any roles.<br /> If you think you should have such rights, contact a WebAccess Administrator. </p>""" extra = '' else: subtitle = 'step 1 - select role' output += """ <p> Lower level delegation of access rights to roles.<br /> An administrator with all rights have to give you these rights. </p>""" 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 = ' <span class="adminlabel">2. search for user </span>\n' text += ' <input class="admin_wvar" type="text" name="email_user_pattern" value="%s" />\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<>'' AND email RLIKE %s ORDER BY email """, (email_user_pattern, )) + try: + users1 = run_sql("""SELECT id, email FROM user WHERE email<>'' AND email RLIKE %s ORDER BY email """, (email_user_pattern, )) + except OperationalError: + users1 = () # 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)) - + try: + 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)) + except OperationalError: + users2 = () # no users that match the pattern if not (users1 or users2): output += '<p>no qualified users, try new search.</p>' # too many matching users elif len(users1) > MAXSELECTUSERS: output += '<p><strong>%s hits</strong>, too many qualified users, specify more narrow search. (limit %s)</p>' % (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 += '<p>users in brackets are already attached to the role, try another one...</p>' # a user is selected elif email_out: subtitle = "step 4 - confirm to add user" output += createhiddenform(action="delegate_adduserrole", text='add user <strong>%s</strong> to role <strong>%s</strong>?' % (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_add_user_role(id_user=id_user, id_role=id_role) if result and result[2]: subtitle = 'step 5 - confirm user added' output += '<p>confirm: user <strong>%s</strong> added to role <strong>%s</strong>.</p>' % (email_out, name_role) else: subtitle = 'step 5 - user could not be added' output += '<p>sorry, but user could not be added.</p>' extra = """ <dl> <dt><a href="delegate_deleteuserrole?id_role=%s">Remove users from role</a></dt> <dd>remove users from the roles you have delegating rights to.</dd> </dl> """ % (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 = '<p>in progress...</p>' # finding the allowed roles for this user id_admin = getUid(req) 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 += """ <p> You do not have the delegation rights over any roles.<br /> If you think you should have such rights, contact a WebAccess Administrator. </p>""" extra = '' else: subtitle = 'step 1 - select role' output += """ <p> Lower level delegation of access rights to roles.<br /> An administrator with all rights have to give you these rights. </p>""" 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_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_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_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_delete_user_role(id_user=id_user, id_role=id_role) if res: subtitle = 'step 4 - confirm user deleted from role' output += '<p>confirm: deleted user <strong>%s</strong> from role <strong>%s</strong>.</p>' % (email_user, name_role) else: subtitle = 'step 4 - user could not be deleted' output += 'sorry, but user could not be deleted<br />user is probably already deleted.' extra = """ <dl> <dt><a href="delegate_adduserrole?id_role=%s">Connect users to role</a></dt> <dd>add users to the roles you have delegating rights to.</dd> </dl> """ % (id_role, ) return index(req=req, title='Remove users from roles', subtitle=subtitle, body=[output, extra], adminarea=1, authorized=1) def perform_showactiondetails(req, id_action): """show the details of an action. """ (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) output = createactionselect(id_action=id_action, action="showactiondetails", step=1, actions=acca.acc_get_all_actions(), button="select action") if id_action not in [0, '0']: output += actiondetails(id_action=id_action) extra = """ <dl> <dt><a href="addauthorization?id_action=%s&reverse=1">Add new authorization</a></dt> <dd>add an authorization.</dd> <dt><a href="modifyauthorizations?id_action=%s&reverse=1">Modify authorizations</a></dt> <dd>modify existing authorizations.</dd> <dt><a href="deleteroleaction?id_action=%s&reverse=1">Remove role</a></dt> <dd>remove all authorizations from action and a role.</dd> </dl> """ % (id_action, id_action, id_action) body = [output, extra] else: output += '<p>no details to show</p>' body = [output] return index(req=req, title='Show Action Details', subtitle='show action details', body=body, adminarea=4) def actiondetails(id_action=0): """show details of given action. """ output = '' if id_action not in [0, '0']: name_action = acca.acc_get_action_name(id_action=id_action) output += '<p>action details:</p>' output += tupletotable(header=['id', 'name', 'description', 'allowedkeywords', 'optional'], tuple=[acca.acc_get_action_details(id_action=id_action)]) roleshlp = acca.acc_get_action_roles(id_action=id_action) if roleshlp: roles = [] for (id, name, dummy) in roleshlp: roles.append([id, name, '<a href="simpleauthorization?id_role=%s&id_action=%s">show authorization details</a>' % (id, id_action), '<a href="showroleusers?id_role=%s">show connected users</a>' % (id, )]) roletable = tupletotable(header=['id', 'name', '', ''], tuple=roles) output += '<p>roles connected to %s:</p>\n' % (headerstrong(action=name_action, query=0), ) output += roletable else: output += '<p>no roles connected to %s.</p>\n' % (headerstrong(action=name_action, query=0), ) else: output += '<p>no details to show</p>' return output def perform_addrole(req, id_role=0, name_role='', description='put description here.', firerole_def_src=CFG_ACC_EMPTY_ROLE_DEFINITION_SRC, confirm=0): """form to add a new role with these values: name_role - name of the new role description - optional description of the role """ (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) name_role = cleanstring(name_role) title='Add Role' subtitle = 'step 1 - give values to the requested fields' output = """ <form action="addrole" method="POST"> <table><tbody><tr><td align='right' valign='top'> <span class="adminlabel">role name </span> </td><td> <input class="admin_wvar" type="text" name="name_role" value="%s" /> </td></tr><tr><td align='right' valign='top'> <span class="adminlabel">description </span> </td><td> <textarea class="admin_wvar" rows="6" cols="80" name="description">%s</textarea> </td></tr><tr><td align='right' valign='top'> <span class="adminlabel">firewall like role definition [<a href="/help/admin/webaccess-admin-guide#6">?</a>]</span> </td><td> <textarea class="admin_wvar" rows="6" cols="80" name="firerole_def_src">%s</textarea> </td></tr> <tr><td></td><td>See the <a href="listgroups" target="_blank">list of groups</a> for a hint about which group names you can use.</td></tr> <tr><td></td><td> <input class="adminbutton" type="submit" value="add role" /> </td></tr></tbody></table> </form> """ % (escape(name_role, '"'), escape(description), escape(firerole_def_src)) if name_role: # description must be changed before submitting subtitle = 'step 2 - confirm to add role' internaldesc = '' if description != 'put description here.': internaldesc = description try: firerole_def_ser = serialize(compile_role_definition(firerole_def_src)) except InvenioWebAccessFireroleError, msg: output += "<strong>%s</strong>" % msg else: text = """ add role with: <br />\n name: <strong>%s</strong> <br />""" % (name_role, ) if internaldesc: text += 'description: <strong>%s</strong>?\n' % (description, ) output += createhiddenform(action="addrole", text=text, name_role=escape(name_role, '"'), description=escape(description, '"'), firerole_def_src=escape(firerole_def_src, '"'), confirm=1) if confirm not in ["0", 0]: result = acca.acc_add_role(name_role=name_role, description=internaldesc, firerole_def_ser=firerole_def_ser, firerole_def_src=firerole_def_src) if result: subtitle = 'step 3 - role added' output += '<p>role added: </p>' result = list(result) result[3] = result[3].replace('\n', '<br/>') result = tuple(result) output += tupletotable(header=['id', 'role name', 'description', 'firewall like role definition'], tuple=[result]) else: subtitle = 'step 3 - role could not be added' output += '<p>sorry, could not add role, <br />role with the same name probably exists.</p>' id_role = acca.acc_get_role_id(name_role=name_role) extra = """ <dl> <dt><a href="addauthorization?id_role=%s">Add authorization</a></dt> <dd>start adding new authorizations to role %s.</dd> </dl> <dt><a href="adduserrole?id_role=%s">Connect user</a></dt> <dd>connect a user to role %s.</dd> <dl> </dl>""" % (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_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 = """ <form action="modifyrole" method="POST"> <table><tbody><tr><td align='right' valign='top'> <input type="hidden" name="id_role" value="%s" /> <span class="adminlabel">role name </span> </td><td> <input class="admin_wvar" type="text" name="name_role" value="%s" /> <br /> </td></tr><tr><td align='right' valign='top'> <span class="adminlabel">description </span> </td><td> <textarea class="admin_wvar" rows="6" cols="80" name="description">%s</textarea> <br /> </td></tr><tr><td align='right' valign='top'> <span class="adminlabel">firewall like role definition</span> [<a href="/help/admin/webaccess-admin-guide#6">?</a>] </td><td> <textarea class="admin_wvar" rows="6" cols="80" name="firerole_def_src">%s</textarea><br /> </td></tr> <tr><td></td><td>See the <a href="listgroups" target="_blank">list of groups</a> for a hint about which group names you can use.</td></tr> <tr><td></td><td> <input class="adminbutton" type="submit" value="modify role" /> <input type="hidden" name="modified" value="1" /> </td></tr></tbody></table> </form> """ % (id_role, escape(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: <br />\n name: <strong>%s</strong> <br />""" % (name_role, ) if internaldesc: text += 'description: <strong>%s</strong>?<br />' % (description, ) text += 'firewall like role definition: <strong>%s</strong>' % firerole_def_src.replace('\n', '<br />') try: firerole_def_ser = serialize(compile_role_definition(firerole_def_src)) except InvenioWebAccessFireroleError, msg: subtitle = 'step 2 - role could not be modified' output += '<p>sorry, could not modify role because of troubles with its definition:<br />%s</p>' % 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_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 += '<p>role modified: </p>' output += tupletotable(header=['id', 'role name', 'description', 'firewall like role definition'], tuple=[(id_role, name_role, description, firerole_def_src.replace('\n', '<br />'))]) else: subtitle = 'step 2 - role could not be modified' output += '<p>sorry, could not modify role, <br />please contact the administrator.</p>' 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_get_role_name(id_role=id_role) output = createroleselect(id_role=id_role, action="deleterole", step=1, 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 <strong>%s</strong> and all connections?' % (name_role, ), id_role=id_role, confirm=1) if confirm: res = acca.acc_delete_role(id_role=id_role) subtitle = 'step 3 - confirm role deleted' if res: output += "<p>confirm: role <strong>%s</strong> deleted.<br />" % (name_role, ) output += "<strong>%s</strong> entries were removed.</p>" % (res, ) else: output += "<p>sorry, the role could not be deleted.</p>" elif id_role != "0": output += '<p>the role has been deleted...</p>' 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_get_all_roles(), button="select role") if id_role not in [0, '0']: name_role = acca.acc_get_role_name(id_role=id_role) output += roledetails(id_role=id_role) extra = """ <dl> <dt><a href="modifyrole?id_role=%(id_role)s">Modify role</a><dt> <dd>modify the role you are seeing</dd> <dt><a href="addauthorization?id_role=%(id_role)s">Add new authorization</a></dt> <dd>add an authorization.</dd> <dt><a href="modifyauthorizations?id_role=%(id_role)s">Modify authorizations</a></dt> <dd>modify existing authorizations.</dd> </dl> <dl> <dt><a href="adduserrole?id_role=%(id_role)s">Connect user</a></dt> <dd>connect a user to role %(name_role)s.</dd> <dt><a href="deleteuserrole?id_role=%(id_role)s">Remove user</a></dt> <dd>remove a user from role %(name_role)s.</dd> </dl> """ % {'id_role' : id_role, 'name_role' : name_role} body = [output, extra] else: output += '<p>no details to show</p>' body = [output] return index(req=req, title='Show Role Details', subtitle='show role details', body=body, adminarea=3) def roledetails(id_role=0): """create the string to show details about a role. """ name_role = acca.acc_get_role_name(id_role=id_role) usershlp = acca.acc_get_role_users(id_role) users = [] for (id, email, dummy) in usershlp: users.append([id, email, '<a href="showuserdetails?id_user=%s">show user details</a>' % (id, )]) usertable = tupletotable(header=['id', 'email'], tuple=users) actionshlp = acca.acc_get_role_actions(id_role) actions = [] for (action_id, name, dummy) in actionshlp: actions.append([action_id, name, '<a href="showactiondetails?id_role=%s&id_action=%s">show action details</a>' % (id_role, action_id), '<a href="simpleauthorization?id_role=%s&id_action=%s">show authorization details</a>' % (id_role, action_id)]) actiontable = tupletotable(header=['id', 'name', '', ''], tuple=actions) # show role details details = '<p>role details:</p>' role_details = acca.acc_get_role_details(id_role=id_role) if role_details[3] is None: role_details[3] = '' role_details[3] = role_details[3].replace('\n', '<br />') # Hack for preformatting firerole rules details += tupletotable(header=['id', 'name', 'description', 'firewall like role definition'], tuple=[role_details]) # show connected users details += '<p>users connected to %s:</p>' % (headerstrong(role=name_role, query=0), ) if users: details += usertable else: details += '<p>no users connected.</p>' # show connected authorizations details += '<p>authorizations for %s:</p>' % (headerstrong(role=name_role, query=0), ) if actions: details += actiontable else: details += '<p>no authorizations connected</p>' 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_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_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 = ' <span class="adminlabel">2. search for user </span>\n' text += ' <input class="admin_wvar" type="text" name="email_user_pattern" value="%s" />\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<>'' AND email RLIKE %s ORDER BY email """, (email_user_pattern, )) + try: + users1 = run_sql("""SELECT id, email FROM user WHERE email<>'' AND email RLIKE %s ORDER BY email """, (email_user_pattern, )) + except OperationalError: + users1 = () # 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)) + try: + 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)) + except OperationalError: + users2 = () # no users that match the pattern if not (users1 or users2): output += '<p>no qualified users, try new search.</p>' elif len(users1) > MAXSELECTUSERS: output += '<p><strong>%s hits</strong>, too many qualified users, specify more narrow search. (limit %s)</p>' % (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 += '<p>users in brackets are already attached to the role, try another one...</p>' # a user is selected elif email_out: subtitle = "step 4 - confirm to add user" output += createhiddenform(action="adduserrole", text='add user <strong>%s</strong> to role <strong>%s</strong>?' % (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_add_user_role(id_user=id_user, id_role=id_role) if result and result[2]: subtitle = 'step 5 - confirm user added' output += '<p>confirm: user <strong>%s</strong> added to role <strong>%s</strong>.</p>' % (email_out, name_role) else: subtitle = 'step 5 - user could not be added' output += '<p>sorry, but user could not be added.</p>' extra = """ <dl> <dt><a href="addrole">Create new role</a></dt> <dd>go here to add a new role.</dd> </dl> """ if str(id_role) != "0": extra += """ <dl> <dt><a href="deleteuserrole?id_role=%s">Remove users</a></dt> <dd>remove users from role %s.</dd> <dt><a href="showroleusers?id_role=%s">Connected users</a></dt> <dd>show all users connected to role %s.</dd> </dl> <dl> <dt><a href="addauthorization?id_role=%s">Add authorization</a></dt> <dd>start adding new authorizations to role %s.</dd> </dl> """ % (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_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 = ' <span class="adminlabel">1. search for user </span>\n' text += ' <input class="admin_wvar" type="text" name="email_user_pattern" value="%s" />\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<>'' AND email RLIKE %s ORDER BY email """, (email_user_pattern, )) + try: + users1 = run_sql("""SELECT id, email FROM user WHERE email<>'' AND email RLIKE %s ORDER BY email """, (email_user_pattern, )) + except OperationalError: + users1 = () users = [] for (id, email) in users1: users.append([id, email, '']) # no users if not users: output += '<p>no qualified users, try new search.</p>' # too many users elif len(users) > MAXSELECTUSERS: output += '<p><strong>%s hits</strong>, too many qualified users, specify more narrow search. (limit %s)</p>' % (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_get_user_roles(id_user=id_user) # all the roles, lists are sorted on the background of these... all_roles = acca.acc_get_all_roles() # sort the roles in connected and not connected roles for (id, name, description, dummy, dummy) 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_get_role_name(id_role=-int(id_role)) output += '<p>role %s already connected to the user, try another one...<p>' % (name_role, ) elif int(id_role): subtitle = 'step 4 - confirm to add role to user' output += createhiddenform(action='addroleuser', text='add role <strong>%s</strong> to user <strong>%s</strong>?' % (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_add_user_role(id_user=id_user, id_role=id_role) if result and result[2]: subtitle = 'step 5 - confirm role added' output += '<p>confirm: role <strong>%s</strong> added to user <strong>%s</strong>.</p>' % (name_role, email_out) else: subtitle = 'step 5 - role could not be added' output += '<p>sorry, but role could not be added</p>' extra = """ <dl> <dt><a href="addrole">Create new role</a></dt> <dd>go here to add a new role.</dd> """ if int(id_user) and con_roles: extra += """ </dl> <dl> <dt><a href="deleteuserrole?id_user=%s&reverse=1">Remove roles</a></dt> <dd>disconnect roles from user %s.</dd> </dl> """ % (id_user, email_out) if int(id_role): if int(id_role) < 0: id_role = -int(id_role) extra += """ <dl> <dt><a href="deleteuserrole?id_role=%s">Remove users</a></dt> <dd>disconnect users from role %s.<dd> </dl> """ % (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_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_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_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 += '<p>no need to remove roles from user <strong>%s</strong>,<br />user is not connected to any roles.</p>' % (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_get_user_roles(id_user=id_user) all_roles = acca.acc_get_all_roles() roles = [] for (id, name, desc, dummy, dummy) 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_delete_user_role(id_user=id_user, id_role=id_role) if res: subtitle = 'step 4 - confirm delete of user' output += '<p>confirm: deleted user <strong>%s</strong> from role <strong>%s</strong>.</p>' % (email_user, name_role) else: subtitle = 'step 4 - user could not be deleted' output += 'sorry, but user could not be deleted<br />user is probably already deleted.' extra = '' if str(id_role) != "0": extra += """ <dl> <dt><a href="adduserrole?id_role=%s">Connect user</a></dt> <dd>add users to role %s.</dd> """ % (id_role, name_role) if int(reverse): extra += """ <dt><a href="deleteuserrole?id_role=%s">Remove user</a></dt> <dd>remove users from role %s.</dd> """ % (id_role, name_role) extra += '</dl>' if str(id_user) != "0": extra += """ <dl> <dt><a href="addroleuser?email_user_pattern=%s&id_user=%s">Connect role</a></dt> <dd>add roles to user %s.</dd> """ % (email_user, id_user, email_user) if not int(reverse): extra += """ <dt><a href="deleteuserrole?id_user=%s&email_user_pattern=%s&reverse=1">Remove role</a></dt> <dd>remove roles from user %s.</dd> """ % (id_user, email_user, email_user) extra += '</dl>' if extra: body = [output, extra] else: body = [output] return index(req=req, title=title, subtitle=subtitle, body=body, adminarea=adminarea) def perform_showuserdetails(req, id_user=0): """show the details of a user. """ (auth_code, auth_message) = is_adminuser(req) if auth_code != 0: return mustloginpage(req, auth_message) if id_user not in [0, '0']: output = userdetails(id_user=id_user) email_user = acca.acc_get_user_email(id_user=id_user) extra = """ <dl> <dt><a href="addroleuser?id_user=%s&email_user_pattern=%s">Connect role</a></dt> <dd>connect a role to user %s.</dd> <dt><a href="deleteuserrole?id_user=%s&reverse=1">Remove role</a></dt> <dd>remove a role from user %s.</dd> </dl> """ % (id_user, email_user, email_user, id_user, email_user) body = [output, extra] else: body = ['<p>no details to show</p>'] return index(req=req, title='Show User Details', subtitle='show user details', body=body, adminarea=5) def userdetails(id_user=0): """create the string to show details about a user. """ # find necessary details email_user = acca.acc_get_user_email(id_user=id_user) userroles = acca.acc_get_user_roles(id_user=id_user) conn_roles = [] # find connected roles for (id, name, desc, dummy, dummy) in acca.acc_get_all_roles(): if (id, ) in userroles: conn_roles.append([id, name, desc]) conn_roles[-1].append('<a href="showroledetails?id_role=%s">show details</a>' % (id, )) if conn_roles: # print details details = '<p>roles connected to user <strong>%s</strong></p>' % (email_user, ) details += tupletotable(header=['id', 'name', 'description', ''], tuple=conn_roles) else: details = '<p>no roles connected to user <strong>%s</strong>.</p>' % (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_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 = """ <dl> <dt><a href="addrole">Create new role</a></dt> <dd>go here to add a new role.</dd> </dl> """ # 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_get_all_roles(), reverse=reverse) if str(id_role) != "0": subtitle = 'step 2 - select action' 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_get_all_actions(), reverse=reverse) if str(id_action) != "0": subtitle = 'step 2 - select role' 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 += """ <dl> <dt><a href="addauthorization?id_action=%s&reverse=1">Add authorization</a></dt> <dd>add authorizations to action %s.</dd> </dl> """ % (id_action, name_action) else: extra += """ <dl> <dt><a href="addauthorization?id_role=%s">Add authorization</a></dt> <dd>add authorizations to role %s.</dd> </dl> """ % (id_role, name_role) subtitle = 'step 3 - enter values for the keywords\n' output += """ <form action="addauthorization" method="POST"> <input type="hidden" name="id_role" value="%s"> <input type="hidden" name="id_action" value="%s"> <input type="hidden" name="reverse" value="%s"> """ % (id_role, id_action, reverse) # the actions argument keywords res_keys = acca.acc_get_action_keywords(id_action=id_action) # res used to display existing authorizations # res used to determine if showing "create connection without arguments" res_auths = acca.acc_find_possible_actions(id_role, id_action) if not res_keys: # action without arguments if not res_auths: output += """ <input type="hidden" name="confirm" value="1"> create connection between %s? <input class="adminbutton" type="submit" value="confirm"> </form> """ % (headerstrong(role=name_role, action=name_action, query=0), ) else: output += '<p><strong>connection without arguments is already created.</strong></p>' else: # action with arguments optionalargs = acca.acc_get_action_is_optional(id_action=id_action) output += '<span class="adminlabel">3. authorized arguments</span><br />' if optionalargs: # optional arguments output += """ <p> <input type="radio" name="optional" value="1" %s /> connect %s to %s for any arguments <br /> <input type="radio" name="optional" value="0" %s /> connect %s to %s for only these argument cases: </p> """ % (optional and 'checked="checked"' or '', name_role, name_action, not optional and 'checked="checked"' or '', name_role, name_action) # list the arguments allkeys = 1 for key in res_keys: output += '<span class="adminlabel" style="margin-left: 30px;">%s </span>\n <input class="admin_wvar" type="text" name="%s"' % (key, key) try: val = keywords[key] = cleanstring_argumentvalue(keywords[key]) if val: output += 'value="%s" ' % (val, ) else: allkeys = 0 except KeyError: allkeys = 0 output += ' /> <br />\n' output = output[:-5] + ' <input class="adminbutton" type="submit" value="create authorization -->" />\n' output += '</form>\n' # ask for confirmation if str(allkeys) != "0" or optional: keys = keywords.keys() keys.reverse() subtitle = 'step 4 - confirm add of authorization\n' text = """ create connection between <br /> %s <br /> """ % (headerstrong(role=name_role, action=name_action, query=0), ) if optional: text += 'withouth arguments' keywords = {} else: for key in keys: text += '<strong>%s</strong>: %s \n' % (key, keywords[key]) output += createhiddenform(action="addauthorization", text=text, id_role=id_role, id_action=id_action, reverse=reverse, confirm=1, optional=optional, **keywords) # show existing authorizations, found authorizations further up in the code... # res_auths = acca.acc_find_possible_actions(id_role, id_action) output += '<p>existing authorizations:</p>' if res_auths: output += tupletotable(header=res_auths[0], tuple=res_auths[1:]) # shortcut to modifying authorizations extra += """ <dl> <dt><a href="modifyauthorizations?id_role=%s&id_action=%s&reverse=%s">Modify authorizations</a></dt> <dd>modify the existing authorizations.</dd> </dl> """ % (id_role, id_action, reverse) else: output += '<p>no details to show</p>' # user confirmed to add entries if confirm: subtitle = 'step 5 - confirm authorization added' res1 = acca.acc_add_authorization(name_role=name_role, name_action=name_action, optional=optional, **keywords) if res1: res2 = acca.acc_find_possible_actions(id_role, id_action) arg = res1[0][3] # the arglistid new = [res2[0]] for row in res2[1:]: if int(row[0]) == int(arg): new.append(row) newauths = tupletotable(header=new[0], tuple=new[1:]) newentries = tupletotable(header=['role id', 'action id', 'argument id', '#'], tuple=res1) st = 'style="vertical-align: top"' output += """ <p>new authorization and entries:</p> <table><tr> <td class="admintd" %s>%s</td> <td class="admintd" %s>%s</td> </tr></table> """ % (st, newauths, st, newentries) else: output += '<p>sorry, authorization could not be added,<br />it probably already exists</p>' # 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_get_all_roles(), reverse=reverse) if id_role != "0": 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_get_all_actions(), reverse=reverse) if id_action != "0": 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_find_possible_actions(id_role, id_action) if res: output += '<p>authorizations that will be deleted:</p>' 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_delete_role_action(id_role=id_role, id_action=id_action) if res: output += '<p>confirm: removed %s from %s<br />' % (headerstrong(action=id_action), headerstrong(role=id_role)) output += '<strong>%s</strong> entries were removed.</p>' % (res, ) else: output += '<p>sorry, no entries could be removed.</p>' 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_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 = """ <dl> <dt><a href="addrole">Create new role</a></dt> <dd>go here to add a new role.</dd> </dl> """ if id_role or id_action: extra += '\n<dl>\n' if id_role and id_action: extra += """ <dt><a href="addauthorization?id_role=%s&id_action=%s&reverse=%s">Add authorizations</a></dt> <dd>add an authorization to the existing ones.</dd> """ % (id_role, id_action, reverse) if id_role: extra += """ <dt><a href="addauthorization?id_role=%s">Add authorizations</a></dt> <dd>add to role %s.</dd> """ % (id_role, name_role) if id_action: extra += """ <dt><a href="addauthorization?id_action=%s&reverse=1">Add authorizations</a></dt> <dd>add to action %s.</dd> """ % (id_action, name_action) extra += '\n</dl>\n' if not reverse: # role -> action adminarea = 3 subtitle = 'step 1 - select the role' output += createroleselect(id_role=str(id_role), action="modifyauthorizations", step=1, roles=acca.acc_get_all_roles(), reverse=reverse) if id_role: rolacts = acca.acc_get_role_actions(id_role=id_role) subtitle = 'step 2 - select the action' output += createactionselect(id_action=str(id_action), action="modifyauthorizations", step=2, actions=rolacts, id_role=id_role, reverse=reverse) else: adminarea = 4 # action -> role subtitle = 'step 1 - select the action' output += createactionselect(id_action=str(id_action), action="modifyauthorizations", step=1, actions=acca.acc_get_all_actions(), reverse=reverse) if id_action: actroles = acca.acc_get_action_roles(id_action=id_action) subtitle = 'step 2 - select the role' output += createroleselect(id_role=str(id_role), action="modifyauthorizations", step=2, roles=actroles, id_action=id_action, reverse=reverse) if errortext: output += '<p>%s</p>' % (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_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_find_possible_actions(id_role, id_action) output += 'authorizations after <strong>%s</strong>.<br />\n' % (sel, ) elif sel and authids: output += 'confirm choice of authorizations and modification.<br />\n' else: output += 'select authorizations and perform modification.<br />\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 += '<form action="%s" method="POST">\n' % ('modifyauthorizations', ) for hiddenid in hiddenids: output += '<input type="hidden" name="authids" value="%s" />\n' % (hiddenid, ) # choose what to do if sel == 'split groups': output += '<p>split groups containing:</p>' elif sel == 'merge groups': output += '<p>merge groups containing:</p>' elif sel == 'delete selected': output += '<p>delete selected entries:</p>' extracolumn = '<input type="checkbox" name="confirm" value="1" />\n' extracolumn += '<input class="adminbutton" type="submit" value="confirm" />\n' # show the entries here... output += tupletotable_onlyselected(header=res[0], tuple=res[1:], selected=hiddenids, extracolumn=extracolumn) output += '<input type="hidden" name="id_role" value="%s" />\n' \ % (id_role, ) output += '<input type="hidden" name="id_action" value="%s" />\n' \ % (id_action, ) output += '<input type="hidden" name="sel" value="%s" />\n' \ % (sel, ) output += '<input type="hidden" name="reverse" value="%s" />\n' \ % (reverse, ) output += '</form>' # tried to perform modification without something selected elif sel and not authids and not confirm: output += '<p>no valid groups selected</p>' # 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_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 = '<input type="hidden" name="id_role" value="%s" /> \n' \ % (id_role, ) hidden += '<input type="hidden" name="id_action" value="%s" /> \n' \ % (id_action, ) hidden += '<input type="hidden" name="reverse" value="%s" /> \n' \ % (reverse, ) button = '<input type="submit" class="adminbutton" ' \ 'value="delete selected" name="sel" />\n' if argnum > 1: button += '<input type="submit" class="adminbutton" ' \ 'value="split groups" name="sel" />\n' button += '<input type="submit" class="adminbutton" ' \ 'value="merge groups" name="sel" />\n' hdrstr = '' for h in [''] + header + ['']: hdrstr += ' <th class="adminheader">%s</th>\n' % (h, ) if hdrstr: hdrstr = ' <tr>\n%s\n </tr>\n' % (hdrstr, ) output = '<form action="modifyauthorizations" method="POST">\n' output += '<table class="admin_wvar_nomargin"> \n' output += hdrstr output += '<tr><td>%s</td></tr>\n' % (hidden, ) align = ['admintdleft'] * len(tuple2[0]) try: align[1] = 'admintdright' except IndexError: pass output += '<tr>' for i in range(len(tuple2[0])): output += '<td class="%s">%s</td>\n' % (align[i], tuple2[0][i]) output += '<td rowspan="%s" style="vertical-align: bottom">\n%s\n</td>\n' \ % (len(tuple2), button) output += '</tr>\n' for row in tuple2[1:]: output += ' <tr>\n' for i in range(len(row)): output += '<td class="%s">%s</td>\n' % (align[i], row[i]) output += ' </tr>\n' output += '</table>\n</form>\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_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_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_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_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_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 <i>%s</i>' % (key, ids[key]) continue res = run_sql("""SELECT %%s FROM %s WHERE id = %%s""" % table, (value, ids[key])) if res: if output: output += ' and ' output += ' %s <i>%s</i>' % (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 <strong>%s</strong>' % (key, ids[key]) continue if query: res = run_sql("""SELECT %%s FROM %s WHERE id = %%s""" % table, (value, ids[key])) if res: if output: output += ' and ' output += ' %s <strong>%s</strong>' % (key, res[0][0]) else: if output: output += ' and ' output += ' %s <strong>%s</strong>' % (key, ids[key]) return output def startpage(): """create the menu for the startpage""" body = """ <table class="admin_wvar" width="100%" summary=""> <thead> <tr> <th class="adminheaderleft">selection for WebAccess Admin</th> </tr> </thead> <tbody> <tr> <td> <dl> <dt><a href="webaccessadmin.py/rolearea">Role Area</a></dt> <dd>main area to configure administration rights and authorization rules.</dd> <dt><a href="webaccessadmin.py/actionarea">Action Area</a></dt> <dd>configure administration rights with the actions as starting point.</dd> <dt><a href="webaccessadmin.py/userarea">User Area</a></dt> <dd>configure administration rights with the users as starting point.</dd> <dt><a href="webaccessadmin.py/resetarea">Reset Area</a></dt> <dd>reset roles, actions and authorizations.</dd> <dt><a href="webaccessadmin.py/manageaccounts">Manage accounts Area</a></dt> <dd>manage user accounts.</dd> <dt><a href="webaccessadmin.py/delegate_startarea">Delegate Rights - With Restrictions</a></dt> <dd>delegate your rights for some roles.</dd> </dl> </td> </tr> </tbody> </table>""" 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_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 = '<p>authorizations for %s:</p>' \ % (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_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, '<a href="showuserdetails?' 'id_user=%s">show user details</a>' % (role_id, )]) output = '<p>users connected to %s:</p>' \ % (headerstrong(role=id_role), ) output += tupletotable(header=['id', 'name', ''], tuple=users) else: output = 'no users connected to role <strong>%s</strong>' \ % (name_role, ) extra = """ <dl> <dt><a href="adduserrole?id_role=%s">Connect user</a></dt> <dd>connect users to the role.</dd> </dl> """ % (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 = '<form action="%s" method="POST">\n' % (action, ) output += ' <span class="adminlabel">%s</span>\n' % (step + label, ) output += ' <select name="%s" class="admin_w200">\n' % (name, ) if not list and not extralist: output += ' <option value="0">*** no %ss to select from ***' \ '</option>\n' % (label.split()[-1], ) else: output += ' <option value="0">*** %s ***</option>\n' % (label, ) for elem in list: elem_id = elem[0] email = elem[1] if str(elem_id) == id_input: output += ' <option value="%s" selected="selected">' \ '%s</option>\n' % (elem_id, email) else: output += ' <option value="%s">%s</option>\n' \ % (elem_id, email) for elem in extralist: elem_id = elem[0] email = elem[1] if str(elem_id) == id_input: if not extrastamp: output += ' <option value="%s" selected="selected">' \ '(%s)</option>\n' % (elem_id, email) else: output += ' <option value="%s">%s %s</option>\n' \ % (elem_id, email, extrastamp) elif not extrastamp: output += ' <option value="%s">(%s)</option>\n' \ % (elem_id, email) else: output += ' <option value="%s">%s %s</option>\n' \ % (elem_id, email, extrastamp) output += ' </select>\n' for key in hidden.keys(): output += ' <input type="hidden" name="%s" value="%s" />\n' \ % (key, hidden[key]) output += ' <input class="adminbutton" type="submit" value="%s" />\n' \ % (button, ) output += '</form>\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 send_account_activated_message(account_email, send_to, password, ln=CFG_SITE_LANG): """Send an email to the address given by send_to about the new activated account.""" _ = gettext_set_language(ln) sub = _("Your account on '%s' has been activated") % CFG_SITE_NAME body = _("Your account earlier created on '%s' has been activated:") \ % CFG_SITE_NAME + '\n\n' body += ' ' + _("Username/Email:") + " %s\n" % account_email body += ' ' + _("Password:") + " %s\n" % ("*" * len(password)) body += "\n---------------------------------" body += "\n%s" % CFG_SITE_NAME return send_email(CFG_SITE_SUPPORT_EMAIL, send_to, sub, body, header='') def send_new_user_account_warning(new_account_email, send_to, password, ln=CFG_SITE_LANG): """Send an email to the address given by send_to about the new account new_account_email.""" _ = gettext_set_language(ln) sub = _("Account created on '%s'") % CFG_SITE_NAME body = _("An account has been created for you on '%s':") % CFG_SITE_NAME + '\n\n' body += ' ' + _("Username/Email:") + " %s\n" % new_account_email body += ' ' + _("Password:") + " %s\n" % ("*" * len(password)) body += "\n---------------------------------" body += "\n%s" % CFG_SITE_NAME return send_email(CFG_SITE_SUPPORT_EMAIL, send_to, sub, body, header='') def send_account_rejected_message(new_account_email, send_to, ln=CFG_SITE_LANG): """Send an email to the address given by send_to about the new account new_account_email.""" _ = gettext_set_language(ln) sub = _("Account rejected on '%s'") % CFG_SITE_NAME body = _("Your request for an account has been rejected on '%s':") \ % CFG_SITE_NAME + '\n\n' body += ' ' + _("Username/Email: %s") % new_account_email + "\n" body += "\n---------------------------------" body += "\n%s" % CFG_SITE_NAME return send_email(CFG_SITE_SUPPORT_EMAIL, send_to, sub, body, header='') def send_account_deleted_message(new_account_email, send_to, ln=CFG_SITE_LANG): """Send an email to the address given by send_to about the new account new_account_email.""" _ = gettext_set_language(ln) sub = _("Account deleted on '%s'") % CFG_SITE_NAME body = _("Your account on '%s' has been deleted:") % CFG_SITE_NAME + '\n\n' body += ' ' + _("Username/Email:") + " %s\n" % new_account_email body += "\n---------------------------------" body += "\n%s" % CFG_SITE_NAME return send_email(CFG_SITE_SUPPORT_EMAIL, send_to, sub, body, header='') def usage(exitcode=1, msg=""): """Prints usage info.""" if msg: print >> sys.stderr, "Error: %s." % msg print >> sys.stderr print >> sys.stderr, """Usage: %s [options] General options: -h, --help\t\tprint this help -V, --version\t\tprint version number Authentication options: -u, --user=USER\tUser name needed to perform the administrative task Option to administrate authorizations: -a, --add\t\tadd default authorization settings -c, --compile\t\tcompile firewall like role definitions (FireRole) -r, --reset\t\treset to default settings -D, --demo\t\tto be used with -a or -r in order to consider demo site authorizationss """ % 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, 'demo' : 0} try: opts, args = getopt.getopt(sys.argv[1:], "hVu:racD", ["help", "version", "user=", "reset", "add", "compile", "demo"]) 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 elif opt[0] in ("-D", "--demo"): options["demo"] = 1 else: usage(1) if options['add'] or options['reset'] or options['compile']: if acca.acc_get_action_id('cfgwebaccess'): # Action exists hence authentication works :-) options['user'] = authenticate(options['user'], authorization_msg="WebAccess Administration", authorization_action="cfgwebaccess") if options['reset'] and options['demo']: acca.acc_reset_default_settings([CFG_SITE_ADMIN_EMAIL], DEF_DEMO_USER_ROLES, DEF_DEMO_ROLES, DEF_DEMO_AUTHS) print "Reset default demo site settings." elif options['reset']: acca.acc_reset_default_settings([CFG_SITE_ADMIN_EMAIL]) print "Reset default settings." elif options['add'] and options['demo']: acca.acc_add_default_settings([CFG_SITE_ADMIN_EMAIL], DEF_DEMO_USER_ROLES, DEF_DEMO_ROLES, DEF_DEMO_AUTHS) print "Added default demo site settings." elif options['add']: acca.acc_add_default_settings([CFG_SITE_ADMIN_EMAIL]) 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/webmessage/lib/webmessage_dblayer.py b/modules/webmessage/lib/webmessage_dblayer.py index 8466b79f6..9fc7ca4d1 100644 --- a/modules/webmessage/lib/webmessage_dblayer.py +++ b/modules/webmessage/lib/webmessage_dblayer.py @@ -1,625 +1,634 @@ # -*- coding: utf-8 -*- ## ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 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. """Every db-related function of module webmessage""" __revision__ = "$Id$" from time import localtime, mktime from invenio.config import \ CFG_WEBMESSAGE_MAX_NB_OF_MESSAGES, \ CFG_WEBMESSAGE_DAYS_BEFORE_DELETE_ORPHANS -from invenio.dbquery import run_sql +from invenio.dbquery import run_sql, OperationalError from invenio.webmessage_config import CFG_WEBMESSAGE_STATUS_CODE, \ CFG_WEBMESSAGE_ROLES_WITHOUT_QUOTA from invenio.dateutils import datetext_default, \ convert_datestruct_to_datetext from invenio.webuser import list_users_in_roles from invenio.webbasket_dblayer import get_groups_user_member_of from invenio.websession_config import CFG_WEBSESSION_USERGROUP_STATUS def check_user_owns_message(uid, msgid): """ Checks whether a user owns a message @param uid: user id @param msgid: message id @return 1 if the user owns the message, else 0 """ query = """SELECT count(*) FROM user_msgMESSAGE WHERE id_user_to=%s AND id_msgMESSAGE=%s""" params = (uid, msgid) res = run_sql(query, params) return int(res[0][0]) def get_message(uid, msgid): """ get a message with its status @param uid: user id @param msgid: message id @return a (message_id, id_user_from, nickname_user_from, sent_to_user_nicks, sent_to_group_names, subject, body, sent_date, received_date, status) formed tuple or 0 (ZERO) if none found """ query = """SELECT m.id, m.id_user_from, u.nickname, m.sent_to_user_nicks, m.sent_to_group_names, m.subject, m.body, DATE_FORMAT(m.sent_date, '%%Y-%%m-%%d %%H:%%i:%%s'), DATE_FORMAT(m.received_date, '%%Y-%%m-%%d %%H:%%i:%%s'), um.status FROM msgMESSAGE m, user_msgMESSAGE um, user u WHERE m.id=%s AND um.id_msgMESSAGE=%s AND um.id_user_to=%s AND u.id=m.id_user_from""" params = (msgid, msgid, uid) res = run_sql(query, params) if res: return res[0] else: return 0 def set_message_status(uid, msgid, new_status): """ Change the status of a message (e.g. from "new" to "read"). the status is a single character string, specified in constant CFG_WEBMESSAGE_STATUS_CODE in file webmessage_config.py examples: N: New message R: alreay Read message M: reminder @param uid: user ID @param msgid: Message ID @param new_status: new status. Should be a single character @return 1 if succes, 0 if not """ return int(run_sql("""UPDATE user_msgMESSAGE SET status=%s WHERE id_user_to=%s AND id_msgMESSAGE=%s""", (new_status, uid, msgid))) def get_nb_new_messages_for_user(uid): """ Get number of new mails for a given user @param uid: user id (int) @return number of new mails as int. """ update_user_inbox_for_reminders(uid) new_status = CFG_WEBMESSAGE_STATUS_CODE['NEW'] res = run_sql("""SELECT count(id_msgMESSAGE) FROM user_msgMESSAGE WHERE id_user_to=%s AND BINARY status=%s""", (uid, new_status)) if res: return res[0][0] return 0 def get_nb_readable_messages_for_user(uid): """ Get number of mails of a fiven user. Reminders are not counted @param uid: user id (int) @return number of messages (int) """ reminder_status = CFG_WEBMESSAGE_STATUS_CODE['REMINDER'] query = """SELECT count(id_msgMESSAGE) FROM user_msgMESSAGE WHERE id_user_to=%s AND BINARY status!=%s""" params = (uid, reminder_status) res = run_sql(query, params) if res: return res[0][0] return 0 def get_all_messages_for_user(uid): """ Get all messages for a user's inbox, without the eventual non-expired reminders. @param uid: user id @return [(message_id, id_user_from, nickname_user_from, message_subject, message_sent_date, message_status)] """ update_user_inbox_for_reminders(uid) reminder_status = CFG_WEBMESSAGE_STATUS_CODE['REMINDER'] return run_sql("""SELECT m.id, m.id_user_from, u.nickname, m.subject, DATE_FORMAT(m.sent_date, '%%Y-%%m-%%d %%H:%%i:%%s'), um.status FROM user_msgMESSAGE um, msgMESSAGE m, user u WHERE um.id_user_to = %s AND !(BINARY um.status=%s) AND um.id_msgMESSAGE=m.id AND u.id=m.id_user_from ORDER BY m.sent_date DESC """, (uid, reminder_status)) def count_nb_messages(uid): """ @param uid: user id @return integer of number of messages a user has, 0 if none """ uid = int(uid) query = """SELECT count(id_user_to) FROM user_msgMESSAGE WHERE id_user_to=%s """ res = run_sql(query, (uid, )) if res: return int(res[0][0]) else: return 0 def delete_message_from_user_inbox(uid, msg_id): """ Delete message from users inbox If this message was does not exist in any other user's inbox, delete it permanently from the database @param uid: user id @param msg_id: message id @return integer 1 if delete was successful, integer 0 else """ query1 = """DELETE FROM user_msgMESSAGE WHERE id_user_to=%s AND id_msgMESSAGE=%s""" params1 = (uid, msg_id) res1 = run_sql(query1, params1) check_if_need_to_delete_message_permanently([msg_id]) return int(res1) def check_if_need_to_delete_message_permanently(msg_ids): """ Checks if a list of messages exist in anyone's inbox, if not, delete them permanently @param msg_id: sequence of message ids @return number of deleted messages """ if not((type(msg_ids) is list) or (type(msg_ids) is tuple)): msg_ids = [msg_ids] query1 = """SELECT count(id_msgMESSAGE) FROM user_msgMESSAGE WHERE id_msgMESSAGE=%s""" messages_to_delete = [] for msg_id in msg_ids: nb_users = int(run_sql(query1, (msg_id,))[0][0]) if nb_users == 0: messages_to_delete.append(int(msg_id)) if len(messages_to_delete) > 0: query2 = """DELETE FROM msgMESSAGE WHERE""" params2 = [] for msg_id in messages_to_delete[0:-1]: query2 += " id=%s OR" params2.append(msg_id) query2 += " id=%s" params2.append(messages_to_delete[-1]) run_sql(query2, tuple(params2)) return len(messages_to_delete) def delete_all_messages(uid): """ Delete all messages of a user (except reminders) @param uid: user id @return the number of messages deleted """ reminder_status = CFG_WEBMESSAGE_STATUS_CODE['REMINDER'] query1 = """SELECT id_msgMESSAGE FROM user_msgMESSAGE WHERE id_user_to=%s AND NOT(BINARY status like %s)""" params = (uid, reminder_status) msg_ids = map(get_element, run_sql(query1, params)) query2 = """DELETE FROM user_msgMESSAGE WHERE id_user_to=%s AND NOT(BINARY status like %s)""" nb_messages = int(run_sql(query2, params)) check_if_need_to_delete_message_permanently(msg_ids) return nb_messages def get_uids_from_nicks(nicks): """ Get the association uid/nickname of given nicknames @param nicks: list or sequence of strings, each string being a nickname @return a dictionary {nickname: uid} """ # FIXME: test case if not((type(nicks) is list) or (type(nicks) is tuple)): nicks = [nicks] users = {} query = "SELECT nickname, id FROM user WHERE BINARY nickname IN (" query_params = () if len(nicks)> 0: for nick in nicks: users[nick] = None users_keys = users.keys() for nick in users_keys[0:-1]: query += "%s," query_params += (nick,) query += "%s)" query_params += (users_keys[-1],) res = run_sql(query, query_params) def enter_dict(couple): """ takes a a tuple and enters it into dict users """ users[couple[0]] = int(couple[1]) map(enter_dict, res) return users def get_nicks_from_uids(uids): """ Get the association uid/nickname of given uids @param uids: list or sequence of uids @return a dictionary {uid: nickname} where empty value is possible """ if not((type(uids) is list) or (type(uids) is tuple)): uids = [uids] users = {} query = "SELECT id, nickname FROM user WHERE id in(" query_params = [] if len(uids) > 0: for uid in uids: users[uid] = None for uid in users.keys()[0:-1]: query += "%s," query_params.append(uid) query += "%s)" query_params.append(users.keys()[-1]) res = run_sql(query, tuple(query_params)) for (user_id, nickname) in res: users[int(user_id)] = nickname return users def get_uids_from_emails(emails): """ Get the association uid/nickname of given nicknames @param nicks: list or sequence of strings, each string being a nickname @return a dictionary {nickname: uid} """ # FIXME: test case if not((type(emails) is list) or (type(emails) is tuple)): emails = [emails] users = {} query = "SELECT email, id FROM user WHERE BINARY email IN (" query_params = () if len(emails)> 0: for mail in emails: users[mail] = None users_keys = users.keys() for mail in users_keys[0:-1]: query += "%s," query_params += (mail,) query += "%s)" query_params += (users_keys[-1],) res = run_sql(query, query_params) def enter_dict(couple): """ takes a a tuple and enters it into dict users """ users[couple[0]] = int(couple[1]) map(enter_dict, res) return users def get_gids_from_groupnames(groupnames): """ Get the gids of given groupnames @param groupnames: list or sequence of strings, each string being a groupname @return a dictionary {groupname: gid} """ # FIXME: test case if not((type(groupnames) is list) or (type(groupnames) is tuple)): groupnames = [groupnames] groups = {} query = "SELECT name, id FROM usergroup WHERE BINARY name IN (" query_params = () if len(groupnames) > 0: for groupname in groupnames: groups[groupname] = None groups_keys = groups.keys() for groupname in groups_keys[0:-1]: query += "%s," query_params += (groupname,) query += "%s)" query_params += (groups_keys[-1],) res = run_sql(query, query_params) def enter_dict(couple): """ enter a tuple into dictionary groups """ groups[couple[0]] = int(couple[1]) map(enter_dict, res) return groups def get_uids_members_of_groups(gids): """ Get the distinct ids of users members of given groups. @param groupnames: list or sequence of group ids @return a list of uids. """ if not((type(gids) is list) or (type(gids) is tuple)): gids = [gids] query = """SELECT DISTINCT id_user FROM user_usergroup WHERE user_status!=%s AND ( """ query_params = [CFG_WEBSESSION_USERGROUP_STATUS['PENDING']] if len(gids) > 0: for gid in gids[0:-1]: query += " id_usergroup=%s OR" query_params.append(gid) query += " id_usergroup=%s)" query_params.append(gids[-1]) return map(get_element, run_sql(query, tuple(query_params))) return [] def user_exists(uid): """ checks if a user exists in the system, given his uid. return 0 or 1""" query = "SELECT count(id) FROM user WHERE id=%s GROUP BY id" res = run_sql(query, (uid, )) if res: return int(res[0][0]) return 0 def create_message(uid_from, users_to_str="", groups_to_str="", msg_subject="", msg_body="", msg_send_on_date=datetext_default): """ Creates a message in the msgMESSAGE table. Does NOT send the message. This function is like a datagramPacket... @param uid_from: uid of the sender (int) @param users_to_str: a string, with nicknames separated by semicolons (';') @param groups_to_str: a string with groupnames separated by semicolons @param msg_subject: string containing the subject of the message @param msg_body: string containing the body of the message @param msg_send_on_date: date on which message must be sent. Has to be a datetex format (i.e. YYYY-mm-dd HH:MM:SS) @return id of the created message """ now = convert_datestruct_to_datetext(localtime()) msg_id = run_sql("""INSERT INTO msgMESSAGE(id_user_from, sent_to_user_nicks, sent_to_group_names, subject, body, sent_date, received_date) VALUES (%s,%s,%s,%s,%s,%s,%s)""", (uid_from, users_to_str, groups_to_str, msg_subject, msg_body, now, msg_send_on_date)) return int(msg_id) def send_message(uids_to, msgid, status=CFG_WEBMESSAGE_STATUS_CODE['NEW']): """ Send message to uids @param uids: sequence of user ids @param msg_id: id of message @param status: status of the message. (single char, see webmessage_config.py). @return a list of users having their mailbox full """ if not((type(uids_to) is list) or (type(uids_to) is tuple)): uids_to = [uids_to] user_problem = [] if len(uids_to) > 0: users_quotas = check_quota(CFG_WEBMESSAGE_MAX_NB_OF_MESSAGES - 1) query = """INSERT INTO user_msgMESSAGE (id_user_to, id_msgMESSAGE, status) VALUES """ fixed_value = ",%s,%s)" query_params = [] def not_users_quotas_has_key(key): """ not(is key in users over quota?)""" return not(users_quotas.has_key(key)) user_ids_to = filter(not_users_quotas_has_key, uids_to) user_problem = filter(users_quotas.has_key, uids_to) if len(user_ids_to) > 0: for uid_to in user_ids_to[0:-1]: query += "(%%s%s," % fixed_value query_params += [uid_to, msgid, status] query += "(%%s%s" % fixed_value query_params += [user_ids_to[-1], msgid, status] run_sql(query, tuple(query_params)) return user_problem def check_quota(nb_messages): """ @param nb_messages: max number of messages a user can have @return a dictionary of users over-quota """ where = '' no_quota_users = list_users_in_roles(CFG_WEBMESSAGE_ROLES_WITHOUT_QUOTA) query_params = [] if len(no_quota_users) > 0: where = """WHERE """ for uid in no_quota_users[:-1]: where += "id_user_to!=%s AND " query_params.append(uid) where += "id_user_to!=%s" query_params.append(no_quota_users[-1]) query = """SELECT id_user_to, count(id_user_to) FROM user_msgMESSAGE %s GROUP BY id_user_to HAVING count(id_user_to)>%%s""" query_params.append(nb_messages) res = run_sql(query % where, tuple(query_params)) user_over_quota = {} def enter_dict(couple): """ enter a tuple in user_over_quota dict """ user_over_quota[int(couple[0])] = int(couple[1]) map(enter_dict, res) return user_over_quota def update_user_inbox_for_reminders(uid): """ Updates user's inbox with any reminders that should have arrived @param uid: user id @return integer number of new expired reminders """ now = convert_datestruct_to_datetext(localtime()) reminder_status = CFG_WEBMESSAGE_STATUS_CODE['REMINDER'] new_status = CFG_WEBMESSAGE_STATUS_CODE['NEW'] query1 = """SELECT m.id FROM msgMESSAGE m, user_msgMESSAGE um WHERE um.id_user_to=%s AND um.id_msgMESSAGE=m.id AND m.received_date<=%s AND um.status like binary %s """ params1 = (uid, now, reminder_status) res_ids = run_sql(query1, params1) out = len(res_ids) if (out>0): query2 = """UPDATE user_msgMESSAGE SET status=%s WHERE id_user_to=%s AND (""" query_params = [new_status, uid] for msg_id in res_ids[0:-1]: query2 += "id_msgMESSAGE=%s OR " query_params.append(msg_id[0]) query2 += "id_msgMESSAGE=%s)" query_params.append(res_ids[-1][0]) run_sql(query2, tuple(query_params)) return out def get_nicknames_like(pattern): """get nicknames like pattern""" if pattern: - res = run_sql("SELECT nickname FROM user WHERE nickname RLIKE %s", (pattern,)) + try: + res = run_sql("SELECT nickname FROM user WHERE nickname RLIKE %s", (pattern,)) + except OperationalError: + res = () return res return () def get_groupnames_like(uid, pattern): """Get groupnames like pattern. Will return only groups that user is allowed to see """ groups = {} if pattern: # For this use case external groups are like invisible one query1 = "SELECT id, name FROM usergroup WHERE name RLIKE %s AND join_policy like 'V%%' AND join_policy<>'VE'" - res = run_sql(query1, (pattern,)) + try: + res = run_sql(query1, (pattern,)) + except OperationalError: + res = () # The line belows inserts into groups dictionary every tuple the database returned, # assuming field0=key and field1=value map(lambda x: groups.setdefault(x[0], x[1]), res) query2 = """SELECT g.id, g.name FROM usergroup g, user_usergroup ug WHERE g.id=ug.id_usergroup AND ug.id_user=%s AND g.name RLIKE %s""" - res = run_sql(query2, (uid, pattern)) + try: + res = run_sql(query2, (uid, pattern)) + except OperationalError: + res = () map(lambda x: groups.setdefault(x[0], x[1]), res) return groups def get_element(sql_res): """convert mySQL output @param x: a tuple like this: (6789L,) @return integer conversion of the number in tuple """ return int(sql_res[0]) def clean_messages(): """ Cleans msgMESSAGE table""" current_time = localtime() seconds = mktime(current_time) seconds -= CFG_WEBMESSAGE_DAYS_BEFORE_DELETE_ORPHANS * 86400 sql_date = convert_datestruct_to_datetext(localtime(seconds)) deleted_items = 0 #find id and email from every user who has got an email query1 = """SELECT distinct(umsg.id_user_to), user.email FROM user_msgMESSAGE umsg LEFT JOIN user ON umsg.id_user_to=user.id""" res1 = run_sql(query1) # if there is no email, user has disappeared users_deleted = map(lambda u: int(u[0]), filter(lambda x: x[1] is None, res1)) # find ids from messages in user's inbox query2 = """SELECT distinct(umsg.id_msgMESSAGE), msg.id FROM user_msgMESSAGE umsg LEFT JOIN msgMESSAGE msg ON umsg.id_msgMESSAGE=msg.id""" res2 = run_sql(query2) # if there is no id, message was deleted from table msgMESSAGE... messages_deleted = map(lambda u: int(u[0]), filter(lambda x: x[1] is None, res2)) def tuplize(el1, el2): return str(el1) + ',' + str(el2) if len(users_deleted) or len(messages_deleted): # Suppress every referential error from user_msgMESSAGE query3 = "DELETE FROM user_msgMESSAGE WHERE " query_params = [] if len(users_deleted): query3 += "id_user_to IN (%s)" query_params.append(reduce(tuplize, users_deleted)) if len(messages_deleted): query3 += ' OR ' if len(messages_deleted): query3 += "id_msgMESSAGE IN (%s)" query_params.append(reduce(tuplize, messages_deleted)) deleted_items = int(run_sql(query3, tuple(query_params))) # find every message that is nobody's inbox query4 = """SELECT msg.id FROM msgMESSAGE msg LEFT JOIN user_msgMESSAGE umsg ON msg.id=umsg.id_msgMESSAGE WHERE msg.sent_date<%s GROUP BY umsg.id_msgMESSAGE HAVING count(umsg.id_msgMESSAGE)=0 """ res4 = map(lambda x: x[0], run_sql(query4, (sql_date, ))) if len(res4): # delete these messages query5 = "DELETE FROM msgMESSAGE WHERE " query5 += "id IN (%s)" deleted_items += int(run_sql(query5, (reduce(tuplize, res4), ))) return deleted_items diff --git a/modules/websession/lib/webgroup_dblayer.py b/modules/websession/lib/webgroup_dblayer.py index 4b4f0eb18..7a3b155ea 100644 --- a/modules/websession/lib/webgroup_dblayer.py +++ b/modules/websession/lib/webgroup_dblayer.py @@ -1,442 +1,445 @@ # -*- coding: utf-8 -*- ## ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 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. """ Database related functions for groups""" __revision__ = "$Id$" from time import localtime from zlib import decompress from invenio.config import \ CFG_SITE_LANG, \ CFG_VERSION -from invenio.dbquery import run_sql, run_sql_cached +from invenio.dbquery import run_sql, run_sql_cached, OperationalError from invenio.dateutils import convert_datestruct_to_datetext from invenio.messages import gettext_set_language from invenio.websession_config import CFG_WEBSESSION_GROUP_JOIN_POLICY def get_groups_by_user_status(uid, user_status, login_method='INTERNAL'): """Select all the groups the user is admin of. @param uid: user id @return ((id_usergroup, group_name, group_description, )) """ query = """SELECT g.id, g.name, g.description FROM usergroup g, user_usergroup ug WHERE ug.id_user=%s AND ug.id_usergroup=g.id AND ug.user_status=%s AND g.login_method = %s ORDER BY g.name""" uid = int(uid) res = run_sql_cached(query, (uid, user_status, login_method), affected_tables=['usergroup', 'user_usergroup']) return res def get_groups_by_login_method(uid, login_method): """Select all the groups the user is member of selecting the login_method. @param uid: user id @param login_method: the login_method (>0 external) @return ((id_usergroup, group_name, group_description, )) """ query = """SELECT g.id, g.name, g.description FROM usergroup g, user_usergroup ug WHERE ug.id_user=%s AND ug.id_usergroup=g.id AND g.login_method=%s ORDER BY g.name""" uid = int(uid) res = run_sql_cached(query, (uid, login_method), affected_tables=['usergroup', 'user_usergroup']) return res def get_groups_with_description(uid): """Select all the groups the user is member of. @param uid: user id @return ((id_usergroup, group_name, group_description, )) """ query = """SELECT g.id, g.name, g.description FROM usergroup g, user_usergroup ug WHERE ug.id_user=%s AND ug.id_usergroup=g.id ORDER BY g.name""" uid = int(uid) res = run_sql_cached(query, (uid, ), affected_tables=['usergroup', 'user_usergroup']) return res def get_external_groups(uid): """Select all the groups the user is member of selecting the login_method. @param uid: user id @param login_method: the login_method (>0 external) @return ((id_usergroup, group_name, group_description, )) """ query = """SELECT g.id, g.name, g.description FROM usergroup g, user_usergroup ug WHERE ug.id_user=%s AND ug.id_usergroup=g.id AND g.login_method != 'INTERNAL' ORDER BY g.name""" uid = int(uid) res = run_sql_cached(query, (uid, ), affected_tables=['usergroup', 'user_usergroup']) return res def get_groups(uid): """Select all the groups id the user is member of.""" query = """SELECT g.id, g.name FROM usergroup g, user_usergroup ug WHERE ug.id_user=%s AND ug.id_usergroup=g.id """ res = run_sql_cached(query, (uid, ), affected_tables=['usergroup', 'user_usergroup']) res = list(res) return res def get_group_id(group_name, login_method): """@return the id of the group called group_name with given login_method.""" return run_sql(""" SELECT id FROM usergroup WHERE login_method = %s AND name = %s""", (login_method, group_name,)) def get_login_method_groups(uid, login_method): """Select all the external groups of a particular login_method for which the user is subscrided. @return ((group_name, group_id)) """ return run_sql(""" SELECT g.name as name, g.id as id FROM user_usergroup as u JOIN usergroup as g ON u.id_usergroup = g.id WHERE u.id_user = %s and g.login_method = %s""", (uid, login_method,)) def get_all_login_method_groups(login_method): """Select all the external groups of a particular login_method. @return ({group_name: group_id, ...}) """ return dict(run_sql(""" SELECT name, id FROM usergroup WHERE login_method = %s""", (login_method,))) def get_all_users_with_groups_with_login_method(login_method): """Select all the users that belong at least to one external group of kind login_method. """ return dict(run_sql(""" SELECT DISTINCT u.email, u.id FROM user AS u JOIN user_usergroup AS uu ON u.id = uu.id_user JOIN usergroup AS ug ON ug.id = uu.id_usergroup WHERE ug.login_method = %s""", (login_method,))) def get_visible_group_list(uid, pattern=""): """List the group the user can join (not already member of the group regardless user's status). @return groups {id : name} whose name matches pattern """ grpID = [] groups = {} #list the group the user is member of""" query = """SELECT distinct(id_usergroup) FROM user_usergroup WHERE id_user=%i """ uid = int(uid) query %= uid res = run_sql(query) map(lambda x: grpID.append(int(x[0])), res) query2 = """SELECT id,name FROM usergroup WHERE (join_policy='%s' OR join_policy='%s')""" % ( CFG_WEBSESSION_GROUP_JOIN_POLICY['VISIBLEOPEN'], CFG_WEBSESSION_GROUP_JOIN_POLICY['VISIBLEMAIL']) if len(grpID) == 1 : query2 += """ AND id!=%i""" % grpID[0] elif len(grpID) > 1: query2 += """ AND id NOT IN %s""" % str(tuple(grpID)) if pattern: - res2 = run_sql(query2 + """ AND name RLIKE %s ORDER BY name""", (pattern,)) + try: + res2 = run_sql(query2 + """ AND name RLIKE %s ORDER BY name""", (pattern,)) + except OperationalError: + res2 = () else: res2 = run_sql(query2 + """ ORDER BY name""") map(lambda x: groups.setdefault(x[0], x[1]), res2) return groups def insert_new_group(uid, new_group_name, new_group_description, join_policy, login_method='INTERNAL'): """Create a new group and affiliate a user.""" query1 = """INSERT INTO usergroup (id, name, description, join_policy, login_method) VALUES (NULL,%s,%s,%s,%s) """ params1 = (new_group_name, new_group_description, join_policy, login_method) res1 = run_sql(query1, params1) date = convert_datestruct_to_datetext(localtime()) uid = int(uid) query2 = """INSERT INTO user_usergroup (id_user, id_usergroup, user_status, user_status_date) VALUES (%s,%s,'A',%s) """ params2 = (uid, res1, date) res2 = run_sql(query2, params2) return res1 def insert_only_new_group(new_group_name, new_group_description, join_policy, login_method='INTERNAL'): """Create a group with no user in (yet). @return its id """ query = """INSERT INTO usergroup (name, description, join_policy, login_method) VALUES (%s, %s, %s, %s) """ res = run_sql(query, (new_group_name, new_group_description, join_policy, login_method)) return res def insert_new_member(uid, grpID, status): """Insert new member.""" query = """INSERT INTO user_usergroup (id_user, id_usergroup, user_status, user_status_date) VALUES (%s,%s,%s,%s) """ date = convert_datestruct_to_datetext(localtime()) res = run_sql(query, (uid, grpID, status, date)) return res def get_group_infos(grpID): """Get group infos.""" query = """SELECT id,name,description,join_policy,login_method FROM usergroup WHERE id = %s""" grpID = int(grpID) res = run_sql(query, (grpID, )) return res def get_all_groups_description(login_method): """Get all groups description, dictionary with key name.""" query = """SELECT name, description FROM usergroup WHERE login_method = %s """ res = run_sql(query, (login_method, )) if res: return dict(res) else: return {} def update_group_infos(grpID, group_name, group_description, join_policy): """Update group.""" res = run_sql("""UPDATE usergroup SET name=%s, description=%s, join_policy=%s WHERE id=%s""", (group_name, group_description, join_policy, grpID)) return res def get_user_status(uid, grpID): """Get the status of the user for the given group.""" query = """SELECT user_status FROM user_usergroup WHERE id_user = %i AND id_usergroup=%i""" uid = int(uid) grpID = int(grpID) res = run_sql(query% (uid, grpID)) return res def get_users_by_status(grpID, status, ln=CFG_SITE_LANG): """Get the list of users with the given status. @return ((id, nickname),) nickname= user # uid if the user has no nickname """ _ = gettext_set_language(ln) res = run_sql("""SELECT ug.id_user, u.nickname FROM user_usergroup ug, user u WHERE ug.id_usergroup = %s AND ug.id_user=u.id AND user_status = %s""", (grpID, status)) users = [] if res: for (mid, nickname) in res: nn = nickname if not nickname: nn = _("user") + "#%i" % mid users.append((mid, nn)) return tuple(users) def delete_member(grpID, member_id): """Delete member.""" query = """DELETE FROM user_usergroup WHERE id_usergroup = %i AND id_user = %i""" grpID = int(grpID) member_id = int(member_id) res = run_sql(query% (grpID, member_id)) return res def delete_group_and_members(grpID): """Delete the group and its members.""" query = """DELETE FROM usergroup WHERE id = %i """ grpID = int(grpID) res = run_sql(query% grpID) query = """DELETE FROM user_usergroup WHERE id_usergroup = %i """ res = run_sql(query% grpID) return res def add_pending_member(grpID, member_id, user_status): """Change user status: Pending member becomes normal member""" date = convert_datestruct_to_datetext(localtime()) res = run_sql("""UPDATE user_usergroup SET user_status = %s, user_status_date = %s WHERE id_usergroup = %s AND id_user = %s""", (user_status, date, grpID, member_id)) return res def leave_group(grpID, uid): """Remove user from the group member list.""" query = """DELETE FROM user_usergroup WHERE id_usergroup=%i AND id_user=%i""" grpID = int(grpID) uid = int(uid) res = run_sql(query% (grpID, uid)) return res def drop_external_groups(userId): """Drops all the external groups memberships of userid.""" query = """DELETE user_usergroup FROM user_usergroup, usergroup WHERE user_usergroup.id_user=%s AND usergroup.id = user_usergroup.id_usergroup AND usergroup.login_method <> 'INTERNAL'""" return run_sql(query, (userId,)) def group_name_exist(group_name, login_method='INTERNAL'): """Get all group id whose name like group_name and login_method.""" query = """SELECT id FROM usergroup WHERE login_method=%s AND name=%s""" res = run_sql(query, (group_name, login_method,)) return res def get_group_login_method(grpID): """Return the login_method of the group or None if the grpID doesn't exist.""" query = """SELECT login_method FROM usergroup WHERE id=%s""" res = run_sql(query, (grpID, )) if res: return res[0][0] else: return None def count_nb_group_user(uid, user_status): """ @param uid: user id @param status: member status @return integer of number of groups the user belongs to with the given status, 0 if none """ res = run_sql("""SELECT count(id_user) FROM user_usergroup WHERE id_user = %s AND user_status = %s""", (uid, user_status)) if res: return int(res[0][0]) else: return 0 def get_all_users(): """@return all the email:id""" query = """SELECT UPPER(email), id FROM user WHERE email != '' """ res = run_sql(query) if res: return dict(res) else: return {} def get_users_in_group(grpID): """@return all uids of users belonging to group grpID""" grpID = int(grpID) query = """SELECT id_user FROM user_usergroup WHERE id_usergroup = %s """ res = run_sql(query, (grpID, )) return [uid[0] for uid in res] ########################## helpful functions ################################## def __decompress_last(item): """private function, used to shorten code""" item = list(item) item[-1] = decompress(item[-1]) return item diff --git a/modules/websubmit/web/publiline.py b/modules/websubmit/web/publiline.py index a2b604882..24ef4bd70 100644 --- a/modules/websubmit/web/publiline.py +++ b/modules/websubmit/web/publiline.py @@ -1,1828 +1,1836 @@ ## $Id$ ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 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. """ publiline_complex.py -- implementes ... actors in this process are: 1. author -- subilmts ... 2. edi 3; ref Il ne faut pas oublier de definir les roles... """ __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, \ CFG_SITE_ADMIN_EMAIL, \ CFG_SITE_LANG, \ CFG_SITE_NAME, \ CFG_SITE_URL, \ CFG_PYLIBDIR, \ CFG_WEBSUBMIT_STORAGEDIR, \ CFG_SITE_SUPPORT_EMAIL, \ CFG_SITE_SECURE_URL, \ CFG_VERSION -from invenio.dbquery import run_sql, Error +from invenio.dbquery import run_sql, Error, OperationalError 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, get_fieldvalues from invenio.websubmit_functions.Retrieve_Data import Get_Field from invenio.mailutils import send_email from invenio.urlutils import wash_url_argument from invenio.webgroup_dblayer import get_group_infos, insert_new_group, insert_new_member, delete_member from invenio.webaccessadmin_lib import cleanstring_email from invenio.access_control_config import MAXSELECTUSERS from invenio.access_control_admin import acc_get_user_email from invenio.webmessage import perform_request_send, perform_request_write_with_search import invenio.webbasket_dblayer as basketdb from invenio.webbasket_config import CFG_WEBBASKET_SHARE_LEVELS, CFG_WEBBASKET_CATEGORIES, CFG_WEBBASKET_SHARE_LEVELS_ORDERED from invenio.webbasket import perform_request_display_item, perform_request_save_comment from invenio.websubmit_functions.Retrieve_Data import Get_Field from invenio.errorlib import register_exception from invenio.bibrecord import create_records, record_get_field_value, record_get_field_values execfile("%s/invenio/websubmit_functions/Retrieve_Data.py" % CFG_PYLIBDIR) import invenio.template websubmit_templates = invenio.template.load('websubmit') CFG_WEBSUBMIT_PENDING_DIR = "%s/pending" % CFG_WEBSUBMIT_STORAGEDIR CFG_WEBSUBMIT_DUMMY_MARC_XML_REC = "dummy_marcxml_rec" CFG_WEBSUBMIT_MARC_XML_REC = "recmysql" def index(req,c=CFG_SITE_NAME,ln=CFG_SITE_LANG,doctype="",categ="",RN="",send="",flow="",apptype="", action="", email_user_pattern="", id_user="", id_user_remove="", validate="", id_user_val="", msg_subject="", msg_body="", reply="", commentId=""): global uid ln = wash_language(ln) categ = wash_url_argument(categ, 'str') RN = wash_url_argument(RN, 'str') send = wash_url_argument(send, 'str') flow = wash_url_argument(flow, 'str') apptype = wash_url_argument(apptype, 'str') action = wash_url_argument(action, 'str') email_user_pattern = wash_url_argument(email_user_pattern, 'str') id_user = wash_url_argument(id_user, 'int') id_user_remove = wash_url_argument(id_user_remove, 'int') validate = wash_url_argument(validate, 'str') id_user_val = wash_url_argument(id_user_val, 'int') msg_subject = wash_url_argument(msg_subject, 'str') msg_body = wash_url_argument(msg_body, 'str') reply = wash_url_argument(reply, 'str') commentId = wash_url_argument(commentId, 'str') # 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(str(e),req, ln = ln) if flow == "cplx": if doctype == "": t = selectCplxDoctype(ln) elif (categ == "") or (apptype == ""): t = selectCplxCateg(doctype, ln) elif RN == "": t = selectCplxDocument(doctype, categ, apptype, ln) elif action == "": t = displayCplxDocument(req, doctype, categ, RN, apptype, reply, commentId, ln) else: t = doCplxAction(req, doctype, categ, RN, apptype, action, email_user_pattern, id_user, id_user_remove, validate, id_user_val, msg_subject, msg_body, reply, commentId, ln) return page(title=_("Document Approval Workflow"), navtrail= """<a class="navtrail" href="%(sitesecureurl)s/youraccount/display">%(account)s</a>""" % { 'sitesecureurl' : CFG_SITE_SECURE_URL, 'account' : _("Your Account"), }, body=t, description="", keywords="", uid=uid, language=ln, req=req, navmenuid='yourapprovals') else: 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=_("Approval and Refereeing Workflow"), navtrail= """<a class="navtrail" href="%(sitesecureurl)s/youraccount/display">%(account)s</a>""" % { 'sitesecureurl' : CFG_SITE_SECURE_URL, 'account' : _("Your Account"), }, body=t, description="", keywords="", uid=uid, language=ln, req=req, navmenuid='yourapprovals') def selectDoctype(ln = CFG_SITE_LANG): 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 selectCplxDoctype(ln = CFG_SITE_LANG): res = run_sql("select DISTINCT doctype from sbmCPLXAPPROVAL") 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_selectcplxdoctype( ln = ln, docs = docs, ) return t def selectCateg(doctype, ln = CFG_SITE_LANG): 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, ) return t def selectCplxCateg(doctype, ln = CFG_SITE_LANG): 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 selectCplxDocument(doctype,categ, "", ln = ln) types = {} for apptype in ('RRP', 'RPB', 'RDA'): for arr in sth: info = {'id' : arr[1], 'desc' : arr[2],} for status in ('waiting', 'rejected', 'approved', 'cancelled'): info[status] = __db_count_doc (doctype, arr[1], status, apptype) types.setdefault (apptype, []).append(info) t = websubmit_templates.tmpl_publiline_selectcplxcateg( ln = ln, types = types, doctype = doctype, title = title, ) return t def selectDocument(doctype,categ, ln = CFG_SITE_LANG): 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, docs = docs, ) return t def selectCplxDocument(doctype,categ,apptype, ln = CFG_SITE_LANG): t="" res = run_sql("select ldocname from sbmDOCTYPE where sdocname=%s", (doctype,)) title = res[0][0] sth = run_sql("select lname from sbmCATEGORIES where doctype=%s and sname=%s order by lname",(doctype,categ,)) if len(sth) != 0: categname = sth[0][0] else: categname = "Unknown" docs = [] sth = run_sql("select rn,status from sbmCPLXAPPROVAL where doctype=%s and categ=%s and type=%s order by status DESC,rn DESC",(doctype,categ,apptype)) for arr in sth: docs.append({ 'RN' : arr[0], 'status' : arr[1], }) t = websubmit_templates.tmpl_publiline_selectcplxdocument( ln = ln, doctype = doctype, title = title, categ = categ, categname = categname, docs = docs, apptype = apptype, ) return t def displayDocument(req, doctype,categ,RN,send, ln = CFG_SITE_LANG): # 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.") + "<br /> " ## Get the details of the pending item: item_details = get_pending_item_details(doctype, RN) ## get_pending_item_details has returned either None or a dictionary ## with the following structure: ## { 'title' : '-', ## String - the item's title ## 'recid' : '', ## String - recid ## 'report-number' : '', ## String - the item's report number ## 'authors' : [], ## List - the item's authors ## } if item_details is not None: authors = ", ".join(item_details['authors']) newrn = item_details['report-number'] title = item_details['title'] sysno = item_details['recid'] else: ## FIXME! ## For backward compatibility reasons, it we failed to find the item's ## details, we will try the old way, which includes searching for files ## like TI, TIF in the submission's working directory. ## This is not nice and should be removed. 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": if categ == "unknown": ## FIXME: This was necessary for document types without categories, ## such as DEMOBOO: categ = "*" (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, confirm_send = confirm_send, auth_code = auth_code, auth_message = auth_message, authors = authors, title = title, sysno = sysno, newrn = newrn, ) return t def displayCplxDocument(req, doctype,categ,RN,apptype, reply, commentId, ln = CFG_SITE_LANG): # load the right message language _ = gettext_set_language(ln) t="" uid = getUid(req) res = run_sql("select ldocname from sbmDOCTYPE where sdocname=%s", (doctype,)) docname = res[0][0] if categ == "": categ = "unknown" key = (RN, apptype) infos = __db_get_infos (key) if len(infos) > 0: (status, id_group, id_bskBASKET, id_EdBoardGroup, dFirstReq,dLastReq,dEdBoardSel, dRefereeSel, dRefereeRecom, dEdBoardRecom, dPubComRecom, dProjectLeaderAction) = infos[0] dates = {'dFirstReq' : dFirstReq, 'dLastReq' : dLastReq, 'dEdBoardSel' : dEdBoardSel, 'dRefereeSel' : dRefereeSel, 'dRefereeRecom' : dRefereeRecom, 'dEdBoardRecom' : dEdBoardRecom, 'dPubComRecom' : dPubComRecom, 'dProjectLeaderAction' : dProjectLeaderAction, } else: return _("Approval has never been requested for this document.") + "<br /> " ## Removing call to deprecated "getInAlice" function and replacing it with ## a call to the newer "get_brief_doc_details_from_repository" function: ## try: ## (authors,title,sysno,newrn) = getInAlice(doctype,categ,RN) ## except TypeError: ## return _("Unable to display document.") item_details = get_brief_doc_details_from_repository(RN) ## get_brief_doc_details_from_repository has returned either None ## or a dictionary with the following structure: ## { 'title' : '-', ## String - the item's title ## 'recid' : '', ## String - recid ## 'report-number' : '', ## String - the item's report number ## 'authors' : [], ## List - the item's authors ## } if item_details is not None: ## Details of the item were found in the CDS Invenio repository authors = ", ".join(item_details['authors']) newrn = item_details['report-number'] title = item_details['title'] sysno = item_details['recid'] else: ## Can't find any document details. return _("Unable to display document.") if status == "waiting": isPubCom = __is_PubCom (req, doctype) isEdBoard = __is_EdBoard (uid, id_EdBoardGroup) isReferee = __is_Referee (uid, id_bskBASKET) isProjectLeader = __is_ProjectLeader (req, doctype, categ) isAuthor = __is_Author (uid, sysno) else: isPubCom = None isEdBoard = None isReferee = None isProjectLeader = None isAuthor = None t += websubmit_templates.tmpl_publiline_displaycplxdoc( ln = ln, docname = docname, doctype = doctype, categ = categ, rn = RN, apptype = apptype, status = status, dates = dates, isPubCom = isPubCom, isEdBoard = isEdBoard, isReferee = isReferee, isProjectLeader = isProjectLeader, isAuthor = isAuthor, authors = authors, title = title, sysno = sysno, newrn = newrn, ) if id_bskBASKET > 0: rights = basketdb.get_max_user_rights_on_basket(uid, id_bskBASKET) if not(__check_basket_sufficient_rights(rights, CFG_WEBBASKET_SHARE_LEVELS['READITM'])): return t comments = basketdb.get_comments(id_bskBASKET, sysno) if dProjectLeaderAction != None: user_can_add_comment = 0 else: user_can_add_comment = __check_basket_sufficient_rights(rights, CFG_WEBBASKET_SHARE_LEVELS['ADDCMT']) comment_subject = "" comment_body = "" if reply == "true": #Get the message subject and body from the comment for comment in comments: if str(commentId) == str(comment[0]): comment_subject = comment[2] comment_body = comment[3] comment_subject = comment_subject.lstrip("Re: ") comment_subject = "Re: " + comment_subject comment_body = "> " + comment_body.replace("\n", "\n> ") t += websubmit_templates.tmpl_publiline_displaycplxdocitem( doctype, categ, RN, apptype, "AddComment", comments, (__check_basket_sufficient_rights(rights, CFG_WEBBASKET_SHARE_LEVELS['READCMT']), user_can_add_comment, __check_basket_sufficient_rights(rights, CFG_WEBBASKET_SHARE_LEVELS['DELCMT'])), selected_category=CFG_WEBBASKET_CATEGORIES['GROUP'], selected_topic=0, selected_group_id=id_group, comment_subject=comment_subject, comment_body=comment_body, ln=ln) return t def __check_basket_sufficient_rights(rights_user_has, rights_needed): """Private function, check if the rights are sufficient.""" try: out = CFG_WEBBASKET_SHARE_LEVELS_ORDERED.index(rights_user_has) >= \ CFG_WEBBASKET_SHARE_LEVELS_ORDERED.index(rights_needed) except ValueError: out = 0 return out def __is_PubCom (req,doctype): (isPubCom, auth_message) = acc_authorize_action(req, "pubcomchair",verbose=0,doctype=doctype) return isPubCom def __is_EdBoard (uid, id_EdBoardGroup): isEdBoard = None if id_EdBoardGroup > 0: edBoard = run_sql("""SELECT u.id FROM user u LEFT JOIN user_usergroup ug ON u.id = ug.id_user WHERE ug.id_usergroup = '%s' and user_status != 'A' AND user_status != 'P'""" % (id_EdBoardGroup, )) for uid_scan in edBoard: if uid == uid_scan[0]: isEdBoard = 0 break return isEdBoard def __is_Referee (uid, id_bskBASKET): isReferee = None if id_bskBASKET > 0: if basketdb.check_user_owns_baskets (uid, id_bskBASKET) == 1: isReferee = 0 return isReferee def __is_ProjectLeader (req, doctype, categ): (isProjectLeader, auth_message) = acc_authorize_action(req, "projectleader",verbose=0,doctype=doctype,categ=categ) return isProjectLeader def __is_Author (uid, sysno): email = Get_Field("8560_f",sysno) email = re.sub("[\n\r ]+","",email) uid_email = re.sub("[\n\r ]+","", acc_get_user_email(uid)) isAuthor = None if (re.search(uid_email,email,re.IGNORECASE) != None) and (uid_email != ""): isAuthor = 0 return isAuthor def __db_count_doc (doctype, categ, status, apptype): return run_sql("SELECT COUNT(*) FROM sbmCPLXAPPROVAL WHERE doctype=%s AND categ=%s AND status=%s AND type=%s",(doctype,categ,status,apptype,))[0][0] def __db_get_infos (key): return run_sql("SELECT status,id_group,id_bskBASKET,id_EdBoardGroup,dFirstReq,dLastReq,dEdBoardSel,dRefereeSel,dRefereeRecom,dEdBoardRecom,dPubComRecom,dProjectLeaderAction FROM sbmCPLXAPPROVAL WHERE rn=%s and type=%s", key) def __db_set_EdBoardSel_time (key): run_sql("UPDATE sbmCPLXAPPROVAL SET dEdBoardSel=NOW() WHERE rn=%s and type=%s", key) def __db_check_EdBoardGroup ((RN,apptype), id_EdBoardGroup, uid, group_descr): res = get_group_infos (id_EdBoardGroup) if len(res) == 0: id_EdBoardGroup = insert_new_group (uid, RN, group_descr % RN, "VM") run_sql("UPDATE sbmCPLXAPPROVAL SET id_EdBoardGroup=%s WHERE rn=%s and type=%s", (id_EdBoardGroup,RN,apptype,)) return id_EdBoardGroup def __db_set_basket ((RN,apptype), id_bsk): run_sql("UPDATE sbmCPLXAPPROVAL SET id_bskBASKET=%s, dRefereeSel=NOW() WHERE rn=%s and type=%s", (id_bsk,RN,apptype,)) def __db_set_RefereeRecom_time (key): run_sql("UPDATE sbmCPLXAPPROVAL SET dRefereeRecom=NOW() WHERE rn=%s and type=%s", key) def __db_set_EdBoardRecom_time (key): run_sql("UPDATE sbmCPLXAPPROVAL SET dEdBoardRecom=NOW() WHERE rn=%s and type=%s", key) def __db_set_PubComRecom_time (key): run_sql("UPDATE sbmCPLXAPPROVAL SET dPubComRecom=NOW() WHERE rn=%s and type=%s", key) def __db_set_status ((RN,apptype), status): run_sql("UPDATE sbmCPLXAPPROVAL SET status=%s, dProjectLeaderAction=NOW() WHERE rn=%s and type=%s", (status,RN,apptype,)) def doCplxAction(req, doctype, categ, RN, apptype, action, email_user_pattern, id_user, id_user_remove, validate, id_user_val, msg_subject, msg_body, reply, commentId, ln=CFG_SITE_LANG): """ Perform complex action. Note: all argume,ts are supposed to be washed already. Return HTML body for the paget. In case of errors, deletes hard drive. ;-) """ # load the right message language _ = gettext_set_language(ln) TEXT_RSN_RefereeSel_BASKET_DESCR = "Requests for refereeing process" TEXT_RSN_RefereeSel_MSG_REFEREE_SUBJECT = "Referee selection" TEXT_RSN_RefereeSel_MSG_REFEREE_BODY = "You have been named as a referee for this document :" TEXT_RSN_RefereeSel_MSG_GROUP_SUBJECT = "Please, review this publication" TEXT_RSN_RefereeSel_MSG_GROUP_BODY = "Please, review the following publication" TEXT_RSN_RefereeRecom_MSG_PUBCOM_SUBJECT = "Final recommendation from the referee" TEXT_RSN_PubComRecom_MSG_PRJLEADER_SUBJECT = "Final recommendation from the publication board" TEXT_RSN_ProjectLeaderDecision_MSG_SUBJECT = "Final decision from the project leader" TEXT_RPB_EdBoardSel_MSG_EDBOARD_SUBJECT = "You have been selected in a editorial board" TEXT_RPB_EdBoardSel_MSG_EDBOARD_BODY = "You have been selected as a member of the editorial board of this document :" TEXT_RPB_EdBoardSel_EDBOARD_GROUP_DESCR = "Editorial board for %s" TEXT_RPB_RefereeSel_BASKET_DESCR = "Requests for publication" TEXT_RPB_RefereeSel_MSG_REFEREE_SUBJECT = "Referee selection" TEXT_RPB_RefereeSel_MSG_REFEREE_BODY = "You have been named as a referee for this document :" TEXT_RPB_RefereeSel_MSG_GROUP_SUBJECT = "Please, review this publication" TEXT_RPB_RefereeSel_MSG_GROUP_BODY = "Please, review the following publication" TEXT_RPB_RefereeRecom_MSG_EDBOARD_SUBJECT = "Final recommendation from the referee" TEXT_RPB_EdBoardRecom_MSG_PUBCOM_SUBJECT = "Final recommendation from the editorial board" TEXT_RPB_PubComRecom_MSG_PRJLEADER_SUBJECT = "Final recommendation from the publication board" TEXT_RPB_ProjectLeaderDecision_MSG_SUBJECT = "Final decision from the project leader" t="" uid = getUid(req) if categ == "": categ = "unknown" key = (RN, apptype) infos = __db_get_infos (key) if len(infos) > 0: (status, id_group, id_bskBASKET, id_EdBoardGroup, dummy, dummy, dEdBoardSel, dRefereeSel, dRefereeRecom, dEdBoardRecom, dPubComRecom, dProjectLeaderAction) = infos[0] else: return _("Approval has never been requested for this document.") + "<br /> " ## Removing call to deprecated "getInAlice" function and replacing it with ## a call to the newer "get_brief_doc_details_from_repository" function: ## try: ## (authors,title,sysno,newrn) = getInAlice(doctype,categ,RN) ## except TypeError: ## return _("Unable to display document.") item_details = get_brief_doc_details_from_repository(RN) ## get_brief_doc_details_from_repository has returned either None ## or a dictionary with the following structure: ## { 'title' : '-', ## String - the item's title ## 'recid' : '', ## String - recid ## 'report-number' : '', ## String - the item's report number ## 'authors' : [], ## List - the item's authors ## } if item_details is not None: ## Details of the item were found in the CDS Invenio repository authors = ", ".join(item_details['authors']) newrn = item_details['report-number'] title = item_details['title'] sysno = item_details['recid'] else: ## Can't find any document details. return _("Unable to display document.") if (action == "EdBoardSel") and (apptype == "RPB"): if __is_PubCom (req, doctype) != 0: return _("Action unauthorized for this document.") + "<br /> " if status == "cancelled": return _("Action unavailable for this document.") + "<br /> " if validate == "go": if dEdBoardSel == None: __db_set_EdBoardSel_time (key) perform_request_send (uid, "", RN, TEXT_RPB_EdBoardSel_MSG_EDBOARD_SUBJECT, TEXT_RPB_EdBoardSel_MSG_EDBOARD_BODY) return displayCplxDocument(req, doctype,categ,RN,apptype, reply, commentId, ln) id_EdBoardGroup = __db_check_EdBoardGroup (key, id_EdBoardGroup, uid, TEXT_RPB_EdBoardSel_EDBOARD_GROUP_DESCR) subtitle1 = _('Adding users to the editorial board') # remove letters not allowed in an email email_user_pattern = cleanstring_email(email_user_pattern) stopon1 = "" stopon2 = "" stopon3 = "" users = [] extrausers = [] # 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, )) + try: + users1 = run_sql("""SELECT id, email FROM user WHERE email RLIKE %s ORDER BY email """, (email_user_pattern, )) + except OperationalError: + users1 = () # users that are connected - users2 = run_sql("""SELECT DISTINCT u.id, u.email - FROM user u LEFT JOIN user_usergroup ug ON u.id = ug.id_user - WHERE ug.id_usergroup = %s AND u.email RLIKE %s - ORDER BY u.email """, (id_EdBoardGroup, email_user_pattern)) + try: + users2 = run_sql("""SELECT DISTINCT u.id, u.email + FROM user u LEFT JOIN user_usergroup ug ON u.id = ug.id_user + WHERE ug.id_usergroup = %s AND u.email RLIKE %s + ORDER BY u.email """, (id_EdBoardGroup, email_user_pattern)) + except OperationalError: + users2 = () # no users that match the pattern if not (users1 or users2): stopon1 = '<p>%s</p>' % _("no qualified users, try new search.") elif len(users1) > MAXSELECTUSERS: stopon1 = '<p><strong>%s %s</strong>, %s (%s %s)</p>' % (len(users1), _("hits"), _("too many qualified users, specify more narrow search."), _("limit"), MAXSELECTUSERS) # show matching users else: 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,'']) try: id_user = int(id_user) except ValueError: pass # user selected already connected to role email_out = acc_get_user_email(id_user) if id_user < 0: stopon2 = '<p>%s</p>' % _("users in brackets are already attached to the role, try another one...") # a user is selected elif email_out: result = insert_new_member(id_user, id_EdBoardGroup, "M") stopon2 = '<p>confirm: user <strong>%s</strong> added to the editorial board.</p>' % (email_out, ) subtitle2 = _('Removing users from the editorial board') usersremove = run_sql("""SELECT DISTINCT u.id, u.email FROM user u LEFT JOIN user_usergroup ug ON u.id = ug.id_user WHERE ug.id_usergroup = %s and user_status != 'A' AND user_status != 'P' ORDER BY u.email """, (id_EdBoardGroup, )) try: id_user_remove = int(id_user_remove) except ValueError: pass # user selected already connected to role email_out = acc_get_user_email(id_user_remove) # a user is selected if email_out: result = delete_member(id_EdBoardGroup, id_user_remove) stopon3 = '<p>confirm: user <strong>%s</strong> removed from the editorial board.</p>' % (email_out, ) t = websubmit_templates.tmpl_publiline_displaydocplxaction ( ln = ln, doctype = doctype, categ = categ, rn = RN, apptype = apptype, action = action, status = status, authors = authors, title = title, sysno = sysno, subtitle1 = subtitle1, email_user_pattern = email_user_pattern, stopon1 = stopon1, users = users, extrausers = extrausers, stopon2 = stopon2, subtitle2 = subtitle2, usersremove = usersremove, stopon3 = stopon3, validate_btn = _("Validate the editorial board selection"), ) return t elif (action == "RefereeSel") and ((apptype == "RRP") or (apptype == "RPB")): if apptype == "RRP": to_check = __is_PubCom (req, doctype) TEXT_RefereeSel_BASKET_DESCR = TEXT_RSN_RefereeSel_BASKET_DESCR TEXT_RefereeSel_MSG_REFEREE_SUBJECT = TEXT_RSN_RefereeSel_MSG_REFEREE_SUBJECT TEXT_RefereeSel_MSG_REFEREE_BODY = TEXT_RSN_RefereeSel_MSG_REFEREE_BODY + " " + "\"" + item_details['title'] + "\"" TEXT_RefereeSel_MSG_GROUP_SUBJECT = TEXT_RSN_RefereeSel_MSG_GROUP_SUBJECT TEXT_RefereeSel_MSG_GROUP_BODY = TEXT_RSN_RefereeSel_MSG_GROUP_BODY elif apptype == "RPB": to_check = __is_EdBoard (uid, id_EdBoardGroup) TEXT_RefereeSel_BASKET_DESCR = TEXT_RSN_RefereeSel_BASKET_DESCR TEXT_RefereeSel_MSG_REFEREE_SUBJECT = TEXT_RSN_RefereeSel_MSG_REFEREE_SUBJECT TEXT_RefereeSel_MSG_REFEREE_BODY = TEXT_RSN_RefereeSel_MSG_REFEREE_BODY TEXT_RefereeSel_MSG_GROUP_SUBJECT = TEXT_RSN_RefereeSel_MSG_GROUP_SUBJECT TEXT_RefereeSel_MSG_GROUP_BODY = TEXT_RSN_RefereeSel_MSG_GROUP_BODY else: to_check = None if to_check != 0: return _("Action unauthorized for this document.") + "<br /> " if status == "cancelled": return _("Action unavailable for this document.") + "<br /> " if validate == "go": if dRefereeSel == None: id_bsk = basketdb.create_basket (int(id_user_val), RN, TEXT_RefereeSel_BASKET_DESCR) basketdb.share_basket_with_group (id_bsk, id_group, CFG_WEBBASKET_SHARE_LEVELS['ADDCMT']) basketdb.add_to_basket (int(id_user_val), (sysno, ), (id_bsk, )) __db_set_basket (key, id_bsk) email_address = run_sql("""SELECT email FROM user WHERE id = %s """, (id_user_val, ))[0][0] perform_request_send (uid, email_address, "", TEXT_RefereeSel_MSG_REFEREE_SUBJECT, TEXT_RefereeSel_MSG_REFEREE_BODY, 0, 0, 0, ln, 1) group_name = run_sql("""SELECT name FROM usergroup WHERE id = %s""", (id_group, ))[0][0] perform_request_send (int(id_user_val), "", group_name, TEXT_RefereeSel_MSG_GROUP_SUBJECT, TEXT_RefereeSel_MSG_GROUP_BODY) sendMailToGroup(doctype,categ,RN,id_group,authors) return displayCplxDocument(req, doctype,categ,RN,apptype, reply, commentId, ln) subtitle1 = _('Referee selection') # remove letters not allowed in an email email_user_pattern = cleanstring_email(email_user_pattern) stopon1 = "" stopon2 = "" users = [] extrausers = [] # 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, )) - + try: + users1 = run_sql("""SELECT id, email FROM user WHERE email RLIKE %s ORDER BY email """, (email_user_pattern, )) + except OperationalError: + users1 = () # no users that match the pattern if not users1: stopon1 = '<p>%s</p>' % _("no qualified users, try new search.") elif len(users1) > MAXSELECTUSERS: stopon1 = '<p><strong>%s %s</strong>, %s (%s %s)</p>' % (len(users1), _("hits"), _("too many qualified users, specify more narrow search."), _("limit"), MAXSELECTUSERS) # show matching users else: users = [] for (user_id, email) in users1: users.append([user_id,email,'']) try: id_user = int(id_user) except ValueError: pass # user selected already connected to role email_out = acc_get_user_email(id_user) # a user is selected if email_out: stopon2 = """<p>user <strong>%s</strong> will be the referee ? <input type="hidden" name="id_user_val" value="%s" /> <input type="hidden" name="validate" value="go" /> <input class="adminbutton" type="submit" value="Validate the referee selection" /> </p>""" % (email_out, id_user) t = websubmit_templates.tmpl_publiline_displaydocplxaction ( ln = ln, doctype = doctype, categ = categ, rn = RN, apptype = apptype, action = action, status = status, authors = authors, title = title, sysno = sysno, subtitle1 = subtitle1, email_user_pattern = email_user_pattern, stopon1 = stopon1, users = users, extrausers = [], stopon2 = stopon2, subtitle2 = "", usersremove = [], stopon3 = "", validate_btn = "", ) return t elif (action == "AddAuthorList") and (apptype == "RPB"): return "" elif (action == "AddComment") and ((apptype == "RRP") or (apptype == "RPB")): t = "" if validate == "go": (errors, infos) = perform_request_save_comment (uid, id_bskBASKET, sysno, msg_subject, msg_body, ln) t += "%(infos)s<br /><br />" % {'infos' : infos[0]} t += """ <form action="publiline.py"> <input type="hidden" name="flow" value="cplx" /> <input type="hidden" name="doctype" value="%(doctype)s" /> <input type="hidden" name="categ" value="%(categ)s" /> <input type="hidden" name="RN" value="%(rn)s" /> <input type="hidden" name="apptype" value="%(apptype)s" /> <input type="submit" class="formbutton" value="%(button_label)s" /> </form>""" % {'doctype' : doctype, 'categ' : categ, 'rn' : RN, 'apptype' : apptype, 'button_label' : _("Come back to the document"), } return t elif (action == "RefereeRecom") and ((apptype == "RRP") or (apptype == "RPB")): if __is_Referee (uid, id_bskBASKET) != 0: return _("Action unauthorized for this document.") + "<br /> " if status == "cancelled": return _("Action unavailable for this document.") + "<br /> " if apptype == "RRP": # Build publication committee chair's email address user_addr = "" # Try to retrieve the publication committee chair's email from the role database for user in acc_get_role_users(acc_get_role_id("pubcomchair_%s_%s" % (doctype,categ))): user_addr += run_sql("""SELECT email FROM user WHERE id = %s """, (user[0], ))[0][0] + "," # And if there are general publication committee chair's for user in acc_get_role_users(acc_get_role_id("pubcomchair_%s_*" % doctype)): user_addr += run_sql("""SELECT email FROM user WHERE id = %s """, (user[0], ))[0][0] + "," user_addr = re.sub(",$","",user_addr) group_addr = "" TEXT_RefereeRecom_MSG_SUBJECT = TEXT_RSN_RefereeRecom_MSG_PUBCOM_SUBJECT elif apptype == "RPB": user_addr = "" group_addr = RN TEXT_RefereeRecom_MSG_SUBJECT = TEXT_RPB_RefereeRecom_MSG_EDBOARD_SUBJECT else: user_addr = "" group_addr = "" TEXT_RefereeRecom_MSG_SUBJECT = "" if validate == "approve" or validate == "reject": if dRefereeRecom == None: perform_request_send (uid, user_addr, group_addr, msg_subject, msg_body, 0, 0, 0, ln, 1) if validate == "approve": msg_body = "Approved : " + msg_body else: msg_body = "Rejected : " + msg_body #Get the Project Leader's email address email = "" for user in acc_get_role_users(acc_get_role_id("projectleader_%s_%s" % (doctype,categ))): email += run_sql("""SELECT email FROM user WHERE id = %s """, (user[0], ))[0][0] + "," sendMailToProjectLeader(doctype, categ, RN, email, authors, "referee", msg_body) sendMailtoCommitteeChair(doctype, categ, RN, user_addr, authors) __db_set_RefereeRecom_time (key) return displayCplxDocument(req, doctype,categ,RN,apptype, reply, commentId, ln) t = websubmit_templates.tmpl_publiline_displaycplxrecom ( ln = ln, doctype = doctype, categ = categ, rn = RN, apptype = apptype, action = action, status = status, authors = authors, title = title, sysno = sysno, msg_to = user_addr, msg_to_group = group_addr, msg_subject = TEXT_RefereeRecom_MSG_SUBJECT, ) return t elif (action == "EdBoardRecom") and (apptype == "RPB"): if __is_EdBoard (uid, id_EdBoardGroup) != 0: return _("Action unauthorized for this document.") + "<br /> " if status == "cancelled": return _("Action unavailable for this document.") + "<br /> " # Build publication committee chair's email address user_addr = "" # Try to retrieve the publication committee chair's email from the role database for user in acc_get_role_users(acc_get_role_id("pubcomchair_%s_%s" % (doctype,categ))): user_addr += run_sql("""SELECT nickname FROM user WHERE id = %s """, (user[0], ))[0][0] + "," # And if there are general publication committee chair's for user in acc_get_role_users(acc_get_role_id("pubcomchair_%s_*" % doctype)): user_addr += run_sql("""SELECT nickname FROM user WHERE id = %s """, (user[0], ))[0][0] + "," user_addr = re.sub(",$","",user_addr) if validate == "go": if dEdBoardRecom == None: perform_request_send (uid, user_addr, "", msg_subject, msg_body) __db_set_EdBoardRecom_time (key) return displayCplxDocument(req, doctype,categ,RN,apptype, reply, commentId, ln) t = websubmit_templates.tmpl_publiline_displaycplxrecom ( ln = ln, doctype = doctype, categ = categ, rn = RN, apptype = apptype, action = action, status = status, authors = authors, title = title, sysno = sysno, msg_to = user_addr, msg_to_group = "", msg_subject = TEXT_RPB_EdBoardRecom_MSG_PUBCOM_SUBJECT, ) return t elif (action == "PubComRecom") and ((apptype == "RRP") or (apptype == "RPB")): if __is_PubCom (req, doctype) != 0: return _("Action unauthorized for this document.") + "<br /> " if status == "cancelled": return _("Action unavailable for this document.") + "<br /> " # Build project leader's email address user_addr = "" # Try to retrieve the project leader's email from the role database for user in acc_get_role_users(acc_get_role_id("projectleader_%s_%s" % (doctype,categ))): user_addr += run_sql("""SELECT email FROM user WHERE id = %s """, (user[0], ))[0][0] + "," # And if there are general project leader's for user in acc_get_role_users(acc_get_role_id("projectleader_%s_*" % doctype)): user_addr += run_sql("""SELECT email FROM user WHERE id = %s """, (user[0], ))[0][0] + "," user_addr = re.sub(",$","",user_addr) if apptype == "RRP": TEXT_PubComRecom_MSG_SUBJECT = TEXT_RSN_PubComRecom_MSG_PRJLEADER_SUBJECT elif apptype == "RPB": group_addr = RN TEXT_PubComRecom_MSG_SUBJECT = TEXT_RPB_PubComRecom_MSG_PRJLEADER_SUBJECT else: TEXT_PubComRecom_MSG_SUBJECT = "" if validate == "approve" or validate == "reject": if validate == "approve": msg_body = "Approved : " + msg_body else: msg_body = "Rejected : " + msg_body if dPubComRecom == None: perform_request_send (uid, user_addr, "", msg_subject, msg_body, 0, 0, 0, ln, 1) sendMailToProjectLeader(doctype, categ, RN, user_addr, authors, "publication committee chair", msg_body) __db_set_PubComRecom_time (key) return displayCplxDocument(req, doctype,categ,RN,apptype, reply, commentId, ln) t = websubmit_templates.tmpl_publiline_displaycplxrecom ( ln = ln, doctype = doctype, categ = categ, rn = RN, apptype = apptype, action = action, status = status, authors = authors, title = title, sysno = sysno, msg_to = user_addr, msg_to_group = "", msg_subject = TEXT_PubComRecom_MSG_SUBJECT + " " + "\"" + item_details['title'] + "\"", ) return t elif (action == "ProjectLeaderDecision") and ((apptype == "RRP") or (apptype == "RPB")): if __is_ProjectLeader (req, doctype, categ) != 0: return _("Action unauthorized for this document.") + "<br /> " if status == "cancelled": return _("Action unavailable for this document.") + "<br /> " t += """ <form action="publiline.py"> <input type="hidden" name="flow" value="cplx" /> <input type="hidden" name="doctype" value="%(doctype)s" /> <input type="hidden" name="categ" value="%(categ)s" /> <input type="hidden" name="RN" value="%(rn)s" /> <input type="hidden" name="apptype" value="%(apptype)s" /> <input type="submit" class="formbutton" value="%(button_label)s" /> </form>""" % {'doctype' : doctype, 'categ' : categ, 'rn' : RN, 'apptype' : apptype, 'button_label' : _("Come back to the document"), } if validate == "approve": if dProjectLeaderAction == None: (errors, infos) = perform_request_save_comment (uid, id_bskBASKET, sysno, msg_subject, msg_body, ln) out = "%(infos)s<br /><br />" % {'infos' : infos[0]} sendMailToSubmitter(doctype, categ, RN, "approved") __db_set_status (key, 'approved') return out + t elif validate == "reject": if dProjectLeaderAction == None: (errors, infos) = perform_request_save_comment (uid, id_bskBASKET, sysno, msg_subject, msg_body, ln) out = "%(infos)s<br /><br />" % {'infos' : infos[0]} sendMailToSubmitter(doctype, categ, RN, "rejected") __db_set_status (key, 'rejected') return out + t validation = """ <select name="validate"> <option> %(select)s</option> <option value="approve">%(approve)s</option> <option value="reject">%(reject)s</option> </select> <input type="submit" class="formbutton" value="%(button_label)s" />""" % {'select' : _('Select:'), 'approve' : _('Approve'), 'reject' : _('Reject'), 'button_label' : _('Take a decision'), } if apptype == "RRP": TEXT_ProjectLeaderDecision_MSG_SUBJECT = TEXT_RSN_ProjectLeaderDecision_MSG_SUBJECT elif apptype == "RPB": TEXT_ProjectLeaderDecision_MSG_SUBJECT = TEXT_RPB_ProjectLeaderDecision_MSG_SUBJECT else: TEXT_ProjectLeaderDecision_MSG_SUBJECT = "" t = websubmit_templates.tmpl_publiline_displaywritecomment(doctype, categ, RN, apptype, action, _("Take a decision"), TEXT_ProjectLeaderDecision_MSG_SUBJECT, validation, "", ln) return t elif (action == "ProjectLeaderDecision") and (apptype == "RDA"): if __is_ProjectLeader (req, doctype, categ) != 0: return _("Action unauthorized for this document.") + "<br /> " if status == "cancelled": return _("Action unavailable for this document.") + "<br /> " if validate == "approve": if dProjectLeaderAction == None: __db_set_status (key, 'approved') return displayCplxDocument(req, doctype,categ,RN,apptype, reply, commentId, ln) elif validate == "reject": if dProjectLeaderAction == None: __db_set_status (key, 'rejected') return displayCplxDocument(req, doctype,categ,RN,apptype, reply, commentId, ln) t = """<p> <form action="publiline.py"> <input type="hidden" name="flow" value="cplx" /> <input type="hidden" name="doctype" value="%(doctype)s" /> <input type="hidden" name="categ" value="%(categ)s" /> <input type="hidden" name="RN" value="%(rn)s" /> <input type="hidden" name="apptype" value="%(apptype)s" /> <input type="hidden" name="action" value="%(action)s" /> <input type="hidden" name="validate" value="approve" /> <input class="adminbutton" type="submit" value="%(approve)s" /> </form> <form action="publiline.py"> <input type="hidden" name="flow" value="cplx" /> <input type="hidden" name="doctype" value="%(doctype)s" /> <input type="hidden" name="categ" value="%(categ)s" /> <input type="hidden" name="RN" value="%(rn)s" /> <input type="hidden" name="apptype" value="%(apptype)s" /> <input type="hidden" name="action" value="%(action)s" /> <input type="hidden" name="validate" value="reject" /> <input class="adminbutton" type="submit" value="%(reject)s" /> </form> </p>""" % { 'rn' : RN, 'categ' : categ, 'doctype' : doctype, 'apptype' : apptype, 'action' : action, 'approve' : _('Approve'), 'reject' : _('Reject'), } return t elif (action == "AuthorCancel") and ((apptype == "RRP") or (apptype == "RPB") or (apptype == "RDA")): if __is_Author (uid, sysno) != 0: return _("Action unauthorized for this document.") + "<br /> " if (status == "cancelled") or (dProjectLeaderAction != None): return _("Action unavailable for this document.") + "<br /> " if validate == "go": __db_set_status (key, 'cancelled') return displayCplxDocument(req, doctype,categ,RN,apptype, reply, commentId, ln) t = """<p> <form action="publiline.py"> <input type="hidden" name="flow" value="cplx" /> <input type="hidden" name="doctype" value="%(doctype)s" /> <input type="hidden" name="categ" value="%(categ)s" /> <input type="hidden" name="RN" value="%(rn)s" /> <input type="hidden" name="apptype" value="%(apptype)s" /> <input type="hidden" name="action" value="%(action)s" /> <input type="hidden" name="validate" value="go" /> <input class="adminbutton" type="submit" value="%(cancel)s" /> </form> </p>""" % { 'rn' : RN, 'categ' : categ, 'doctype' : doctype, 'apptype' : apptype, 'action' : action, 'cancel' : _('Cancel'), } return t else: return _("Wrong action for this document.") + "<br /> " return t def get_pending_item_details(doctype, reportnumber): """Given a doctype and reference number, try to retrieve an item's details. The first place to search for them should be the WebSubmit pending directory. If nothing is retrieved from there, and attempt is made to retrieve them from the CDS Invenio repository itself. @param doctype: (string) - the doctype of the item for which brief details are to be retrieved. @param reportnumber: (string) - the report number of the item for which details are to be retrieved. @return: (dictionary or None) - If details are found for the item, they will be returned in a dictionary structured as follows: { 'title' : '-', ## String - the item's title 'recid' : '', ## String - recid taken from the SN file 'report-number' : '', ## String - the item's report number 'authors' : [], ## List - the item's authors } If no details were found a NoneType is returned. """ ## First try to get the details of a document from the pending dir: item_details = get_brief_doc_details_from_pending(doctype, \ reportnumber) if item_details is None: item_details = get_brief_doc_details_from_repository(reportnumber) ## Return the item details: return item_details def get_brief_doc_details_from_pending(doctype, reportnumber): """Try to get some brief details about the submission that is awaiting the referee's decision. Details sought are: + title + Authors + recid (why?) + report-number (why?) This function searches for a MARC XML record in the pending submission's working directory. It prefers the so-called 'dummy' record, but will search for the final MARC XML record that would usually be passed to bibupload (i.e. recmysql) if that is not present. If neither of these records are present, no details will be found. @param doctype: (string) - the WebSubmit document type of the item to be refereed. It is used in order to locate the submission's working directory in the WebSubmit pending directory. @param reportnumber: (string) - the report number of the item for which details are to be recovered. It is used in order to locate the submission's working directory in the WebSubmit pending directory. @return: (dictionary or None) - If details are found for the item, they will be returned in a dictionary structured as follows: { 'title' : '-', ## String - the item's title 'recid' : '', ## String - recid taken from the SN file 'report-number' : '', ## String - the item's report number 'authors' : [], ## List - the item's authors } If no details were found (i.e. no MARC XML files in the submission's working directory), a NoneType is returned. """ pending_doc_details = None marcxml_rec_name = None ## Check for a MARC XML record in the pending dir. ## If it's there, we will use it to obtain certain bibliographic ## information such as title, author(s), etc, which we will then ## display to the referee. ## We favour the "dummy" record (created with the WebSubmit function ## "Make_Dummy_MARC_XML_Record"), because it was made for this ## purpose. If it's not there though, we'll take the normal ## (final) recmysql record that would generally be passed to bibupload. if os.access("%s/%s/%s/%s" % (CFG_WEBSUBMIT_PENDING_DIR, \ doctype, \ reportnumber, \ CFG_WEBSUBMIT_DUMMY_MARC_XML_REC), \ os.F_OK|os.R_OK): ## Found the "dummy" marc xml record in the submission dir. ## Use it: marcxml_rec_name = CFG_WEBSUBMIT_DUMMY_MARC_XML_REC elif os.access("%s/%s/%s/%s" % (CFG_WEBSUBMIT_PENDING_DIR, \ doctype, \ reportnumber, \ CFG_WEBSUBMIT_MARC_XML_REC), \ os.F_OK|os.R_OK): ## Although we didn't find the "dummy" marc xml record in the ## submission dir, we did find the "real" one (that which would ## normally be passed to bibupload). Use it: marcxml_rec_name = CFG_WEBSUBMIT_MARC_XML_REC ## If we have a MARC XML record in the pending submission's ## working directory, go ahead and use it: if marcxml_rec_name is not None: try: fh_marcxml_record = open("%s/%s/%s/%s" \ % (CFG_WEBSUBMIT_PENDING_DIR, \ doctype, \ reportnumber, \ marcxml_rec_name), "r") xmltext = fh_marcxml_record.read() fh_marcxml_record.close() except IOError: ## Unfortunately, it wasn't possible to read the details of the ## MARC XML record. Register the exception. exception_prefix = "Error: Publiline was unable to read the " \ "MARC XML record [%s/%s/%s/%s] when trying to " \ "use it to recover details about a pending " \ "submission." % (CFG_WEBSUBMIT_PENDING_DIR, \ doctype, \ reportnumber, \ marcxml_rec_name) register_exception(prefix=exception_prefix) else: ## Attempt to use bibrecord to create an internal representation ## of the record, from which we can extract certain bibliographic ## information: records = create_records(xmltext, 1, 1) try: record = records[0][0] except IndexError: ## Bibrecord couldn't successfully represent the record ## contained in the xmltext string. The record must have ## been empty or badly formed (or something). pass else: ## Dictionary to hold the interesting details of the ## pending item: pending_doc_details = { 'title' : '-', 'recid' : '', 'report-number' : '', 'authors' : [], } ## Get the recid: ## Note - the old "getInPending" function reads the "SN" ## file from the submission's working directory and since ## the "SN" file is currently "magic" and hardcoded ## throughout WebSubmit, I'm going to stick to this model. ## I could, however, have tried to get it from the MARC XML ## record as so: ## recid = record_get_field_value(rec=record, tag="001") try: fh_recid = open("%s/%s/%s/SN" \ % (CFG_WEBSUBMIT_PENDING_DIR, \ doctype, \ reportnumber), "r") recid = fh_recid.read() fh_recid.close() except IOError: ## Probably, there was no "SN" file in the submission's ## working directory. pending_doc_details['recid'] = "" else: pending_doc_details['recid'] = recid.strip() ## Item report number (from record): ## Note: I don't know what purpose this serves. It appears ## to be used in the email that is sent to the author, but ## it seems funny to me, since we already have the report ## number (which is indeed used to find the submission's ## working directory in pending). Perhaps it's used for ## cases when the reportnumber is changed after approval? ## To investigate when time allows: finalrn = record_get_field_value(rec=record, \ tag="037", \ code="a") if finalrn != "": pending_doc_details['report-number'] = finalrn ## Item title: title = record_get_field_value(rec=record, \ tag="245", \ code="a") if title != "": pending_doc_details['title'] = title else: ## Alternative title: alt_title = record_get_field_value(rec=record, \ tag="246", \ ind1="1", \ code="a") if alt_title != "": pending_doc_details['title'] = alt_title ## Item first author: first_author = record_get_field_value(rec=record, \ tag="100", \ code="a") if first_author != "": pending_doc_details['authors'].append(first_author) ## Other Authors: other_authors = record_get_field_values(rec=record, \ tag="700", \ code="a") for author in other_authors: pending_doc_details['authors'].append(author) ## Return the details discovered about the pending document: return pending_doc_details def get_brief_doc_details_from_repository(reportnumber): """Try to get some brief details about the submission that is awaiting the referee's decision. Details sought are: + title + Authors + recid (why?) + report-number (why?) + email This function searches in the CDS Invenio repository, based on "reportnumber" for a record and then pulls the interesting fields from it. @param reportnumber: (string) - the report number of the item for which details are to be recovered. It is used in the search. @return: (dictionary or None) - If details are found for the item, they will be returned in a dictionary structured as follows: { 'title' : '-', ## String - the item's title 'recid' : '', ## String - recid taken from the SN file 'report-number' : '', ## String - the item's report number 'authors' : [], ## List - the item's authors } If no details were found a NoneType is returned. """ ## Details of the pending document, as found in the repository: pending_doc_details = None ## Search for records matching this "report number" found_record_ids = list(search_pattern(req=None, \ p=reportnumber, \ f="reportnumber", \ m="e")) ## How many records were found? if len(found_record_ids) == 1: ## Found only 1 record. Get the fields of interest: pending_doc_details = { 'title' : '-', 'recid' : '', 'report-number' : '', 'authors' : [], 'email' : '', } recid = found_record_ids[0] ## Authors: first_author = get_fieldvalues(recid, "100__a") for author in first_author: pending_doc_details['authors'].append(author) other_authors = get_fieldvalues(recid, "700__a") for author in other_authors: pending_doc_details['authors'].append(author) ## Title: title = get_fieldvalues(recid, "245__a") if len(title) > 0: pending_doc_details['title'] = title[0] else: ## There was no value for title - check for an alternative title: alt_title = get_fieldvalues(recid, "2641_a") if len(alt_title) > 0: pending_doc_details['title'] = alt_title[0] ## Record ID: pending_doc_details['recid'] = recid ## Report Number: reptnum = get_fieldvalues(recid, "037__a") if len(reptnum) > 0: pending_doc_details['report-number'] = reptnum[0] ## Email: email = get_fieldvalues(recid, "859__f") if len(email) > 0: pending_doc_details['email'] = email[0] elif len(found_record_ids) > 1: ## Oops. This is unexpected - there shouldn't be me multiple matches ## for this item. The old "getInAlice" function would have simply ## taken the first record in the list. That's not very nice though. ## Some kind of warning or error should be raised here. FIXME. pass return pending_doc_details # Retrieve info about document def getInfo(doctype,categ,RN): """FIXME: DEPRECATED!""" 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): """FIXME: DEPRECATED!""" PENDIR="%s/pending" % CFG_WEBSUBMIT_STORAGEDIR 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): """FIXME: DEPRECATED!""" # initialize sysno variable sysno = "" searchresults = list(search_pattern(req=None, p=RN, f="reportnumber")) 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>' % (CFG_SITE_NAME,CFG_SITE_SUPPORT_EMAIL) # 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("<CATEG>","([^-]*)",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>",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_get_role_users(acc_get_role_id("referee_%s_%s" % (doctype,categ))): refereeaddress += user[1] + "," # And if there are general referees for user in acc_get_role_users(acc_get_role_id("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,CFG_SITE_URL,sysno,CFG_SITE_URL,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>' % (CFG_SITE_NAME,CFG_SITE_SUPPORT_EMAIL) message = "Failed sending approval email request for %s" % RN # send the mail send_email(FROMADDR,CFG_SITE_ADMIN_EMAIL,"Failed sending approval email request",message) return "" def errorMsg(title,req,c=CFG_SITE_NAME,ln=CFG_SITE_LANG): 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, uid = getUid(req), language=ln, req=req, navmenuid='yourapprovals') def warningMsg(title,req,c=CFG_SITE_NAME,ln=CFG_SITE_LANG): return page(title="warning", body = title, description="%s - Internal Error" % c, keywords="%s, Internal Error" % c, uid = getUid(req), language=ln, req=req, navmenuid='yourapprovals') def sendMailToReferee(doctype,categ,RN,email,authors): item_details = get_brief_doc_details_from_repository(RN) ## get_brief_doc_details_from_repository has returned either None ## or a dictionary with the following structure: ## { 'title' : '-', ## String - the item's title ## 'recid' : '', ## String - recid ## 'report-number' : '', ## String - the item's report number ## 'authors' : [], ## List - the item's authors ## } FROMADDR = '%s Submission Engine <%s>' % (CFG_SITE_NAME,CFG_SITE_SUPPORT_EMAIL) message = """ Scientific Note approval for document %s has been submitted to the CERN Document Server. Your reccommendation is requested on it. Requested subcategory: %s Title: %s Author(s): %s To access the document(s), select the file(s) from the location: <%s/record/%s> To make a reccommendation, you should go to this URL: <%s> You can also check the status of the document: <%s> --------------------------------------------- Best regards. The submission team.""" % (str(RN), str(categ), str(item_details['title']), authors, CFG_SITE_URL, str(item_details['recid']), str(CFG_SITE_URL + "/publiline.py?flow=cplx&doctype="+doctype+"&ln=en&apptype=RRP&categ="+categ+"&RN="+RN+"&action=RefereeRecom"), str(CFG_SITE_URL + "/publiline.py?flow=cplx&doctype="+doctype+"&ln=en&apptype=RRP&categ="+categ+"&RN="+RN)) # send the mail send_email(FROMADDR, email,"Request for document %s recommendation" % (RN),message) return "" def sendMailToGroup(doctype,categ,RN,group_id,authors): item_details = get_brief_doc_details_from_repository(RN) ## get_brief_doc_details_from_repository has returned either None ## or a dictionary with the following structure: ## { 'title' : '-', ## String - the item's title ## 'recid' : '', ## String - recid ## 'report-number' : '', ## String - the item's report number ## 'authors' : [], ## List - the item's authors ## } FROMADDR = '%s Submission Engine <%s>' % (CFG_SITE_NAME,CFG_SITE_SUPPORT_EMAIL) message = """ Scientific Note approval for document %s has been submitted to the CERN Document Server. Your comments are requested on this document. Requested subcategory: %s Title: %s Author(s): %s To access the document(s), select the file(s) from the location: <%s/record/%s> To leave a comment or check the status of the approval process, you should go to this URL: <%s> """ % (str(RN), str(categ), str(item_details['title']), authors, CFG_SITE_URL, str(item_details['recid']), str(CFG_SITE_URL + "/publiline.py?flow=cplx&doctype="+doctype+"&ln=en&apptype=RRP&categ="+categ+"&RN="+RN)) # send mails to all members of the ATLAS group group_member_ids = run_sql("SELECT id_user FROM user_usergroup WHERE id_usergroup = '%s'" % (group_id)) for member_id in group_member_ids: member_email = run_sql("SELECT email FROM user WHERE id = '%s'" % (member_id)) if not member_email[0][0] == "cds.support@cern.ch": send_email(FROMADDR, member_email[0][0],"Request for comment on document %s" % (RN),message) return "" def sendMailToProjectLeader(doctype, categ, RN, email, authors, actor, recommendation): item_details = get_brief_doc_details_from_repository(RN) ## get_brief_doc_details_from_repository has returned either None ## or a dictionary with the following structure: ## { 'title' : '-', ## String - the item's title ## 'recid' : '', ## String - recid ## 'report-number' : '', ## String - the item's report number ## 'authors' : [], ## List - the item's authors ## } FROMADDR = '%s Submission Engine <%s>' % (CFG_SITE_NAME,CFG_SITE_SUPPORT_EMAIL) message = """ Scientific Note approval for document %s has been submitted to the CERN Document Server. Your approval is requested for this document. Once you have received recommendations from both the referee and the publication committee chair, you will be able to make your decision. Requested subcategory: %s Title: %s Author(s): %s To access the document(s), select the file(s) from the location: <%s/record/%s> The %s has made a recommendation for the document. He/she said the following: %s You can approve this document by visiting this page: <%s> """ % (str(RN), str(categ), str(item_details['title']), authors, CFG_SITE_URL, str(item_details['recid']), actor, recommendation, str(CFG_SITE_URL + "/publiline.py?flow=cplx&doctype="+doctype+"&ln=en&apptype=RRP&categ="+categ+"&RN="+RN+"&action=ProjectLeaderDecision")) # send mails to all members of the ATLAS group send_email(FROMADDR, email,"Request for approval/rejection of document %s" % (RN),message) return "" def sendMailToSubmitter(doctype, categ, RN, outcome): item_details = get_brief_doc_details_from_repository(RN) ## get_brief_doc_details_from_repository has returned either None ## or a dictionary with the following structure: ## { 'title' : '-', ## String - the item's title ## 'recid' : '', ## String - recid ## 'report-number' : '', ## String - the item's report number ## 'authors' : [], ## List - the item's authors ## } FROMADDR = '%s Submission Engine <%s>' % (CFG_SITE_NAME,CFG_SITE_SUPPORT_EMAIL) message = """ The approval process for your document : %s, has been completed. The details of this document are as follows: Requested subcategory: %s Title: %s The project leader has made the following recommendation for the document: %s """ % (RN, categ, item_details['title'], outcome) # send mails to all members of the ATLAS group send_email(FROMADDR, item_details['email'],"Final outcome for approval of document : %s" % (RN),message) return "" def sendMailtoCommitteeChair(doctype, categ, RN, email, authors): item_details = get_brief_doc_details_from_repository(RN) ## get_brief_doc_details_from_repository has returned either None ## or a dictionary with the following structure: ## { 'title' : '-', ## String - the item's title ## 'recid' : '', ## String - recid ## 'report-number' : '', ## String - the item's report number ## 'authors' : [], ## List - the item's authors ## } FROMADDR = '%s Submission Engine <%s>' % (CFG_SITE_NAME,CFG_SITE_SUPPORT_EMAIL) message = """ The referree assigned to the document detailed below has made a reccommendation. You are now requested to make a reccommendation of your own. Requested subcategory: %s Title: %s Author(s): %s To access the document(s), select the file(s) from the location: <%s/record/%s> You can make a reccommendation by visiting this page: <%s> """ % (str(categ), str(item_details['title']), authors, CFG_SITE_URL, str(item_details['recid']), str(CFG_SITE_URL + "/publiline.py?flow=cplx&doctype="+doctype+"&ln=en&apptype=RRP&categ="+categ+"&RN="+RN)) # send mails to all members of the ATLAS group send_email(FROMADDR, email,"Request for reccommendation of document %s" % (RN),message)