Пример #1
0
string filter_passage_link_for_opening_editor_at (int book, int chapter, string verse)
{
  string display = filter_passage_display (book, chapter, verse);
  Passage passage = Passage ("", book, chapter, verse);
  string numeric = convert_to_string (filter_passage_to_integer (passage));
  string link = "<a class=\"starteditor\" href=\"" + numeric + "\">" + display + "</a> <span></span>";
  return link;
}
Пример #2
0
string xrefs_next (void * webserver_request)
{
  Webserver_Request * request = (Webserver_Request *) webserver_request;
  
  
  string bible = request->database_config_user()->getTargetXrefBible ();
  
  
  int currentBook = Ipc_Focus::getBook (webserver_request);
  int currentChapter = Ipc_Focus::getChapter (webserver_request);
  Passage currentPassage = Passage ("", currentBook, currentChapter, "1");
  int currentLocation = filter_passage_to_integer (currentPassage);
  
  
  vector <int> books = request->database_bibles()->getBooks (bible);
  for (auto book : books) {
    vector <int> chapters = request->database_bibles()->getChapters (bible, book);
    for (auto chapter : chapters) {
      if (chapter == 0) continue;
      Passage passage = Passage ("", book, chapter, "1");
      int location = filter_passage_to_integer (passage);
      if (location > currentLocation) {
        string usfm = request->database_bibles()->getChapter (bible, book, chapter);
        auto xrefs = usfm_extract_notes (usfm, {"x"});
        if (xrefs.empty ()) {
          Ipc_Focus::set (webserver_request, book, chapter, 1);
          redirect_browser (request, xrefs_index_url ());
          return "";
        }
      }
    }
  }
  
  
  redirect_browser (request, xrefs_index_url ());
  return "";
}
Пример #3
0
string resource_img (void * webserver_request)
{
  Webserver_Request * request = (Webserver_Request *) webserver_request;
  Database_ImageResources database_imageresources;

  
  string page;
  Assets_Header header = Assets_Header (translate("Image resources"), request);
  page = header.run ();
  Assets_View view;
  string error, success;
  int book1, chapter1, verse1, book2, chapter2, verse2;
  
  
  string name = request->query ["name"];
  view.set_variable ("name", name);

  
  string image = request->query ["image"];
  view.set_variable ("image", image);

  
  int userid = filter_string_user_identifier (webserver_request);

  
  if (request->post.count ("submit")) {
    
    vector <string> errors;
    
    string book = request->post ["book1"];
    book1 = filter_passage_interpret_book (book);
    if (book1 == 0) errors.push_back (translate ("Unknown starting book."));

    chapter1 = convert_to_int (request->post ["chapter1"]);
    if (chapter1 < 0) errors.push_back (translate ("Negative starting chapter."));
    if (chapter1 > 200) errors.push_back (translate ("High starting chapter."));
    
    verse1 = convert_to_int (request->post ["verse1"]);
    if (chapter1 < 0) errors.push_back (translate ("Negative starting verse."));
    if (chapter1 > 200) errors.push_back (translate ("High starting verse."));
    
    book = request->post ["book2"];
    book2 = filter_passage_interpret_book (book);
    if (book2 == 0) errors.push_back (translate ("Unknown ending book."));
    
    chapter2 = convert_to_int (request->post ["chapter2"]);
    if (chapter2 < 0) errors.push_back (translate ("Negative ending chapter."));
    if (chapter2 > 200) errors.push_back (translate ("High ending chapter."));
    
    verse2 = convert_to_int (request->post ["verse2"]);
    if (chapter2 < 0) errors.push_back (translate ("Negative ending verse."));
    if (chapter2 > 200) errors.push_back (translate ("High ending verse."));
    
    int start = filter_passage_to_integer (Passage ("", book1, chapter1, convert_to_string (verse1)));
    int end = filter_passage_to_integer (Passage ("", book2, chapter2, convert_to_string (verse2)));
    if (start > end) {
      errors.push_back (translate ("The starting passage is beyond the ending passage."));
    }

    database_imageresources.assign (name, image, book1, chapter1, verse1, book2, chapter2, verse2);
    
    Database_Volatile::setValue (userid, "imageresources", convert_to_string (end));

    error = filter_string_implode (errors, " ");
    if (errors.empty ()) {
      redirect_browser (request, filter_url_build_http_query (resource_image_url (), "name", name));
      return "";
    }
  }
  
  
  // Retrieve passage range for this image.
  database_imageresources.get (name, image, book1, chapter1, verse1, book2, chapter2, verse2);
  if ((book1 == 0) || (book2 == 0)) {
    string end = Database_Volatile::getValue (userid, "imageresources");
    Passage passage = filter_integer_to_passage (convert_to_int (end));
    book1 = book2 = passage.book;
    chapter1 = chapter2 = passage.chapter;
    verse1 = verse2 = convert_to_int (passage.verse);
    if (book1 == 0) book1 = 1;
    if (book2 == 0) book2 = 1;
  }
  view.set_variable ("book1", Database_Books::getEnglishFromId (book1));
  view.set_variable ("chapter1", convert_to_string (chapter1));
  view.set_variable ("verse1", convert_to_string (verse1));
  view.set_variable ("book2", Database_Books::getEnglishFromId (book2));
  view.set_variable ("chapter2", convert_to_string (chapter2));
  view.set_variable ("verse2", convert_to_string (verse2));
  

  view.set_variable ("success", success);
  view.set_variable ("error", error);
  page += view.render ("resource", "img");
  page += Assets_Page::footer ();
  return page;
}
Пример #4
0
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;
}
Пример #5
0
string search_strong (void * webserver_request)
{
  Webserver_Request * request = (Webserver_Request *) webserver_request;


  Database_Kjv database_kjv = Database_Kjv ();
  
  
  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);
    
    // Get Strong's numbers, plus English snippets.
    string html = "<table>\n";
    vector <Database_Kjv_Item> details = database_kjv.getVerse (book, chapter, verse);
    for (auto & detail : details) {
      string strong = detail.strong;
      string english = detail.english;
      html += "<tr><td><a href=\"" + strong + "\">" + strong + "</a></td><td>" + english + "</td></tr>\n";
    }
    html += "</table>\n";
    
    return html;
  }
  
  
  if (request->query.count ("strong")) {
    
    string strong = request->query ["strong"];
    strong = filter_string_trim (strong);
    
    vector <int> passages;
    
    vector <Passage> details = database_kjv.searchStrong (strong);
    
    for (auto & passage : details) {
      int i_passage = filter_passage_to_integer (passage);
      passages.push_back (i_passage);
    }
    
    passages = array_unique (passages);
    sort (passages.begin(), passages.end());
    
    string output;
    for (auto & passage : passages) {
      if (!output.empty()) output.append ("\n");
      output.append (convert_to_string (passage));
    }
    return output;
  }
  
  
  if (request->query.count ("id")) {
    int id = convert_to_int (request->query ["id"]);
    
    // Get the and passage for this identifier.
    Passage passage = filter_integer_to_passage (id);
    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));
    
    // Format it.
    string link = filter_passage_link_for_opening_editor_at (book, chapter, verse);
    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", "strong");
  
  page += Assets_Page::footer ();
  
  return page;
}
Пример #6
0
void sendreceive_resources ()
{
  if (sendreceive_resources_watchdog) {
    int time = filter_date_seconds_since_epoch ();
    if (time < (sendreceive_resources_watchdog + 900)) {
      return;
    }
    Database_Logs::log ("Resources: " + translate("Watchdog timeout"), Filter_Roles::translator ());
    sendreceive_resources_done ();
  }

  // If any of the prioritized synchronization tasks run, postpone the current task and do not start it.
  if (sendreceive_logic_prioritized_task_is_active ()) {
    sendreceive_resources_done ();
    this_thread::sleep_for (chrono::seconds (5));
    tasks_logic_queue (SYNCRESOURCES);
    return;
  }

  sendreceive_resources_interrupt = false;

  // If there's nothing to cache, bail out.
  vector <string> resources = Database_Config_General::getResourcesToCache ();
  if (resources.empty ()) return;
  
  sendreceive_resources_kick_watchdog ();

  // Error counter.
  int error_count = 0;
  
  // Resource to cache.
  string resource = resources [0];
  
  // Erase the two older storage locations that were used to cache resources in earlier versions of Bibledit.
  {
    Database_OfflineResources database_offlineresources;
    Database_UsfmResources database_usfmresources;
    database_offlineresources.erase (resource);
    database_usfmresources.deleteResource (resource);
  }

  Database_Logs::log ("Starting to install resource:" " " + resource, Filter_Roles::consultant ());
  
  Database_Versifications database_versifications;
  
  vector <int> books = database_versifications.getMaximumBooks ();
  for (auto & book : books) {
    sendreceive_resources_delay_during_prioritized_tasks ();
    if (sendreceive_resources_interrupt) continue;
    
    // Database layout is per book: Create a database for this book.
    Database_Cache::create (resource, book);

    // Last downloaded passage in a previous download operation.
    int last_downloaded_passage = 0;
    {
      pair <int, int> progress = Database_Cache::progress (resource, book);
      int chapter = progress.first;
      int verse = progress.second;
      Passage passage ("", book, chapter, convert_to_string (verse));
      last_downloaded_passage = filter_passage_to_integer (passage);
    }
    
    // List of passages recorded in the database that had errors on a previous download operation.
    vector <int> previous_errors;
    {
      vector <pair <int, int> > errors = Database_Cache::errors (resource, book);
      for (auto & element : errors) {
        int chapter = element.first;
        int verse = element.second;
        Passage passage ("", book, chapter, convert_to_string (verse));
        int numeric_error = filter_passage_to_integer (passage);
        previous_errors.push_back (numeric_error);
      }
    }
    
    string bookName = Database_Books::getEnglishFromId (book);
    
    vector <int> chapters = database_versifications.getMaximumChapters (book);
    for (auto & chapter : chapters) {
      sendreceive_resources_delay_during_prioritized_tasks ();
      if (sendreceive_resources_interrupt) continue;
      bool downloaded = false;
      string message = resource + ": " + bookName + " chapter " + convert_to_string (chapter);
      vector <int> verses = database_versifications.getMaximumVerses (book, chapter);
      for (auto & verse : verses) {
        sendreceive_resources_delay_during_prioritized_tasks ();
        if (sendreceive_resources_interrupt) continue;
        // Numeric representation of passage to deal with.
        Passage passage ("", book, chapter, convert_to_string (verse));
        int numeric_passage = filter_passage_to_integer (passage);
        // Conditions to download this verse:
        // 1. The passage is past the last downloaded passage.
        bool download_verse_past = numeric_passage > last_downloaded_passage;
        // 2. The passage was recorded as an error in a previous download operation.
        bool download_verse_error = in_array (numeric_passage, previous_errors);
        // Whether to download the verse.
        if (download_verse_past || download_verse_error) {
          // Fetch the text for the passage.
          bool server_is_installing_module = false;
          int wait_iterations = 0;
          string html, error;
          do {
            // Fetch this resource from the server.
            string address = Database_Config_General::getServerAddress ();
            int port = Database_Config_General::getServerPort ();
            // If the client has not been connected to a cloud instance,
            // fetch the resource from the Bibledit Cloud demo.
            if (!client_logic_client_enabled ()) {
              address = demo_address ();
              port = demo_port ();
            }
            string url = client_logic_url (address, port, sync_resources_url ());
            url = filter_url_build_http_query (url, "r", filter_url_urlencode (resource));
            url = filter_url_build_http_query (url, "b", convert_to_string (book));
            url = filter_url_build_http_query (url, "c", convert_to_string (chapter));
            url = filter_url_build_http_query (url, "v", convert_to_string (verse));
            error.clear ();
            html = filter_url_http_get (url, error);
            server_is_installing_module = (html == sword_logic_installing_module_text ());
            if (server_is_installing_module) {
              Database_Logs::log ("Waiting while Bibledit Cloud installs the requested SWORD module");
              this_thread::sleep_for (chrono::seconds (60));
              wait_iterations++;
            }
          } while (server_is_installing_module && (wait_iterations < 5));
          // Record the passage as having been done in case it was a regular download,
          // rather than one to retry a previous download error.
          if (download_verse_past) Database_Cache::progress (resource, book, chapter, verse);
          // Clear the registered error in case the verse download corrects it.
          if (download_verse_error) Database_Cache::error (resource, book, chapter, verse, false);
          if (error.empty ()) {
            // Cache the verse data.
            if (!Database_Cache::exists (resource, book)) Database_Cache::create (resource, book);
            Database_Cache::cache (resource, book, chapter, verse, html);
          } else {
            // Record an error.
            Database_Cache::error (resource, book, chapter, verse, true);
            if (message.find (error) == string::npos) {
              message.append ("; " + error);
            }
            error_count++;
            this_thread::sleep_for (chrono::seconds (1));
          }
          downloaded = true;
        }
        sendreceive_resources_kick_watchdog ();
      }
      message += "; done";
      if (downloaded) Database_Logs::log (message, Filter_Roles::manager ());
    }
  }
  
  // Done.
  if (error_count) {
    string msg = "Error count while downloading resource: " + convert_to_string (error_count);
    Database_Logs::log (msg, Filter_Roles::consultant ());
  }
  Database_Logs::log ("Completed installing resource:" " " + resource, Filter_Roles::consultant ());
  // In case of too many errors, schedule the resource download again.
  bool re_schedule_download = false;
  if (error_count) {
    if (!sendreceive_resources_interrupt) {
      re_schedule_download = true;
      Database_Logs::log ("Errors: Re-scheduling resource installation", Filter_Roles::consultant ());
    }
  }
  // Store new download schedule.
  resources = Database_Config_General::getResourcesToCache ();
  resources = filter_string_array_diff (resources, {resource});
  if (re_schedule_download) {
    resources.push_back (resource);
  }
  Database_Config_General::setResourcesToCache (resources);

  sendreceive_resources_done ();
  
  sendreceive_resources_interrupt = false;

  // If there's another resource waiting to be cached, schedule it for caching.
  if (!resources.empty ()) tasks_logic_queue (SYNCRESOURCES);
}
Пример #7
0
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;
}