otsdaq-utilities  3.02.00
LogbookSupervisor.cc
1 #include "otsdaq-utilities/Logbook/LogbookSupervisor.h"
2 // #include "otsdaq/MessageFacility/MessageFacility.h"
3 // #include "otsdaq/Macros/CoutMacros.h"
4 // #include "otsdaq/CgiDataUtilities/CgiDataUtilities.h"
5 // #include "otsdaq/XmlUtilities/HttpXmlDocument.h"
6 // #include "otsdaq/SOAPUtilities/SOAPUtilities.h"
7 // #include "otsdaq/SOAPUtilities/SOAPParameters.h"
8 //
9 // #include <xdaq/NamespaceURI.h>
10 //
11 // #include <iostream>
12 // #include <fstream>
13 // #include <string>
14 #include <dirent.h> //for DIR
15 #include <sys/stat.h> //for mkdir
16 // #include <thread> // std::thread
17 
18 using namespace ots;
19 
20 const std::string LOGBOOK_PATH = __ENV__("LOGBOOK_DATA_PATH") + std::string("/");
21 #define LOGBOOK_CATEGORY_LIST_PATH LOGBOOK_PATH + "category_list.xml"
22 #define LOGBOOK_CATEGORY_DIR_PREFACE "log_"
23 #define LOGBOOK_UPLOADS_PATH "uploads/" // within category directory
24 #define LOGBOOK_LOGBOOKS_PATH "logbooks/"
25 #define LOGBOOK_PREVIEWS_PATH "previews/"
26 #define LOGBOOK_FILE_PREFACE "entries_"
27 #define LOGBOOK_FILE_EXTENSION ".xml"
28 
29 #define ACTIVE_CATEGORY_PATH LOGBOOK_PATH + "active_category.txt"
30 #define REMOVE_CATEGORY_LOG_PATH LOGBOOK_PATH + "removed_categories.log"
31 
32 #define XML_ADMIN_STATUS "logbook_admin_status"
33 #define XML_STATUS "logbook_status"
34 #define XML_MOST_RECENT_DAY "most_recent_day"
35 #define XML_CATEGORY_ROOT "categories"
36 #define XML_CATEGORY "category"
37 #define XML_ACTIVE_CATEGORY "active_category"
38 #define XML_CATEGORY_CREATE "create_time"
39 #define XML_CATEGORY_CREATOR "creator"
40 
41 #define XML_LOGBOOK_ENTRY "logbook_entry"
42 #define XML_LOGBOOK_ENTRY_SUBJECT "logbook_entry_subject"
43 #define XML_LOGBOOK_ENTRY_TEXT "logbook_entry_text"
44 #define XML_LOGBOOK_ENTRY_FILE "logbook_entry_file"
45 #define XML_LOGBOOK_ENTRY_TIME "logbook_entry_time"
46 #define XML_LOGBOOK_ENTRY_CREATOR "logbook_entry_creator"
47 #define XML_LOGBOOK_ENTRY_HIDDEN "logbook_entry_hidden"
48 #define XML_LOGBOOK_ENTRY_HIDER "logbook_entry_hider"
49 #define XML_LOGBOOK_ENTRY_HIDDEN_TIME "logbook_entry_hidden_time"
50 
51 #define XML_PREVIEW_INDEX "preview_index"
52 #define LOGBOOK_PREVIEW_FILE "preview.xml"
53 #define LOGBOOK_PREVIEW_UPLOAD_PREFACE "upload_"
54 
55 XDAQ_INSTANTIATOR_IMPL(LogbookSupervisor)
56 
57 #undef __MF_SUBJECT__
58 #define __MF_SUBJECT__ "Logbook"
59 
60 //==============================================================================
63 int sendmail(const char* to, const char* from, const char* subject, const char* message)
64 {
65  int retval = -1;
66  FILE* mailpipe = popen("/usr/lib/sendmail -t", "w");
67  if(mailpipe != NULL)
68  {
69  fprintf(mailpipe, "To: %s\n", to);
70  fprintf(mailpipe, "From: %s\n", from);
71  fprintf(mailpipe, "Subject: %s\n\n", subject);
72  fwrite(message, 1, strlen(message), mailpipe);
73  fwrite(".\n", 1, 2, mailpipe);
74  pclose(mailpipe);
75  retval = 0;
76  }
77  else
78  {
79  perror("Failed to invoke sendmail");
80  }
81  return retval;
82 }
83 
84 //==============================================================================
85 LogbookSupervisor::LogbookSupervisor(xdaq::ApplicationStub* stub)
86  : CoreSupervisorBase(stub)
87  , allowedFileUploadTypes_({"image/png",
88  "image/jpeg",
89  "image/gif",
90  "image/bmp",
91  "application/pdf",
92  "application/zip",
93  "text/plain"}) // init allowed file upload types
94  , matchingFileUploadTypes_(
95  {"png", "jpeg", "gif", "bmp", "pdf", "zip", "txt"}) // init allowed file upload
96  // types
97 {
98  INIT_MF("." /*directory used is USER_DATA/LOG/.*/);
99 
100  // xgi::bind (this, &LogbookSupervisor::Default, "Default" );
101  // xgi::bind (this, &LogbookSupervisor::Log, "Log" );
102  // xgi::bind (this, &LogbookSupervisor::LogImage, "LogImage" );
103  // xgi::bind (this, &LogbookSupervisor::LogReport, "LogReport" );
104 
105  xoap::bind(
106  this, &LogbookSupervisor::MakeSystemLogEntry, "MakeSystemLogEntry", XDAQ_NS_URI);
107 
108  init();
109 
110  // TODO allow admins to subscribe to active category alerts using System messages
111  // (and email)
112 } // end constructor()
113 
114 //==============================================================================
115 LogbookSupervisor::~LogbookSupervisor(void) { destroy(); }
116 
117 //==============================================================================
118 void LogbookSupervisor::init(void)
119 {
120  // called by constructor
121  // allSupervisorInfo_.init(getApplicationContext());
122 
123  if(1) // check if LOGBOOK_PATH and subpaths event exist?! (if not, attempt to create)
124  {
125  std::string path = LOGBOOK_PATH;
126  DIR* dir = opendir(path.c_str());
127  if(dir)
128  closedir(dir);
129  else if(-1 == mkdir(path.c_str(), 0755))
130  {
131  // lets create the service folder (for first time)
132  std::stringstream ss;
133  ss << __COUT_HDR_FL__ << "Service directory creation failed: " << path
134  << std::endl;
135  __SS_THROW__;
136  }
137 
138  path = LOGBOOK_PATH + LOGBOOK_UPLOADS_PATH;
139  dir = opendir(path.c_str());
140  if(dir)
141  closedir(dir);
142  else if(-1 == mkdir((path).c_str(), 0755))
143  {
144  // lets create the service folder (for first time)
145  __SS__ << "Service directory creation failed: " << path << std::endl;
146  __SS_THROW__;
147  }
148 
149  path = LOGBOOK_PATH + LOGBOOK_LOGBOOKS_PATH;
150  dir = opendir(path.c_str());
151  if(dir)
152  closedir(dir);
153  else if(-1 == mkdir(path.c_str(), 0755))
154  {
155  // lets create the service folder (for first time)
156  __SS__ << "Service directory creation failed: " << path << std::endl;
157  __SS_THROW__;
158  }
159  }
160 
161  getActiveCategory(); // init active category
162  __COUT__ << "Active Category is " << activeCategory_ << std::endl;
163  mostRecentDayIndex_ = 0;
164 } //end init()
165 
166 //==============================================================================
167 void LogbookSupervisor::destroy(void)
168 {
169  // called by destructor
170 } //end destroy()
171 
172 //==============================================================================
173 void LogbookSupervisor::defaultPage(xgi::Input* /*in*/, xgi::Output* out)
174 {
175  __COUT__ << " active category " << activeCategory_ << std::endl;
176  *out << "<!DOCTYPE HTML><html lang='en'><frameset col='100%' row='100%'><frame "
177  "src='/WebPath/html/Logbook.html?urn="
178  << this->getApplicationDescriptor()->getLocalId()
179  << "&active_category=" << activeCategory_ << "'></frameset></html>";
180 } //end defaultPage()
181 
182 //==============================================================================
187 {
188  CorePropertySupervisorBase::setSupervisorProperty(
189  CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.UserPermissionsThreshold,
190  std::string() +
191  "*=1 | CreateCategory=-1 | RemoveCategory=-1 | GetCategoryListAdmin=-1 "
192  "| SetActiveCategory=-1" +
193  " | AdminRemoveRestoreEntry=-1");
194 } //end setSupervisorPropertyDefaults()
195 
196 //==============================================================================
200 {
201  CorePropertySupervisorBase::setSupervisorProperty(
202  CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.AutomatedRequestTypes,
203  "RefreshLogbook");
204  CorePropertySupervisorBase::setSupervisorProperty(
205  CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.NonXMLRequestTypes,
206  "LogImage | LogReport");
207  CorePropertySupervisorBase::setSupervisorProperty(
208  CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.RequireUserLockRequestTypes,
209  "CreateCategory | RemoveCategory | PreviewEntry | AdminRemoveRestoreEntry");
210 } //end forceSupervisorPropertyValues()
211 
212 //==============================================================================
216 void LogbookSupervisor::request(const std::string& requestType,
217  cgicc::Cgicc& cgiIn,
218  HttpXmlDocument& xmlOut,
219  const WebUsers::RequestUserInfo& userInfo)
220 {
221  __COUTTV__(requestType);
222 
223  // Commands
224  // CreateCategory
225  // RemoveCategory
226  // GetCategoryList
227  // SetActiveCategory
228  // RefreshLogbook
229  // PreviewEntry
230  // ApproveEntry
231  // AdminRemoveRestoreEntry
232 
233  //
234  // cgicc::Cgicc cgiIn(in);
235  // std::string requestType;
236  // if((requestType = CgiDataUtilities::postData(cgiIn,"RequestType")) == "")
237  // requestType = cgiIn("RequestType"); //get command from form, if PreviewEntry
238  //
239  // __COUT__ << "requestType " << requestType << " files: " << cgiIn.getFiles().size()
240  //<< std::endl;
241  //
242 
243  // to report to logbook admin status use
244  // xmlOut.addTextElementToData(XML_ADMIN_STATUS,tempStr);
245 
246  if(requestType == "CreateCategory")
247  {
248  // check that category directory does not exist, and it is not in xml list
249  // create category
250  // create directory
251  // add to categories list
252  //
253  // if(userPermissions < ADMIN_PERMISSIONS_THRESHOLD)
254  // {
255  // xmlOut.addTextElementToData(XML_ADMIN_STATUS,"Error - Insufficient
256  // permissions."); goto CLEANUP;
257  // }
258  //
259  // //user is admin
260  //
261  // __COUT__ << "Admin" << std::endl;
262 
263  // get creator name
264  std::string creator = userInfo.username_;
265 
266  createCategory(CgiDataUtilities::postData(cgiIn, "Category"), creator, &xmlOut);
267 
268  __COUT__ << "Created" << std::endl;
269  }
270  else if(requestType == "RemoveCategory")
271  {
272  // remove from xml list, but do not remove directory (requires manual delete so
273  // mistakes aren't made)
274  //
275  // if(userPermissions < ADMIN_PERMISSIONS_THRESHOLD)
276  // {
277  // xmlOut.addTextElementToData(XML_ADMIN_STATUS,"Error - Insufficient
278  // permissions."); goto CLEANUP;
279  // }
280 
281  // get remover name
282  std::string remover = userInfo.username_;
283  removeCategory(CgiDataUtilities::postData(cgiIn, "Category"), remover, &xmlOut);
284  }
285  else if(requestType == "GetCategoryList")
286  {
287  // remove from xml list, but do not remove directory (requires manual delete so
288  // mistakes aren't made)
289  if(userInfo.permissionLevel_ >=
291  "GetCategoryListAdmin"))
292  {
293  xmlOut.addTextElementToData("is_admin", "0"); // indicate not an admin
294  return;
295  }
296  // else
297 
298  xmlOut.addTextElementToData("is_admin", "1"); // indicate not an admin
299  getCategories(&xmlOut);
300  }
301  else if(requestType == "SetActiveCategory")
302  {
303  // check that category exists
304  // set active category
305 
306  // if(userPermissions < ADMIN_PERMISSIONS_THRESHOLD)
307  // {
308  // xmlOut.addTextElementToData(XML_ADMIN_STATUS,"Error - Insufficient
309  // permissions."); goto CLEANUP;
310  // }
311 
312  webUserSetActiveCategory(CgiDataUtilities::postData(cgiIn, "Category"), &xmlOut);
313  }
314  else if(requestType == "RefreshLogbook")
315  {
316  // returns logbook for currently active category based on date and duration
317  // parameters
318 
319  std::string Date = CgiDataUtilities::postData(cgiIn, "Date");
320  uint32_t Duration = CgiDataUtilities::postDataAsInt(cgiIn, "Duration");
321 
322  time_t date;
323  sscanf(Date.c_str(), "%li", &date); // scan for unsigned long
324 
325  __COUT__ << "date " << date << " duration " << Duration << std::endl;
326  std::stringstream str;
327  refreshLogbook(date, Duration, &xmlOut, (std::ostringstream*)&str);
328  __COUT__ << str.str() << std::endl;
329  }
330  else if(requestType == "PreviewEntry")
331  {
332  // cleanup temporary folder
333  // NOTE: all input parameters for PreviewEntry will be attached to form
334  // so use cgiIn(xxx) to get values.
335  // increment number for each temporary preview, previewPostTempIndex_
336  // save entry and uploads to previewPath / previewPostTempIndex_ /.
337 
338  cleanUpPreviews();
339  std::string EntryText = cgiIn("EntryText");
340  __COUT__ << "EntryText " << EntryText << std::endl << std::endl;
341  std::string EntrySubject = cgiIn("EntrySubject");
342  __COUT__ << "EntrySubject " << EntrySubject << std::endl << std::endl;
343 
344  // get creator name
345  std::string creator = userInfo.username_;
346 
347  savePostPreview(EntrySubject, EntryText, cgiIn.getFiles(), creator, &xmlOut);
348  // else xmlOut.addTextElementToData(XML_STATUS,"Failed - could not get username
349  // info.");
350  }
351  else if(requestType == "ApproveEntry")
352  {
353  // If Approve = "1", then previewed Log entry specified by PreviewNumber
354  // is moved to logbook
355  // Else the specified Log entry is deleted.
356  std::string PreviewNumber = CgiDataUtilities::postData(cgiIn, "PreviewNumber");
357  std::string Approve = CgiDataUtilities::postData(cgiIn, "Approve");
358 
359  movePreviewEntry(PreviewNumber, Approve == "1", &xmlOut);
360  }
361  else if(requestType == "AdminRemoveRestoreEntry")
362  {
363  // if(userPermissions < ADMIN_PERMISSIONS_THRESHOLD)
364  // {
365  // xmlOut.addTextElementToData(XML_ADMIN_STATUS,"Error - Insufficient
366  // permissions."); goto CLEANUP;
367  // }
368 
369  std::string EntryId = CgiDataUtilities::postData(cgiIn, "EntryId");
370  bool Hide = CgiDataUtilities::postData(cgiIn, "Hide") == "1" ? true : false;
371 
372  // get creator name
373  std::string hider = userInfo.username_;
374 
375  hideLogbookEntry(EntryId, Hide, hider);
376 
377  xmlOut.addTextElementToData(XML_ADMIN_STATUS, "1"); // success
378  }
379  else
380  {
381  __SUP_SS__ << "requestType Request, " << requestType
382  << ", not recognized by the Logbook Supervisor (was it intended for "
383  "another Supervisor?)."
384  << __E__;
385  __SUP_SS_THROW__;
386  }
387 } //end request()
388 
389 //==============================================================================
393 void LogbookSupervisor::nonXmlRequest(const std::string& requestType,
394  cgicc::Cgicc& cgiIn,
395  std::ostream& out,
396  const WebUsers::RequestUserInfo& /*userInfo*/)
397 {
398  // Commands
399  // LogImage
400  // LogReport
401 
402  if(requestType == "LogImage")
403  {
404  std::string src = CgiDataUtilities::getData(cgiIn, "src");
405  __COUT__ << " Get Log Image " << src << std::endl;
406 
407  out << "<!DOCTYPE HTML><html lang='en'><frameset col='100%' row='100%'><frame "
408  "src='/WebPath/html/LogbookImage.html?urn="
409  << this->getApplicationDescriptor()->getLocalId() << "&src=" << src
410  << "'></frameset></html>";
411  }
412  else if(requestType == "LogReport")
413  {
414  std::string activeCategory = CgiDataUtilities::getData(cgiIn, "activeCategory");
415  __COUT__ << " Start Log Report for " << activeCategory << std::endl;
416 
417  out << "<!DOCTYPE HTML><html lang='en'><header><title>ots Logbook "
418  "Reports</title></header><frameset col='100%' row='100%'><frame "
419  "src='/WebPath/html/LogbookReport.html?urn="
420  << this->getApplicationDescriptor()->getLocalId()
421  << "&activeCategory=" << activeCategory << "'></frameset></html>";
422  }
423  else
424  __COUT__ << "requestType request not recognized." << std::endl;
425 } //end request()
426 
427 //==============================================================================
431 xoap::MessageReference LogbookSupervisor::MakeSystemLogEntry(xoap::MessageReference msg)
432 {
433  SOAPParameters parameters("EntryText");
434  parameters.addParameter("SubjectText");
435  SOAPUtilities::receive(msg, parameters);
436  std::string EntryText = parameters.getValue("EntryText");
437  std::string SubjectText = parameters.getValue("SubjectText");
438 
439  if(SubjectText == "")
440  SubjectText = "System Log";
441 
442  __COUT__ << "Received External Supervisor System Entry " << EntryText << std::endl;
443  __COUTV__(SubjectText);
444  __COUT__ << "Active Category is " << activeCategory_ << std::endl;
445 
446  std::string retStr = "Success";
447 
448  std::string logPath,
449  logDirPath = (std::string)LOGBOOK_PATH + (std::string)LOGBOOK_LOGBOOKS_PATH +
450  (std::string)LOGBOOK_CATEGORY_DIR_PREFACE + activeCategory_;
451 
452  char dayIndexStr[20];
453  HttpXmlDocument logXml;
454  char fileIndex[40];
455  xercesc::DOMElement* entryEl;
456  DIR* dir;
457 
458  if(activeCategory_ == "")
459  {
460  retStr =
461  "Warning - Currently, no Active Category. Turn off the Logbook XDAQ "
462  "Application to suppress this message.";
463  __COUT__ << retStr << std::endl;
464  goto XOAP_CLEANUP;
465  }
466 
467  // check that directory exists
468  dir = opendir(logDirPath.c_str());
469  if(!dir)
470  {
471  retStr = "Error - Active Category directory missing.";
472  __COUT__ << retStr << std::endl;
473  goto XOAP_CLEANUP;
474  }
475  closedir(dir);
476 
477  sprintf(dayIndexStr, "%6.6lu", time(0) / (60 * 60 * 24)); // get today's index
478 
479  logPath = logDirPath + "/" + LOGBOOK_FILE_PREFACE + activeCategory_ + "_" +
480  (std::string)dayIndexStr + LOGBOOK_FILE_EXTENSION;
481  __COUT__ << "logPath " << logPath << std::endl;
482 
483  logXml.loadXmlDocument(logPath); // NOTE: on failure, no need to do anything
484  // because empty XML file is valid structure
485  // entry structure:
486  // <XML_LOGBOOK_ENTRY>
487  // <XML_LOGBOOK_ENTRY_TIME>
488  // <XML_LOGBOOK_ENTRY_CREATOR>
489  // <XML_LOGBOOK_ENTRY_TEXT>
490  // <XML_LOGBOOK_ENTRY_FILE value=fileType0>
491  // <XML_LOGBOOK_ENTRY_FILE value=fileType1> ...
492  // </XML_LOGBOOK_ENTRY>
493 
494  entryEl = logXml.addTextElementToData(XML_LOGBOOK_ENTRY);
495 
496  sprintf(fileIndex,
497  "%lu_%lu",
498  time(0),
499  clock()); // create unique time label for entry time(0)_clock()
500  logXml.addTextElementToParent(XML_LOGBOOK_ENTRY_TIME, fileIndex, entryEl);
501  logXml.addTextElementToParent(XML_LOGBOOK_ENTRY_CREATOR, "SYSTEM LOG", entryEl);
502  logXml.addTextElementToParent(XML_LOGBOOK_ENTRY_TEXT, EntryText, entryEl);
503  logXml.addTextElementToParent(XML_LOGBOOK_ENTRY_SUBJECT, SubjectText, entryEl);
504 
505  logXml.saveXmlDocument(logPath);
506 
507 XOAP_CLEANUP:
508 
509  // fill return parameters
510  SOAPParameters retParameters("Status", retStr);
511  return SOAPUtilities::makeSOAPMessageReference("SystemLogEntryStatusResponse",
512  retParameters);
513 } //end MakeSystemLogEntry()
514 
524 //{
525 // cgicc::Cgicc cgiIn(in);
526 // std::string src = CgiDataUtilities::getData(cgiIn,"src");
527 // __COUT__ << " Get Log Image " << src << std::endl;
528 // *out << "<!DOCTYPE HTML><html lang='en'><frameset col='100%' row='100%'><frame
529 // src='/WebPath/html/LogbookImage.html?urn=" <<
530 // this->getApplicationDescriptor()->getLocalId() << "&src=" << src <<
531 //"'></frameset></html>";
532 //}
533 //
542 //{
543 // cgicc::Cgicc cgiIn(in);
544 // std::string activeCategory = CgiDataUtilities::getData(cgiIn,"activeCategory");
545 // __COUT__ << " Start Log Report for " << activeCategory << std::endl;
546 // *out << "<!DOCTYPE HTML><html lang='en'><header><title>ots Logbook
547 // Reports</title></header><frameset col='100%' row='100%'><frame
548 // src='/WebPath/html/LogbookReport.html?urn=" <<
549 // this->getApplicationDescriptor()->getLocalId() << "&activeCategory=" <<
550 // activeCategory << "'></frameset></html>";
551 //}
552 
553 //==============================================================================
556 std::string LogbookSupervisor::getActiveCategory()
557 {
558  FILE* fp = fopen(std::string((std::string)ACTIVE_CATEGORY_PATH).c_str(), "r");
559  if(!fp)
560  activeCategory_ = "";
561  else
562  {
563  char line[100];
564  if(!fgets(line, 100, fp))
565  line[0] =
566  '\0'; // if null returned, file is empty and line is untouched, so touch.
567  fclose(fp);
568 
569  // remove \n \r
570  if(line[strlen(line) - 2] == '\r')
571  line[strlen(line) - 2] = '\0';
572  else if(line[strlen(line) - 1] == '\n')
573  line[strlen(line) - 1] = '\0';
574 
575  activeCategory_ = line;
576  }
577 
578  return activeCategory_;
579 } //end getActiveCategory()
580 
581 //==============================================================================
584 void LogbookSupervisor::setActiveCategory(std::string category)
585 {
586  FILE* fp = fopen(std::string((std::string)ACTIVE_CATEGORY_PATH).c_str(), "w");
587  if(!fp)
588  {
589  __COUT__ << "FATAL ERROR!!! - file write" << std::endl;
590  return;
591  }
592 
593  fprintf(fp, "%s", category.c_str());
594  fclose(fp);
595 
596  if(activeCategory_ != "" &&
597  activeCategory_ != category) // old active category is on its way out
598  theRemoteWebUsers_.makeSystemLogEntry(
599  "Category was made inactive."); // make system logbook entry
600 
601  bool entryNeeded = false;
602  if(category != "" &&
603  activeCategory_ != category) // old active category is on its way out
604  entryNeeded = true;
605 
606  activeCategory_ = category;
607  __COUT__ << "Active Category set to " << activeCategory_ << std::endl;
608 
609  if(entryNeeded)
610  theRemoteWebUsers_.makeSystemLogEntry(
611  "Category was made active."); // make system logbook entry
612 } //end setActiveCategory()
613 
614 //==============================================================================
617 bool LogbookSupervisor::validateCategoryName(std::string& exp)
618 {
619  if(exp.length() < CATEGORY_NAME_MIN_LENTH || exp.length() > CATEGORY_NAME_MAX_LENTH)
620  return false;
621  for(int i = 0; i < (int)exp.length(); ++i)
622  if(!((exp[i] >= 'a' && exp[i] <= 'z') || (exp[i] >= 'A' && exp[i] <= 'Z') ||
623  (exp[i] >= '0' && exp[i] <= '9') || (exp[i] == '-' || exp[i] == '_')))
624  {
625  exp = exp.substr(0, i) + exp.substr(i + 1);
626  --i;
627  } // remove illegal chars and rewind i
628 
629  return true;
630 } //end validateCategoryName()
631 
632 //==============================================================================
636 void LogbookSupervisor::getCategories(HttpXmlDocument* xmlOut, std::ostringstream* out)
637 {
638  // check that category listing doesn't already exist
639  HttpXmlDocument expXml;
640  if(!expXml.loadXmlDocument((std::string)LOGBOOK_CATEGORY_LIST_PATH))
641  {
642  __COUT__ << "Fatal Error - Category database." << std::endl;
643  __COUT__ << "Creating empty category database." << std::endl;
644 
645  expXml.addTextElementToData((std::string)XML_CATEGORY_ROOT);
646  expXml.saveXmlDocument((std::string)LOGBOOK_CATEGORY_LIST_PATH);
647  return;
648  }
649 
650  std::vector<std::string> exps;
651  expXml.getAllMatchingValues(XML_CATEGORY, exps);
652 
653  if(xmlOut)
654  xmlOut->addTextElementToData(XML_ACTIVE_CATEGORY, activeCategory_);
655 
656  for(unsigned int i = 0; i < exps.size(); ++i) // loop categories
657  {
658  if(xmlOut)
659  xmlOut->addTextElementToData(XML_CATEGORY, exps[i]);
660  if(out)
661  *out << exps[i] << std::endl;
662  }
663 } //end getCategories()
664 
665 //==============================================================================
667 void LogbookSupervisor::createCategory(std::string category,
668  std::string creator,
669  HttpXmlDocument* xmlOut)
670 {
671  if(!validateCategoryName(category))
672  {
673  if(xmlOut)
674  xmlOut->addTextElementToData(
675  XML_ADMIN_STATUS, "Error - Category name must be 3-25 characters.");
676  return;
677  }
678 
679  __COUT__ << "category " << category << std::endl;
680 
681  // check that directory doesn't already exist
682  std::string dirPath = (std::string)LOGBOOK_PATH + (std::string)LOGBOOK_LOGBOOKS_PATH +
683  (std::string)LOGBOOK_CATEGORY_DIR_PREFACE + category;
684 
685  __COUT__ << "dirPath " << dirPath << std::endl;
686 
687  bool directoryExists = false;
688  DIR* dir = opendir(dirPath.c_str());
689  if(dir)
690  {
691  closedir(dir);
692  directoryExists = true;
693  }
694 
695  // check that category listing doesn't already exist
696  HttpXmlDocument expXml;
697  if(!expXml.loadXmlDocument((std::string)LOGBOOK_CATEGORY_LIST_PATH))
698  {
699  if(xmlOut)
700  xmlOut->addTextElementToData(XML_ADMIN_STATUS,
701  "Fatal Error - Category database.");
702  return;
703  }
704 
705  std::vector<std::string> exps;
706  expXml.getAllMatchingValues(XML_CATEGORY, exps);
707 
708  for(unsigned int i = 0; i < exps.size(); ++i)
709  if(category == exps[i])
710  {
711  if(xmlOut)
712  xmlOut->addTextElementToData(
713  XML_ADMIN_STATUS,
714  "Failed - Category, " + category + ", already exists.");
715  return;
716  }
717  __COUT__ << "categories count: " << exps.size() << std::endl;
718 
719  // everything checks out, add category!
720  // add to categories xml doc and save
721  // <categories>
722  // ...
723  // <category_name = "xx">
724  // <create_time = "##"> <who_created = "aa">
725  xercesc::DOMElement* expEl =
726  expXml.addTextElementToParent(XML_CATEGORY, category, XML_CATEGORY_ROOT);
727  char createTime[20];
728  sprintf(createTime, "%lu", time(0));
729  expXml.addTextElementToParent(XML_CATEGORY_CREATE, createTime, expEl);
730  expXml.addTextElementToParent(XML_CATEGORY_CREATOR, creator, expEl);
731  expXml.saveXmlDocument((std::string)LOGBOOK_CATEGORY_LIST_PATH);
732 
733  // create directory only if doesn't already exist
734  if(directoryExists)
735  {
736  // check uploads folder
737  dirPath += "/" + (std::string)LOGBOOK_UPLOADS_PATH;
738  __COUT__ << "Checking uploads directory" << std::endl;
739 
740  directoryExists = false;
741  dir = opendir(dirPath.c_str());
742  if(!dir) // check if uploads directory exists within category directory
743  {
744  __COUT__ << "Creating uploads directory" << std::endl;
745  if(-1 == mkdir(dirPath.c_str(), 0755)) // make uploads directory
746  {
747  if(xmlOut)
748  xmlOut->addTextElementToData(XML_ADMIN_STATUS,
749  "Failed - uploads directory for " +
750  category + " was not created.");
751  __COUT__ << "Uploads directory failure." << std::endl;
752  return;
753  }
754  }
755  else
756  closedir(dir);
757 
758  xmlOut->addTextElementToData(XML_ADMIN_STATUS,
759  "Directory already exists for " + category +
760  ", re-added to list of categories.");
761  return;
762  }
763  __COUT__ << "Creating category and uploads directory at: " << dirPath << std::endl;
764  if(-1 == mkdir(dirPath.c_str(), 0755) ||
765  -1 == mkdir((dirPath + "/" + (std::string)LOGBOOK_UPLOADS_PATH).c_str(), 0755))
766  {
767  if(xmlOut)
768  xmlOut->addTextElementToData(
769  XML_ADMIN_STATUS,
770  "Failed - directory, " + category + ", could not be created.");
771  return;
772  }
773 
774  if(xmlOut)
775  xmlOut->addTextElementToData(XML_ADMIN_STATUS,
776  "Category, " + category + ", successfully created.");
777 } //end createCategory()
778 
779 //==============================================================================
783 void LogbookSupervisor::webUserSetActiveCategory(std::string category,
784  HttpXmlDocument* xmlOut)
785 {
786  if(category == "") // clear active category
787  {
788  setActiveCategory(category);
789  if(xmlOut)
790  xmlOut->addTextElementToData(XML_ADMIN_STATUS,
791  "Active category cleared successfully.");
792  }
793 
794  // check that category listing exists
795  HttpXmlDocument expXml;
796  if(!expXml.loadXmlDocument((std::string)LOGBOOK_CATEGORY_LIST_PATH))
797  {
798  if(xmlOut)
799  xmlOut->addTextElementToData(XML_ADMIN_STATUS,
800  "Fatal Error - Category database.");
801  return;
802  }
803  std::vector<std::string> exps;
804  expXml.getAllMatchingValues(XML_CATEGORY, exps);
805 
806  unsigned int i;
807  for(i = 0; i < exps.size(); ++i)
808  if(category == exps[i])
809  break;
810 
811  if(i == exps.size()) // not found
812  {
813  if(xmlOut)
814  xmlOut->addTextElementToData(
815  XML_ADMIN_STATUS, "Failed - Category, " + category + ", not found.");
816  return;
817  }
818 
819  // found!
820  setActiveCategory(category);
821  if(xmlOut)
822  xmlOut->addTextElementToData(
823  XML_ADMIN_STATUS, "Active category set to " + category + " successfully.");
824 } //end webUserSetActiveCategory()
825 
826 //==============================================================================
830 void LogbookSupervisor::removeCategory(std::string category,
831  std::string remover,
832  HttpXmlDocument* xmlOut)
833 {
834  __COUT__ << "category " << category << std::endl;
835 
836  // check that category listing exists
837  HttpXmlDocument expXml;
838  if(!expXml.loadXmlDocument((std::string)LOGBOOK_CATEGORY_LIST_PATH))
839  {
840  if(xmlOut)
841  xmlOut->addTextElementToData(XML_ADMIN_STATUS,
842  "Fatal Error - Category database.");
843  return;
844  }
845  std::vector<std::string> exps;
846  expXml.getAllMatchingValues(XML_CATEGORY, exps);
847 
848  unsigned int i;
849  for(i = 0; i < exps.size(); ++i)
850  if(category == exps[i])
851  break;
852 
853  if(i == exps.size()) // not found
854  {
855  if(xmlOut)
856  xmlOut->addTextElementToData(
857  XML_ADMIN_STATUS, "Failed - Category, " + category + ", not found.");
858  return;
859  }
860 
861  // found!
862 
863  // remove category from xml
864  xercesc::DOMElement* parent = expXml.getMatchingElement(XML_CATEGORY_ROOT);
865  xercesc::DOMElement* child = expXml.getMatchingElement(XML_CATEGORY, i);
866  __COUT__ << "categories original count: " << expXml.getChildrenCount(parent)
867  << std::endl;
868  expXml.recursiveRemoveChild(child, parent);
869  __COUT__ << "categories new count: " << expXml.getChildrenCount(parent) << std::endl;
870 
871  // update removed categories log
872  FILE* fp = fopen(((std::string)REMOVE_CATEGORY_LOG_PATH).c_str(), "a");
873  if(!fp)
874  {
875  if(xmlOut)
876  xmlOut->addTextElementToData(XML_ADMIN_STATUS, "Fatal Error - Remove log.");
877  return;
878  }
879  fprintf(fp,
880  "%s -- %s Category removed by %s.\n",
881  asctime(localtime(&((time_t const&)(time(0))))),
882  category.c_str(),
883  remover.c_str());
884  fclose(fp);
885 
886  expXml.saveXmlDocument((std::string)LOGBOOK_CATEGORY_LIST_PATH); // save database
887 
888  // unset from activeCategory_ if is active category
889  if(activeCategory_ == category)
890  setActiveCategory(); // clear active category
891 
892  if(xmlOut)
893  xmlOut->addTextElementToData(XML_ADMIN_STATUS,
894  "Category, " + category + ", successfully removed.");
895 } //end removeCategory()
896 
897 //==============================================================================
903 void LogbookSupervisor::refreshLogbook(time_t date,
904  uint32_t duration,
905  HttpXmlDocument* xmlOut,
906  std::ostringstream* out,
907  std::string category)
908 {
909  if(category == "")
910  category = activeCategory_; // default to active category
911  if(xmlOut)
912  xmlOut->addTextElementToData(XML_ACTIVE_CATEGORY, category); // for success
913 
914  // check that directory exists
915  std::string dirPath = (std::string)LOGBOOK_PATH + (std::string)LOGBOOK_LOGBOOKS_PATH +
916  (std::string)LOGBOOK_CATEGORY_DIR_PREFACE + category;
917 
918  if(out)
919  *out << __COUT_HDR_FL__ << "dirPath " << dirPath << std::endl;
920 
921  DIR* dir = opendir(dirPath.c_str());
922  if(!dir)
923  {
924  if(xmlOut)
925  xmlOut->addTextElementToData(
926  XML_STATUS, "Error - Directory for category, " + category + ", missing.");
927  if(out)
928  *out << __COUT_HDR_FL__ << "Error - Directory missing" << std::endl;
929  return;
930  }
931 
932  unsigned int baseDay;
933 
934  if(!date) // if date is 0 take most recent day and update it
935  {
936  struct dirent* drnt;
937  unsigned int extractedDay;
938  int start, finish; // always find number after last _ and before last .
939 
940  mostRecentDayIndex_ = 0;
941  while((drnt = readdir(dir)))
942  {
943  // if(out) *out << __COUT_HDR_FL__ << "dirContents " << drnt->d_name <<
944  // std::endl;
945 
946  if(strcmp(&(drnt->d_name[strlen(drnt->d_name) - 4]), ".xml"))
947  continue; // skip non logbook files
948 
949  for(finish = strlen(drnt->d_name) - 1; finish > 0; --finish)
950  if(drnt->d_name[finish] == '.')
951  break;
952  if(finish == 0)
953  {
954  if(out)
955  *out << __COUT_HDR_FL__ << "failed to find day index finish "
956  << std::endl;
957  return;
958  }
959  for(start = finish - 1; start > 0; --start)
960  if(drnt->d_name[start - 1] == '_')
961  break;
962  if(start == 0)
963  {
964  if(out)
965  *out << __COUT_HDR_FL__ << "failed to find day index start "
966  << std::endl;
967  return;
968  }
969  drnt->d_name[finish] = '\0';
970  extractedDay = atoi((char*)(&(drnt->d_name[start])));
971  // if(out) *out << __COUT_HDR_FL__ << "dirContents " << (char
972  // *)(&(drnt->d_name[start])) << " " << extractedDay << std::endl;
973  if(!mostRecentDayIndex_ || mostRecentDayIndex_ < extractedDay)
974  mostRecentDayIndex_ = extractedDay;
975  }
976  if(out)
977  *out << __COUT_HDR_FL__
978  << "dirContents done, found most recent day: " << mostRecentDayIndex_
979  << std::endl;
980 
981  baseDay = mostRecentDayIndex_;
982  }
983  else
984  baseDay = (date / (60 * 60 * 24));
985  closedir(dir);
986 
987  std::string entryPath;
988  char dayIndexStr[20];
989  FILE* fp;
990 
991  // read all days selected out
992  // entries are in file as oldest at top, newest at bottom
993  // so read oldest files first to have global ordering of old to new
994  for(uint32_t i = duration; i != 0; --i)
995  {
996  sprintf(dayIndexStr, "%6.6u", baseDay - i + 1); // get day index, back in time
997  entryPath = dirPath + "/" + LOGBOOK_FILE_PREFACE + category + "_" +
998  (std::string)dayIndexStr + LOGBOOK_FILE_EXTENSION;
999 
1000  if(out)
1001  *out << __COUT_HDR_FL__ << "Directory Entry " << entryPath << std::endl;
1002 
1003  fp = fopen(entryPath.c_str(), "r");
1004  if(!fp)
1005  {
1006  if(out)
1007  *out << __COUT_HDR_FL__ << "File not found" << std::endl;
1008  continue;
1009  }
1010  fclose(fp);
1011 
1012  // file found! read file out
1013 
1014  HttpXmlDocument logXml;
1015  if(!logXml.loadXmlDocument(entryPath))
1016  {
1017  if(xmlOut)
1018  xmlOut->addTextElementToData(
1019  XML_STATUS, "Critical Failure - log did not load. Notify admins.");
1020  if(out)
1021  *out << __COUT_HDR_FL__ << "Failure - log XML did not load" << std::endl;
1022  return;
1023  }
1024 
1025  if(xmlOut)
1026  xmlOut->copyDataChildren(logXml); // copy file to output xml
1027  }
1028 
1029  if(xmlOut)
1030  xmlOut->addTextElementToData(XML_STATUS, "1"); // for success
1031  if(out)
1032  *out << __COUT_HDR_FL__ << "Today: " << time(0) / (60 * 60 * 24) << std::endl;
1033 
1034  sprintf(dayIndexStr, "%lu", time(0) / (60 * 60 * 24) - mostRecentDayIndex_);
1035  if(xmlOut)
1036  xmlOut->addTextElementToData(XML_MOST_RECENT_DAY,
1037  dayIndexStr); // send most recent day index
1038 } //end refreshLogbook()
1039 
1040 //==============================================================================
1044 void LogbookSupervisor::cleanUpPreviews()
1045 {
1046  std::string previewPath =
1047  (std::string)LOGBOOK_PATH + (std::string)LOGBOOK_PREVIEWS_PATH;
1048 
1049  DIR* dir = opendir(previewPath.c_str());
1050  if(!dir)
1051  {
1052  __COUT__ << "Error - Previews directory missing: " << previewPath << std::endl;
1053  return;
1054  }
1055 
1056  struct dirent* entry;
1057  time_t dirCreateTime;
1058  unsigned int i;
1059 
1060  while(
1061  (entry = readdir(
1062  dir))) // loop through all entries in directory and remove anything expired
1063  {
1064  if(strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0 &&
1065  strcmp(entry->d_name, ".svn") != 0)
1066  {
1067  // replace _ with space so sscanf works
1068  for(i = 0; i < strlen(entry->d_name); ++i)
1069  if(entry->d_name[i] == '_')
1070  {
1071  entry->d_name[i] = ' ';
1072  break;
1073  }
1074  sscanf(entry->d_name, "%li", &dirCreateTime);
1075 
1076  if((time(0) - dirCreateTime) > LOGBOOK_PREVIEW_EXPIRATION_TIME)
1077  {
1078  __COUT__ << "Expired" << std::endl;
1079 
1080  entry->d_name[i] = '_'; // put _ back
1081 
1082  __COUT__ << "rm -rf " << previewPath + (std::string)entry->d_name
1083  << std::endl
1084  << std::endl;
1085  system(
1086  ((std::string)("rm -rf " + previewPath + (std::string)entry->d_name))
1087  .c_str());
1088  }
1089  }
1090  }
1091 
1092  closedir(dir);
1093 } //end cleanUpPreviews()
1094 
1095 //==============================================================================
1098 void LogbookSupervisor::savePostPreview(std::string& subject,
1099  std::string& text,
1100  const std::vector<cgicc::FormFile>& files,
1101  std::string creator,
1102  HttpXmlDocument* xmlOut)
1103 {
1104  if(activeCategory_ == "") // no active category!
1105  {
1106  if(xmlOut)
1107  xmlOut->addTextElementToData(XML_STATUS,
1108  "Failed - no active category currently!");
1109  return;
1110  }
1111 
1112  char fileIndex[40];
1113  sprintf(fileIndex,
1114  "%lu_%lu",
1115  time(0),
1116  clock()); // create unique time label for entry time(0)_clock()
1117  std::string previewPath = (std::string)LOGBOOK_PATH +
1118  (std::string)LOGBOOK_PREVIEWS_PATH + (std::string)fileIndex;
1119 
1120  __COUT__ << "previewPath " << previewPath << std::endl;
1121  if(-1 == mkdir(previewPath.c_str(), 0755))
1122  {
1123  if(xmlOut)
1124  xmlOut->addTextElementToData(XML_STATUS,
1125  "Failed - preview could not be generated.");
1126  return;
1127  }
1128 
1129  // new directory created successfully, save text and files
1130  // entry structure:
1131  // <XML_LOGBOOK_ENTRY>
1132  // <XML_LOGBOOK_ENTRY_TIME>
1133  // <XML_LOGBOOK_ENTRY_CREATOR>
1134  // <XML_LOGBOOK_ENTRY_SUBJECT>
1135  // <XML_LOGBOOK_ENTRY_TEXT>
1136  // <XML_LOGBOOK_ENTRY_FILE value=fileType0>
1137  // <XML_LOGBOOK_ENTRY_FILE value=fileType1> ...
1138  // </XML_LOGBOOK_ENTRY>
1139 
1140  escapeLogbookEntry(text);
1141  escapeLogbookEntry(subject);
1142  __COUT__ << "~~subject " << subject << std::endl
1143  << "~~text " << text << std::endl
1144  << std::endl;
1145 
1146  HttpXmlDocument previewXml;
1147 
1148  previewXml.addTextElementToData(XML_LOGBOOK_ENTRY);
1149  previewXml.addTextElementToParent(
1150  XML_LOGBOOK_ENTRY_TIME, fileIndex, XML_LOGBOOK_ENTRY);
1151  if(xmlOut)
1152  xmlOut->addTextElementToData(XML_LOGBOOK_ENTRY_TIME, fileIndex); // return time
1153  previewXml.addTextElementToParent(
1154  XML_LOGBOOK_ENTRY_CREATOR, creator, XML_LOGBOOK_ENTRY);
1155  if(xmlOut)
1156  xmlOut->addTextElementToData(XML_LOGBOOK_ENTRY_CREATOR,
1157  creator); // return creator
1158  previewXml.addTextElementToParent(XML_LOGBOOK_ENTRY_TEXT, text, XML_LOGBOOK_ENTRY);
1159  if(xmlOut)
1160  xmlOut->addTextElementToData(XML_LOGBOOK_ENTRY_TEXT, text); // return text
1161  previewXml.addTextElementToParent(
1162  XML_LOGBOOK_ENTRY_SUBJECT, subject, XML_LOGBOOK_ENTRY);
1163  if(xmlOut)
1164  xmlOut->addTextElementToData(XML_LOGBOOK_ENTRY_SUBJECT,
1165  subject); // return subject
1166 
1167  __COUT__ << "file size " << files.size() << std::endl;
1168 
1169  std::string filename;
1170  std::ofstream myfile;
1171  for(unsigned int i = 0; i < files.size(); ++i)
1172  {
1173  previewXml.addTextElementToParent(
1174  XML_LOGBOOK_ENTRY_FILE, files[i].getDataType(), XML_LOGBOOK_ENTRY);
1175  if(xmlOut)
1176  xmlOut->addTextElementToData(XML_LOGBOOK_ENTRY_FILE,
1177  files[i].getDataType()); // return file type
1178 
1179  if((filename = validateUploadFileType(files[i].getDataType())) ==
1180  "") // invalid file type
1181  {
1182  if(xmlOut)
1183  xmlOut->addTextElementToData(
1184  XML_STATUS,
1185  "Failed - invalid file type, " + files[i].getDataType() + ".");
1186  return;
1187  }
1188 
1189  // file validated, so save upload to temp directory
1190  sprintf(fileIndex, "%d", i);
1191  filename = previewPath + "/" + (std::string)LOGBOOK_PREVIEW_UPLOAD_PREFACE +
1192  (std::string)fileIndex + "." + filename;
1193 
1194  __COUT__ << "file " << i << " - " << filename << std::endl;
1195  myfile.open(filename.c_str());
1196  if(myfile.is_open())
1197  {
1198  files[i].writeToStream(myfile);
1199  myfile.close();
1200  }
1201  }
1202 
1203  // save xml doc for preview entry
1204  previewXml.saveXmlDocument(previewPath + "/" + (std::string)LOGBOOK_PREVIEW_FILE);
1205 
1206  if(xmlOut)
1207  xmlOut->addTextElementToData(XML_STATUS, "1"); // 1 indicates success!
1208  if(xmlOut)
1209  xmlOut->addTextElementToData(XML_PREVIEW_INDEX,
1210  "1"); // 1 indicates is a preview post
1211 } //end savePostPreview()
1212 
1213 //==============================================================================
1219 void LogbookSupervisor::movePreviewEntry(std::string previewNumber,
1220  bool approve,
1221  HttpXmlDocument* /*xmlOut*/)
1222 {
1223  __COUT__ << "previewNumber " << previewNumber
1224  << (approve ? " Accepted" : " Cancelled") << std::endl;
1225 
1226  std::string sysCmd, previewPath = (std::string)LOGBOOK_PATH +
1227  (std::string)LOGBOOK_PREVIEWS_PATH + previewNumber;
1228 
1229  if(approve)
1230  {
1231  // move from preview to logbook
1232 
1233  HttpXmlDocument previewXml;
1234  previewXml.loadXmlDocument(previewPath + "/" + (std::string)LOGBOOK_PREVIEW_FILE);
1235 
1236  std::string logPath,
1237  logDirPath = (std::string)LOGBOOK_PATH + (std::string)LOGBOOK_LOGBOOKS_PATH +
1238  (std::string)LOGBOOK_CATEGORY_DIR_PREFACE + activeCategory_;
1239 
1240  // check that directory exists
1241  DIR* dir = opendir(logDirPath.c_str());
1242  if(!dir)
1243  {
1244  __COUT__ << "Error - Active Category directory missing: " << logPath
1245  << std::endl;
1246  return;
1247  }
1248  closedir(dir);
1249 
1250  char dayIndexStr[20];
1251  sprintf(dayIndexStr, "%6.6lu", time(0) / (60 * 60 * 24)); // get today's index
1252 
1253  logPath = logDirPath + "/" + LOGBOOK_FILE_PREFACE + activeCategory_ + "_" +
1254  (std::string)dayIndexStr + LOGBOOK_FILE_EXTENSION;
1255  __COUT__ << "logPath " << logPath << std::endl;
1256 
1257  HttpXmlDocument logXml;
1258  logXml.loadXmlDocument(logPath); // NOTE: on failure, no need to do anything
1259  // because empty XML file is valid structure
1260  // entry structure:
1261  // <XML_LOGBOOK_ENTRY>
1262  // <XML_LOGBOOK_ENTRY_TIME>
1263  // <XML_LOGBOOK_ENTRY_CREATOR>
1264  // <XML_LOGBOOK_ENTRY_TEXT>
1265  // <XML_LOGBOOK_ENTRY_FILE value=fileType0>
1266  // <XML_LOGBOOK_ENTRY_FILE value=fileType1> ...
1267  // </XML_LOGBOOK_ENTRY>
1268 
1269  logXml.copyDataChildren(previewXml); // Copy from previewXML to logXML
1270  logXml.saveXmlDocument(logPath);
1271 
1272  // Move upload files
1273  std::vector<std::string> fileTypes;
1274  previewXml.getAllMatchingValues(XML_LOGBOOK_ENTRY_FILE, fileTypes);
1275  std::string entryTimeLabel = previewXml.getMatchingValue(XML_LOGBOOK_ENTRY_TIME);
1276  std::string fileExtension, previewFilename, logFilename;
1277  char fileIndex[10];
1278  for(unsigned int i = 0; i < fileTypes.size(); ++i)
1279  {
1280  if((fileExtension = validateUploadFileType(fileTypes[i])) ==
1281  "") // invalid file type
1282  {
1283  __COUT__ << "Failed - invalid file type: " << fileTypes[i] << std::endl;
1284  continue;
1285  }
1286 
1287  // file validated, so save upload to temp directory
1288  sprintf(fileIndex, "%d", i);
1289  previewFilename = (std::string)LOGBOOK_PREVIEW_UPLOAD_PREFACE +
1290  (std::string)fileIndex + "." + fileExtension;
1291  logFilename = (std::string)LOGBOOK_PREVIEW_UPLOAD_PREFACE + entryTimeLabel +
1292  "_" + (std::string)fileIndex + "." + fileExtension;
1293 
1294  sysCmd = "mv " + (previewPath + "/" + previewFilename) + " " +
1295  (logDirPath + "/" + (std::string)LOGBOOK_UPLOADS_PATH + logFilename);
1296  __COUT__ << sysCmd << std::endl;
1297  system(sysCmd.c_str());
1298  }
1299  }
1300 
1301  // remove preview directory
1302  sysCmd = "rm -rf " + previewPath;
1303  __COUT__ << sysCmd << std::endl << std::endl;
1304  system(sysCmd.c_str());
1305 } //end movePreviewEntry()
1306 
1307 //==============================================================================
1310 std::string LogbookSupervisor::validateUploadFileType(const std::string fileType)
1311 {
1312  for(unsigned int i = 0; i < allowedFileUploadTypes_.size(); ++i)
1313  if(allowedFileUploadTypes_[i] == fileType)
1314  return matchingFileUploadTypes_[i]; // found and done
1315 
1316  return ""; // not valid, return ""
1317 } //end validateUploadFileType()
1318 
1319 //==============================================================================
1323 void LogbookSupervisor::escapeLogbookEntry(std::string& /*entry*/)
1324 {
1325  // NOTE: should already be taken care of by web gui javascript! do we care to check?
1326 } //end escapeLogbookEntry()
1327 
1328 //==============================================================================
1337 void LogbookSupervisor::hideLogbookEntry(const std::string& entryId,
1338  bool hide,
1339  const std::string& hider)
1340 {
1341  __COUT__ << "Hide=" << hide << " for entryid " << entryId << std::endl;
1342 
1343  // get path to entries file for entry at entryId
1344  char dayIndexStr[20];
1345  unsigned int i;
1346  for(i = 0; i < entryId.length(); ++i)
1347  if(entryId[i] == '_')
1348  {
1349  dayIndexStr[i] = '\0';
1350  break;
1351  }
1352  else
1353  dayIndexStr[i] = entryId[i];
1354  time_t days;
1355  sscanf(dayIndexStr, "%li", &days); // get seconds
1356  days /= 60 * 60 * 24; // get days
1357  sprintf(dayIndexStr, "%6.6lu", days);
1358 
1359  std::string logDirPath = (std::string)LOGBOOK_PATH +
1360  (std::string)LOGBOOK_LOGBOOKS_PATH +
1361  (std::string)LOGBOOK_CATEGORY_DIR_PREFACE + activeCategory_;
1362  std::string logPath = logDirPath + "/" + LOGBOOK_FILE_PREFACE + activeCategory_ +
1363  "_" + (std::string)dayIndexStr + LOGBOOK_FILE_EXTENSION;
1364 
1365  __COUT__ << "logPath=" << logPath << std::endl;
1366 
1367  // locate entry
1368  HttpXmlDocument logXml;
1369  if(!logXml.loadXmlDocument(logPath))
1370  {
1371  __COUT__ << "Failure - log XML did not load" << std::endl;
1372  return;
1373  }
1374 
1375  std::vector<std::string> allEntryIds;
1376  logXml.getAllMatchingValues(XML_LOGBOOK_ENTRY_TIME, allEntryIds);
1377  for(i = 0; i < allEntryIds.size(); ++i)
1378  if(allEntryIds[i] == entryId)
1379  break;
1380  if(i == allEntryIds.size())
1381  {
1382  __COUT__ << "Failure - entry not found" << std::endl;
1383  return;
1384  }
1385 
1386  __COUT__ << "found " << logXml.getMatchingValue(XML_LOGBOOK_ENTRY_TEXT, i)
1387  << std::endl;
1388 
1389  xercesc::DOMElement *hiddenParentEl, *entryParentEl = logXml.getMatchingElement(
1390  XML_LOGBOOK_ENTRY, i); // get entry element
1391 
1392  // check if already hidden
1393  hiddenParentEl =
1394  logXml.getMatchingElementInSubtree(entryParentEl, XML_LOGBOOK_ENTRY_HIDDEN);
1395 
1396  if(hide) // remove entry
1397  {
1398  if(hiddenParentEl)
1399  {
1400  __COUT__ << "Hidden tag already applied to entry." << std::endl;
1401  return;
1402  }
1403  hiddenParentEl = logXml.addTextElementToParent(
1404  XML_LOGBOOK_ENTRY_HIDDEN,
1405  "1",
1406  entryParentEl); // add hidden parent with value "1"
1407  logXml.addTextElementToParent(
1408  XML_LOGBOOK_ENTRY_HIDER, hider, hiddenParentEl); // hider
1409  sprintf(dayIndexStr, "%lu", time(0));
1410  logXml.addTextElementToParent(
1411  XML_LOGBOOK_ENTRY_HIDDEN_TIME, dayIndexStr, hiddenParentEl); // hide time
1412  }
1413  else // restore entry
1414  {
1415  if(!hiddenParentEl)
1416  {
1417  __COUT__ << "Entry already was not hidden." << std::endl;
1418  return;
1419  }
1420 
1421  logXml.recursiveRemoveChild(hiddenParentEl,
1422  entryParentEl); // remove hidden parent
1423  }
1424  logXml.saveXmlDocument(logPath);
1425  __COUT__ << "Success." << std::endl;
1426 } //end hideLogbookEntry()
static std::string postData(cgicc::Cgicc &cgi, const std::string &needle)
static std::string getData(cgicc::Cgicc &cgi, const std::string &needle)
WebUsers::permissionLevel_t getSupervisorPropertyUserPermissionsThreshold(const std::string &requestType)
xercesc::DOMElement * getMatchingElement(const std::string &field, const unsigned int occurance=0)
void getAllMatchingValues(const std::string &field, std::vector< std::string > &retVec)
xercesc::DOMElement * getMatchingElementInSubtree(xercesc::DOMElement *currEl, const std::string &field, const unsigned int occurance=0)
void copyDataChildren(HttpXmlDocument &document)
bool loadXmlDocument(const std::string &filePath)
unsigned int getChildrenCount(xercesc::DOMElement *parent=0)
std::string getMatchingValue(const std::string &field, const unsigned int occurance=0)
xoap::MessageReference MakeSystemLogEntry(xoap::MessageReference msg)
External Supervisor XOAP handlers.
virtual void request(const std::string &requestType, cgicc::Cgicc &cgiIn, HttpXmlDocument &xmlOut, const WebUsers::RequestUserInfo &userInfo) override
virtual void forceSupervisorPropertyValues(void) override
override to force supervisor property values (and ignore user settings)
virtual void setSupervisorPropertyDefaults(void) override
override to control supervisor specific defaults
virtual void nonXmlRequest(const std::string &requestType, cgicc::Cgicc &cgiIn, std::ostream &out, const WebUsers::RequestUserInfo &userInfo) override
void addParameter(const std::string name, const std::string value)
xercesc::DOMElement * addTextElementToParent(const std::string &childName, const std::string &childText, xercesc::DOMElement *parent)
void recursiveRemoveChild(xercesc::DOMElement *childEl, xercesc::DOMElement *parentEl)
void saveXmlDocument(const std::string &filePath)
void INIT_MF(const char *name)