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 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); }
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); }
// This handles email to users. // identifier: the note that is being handled. // label: prefix to the subject line of the email. // users: array of users to be mailed. // postpone: whether to postpone sending the email till the evening. void Notes_Logic::emailUsers (int identifier, const string& label, const vector <string> & users, bool postpone) { // Databases. Database_Notes database_notes (webserver_request); Database_Mail database_mail = Database_Mail(webserver_request); // Send mail to all users. string summary = database_notes.getSummary (identifier); string passages = filter_passage_display_inline (database_notes.getPassages (identifier)); string contents = database_notes.getContents (identifier); // Include links to the Cloud: One to the note, and one to the active desktop. contents.append ("<br>\n"); contents.append ("<p>"); contents.append ("<a href=\""); string notelink = Database_Config_General::getSiteURL () + notes_note_url () + "?id=" + convert_to_string (identifier); contents.append (notelink); contents.append ("\">"); contents.append (translate ("View or respond online")); contents.append ("</a>"); contents.append (" " + translate ("or") + " "); contents.append ("<a href=\""); string desktoplink = Database_Config_General::getSiteURL () + workbench_index_url () + "?note=" + convert_to_string (identifier); contents.append (desktoplink); contents.append ("\">"); contents.append (translate ("open the desktop online")); contents.append ("</a>"); contents.append ("</p>\n"); string mailto = "mailto:" + Database_Config_General::getSiteMailAddress () + "?subject=(CNID" + convert_to_string (identifier) + ")"; contents.append ("<p><a href=\""); contents.append (mailto); contents.append ("\">Respond by email</a></p>\n"); // Deal with possible postponing email till 9 PM. int timestamp = filter_date_seconds_since_epoch (); if (postpone) { int localseconds = filter_date_local_seconds (timestamp); float localhour = filter_date_numerical_hour (localseconds) + (float) filter_date_numerical_minute (localseconds) / 60; if (localhour < 21) { float difference = 21 - localhour; timestamp += (3600 * difference) - 10; } } // Send (but not in client mode). for (auto & user : users) { if (!client_logic_client_enabled ()) { string subject = label; subject.append (" | "); subject.append (passages); subject.append (" | "); subject.append (summary); subject.append (" | (CNID"); subject.append (convert_to_string (identifier)); subject.append (")"); database_mail.send (user, subject, contents, timestamp); } } }
string notes_actions (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("Note actions"), request); header.setNavigator (); page += header.run (); Assets_View view; string success, error; string user = request->session_logic()->currentUser (); int level = request->session_logic()->currentLevel (); int id; if (request->query.count ("id")) id = convert_to_int (request->query ["id"]); else id = convert_to_int (request->post ["id"]); if (request->query.count ("unsubscribe")) { notes_logic.unsubscribe (id); } if (request->query.count ("subscribe")) { notes_logic.subscribe (id); } if (request->query.count ("unassign")) { string unassign = request->query["unassign"]; notes_logic.unassignUser (id, unassign); } if (request->query.count ("done")) { notes_logic.unassignUser (id, user); } if (request->query.count ("markdel")) { notes_logic.markForDeletion (id); success = translate("The note will be deleted after a week.") + " " + translate ("Adding a comment to the note cancels the deletion."); } if (request->query.count ("unmarkdel")) { notes_logic.unmarkForDeletion (id); } if (request->query.count ("delete")) { notes_logic.erase (id); redirect_browser (request, notes_index_url ()); return ""; } if (request->query.count ("publicnote")) { bool state = database_notes.getPublic (id); database_notes.setPublic (id, !state); } view.set_variable ("id", convert_to_string (id)); string summary = database_notes.getSummary (id); view.set_variable ("summary", summary); bool subscribed = database_notes.isSubscribed (id, user); if (subscribed) view.enable_zone ("subscribed"); else view.enable_zone ("subscribe"); vector <string> assignees = database_notes.getAssignees (id); string assigneeblock; for (auto & assignee : assignees) { assigneeblock.append (assignee); if (level >= Filter_Roles::manager ()) { assigneeblock.append ("<a href=\"?id=" + convert_to_string (id) + "&unassign=" + assignee + "\"> [" + translate("unassign") + "]</a>"); assigneeblock.append (" | "); } } view.set_variable ("assigneeblock", assigneeblock); if (level >= Filter_Roles::manager ()) view.enable_zone ("assign"); bool assigned = database_notes.isAssigned (id, user); if (assigned) view.enable_zone ("assigned"); string status = database_notes.getStatus (id); view.set_variable ("status", status); if (Filter_Roles::translator ()) view.enable_zone ("editstatus"); else view.enable_zone ("viewstatus"); string verses = filter_passage_display_inline (database_notes.getPassages (id)); view.set_variable ("verses", verses); string severity = database_notes.getSeverity (id); view.set_variable ("severity", severity); string bible = database_notes.getBible (id); view.set_variable ("bible", bible); if (bible.empty ()) view.enable_zone ("nobible"); if (level >= Filter_Roles::manager ()) view.enable_zone ("rawedit"); if (level >= Filter_Roles::manager ()) view.enable_zone ("marknote"); bool marked = database_notes.isMarkedForDeletion (id); if (marked) view.enable_zone ("marked"); else view.enable_zone ("mark"); #ifndef HAVE_CLIENT view.enable_zone ("cloud"); string on_off = styles_logic_off_on_inherit_toggle_text (database_notes.getPublic (id)); view.set_variable ("publicnote", on_off); #endif // Roles of translator or higher can edit the public visibility of a note. if (level >= Filter_Roles::translator ()) view.enable_zone ("translator"); view.set_variable ("success", success); view.set_variable ("error", error); page += view.render ("notes", "actions"); page += Assets_Page::footer (); return page; }
string notes_notes (void * webserver_request) { Webserver_Request * request = (Webserver_Request *) webserver_request; Database_Notes database_notes (webserver_request); string bible = access_bible_clamp (webserver_request, 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); int passage_selector = request->database_config_user()->getConsultationNotesPassageSelector(); int edit_selector = request->database_config_user()->getConsultationNotesEditSelector(); int non_edit_selector = request->database_config_user()->getConsultationNotesNonEditSelector(); string status_selector = request->database_config_user()->getConsultationNotesStatusSelector(); string bible_selector = request->database_config_user()->getConsultationNotesBibleSelector(); string assignment_selector = request->database_config_user()->getConsultationNotesAssignmentSelector(); bool subscription_selector = request->database_config_user()->getConsultationNotesSubscriptionSelector(); int severity_selector = request->database_config_user()->getConsultationNotesSeveritySelector(); int text_selector = request->database_config_user()->getConsultationNotesTextSelector(); string search_text = request->database_config_user()->getConsultationNotesSearchText(); int passage_inclusion_selector = request->database_config_user()->getConsultationNotesPassageInclusionSelector(); int text_inclusion_selector = request->database_config_user()->getConsultationNotesTextInclusionSelector(); // The Bibles the current user has access to. vector <string> bibles = access_bible_bibles (webserver_request, request->session_logic()->currentUser ()); // The admin disables notes selection on Bibles, // so the admin sees all notes, including notes referring to non-existing Bibles. if (request->session_logic ()->currentLevel () == Filter_Roles::admin ()) bibles.clear (); vector <int> identifiers = database_notes.selectNotes (bibles, book, chapter, verse, passage_selector, edit_selector, non_edit_selector, status_selector, bible_selector, assignment_selector, subscription_selector, severity_selector, text_selector, search_text, -1); // In case there aren't too many notes, there's enough time to sort them in passage order. if (identifiers.size () <= 200) { vector <int> passage_sort_keys; for (auto & identifier : identifiers) { int passage_sort_key = 0; vector <float> numeric_passages; vector <Passage> passages = database_notes.getPassages (identifier); for (auto & passage : passages) { numeric_passages.push_back (filter_passage_to_integer (passage)); } if (!numeric_passages.empty ()) { float average = accumulate (numeric_passages.begin (), numeric_passages.end (), 0) / numeric_passages.size (); passage_sort_key = round (average); } passage_sort_keys.push_back (passage_sort_key); } quick_sort (passage_sort_keys, identifiers, 0, identifiers.size ()); } string notesblock; for (auto & identifier : identifiers) { string summary = database_notes.getSummary (identifier); vector <Passage> passages = database_notes.getPassages (identifier); string verses = filter_passage_display_inline (passages); // A simple way to make it easier to see the individual notes in the list, // when the summaries of some notes are long, is to display the passage first. summary.insert (0, verses + " | "); string verse_text; if (passage_inclusion_selector) { vector <Passage> passages = database_notes.getPassages (identifier); for (auto & passage : passages) { string usfm = request->database_bibles()->getChapter (bible, passage.book, passage.chapter); string text = usfm_get_verse_text (usfm, convert_to_int (passage.verse)); if (!verse_text.empty ()) verse_text.append ("<br>"); verse_text.append (text); } } string content; if (text_inclusion_selector) { content = database_notes.getContents (identifier); } notesblock.append ("<a name=\"note" + convert_to_string (identifier) + "\"></a>\n"); notesblock.append ("<p><a href=\"note?id=" + convert_to_string (identifier) + "\">" + summary + "</a></p>\n"); if (!verse_text.empty ()) notesblock.append ("<p>" + verse_text + "</p>\n"); if (!content.empty ()) notesblock.append ("<p>" + content + "</p>\n"); } if (identifiers.empty ()) { return translate("This selection does not display any notes."); } return notesblock; }
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; }