// Send the named $desktop to a $user name. void workspace_send (void * webserver_request, string desktop, string user) { Webserver_Request * request = (Webserver_Request *) webserver_request; // Save current active desktop. string active_desktop = request->database_config_user()->getActiveWorkspace (); // Retrieve settings for the $desktop of the current user. request->database_config_user()->setActiveWorkspace (desktop); map <int, string> urls = workspace_get_urls (webserver_request, false); map <int, string> widths = workspace_get_widths (webserver_request); map <int, string> heights = workspace_get_heights (webserver_request); string entire_width = workspace_get_entire_width (webserver_request); // Restore current active desktop. request->database_config_user()->setActiveWorkspace (active_desktop); // New webserver request object for the destination user. Webserver_Request destination_request; destination_request.session_logic ()->setUsername (user); // Save desktop for destination user. active_desktop = destination_request.database_config_user()->getActiveWorkspace (); destination_request.database_config_user()->setActiveWorkspace (desktop); // Copy source desktop to destination. workspace_set_urls (&destination_request, urls); workspace_set_widths (&destination_request, widths); workspace_set_heights (&destination_request, heights); workspace_set_entire_width (&destination_request, entire_width); // Restore desktop for the destination user. request->database_config_user()->setActiveWorkspace (active_desktop); }
// This function compares the $newtext with the $oldtext. // It returns an empty string if the difference is below the limit set for the Bible. // It returns a message specifying the difference if it exceeds that limit. string usfm_save_is_safe (void * webserver_request, string oldtext, string newtext, bool chapter) { // Two texts are equal: safe. if (newtext == oldtext) return ""; Webserver_Request * request = (Webserver_Request *) webserver_request; // Allowed percentage difference. int allowed_percentage = request->database_config_user ()->getEditingAllowedDifferenceVerse (); if (chapter) allowed_percentage = request->database_config_user ()->getEditingAllowedDifferenceChapter (); // The length of the new text should not differ more than a set percentage from the old text. float existingLength = oldtext.length(); float newLength = newtext.length (); int percentage = 100 * (newLength - existingLength) / existingLength; percentage = abs (percentage); if (percentage > 100) percentage = 100; if (percentage > allowed_percentage) { Database_Logs::log ("The text was not saved for safety reasons. The length differs " + convert_to_string (percentage) + "% from the existing text. Make smaller changes and save more often. Or relax the restriction in the Bible's editing settings."); Database_Logs::log (newtext); return translate ("Text length differs too much"); } // The new text should be at least a set percentage similar to the old text. percentage = filter_diff_similarity (oldtext, newtext); if (percentage < (100 - allowed_percentage)) { Database_Logs::log ("The text was not saved for safety reasons. The new text is " + convert_to_string (percentage) + "% similar to the existing text. Make smaller changes and save more often. Or relax the restriction in the Bible's editing settings."); Database_Logs::log (newtext); return translate ("Text content differs too much"); } // Safety checks have passed. return ""; }
void Editor_Export::stylesheet (string stylesheet) { Webserver_Request * request = (Webserver_Request *) webserver_request; styles.clear (); noteOpeners.clear (); characterStyles.clear (); vector <string> markers = request->database_styles()->getMarkers (stylesheet); // Load the style information into the object. for (string & marker : markers) { Database_Styles_Item style = request->database_styles()->getMarkerData (stylesheet, marker); styles [marker] = style; // Get markers with should not have endmarkers. bool suppress = false; int type = style.type; int subtype = style.subtype; if (type == StyleTypeVerseNumber) suppress = true; if (type == StyleTypeFootEndNote) { suppress = true; if (subtype == FootEndNoteSubtypeFootnote) noteOpeners.insert (marker); if (subtype == FootEndNoteSubtypeEndnote) noteOpeners.insert (marker); if (subtype == FootEndNoteSubtypeContentWithEndmarker) suppress = false; if (subtype == FootEndNoteSubtypeParagraph) suppress = false; } if (type == StyleTypeCrossreference) { suppress = true; if (subtype == CrossreferenceSubtypeCrossreference) noteOpeners.insert (marker); if (subtype == CrossreferenceSubtypeContentWithEndmarker) suppress = false; } if (type == StyleTypeTableElement) suppress = true; if (suppress) suppressEndMarkers.insert (marker); } }
string notes_assign_n (void * webserver_request) { Webserver_Request * request = (Webserver_Request *) webserver_request; Database_Notes database_notes (webserver_request); Notes_Logic notes_logic = Notes_Logic (webserver_request); Database_NoteAssignment database_noteassignment; string page; Assets_Header header = Assets_Header (translate("Assign notes"), request); page += header.run(); Assets_View view; string user = request->session_logic ()->currentUser (); // Notes can be assigned to the assignees. string userblock; vector <string> assignees = database_noteassignment.assignees (user); for (auto & assignee : assignees) { userblock.append ("<li><a href=\"bulk?assign=" + assignee + "\">" + assignee + "</a></li>\n"); } view.set_variable ("userblock", userblock); page += view.render ("notes", "assign-n"); page += Assets_Page::footer (); return page; }
string edit_load (void * webserver_request) { Webserver_Request * request = (Webserver_Request *) webserver_request; string bible = request->query ["bible"]; int book = convert_to_int (request->query ["book"]); int chapter = convert_to_int (request->query ["chapter"]); // Store a copy of the USFM loaded in the editor for later reference. storeLoadedUsfm (webserver_request, bible, book, chapter, "edit"); string stylesheet = request->database_config_user()->getStylesheet (); string usfm = request->database_bibles()->getChapter (bible, book, chapter); Editor_Usfm2Html editor_usfm2html; editor_usfm2html.load (usfm); editor_usfm2html.stylesheet (stylesheet); editor_usfm2html.run (); string html = editor_usfm2html.get (); // To make editing empty verses easier, convert spaces to non-breaking spaces, so they appear in the editor. if (usfm_contains_empty_verses (usfm)) { string search = "<span> </span>"; string replace = "<span>" + unicode_non_breaking_space_entity () + "</span>"; html = filter_string_str_replace (search, replace, html); } string user = request->session_logic ()->currentUser (); bool write = access_bible_book_write (webserver_request, user, bible, book); return Checksum_Logic::send (html, write); }
string public_create (void * webserver_request) { Webserver_Request * request = (Webserver_Request *) webserver_request; Database_Notes database_notes (webserver_request); Notes_Logic notes_logic = Notes_Logic (webserver_request); string page; Assets_Header header = Assets_Header (translate("Create note"), request); page += header.run (); Assets_View view; string bible = request->database_config_user()->getBible (); int book = Ipc_Focus::getBook (webserver_request); int chapter = Ipc_Focus::getChapter (webserver_request); int verse = Ipc_Focus::getVerse (webserver_request); string chapter_usfm = request->database_bibles()->getChapter (bible, book, chapter); string verse_usfm = usfm_get_verse_text (chapter_usfm, verse); string stylesheet = Database_Config_Bible::getExportStylesheet (bible); Filter_Text filter_text = Filter_Text (bible); filter_text.html_text_standard = new Html_Text (bible); filter_text.addUsfmCode (verse_usfm); filter_text.run (stylesheet); string versetext = filter_text.html_text_standard->getInnerHtml (); view.set_variable ("versetext", versetext); if (request->post.count ("submit")) { string summary = filter_string_trim (request->post["summary"]); if (summary.empty ()) summary = translate ("Feedback"); string contents = "<p>" + versetext + "</p>" + filter_string_trim (request->post["contents"]); int identifier = notes_logic.createNote (bible, book, chapter, verse, summary, contents, false); // A note created by a public user is made public to all. database_notes.setPublic (identifier, true); // Subscribe the user to the note. // Then the user receives email about any updates made on this note. database_notes.subscribe (identifier); // Go to the main public notes page. redirect_browser (request, public_index_url ()); return ""; } if (request->post.count ("cancel")) { redirect_browser (request, public_index_url ()); return ""; } string passage = filter_passage_display (book, chapter, convert_to_string (verse)); view.set_variable ("passage", passage); page += view.render ("public", "create"); page += Assets_Page::footer (); return page; }
void Navigation_Passage::recordHistory (void * webserver_request, int book, int chapter, int verse) { Webserver_Request * request = (Webserver_Request *) webserver_request; string user = request->session_logic()->currentUser (); Database_Navigation database_navigation; database_navigation.record (filter_date_seconds_since_epoch (), user, book, chapter, verse); }
string Navigation_Passage::getChaptersFragment (void * webserver_request, string bible, int book, int chapter) { Webserver_Request * request = (Webserver_Request *) webserver_request; vector <int> chapters; if (bible.empty ()) { Database_Versifications database_versifications; chapters = database_versifications.getChapters ("English", book, true); } else { chapters = request->database_bibles()->getChapters (bible, book); } string html; addSelectorLink (html, "previous", "applychapter", "[" + translate ("previous") + "]", false); addSelectorLink (html, "next", "applychapter", "[" + translate ("next") + "]", false); addSelectorLink (html, "cancel", "applychapter", "[" + translate ("cancel") + "]", false); for (auto ch : chapters) { bool selected = (ch == chapter); addSelectorLink (html, convert_to_string (ch), "applychapter", convert_to_string (ch), selected); } addSelectorLink (html, "cancel", "applychapter", "[" + translate ("cancel") + "]", false); html.insert (0, "<span id=\"applychapter\">" + translate ("Select chapter")); html.append ("</span>"); return html; }
// Handles a confirmation email received "from" with "subject" and "body". // Returns true if the mail was handled, else false. bool Confirm_Worker::handleEmail (string from, string subject, string body) { if (from.empty()) {}; // Find out in the confirmation database whether the subject line contains an active ID. // If not, bail out. Database_Confirm database_confirm = Database_Confirm (); int id = database_confirm.searchID (subject); if (id == 0) { return false; } // An active ID was found: Execute the associated database query. string query = database_confirm.getQuery (id); Webserver_Request * request = (Webserver_Request *) webserver_request; request->database_users()->execute (query); // Send confirmation mail. string mailto = database_confirm.getMailTo (id); subject = database_confirm.getSubject (id); body = database_confirm.getBody (id); Database_Mail database_mail = Database_Mail (webserver_request); database_mail.send (mailto, subject, body); // Delete the confirmation record. database_confirm.erase (id); // Job done. return true; }
void client_index_remove_all_users (void * webserver_request) { Webserver_Request * request = (Webserver_Request *) webserver_request; vector <string> existingusers = request->database_users()->getUsers (); for (auto existinguser : existingusers) { request->database_users()->removeUser (existinguser); } }
string xrefs_translate (void * webserver_request) { Webserver_Request * request = (Webserver_Request *) webserver_request; string sourceBible = request->database_config_user()->getSourceXrefBible (); string targetBible = request->database_config_user()->getTargetXrefBible (); // Save book / abbreviation pair. if (request->post.count ("save")) { string fullname = request->post ["fullname"]; string abbreviation = request->post ["abbreviation"]; string abbreviations = Database_Config_Bible::getBookAbbreviations (targetBible); abbreviations = filter_abbreviations_add (abbreviations, fullname, abbreviation); Database_Config_Bible::setBookAbbreviations (targetBible, abbreviations); } string abbrevs = Database_Config_Bible::getBookAbbreviations (sourceBible); vector <pair <int, string> > sourceAbbreviations = filter_abbreviations_read (abbrevs); vector <int> sourceBooks; for (auto element : sourceAbbreviations) sourceBooks.push_back (element.first); abbrevs = Database_Config_Bible::getBookAbbreviations (targetBible); vector <pair <int, string> > targetAbbreviations = filter_abbreviations_read (abbrevs); vector <int> targetBooks; for (auto element : targetAbbreviations) targetBooks.push_back (element.first); vector <int> unknown_books = filter_string_array_diff (sourceBooks, targetBooks); unknown_books = array_unique (unknown_books); if (unknown_books.empty ()) { redirect_browser (request, xrefs_clear_url ()); return ""; } string page; Assets_Header header = Assets_Header (translate("Cross references"), webserver_request); page = header.run (); Assets_View view; view.set_variable ("remaining", convert_to_string (unknown_books.size () - 1)); string bookname = Database_Books::getEnglishFromId (unknown_books [0]); view.set_variable ("bookname", bookname); page += view.render ("xrefs", "translate"); page += Assets_Page::footer (); return page; }
string workspace_get_active_name (void * webserver_request) { Webserver_Request * request = (Webserver_Request *) webserver_request; string workspace = request->database_config_user()->getActiveWorkspace (); if (workspace.empty ()) { workspace = workspace_get_default_name (); } return workspace; }
string editone_preview (void * webserver_request) { Webserver_Request * request = (Webserver_Request *) webserver_request; bool touch = request->session_logic ()->touchEnabled (); string page; Assets_Header header = Assets_Header (translate("Preview"), request); header.setNavigator (); header.setEditorStylesheet (); if (touch) header.jQueryTouchOn (); header.addBreadCrumb (menu_logic_translate_menu (), menu_logic_translate_text ()); header.refresh (5, "index"); page = header.run (); Assets_View view; // Get active Bible, and check read access to it. // If needed, change Bible to one it has read access to. string bible = access_bible_clamp (request, request->database_config_user()->getBible ()); string cls = Filter_Css::getClass (bible); string font = Fonts_Logic::getTextFont (bible); int direction = Database_Config_Bible::getTextDirection (bible); int lineheight = Database_Config_Bible::getLineHeight (bible); int letterspacing = Database_Config_Bible::getLetterSpacing (bible); view.set_variable ("custom_class", cls); view.set_variable ("custom_css", Filter_Css::getCss (cls, Fonts_Logic::getFontPath (font), direction, lineheight, letterspacing)); int book = Ipc_Focus::getBook (webserver_request); int chapter = Ipc_Focus::getChapter (webserver_request); //int verse = Ipc_Focus::getVerse (webserver_request); string stylesheet = request->database_config_user()->getStylesheet (); string usfm = request->database_bibles()->getChapter (bible, book, chapter); Editor_Usfm2Html editor_usfm2html; editor_usfm2html.load (usfm); editor_usfm2html.stylesheet (stylesheet); editor_usfm2html.run (); string html = editor_usfm2html.get (); view.set_variable ("html", html); page += view.render ("editone", "preview"); page += Assets_Page::footer (); return page; }
string checks_suppress (void * webserver_request) { Webserver_Request * request = (Webserver_Request *) webserver_request; Database_Check database_check; string page; page = Assets_Page::header (translate ("Suppressed check results"), webserver_request); Assets_View view; if (request->query.count ("release")) { int release = convert_to_int (request->query["release"]); database_check.release (release); view.set_variable ("success", translate("The check result is no longer suppressed.")); } // Get the Bibles the user has write-access to. vector <string> bibles; { vector <string> all_bibles = request->database_bibles()->getBibles (); for (auto bible : all_bibles) { if (access_bible_write (webserver_request, bible)) { bibles.push_back (bible); } } } string block; vector <Database_Check_Hit> suppressions = database_check.getSuppressions (); for (auto suppression : suppressions) { string bible = suppression.bible; // Only display entries for Bibles the user has write access to. if (in_array (bible, bibles)) { int id = suppression.rowid; bible = filter_string_sanitize_html (bible); string passage = filter_passage_display_inline ({Passage ("", suppression.book, suppression.chapter, convert_to_string (suppression.verse))}); string result = filter_string_sanitize_html (suppression.data); result.insert (0, bible + " " + passage + " "); block.append ("<p style=\"color:grey;\">\n"); block.append ("<a href=\"suppress?release=" + convert_to_string (id) + "\">\n"); block.append (emoji_wastebasket () + "\n"); block.append ("</a>\n"); block.append (result + "\n"); block.append ("</p>\n"); } } view.set_variable ("block", block); page += view.render ("checks", "suppress"); page += Assets_Page::footer (); return page; }
void Navigation_Passage::goForward (void * webserver_request) { Webserver_Request * request = (Webserver_Request *) webserver_request; Database_Navigation database_navigation; string user = request->session_logic()->currentUser (); Passage passage = database_navigation.getNext (user); if (passage.book) { Ipc_Focus::set (webserver_request, passage.book, passage.chapter, convert_to_int (passage.verse)); } }
void trash_change_notification (void * webserver_request, int id) { Database_Modifications database_modifications; Passage passage = database_modifications.getNotificationPassage (id); string passageText = filter_passage_display_inline ({passage}); string modification = database_modifications.getNotificationModification (id); Webserver_Request * request = (Webserver_Request *) webserver_request; string username = request->session_logic()->currentUser (); Database_Logs::log (username + " removed change notification " + passageText + " : " + modification); }
// If $set is true, it sets the alive status of the notes editor. // If $set is false, it returns the alive status. bool Ipc_Notes::alive (void * webserver_request, bool set, bool alive) { Webserver_Request * request = (Webserver_Request *) webserver_request; string user = request->session_logic()->currentUser (); if (set) { request->database_ipc()->storeMessage (user, "", "notesalive", convert_to_string (alive)); } else { return request->database_ipc()->getNotesAlive (); } return false; }
void Ipc_Notes::erase (void * webserver_request) { Webserver_Request * request = (Webserver_Request *) webserver_request; Database_Ipc_Message data = request->database_ipc()->getNote (); int counter = 0; while (data.id && (counter < 100)) { int id = data.id; request->database_ipc()->deleteMessage (id); counter++; } }
string edit_focus (void * webserver_request) { Webserver_Request * request = (Webserver_Request *) webserver_request; // Get Bible: If an empty Bible is given, bail out. string bible = request->query ["bible"]; if (bible.empty ()) return ""; // Get book: If no book is given: Bail out. int book = convert_to_int (request->query ["book"]); if (!book) return ""; // Get chapter. int chapter = convert_to_int (request->query ["chapter"]); string stylesheet = request->database_config_user()->getStylesheet (); string usfm = request->database_bibles()->getChapter (bible, book, chapter); int verse = Ipc_Focus::getVerse (request); Editor_Usfm2Html editor_usfm2html; editor_usfm2html.load (usfm); editor_usfm2html.stylesheet (stylesheet); editor_usfm2html.run (); int startingOffset = 0; int endingOffset = 0; // To deal with a combined verse, go through the offsets, and pick the correct one. for (auto element : editor_usfm2html.verseStartOffsets) { int vs = element.first; int offset = element.second; if (vs <= verse) startingOffset = offset; if (endingOffset == 0) { if (vs > verse) { endingOffset = offset; } } } if (verse) { startingOffset += convert_to_string (verse).length () + 1; } if (endingOffset) { endingOffset--; } else { endingOffset = editor_usfm2html.textLength; } string data = convert_to_string (startingOffset); data.append ("\n"); data.append (convert_to_string (endingOffset)); return data; }
Passage Navigation_Passage::getPreviousVerse (void * webserver_request, string bible, int book, int chapter, int verse) { verse--; if (bible != "") { Webserver_Request * request = (Webserver_Request *) webserver_request; vector <int> verses = usfm_get_verse_numbers (request->database_bibles()->getChapter (bible, book, chapter)); if (find (verses.begin(), verses.end(), verse) == verses.end()) { if (!verses.empty ()) verse = verses [0]; } } Passage passage = Passage ("", book, chapter, convert_to_string (verse)); return passage; }
Passage Navigation_Passage::getPreviousChapter (void * webserver_request, string bible, int book, int chapter) { chapter--; if (bible != "") { Webserver_Request * request = (Webserver_Request *) webserver_request; vector <int> chapters = request->database_bibles ()->getChapters (bible, book); if (find (chapters.begin(), chapters.end(), chapter) == chapters.end()) { if (!chapters.empty ()) chapter = chapters [0]; } } Passage passage = Passage ("", book, chapter, "1"); return passage; }
void trash_consultation_note (void * webserver_request, int id) { Database_Notes database_notes (webserver_request); vector <Passage> passages = database_notes.getPassages (id); string passageText = filter_passage_display_inline (passages); string summary = database_notes.getSummary (id); string contents = database_notes.getContents (id); contents = filter_string_html2text (contents); Webserver_Request * request = (Webserver_Request *) webserver_request; string username = request->session_logic()->currentUser (); if (username.empty ()) username = "******"; Database_Logs::log (username + " deleted or marked for deletion consultation note " + passageText + " | " + summary + " | " + contents); }
// Returns whether the interface is supposed to be in basic mode. // When the mode was flipped, this used to expire after some hours. // But there may be people working on a tablet, // who would want to permanently switch to advanced mode, without this mode to expire. // Therefore the mode flip switch is now permanent, till flipped again. bool config_logic_basic_mode (void * webserver_request) { Webserver_Request * request = (Webserver_Request *) webserver_request; // When this is a touch-enabled device, the basic mode will be on. bool basic_mode = request->session_logic ()->touchEnabled (); // Check whether to flip basic <> advanced mode. if (request->database_config_user ()->getFlipInterfaceMode ()) { basic_mode = !basic_mode; } return basic_mode; }
string basic_index (void * webserver_request) { Webserver_Request * request = (Webserver_Request *) webserver_request; Assets_Header header = Assets_Header ("Settings", webserver_request); string page = header.run (); Assets_View view; if (request->query.count ("changebible")) { string changebible = request->query ["changebible"]; if (changebible == "") { Dialog_List dialog_list = Dialog_List ("index", translate("Select which Bible to make the active one for editing"), "", ""); vector <string> bibles = access_bible_bibles (request); for (auto & bible : bibles) { dialog_list.add_row (bible, "changebible", bible); } page += dialog_list.run(); return page; } else { request->database_config_user()->setBible (changebible); // Going to another Bible, ensure that the focused book exists there. int book = Ipc_Focus::getBook (request); vector <int> books = request->database_bibles()->getBooks (changebible); if (find (books.begin(), books.end(), book) == books.end()) { if (!books.empty ()) book = books [0]; else book = 0; Ipc_Focus::set (request, book, 1, 1); } } } string bible = access_bible_clamp (request, request->database_config_user()->getBible ()); view.set_variable ("bible", bible); #ifdef CLIENT_PREPARED view.enable_zone ("client"); if (client_logic_client_enabled ()) { view.enable_zone ("connected"); } #else view.enable_zone ("cloud"); #endif page += view.render ("basic", "index"); page += Assets_Page::footer (); return page; }
// Generates the CSS. void Styles_Css::generate () { code.push_back (".superscript { font-size: x-small; vertical-align: super; }"); if (exports_enabled) { add_exports_styles (); } if (editor_enabled) { add_editor_styles (); } Webserver_Request * request = (Webserver_Request *) webserver_request; vector <string> markers = request->database_styles ()->getMarkers (stylesheet); for (auto & marker : markers) { Database_Styles_Item style = request->database_styles ()->getMarkerData (stylesheet, marker); evaluate (&style); } }
void config_logic_swipe_enabled (void * webserver_request, string & script) { Webserver_Request * request = (Webserver_Request *) webserver_request; string true_false = "false"; if (request->session_logic ()->touchEnabled ()) { if (request->database_config_user ()->getSwipeActionsAvailable ()) { true_false = "true"; } } script.append ("\n"); script.append ("var swipe_operations = "); script.append (true_false); script.append (";"); }
string notes_assign_1 (void * webserver_request) { Webserver_Request * request = (Webserver_Request *) webserver_request; Database_Notes database_notes (webserver_request); Notes_Logic notes_logic = Notes_Logic (webserver_request); Database_NoteAssignment database_noteassignment; string page; Assets_Header header = Assets_Header (translate("Assign note"), request); page += header.run(); Assets_View view; string success, error; string user = request->session_logic ()->currentUser (); int id = convert_to_int (request->query ["id"]); view.set_variable ("id", convert_to_string (id)); if (request->query.count ("assign")) { string assign = request->query ["assign"]; if (database_noteassignment.exists (user, assign)) { notes_logic.assignUser (id, assign); } redirect_browser (request, notes_actions_url () + "?id=" + convert_to_string (id)); return ""; } // Note assignees. string userblock; vector <string> assignees = database_noteassignment.assignees (user); for (auto & assignee : assignees) { userblock.append ("<li><a href=\"assign-1?id=" + convert_to_string (id) + "&assign=" + assignee + "\">" + assignee + "</a></li>\n"); } view.set_variable ("userblock", userblock); view.set_variable ("success", success); view.set_variable ("error", error); page += view.render ("notes", "assign-1"); page += Assets_Page::footer (); return page; }
string search_replace2 (void * webserver_request) { // Build the advanced replace page. Webserver_Request * request = (Webserver_Request *) webserver_request; string bible = request->database_config_user()->getBible (); string page; Assets_Header header = Assets_Header (translate("Replace"), request); header.addBreadCrumb (menu_logic_search_menu (), menu_logic_search_text ()); page = header.run (); Assets_View view; view.set_variable ("bible", bible); string script = "var searchBible = \"" + bible + "\";"; view.set_variable ("script", script); page += view.render ("search", "replace2"); page += Assets_Page::footer (); return page; }
string index_index (void * webserver_request) { Webserver_Request * request = (Webserver_Request *) webserver_request; Assets_Header header = Assets_Header ("Bibledit", webserver_request); if (config_logic_demo_enabled ()) { // The demo, when there's no active menu, forwards to a the active workbench. if (request->query.empty ()) { header.refresh (5, "/" + workbench_index_url ()); } } // Mode toggle: basic <> advanced. string mode = request->query ["mode"]; if (!mode.empty ()) { int flip = false; if (mode == "basic") { if (!request->session_logic ()->touchEnabled ()) { flip = true; } } if (mode == "advanced") { if (request->session_logic ()->touchEnabled ()) { flip = true; } } request->database_config_user ()->setFlipInterfaceMode (flip); } // Normally a page does not show the expanded main menu. // This is to save space on the screen. // But the home page of Bibledit show the extended main menu. if (request->query.count ("item") == 0) { request->query ["item"] = "main"; } string page = header.run (); Assets_View view; page += view.render ("index", "index"); page += Assets_Page::footer (); return page; }
// Function to safely store a chapter. // It saves the chapter if the new USFM does not differ too much from the existing USFM. // On success it returns an empty string. // On failure it returns the reason of the failure. // This function proves useful in cases that the text in the Bible editor gets corrupted // due to human error. // It also is useful in cases where the session is deleted from the server, // where the text in the editors would get corrupted. // It also is useful in view of an unstable connection between browser and server, to prevent data corruption. string usfm_safely_store_chapter (void * webserver_request, string bible, int book, int chapter, string usfm) { Webserver_Request * request = (Webserver_Request *) webserver_request; // Existing chapter contents. string existing = request->database_bibles()->getChapter (bible, book, chapter); // Bail out if the existing chapter equals the USFM to be saved. if (usfm == existing) return ""; // Safety check. string message = usfm_save_is_safe (webserver_request, existing, usfm, true); if (!message.empty ()) return message; // Safety checks have passed: Save chapter. Bible_Logic::storeChapter (bible, book, chapter, usfm); return ""; }