string search_replacepre2 (void * webserver_request) { Webserver_Request * request = (Webserver_Request *) webserver_request; string siteUrl = Database_Config_General::getSiteURL (); // Get search variables from the query. string searchfor = request->query ["q"]; string replacewith = request->query ["r"]; bool casesensitive = (request->query ["c"] == "true"); string id = request->query ["id"]; bool searchplain = (request->query ["p"] == "true"); // Get the Bible and passage for this identifier. Passage details = Passage::from_text (id); string bible = details.bible; int book = details.book; int chapter = details.chapter; string verse = details.verse; // Get the plain text or the USFM. string text; if (searchplain) { text = search_logic_get_bible_verse_text (bible, book, chapter, convert_to_int (verse)); } else { text = search_logic_get_bible_verse_usfm (bible, book, chapter, convert_to_int (verse)); } // Clickable passage. string link = filter_passage_link_for_opening_editor_at (book, chapter, verse); string oldtext = filter_string_markup_words ({searchfor}, text); string newtext (text); if (casesensitive) { newtext = filter_string_str_replace (searchfor, replacewith, newtext); } else { vector <string> needles = filter_string_search_needles (searchfor, text); for (auto & needle : needles) { newtext = filter_string_str_replace (needle, replacewith, newtext); } } if (replacewith != "") newtext = filter_string_markup_words ({replacewith}, newtext); // The id sent to the browser contains bible identifier, book, chapter, and verse. int bibleID = request->database_bibles()->getID (bible); vector <string> bits = {convert_to_string (bibleID), convert_to_string (book), convert_to_string (chapter), verse}; string s_id = filter_string_implode (bits, "_"); // Check whether the user has write access to the book. string user = request->session_logic ()->currentUser (); bool write = access_bible_book_write (webserver_request, user, bible, book); // Create output. string output; output.append ("<div id=\"" + s_id + "\">\n"); output.append ("<p>"); if (write) output.append ("<a href=\"replace\"> ✔ </a> <a href=\"delete\"> ✗ </a> "); output.append (link); output.append ("</p>\n"); output.append ("<p>" + oldtext + "</p>\n"); output.append ("<p>"); if (write) output.append (newtext); else output.append (locale_logic_text_no_privileges_modify_book ()); output.append ("</p>\n"); output.append ("</div>\n"); // Output to browser. return output; }
string search_search2 (void * webserver_request) { Webserver_Request * request = (Webserver_Request *) webserver_request; Database_Volatile database_volatile = Database_Volatile (); string siteUrl = config_logic_site_url (); string bible = request->database_config_user()->getBible (); if (request->query.count ("bible")) bible = request->query ["bible"]; bool hit_is_set = request->query.count ("h"); bool query_is_set = request->query.count ("q"); int identifier = convert_to_int (request->query ["i"]); string query = request->query ["q"]; string hit = request->query ["h"]; // Get one search hit. if (hit_is_set) { // Retrieve the search parameters from the volatile database. string query = database_volatile.getValue (identifier, "query"); //bool casesensitive = convert_to_bool (database_volatile.getValue (identifier, "casesensitive")); bool plaintext = convert_to_bool (database_volatile.getValue (identifier, "plaintext")); // Get the Bible and passage for this identifier. Passage details = Passage::from_text (hit); string bible = details.bible; int book = details.book; int chapter = details.chapter; string verse = details.verse; // Get the plain text or USFM. string text; if (plaintext) { text = search_logic_get_bible_verse_text (bible, book, chapter, convert_to_int (verse)); } else { text = search_logic_get_bible_verse_usfm (bible, book, chapter, convert_to_int (verse)); } // Format it. string link = filter_passage_link_for_opening_editor_at (book, chapter, verse); text = filter_string_markup_words ({query}, text); string output = "<div>" + link + " " + text + "</div>"; // Output to browser. return output; } // Perform the initial search. if (query_is_set) { // Get extra search parameters and store them all in the volatile database. bool casesensitive = (request->query ["c"] == "true"); bool plaintext = (request->query ["p"] == "true"); bool currentbook = (request->query ["b"] == "true"); string sharing = request->query ["s"]; database_volatile.setValue (identifier, "query", query); database_volatile.setValue (identifier, "casesensitive", convert_to_string (casesensitive)); database_volatile.setValue (identifier, "plaintext", convert_to_string (plaintext)); // Deal with case sensitivity. // Deal with whether to search the plain text, or the raw USFM. // Fetch the initial set of hits. vector <Passage> passages; if (plaintext) { if (casesensitive) { passages = search_logic_search_bible_text_case_sensitive (bible, query); } else { passages = search_logic_search_bible_text (bible, query); } } else { if (casesensitive) { passages = search_logic_search_bible_usfm_case_sensitive (bible, query); } else { passages = search_logic_search_bible_usfm (bible, query); } } // Deal with possible searching in the current book only. if (currentbook) { int book = Ipc_Focus::getBook (request); vector <Passage> bookpassages; for (auto & passage : passages) { if (book == passage.book) { bookpassages.push_back (passage); } } passages = bookpassages; } // Deal with how to share the results. vector <string> hits; for (auto & passage : passages) { hits.push_back (passage.to_text ()); } if (sharing != "load") { vector <string> loaded_hits = filter_string_explode (database_volatile.getValue (identifier, "hits"), '\n'); if (sharing == "add") { hits.insert (hits.end(), loaded_hits.begin(), loaded_hits.end()); } if (sharing == "remove") { hits = filter_string_array_diff (loaded_hits, hits); } if (sharing == "intersect") { hits = array_intersect (loaded_hits, hits); } hits = array_unique (hits); } // Generate one string from the hits. string output = filter_string_implode (hits, "\n"); // Store search hits in the volatile database. database_volatile.setValue (identifier, "hits", output); // Output results. return output; } // Build the advanced search page. string page; Assets_Header header = Assets_Header (translate("Search"), request); header.setNavigator (); 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", "search2"); page += Assets_Page::footer (); return page; }
string Consistency_Logic::response () { // The request. Webserver_Request * request = (Webserver_Request *) webserver_request; // The resources to display in the Consistency tool. vector <string> resources = request->database_config_user()->getConsistencyResources (); string bible = access_bible_clamp (webserver_request, request->database_config_user()->getBible ()); resources.insert (resources.begin (), bible); // The passages entered in the Consistency tool. string s_passages = Database_Volatile::getValue (id, "passages"); s_passages = filter_string_trim (s_passages); vector <string> passages = filter_string_explode (s_passages, '\n'); // The translations entered in the Consistency tool. string s_translations = Database_Volatile::getValue (id, "translations"); s_translations = filter_string_trim (s_translations); vector <string> translations = filter_string_explode (s_translations, '\n'); // Contains the response to display. vector <string> response; // Go through the passages interpreting them. Passage previousPassage = Passage ("", 1, 1, "1"); for (auto line : passages) { // Clean line. line = filter_string_trim (line); // Skip empty line. if (line.empty ()) continue; // Remove verse text remaining with the passage(s) only. line = omit_verse_text (line); vector <string> range_sequence = filter_passage_handle_sequences_ranges (line); for (auto line : range_sequence) { Passage passage = filter_passage_interpret_passage (previousPassage, line); if (passage.book != 0) { int book = passage.book; int chapter = passage.chapter; string verse = passage.verse; line = filter_passage_link_for_opening_editor_at (book, chapter, verse); line += " "; // Check whether the chapter identifier has changed for this reference. // If so, set a flag so the data can be re-assembled for this verse. // If there was no change, then the data can be fetched from the volatile database. bool redoPassage = false; string passageKey = convert_to_string (book) + "." + convert_to_string (chapter) + "." + verse; int currentChapterId = request->database_bibles()->getChapterId (resources [0], book, chapter); int storedChapterId = convert_to_int (Database_Volatile::getValue (id, passageKey + ".id")); if (currentChapterId != storedChapterId) { Database_Volatile::setValue (id, passageKey + ".id", convert_to_string (currentChapterId)); redoPassage = true; } // Go through each resource. for (auto resource : resources) { // Produce new verse text if the passage is to be redone, or else fetch the existing text. string text; if (redoPassage) { text = verseText (resource, book, chapter, convert_to_int (verse)); if (!translations.empty ()) { text = filter_string_markup_words (translations, text); } Database_Volatile::setValue (id, passageKey + "." + resource, text); } else { text = Database_Volatile::getValue (id, passageKey + "." + resource); } // Formatting. if (resources.size () > 1) { line += "<br>"; } line += text; } response.push_back (line); previousPassage = passage; } else { response.push_back ("<span class=\"error\">" + translate("Unknown passage") + " " + line + "</span>"); } } } string output; for (auto line : response) { output += "<div>" + line + "</div>\n"; } return output; }
string search_all (void * webserver_request) { Webserver_Request * request = (Webserver_Request *) webserver_request; string page; Assets_Header header = Assets_Header (translate("Search"), request); header.addBreadCrumb (menu_logic_search_menu (), menu_logic_search_text ()); page = header.run (); Assets_View view; // The query: The word or string to search for. // Put the query string into the search box. string queryString; if (request->query.count ("q")) { queryString = request->query ["q"]; } view.set_variable ("query", queryString); // Clean the query string up. queryString = filter_string_trim (queryString); // Generate search words for emphasizing the search passages. vector <string> queryWords = filter_string_explode (queryString, ' '); Database_Notes database_notes = Database_Notes (request); string siteUrl = config_logic_site_url (); vector <string> bibles = access_bible_bibles (request); // Search the notes. vector <int> identifiers = database_notes.searchNotes (queryString, bibles); int noteCount = identifiers.size(); view.set_variable ("noteCount", convert_to_string (noteCount)); // Assemble the block of search results for the consultation notes. string notesblock; for (auto identifier : identifiers) { // The title. string summary = database_notes.getSummary (identifier); string verses = filter_passage_display_inline (database_notes.getPassages (identifier)); string title = summary + " | " + verses; title = filter_string_sanitize_html (title); // The url. string url = siteUrl + notes_note_url () + "?id=" + convert_to_string (identifier); // The excerpt. string stext = database_notes.getSearchField (identifier); vector <string> vtext = filter_string_explode (stext, '\n'); string excerpt; // Go through each line of text separately. for (auto & line : vtext) { string markedLine = filter_string_markup_words (queryWords, line); // If the line is marked up, add it to the excerpts. if (!excerpt.empty()) excerpt.append ("\n"); if (markedLine != line) { excerpt.append ("<p style=\"margin-top: 0em\">" + markedLine + "</p>"); } } // The html to display. string html = "<p style=\"margin-top: 0.75em; margin-bottom: 0em\"><a href=\""; html.append (url); html.append ("\">"); html.append (title); html.append ("</a></p>"); html.append (excerpt); if (!notesblock.empty ()) notesblock.append ("\n"); notesblock.append (html); } // Display the search results for the notes. view.set_variable ("notesblock", notesblock); // Search the Bible text. vector <Passage> passages = search_logic_search_text (queryString, bibles); int textCount = passages.size (); view.set_variable ("textCount", convert_to_string (textCount)); // Assemble the search results for the Bible text. string textblock; for (auto & passage : passages) { string bible = passage.bible; int book = passage.book; int chapter = passage.chapter; string verse = passage.verse; // The title plus link. string link = bible + " | " + filter_passage_link_for_opening_editor_at (book, chapter, verse); // The excerpt. string stext = search_logic_get_bible_verse_text (bible, book, chapter, convert_to_int (verse)); vector <string> vtext = filter_string_explode (stext, '\n'); string excerpt; // Go through each line of text separately. for (auto & line : vtext) { string markedLine = filter_string_markup_words (queryWords, line); if (markedLine != line) { // Store this bit of the excerpt. excerpt.append ("<p style=\"margin-top: 0em\">" + markedLine + "</p>\n"); } } if (!textblock.empty ()) textblock.append ("\n"); textblock.append ("<p style=\"margin-top: 0.75em; margin-bottom: 0em\">"); textblock.append (link); textblock.append ("</p>"); textblock.append (excerpt); } // Display the search results for the Bible text. view.set_variable ("textblock", textblock); page += view.render ("search", "all"); page += Assets_Page::footer (); return page; }
string search_similar (void * webserver_request) { Webserver_Request * request = (Webserver_Request *) webserver_request; Database_Volatile database_volatile = Database_Volatile (); int myIdentifier = filter_string_user_identifier (request); string bible = request->database_config_user()->getBible (); if (request->query.count ("b")) { bible = request->query ["b"]; } if (request->query.count ("load")) { int book = Ipc_Focus::getBook (request); int chapter = Ipc_Focus::getChapter (request); int verse = Ipc_Focus::getVerse (request); // Text of the focused verse in the active Bible. // Remove all punctuation from it. string versetext = search_logic_get_bible_verse_text (bible, book, chapter, verse); vector <string> punctuation = filter_string_explode (Database_Config_Bible::getSentenceStructureEndPunctuation (bible), ' '); for (auto & sign : punctuation) { versetext = filter_string_str_replace (sign, "", versetext); } punctuation = filter_string_explode (Database_Config_Bible::getSentenceStructureMiddlePunctuation (bible), ' '); for (auto & sign : punctuation) { versetext = filter_string_str_replace (sign, "", versetext); } versetext = filter_string_trim (versetext); database_volatile.setValue (myIdentifier, "searchsimilar", versetext); return versetext; } if (request->query.count ("words")) { string words = request->query ["words"]; words = filter_string_trim (words); database_volatile.setValue (myIdentifier, "searchsimilar", words); vector <string> vwords = filter_string_explode (words, ' '); // Include items if there are no more search hits than 30% of the total number of verses in the Bible. size_t maxcount = round (0.3 * search_logic_get_verse_count (bible)); // Store how often a verse occurs in an array. // The keys are the identifiers of the search results. // The values are how often the identifiers occur in the entire focused verse. map <int, int> identifiers; for (auto & word : vwords) { // Find out how often this word occurs in the Bible. Skip if too often. vector <Passage> passages = search_logic_search_bible_text (bible, word); if (passages.size () > maxcount) continue; // Store the identifiers and their count. for (auto & passage : passages) { int id = filter_passage_to_integer (passage); if (identifiers.count (id)) identifiers [id]++; else identifiers [id] = 1; } } // Sort on occurrence from high to low. // Skip identifiers that only occur once. vector <int> ids; vector <int> counts; for (auto & element : identifiers) { int id = element.first; int count = element.second; if (count <= 1) continue; ids.push_back (id); counts.push_back (count); } quick_sort (counts, ids, 0, counts.size()); reverse (ids.begin(), ids.end()); // Output the passage identifiers to the browser. string output; for (auto & id : ids) { if (!output.empty ()) output.append ("\n"); output.append (convert_to_string (id)); } return output; } if (request->query.count ("id")) { int id = convert_to_int (request->query ["id"]); // Get the Bible and passage for this identifier. Passage passage = filter_integer_to_passage (id); string bible = request->database_config_user()->getBible (); // string bible = passage.bible; int book = passage.book; int chapter = passage.chapter; string verse = passage.verse; // Get the plain text. string text = search_logic_get_bible_verse_text (bible, book, chapter, convert_to_int (verse)); // Get search words. vector <string> words = filter_string_explode (database_volatile.getValue (myIdentifier, "searchsimilar"), ' '); // Format it. string link = filter_passage_link_for_opening_editor_at (book, chapter, verse); text = filter_string_markup_words (words, text); string output = "<div>" + link + " " + text + "</div>"; // Output to browser. return output; } string page; Assets_Header header = Assets_Header (translate("Search"), request); header.setNavigator (); 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", "similar"); page += Assets_Page::footer (); return page; }