示例#1
0
string notes_assign_n (void * webserver_request)
{
  Webserver_Request * request = (Webserver_Request *) webserver_request;
  Database_Notes database_notes (webserver_request);
  Notes_Logic notes_logic = Notes_Logic (webserver_request);
  Database_NoteAssignment database_noteassignment;

  
  string page;
  Assets_Header header = Assets_Header (translate("Assign notes"), request);
  page += header.run();
  Assets_View view;

  
  string user = request->session_logic ()->currentUser ();
 
  
  // Notes can be assigned to the assignees.
  string userblock;
  vector <string> assignees = database_noteassignment.assignees (user);
  for (auto & assignee : assignees) {
    userblock.append ("<li><a href=\"bulk?assign=" + assignee + "\">" + assignee + "</a></li>\n");
  }
  view.set_variable ("userblock", userblock);
  
  
  page += view.render ("notes", "assign-n");
  page += Assets_Page::footer ();
  return page;
}
示例#2
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;
}
示例#3
0
string notes_bible_n (void * webserver_request)
{
  Webserver_Request * request = (Webserver_Request *) webserver_request;
  Database_Notes database_notes (webserver_request);
  Notes_Logic notes_logic = Notes_Logic (webserver_request);

  
  string page;
  Assets_Header header = Assets_Header (translate("Bibles"), request);
  page += header.run ();
  Assets_View view;
  
  
  string bibleblock;
  vector <string> bibles = access_bible_bibles (webserver_request);
  bibles.push_back (notes_logic.generalBibleName ());
  for (auto & bible : bibles) {
    bibleblock.append ("<li><a href=\"bulk?bible=" + bible + "\">" + bible + "</a></li>\n");
  }
  view.set_variable ("bibleblock", bibleblock);
  
  
  page += view.render ("notes", "bible-n");
  page += Assets_Page::footer ();
  return page;
}
示例#4
0
void search_reindex_notes ()
{
  if (!Database_Config_General::getIndexNotes ()) return;
  
  
  // One simultaneous instance.
  if (search_reindex_notes_running) {
    Database_Logs::log ("Still indexing Consultation Notes", Filter_Roles::manager ());
    return;
  }
  search_reindex_notes_running = true;
  
  
  // This does not run as a result of a webserver request, so create one.
  Webserver_Request request;


  // Database.
  Database_Notes database_notes (&request);


  // Set a flag indicating that the notes databases are not available to clients and other parties.
  database_notes.set_availability (false);
  
  
  // Delay shortly to give existing processes a change to complete.
  // Without this delay, "locked database" errors have been seen.
  this_thread::sleep_for (chrono::seconds (1));


  // Check on health of the databases, and optionally recreate them.
  bool recreate = database_notes.checkup ();
  if (recreate) {
    Database_Logs::log ("The Consultation Notes main index was damaged and is being recreated", Filter_Roles::manager ());
  }
  recreate = database_notes.checkup_checksums ();
  if (recreate) {
    Database_Logs::log ("The Consultation Notes checksums database was damaged and is being recreated", Filter_Roles::manager ());
  }
  
  
  // Synchronize the notes databases with the notes on the filesystem,
  // because it may have happened that certain values at certain times 
  // could not be written to the database because of errors. 
  // Then the notes index would not match the notes data.
  // Syncing ensures the index matches the notes data in the filesystem.
  Database_Logs::log ("Updating Consultation Notes databases", Filter_Roles::manager ());
  database_notes.sync ();
  
  
  // Set the availability flag so that clients and other parties access the notes databases again.
  database_notes.set_availability (true);
  
  
  Database_Logs::log ("Updating Consultation Notes databases ready", Filter_Roles::manager ());
  Database_Config_General::setIndexNotes (false);
  search_reindex_notes_running = false;
}
示例#5
0
void Notes_Logic::handlerAddComment (int identifier)
{
  notifyUsers (identifier, notifyNoteComment);
  // If the note status was Done, and a comment is added, mark it Reopened.
  Database_Notes database_notes (webserver_request);
  string status = database_notes.getRawStatus (identifier);
  if (status == "Done") {
    database_notes.setStatus (identifier, "Reopened");
  }
}
示例#6
0
// Create sample notes.
void demo_create_sample_notes (void * webserver_request)
{
  Database_Notes database_notes (webserver_request);
  vector <int> identifiers = database_notes.getIdentifiers ();
  if (identifiers.size () < 10) {
    for (size_t i = 1; i <= 10; i++) {
      database_notes.storeNewNote (demo_sample_bible_name (), i, i, i, "Sample Note " + convert_to_string (i), "Sample Contents for note " + convert_to_string (i), false);
    }
  }
}
示例#7
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;
}
示例#8
0
void Notes_Logic::unmarkForDeletion (int identifier)
{
  Database_Notes database_notes (webserver_request);
  database_notes.unmarkForDeletion (identifier);
  if (client_logic_client_enabled ()) {
    // Client: record the action in the database.
    string user = ((Webserver_Request *) webserver_request)->session_logic ()->currentUser ();
    Database_NoteActions database_noteactions = Database_NoteActions ();
    database_noteactions.record (user, identifier, Sync_Logic::notes_put_unmark_delete, "");
  } else {
    // Server: do nothing extra.
  }
}
示例#9
0
// Sets the bible for note identifier.
void Notes_Logic::setBible (int identifier, const string& bible)
{
  Database_Notes database_notes (webserver_request);
  database_notes.setBible (identifier, bible);
  if (client_logic_client_enabled ()) {
    // Client: record the action in the database.
    string user = ((Webserver_Request *) webserver_request)->session_logic ()->currentUser ();
    Database_NoteActions database_noteactions = Database_NoteActions ();
    database_noteactions.record (user, identifier, Sync_Logic::notes_put_bible, "");
  } else {
    // Server: do nothing extra.
  }
}
示例#10
0
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);
}
示例#11
0
void Notes_Logic::assignUser (int identifier, const string& user)
{
  Database_Notes database_notes (webserver_request);
  if (client_logic_client_enabled ()) {
    // Client: record the action in the database.
    string myuser = ((Webserver_Request *) webserver_request)->session_logic ()->currentUser ();
    Database_NoteActions database_noteactions;
    database_noteactions.record (myuser, identifier, Sync_Logic::notes_put_assign, user);
  } else {
    // Server: do the notifications.
    // Assign logic comes before the database action in this particular case.
    handlerAssignNote (identifier, user);
  }
  database_notes.assignUser (identifier, user);
}
示例#12
0
void Notes_Logic::erase (int identifier)
{
  Database_Notes database_notes (webserver_request);
  if (client_logic_client_enabled ()) {
    // Client: record the action in the database.
    string user = ((Webserver_Request *) webserver_request)->session_logic ()->currentUser ();
    Database_NoteActions database_noteactions = Database_NoteActions ();
    database_noteactions.record (user, identifier, Sync_Logic::notes_put_delete, "");
  } else {
    // Server: notification.
    handlerDeleteNote (identifier);
  }
  trash_consultation_note (webserver_request, identifier);
  database_notes.erase (identifier);
}
示例#13
0
void Notes_Logic::handlerAssignNote (int identifier, const string& user)
{
  // Take no action in client mode.
  if (client_logic_client_enabled ()) return;

  Database_Config_User database_config_user = Database_Config_User (webserver_request);
  if (database_config_user.getUserAssignedConsultationNoteNotification (user)) {
    // Only email the user if the user was not yet assigned this note.
    Database_Notes database_notes (webserver_request);
    vector <string> assignees = database_notes.getAssignees (identifier);
    if (find (assignees.begin(), assignees.end(), user) == assignees.end()) {
      emailUsers (identifier, translate("Assigned"), {user}, false);
    }
  }
}
示例#14
0
string notes_assign_1 (void * webserver_request)
{
  Webserver_Request * request = (Webserver_Request *) webserver_request;
  Database_Notes database_notes (webserver_request);
  Notes_Logic notes_logic = Notes_Logic (webserver_request);
  Database_NoteAssignment database_noteassignment;
  
  
  string page;
  Assets_Header header = Assets_Header (translate("Assign note"), request);
  page += header.run();
  Assets_View view;
  string success, error;

  
  string user = request->session_logic ()->currentUser ();

  
  int id = convert_to_int (request->query ["id"]);
  view.set_variable ("id", convert_to_string (id));

  
  if (request->query.count ("assign")) {
    string assign = request->query ["assign"];
    if (database_noteassignment.exists (user, assign)) {
      notes_logic.assignUser (id, assign);
    }
    redirect_browser (request, notes_actions_url () + "?id=" + convert_to_string (id));
    return "";
  }


  // Note assignees.
  string userblock;
  vector <string> assignees = database_noteassignment.assignees (user);
  for (auto & assignee : assignees) {
    userblock.append ("<li><a href=\"assign-1?id=" + convert_to_string (id) + "&assign=" + assignee + "\">" + assignee + "</a></li>\n");
  }
  view.set_variable ("userblock", userblock);
  
  
  view.set_variable ("success", success);
  view.set_variable ("error", error);
  page += view.render ("notes", "assign-1");
  page += Assets_Page::footer ();
  return page;
}
示例#15
0
// Add a comment to an exiting note identified by identifier.
void Notes_Logic::addComment (int identifier, const string& comment)
{
  // Do nothing if there was no content.
  if (comment == "") return;

  Database_Notes database_notes (webserver_request);
  database_notes.addComment (identifier, comment);
  if (client_logic_client_enabled ()) {
    // Client: record the action in the database.
    string user = ((Webserver_Request *) webserver_request)->session_logic ()->currentUser ();
    Database_NoteActions database_noteactions = Database_NoteActions ();
    database_noteactions.record (user, identifier, Sync_Logic::notes_put_comment, comment);
  } else {
    // Server: do the notifications.
    handlerAddComment (identifier);
  }
}
示例#16
0
string public_comment (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("Feedback"), request);
  page += header.run();
  Assets_View view;
  
  
  int id = convert_to_int (request->query ["id"]);
  view.set_variable ("id", convert_to_string (id));
  
  
  if (request->post.count ("submit")) {
    string comment = filter_string_trim (request->post ["comment"]);
    notes_logic.addComment (id, comment);
    redirect_browser (request, public_note_url () + "?id=" + convert_to_string (id));
    return "";
  }
  
  
  if (request->post.count ("cancel")) {
    redirect_browser (request, public_note_url () + "?id=" + convert_to_string (id));
    return "";
  }
  
  
  string summary = database_notes.getSummary (id);
  view.set_variable ("summary", summary);
  
  
  string content = database_notes.getContents (id);
  view.set_variable ("content", content);
  
  
  page += view.render ("public", "comment");
  page += Assets_Page::footer ();
  return page;
}
示例#17
0
string notes_severity_1 (void * webserver_request)
{
    Webserver_Request * request = (Webserver_Request *) webserver_request;
    Database_Notes database_notes (webserver_request);
    Notes_Logic notes_logic = Notes_Logic (webserver_request);


    string page;
    Assets_Header header = Assets_Header (translate("Severity"), request);
    page += header.run();
    Assets_View view;
    string success, error;


    int id = convert_to_int (request->query ["id"]);
    view.set_variable ("id", convert_to_string (id));


    if (request->query.count ("severity")) {
        int severity = convert_to_int (request->query["severity"]);
        notes_logic.setRawSeverity (id, severity);
        redirect_browser (request, notes_actions_url () + "?id=" + convert_to_string (id));
        return "";
    }


    string severityblock;
    vector <Database_Notes_Text> severities = database_notes.getPossibleSeverities ();
    for (auto & severity : severities) {
        severityblock.append ("<li><a href=\"severity-1?id=" + convert_to_string (id) + "&severity=" + severity.raw + "\">" + severity.localized + "</a></li>\n");
    }
    view.set_variable ("severityblock", severityblock);


    view.set_variable ("success", success);
    view.set_variable ("error", error);
    page += view.render ("notes", "severity-1");
    page += Assets_Page::footer ();
    return page;
}
示例#18
0
// Create a consultation note.
// $bible: The notes's Bible.
// $book, $chapter, $verse: The note's passage.
// $summary: The note's summary.
// $contents: The note's contents.
// $raw: Import $contents as it is.
// It returns the $identifier of this new note.
int Notes_Logic::createNote (string bible, int book, int chapter, int verse, string summary, string contents, bool raw)
{
  summary = filter_string_str_replace ("\n", "", summary);
  Database_Notes database_notes (webserver_request);
  int note_id = database_notes.storeNewNote (bible, book, chapter, verse, summary, contents, raw);
  if (client_logic_client_enabled ()) {
    // Client: record the action in the database.
    Database_NoteActions database_noteactions;
    Webserver_Request * request = (Webserver_Request *) webserver_request;
    database_noteactions.record (request->session_logic()->currentUser (), note_id, Sync_Logic::notes_put_create_initiate, "");
    database_noteactions.record (request->session_logic()->currentUser (), note_id, Sync_Logic::notes_put_summary, "");
    // The contents to submit to the server, take it from the database, as it was updated in the logic above.
    database_noteactions.record (request->session_logic()->currentUser (), note_id, Sync_Logic::notes_put_contents, database_notes.getContents (note_id));
    database_noteactions.record (request->session_logic()->currentUser (), note_id, Sync_Logic::notes_put_bible, "");
    database_noteactions.record (request->session_logic()->currentUser (), note_id, Sync_Logic::notes_put_passages, "");
    database_noteactions.record (request->session_logic()->currentUser (), note_id, Sync_Logic::notes_put_create_complete, "");
  } else {
    // Server: do the notifications.
    handlerNewNote (note_id);
  }
  return note_id;
}
示例#19
0
void statistics_statistics ()
{
  Webserver_Request request;
  Database_Mail database_mail = Database_Mail (&request);
  Database_Modifications database_modifications;
  Database_Notes database_notes (&request);
  
  
  Database_Logs::log (translate("Sending statistics"), Filter_Roles::manager ());

  
  string siteUrl = config_logic_site_url ();
  
  
  vector <string> bibles = request.database_bibles()->getBibles ();
  
  
  vector <string> users = request.database_users ()->getUsers ();
  for (auto & user : users) {
    
    
    string subject = "Bibledit " + translate("statistics");
    vector <string> body;
    
    
    if (request.database_config_user()->getUserPendingChangesNotification (user)) {
      vector <int> ids = database_modifications.getNotificationIdentifiers (user);
      body.push_back ("<p><a href=\"" + siteUrl + changes_changes_url () + "\">" + translate("Number of change notifications") + "</a>: " + convert_to_string (ids.size()) + "</p>\n");
    }
    
    
    if (request.database_config_user()->getUserAssignedNotesStatisticsNotification (user)) {
      vector <int> ids = database_notes.selectNotes (
                                                     bibles, // Bibles.
                                                     0,      // Book
                                                     0,      // Chapter
                                                     0,      // Verse
                                                     3,      // Passage selector.
                                                     0,      // Edit selector.
                                                     0,      // Non-edit selector.
                                                     "",     // Status selector.
                                                     "",     // Bible selector.
                                                     user,   // Assignment selector.
                                                     0,      // Subscription selector.
                                                     -1,     // Severity selector.
                                                     0,      // Text selector.
                                                     "",     // Search text.
                                                     -1);     // Limit.
      body.push_back ("<p><a href=\"" + siteUrl + notes_index_url () + "?presetselection=assigned\">" + translate("Number of consultation notes assigned to you awaiting your response") + "</a>: " + convert_to_string (ids.size ()) + "</p>\n");
    }
    
    
    if (request.database_config_user()->getUserSubscribedNotesStatisticsNotification (user)) {
      body.push_back ("<p>" + translate("Number of consultation notes you are subscribed to") + ":</p>\n");
      body.push_back ("<ul>\n");
      request.session_logic ()->setUsername (user);
      
      vector <int> ids = database_notes.selectNotes (
                                                     bibles, // Bible.
                                                     0,      // Book
                                                     0,      // Chapter
                                                     0,      // Verse
                                                     3,      // Passage selector.
                                                     0,      // Edit selector.
                                                     0,      // Non-edit selector.
                                                     "",     // Status selector.
                                                     "",     // Bible selector.
                                                     "",     // Assignment selector.
                                                     1,      // Subscription selector.
                                                     -1,     // Severity selector.
                                                     0,      // Text selector.
                                                     "",     // Search text.
                                                     -1);     // Limit.
      body.push_back ("<li><a href=\"" + siteUrl + notes_index_url () + "?presetselection=subscribed\">" + translate("Total") + "</a>: " + convert_to_string (ids.size ()) + "</li>\n");
      ids = database_notes.selectNotes (
                                                     bibles, // Bible.
                                                     0,      // Book
                                                     0,      // Chapter
                                                     0,      // Verse
                                                     3,      // Passage selector.
                                                     0,      // Edit selector.
                                                     1,      // Non-edit selector.
                                                     "",     // Status selector.
                                                     "",     // Bible selector.
                                                     "",     // Assignment selector.
                                                     1,      // Subscription selector.
                                                     -1,     // Severity selector.
                                                     0,      // Text selector.
                                                     "",     // Search text.
                                                     -1);     // Limit.
      body.push_back ("<li><a href=\"" + siteUrl + notes_index_url () + "?presetselection=subscribeddayidle\">" + translate("Inactive for a day") + "</a>: " + convert_to_string (ids.size ()) + "</li>\n");
      ids = database_notes.selectNotes (
                                                     bibles, // Bible.
                                                     0,      // Book
                                                     0,      // Chapter
                                                     0,      // Verse
                                                     3,      // Passage selector.
                                                     0,      // Edit selector.
                                                     3,      // Non-edit selector.
                                                     "",     // Status selector.
                                                     "",     // Bible selector.
                                                     "",     // Assignment selector.
                                                     1,      // Subscription selector.
                                                     -1,     // Severity selector.
                                                     0,      // Text selector.
                                                     "",     // Search text.
                                                     -1);     // Limit.
      body.push_back ("<li><a href=\"" + siteUrl + notes_index_url () + "?presetselection=subscribedweekidle\">" + translate("Inactive for a week") + "</a>: " + convert_to_string (ids.size ()) + "</li>\n");
      body.push_back ("</ul>\n");
      request.session_logic ()->setUsername ("");
    }
    
    
    if (!body.empty ()) {
      string mailbody = filter_string_implode (body, "\n");
      database_mail.send (user, subject, mailbody);
    }
  }
}
示例#20
0
string notes_index (void * webserver_request)
{
  Webserver_Request * request = (Webserver_Request *) webserver_request;
  Database_Notes database_notes (webserver_request);
  
  string page;
  
  Assets_Header header = Assets_Header (translate("Consultation Notes"), request);
  header.setNavigator ();
  header.addBreadCrumb (menu_logic_translate_menu (), menu_logic_translate_text ());
  page = header.run();
  
  Assets_View view;
  string error;
  string success;

  // Presets for notes selectors.
  // This is for the daily statistics and the workspace.
  if (request->query.count ("presetselection")) {
    request->database_config_user()->setConsultationNotesPassageSelector (3);
    request->database_config_user()->setConsultationNotesEditSelector (0);
    request->database_config_user()->setConsultationNotesNonEditSelector (0);
    request->database_config_user()->setConsultationNotesStatusSelector ("");
    request->database_config_user()->setConsultationNotesBibleSelector ("");
    request->database_config_user()->setConsultationNotesAssignmentSelector ("");
    request->database_config_user()->setConsultationNotesSubscriptionSelector (0);
    request->database_config_user()->setConsultationNotesSeveritySelector (-1);
    request->database_config_user()->setConsultationNotesTextSelector (0);
    string preset_selector = request->query ["presetselection"];
    if (preset_selector == "assigned") {
      request->database_config_user()->setConsultationNotesAssignmentSelector (request->session_logic()->currentUser ());
    }
    if (preset_selector == "subscribed") {
      request->database_config_user()->setConsultationNotesSubscriptionSelector (1);
    }
    if (preset_selector == "subscribeddayidle") {
      request->database_config_user()->setConsultationNotesSubscriptionSelector (1);
      request->database_config_user()->setConsultationNotesNonEditSelector (1);
    }
    if (preset_selector == "subscribedweekidle") {
      request->database_config_user()->setConsultationNotesSubscriptionSelector (1);
      request->database_config_user()->setConsultationNotesNonEditSelector (3);
    }
    if (preset_selector == "forverse") {
      request->database_config_user()->setConsultationNotesPassageSelector (0);
    }
  }

  int level = request->session_logic ()->currentLevel ();
  // Manager roles and higher can do mass updates on the notes.
  if (level >= Filter_Roles::manager ()) {
    // No mass updates in basic mode.
    if (!config_logic_basic_mode (webserver_request)) {
      view.enable_zone ("update");
    }
  }
  
  // Whether the user can create a new note.
  if (access_logic_privilege_create_comment_notes (webserver_request)) {
    view.enable_zone ("create");
  }
  
  page += view.render ("notes", "index");
  
  page += Assets_Page::footer ();
  
  return page;
}
示例#21
0
// 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);
    }
  }
}
示例#22
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);
}
示例#23
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;
}
示例#24
0
string workbench_index (void * webserver_request)
{
  Webserver_Request * request = (Webserver_Request *) webserver_request;
  vector <string> desktops = workbench_get_names (request);

  
  // Set the requested desktop as the active one.
  if (request->query.count ("bench")) {
    unsigned int bench = convert_to_int (request->query ["bench"]);
    if (bench < desktops.size ()) {
      string workbench = desktops [bench];
      request->database_config_user()->setActiveWorkbench (workbench);
    }
  }
  
  
  // Check that the active desktop exists, else set the first available desktop as the active one.
  {
    string desktop = request->database_config_user ()->getActiveWorkbench ();
    if (!in_array (desktop, desktops)) {
      if (!desktops.empty ()) {
        request->database_config_user ()->setActiveWorkbench (desktops [0]);
      }
    }
  }
  
  
  // Create default set of desktops if there are none.
  bool create = desktops.empty ();
  if (!create) {
    create = (desktops [0] == workbench_get_default_name ());
  }
  if (create) {
    workbench_create_defaults (webserver_request);
  }

  
  // In case the desktop is opened from a consultation note email,
  // read the note, and set the active passage to the passage the note refers to.
  int noteid = convert_to_int (request->query ["note"]);
  if (noteid) {
    Database_Notes database_notes (webserver_request);
    vector <Passage> passages = database_notes.getPassages (noteid);
    if (!passages.empty ()) {
      Ipc_Focus::set (webserver_request, passages[0].book, passages[0].chapter, convert_to_int (passages[0].verse));
      Navigation_Passage::recordHistory (webserver_request, passages[0].book, passages[0].chapter, convert_to_int (passages[0].verse));
    }
  }
  
  
  string page;
  Assets_Header header = Assets_Header (translate("Desktop"), request);
  header.setNavigator ();
  header.setFadingMenu (menu_logic_desktop_category (webserver_request));
  page = header.run ();
  Assets_View view;

  
  map <int, string> urls = workbench_get_urls (request, true);
  map <int, string> widths = workbench_get_widths (request);
  for (unsigned int key = 0; key < 15; key++) {
    string url = urls [key];
    string width = widths [key];
    int row = round (key / 5) + 1;
    int column = key % 5 + 1;
    string variable = "url" + convert_to_string (row) + convert_to_string (column);
    view.set_variable (variable, url);
    variable = "width" + convert_to_string (row) + convert_to_string (column);
    view.set_variable (variable, width);
    if (convert_to_int (width) > 0) view.enable_zone (variable);
  }
  
  
  map <int, string> heights = workbench_get_heights (request);
  for (unsigned int key = 0; key < 3; key++) {
    string height = heights [key];
    int row = key + 1;
    string variable = "height" + convert_to_string (row);
    view.set_variable (variable, height);
    if (convert_to_int (height) > 0) view.enable_zone (variable);
  }
  
  
  string workbenchwidth = workbench_get_entire_width (request);
  if (!workbenchwidth.empty ()) {
    workbenchwidth.insert (0, "width: ");
    workbenchwidth.append (";");
  }
  view.set_variable ("workbenchwidth", workbenchwidth);
  
  
  // The rendered template disables framekillers through the "sandbox" attribute on the iframe elements.
  page += view.render ("workbench", "index");
  page += Assets_Page::footer ();
  return page;
}
示例#25
0
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;
}