string user_account (void * webserver_request) { Webserver_Request * request = (Webserver_Request *) webserver_request; string page; Assets_Header header = Assets_Header (translate("Account"), webserver_request); header.addBreadCrumb (menu_logic_settings_menu (), menu_logic_settings_text ()); page = header.run (); Assets_View view; string username = request->session_logic()->currentUser (); string email = request->database_users()->get_email (username); bool actions_taken = false; vector <string> success_messages; // Form submission handler. if (request->post.count ("submit")) { bool form_is_valid = true; string currentpassword = request->post ["currentpassword"]; string newpassword = request->post ["newpassword"]; string newpassword2 = request->post ["newpassword2"]; string newemail = request->post ["newemail"]; if ((newpassword != "") || (newpassword2 != "")) { if (newpassword.length () < 4) { form_is_valid = false; view.set_variable ("new_password_invalid_message", translate("Password should be at least four characters long")); } if (newpassword2.length () < 4) { form_is_valid = false; view.set_variable ("new_password2_invalid_message", translate("Password should be at least four characters long")); } if (newpassword2 != newpassword) { form_is_valid = false; view.set_variable ("new_password2_invalid_message", translate("Passwords do not match")); } if (!request->database_users()->matchUserPassword (username, currentpassword)) { form_is_valid = false; view.set_variable ("current_password_invalid_message", translate("Current password is not valid")); } if (form_is_valid) { request->database_users()->set_password (username, newpassword); actions_taken = true; success_messages.push_back (translate("The new password was saved")); } } if (newemail != "") { if (!filter_url_email_is_valid (newemail)) { form_is_valid = false; view.set_variable ("new_email_invalid_message", translate("Email address is not valid")); } if (!request->database_users()->matchUserPassword (username, currentpassword)) { form_is_valid = false; view.set_variable ("current_password_invalid_message", translate("Current password is not valid")); } if (form_is_valid) { Confirm_Worker confirm_worker = Confirm_Worker (webserver_request); string initial_subject = translate("Email address verification"); string initial_body = translate("Somebody requested to change the email address that belongs to your account."); string query = request->database_users()->updateEmailQuery (username, newemail); string subsequent_subject = translate("Email address change"); string subsequent_body = translate("The email address that belongs to your account has been changed successfully."); confirm_worker.setup (newemail, initial_subject, initial_body, query, subsequent_subject, subsequent_body); actions_taken = true; success_messages.push_back (translate("A verification email was sent to ") + newemail); } } if (!actions_taken) { success_messages.push_back (translate("No changes were made")); } } view.set_variable ("username", filter_string_sanitize_html (username)); view.set_variable ("email", filter_string_sanitize_html (email)); string success_message = filter_string_implode (success_messages, "\n"); view.set_variable ("success_messages", success_message); if (!actions_taken) view.enable_zone ("no_actions_taken"); page += view.render ("user", "account"); page += Assets_Page::footer (); return page; }
string manage_users (void * webserver_request) { Webserver_Request * request = (Webserver_Request *) webserver_request; bool user_updated = false; bool privileges_updated = false; string page; Assets_Header header = Assets_Header (translate("Users"), webserver_request); header.addBreadCrumb (menu_logic_settings_menu (), menu_logic_settings_text ()); page = header.run (); Assets_View view; int myLevel = request->session_logic ()->currentLevel (); // New user creation. if (request->query.count ("new")) { Dialog_Entry dialog_entry = Dialog_Entry ("users", translate("Please enter a name for the new user"), "", "new", ""); page += dialog_entry.run (); return page; } if (request->post.count ("new")) { string user = request->post["entry"]; if (request->database_users ()->usernameExists (user)) { page += Assets_Page::error (translate("User already exists")); } else { request->database_users ()->addNewUser(user, user, Filter_Roles::member (), ""); user_updated = true; page += Assets_Page::success (translate("User created")); } } // The user to act on. string objectUsername = request->query["user"]; int objectUserLevel = request->database_users ()->getUserLevel (objectUsername); // Delete a user. if (request->query.count ("delete")) { string role = Filter_Roles::text (objectUserLevel); string email = request->database_users ()->getUserToEmail (objectUsername); string message = "Deleted user " + objectUsername + " with role " + role + " and email " + email; Database_Logs::log (message, Filter_Roles::admin ()); request->database_users ()->removeUser (objectUsername); user_updated = true; database_privileges_client_remove (objectUsername); page += Assets_Page::success (message); // Also remove any privileges for this user. // In particular for the Bible privileges this is necessary, // beause if old users remain in the privileges storage, // then a situation where no user has any privileges to any Bible, // and thus all relevant users have all privileges, // can never be achieved again. Database_Privileges::removeUser (objectUsername); // Remove any login tokens the user might have had: Just to clean things up. Database_Login::removeTokens (objectUsername); // Remove any settings for the user. // The advantage of this is that when a user is removed, all settings are gone, // so when the same user would be created again, all settings will go back to their defaults. request->database_config_user ()->remove (objectUsername); } // The user's role. if (request->query.count ("level")) { string level = request->query ["level"]; if (level == "") { Dialog_List dialog_list = Dialog_List ("users", translate("Select a role for") + " " + objectUsername, "", ""); dialog_list.add_query ("user", objectUsername); for (int i = Filter_Roles::lowest (); i <= Filter_Roles::highest (); i++) { if (i <= myLevel) { dialog_list.add_row (Filter_Roles::text (i), "level", convert_to_string (i)); } } page += dialog_list.run (); return page; } else { request->database_users ()->updateUserLevel (objectUsername, convert_to_int (level)); user_updated = true; } } // User's email address. if (request->query.count ("email")) { string email = request->query ["email"]; if (email == "") { string question = translate("Please enter an email address for") + " " + objectUsername; string value = request->database_users ()->getUserToEmail (objectUsername); Dialog_Entry dialog_entry = Dialog_Entry ("users", question, value, "email", ""); dialog_entry.add_query ("user", objectUsername); page += dialog_entry.run (); return page; } } if (request->post.count ("email")) { string email = request->post["entry"]; if (filter_url_email_is_valid (email)) { page += Assets_Page::success (translate("Email address was updated")); request->database_users ()->updateUserEmail (objectUsername, email); user_updated = true; } else { page += Assets_Page::error (translate("The email address is not valid")); } } // Fetch all available Bibles. vector <string> allbibles = request->database_bibles ()->getBibles (); // Add Bible to user account. if (request->query.count ("addbible")) { string addbible = request->query["addbible"]; if (addbible == "") { Dialog_List dialog_list = Dialog_List ("users", translate("Would you like to grant the user access to a Bible?"), "", ""); dialog_list.add_query ("user", objectUsername); for (auto bible : allbibles) { dialog_list.add_row (bible, "addbible", bible); } page += dialog_list.run (); return page; } else { Assets_Page::success (translate("The user has been granted access to this Bible")); // Write access depends on whether it's a translator role or higher. bool write = (objectUserLevel >= Filter_Roles::translator ()); Database_Privileges::setBible (objectUsername, addbible, write); user_updated = true; privileges_updated = true; } } // Remove Bible from user. if (request->query.count ("removebible")) { string removebible = request->query ["removebible"]; Database_Privileges::removeBibleBook (objectUsername, removebible, 0); user_updated = true; privileges_updated = true; Assets_Page::success (translate("The user no longer has access to this Bible")); } // Login on behalf of another user. if (request->query.count ("login")) { request->session_logic ()->switchUser (objectUsername); redirect_browser (request, session_switch_url ()); return ""; } // User accounts to display. vector <string> tbody; // Retrieve assigned users. vector <string> users = access_user_assignees (webserver_request); for (auto & username : users) { // Gather details for this user account. objectUserLevel = request->database_users ()->getUserLevel (username); string namedrole = Filter_Roles::text (objectUserLevel); string email = request->database_users ()->getUserToEmail (username); if (email == "") email = "--"; tbody.push_back ("<tr>"); tbody.push_back ("<td><a href=\"?user="******"&delete\">✗</a> " + username + "</td>"); tbody.push_back ("<td>│</td>"); tbody.push_back ("<td><a href=\"?user="******"&level\">" + namedrole + "</a></td>"); tbody.push_back ("<td>│</td>"); tbody.push_back ("<td><a href=\"?user="******"&email\">" + email + "</a></td>"); tbody.push_back ("<td>│</td>"); tbody.push_back ("<td>"); if (objectUserLevel < Filter_Roles::manager ()) { for (auto & bible : allbibles) { bool exists = Database_Privileges::getBibleBookExists (username, bible, 0); if (exists) { bool read, write; Database_Privileges::getBible (username, bible, read, write); if (objectUserLevel >= Filter_Roles::translator ()) write = true; tbody.push_back ("<a href=\"?user="******"&removebible=" + bible + "\">✗</a>"); tbody.push_back ("<a href=\"/bible/settings?bible=" + bible + "\">" + bible + "</a>"); tbody.push_back ("<a href=\"write?user="******"&bible=" + bible + "\">"); int readwritebooks = 0; vector <int> books = request->database_bibles ()->getBooks (bible); for (auto book : books) { Database_Privileges::getBibleBook (username, bible, book, read, write); if (write) readwritebooks++; } tbody.push_back ("(" + convert_to_string (readwritebooks) + "/" + convert_to_string (books.size ()) + ")"); tbody.push_back ("</a>"); tbody.push_back ("|"); } } } if (objectUserLevel >= Filter_Roles::manager ()) { // Managers and higher roles have access to all Bibles. tbody.push_back ("(" + translate ("all") + ")"); } else { tbody.push_back ("<a href=\"?user="******"&addbible=\">➕</a>"); } tbody.push_back ("</td>"); tbody.push_back ("<td>│</td>"); tbody.push_back ("<td>"); if (objectUserLevel >= Filter_Roles::manager ()) { // Managers and higher roles have all privileges. tbody.push_back ("(" + translate ("all") + ")"); } else { tbody.push_back ("<a href=\"privileges?user="******"\">" + translate ("edit") + "</a>"); } tbody.push_back ("</td>"); // Logging for another user. if (myLevel > objectUserLevel) { tbody.push_back ("<td>│</td>"); tbody.push_back ("<td>"); tbody.push_back ("<a href=\"?user="******"&login\">" + translate ("Login") + "</a>"); tbody.push_back ("</td>"); } tbody.push_back ("</tr>"); } view.set_variable ("tbody", filter_string_implode (tbody, "\n")); page += view.render ("manage", "users"); page += Assets_Page::footer (); if (user_updated) notes_logic_maintain_note_assignees (true); if (privileges_updated) database_privileges_client_create (objectUsername, true); return page; }