def admin_main(user, admin, mode, **kwargs): scriptpath = os.path.dirname(os.path.realpath(__file__)) + os.sep userdir = scriptpath + "users" + os.sep config = ConfigObj(userdir + 'config.ini') exportdir = scriptpath + config['exportdir'].replace("/", os.sep) theform = kwargs cgitb.enable() import re def is_email(email): pattern = '[\.\w]{1,}[@]\w+[.]\w+' if re.match(pattern, email): return True else: return False config = ConfigObj(userdir + 'config.ini') templatedir = scriptpath + config['controltemplates'].replace("/", os.sep) template = "main_header.html" header = readfile(templatedir + template) header = header.replace("**page_title**", "Administration") header = header.replace("**user**", user) importdir = scriptpath + config['importdir'].replace("/", os.sep) def_relfile = scriptpath + config['default_rels'].replace("/", os.sep) cpout = "" if mode == "server": cpout += "Content-Type: text/html\n\n\n" header = header.replace("**logout_control**", '(<a href="logout.py">log out</a>)') else: header = header.replace("**logout_control**", '') cpout += header if "current_doc" in theform: current_doc = theform["current_doc"] current_project = theform["current_project"] else: current_doc = "" current_project = "" edit_bar = "edit_bar.html" edit_bar = readfile(templatedir + edit_bar) edit_bar = edit_bar.replace("**doc**", current_doc) edit_bar = edit_bar.replace("**project**", current_project) edit_bar = edit_bar.replace("**structure_disabled**", '') edit_bar = edit_bar.replace("**segment_disabled**", '') edit_bar = edit_bar.replace("**relations_disabled**", '') edit_bar = edit_bar.replace("**submit_target**", 'admin.py') edit_bar = edit_bar.replace("**action_type**", '') edit_bar = edit_bar.replace("**serve_mode**", mode) edit_bar = edit_bar.replace("**open_disabled**", '') edit_bar = edit_bar.replace("**reset_disabled**", 'disabled="disabled"') edit_bar = edit_bar.replace("**quickexp_disabled**", 'disabled="disabled"') edit_bar = edit_bar.replace("**screenshot_disabled**", 'disabled="disabled"') edit_bar = edit_bar.replace("**save_disabled**", 'disabled="disabled"') edit_bar = edit_bar.replace("**undo_disabled**", 'disabled="disabled"') edit_bar = edit_bar.replace("**redo_disabled**", 'disabled="disabled"') edit_bar = edit_bar.replace("**admin_disabled**", 'disabled="disabled"') edit_bar = edit_bar.replace( 'id="nav_admin" class="nav_button"', 'id="nav_admin" class="nav_button nav_button_inset"') if admin == "0": cpout += '<p class="warn">User ' + user + ' does not have administrator rights!</p></body></html>' return cpout else: edit_bar = edit_bar.replace("**admin_disabled**", '') cpout += edit_bar help = "help.html" help = readfile(templatedir + help) help_match = re.search(r'(<div id="help_admin".*?</div>)', help, re.MULTILINE | re.DOTALL) help = help_match.group(1) cpout += help about = "about.html" about = readfile(templatedir + about) about = about.replace("**version**", _version.__version__) cpout += about if "wipe" in theform: if theform["wipe"] == "wipe": setup_db() if "create_project" in theform: new_project = theform["create_project"] if len(new_project) > 0: create_project(new_project) if "doclist" in theform: current_doc = theform["doclist"] else: current_doc = "" cpout += ''' <div id="control"> <form id="admin_form" name="id_form" action="admin.py" method="post" enctype="multipart/form-data"> <input type="hidden" name="create_project" id="create_project" value=""/> <input type="hidden" name="sel_tab" id="sel_tab" value="project"/> <input type="hidden" name="delete" id="delete" value=""/> <input type="hidden" name="delete_user" id="delete_user" value=""/> <input type="hidden" name="export" id="export" value=""/> <input type="hidden" name="wipe" id="wipe" value=""/> <input type="hidden" name="switch_signals" id="switch_signals" value=""/> <input type="hidden" name="signals_file" id="signals_file" value=""/> <input type="hidden" name="switch_logging" id="switch_logging" value=""/> <input type="hidden" name="switch_span_buttons" id="switch_span_buttons" value=""/> <input type="hidden" name="switch_multinuc_buttons" id="switch_multinuc_buttons" value=""/> <input type="hidden" name="update_schema" id="update_schema" value=""/> <input type="hidden" name="imp_project" id="imp_project" value=""/> <input type="hidden" name="import_file_type" id="import_file_type" value=""/> <input type="hidden" name="do_tokenize" id="do_tokenize" value=""/> <input type="hidden" name="doclist" id="doclist" value="''' cpout += current_doc cpout += '''"/> <input type="hidden" name="userlist" id="userlist" value=""/> <input type="hidden" name="assign_doc" id="assign_doc" value=""/> <input type="hidden" name="assign_user" id="assign_user" value=""/> <input type="hidden" name="unassign_doc" id="unassign_doc" value=""/> <input type="hidden" name="unassign_user" id="unassign_user" value=""/> <input type="hidden" name="new_user_data" id="new_user_data" value=""/> <input type="hidden" name="edit_validation" id="edit_validation" value=""/> <input type="hidden" name="del_project" id="del_project" value=""/> <input type="hidden" name="guidelines_url" id="guidelines_url" value=""/> <input id="file" type="file" name="file" multiple="multiple"/> </form> <script src="./script/admin.js"></script> <script src="./script/jquery-1.11.3.min.js"></script> <script src="./script/jquery-ui.min.js"></script> ''' cpout += ''' <div class="tab_btn" id="project_btn" onclick="open_tab('project');">Projects</div><div id="project" class="tab"> <h2>Manage Projects</h2> <p>Create a new project named: <input id="new_project"/></p> <button onclick="admin('create_project')">Create Project</button> ''' #cpout += theform if "update_schema" in theform: if theform["update_schema"] == "update_schema": update_schema() if "del_project" in theform: projects_to_delete = theform["del_project"].split(";") if len(projects_to_delete) > 0: if isinstance(projects_to_delete, list): for project in projects_to_delete: delete_project(project) else: delete_project(projects_to_delete) all_project_list = get_all_projects() url_message = "" if "guidelines_url" in theform: if "::" in theform["guidelines_url"]: project_list, guideline_url = theform["guidelines_url"].split("::") if len(project_list) > 0: schema = get_schema() if schema < 2: update_schema() if isinstance(project_list, list): for project in project_list: set_guidelines_url(project, guideline_url) else: set_guidelines_url(project_list, guideline_url) url_message = '<p class="warn">Added the URL ' + guideline_url + " to the selected projects</p>" cpout += '<p>Existing projects:</p>' if all_project_list: cpout += '<select class="doclist" id="project_select" size="5" multiple="multiple">\n' for project in all_project_list: cpout += '\t<option value="' + project[0] + '">' + project[ 0] + "</option>" cpout += '</select>\n' else: cpout += '<p class="warn">No projects found!</p>' cpout += '''<p> <p>Add guidelines URL to selected project:</p><p><input id="guidelines_url_input"/></p> <button onclick="admin('guidelines_url')">Add URL</button> ''' + url_message cpout += ''' <p>Delete selected projects:</p> <button onclick="admin('delete_project')">Delete Selected</button></p> ''' # Handle validation settings validation_message = "" val_project = "" if "edit_validation" in theform: if "::" in theform["edit_validation"]: val_project, validations = theform["edit_validation"].split("::") schema = get_schema() if schema < 5: update_schema() set_project_validations(val_project, validations) validation_message = '<p class="warn">Updated validation settings for project ' + val_project cpout += '''<p>Change annotation warning settings for project:</p>''' if all_project_list: cpout += '''<select class="doclist" id="validate_project_select" onchange="toggle_validation_project();">\n''' if val_project == "": val_project = all_project_list[0][0] for project in all_project_list: if project[0] == val_project: sel_string = ' selected="selected"' else: sel_string = "" cpout += '\t<option value="' + project[ 0] + '"' + sel_string + '>' + project[0] + "</option>\n" cpout += '</select>\n' for project in all_project_list: vals = get_project_validations(project[0]) cpout += '\t<input id="validations_' + project[ 0] + '" type="hidden" value="' + vals + '">' else: cpout += "<p>No projects found with permissions for user: "******"</p>" validations = get_project_validations(val_project) validation_list = validations.split(";") checked = "" if "validate_empty" in validation_list: checked = " checked" cpout += '''<br><br><label class="switch"> <input type="checkbox" id="check_empty_span" onclick="admin('toggle_validations');"''' + checked + '''> <div class="slider round"></div> </label><div style="position: relative; top: -3px; left: 3px; display: inline-block">Warn on empty span <a class="tooltip" href=""> <i class="fa fa-question-circle"> </i> <span><img src="img/empty_span.png" height="100px"> <i>Highlights spans with single span child</i> </span> </a></div> ''' checked = "" if "validate_flat" in validation_list: checked = " checked" cpout += '''<br><label class="switch"> <input type="checkbox" id="check_flat_rst" onclick="admin('toggle_validations');"''' + checked + '''> <div class="slider round"></div> </label><div style="margin-top: 10px; position: relative; top: -3px; left: 3px; display: inline-block">Warn on multiple incoming flat RST relations <a class="tooltip" href=""> <i class="fa fa-question-circle"> </i> <span><img src="img/flat_rst.png" height="75px"> <i>Highlights spans with multiple incoming satellites</i> </span> </a></div> ''' checked = "" if "validate_mononuc" in validation_list: checked = " checked" cpout += '''<br><label class="switch"> <input type="checkbox" id="check_mononuc" onclick="admin('toggle_validations');"''' + checked + '''> <div class="slider round"></div> </label><div style="margin-top: 10px; position: relative; top: -3px; left: 3px; display: inline-block">Warn on multinucs with single child <a class="tooltip" href=""> <i class="fa fa-question-circle"> </i> <span><img src="img/mononuc.png" height="75px"> <i>Highlights multinucs with a single child</i> </span> </a></div> <script> selproj = document.getElementById("validate_project_select").value; validations = document.getElementById("validations_" + selproj).value; if (validations.indexOf("validate_flat")>0){ document.getElementById("check_flat_rst").checked = true; } if (validations.indexOf("validate_empty")>0){ document.getElementById("check_empty_span").checked = true; } if (validations.indexOf("validate_mononuc")>0){ document.getElementById("check_mononuc").checked = true; } </script>''' cpout += validation_message cpout += ''' </div>''' cpout += ''' <div class="tab_btn" id="import_btn" onclick="open_tab('import');">Import</div><div id="import" class="tab"> <h2>Import a Document</h2> <p>1. Upload .rs3 or plain text file(s): </p> <p>2. Choose file type: <select id="import_file_type_select" class="doclist"><option value="rs3">rs3</option><option value="plain">plain text (EDU per line)</option></select> </p> <p>3. Tokenize words automatically? <input type="checkbox" name="tokenize" id="tokenize"></p> <p>4. Import document(s) into this project: ''' if all_project_list: cpout += '<select class="doclist" id="imp_project_select">\n' if isinstance(all_project_list, list): for project in all_project_list: cpout += '\t<option value="' + project[0] + '">' + project[ 0] + "</option>" else: cpout += '\t<option value="' + all_project_list + '">' + all_project_list + "</option>" cpout += '</select>\n' else: cpout += "<p>No projects found with permissions for user: "******"</p>" cpout += ''' </p> <p><button onclick="admin('upload')">Upload</button></p> ''' fail = 0 if "file" in theform and "imp_project" in theform: fileitem = theform['file'] imp_project = theform["imp_project"] do_tokenize = theform["do_tokenize"] == "tokenize" if isinstance(fileitem, list): message = "" for filelist_item in fileitem: if filelist_item.filename and len( imp_project ) > 0: # Test if the file was uploaded and a project selection exists # strip leading path from file name to avoid directory traversal attacks fn = os.path.basename(filelist_item.filename) open(importdir + fn, 'wb').write(filelist_item.file.read()) message += 'The file "' + fn + '" was uploaded successfully<br/>' if theform['import_file_type'] == "rs3": fail = import_document(importdir + fn, imp_project, user, do_tokenize=do_tokenize) elif theform['import_file_type'] == "plain": if len(def_relfile) > 0: rel_hash = read_relfile(def_relfile) else: rel_hash = {} fail = import_plaintext(importdir + fn, imp_project, user, rel_hash, do_tokenize=do_tokenize) else: message = 'No file was uploaded' else: if fileitem.filename and len( imp_project ) > 0: # Test if the file was uploaded and a project selection exists # strip leading path from file name to avoid directory traversal attacks fn = os.path.basename(fileitem.filename) open(importdir + fn, 'wb').write(fileitem.file.read()) message = 'The file "' + fn + '" was uploaded successfully' if theform['import_file_type'] == "rs3": fail = import_document(importdir + fn, imp_project, user, do_tokenize=do_tokenize) elif theform['import_file_type'] == "plain": if len(def_relfile) > 0: rel_hash = read_relfile(def_relfile) else: rel_hash = {} fail = import_plaintext(importdir + fn, imp_project, user, rel_hash, do_tokenize=do_tokenize) else: message = 'No file was uploaded' if isinstance(fail, basestring): message = fail cpout += """ <p class="warn">%s</p> """ % (message, ) cpout += '</div><div class="tab_btn" id="docs_btn" onclick="open_tab(' + "'" + "docs" + "'" + ');">Documents</div><div id="docs" class="tab">' cpout += "<h2>Current Documents</h2>" if "delete" in theform: #execute delete documents before retrieving doclist doclist = theform["doclist"] if len(doclist) > 0 and theform["delete"] == "delete": docs_to_delete = doclist.split(";") if len(docs_to_delete) > 0: if isinstance(docs_to_delete, list): for doc in docs_to_delete: delete_document(doc.split("/")[1], doc.split("/")[0]) else: delete_document( docs_to_delete.split("/")[1], docs_to_delete.split("/")[0]) cpout += '<p class="warn">Deletion complete</p>' cpout += '<p>List of documents in the database:</p>' docs = get_all_docs_by_project() if not docs: cpout += "<p>No documents found with permissions for user name: " + user + "</p>" else: cpout += '<select name="doclist_select" id="doclist_select" class="doclist" size="15" multiple="multiple">\n' project_group = "" for doc in docs: if project_group != doc[1]: if project_group != "": cpout += '</optgroup>\n' project_group = doc[1] cpout += '<optgroup label="' + doc[1] + '">\n' cpout += '\t<option value="' + doc[1] + "/" + doc[0] + '">' + doc[ 0] + '</option>\n' cpout += '</optgroup>\n</select>\n' cpout += ''' <p>Export selected document(s) to export folder as .rs3 file(s):</p> <button onclick="admin('export');">Export</button> <p>Delete selected document(s):</p> <button onclick="admin('delete_doc');">Delete</button> ''' if "export" in theform: export_doc_list = theform["doclist"] if len(export_doc_list) > 0 and theform["export"] == "export": export_docs = export_doc_list.split(";") if isinstance(export_docs, list): for doc in export_docs: export_document( doc.split("/")[1], doc.split("/")[0], exportdir) else: export_document( export_docs.split("/")[1], export_docs.split("/")[0], exportdir) cpout += '<p class="warn">Export complete</p>' # Handle user add and delete before showing user list if "delete_user" in theform: if len(theform["delete_user"]) > 0: users_to_delete = theform["userlist"] users = users_to_delete.split(";") if isinstance(users, list): for user in users: try: os.remove(userdir + user) delete_docs_for_user(user) user_del_message = '<p class="warn">Deleted users from selection</p>' except OSError as e: if e.errno == errno.ENOENT: user_del_message = '<p class="warn">File to delete <i>' + user + '</i> not found!</p>' else: raise else: try: os.remove(userdir + users_to_delete) delete_docs_for_user(users_to_delete) user_del_message = 'Deleted users from selection' except OSError as e: if e.errno == errno.ENOENT: user_del_message = '<p class="warn">File to delete <i>' + users_to_delete + '</i> not found!</p>' else: raise # Handle user document assignment if "assign_user" in theform: if len(theform["assign_user"]) > 0: users_to_assign = theform["assign_user"] docs_to_assign = theform["assign_doc"] users = users_to_assign.split(";") if ";" in users_to_assign else [ users_to_assign ] docs = docs_to_assign.split(";") if ";" in docs_to_assign else [ docs_to_assign ] for user in users: for doc in docs: user = user.replace(".ini", "") copy_doc_to_user( doc.split("/")[1], doc.split("/")[0], user) if "unassign_user" in theform: if len(theform["unassign_user"]) > 0: user_to_unassign = theform["unassign_user"] doc_to_unassign = theform["unassign_doc"] delete_doc_user_version( doc_to_unassign.split("/")[1], doc_to_unassign.split("/")[0], user_to_unassign) if "new_user_data" in theform: if len(theform["new_user_data"]) > 0: user_data = theform["new_user_data"].split("/") username = user_data[0] realname = user_data[1] email = user_data[2] RESERVEDNAMES = { 'config': 1, 'default': 1, 'temp': 1, 'emails': 1, 'pending': 1, '_orig': 1 } if username in RESERVEDNAMES: user_create_message = '<p class="warn">User name cannot be: "config", "default", "temp", "emails", or "pending"</p>' else: if len(realname) < 1: user_create_message = '<p class="warn">The real name cannot be empty!</p>' else: if not is_email(email): user_create_message = '<p class="warn">Invalid e-mail address: <b>' + email + '</b></p>' else: password = user_data[3] if len(password) < 5: user_create_message = '<p class="warn">Password must be at least 5 characters long</p>' else: administrator = user_data[4] if str(administrator) != "3" and str( administrator) != "0": user_create_message = '<p class="warn">Invalid administrator setting value for new user</p>' else: createuser(userdir, realname, username, email, password, administrator) user_create_message = '<p class="warn">Created the user ' + username + '</p>' if mode == "server": cpout += '</div><div class="tab_btn" id="users_btn" onclick="open_tab(' + "'" + "users" + "'" + ');">Users</div><div id="users" class="tab">' else: cpout += '''</div><div class="tab_btn disabled_tab" id="users_btn" onclick="alert('User management disabled in local mode');">Users</div><div id="users" class="tab">''' cpout += '''<h2>User Management</h2> <table id="doc_assign"><tr><td><p>Users:</p> <select id="userlist_select" multiple="multiple" size="10" class="doclist"> ''' userfiles = [f for f in listdir(userdir) if isfile(join(userdir, f))] for userfile in sorted(userfiles): if userfile != "config.ini" and userfile != "default.ini" and userfile != "admin.ini" and userfile.endswith( ".ini"): userfile = userfile.replace(".ini", "") cpout += '<option value="' + userfile + '.ini">' + userfile + '</option>' cpout += ''' </select></td><td> <p>Documents to assign to:</p>''' docs = get_all_docs_by_project() if not docs: cpout += "<p class='warn'>No documents found with permissions for user name: " + user + "</p>" else: cpout += '<select name="doc_assign_select" id="doc_assign_select" class="doclist" size="10" multiple="multiple">\n' project_group = "" for doc in docs: if project_group != doc[1]: if project_group != "": cpout += '</optgroup>\n' project_group = doc[1] cpout += '<optgroup label="' + doc[1] + '">\n' cpout += '\t<option value="' + doc[1] + "/" + doc[0] + '">' + doc[ 0] + '</option>\n' cpout += '</optgroup>\n</select>\n' cpout += ''' </td></tr></table> <p>Delete selected user files: (annotations will not be deleted)</p> <button onclick="admin('delete_user')">Delete user(s)</button> ''' if "delete_user" in theform: if len(theform["delete_user"]) > 0: cpout += user_del_message cpout += ''' <p>Assign selected users to selected documents:</p> <button onclick="admin('assign_user')">Assign</button> <p>Delete assignments for user: (annotations will be deleted)</p> ''' assigned_users = get_assigned_users() if len(assigned_users) > 0: cpout += '<select id="assigned_user_sel" name="assigned_user_sel" class="doclist" onchange="update_assignments()">' first_user = assigned_users[0][0] for user in assigned_users: assigned_docs = get_assignments(user[0]) cpout += '<option value="' # + user[0] +":" for doc in assigned_docs: cpout += doc[1] + "/" + doc[0] + ";" cpout += '">' + user[0] + '</option>' cpout += '</select>\n' assigned_docs = get_assignments(first_user) cpout += '<select id="assigned_doc_sel" name="assigned_doc_sel" class="doclist">' for doc in assigned_docs: cpout += '<option value="' + doc[1] + "/" + doc[0] + '">' + doc[ 1] + "/" + doc[0] + '</option>' cpout += '</select>' cpout += '''<p><button onclick="admin('unassign_user')">Delete assignment</button></p>''' else: cpout += '<p class="warn">No user assignments found</p>' cpout += '''<p>Create new user:</p> <table class="gray_tab"> <tr><td>User name:</td><td><input name="username" id="username" type="text" value=""></td></tr> <tr><td>Real name:</td><td><input name="realname" id="realname" type="text" value=""></td></tr> <tr><td>Email address:</td><td><input name="email" id="email" type="text" value=""></td></tr> <tr><td>Password:</td><td><input name="pass" id="pass" type="password"> <tr><td>Administrator:</td><td><input type="checkbox" id="chk_admin" name="chk_admin"> <button onclick="admin('create_user')">Create user</button></td></tr> </td></tr> </table> ''' if "new_user_data" in theform: if len(theform["new_user_data"]) > 0: cpout += user_create_message ### database cpout += '</div><div class="tab_btn" id="database_btn" onclick="open_tab(' + "'" + "database" + "'" + ');">Database</div><div id="database" class="tab">' # signals cpout += '''<h2>Signals</h2> <p>Turn signal display and editing signals on/off.</p>''' try: signals_state = get_setting("signals") except IndexError: signals_state = "False" if "switch_signals" in theform: if theform["switch_signals"] == "switch_signals": if signals_state == "True": signals_state = "False" else: signals_state = "True" save_setting("signals", signals_state) if signals_state == "True": opposite_signals = "False" else: opposite_signals = "True" cpout += '''<button onclick="admin('switch_signals')">Turn ''' + ( 'on' if opposite_signals == "True" else 'off') + '''</button>''' if "signals_file" in theform and theform["signals_file"]: save_setting("signals_file", theform["signals_file"]) cpout += '''<div> <br> <span>Signal types: </span> <select name="signals_file_select" id="signals_file_select" class="doclist" onchange="admin('select_signals_file')">''' signals_files = [ fname for fname in os.listdir('signals') if fname.endswith('.json') ] signals_file = get_setting("signals_file") for fname in signals_files: selected_string = (' selected="selected"' if signals_file and signals_file == fname else '') cpout += '<option value="' + fname + '"' + selected_string + '>' + fname[: -5] + '</option>' cpout += '''</select> </div>''' # logging cpout += '''<h2>Logging</h2> <p>Turn detailed action logging on/off.</p>''' try: logging_state = get_setting("logging") except IndexError: logging_state = "off" if "switch_logging" in theform: if theform["switch_logging"] == "switch_logging": if logging_state == "on": logging_state = "off" else: logging_state = "on" save_setting("logging", logging_state) if logging_state == "on": opposite_logging = "off" else: opposite_logging = "on" cpout += '''<button onclick="admin('switch_logging')">Turn ''' + opposite_logging + '''</button>''' # spans/multinucs cpout += '''<h2>Disable spans or multinucs</h2> <p>Turn on/off add span and multinuc buttons (for non-RST annotation).</p>''' try: span_state = get_setting("use_span_buttons") multinuc_state = get_setting("use_multinuc_buttons") except IndexError: span_state = "True" multinuc_state = "True" if "switch_span_buttons" in theform: if int(get_schema()) < 3: update_schema() if theform["switch_span_buttons"] == "switch_span_buttons": if span_state == "True": span_state = "False" else: span_state = "True" save_setting("use_span_buttons", span_state) if span_state == "True": opposite_span = "Disable" else: opposite_span = "Enable" if "switch_multinuc_buttons" in theform: if int(get_schema()) < 3: update_schema() if theform["switch_multinuc_buttons"] == "switch_multinuc_buttons": if multinuc_state == "True": multinuc_state = "False" else: multinuc_state = "True" save_setting("use_multinuc_buttons", multinuc_state) if multinuc_state == "True": opposite_multinuc = "Disable" else: opposite_multinuc = "Enable" cpout += '''<button onclick="admin('switch_span_buttons')">''' + opposite_span + ''' span buttons</button><br/><br/>''' cpout += '''<button onclick="admin('switch_multinuc_buttons')">''' + opposite_multinuc + ''' multinuc buttons</button>''' cpout += '''<h2>Update schema</h2> <p>Update the schema without losing data between major schema upgrades.</p>''' cpout += '''<button onclick="admin('update_schema')">Update</button>''' cpout += '''<h2>Initialize the Database</h2> <p>Wipe and restore database structure.</p> <p class="warn">Warning:</p> <p>this will delete all imported documents and all edits from the database.</p> <button onclick="admin('wipe')">Init DB</button> ''' if "wipe" in theform: if theform["wipe"] == "wipe": cpout += '<p class="warn">Database has been re-initialized</p>' cpout += ''' </div> <script> open_tab(document.getElementById("sel_tab").value); </script>''' if "sel_tab" in theform: sel_tab = theform['sel_tab'] cpout += '<script>open_tab("' + sel_tab + '")</script>' cpout += ''' </div> </body> </html> ''' if mode != "server": cpout = cpout.replace(".py", "") return cpout
def admin_main(user, admin, mode, **kwargs): scriptpath = os.path.dirname(os.path.realpath(__file__)) + os.sep userdir = scriptpath + "users" + os.sep config = ConfigObj(userdir + 'config.ini') exportdir = scriptpath + config['exportdir'].replace("/",os.sep) theform = kwargs cgitb.enable() import re def is_email(email): pattern = '[\.\w]{1,}[@]\w+[.]\w+' if re.match(pattern, email): return True else: return False config = ConfigObj(userdir + 'config.ini') templatedir = scriptpath + config['controltemplates'].replace("/",os.sep) template = "main_header.html" header = readfile(templatedir+template) header = header.replace("**page_title**","Administration") header = header.replace("**user**",user) importdir = scriptpath + config['importdir'].replace("/",os.sep) def_relfile = scriptpath + config['default_rels'].replace("/",os.sep) cpout = "" if mode == "server": cpout += "Content-Type: text/html\n\n\n" header = header.replace("**logout_control**",'(<a href="logout.py">log out</a>)') else: header = header.replace("**logout_control**",'') cpout += header if "current_doc" in theform: current_doc = theform["current_doc"] current_project = theform["current_project"] else: current_doc = "" current_project = "" edit_bar = "edit_bar.html" edit_bar = readfile(templatedir+edit_bar) edit_bar = edit_bar.replace("**doc**",current_doc) edit_bar = edit_bar.replace("**project**",current_project) edit_bar = edit_bar.replace("**structure_disabled**",'') edit_bar = edit_bar.replace("**segment_disabled**",'') edit_bar = edit_bar.replace("**relations_disabled**",'') edit_bar = edit_bar.replace("**submit_target**",'admin.py') edit_bar = edit_bar.replace("**action_type**",'') edit_bar = edit_bar.replace("**serve_mode**",mode) edit_bar = edit_bar.replace("**open_disabled**",'') edit_bar = edit_bar.replace("**reset_disabled**",'disabled="disabled"') edit_bar = edit_bar.replace("**save_disabled**",'disabled="disabled"') edit_bar = edit_bar.replace("**undo_disabled**",'disabled="disabled"') edit_bar = edit_bar.replace("**redo_disabled**",'disabled="disabled"') edit_bar = edit_bar.replace("**admin_disabled**",'disabled="disabled"') edit_bar = edit_bar.replace('id="nav_admin" class="nav_button"','id="nav_admin" class="nav_button nav_button_inset"') if admin == "0": cpout += '<p class="warn">User '+ user+' does not have administrator rights!</p></body></html>' return cpout else: edit_bar = edit_bar.replace("**admin_disabled**",'') cpout += edit_bar help = "help.html" help = readfile(templatedir+help) help_match = re.search(r'(<div id="help_admin".*?</div>)',help,re.MULTILINE|re.DOTALL) help = help_match.group(1) cpout += help about = "about.html" about = readfile(templatedir+about) about = about.replace("**version**", _version.__version__) cpout += about if "wipe" in theform: if theform["wipe"] =="wipe": setup_db() if "create_project" in theform: new_project = theform["create_project"] if len(new_project)>0: create_project(new_project) all_project_list = get_all_projects() if "doclist" in theform: current_doc = theform["doclist"] else: current_doc = "" cpout += ''' <div id="control"> <form id="admin_form" name="id_form" action="admin.py" method="post" enctype="multipart/form-data"> <input type="hidden" name="create_project" id="create_project" value=""/> <input type="hidden" name="sel_tab" id="sel_tab" value="project"/> <input type="hidden" name="delete" id="delete" value=""/> <input type="hidden" name="delete_user" id="delete_user" value=""/> <input type="hidden" name="export" id="export" value=""/> <input type="hidden" name="wipe" id="wipe" value=""/> <input type="hidden" name="switch_logging" id="switch_logging" value=""/> <input type="hidden" name="update_schema" id="update_schema" value=""/> <input type="hidden" name="imp_project" id="imp_project" value=""/> <input type="hidden" name="import_file_type" id="import_file_type" value=""/> <input type="hidden" name="doclist" id="doclist" value="''' cpout += current_doc cpout += '''"/> <input type="hidden" name="userlist" id="userlist" value=""/> <input type="hidden" name="assign_doc" id="assign_doc" value=""/> <input type="hidden" name="assign_user" id="assign_user" value=""/> <input type="hidden" name="unassign_doc" id="unassign_doc" value=""/> <input type="hidden" name="unassign_user" id="unassign_user" value=""/> <input type="hidden" name="new_user_data" id="new_user_data" value=""/> <input type="hidden" name="del_project" id="del_project" value=""/> <input type="hidden" name="guidelines_url" id="guidelines_url" value=""/> <input id="file" type="file" name="file"/> </form> <script src="./script/admin.js"></script> <script src="./script/jquery-1.11.3.min.js"></script> <script src="./script/jquery-ui.min.js"></script> ''' cpout += ''' <div class="tab_btn" id="project_btn" onclick="open_tab('project');">Projects</div><div id="project" class="tab"> <h2>Manage Projects</h2> <p>Create a new project named: <input id="new_project"/></p> <button onclick="admin('create_project')">Create Project</button> ''' #cpout += theform if "del_project" in theform: projects_to_delete = theform["del_project"].split(";") if len(projects_to_delete)>0: if isinstance(projects_to_delete,list): for project in projects_to_delete: delete_project(project) else: delete_project(projects_to_delete) url_message = "" if "guidelines_url" in theform: if "::" in theform["guidelines_url"]: project_list, guideline_url = theform["guidelines_url"].split("::") if len(project_list)>0: schema = get_schema() if schema < 2: update_schema() if isinstance(project_list,list): for project in project_list: set_guidelines_url(project,guideline_url) else: set_guidelines_url(project_list,guideline_url) url_message = '<p class="warn">Added the URL ' + guideline_url + " to the selected projects</p>" cpout += '<p>Existing projects:</p>' if all_project_list: cpout += '<select class="doclist" id="project_select" size="5" multiple="multiple">\n' for project in all_project_list: cpout += '\t<option value="' + project[0] +'">' + project[0] + "</option>" cpout += '</select>\n' else: cpout += '<p class="warn">No projects found!</p>' cpout += '''<p> <p>Add guidlines URL to selected project:</p><p><input id="guidelines_url_input"/></p> <button onclick="admin('guidelines_url')">Add URL</button> ''' + url_message + ''' <p>Delete selected projects:</p> <button onclick="admin('delete_project')">Delete Selected</button></p> </div>''' cpout += ''' <div class="tab_btn" id="import_btn" onclick="open_tab('import');">Import</div><div id="import" class="tab"> <h2>Import a Document</h2> <p>1. Upload .rs3 or plain text file: </p> <p>2. Choose file type: <select id="import_file_type_select" class="doclist"><option value="rs3">rs3</option><option value="plain">plain text (EDU per line)</option></select> </p> <p>3. Import document into this project: ''' if all_project_list: cpout += '<select class="doclist" id="imp_project_select">\n' if isinstance(all_project_list,list): for project in all_project_list: cpout += '\t<option value="' + project[0] +'">' + project[0] + "</option>" else: cpout += '\t<option value="' + all_project_list +'">' + all_project_list + "</option>" cpout += '</select>\n' else: cpout += "<p>No projects found with permissons for user: "******"</p>" cpout += ''' </p> <p><button onclick="admin('upload')">Upload</button></p> ''' fail = 0 if "file" in theform and "imp_project" in theform: fileitem = theform['file'] imp_project = theform["imp_project"] if fileitem.filename and len(imp_project) > 0: # Test if the file was uploaded and a project selection exists # strip leading path from file name to avoid directory traversal attacks fn = os.path.basename(fileitem.filename) open(importdir + fn, 'wb').write(fileitem.file.read()) message = 'The file "' + fn + '" was uploaded successfully' if theform['import_file_type'] == "rs3": fail = import_document(importdir + fn,imp_project,user) elif theform['import_file_type'] == "plain": if len(def_relfile) > 0: rel_hash = read_relfile(def_relfile) else: rel_hash = {} fail = import_plaintext(importdir + fn,imp_project,user,rel_hash) else: message = 'No file was uploaded' if isinstance(fail,basestring): message = fail cpout += """ <p class="warn">%s</p> """ % (message,) cpout += '</div><div class="tab_btn" id="docs_btn" onclick="open_tab('+"'"+"docs"+"'"+');">Documents</div><div id="docs" class="tab">' cpout += "<h2>Current Documents</h2>" if "delete" in theform: #execute delete documents before retrieving doclist doclist = theform["doclist"] if len(doclist) > 0 and theform["delete"] =="delete": docs_to_delete = doclist.split(";") if len(docs_to_delete) > 0: if isinstance(docs_to_delete,list): for doc in docs_to_delete: delete_document(doc.split("/")[1],doc.split("/")[0]) else: delete_document(docs_to_delete.split("/")[1],docs_to_delete.split("/")[0]) cpout += '<p class="warn">Deletion complete</p>' cpout += '<p>List of documents in the database:</p>' docs = get_all_docs_by_project() if not docs: cpout += "<p>No documents found with permissions for user name: " + user + "</p>" else: cpout += '<select name="doclist_select" id="doclist_select" class="doclist" size="15" multiple="multiple">\n' project_group="" for doc in docs: if project_group!=doc[1]: if project_group !="": cpout += '</optgroup>\n' project_group = doc[1] cpout += '<optgroup label="'+doc[1]+'">\n' cpout += '\t<option value="'+doc[1]+"/"+doc[0]+'">'+doc[0]+'</option>\n' cpout += '</optgroup>\n</select>\n' cpout += ''' <p>Export selected document(s) to export folder as .rs3 file(s):</p> <button onclick="admin('export');">Export</button> <p>Delete selected document(s):</p> <button onclick="admin('delete_doc');">Delete</button> ''' if "export" in theform: export_doc_list = theform["doclist"] if len(export_doc_list) > 0 and theform["export"]== "export": export_docs = export_doc_list.split(";") if isinstance(export_docs,list): for doc in export_docs: export_document(doc.split("/")[1],doc.split("/")[0],exportdir) else: export_document(export_docs.split("/")[1],export_docs.split("/")[0],exportdir) cpout += '<p class="warn">Export complete</p>' # Handle user add and delete before showing user list if "delete_user" in theform: if len(theform["delete_user"]) > 0: users_to_delete = theform["userlist"] users = users_to_delete.split(";") if isinstance(users,list): for user in users: try: os.remove(userdir+user) delete_docs_for_user(user) user_del_message = '<p class="warn">Deleted users from selection</p>' except OSError as e: if e.errno == errno.ENOENT: user_del_message = '<p class="warn">File to delete <i>'+user+'</i> not found!</p>' else: raise else: try: os.remove(userdir+users_to_delete) delete_docs_for_user(users_to_delete) user_del_message = 'Deleted users from selection' except OSError as e: if e.errno == errno.ENOENT: user_del_message = '<p class="warn">File to delete <i>'+ users_to_delete + '</i> not found!</p>' else: raise # Handle user document assignment if "assign_user" in theform: if len(theform["assign_user"]) > 0: users_to_assign = theform["assign_user"] docs_to_assign = theform["assign_doc"] users = users_to_assign.split(";") if ";" in users_to_assign else [users_to_assign] docs = docs_to_assign.split(";") if ";" in docs_to_assign else [docs_to_assign] for user in users: for doc in docs: user = user.replace(".ini","") copy_doc_to_user(doc.split("/")[1],doc.split("/")[0],user) if "unassign_user" in theform: if len(theform["unassign_user"]) > 0: user_to_unassign = theform["unassign_user"] doc_to_unassign = theform["unassign_doc"] print theform delete_doc_user_version(doc_to_unassign.split("/")[1],doc_to_unassign.split("/")[0],user_to_unassign) if "new_user_data" in theform: if len(theform["new_user_data"]) >0: user_data = theform["new_user_data"].split("/") username = user_data[0] realname = user_data[1] email = user_data[2] RESERVEDNAMES = {'config':1, 'default':1, 'temp':1, 'emails':1, 'pending':1, '_orig':1} if username in RESERVEDNAMES: user_create_message = '<p class="warn">User name cannot be: "config", "default", "temp", "emails", or "pending"</p>' else: if len(realname)<1: user_create_message = '<p class="warn">The real name cannot be empty!</p>' else: if not is_email(email): user_create_message = '<p class="warn">Invalid e-mail address: <b>'+email+'</b></p>' else: password = user_data[3] if len(password)<5: user_create_message = '<p class="warn">Password must be at least 5 characters long</p>' else: administrator = user_data[4] if str(administrator) != "3" and str(administrator) != "0": user_create_message = '<p class="warn">Invalid administrator setting value for new user</p>' else: createuser(userdir, realname, username, email, password, administrator) user_create_message = '<p class="warn">Created the user ' + username + '</p>' if mode=="server": cpout += '</div><div class="tab_btn" id="users_btn" onclick="open_tab('+"'"+"users"+"'"+');">Users</div><div id="users" class="tab">' else: cpout += '''</div><div class="tab_btn disabled_tab" id="users_btn" onclick="alert('User management disabled in local mode');">Users</div><div id="users" class="tab">''' cpout += '''<h2>User Management</h2> <table id="doc_assign"><tr><td><p>Users:</p> <select id="userlist_select" multiple="multiple" size="10" class="doclist"> ''' userfiles = [ f for f in listdir(userdir) if isfile(join(userdir,f)) ] for userfile in sorted(userfiles): if userfile != "config.ini" and userfile != "default.ini" and userfile != "admin.ini" and userfile.endswith(".ini"): userfile = userfile.replace(".ini","") cpout += '<option value="' + userfile + '.ini">'+userfile+'</option>' cpout += ''' </select></td><td> <p>Documents to assign to:</p>''' docs = get_all_docs_by_project() if not docs: cpout += "<p class='warn'>No documents found with permissions for user name: " + user + "</p>" else: cpout += '<select name="doc_assign_select" id="doc_assign_select" class="doclist" size="10" multiple="multiple">\n' project_group="" for doc in docs: if project_group!=doc[1]: if project_group !="": cpout += '</optgroup>\n' project_group = doc[1] cpout += '<optgroup label="'+doc[1]+'">\n' cpout += '\t<option value="'+doc[1]+"/"+doc[0]+'">'+doc[0]+'</option>\n' cpout += '</optgroup>\n</select>\n' cpout += ''' </td></tr></table> <p>Delete selected user files: (annotations will not be deleted)</p> <button onclick="admin('delete_user')">Delete user(s)</button> ''' if "delete_user" in theform: if len(theform["delete_user"]) > 0: cpout += user_del_message cpout += ''' <p>Assign selected users to selected documents:</p> <button onclick="admin('assign_user')">Assign</button> <p>Delete assignments for user: (annotations will be deleted)</p> ''' assigned_users = get_assigned_users() if len(assigned_users)>0: cpout += '<select id="assigned_user_sel" name="assigned_user_sel" class="doclist" onchange="update_assignments()">' first_user = assigned_users[0][0] for user in assigned_users: assigned_docs = get_assignments(user[0]) cpout += '<option value="' # + user[0] +":" for doc in assigned_docs: cpout += doc[1]+"/"+doc[0]+";" cpout += '">'+user[0]+'</option>' cpout += '</select>\n' assigned_docs = get_assignments(first_user) cpout += '<select id="assigned_doc_sel" name="assigned_doc_sel" class="doclist">' for doc in assigned_docs: cpout += '<option value="' + doc[1]+"/"+doc[0] + '">'+doc[1]+"/"+doc[0]+'</option>' cpout += '</select>' cpout += '''<p><button onclick="admin('unassign_user')">Delete assignment</button></p>''' else: cpout += '<p class="warn">No user assignments found</p>' cpout += '''<p>Create new user:</p> <table class="gray_tab"> <tr><td>User name:</td><td><input name="username" id="username" type="text" value=""></td></tr> <tr><td>Real name:</td><td><input name="realname" id="realname" type="text" value=""></td></tr> <tr><td>Email address:</td><td><input name="email" id="email" type="text" value=""></td></tr> <tr><td>Password:</td><td><input name="pass" id="pass" type="password"> <tr><td>Administrator:</td><td><input type="checkbox" id="chk_admin" name="chk_admin"> <button onclick="admin('create_user')">Create user</button></td></tr> </td></tr> </table> ''' if "new_user_data" in theform: if len(theform["new_user_data"]) > 0: cpout += user_create_message cpout += '</div><div class="tab_btn" id="database_btn" onclick="open_tab('+"'"+"database"+"'"+');">Database</div><div id="database" class="tab">' cpout += '''<h2>Logging</h2> <p>Turn detailed action logging on/off.</p>''' try: logging_state = get_setting("logging") except IndexError: logging_state="off" if "switch_logging" in theform: if theform["switch_logging"] == "switch_logging": if logging_state == "on": logging_state = "off" else: logging_state = "on" save_setting("logging",logging_state) if logging_state == "on": opposite_logging = "off" else: opposite_logging = "on" cpout += '''<button onclick="admin('switch_logging')">Turn '''+ opposite_logging +'''</button>''' cpout += '''<h2>Update schema</h2> <p>Update the schema without losing data between major schema upgrades.</p>''' if "update_schema" in theform: if theform["update_schema"] == "update_schema": update_schema() cpout += '''<button onclick="admin('update_schema')">Update</button>''' cpout += '''<h2>Initialize the Database</h2> <p>Wipe and restore database structure.</p> <p class="warn">Warning:</p> <p>this will delete all imported documents and all edits from the database.</p> <button onclick="admin('wipe')">Init DB</button> ''' if "wipe" in theform: if theform["wipe"] =="wipe": cpout += '<p class="warn">Database has been re-initialized</p>' cpout += ''' </div> <script> open_tab(document.getElementById("sel_tab").value); </script>''' if "sel_tab" in theform: sel_tab = theform['sel_tab'] cpout += '<script>open_tab("'+sel_tab+'")</script>' cpout += ''' </div> </body> </html> ''' if mode != "server": cpout = cpout.replace(".py","") return cpout