tdaq-develop-2025-02-12
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_ >=
290  CoreSupervisorBase::getSupervisorPropertyUserPermissionsThreshold(
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  __COUT__ << "requestType request not recognized." << std::endl;
381 } //end request()
382 
383 //==============================================================================
387 void LogbookSupervisor::nonXmlRequest(const std::string& requestType,
388  cgicc::Cgicc& cgiIn,
389  std::ostream& out,
390  const WebUsers::RequestUserInfo& /*userInfo*/)
391 {
392  // Commands
393  // LogImage
394  // LogReport
395 
396  if(requestType == "LogImage")
397  {
398  std::string src = CgiDataUtilities::getData(cgiIn, "src");
399  __COUT__ << " Get Log Image " << src << std::endl;
400 
401  out << "<!DOCTYPE HTML><html lang='en'><frameset col='100%' row='100%'><frame "
402  "src='/WebPath/html/LogbookImage.html?urn="
403  << this->getApplicationDescriptor()->getLocalId() << "&src=" << src
404  << "'></frameset></html>";
405  }
406  else if(requestType == "LogReport")
407  {
408  std::string activeCategory = CgiDataUtilities::getData(cgiIn, "activeCategory");
409  __COUT__ << " Start Log Report for " << activeCategory << std::endl;
410 
411  out << "<!DOCTYPE HTML><html lang='en'><header><title>ots Logbook "
412  "Reports</title></header><frameset col='100%' row='100%'><frame "
413  "src='/WebPath/html/LogbookReport.html?urn="
414  << this->getApplicationDescriptor()->getLocalId()
415  << "&activeCategory=" << activeCategory << "'></frameset></html>";
416  }
417  else
418  __COUT__ << "requestType request not recognized." << std::endl;
419 } //end request()
420 
421 //==============================================================================
425 xoap::MessageReference LogbookSupervisor::MakeSystemLogEntry(xoap::MessageReference msg)
426 {
427  SOAPParameters parameters("EntryText");
428  parameters.addParameter("SubjectText");
429  SOAPUtilities::receive(msg, parameters);
430  std::string EntryText = parameters.getValue("EntryText");
431  std::string SubjectText = parameters.getValue("SubjectText");
432 
433  if(SubjectText == "")
434  SubjectText = "System Log";
435 
436  __COUT__ << "Received External Supervisor System Entry " << EntryText << std::endl;
437  __COUTV__(SubjectText);
438  __COUT__ << "Active Category is " << activeCategory_ << std::endl;
439 
440  std::string retStr = "Success";
441 
442  std::string logPath,
443  logDirPath = (std::string)LOGBOOK_PATH + (std::string)LOGBOOK_LOGBOOKS_PATH +
444  (std::string)LOGBOOK_CATEGORY_DIR_PREFACE + activeCategory_;
445 
446  char dayIndexStr[20];
447  HttpXmlDocument logXml;
448  char fileIndex[40];
449  xercesc::DOMElement* entryEl;
450  DIR* dir;
451 
452  if(activeCategory_ == "")
453  {
454  retStr =
455  "Warning - Currently, no Active Category. Turn off the Logbook XDAQ "
456  "Application to suppress this message.";
457  __COUT__ << retStr << std::endl;
458  goto XOAP_CLEANUP;
459  }
460 
461  // check that directory exists
462  dir = opendir(logDirPath.c_str());
463  if(!dir)
464  {
465  retStr = "Error - Active Category directory missing.";
466  __COUT__ << retStr << std::endl;
467  goto XOAP_CLEANUP;
468  }
469  closedir(dir);
470 
471  sprintf(dayIndexStr, "%6.6lu", time(0) / (60 * 60 * 24)); // get today's index
472 
473  logPath = logDirPath + "/" + LOGBOOK_FILE_PREFACE + activeCategory_ + "_" +
474  (std::string)dayIndexStr + LOGBOOK_FILE_EXTENSION;
475  __COUT__ << "logPath " << logPath << std::endl;
476 
477  logXml.loadXmlDocument(logPath); // NOTE: on failure, no need to do anything
478  // because empty XML file is valid structure
479  // entry structure:
480  // <XML_LOGBOOK_ENTRY>
481  // <XML_LOGBOOK_ENTRY_TIME>
482  // <XML_LOGBOOK_ENTRY_CREATOR>
483  // <XML_LOGBOOK_ENTRY_TEXT>
484  // <XML_LOGBOOK_ENTRY_FILE value=fileType0>
485  // <XML_LOGBOOK_ENTRY_FILE value=fileType1> ...
486  // </XML_LOGBOOK_ENTRY>
487 
488  entryEl = logXml.addTextElementToData(XML_LOGBOOK_ENTRY);
489 
490  sprintf(fileIndex,
491  "%lu_%lu",
492  time(0),
493  clock()); // create unique time label for entry time(0)_clock()
494  logXml.addTextElementToParent(XML_LOGBOOK_ENTRY_TIME, fileIndex, entryEl);
495  logXml.addTextElementToParent(XML_LOGBOOK_ENTRY_CREATOR, "SYSTEM LOG", entryEl);
496  logXml.addTextElementToParent(XML_LOGBOOK_ENTRY_TEXT, EntryText, entryEl);
497  logXml.addTextElementToParent(XML_LOGBOOK_ENTRY_SUBJECT, SubjectText, entryEl);
498 
499  logXml.saveXmlDocument(logPath);
500 
501 XOAP_CLEANUP:
502 
503  // fill return parameters
504  SOAPParameters retParameters("Status", retStr);
505  return SOAPUtilities::makeSOAPMessageReference("SystemLogEntryStatusResponse",
506  retParameters);
507 } //end MakeSystemLogEntry()
508 
518 //{
519 // cgicc::Cgicc cgiIn(in);
520 // std::string src = CgiDataUtilities::getData(cgiIn,"src");
521 // __COUT__ << " Get Log Image " << src << std::endl;
522 // *out << "<!DOCTYPE HTML><html lang='en'><frameset col='100%' row='100%'><frame
523 // src='/WebPath/html/LogbookImage.html?urn=" <<
524 // this->getApplicationDescriptor()->getLocalId() << "&src=" << src <<
525 //"'></frameset></html>";
526 //}
527 //
536 //{
537 // cgicc::Cgicc cgiIn(in);
538 // std::string activeCategory = CgiDataUtilities::getData(cgiIn,"activeCategory");
539 // __COUT__ << " Start Log Report for " << activeCategory << std::endl;
540 // *out << "<!DOCTYPE HTML><html lang='en'><header><title>ots Logbook
541 // Reports</title></header><frameset col='100%' row='100%'><frame
542 // src='/WebPath/html/LogbookReport.html?urn=" <<
543 // this->getApplicationDescriptor()->getLocalId() << "&activeCategory=" <<
544 // activeCategory << "'></frameset></html>";
545 //}
546 
547 //==============================================================================
550 std::string LogbookSupervisor::getActiveCategory()
551 {
552  FILE* fp = fopen(std::string((std::string)ACTIVE_CATEGORY_PATH).c_str(), "r");
553  if(!fp)
554  activeCategory_ = "";
555  else
556  {
557  char line[100];
558  if(!fgets(line, 100, fp))
559  line[0] =
560  '\0'; // if null returned, file is empty and line is untouched, so touch.
561  fclose(fp);
562 
563  // remove \n \r
564  if(line[strlen(line) - 2] == '\r')
565  line[strlen(line) - 2] = '\0';
566  else if(line[strlen(line) - 1] == '\n')
567  line[strlen(line) - 1] = '\0';
568 
569  activeCategory_ = line;
570  }
571 
572  return activeCategory_;
573 } //end getActiveCategory()
574 
575 //==============================================================================
578 void LogbookSupervisor::setActiveCategory(std::string category)
579 {
580  FILE* fp = fopen(std::string((std::string)ACTIVE_CATEGORY_PATH).c_str(), "w");
581  if(!fp)
582  {
583  __COUT__ << "FATAL ERROR!!! - file write" << std::endl;
584  return;
585  }
586 
587  fprintf(fp, "%s", category.c_str());
588  fclose(fp);
589 
590  if(activeCategory_ != "" &&
591  activeCategory_ != category) // old active category is on its way out
592  theRemoteWebUsers_.makeSystemLogEntry(
593  "Category was made inactive."); // make system logbook entry
594 
595  bool entryNeeded = false;
596  if(category != "" &&
597  activeCategory_ != category) // old active category is on its way out
598  entryNeeded = true;
599 
600  activeCategory_ = category;
601  __COUT__ << "Active Category set to " << activeCategory_ << std::endl;
602 
603  if(entryNeeded)
604  theRemoteWebUsers_.makeSystemLogEntry(
605  "Category was made active."); // make system logbook entry
606 } //end setActiveCategory()
607 
608 //==============================================================================
611 bool LogbookSupervisor::validateCategoryName(std::string& exp)
612 {
613  if(exp.length() < CATEGORY_NAME_MIN_LENTH || exp.length() > CATEGORY_NAME_MAX_LENTH)
614  return false;
615  for(int i = 0; i < (int)exp.length(); ++i)
616  if(!((exp[i] >= 'a' && exp[i] <= 'z') || (exp[i] >= 'A' && exp[i] <= 'Z') ||
617  (exp[i] >= '0' && exp[i] <= '9') || (exp[i] == '-' || exp[i] == '_')))
618  {
619  exp = exp.substr(0, i) + exp.substr(i + 1);
620  --i;
621  } // remove illegal chars and rewind i
622 
623  return true;
624 } //end validateCategoryName()
625 
626 //==============================================================================
630 void LogbookSupervisor::getCategories(HttpXmlDocument* xmlOut, std::ostringstream* out)
631 {
632  // check that category listing doesn't already exist
633  HttpXmlDocument expXml;
634  if(!expXml.loadXmlDocument((std::string)LOGBOOK_CATEGORY_LIST_PATH))
635  {
636  __COUT__ << "Fatal Error - Category database." << std::endl;
637  __COUT__ << "Creating empty category database." << std::endl;
638 
639  expXml.addTextElementToData((std::string)XML_CATEGORY_ROOT);
640  expXml.saveXmlDocument((std::string)LOGBOOK_CATEGORY_LIST_PATH);
641  return;
642  }
643 
644  std::vector<std::string> exps;
645  expXml.getAllMatchingValues(XML_CATEGORY, exps);
646 
647  if(xmlOut)
648  xmlOut->addTextElementToData(XML_ACTIVE_CATEGORY, activeCategory_);
649 
650  for(unsigned int i = 0; i < exps.size(); ++i) // loop categories
651  {
652  if(xmlOut)
653  xmlOut->addTextElementToData(XML_CATEGORY, exps[i]);
654  if(out)
655  *out << exps[i] << std::endl;
656  }
657 } //end getCategories()
658 
659 //==============================================================================
661 void LogbookSupervisor::createCategory(std::string category,
662  std::string creator,
663  HttpXmlDocument* xmlOut)
664 {
665  if(!validateCategoryName(category))
666  {
667  if(xmlOut)
668  xmlOut->addTextElementToData(
669  XML_ADMIN_STATUS, "Error - Category name must be 3-25 characters.");
670  return;
671  }
672 
673  __COUT__ << "category " << category << std::endl;
674 
675  // check that directory doesn't already exist
676  std::string dirPath = (std::string)LOGBOOK_PATH + (std::string)LOGBOOK_LOGBOOKS_PATH +
677  (std::string)LOGBOOK_CATEGORY_DIR_PREFACE + category;
678 
679  __COUT__ << "dirPath " << dirPath << std::endl;
680 
681  bool directoryExists = false;
682  DIR* dir = opendir(dirPath.c_str());
683  if(dir)
684  {
685  closedir(dir);
686  directoryExists = true;
687  }
688 
689  // check that category listing doesn't already exist
690  HttpXmlDocument expXml;
691  if(!expXml.loadXmlDocument((std::string)LOGBOOK_CATEGORY_LIST_PATH))
692  {
693  if(xmlOut)
694  xmlOut->addTextElementToData(XML_ADMIN_STATUS,
695  "Fatal Error - Category database.");
696  return;
697  }
698 
699  std::vector<std::string> exps;
700  expXml.getAllMatchingValues(XML_CATEGORY, exps);
701 
702  for(unsigned int i = 0; i < exps.size(); ++i)
703  if(category == exps[i])
704  {
705  if(xmlOut)
706  xmlOut->addTextElementToData(
707  XML_ADMIN_STATUS,
708  "Failed - Category, " + category + ", already exists.");
709  return;
710  }
711  __COUT__ << "categories count: " << exps.size() << std::endl;
712 
713  // everything checks out, add category!
714  // add to categories xml doc and save
715  // <categories>
716  // ...
717  // <category_name = "xx">
718  // <create_time = "##"> <who_created = "aa">
719  xercesc::DOMElement* expEl =
720  expXml.addTextElementToParent(XML_CATEGORY, category, XML_CATEGORY_ROOT);
721  char createTime[20];
722  sprintf(createTime, "%lu", time(0));
723  expXml.addTextElementToParent(XML_CATEGORY_CREATE, createTime, expEl);
724  expXml.addTextElementToParent(XML_CATEGORY_CREATOR, creator, expEl);
725  expXml.saveXmlDocument((std::string)LOGBOOK_CATEGORY_LIST_PATH);
726 
727  // create directory only if doesn't already exist
728  if(directoryExists)
729  {
730  // check uploads folder
731  dirPath += "/" + (std::string)LOGBOOK_UPLOADS_PATH;
732  __COUT__ << "Checking uploads directory" << std::endl;
733 
734  directoryExists = false;
735  dir = opendir(dirPath.c_str());
736  if(!dir) // check if uploads directory exists within category directory
737  {
738  __COUT__ << "Creating uploads directory" << std::endl;
739  if(-1 == mkdir(dirPath.c_str(), 0755)) // make uploads directory
740  {
741  if(xmlOut)
742  xmlOut->addTextElementToData(XML_ADMIN_STATUS,
743  "Failed - uploads directory for " +
744  category + " was not created.");
745  __COUT__ << "Uploads directory failure." << std::endl;
746  return;
747  }
748  }
749  else
750  closedir(dir);
751 
752  xmlOut->addTextElementToData(XML_ADMIN_STATUS,
753  "Directory already exists for " + category +
754  ", re-added to list of categories.");
755  return;
756  }
757  __COUT__ << "Creating category and uploads directory at: " << dirPath << std::endl;
758  if(-1 == mkdir(dirPath.c_str(), 0755) ||
759  -1 == mkdir((dirPath + "/" + (std::string)LOGBOOK_UPLOADS_PATH).c_str(), 0755))
760  {
761  if(xmlOut)
762  xmlOut->addTextElementToData(
763  XML_ADMIN_STATUS,
764  "Failed - directory, " + category + ", could not be created.");
765  return;
766  }
767 
768  if(xmlOut)
769  xmlOut->addTextElementToData(XML_ADMIN_STATUS,
770  "Category, " + category + ", successfully created.");
771 } //end createCategory()
772 
773 //==============================================================================
777 void LogbookSupervisor::webUserSetActiveCategory(std::string category,
778  HttpXmlDocument* xmlOut)
779 {
780  if(category == "") // clear active category
781  {
782  setActiveCategory(category);
783  if(xmlOut)
784  xmlOut->addTextElementToData(XML_ADMIN_STATUS,
785  "Active category cleared successfully.");
786  }
787 
788  // check that category listing exists
789  HttpXmlDocument expXml;
790  if(!expXml.loadXmlDocument((std::string)LOGBOOK_CATEGORY_LIST_PATH))
791  {
792  if(xmlOut)
793  xmlOut->addTextElementToData(XML_ADMIN_STATUS,
794  "Fatal Error - Category database.");
795  return;
796  }
797  std::vector<std::string> exps;
798  expXml.getAllMatchingValues(XML_CATEGORY, exps);
799 
800  unsigned int i;
801  for(i = 0; i < exps.size(); ++i)
802  if(category == exps[i])
803  break;
804 
805  if(i == exps.size()) // not found
806  {
807  if(xmlOut)
808  xmlOut->addTextElementToData(
809  XML_ADMIN_STATUS, "Failed - Category, " + category + ", not found.");
810  return;
811  }
812 
813  // found!
814  setActiveCategory(category);
815  if(xmlOut)
816  xmlOut->addTextElementToData(
817  XML_ADMIN_STATUS, "Active category set to " + category + " successfully.");
818 } //end webUserSetActiveCategory()
819 
820 //==============================================================================
824 void LogbookSupervisor::removeCategory(std::string category,
825  std::string remover,
826  HttpXmlDocument* xmlOut)
827 {
828  __COUT__ << "category " << category << std::endl;
829 
830  // check that category listing exists
831  HttpXmlDocument expXml;
832  if(!expXml.loadXmlDocument((std::string)LOGBOOK_CATEGORY_LIST_PATH))
833  {
834  if(xmlOut)
835  xmlOut->addTextElementToData(XML_ADMIN_STATUS,
836  "Fatal Error - Category database.");
837  return;
838  }
839  std::vector<std::string> exps;
840  expXml.getAllMatchingValues(XML_CATEGORY, exps);
841 
842  unsigned int i;
843  for(i = 0; i < exps.size(); ++i)
844  if(category == exps[i])
845  break;
846 
847  if(i == exps.size()) // not found
848  {
849  if(xmlOut)
850  xmlOut->addTextElementToData(
851  XML_ADMIN_STATUS, "Failed - Category, " + category + ", not found.");
852  return;
853  }
854 
855  // found!
856 
857  // remove category from xml
858  xercesc::DOMElement* parent = expXml.getMatchingElement(XML_CATEGORY_ROOT);
859  xercesc::DOMElement* child = expXml.getMatchingElement(XML_CATEGORY, i);
860  __COUT__ << "categories original count: " << expXml.getChildrenCount(parent)
861  << std::endl;
862  expXml.recursiveRemoveChild(child, parent);
863  __COUT__ << "categories new count: " << expXml.getChildrenCount(parent) << std::endl;
864 
865  // update removed categories log
866  FILE* fp = fopen(((std::string)REMOVE_CATEGORY_LOG_PATH).c_str(), "a");
867  if(!fp)
868  {
869  if(xmlOut)
870  xmlOut->addTextElementToData(XML_ADMIN_STATUS, "Fatal Error - Remove log.");
871  return;
872  }
873  fprintf(fp,
874  "%s -- %s Category removed by %s.\n",
875  asctime(localtime(&((time_t const&)(time(0))))),
876  category.c_str(),
877  remover.c_str());
878  fclose(fp);
879 
880  expXml.saveXmlDocument((std::string)LOGBOOK_CATEGORY_LIST_PATH); // save database
881 
882  // unset from activeCategory_ if is active category
883  if(activeCategory_ == category)
884  setActiveCategory(); // clear active category
885 
886  if(xmlOut)
887  xmlOut->addTextElementToData(XML_ADMIN_STATUS,
888  "Category, " + category + ", successfully removed.");
889 } //end removeCategory()
890 
891 //==============================================================================
897 void LogbookSupervisor::refreshLogbook(time_t date,
898  uint32_t duration,
899  HttpXmlDocument* xmlOut,
900  std::ostringstream* out,
901  std::string category)
902 {
903  if(category == "")
904  category = activeCategory_; // default to active category
905  if(xmlOut)
906  xmlOut->addTextElementToData(XML_ACTIVE_CATEGORY, category); // for success
907 
908  // check that directory exists
909  std::string dirPath = (std::string)LOGBOOK_PATH + (std::string)LOGBOOK_LOGBOOKS_PATH +
910  (std::string)LOGBOOK_CATEGORY_DIR_PREFACE + category;
911 
912  if(out)
913  *out << __COUT_HDR_FL__ << "dirPath " << dirPath << std::endl;
914 
915  DIR* dir = opendir(dirPath.c_str());
916  if(!dir)
917  {
918  if(xmlOut)
919  xmlOut->addTextElementToData(
920  XML_STATUS, "Error - Directory for category, " + category + ", missing.");
921  if(out)
922  *out << __COUT_HDR_FL__ << "Error - Directory missing" << std::endl;
923  return;
924  }
925 
926  unsigned int baseDay;
927 
928  if(!date) // if date is 0 take most recent day and update it
929  {
930  struct dirent* drnt;
931  unsigned int extractedDay;
932  int start, finish; // always find number after last _ and before last .
933 
934  mostRecentDayIndex_ = 0;
935  while((drnt = readdir(dir)))
936  {
937  // if(out) *out << __COUT_HDR_FL__ << "dirContents " << drnt->d_name <<
938  // std::endl;
939 
940  if(strcmp(&(drnt->d_name[strlen(drnt->d_name) - 4]), ".xml"))
941  continue; // skip non logbook files
942 
943  for(finish = strlen(drnt->d_name) - 1; finish > 0; --finish)
944  if(drnt->d_name[finish] == '.')
945  break;
946  if(finish == 0)
947  {
948  if(out)
949  *out << __COUT_HDR_FL__ << "failed to find day index finish "
950  << std::endl;
951  return;
952  }
953  for(start = finish - 1; start > 0; --start)
954  if(drnt->d_name[start - 1] == '_')
955  break;
956  if(start == 0)
957  {
958  if(out)
959  *out << __COUT_HDR_FL__ << "failed to find day index start "
960  << std::endl;
961  return;
962  }
963  drnt->d_name[finish] = '\0';
964  extractedDay = atoi((char*)(&(drnt->d_name[start])));
965  // if(out) *out << __COUT_HDR_FL__ << "dirContents " << (char
966  // *)(&(drnt->d_name[start])) << " " << extractedDay << std::endl;
967  if(!mostRecentDayIndex_ || mostRecentDayIndex_ < extractedDay)
968  mostRecentDayIndex_ = extractedDay;
969  }
970  if(out)
971  *out << __COUT_HDR_FL__
972  << "dirContents done, found most recent day: " << mostRecentDayIndex_
973  << std::endl;
974 
975  baseDay = mostRecentDayIndex_;
976  }
977  else
978  baseDay = (date / (60 * 60 * 24));
979  closedir(dir);
980 
981  std::string entryPath;
982  char dayIndexStr[20];
983  FILE* fp;
984 
985  // read all days selected out
986  // entries are in file as oldest at top, newest at bottom
987  // so read oldest files first to have global ordering of old to new
988  for(uint32_t i = duration; i != 0; --i)
989  {
990  sprintf(dayIndexStr, "%6.6u", baseDay - i + 1); // get day index, back in time
991  entryPath = dirPath + "/" + LOGBOOK_FILE_PREFACE + category + "_" +
992  (std::string)dayIndexStr + LOGBOOK_FILE_EXTENSION;
993 
994  if(out)
995  *out << __COUT_HDR_FL__ << "Directory Entry " << entryPath << std::endl;
996 
997  fp = fopen(entryPath.c_str(), "r");
998  if(!fp)
999  {
1000  if(out)
1001  *out << __COUT_HDR_FL__ << "File not found" << std::endl;
1002  continue;
1003  }
1004  fclose(fp);
1005 
1006  // file found! read file out
1007 
1008  HttpXmlDocument logXml;
1009  if(!logXml.loadXmlDocument(entryPath))
1010  {
1011  if(xmlOut)
1012  xmlOut->addTextElementToData(
1013  XML_STATUS, "Critical Failure - log did not load. Notify admins.");
1014  if(out)
1015  *out << __COUT_HDR_FL__ << "Failure - log XML did not load" << std::endl;
1016  return;
1017  }
1018 
1019  if(xmlOut)
1020  xmlOut->copyDataChildren(logXml); // copy file to output xml
1021  }
1022 
1023  if(xmlOut)
1024  xmlOut->addTextElementToData(XML_STATUS, "1"); // for success
1025  if(out)
1026  *out << __COUT_HDR_FL__ << "Today: " << time(0) / (60 * 60 * 24) << std::endl;
1027 
1028  sprintf(dayIndexStr, "%lu", time(0) / (60 * 60 * 24) - mostRecentDayIndex_);
1029  if(xmlOut)
1030  xmlOut->addTextElementToData(XML_MOST_RECENT_DAY,
1031  dayIndexStr); // send most recent day index
1032 } //end refreshLogbook()
1033 
1034 //==============================================================================
1038 void LogbookSupervisor::cleanUpPreviews()
1039 {
1040  std::string previewPath =
1041  (std::string)LOGBOOK_PATH + (std::string)LOGBOOK_PREVIEWS_PATH;
1042 
1043  DIR* dir = opendir(previewPath.c_str());
1044  if(!dir)
1045  {
1046  __COUT__ << "Error - Previews directory missing: " << previewPath << std::endl;
1047  return;
1048  }
1049 
1050  struct dirent* entry;
1051  time_t dirCreateTime;
1052  unsigned int i;
1053 
1054  while(
1055  (entry = readdir(
1056  dir))) // loop through all entries in directory and remove anything expired
1057  {
1058  if(strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0 &&
1059  strcmp(entry->d_name, ".svn") != 0)
1060  {
1061  // replace _ with space so sscanf works
1062  for(i = 0; i < strlen(entry->d_name); ++i)
1063  if(entry->d_name[i] == '_')
1064  {
1065  entry->d_name[i] = ' ';
1066  break;
1067  }
1068  sscanf(entry->d_name, "%li", &dirCreateTime);
1069 
1070  if((time(0) - dirCreateTime) > LOGBOOK_PREVIEW_EXPIRATION_TIME)
1071  {
1072  __COUT__ << "Expired" << std::endl;
1073 
1074  entry->d_name[i] = '_'; // put _ back
1075 
1076  __COUT__ << "rm -rf " << previewPath + (std::string)entry->d_name
1077  << std::endl
1078  << std::endl;
1079  system(
1080  ((std::string)("rm -rf " + previewPath + (std::string)entry->d_name))
1081  .c_str());
1082  }
1083  }
1084  }
1085 
1086  closedir(dir);
1087 } //end cleanUpPreviews()
1088 
1089 //==============================================================================
1092 void LogbookSupervisor::savePostPreview(std::string& subject,
1093  std::string& text,
1094  const std::vector<cgicc::FormFile>& files,
1095  std::string creator,
1096  HttpXmlDocument* xmlOut)
1097 {
1098  if(activeCategory_ == "") // no active category!
1099  {
1100  if(xmlOut)
1101  xmlOut->addTextElementToData(XML_STATUS,
1102  "Failed - no active category currently!");
1103  return;
1104  }
1105 
1106  char fileIndex[40];
1107  sprintf(fileIndex,
1108  "%lu_%lu",
1109  time(0),
1110  clock()); // create unique time label for entry time(0)_clock()
1111  std::string previewPath = (std::string)LOGBOOK_PATH +
1112  (std::string)LOGBOOK_PREVIEWS_PATH + (std::string)fileIndex;
1113 
1114  __COUT__ << "previewPath " << previewPath << std::endl;
1115  if(-1 == mkdir(previewPath.c_str(), 0755))
1116  {
1117  if(xmlOut)
1118  xmlOut->addTextElementToData(XML_STATUS,
1119  "Failed - preview could not be generated.");
1120  return;
1121  }
1122 
1123  // new directory created successfully, save text and files
1124  // entry structure:
1125  // <XML_LOGBOOK_ENTRY>
1126  // <XML_LOGBOOK_ENTRY_TIME>
1127  // <XML_LOGBOOK_ENTRY_CREATOR>
1128  // <XML_LOGBOOK_ENTRY_SUBJECT>
1129  // <XML_LOGBOOK_ENTRY_TEXT>
1130  // <XML_LOGBOOK_ENTRY_FILE value=fileType0>
1131  // <XML_LOGBOOK_ENTRY_FILE value=fileType1> ...
1132  // </XML_LOGBOOK_ENTRY>
1133 
1134  escapeLogbookEntry(text);
1135  escapeLogbookEntry(subject);
1136  __COUT__ << "~~subject " << subject << std::endl
1137  << "~~text " << text << std::endl
1138  << std::endl;
1139 
1140  HttpXmlDocument previewXml;
1141 
1142  previewXml.addTextElementToData(XML_LOGBOOK_ENTRY);
1143  previewXml.addTextElementToParent(
1144  XML_LOGBOOK_ENTRY_TIME, fileIndex, XML_LOGBOOK_ENTRY);
1145  if(xmlOut)
1146  xmlOut->addTextElementToData(XML_LOGBOOK_ENTRY_TIME, fileIndex); // return time
1147  previewXml.addTextElementToParent(
1148  XML_LOGBOOK_ENTRY_CREATOR, creator, XML_LOGBOOK_ENTRY);
1149  if(xmlOut)
1150  xmlOut->addTextElementToData(XML_LOGBOOK_ENTRY_CREATOR,
1151  creator); // return creator
1152  previewXml.addTextElementToParent(XML_LOGBOOK_ENTRY_TEXT, text, XML_LOGBOOK_ENTRY);
1153  if(xmlOut)
1154  xmlOut->addTextElementToData(XML_LOGBOOK_ENTRY_TEXT, text); // return text
1155  previewXml.addTextElementToParent(
1156  XML_LOGBOOK_ENTRY_SUBJECT, subject, XML_LOGBOOK_ENTRY);
1157  if(xmlOut)
1158  xmlOut->addTextElementToData(XML_LOGBOOK_ENTRY_SUBJECT,
1159  subject); // return subject
1160 
1161  __COUT__ << "file size " << files.size() << std::endl;
1162 
1163  std::string filename;
1164  std::ofstream myfile;
1165  for(unsigned int i = 0; i < files.size(); ++i)
1166  {
1167  previewXml.addTextElementToParent(
1168  XML_LOGBOOK_ENTRY_FILE, files[i].getDataType(), XML_LOGBOOK_ENTRY);
1169  if(xmlOut)
1170  xmlOut->addTextElementToData(XML_LOGBOOK_ENTRY_FILE,
1171  files[i].getDataType()); // return file type
1172 
1173  if((filename = validateUploadFileType(files[i].getDataType())) ==
1174  "") // invalid file type
1175  {
1176  if(xmlOut)
1177  xmlOut->addTextElementToData(
1178  XML_STATUS,
1179  "Failed - invalid file type, " + files[i].getDataType() + ".");
1180  return;
1181  }
1182 
1183  // file validated, so save upload to temp directory
1184  sprintf(fileIndex, "%d", i);
1185  filename = previewPath + "/" + (std::string)LOGBOOK_PREVIEW_UPLOAD_PREFACE +
1186  (std::string)fileIndex + "." + filename;
1187 
1188  __COUT__ << "file " << i << " - " << filename << std::endl;
1189  myfile.open(filename.c_str());
1190  if(myfile.is_open())
1191  {
1192  files[i].writeToStream(myfile);
1193  myfile.close();
1194  }
1195  }
1196 
1197  // save xml doc for preview entry
1198  previewXml.saveXmlDocument(previewPath + "/" + (std::string)LOGBOOK_PREVIEW_FILE);
1199 
1200  if(xmlOut)
1201  xmlOut->addTextElementToData(XML_STATUS, "1"); // 1 indicates success!
1202  if(xmlOut)
1203  xmlOut->addTextElementToData(XML_PREVIEW_INDEX,
1204  "1"); // 1 indicates is a preview post
1205 } //end savePostPreview()
1206 
1207 //==============================================================================
1213 void LogbookSupervisor::movePreviewEntry(std::string previewNumber,
1214  bool approve,
1215  HttpXmlDocument* /*xmlOut*/)
1216 {
1217  __COUT__ << "previewNumber " << previewNumber
1218  << (approve ? " Accepted" : " Cancelled") << std::endl;
1219 
1220  std::string sysCmd, previewPath = (std::string)LOGBOOK_PATH +
1221  (std::string)LOGBOOK_PREVIEWS_PATH + previewNumber;
1222 
1223  if(approve)
1224  {
1225  // move from preview to logbook
1226 
1227  HttpXmlDocument previewXml;
1228  previewXml.loadXmlDocument(previewPath + "/" + (std::string)LOGBOOK_PREVIEW_FILE);
1229 
1230  std::string logPath,
1231  logDirPath = (std::string)LOGBOOK_PATH + (std::string)LOGBOOK_LOGBOOKS_PATH +
1232  (std::string)LOGBOOK_CATEGORY_DIR_PREFACE + activeCategory_;
1233 
1234  // check that directory exists
1235  DIR* dir = opendir(logDirPath.c_str());
1236  if(!dir)
1237  {
1238  __COUT__ << "Error - Active Category directory missing: " << logPath
1239  << std::endl;
1240  return;
1241  }
1242  closedir(dir);
1243 
1244  char dayIndexStr[20];
1245  sprintf(dayIndexStr, "%6.6lu", time(0) / (60 * 60 * 24)); // get today's index
1246 
1247  logPath = logDirPath + "/" + LOGBOOK_FILE_PREFACE + activeCategory_ + "_" +
1248  (std::string)dayIndexStr + LOGBOOK_FILE_EXTENSION;
1249  __COUT__ << "logPath " << logPath << std::endl;
1250 
1251  HttpXmlDocument logXml;
1252  logXml.loadXmlDocument(logPath); // NOTE: on failure, no need to do anything
1253  // because empty XML file is valid structure
1254  // entry structure:
1255  // <XML_LOGBOOK_ENTRY>
1256  // <XML_LOGBOOK_ENTRY_TIME>
1257  // <XML_LOGBOOK_ENTRY_CREATOR>
1258  // <XML_LOGBOOK_ENTRY_TEXT>
1259  // <XML_LOGBOOK_ENTRY_FILE value=fileType0>
1260  // <XML_LOGBOOK_ENTRY_FILE value=fileType1> ...
1261  // </XML_LOGBOOK_ENTRY>
1262 
1263  logXml.copyDataChildren(previewXml); // Copy from previewXML to logXML
1264  logXml.saveXmlDocument(logPath);
1265 
1266  // Move upload files
1267  std::vector<std::string> fileTypes;
1268  previewXml.getAllMatchingValues(XML_LOGBOOK_ENTRY_FILE, fileTypes);
1269  std::string entryTimeLabel = previewXml.getMatchingValue(XML_LOGBOOK_ENTRY_TIME);
1270  std::string fileExtension, previewFilename, logFilename;
1271  char fileIndex[10];
1272  for(unsigned int i = 0; i < fileTypes.size(); ++i)
1273  {
1274  if((fileExtension = validateUploadFileType(fileTypes[i])) ==
1275  "") // invalid file type
1276  {
1277  __COUT__ << "Failed - invalid file type: " << fileTypes[i] << std::endl;
1278  continue;
1279  }
1280 
1281  // file validated, so save upload to temp directory
1282  sprintf(fileIndex, "%d", i);
1283  previewFilename = (std::string)LOGBOOK_PREVIEW_UPLOAD_PREFACE +
1284  (std::string)fileIndex + "." + fileExtension;
1285  logFilename = (std::string)LOGBOOK_PREVIEW_UPLOAD_PREFACE + entryTimeLabel +
1286  "_" + (std::string)fileIndex + "." + fileExtension;
1287 
1288  sysCmd = "mv " + (previewPath + "/" + previewFilename) + " " +
1289  (logDirPath + "/" + (std::string)LOGBOOK_UPLOADS_PATH + logFilename);
1290  __COUT__ << sysCmd << std::endl;
1291  system(sysCmd.c_str());
1292  }
1293  }
1294 
1295  // remove preview directory
1296  sysCmd = "rm -rf " + previewPath;
1297  __COUT__ << sysCmd << std::endl << std::endl;
1298  system(sysCmd.c_str());
1299 } //end movePreviewEntry()
1300 
1301 //==============================================================================
1304 std::string LogbookSupervisor::validateUploadFileType(const std::string fileType)
1305 {
1306  for(unsigned int i = 0; i < allowedFileUploadTypes_.size(); ++i)
1307  if(allowedFileUploadTypes_[i] == fileType)
1308  return matchingFileUploadTypes_[i]; // found and done
1309 
1310  return ""; // not valid, return ""
1311 } //end validateUploadFileType()
1312 
1313 //==============================================================================
1317 void LogbookSupervisor::escapeLogbookEntry(std::string& /*entry*/)
1318 {
1319  // NOTE: should already be taken care of by web gui javascript! do we care to check?
1320 } //end escapeLogbookEntry()
1321 
1322 //==============================================================================
1331 void LogbookSupervisor::hideLogbookEntry(const std::string& entryId,
1332  bool hide,
1333  const std::string& hider)
1334 {
1335  __COUT__ << "Hide=" << hide << " for entryid " << entryId << std::endl;
1336 
1337  // get path to entries file for entry at entryId
1338  char dayIndexStr[20];
1339  unsigned int i;
1340  for(i = 0; i < entryId.length(); ++i)
1341  if(entryId[i] == '_')
1342  {
1343  dayIndexStr[i] = '\0';
1344  break;
1345  }
1346  else
1347  dayIndexStr[i] = entryId[i];
1348  time_t days;
1349  sscanf(dayIndexStr, "%li", &days); // get seconds
1350  days /= 60 * 60 * 24; // get days
1351  sprintf(dayIndexStr, "%6.6lu", days);
1352 
1353  std::string logDirPath = (std::string)LOGBOOK_PATH +
1354  (std::string)LOGBOOK_LOGBOOKS_PATH +
1355  (std::string)LOGBOOK_CATEGORY_DIR_PREFACE + activeCategory_;
1356  std::string logPath = logDirPath + "/" + LOGBOOK_FILE_PREFACE + activeCategory_ +
1357  "_" + (std::string)dayIndexStr + LOGBOOK_FILE_EXTENSION;
1358 
1359  __COUT__ << "logPath=" << logPath << std::endl;
1360 
1361  // locate entry
1362  HttpXmlDocument logXml;
1363  if(!logXml.loadXmlDocument(logPath))
1364  {
1365  __COUT__ << "Failure - log XML did not load" << std::endl;
1366  return;
1367  }
1368 
1369  std::vector<std::string> allEntryIds;
1370  logXml.getAllMatchingValues(XML_LOGBOOK_ENTRY_TIME, allEntryIds);
1371  for(i = 0; i < allEntryIds.size(); ++i)
1372  if(allEntryIds[i] == entryId)
1373  break;
1374  if(i == allEntryIds.size())
1375  {
1376  __COUT__ << "Failure - entry not found" << std::endl;
1377  return;
1378  }
1379 
1380  __COUT__ << "found " << logXml.getMatchingValue(XML_LOGBOOK_ENTRY_TEXT, i)
1381  << std::endl;
1382 
1383  xercesc::DOMElement *hiddenParentEl, *entryParentEl = logXml.getMatchingElement(
1384  XML_LOGBOOK_ENTRY, i); // get entry element
1385 
1386  // check if already hidden
1387  hiddenParentEl =
1388  logXml.getMatchingElementInSubtree(entryParentEl, XML_LOGBOOK_ENTRY_HIDDEN);
1389 
1390  if(hide) // remove entry
1391  {
1392  if(hiddenParentEl)
1393  {
1394  __COUT__ << "Hidden tag already applied to entry." << std::endl;
1395  return;
1396  }
1397  hiddenParentEl = logXml.addTextElementToParent(
1398  XML_LOGBOOK_ENTRY_HIDDEN,
1399  "1",
1400  entryParentEl); // add hidden parent with value "1"
1401  logXml.addTextElementToParent(
1402  XML_LOGBOOK_ENTRY_HIDER, hider, hiddenParentEl); // hider
1403  sprintf(dayIndexStr, "%lu", time(0));
1404  logXml.addTextElementToParent(
1405  XML_LOGBOOK_ENTRY_HIDDEN_TIME, dayIndexStr, hiddenParentEl); // hide time
1406  }
1407  else // restore entry
1408  {
1409  if(!hiddenParentEl)
1410  {
1411  __COUT__ << "Entry already was not hidden." << std::endl;
1412  return;
1413  }
1414 
1415  logXml.recursiveRemoveChild(hiddenParentEl,
1416  entryParentEl); // remove hidden parent
1417  }
1418  logXml.saveXmlDocument(logPath);
1419  __COUT__ << "Success." << std::endl;
1420 } //end hideLogbookEntry()
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