Пример #1
0
// 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 "";
}
Пример #2
0
// 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);
}
Пример #3
0
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;
}
Пример #4
0
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;
}
Пример #5
0
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);
}
Пример #6
0
void client_index_enable_client (void * webserver_request, string username, string password, int level)
{
  Webserver_Request * request = (Webserver_Request *) webserver_request;

  // Enable client mode upon a successful connection.
  client_logic_enable_client (true);
  
  // Remove all users from the database, and add the current one.
  client_index_remove_all_users (request);
  request->database_users ()->add_user (username, password, level, "");
  
  // Update the username and the level in the current session.
  request->session_logic ()->setUsername (username);
  request->session_logic ()->currentLevel (true);
  
  // Clear all pending note actions and Bible actions and settings updates.
  Database_NoteActions database_noteactions;
  Database_BibleActions database_bibleactions;
  database_noteactions.clear ();
  database_noteactions.create ();
  database_bibleactions.clear ();
  database_bibleactions.create ();
  request->session_logic ()->setUsername (username);
  request->database_config_user()->setUpdatedSettings ({});
  Database_Config_General::setUnsentBibleDataTime (0);
  Database_Config_General::setUnreceivedBibleDataTime (filter_date_seconds_since_epoch ());
  
  // Set it to repeat sync every so often.
  if (Database_Config_General::getRepeatSendReceive () == 0) {
    Database_Config_General::setRepeatSendReceive (2);
  }
  
  // Schedule a sync operation straight-away.
  sendreceive_queue_sync (-1);
}
Пример #7
0
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;
}
Пример #8
0
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;
}
Пример #9
0
// Store updated workspace settings for sending to the cloud.
void workspace_cache_for_cloud (void * webserver_request, bool urls, bool widths, bool heights)
{
#ifdef HAVE_CLIENT
  // For a client, store the setting for sending to the server.
  Webserver_Request * request = (Webserver_Request *) webserver_request;
  if (urls)
    request->database_config_user()->addUpdatedSetting (Sync_Logic::settings_send_workspace_urls);
  if (widths)
    request->database_config_user()->addUpdatedSetting (Sync_Logic::settings_send_workspace_widths);
  if (heights)
    request->database_config_user()->addUpdatedSetting (Sync_Logic::settings_send_workspace_heights);
#else
  (void) webserver_request;
  (void) urls;
  (void) widths;
  (void) heights;
#endif
}
Пример #10
0
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;
}
Пример #11
0
// handleEmailComment - handles an email received from from with subject subject and body body.
// Returns true if the mail was processed, else false.
// The email is considered to have been processed if it comments on an existing Consultation Note.
bool Notes_Logic::handleEmailComment (string from, string subject, string body)
{
  // Check whether the Consultation Notes Identifier in the subject exists in the notes database.
  // The CNID looks like: (CNID123456789)
  size_t pos = subject.find ("(CNID");
  if (pos == string::npos) return false;
  subject = subject.substr (pos + 5);
  pos = subject.find (")");
  if (pos == string::npos) return false;
  subject = subject.substr (0, pos);
  // Webserver request.
  Webserver_Request * request = (Webserver_Request *) webserver_request;
  // At this stage, the subject contains an identifier.
  // Check that the identifier is an existing Consultation Note.
  int identifier = convert_to_int (subject);
  Database_Notes database_notes (webserver_request);
  if (!database_notes.identifierExists (identifier)) return false;
  // Check that the from address of the email belongs to an existing user.
  // Or else use the obfuscated email address as the user name.
  string username;
  from = filter_string_extract_email (from);
  if (request->database_users()->emailExists (from)) {
    username = request->database_users()->getEmailToUser (from);
  } else {
    username = from;
    username = filter_string_str_replace ("@", " ", username);
    username = filter_string_str_replace (".", " ", username);
  }
  // Clean the email's body.
  string year = convert_to_string (filter_date_numerical_year (filter_date_seconds_since_epoch ()));
  string sender = Database_Config_General::getSiteMailName();
  body = filter_string_extract_body (body, year, sender);
  // Remove any new lines from the body. This cleans up the email considerably,
  // because some emails that get posted would otherwise look untidy,
  // when the many new lines take up a lot of space.
  body = filter_string_str_replace ("\n", " ", body);
  // Make comment on the consultation note.
  string sessionuser = request->session_logic ()->currentUser ();
  request->session_logic ()->setUsername (username);
  addComment (identifier, body);
  request->session_logic ()->setUsername (sessionuser);
  // Mail confirmation to the username.
  if (request->database_config_user()->getUserNotifyMeOfMyPosts (username)) {
    Database_Mail database_mail = Database_Mail (webserver_request);
    string subject = translate("Your comment was posted");
    subject.append (" [CNID");
    subject.append (convert_to_string (identifier));
    subject.append ("]");
    database_mail.send (username, subject, body);
  }
  // Log operation.
  Database_Logs::log ("Comment posted: " + body);
  // Job done.
  return true;
}
Пример #12
0
void workspace_create_defaults (void * webserver_request)
{
  Webserver_Request * request = (Webserver_Request *) webserver_request;

  // Save current active desktop.
  string desktop = request->database_config_user()->getActiveWorkspace ();

  // Create or update the default desktops.
  vector <string> names = workspace_get_default_names ();
  for (unsigned int i = 0; i < names.size (); i++) {
    request->database_config_user()->setActiveWorkspace (names [i]);
    int bench = i + 1;
    workspace_set_urls (request, workspace_get_default_urls (bench));
    workspace_set_widths (request, workspace_get_default_widths (bench));
    workspace_set_heights (request, workspace_get_default_heights (bench));
  }

  // Restore current active desktop.
  request->database_config_user()->setActiveWorkspace (desktop);
}
Пример #13
0
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;
}
Пример #14
0
// Copy desktop $source to $destination
void workspace_copy (void * webserver_request, string source, string destination)
{
  Webserver_Request * request = (Webserver_Request *) webserver_request;

  // Save current active desktop.
  string active_desktop = request->database_config_user()->getActiveWorkspace ();
  
  // Copy source desktop to destination.
  request->database_config_user()->setActiveWorkspace (source);
  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);
  request->database_config_user()->setActiveWorkspace (destination);
  workspace_set_urls (webserver_request, urls);
  workspace_set_widths (webserver_request, widths);
  workspace_set_heights (webserver_request, heights);
  workspace_set_entire_width (webserver_request, entire_width);
  
  // Restore current active desktop.
  request->database_config_user()->setActiveWorkspace (active_desktop);
}
Пример #15
0
void demo_create_sample_workbenches (void * webserver_request)
{
  Webserver_Request * request = (Webserver_Request *) webserver_request;
  
  map <int, string> urls;
  map <int, string> widths;
  for (int i = 0; i < 15; i++) {
    string url;
    string width;
    if (i == 0) {
      url = editusfm_index_url ();
      width = "45%";
    }
    if (i == 1) {
      url = resource_index_url ();
      width = "45%";
    }
    urls [i] = url;
    widths [i] = width;
  }
  map <int, string> row_heights = {
    make_pair (0, "90%"),
    make_pair (1, ""),
    make_pair (2, "")
  };

  request->database_config_user()->setActiveWorkbench ("USFM");
  workbench_set_urls (request, urls);
  workbench_set_widths (request, widths);
  workbench_set_heights (request, row_heights);

  urls[0] = edit_index_url ();
  urls[1] = resource_index_url ();

  request->database_config_user()->setActiveWorkbench (demo_workbench ());
  workbench_set_urls (request, urls);
  workbench_set_widths (request, widths);
  workbench_set_heights (request, row_heights);
}
Пример #16
0
// 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;
}
Пример #17
0
// This orders the workspacees.
// It takes the order as in array $workspacees.
void workspace_reorder (void * webserver_request, const vector <string> & workspacees)
{
  // The order of the workspacees is taken from the URLs.
  // Widths and heights are not considered for the order.
  
  Webserver_Request * request = (Webserver_Request *) webserver_request;

  // Retrieve the old order of the workspacees, plus their details.
  string rawvalue = request->database_config_user()->getWorkspaceURLs ();
  vector <string> oldlines = filter_string_explode (rawvalue, '\n');
  
  // Create vector with the sorted workspace definitions.
  vector <string> newlines;
  for (auto & workspace : workspacees) {
    for (auto & line : oldlines) {
      if (line.find (workspace + "_") == 0) {
        newlines.push_back (line);
        line.clear ();
      }
    }
  }
  
  // Add any extra ones.
  for (auto & line : oldlines) {
    if (!line.empty ()) {
      newlines.push_back (line);
    }
  }

  // Save everything.
  rawvalue = filter_string_implode (newlines, "\n");
  request->database_config_user()->setWorkspaceURLs (rawvalue);

  // Schedule for sending to Cloud.
  workspace_cache_for_cloud (request, true, false, false);
}
Пример #18
0
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 (";");
}
Пример #19
0
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;
}
Пример #20
0
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;
}
Пример #21
0
// Returns the names of the available workspacees.
vector <string> workspace_get_names (void * webserver_request)
{
  Webserver_Request * request = (Webserver_Request *) webserver_request;
  vector <string> workspacees;
  // The names and the order of the workspacees is taken from the URLs.
  string rawvalue = request->database_config_user()->getWorkspaceURLs ();
  vector <string> lines = filter_string_explode (rawvalue, '\n');
  for (auto & line : lines) {
    vector <string> bits = filter_string_explode (line, '_');
    if (bits.size() == 3) {
      if (find (workspacees.begin(), workspacees.end(), bits[0]) == workspacees.end()) {
        workspacees.push_back (bits[0]);
      }
    }
  }
  if (workspacees.empty ()) workspacees.push_back (workspace_get_active_name (request));
  return workspacees;
}
Пример #22
0
void workspace_set_values (void * webserver_request, int selector, const map <int, string> & values)
{
  // Store values locally, and for a client, store them also for sending to the server.
  Webserver_Request * request = (Webserver_Request *) webserver_request;
  string workspace = workspace_get_active_name (request);
  string rawvalue;
  if (selector == URLS) rawvalue = request->database_config_user()->getWorkspaceURLs ();
  if (selector == WIDTHS) rawvalue = request->database_config_user()->getWorkspaceWidths ();
  if (selector == HEIGHTS) rawvalue = request->database_config_user()->getWorkspaceHeights ();
  if (selector == ENTIREWIDTH) rawvalue = request->database_config_user()->getEntireWorkspaceWidths ();
  vector <string> currentlines = filter_string_explode (rawvalue, '\n');
  vector <string> newlines;
  for (auto & line : currentlines) {
    if (line.find (workspace + "_") != 0) {
      newlines.push_back (line);
    }
  }
  for (auto & element : values) {
    string line = workspace + "_" + convert_to_string (element.first) + "_" + element.second;
    newlines.push_back (line);
  }
  rawvalue = filter_string_implode (newlines, "\n");
  if (selector == URLS) {
    request->database_config_user()->setWorkspaceURLs (rawvalue);
    workspace_cache_for_cloud (request, true, false, false);
  }
  if (selector == WIDTHS) {
    request->database_config_user()->setWorkspaceWidths (rawvalue);
    workspace_cache_for_cloud (request, false, true, false);
  }
  if (selector == HEIGHTS) {
    request->database_config_user()->setWorkspaceHeights (rawvalue);
    workspace_cache_for_cloud (request, false, false, true);
  }
  if (selector == ENTIREWIDTH) {
    request->database_config_user()->setEntireWorkspaceWidths (rawvalue);
    workspace_cache_for_cloud (request, false, true, false);
  }
}
Пример #23
0
void workspace_delete (void * webserver_request, string workspace)
{
  Webserver_Request * request = (Webserver_Request *) webserver_request;

  string rawvalue;
  vector <string> currentlines;
  vector <string> newlines;
  
  rawvalue = request->database_config_user()->getWorkspaceURLs ();
  currentlines = filter_string_explode (rawvalue, '\n');
  newlines.clear ();
  for (auto & line : currentlines) {
    if (line.find (workspace + "_") != 0) newlines.push_back (line);
  }
  rawvalue = filter_string_implode (newlines, "\n");
  request->database_config_user()->setWorkspaceURLs (rawvalue);
  
  rawvalue = request->database_config_user()->getWorkspaceWidths ();
  currentlines = filter_string_explode (rawvalue, '\n');
  newlines.clear ();
  for (auto & line : currentlines) {
    if (line.find (workspace + "_") != 0) newlines.push_back (line);
  }
  rawvalue = filter_string_implode (newlines, "\n");
  request->database_config_user()->setWorkspaceWidths (rawvalue);
  
  rawvalue = request->database_config_user()->getWorkspaceHeights ();
  currentlines = filter_string_explode (rawvalue, '\n');
  newlines.clear ();
  for (auto & line : currentlines) {
    if (line.find (workspace + "_") != 0) newlines.push_back (line);
  }
  rawvalue = filter_string_implode (newlines, "\n");
  request->database_config_user()->setWorkspaceHeights (rawvalue);
  
  request->database_config_user()->setActiveWorkspace ("");
  
  // For a client, store the setting for sending to the server.
  workspace_cache_for_cloud (request, true, true, true);
}
Пример #24
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 "";
}
Пример #25
0
// handleEmailNew - handles an email received from $from with subject $subject and body $body.
// Returns true if the mail was processed, else false.
// The email is considered to have been processed if it created a new Consultation Note.
bool Notes_Logic::handleEmailNew (string from, string subject, string body)
{
  // Webserver request.
  Webserver_Request * request = (Webserver_Request *) webserver_request;
  // Store the original subject.
  string originalSubject = subject;
  // Check that the subject indicates that a new consultation note is to be created.
  size_t pos = unicode_string_casefold (subject).find ("new note");
  if (pos == string::npos) return false;
  // There is a new note. Remove that bit from the subject.
  if (pos > 0) subject.erase (0, pos + 8);
  // Clean the subject line.
  subject = filter_string_trim (subject);
  subject = filter_string_str_replace (".", " ", subject);
  subject = filter_string_str_replace (":", " ", subject);
  subject = filter_string_str_replace ("   ", " ", subject);
  subject = filter_string_str_replace ("  ", " ", subject);
  // Check that the from address of the email belongs to an existing user.
  from = filter_string_extract_email (from);
  if (!request->database_users()->emailExists (from)) return false;
  string username = request->database_users()->getEmailToUser (from);
  // Extract book, chapter, verse, and note summary from the subject
  int book = -1;
  int chapter = -1;
  int verse = -1;
  string summary;
  vector <string> subjectlines = filter_string_explode (subject, ' ');
  if (!subjectlines.empty()) {
    book = filter_passage_interpret_book (subjectlines[0]);
    subjectlines.erase (subjectlines.begin());
  }
  if (!subjectlines.empty()) {
    chapter = convert_to_int (subjectlines[0]);
    subjectlines.erase (subjectlines.begin());
  }
  if (!subjectlines.empty()) {
    verse = convert_to_int (subjectlines[0]);
    subjectlines.erase (subjectlines.begin());
  }
  summary = filter_string_implode (subjectlines, " ");
  // Check book, chapter, verse, and summary. Give feedback if there's anything wrong.
  string noteCheck;
  if (book <= 0) noteCheck.append (translate("Unknown book"));
  if (chapter < 0) {
    noteCheck.append (" ");
    noteCheck.append (translate("Unknown chapter"));
  }
  if (verse < 0) {
    noteCheck.append (" ");
    noteCheck.append (translate("Unknown verse"));
  }
  if (summary.empty ()) {
    noteCheck.append (" ");
    noteCheck.append (translate("Unknown summary"));
  }
  // Mail user if the note could not be posted.
  Database_Mail database_mail = Database_Mail (webserver_request);
  if (noteCheck != "") {
    subject = translate("Your new note could not be posted");
    database_mail.send (username, subject  + ": " + originalSubject, noteCheck);
    return false;
  }
  // Clean the email's body.
  body = filter_string_extract_body (body);
  // Post the note.
  string sessionuser = request->session_logic()->currentUser ();
  request->session_logic()->setUsername (username);
  Database_Notes database_notes = Database_Notes(webserver_request);
  string bible = request->database_config_user()->getBible ();
  int identifier = database_notes.storeNewNote (bible, book, chapter, verse, summary, body, false);
  handlerNewNote (identifier);
  request->session_logic()->setUsername (sessionuser);
  // Mail confirmation to the username.
  if (request->database_config_user()->getUserNotifyMeOfMyPosts (username)) {
    subject = translate("Your new note was posted");
    database_mail.send (username, subject + ": " + originalSubject, body);
  }
  // Log operation.
  Database_Logs::log ("New note posted : " + body);
  // Job done.
  return true;
}
Пример #26
0
// Cleans and resets the data in the Bibledit installation.
void demo_clean_data ()
{
  Database_Logs::log ("Cleaning up the demo data");

  
  Webserver_Request request;
  
  
  // Set user to the demo credentials (admin) as this is the user who is always logged-in in a demo installation.
  request.session_logic ()->setUsername (session_admin_credentials ());
  
  
  // Delete empty stylesheet that may have been there.
  request.database_styles()->revokeWriteAccess ("", styles_logic_standard_sheet ());
  request.database_styles()->deleteSheet ("");
  styles_sheets_create_all ();
  
  
  // Set the export stylesheet to "Standard" for all Bibles and the admin.
  vector <string> bibles = request.database_bibles()->getBibles ();
  for (auto & bible : bibles) {
    Database_Config_Bible::setExportStylesheet (bible, styles_logic_standard_sheet ());
  }
  request.database_config_user()->setStylesheet (styles_logic_standard_sheet ());
  
  
  // Set the site language to "Default"
  Database_Config_General::setSiteLanguage ("");
  
  
  // Ensure the default users are there.
  map <string, int> users = {
    make_pair ("guest", Filter_Roles::guest ()),
    make_pair ("member", Filter_Roles::member ()),
    make_pair ("consultant", Filter_Roles::consultant ()),
    make_pair ("translator", Filter_Roles::translator ()),
    make_pair ("manager", Filter_Roles::manager ()),
    make_pair (session_admin_credentials (), Filter_Roles::admin ())
  };
  for (auto & element : users) {
    if (!request.database_users ()->usernameExists (element.first)) {
      request.database_users ()->addNewUser(element.first, element.first, element.second, "");
    }
    request.database_users ()->updateUserLevel (element.first, element.second);
  }

  
  // Create / update sample Bible.
  demo_create_sample_bible ();


  // Create sample notes.
  demo_create_sample_notes (&request);
  
  
  // Create samples for the workbenches.
  demo_create_sample_workbenches (&request);
  
  
  // Set navigator to John 3:16.
  Ipc_Focus::set (&request, 43, 3, 16);
  
  
  // Set and/or trim resources to display.
  // Too many resources crash the demo: Limit the amount.
  vector <string> resources = request.database_config_user()->getActiveResources ();
  bool reset_resources = false;
  if (resources.size () > 25) reset_resources = true;
  vector <string> defaults = demo_logic_default_resources ();
  for (auto & name : defaults) {
    if (!in_array (name, resources)) reset_resources = true;
  }
  if (reset_resources) {
    resources = demo_logic_default_resources ();
    request.database_config_user()->setActiveResources (resources);
  }
  
  
  // No flipped basic <> advanded mode.
  request.database_config_user ()->setFlipInterfaceMode (false);
}
Пример #27
0
// This handles notifications for the users
// identifier: the note that is being handled.
// notification: the type of action on the consultation note.
void Notes_Logic::notifyUsers (int identifier, int notification)
{
  // Take no action in client mode.
  if (client_logic_client_enabled ()) return;

  // Data objects.
  Webserver_Request * request = (Webserver_Request *) webserver_request;
  Database_Notes database_notes (webserver_request);
  
  // This note's Bible.
  string bible = database_notes.getBible (identifier);

  // Subscription and assignment not to be used for notes marked for deletion,
  // because marking notes for deletion is nearly the same as deleting them straightaway.
  if (notification != notifyMarkNoteForDeletion) {

    // Whether current user gets subscribed to the note.
    if (request->database_config_user ()->getSubscribeToConsultationNotesEditedByMe ()) {
      database_notes.subscribe (identifier);
    }

    // Users to get subscribed to the note, or to whom the note is to be assigned.
    vector <string> users = request->database_users ()->getUsers ();
    for (const string & user : users) {
      if (access_bible_read (webserver_request, bible, user)) {
        if (request->database_config_user ()->getNotifyUserOfAnyConsultationNotesEdits (user)) {
          database_notes.subscribeUser (identifier, user);
        }
        if (request->database_config_user ()->getUserAssignedToConsultationNotesChanges (user)) {
          database_notes.assignUser (identifier, user);
        }
      }
    }
  }

  // The recipients who receive a notification by email.
  vector <string> recipients;

  // Subscribers who receive email.
  vector <string> subscribers = database_notes.getSubscribers (identifier);
  for (const string & subscriber : subscribers) {
    if (request->database_config_user ()->getUserSubscribedConsultationNoteNotification (subscriber)) {
      recipients.push_back (subscriber);
    }
  }

  // Assignees who receive email.
  vector <string> assignees = database_notes.getAssignees (identifier);
  for (const string & assignee : assignees) {
    if (request->database_config_user ()->getUserAssignedConsultationNoteNotification (assignee)) {
      recipients.push_back (assignee);
    }
  }

  // In case the consultation note is deleted or marked for deletion,
  // notify only the users with this specific notification set.
  if ((notification == notifyNoteDelete) || (notification == notifyMarkNoteForDeletion)) {
    recipients.clear ();
    vector <string> users = request->database_users ()->getUsers ();
    for (const auto & user : users) {
      if (request->database_config_user ()->getUserDeletedConsultationNoteNotification (user)) {
        if (access_bible_read (webserver_request, bible, user)) {
          recipients.push_back (user);
        }
      }
    }
  }

  // Remove duplicates from the recipients.
  set <string> unique (recipients.begin (), recipients.end ());
  recipients.assign (unique.begin (), unique.end());

  // Deal with suppressing mail to the user when he made the update himself.
  string username = request->session_logic ()->currentUser ();
  if (request->database_config_user ()->getUserSuppressMailFromYourUpdatesNotes (username)) {
    recipients.erase (remove (recipients.begin(), recipients.end(), username), recipients.end());
  }

  // Generate the label prefixed to the subject line of the email.
  string label = translate("General");
  switch (notification) {
    case notifyNoteNew             : label = translate("New");                 break;
    case notifyNoteComment         : label = translate("Comment");             break;
    case notifyNoteDelete          : label = translate("Deleted");             break;
    case notifyMarkNoteForDeletion : label = translate("Marked for deletion"); break;
  }

  // Optional postponing sending email.
  bool postpone = false;
  if (notification == notifyNoteNew) {
    if (request->database_config_user ()->getPostponeNewNotesMails ()) {
      postpone = true;
    }
  }

  // Send mail to all recipients.
  emailUsers (identifier, label, recipients, postpone);
}
Пример #28
0
string resource_get (void * webserver_request)
{
    Webserver_Request * request = (Webserver_Request *) webserver_request;


    vector <string> bits;


    string s_resource = request->query["resource"];
    string s_book = request->query["book"];
    string s_chapter = request->query["chapter"];
    string s_verse = request->query["verse"];


    if (!s_resource.empty () && !s_book.empty () && !s_chapter.empty () && !s_verse.empty ()) {


        unsigned int resource = convert_to_int (s_resource);
        int book = convert_to_int (s_book);
        int chapter = convert_to_int (s_chapter);
        int verse = convert_to_int (s_verse);


        // In JavaScript the resource identifier starts at 1 instead of at 0.
        resource--;
        vector <string> resources = request->database_config_user()->getActiveResources ();
        if (resource <= resources.size ()) {
            s_resource = resources [resource];


            // Handle a divider.
            if (resource_logic_is_divider (s_resource)) return resource_logic_get_divider (s_resource);


            string bible = request->database_config_user ()->getBible ();
            string versification = Database_Config_Bible::getVersificationSystem (bible);
            Database_Versifications database_versifications;
            vector <int> chapters = database_versifications.getChapters (versification, book);


            // Whether to add extra verse numbers, for clarity in case of viewing more than one verse.
            bool add_verse_numbers = false;
            int context_before = request->database_config_user ()->getResourceVersesBefore ();
            if (context_before) add_verse_numbers = true;
            int context_after = request->database_config_user ()->getResourceVersesAfter ();
            if (context_after) add_verse_numbers = true;


            // Context before the focused verse.
            vector <int> chapters_before;
            vector <int> verses_before;
            if (context_before > 0) {
                for (int ch = chapter - 1; ch <= chapter; ch++) {
                    if (in_array (ch, chapters)) {
                        vector <int> verses = database_versifications.getVerses (versification, book, ch);
                        for (size_t vs = 0; vs < verses.size (); vs++) {
                            int vs2 = verses [vs];
                            if ((ch < chapter) || (vs2 < verse)) {
                                if (vs2 > 0) {
                                    chapters_before.push_back (ch);
                                    verses_before.push_back (verses[vs]);
                                }
                            }
                        }
                    }
                }
                while ((int)chapters_before.size () > context_before) {
                    chapters_before.erase (chapters_before.begin ());
                    verses_before.erase (verses_before.begin ());
                }
            }
            for (unsigned int i = 0; i < chapters_before.size (); i++) {
                bits.push_back (resource_logic_get_html (request, s_resource, book, chapters_before[i], verses_before[i], add_verse_numbers));
            }


            // Focused verse.
            bits.push_back (resource_logic_get_html (request, s_resource, book, chapter, verse, add_verse_numbers));


            // Context after the focused verse.
            vector <int> chapters_after;
            vector <int> verses_after;
            if (context_after > 0) {
                for (int ch = chapter; ch <= chapter + 1; ch++) {
                    if (in_array (ch, chapters)) {
                        vector <int> verses = database_versifications.getVerses (versification, book, ch);
                        for (size_t vs = 0; vs < verses.size (); vs++) {
                            int vs2 = verses [vs];
                            if ((ch > chapter) || (vs2 > verse)) {
                                if (vs2 > 0) {
                                    chapters_after.push_back (ch);
                                    verses_after.push_back (verses[vs]);
                                }
                            }
                        }
                    }
                }
                while ((int)chapters_after.size () > context_after) {
                    chapters_after.pop_back ();
                    verses_after.pop_back ();
                }
            }
            for (unsigned int i = 0; i < chapters_after.size (); i++) {
                bits.push_back (resource_logic_get_html (request, s_resource, book, chapters_after[i], verses_after[i], add_verse_numbers));
            }
        }
    }


    string page = filter_string_implode (bits, ""); // <br>
    return page;
}
Пример #29
0
string editone_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"]);
  int verse = convert_to_int (request->query ["verse"]);
  string part = request->query ["part"];
  
  string stylesheet = request->database_config_user()->getStylesheet ();

  string chapter_usfm = request->database_bibles()->getChapter (bible, book, chapter);

  string focused_verse_usfm = usfm_get_verse_text (chapter_usfm, verse);
  
  vector <int> verses = usfm_get_verse_numbers (chapter_usfm);
  int highest_verse = 0;
  if (!verses.empty ()) highest_verse = verses.back ();

  string prefix_usfm = usfm_get_verse_range_text (chapter_usfm, 0, verse - 1, focused_verse_usfm);

  string suffix_usfm = usfm_get_verse_range_text (chapter_usfm, verse + 1, highest_verse, focused_verse_usfm);

  // Last paragraph style of the prefix: To be used for the starting visual style for the focused verse.
  string prefix_paragraph_style;
  
  string prefix_html;
  if (!prefix_usfm.empty ()) {
    Editor_Usfm2Html editor_usfm2html;
    editor_usfm2html.load (prefix_usfm);
    editor_usfm2html.stylesheet (stylesheet);
    editor_usfm2html.run ();
    prefix_html = editor_usfm2html.get ();
    prefix_paragraph_style = editor_usfm2html.currentParagraphStyle;
  }
  
  // Last paragraph style of the focused verse: For the starting visual style of the suffix.
  string focused_verse_paragraph_style;
  
  string focused_verse_html;
  if (!focused_verse_usfm.empty ()) {
    Editor_Usfm2Html editor_usfm2html;
    editor_usfm2html.load (focused_verse_usfm);
    editor_usfm2html.stylesheet (stylesheet);
    editor_usfm2html.run ();
    focused_verse_html = editor_usfm2html.get ();
    focused_verse_html = editone_load_remove_id_notes (focused_verse_html);
    focused_verse_paragraph_style = editor_usfm2html.currentParagraphStyle;
  }

  
  // If the first paragraph of the focused verse does not have a paragraph style applied,
  // apply the last paragraph style of the prefix to the first paragraph of the focused verse.
  // For example, html like this:
  // <p><span class="v">7</span><span> </span><span>For Yahweh knows the way of the righteous,</span></p><p class="q2"><span>but the way of the wicked shall perish.</span></p>
  // ... becomes like this:
  // <p class="q1"><span class="v">7</span><span /><span>For Yahweh knows the way of the righteous,</span></p><p class="q2"><span>but the way of the wicked shall perish.</span></p>
  string focused_verse_applied_style;
  if (!focused_verse_html.empty ()) {
    if (!prefix_paragraph_style.empty ()) {
      xml_document document;
      document.load_string (focused_verse_html.c_str(), parse_ws_pcdata_single);
      xml_node p_node = document.first_child ();
      string p_style = p_node.attribute ("class").value ();
      if (p_style.empty ()) {
        p_node.append_attribute ("class") = prefix_paragraph_style.c_str ();
        // Send the applied paragraph style to the browser,
        // for later use when it saves the modified verse text.
        focused_verse_applied_style = prefix_paragraph_style;
      }
      stringstream output;
      document.print (output, "", format_raw);
      focused_verse_html = output.str ();
    }
  }
  
  
  string suffix_html;
  if (!suffix_usfm.empty ()) {
    Editor_Usfm2Html editor_usfm2html;
    editor_usfm2html.load (suffix_usfm);
    editor_usfm2html.stylesheet (stylesheet);
    editor_usfm2html.run ();
    suffix_html = editor_usfm2html.get ();
    suffix_html = editone_load_remove_id_notes (suffix_html);
  }
  
  // If the first paragraph of the suffix does not have a paragraph style applied,
  // apply the last paragraph style of the focused verse to the first paragraph of the suffix.
  // For example, html like this:
  // <p><span class="v">7</span><span> </span><span>For Yahweh knows the way of the righteous,</span></p><p class="q2"><span>but the way of the wicked shall perish.</span></p>
  // ... becomes like this:
  // <p class="q1"><span class="v">7</span><span /><span>For Yahweh knows the way of the righteous,</span></p><p class="q2"><span>but the way of the wicked shall perish.</span></p>
  if (!suffix_html.empty ()) {
    if (!focused_verse_paragraph_style.empty ()) {
      xml_document document;
      document.load_string (suffix_html.c_str(), parse_ws_pcdata_single);
      xml_node p_node = document.first_child ();
      string p_style = p_node.attribute ("class").value ();
      if (p_style.empty ()) {
        p_node.append_attribute ("class") = focused_verse_paragraph_style.c_str ();
      }
      stringstream output;
      document.print (output, "", format_raw);
      suffix_html = output.str ();
    }
  }

  
  string data;
  data.append (focused_verse_applied_style);
  data.append ("#_be_#");
  data.append (prefix_html);
  data.append ("#_be_#");
  data.append (focused_verse_html);
  data.append ("#_be_#");
  data.append (suffix_html);
  
  string user = request->session_logic ()->currentUser ();
  bool write = access_bible_book_write (webserver_request, user, bible, book);
  data = Checksum_Logic::send (data, write);
  
  return data;
}
Пример #30
0
string sync_changes (void * webserver_request)
{
  Webserver_Request * request = (Webserver_Request *) webserver_request;
  Sync_Logic sync_logic = Sync_Logic (webserver_request);
  Database_Modifications database_modifications;

  // Check on the credentials.
  if (!sync_logic.credentials_okay ()) return "";

  // Bail out if the change notifications are not now available to clients.
  if (!config_globals_change_notifications_available) {
    request->response_code = 503;
    return "";
  }
  
  // Client makes a prioritized server call: Record the client's IP address.
  sync_logic.prioritized_ip_address_record ();

  // Get the relevant parameters the client may have POSTed to us, the server.
  string user = hex2bin (request->post ["u"]);
  int action = convert_to_int (request->post ["a"]);
  int id = convert_to_int (request->post ["i"]);

  switch (action) {
    case Sync_Logic::changes_delete_modification:
    {
      // The server deletes the change notification.
      database_modifications.deleteNotification (id);
      Database_Logs::log ("Client deletes change notification from server: " + convert_to_string (id), Filter_Roles::translator ());
      request->database_config_user ()->setChangeNotificationsChecksum ("");
      return "";
    }
    case Sync_Logic::changes_get_checksum:
    {
      // The server responds with the possibly cached total checksum for the user's change notifications.
      string checksum = request->database_config_user ()->getChangeNotificationsChecksum ();
      if (checksum.empty ()) {
        checksum = Sync_Logic::changes_checksum (user);
        request->database_config_user ()->setChangeNotificationsChecksum (checksum);
      }
      return checksum;
    }
    case Sync_Logic::changes_get_identifiers:
    {
      // The server responds with the identifiers of all the user's change notifications.
      vector <int> ids = database_modifications.getNotificationIdentifiers (user, false);
      string response;
      for (auto & id : ids) {
        if (!response.empty ()) response.append ("\n");
        response.append (convert_to_string (id));
      }
      return response;
    }
    case Sync_Logic::changes_get_modification:
    {
      // The server responds with the relevant data of the requested modification.
      vector <string> lines;
      // category
      lines.push_back (database_modifications.getNotificationCategory (id));
      // bible
      lines.push_back (database_modifications.getNotificationBible (id));
      // book
      // chapter
      // verse
      Passage passage = database_modifications.getNotificationPassage (id);
      lines.push_back (convert_to_string (passage.book));
      lines.push_back (convert_to_string (passage.chapter));
      lines.push_back (passage.verse);
      // oldtext
      lines.push_back (database_modifications.getNotificationOldText (id));
      // modification
      lines.push_back (database_modifications.getNotificationModification (id));
      // newtext
      lines.push_back (database_modifications.getNotificationNewText (id));
      // Result.
      return filter_string_implode (lines, "\n");
    }
  }

  
  // Bad request.
  // Delay a while to obstruct a flood of bad requests.
  this_thread::sleep_for (chrono::seconds (1));
  request->response_code = 400;
  return "";
}