otsdaq_utilities  v2_02_00
LogbookSupervisor.cc
1 #include "otsdaq-utilities/Logbook/LogbookSupervisor.h"
2 //#include "otsdaq-core/MessageFacility/MessageFacility.h"
3 //#include "otsdaq-core/Macros/CoutMacros.h"
4 //#include "otsdaq-core/CgiDataUtilities/CgiDataUtilities.h"
5 //#include "otsdaq-core/XmlUtilities/HttpXmlDocument.h"
6 //#include "otsdaq-core/SOAPUtilities/SOAPUtilities.h"
7 //#include "otsdaq-core/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 
21 const std::string LOGBOOK_PATH = getenv("LOGBOOK_DATA_PATH") + std::string("/");
22 #define LOGBOOK_EXPERIMENT_LIST_PATH LOGBOOK_PATH + "experiment_list.xml"
23 #define LOGBOOK_EXPERIMENT_DIR_PREFACE "log_"
24 #define LOGBOOK_UPLOADS_PATH "uploads/" //within experiment directory
25 #define LOGBOOK_LOGBOOKS_PATH "logbooks/"
26 #define LOGBOOK_PREVIEWS_PATH "previews/"
27 #define LOGBOOK_FILE_PREFACE "entries_"
28 #define LOGBOOK_FILE_EXTENSION ".xml"
29 
30 #define ACTIVE_EXPERIMENT_PATH LOGBOOK_PATH + "active_experiment.txt"
31 #define REMOVE_EXPERIMENT_LOG_PATH LOGBOOK_PATH + "removed_experiments.log"
32 
33 #define XML_ADMIN_STATUS "logbook_admin_status"
34 #define XML_STATUS "logbook_status"
35 #define XML_MOST_RECENT_DAY "most_recent_day"
36 #define XML_EXPERIMENTS_ROOT "experiments"
37 #define XML_EXPERIMENT "experiment"
38 #define XML_ACTIVE_EXPERIMENT "active_experiment"
39 #define XML_EXPERIMENT_CREATE "create_time"
40 #define XML_EXPERIMENT_CREATOR "creator"
41 
42 #define XML_LOGBOOK_ENTRY "logbook_entry"
43 #define XML_LOGBOOK_ENTRY_SUBJECT "logbook_entry_subject"
44 #define XML_LOGBOOK_ENTRY_TEXT "logbook_entry_text"
45 #define XML_LOGBOOK_ENTRY_FILE "logbook_entry_file"
46 #define XML_LOGBOOK_ENTRY_TIME "logbook_entry_time"
47 #define XML_LOGBOOK_ENTRY_CREATOR "logbook_entry_creator"
48 #define XML_LOGBOOK_ENTRY_HIDDEN "logbook_entry_hidden"
49 #define XML_LOGBOOK_ENTRY_HIDER "logbook_entry_hider"
50 #define XML_LOGBOOK_ENTRY_HIDDEN_TIME "logbook_entry_hidden_time"
51 
52 #define XML_PREVIEW_INDEX "preview_index"
53 #define LOGBOOK_PREVIEW_FILE "preview.xml"
54 #define LOGBOOK_PREVIEW_UPLOAD_PREFACE "upload_"
55 
56 XDAQ_INSTANTIATOR_IMPL(LogbookSupervisor)
57 
58 #undef __MF_SUBJECT__
59 #define __MF_SUBJECT__ "Logbook"
60 
61 //========================================================================================================================
62 //sendmail ~~
63 // Helper function to send emails to the subscriber list of the active experiment
64 int sendmail(const char *to, const char *from, const char *subject, const char *message)
65 {
66  int retval = -1;
67  FILE *mailpipe = popen("/usr/lib/sendmail -t", "w");
68  if (mailpipe != NULL) {
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  perror("Failed to invoke sendmail");
79  }
80  return retval;
81 }
82 
83 
84 
85 //========================================================================================================================
86 LogbookSupervisor::LogbookSupervisor(xdaq::ApplicationStub* stub)
87 : CoreSupervisorBase(stub)
88 , allowedFileUploadTypes_({"image/png","image/jpeg","image/gif","image/bmp","application/pdf","application/zip","text/plain"}) //init allowed file upload types
89 , matchingFileUploadTypes_({"png","jpeg","gif","bmp","pdf","zip","txt"}) //init allowed file upload types
90 {
91  INIT_MF("LogbookSupervisor");
92 
93  //xgi::bind (this, &LogbookSupervisor::Default, "Default" );
94  //xgi::bind (this, &LogbookSupervisor::Log, "Log" );
95  //xgi::bind (this, &LogbookSupervisor::LogImage, "LogImage" );
96  //xgi::bind (this, &LogbookSupervisor::LogReport, "LogReport" );
97 
98  xoap::bind(this, &LogbookSupervisor::MakeSystemLogbookEntry, "MakeSystemLogbookEntry" , XDAQ_NS_URI);
99 
100  init();
101 
102  //TODO allow admins to subscribe email addresses to the active experiment
103  //sendmail("rrivera@fnal.gov","ots-instance@otsdaq.fnal.gov","My Subject","Message\nHello!\n\nwhats up.");
104 }
105 
106 //========================================================================================================================
107 LogbookSupervisor::~LogbookSupervisor(void)
108 {
109  destroy();
110 }
111 //========================================================================================================================
112 void LogbookSupervisor::init(void)
113 {
114  //called by constructor
115 // allSupervisorInfo_.init(getApplicationContext());
116 
117 
118  if(1) //check if LOGBOOK_PATH and subpaths event exist?! (if not, attempt to create)
119  {
120  std::string path = LOGBOOK_PATH;
121  DIR *dir = opendir(path.c_str());
122  if(dir)
123  closedir(dir);
124  else if(-1 == mkdir(path.c_str(),0755))
125  {
126  //lets create the service folder (for first time)
127  std::stringstream ss;
128  ss << __COUT_HDR_FL__ << "Service directory creation failed: " <<
129  path << std::endl;
130  __SS_THROW__;
131  }
132 
133  path = LOGBOOK_PATH + LOGBOOK_UPLOADS_PATH;
134  dir = opendir(path.c_str());
135  if(dir)
136  closedir(dir);
137  else if(-1 == mkdir((path).c_str(),0755))
138  {
139  //lets create the service folder (for first time)
140  __SS__ << "Service directory creation failed: " <<
141  path << std::endl;
142  __SS_THROW__;
143  }
144 
145  path = LOGBOOK_PATH + LOGBOOK_LOGBOOKS_PATH;
146  dir = opendir(path.c_str());
147  if(dir)
148  closedir(dir);
149  else if(-1 == mkdir(path.c_str(),0755))
150  {
151  //lets create the service folder (for first time)
152  __SS__ << "Service directory creation failed: " <<
153  path << std::endl;
154  __SS_THROW__;
155  }
156  }
157 
158  getActiveExperiment(); //init active experiment
159  __COUT__ << "Active Experiment is " << activeExperiment_ << std::endl;
160  mostRecentDayIndex_ = 0;
161 
162 }
163 
164 //========================================================================================================================
165 void LogbookSupervisor::destroy(void)
166 {
167  //called by destructor
168 }
169 
170 //========================================================================================================================
171 void LogbookSupervisor::defaultPage(xgi::Input * in, xgi::Output * out )
172 {
173  __COUT__ << " active experiment " << activeExperiment_ << std::endl;
174  *out << "<!DOCTYPE HTML><html lang='en'><frameset col='100%' row='100%'><frame src='/WebPath/html/Logbook.html?urn=" <<
175  this->getApplicationDescriptor()->getLocalId() << "&active_experiment=" << activeExperiment_ << "'></frameset></html>";
176 }
177 
178 
179 //========================================================================================================================
180 //setSupervisorPropertyDefaults
181 // override to set defaults for supervisor property values (before user settings override)
182 void LogbookSupervisor::setSupervisorPropertyDefaults()
183 {
184  CorePropertySupervisorBase::setSupervisorProperty(CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.UserPermissionsThreshold, std::string() +
185  "*=1 | CreateExperiment=-1 | RemoveExperiment=-1 | GetExperimentListAdmin=-1 | SetActiveExperiment=-1" +
186  " | AdminRemoveRestoreEntry=-1");
187 }
188 
189 //========================================================================================================================
190 //forceSupervisorPropertyValues
191 // override to force supervisor property values (and ignore user settings)
192 void LogbookSupervisor::forceSupervisorPropertyValues()
193 {
194  CorePropertySupervisorBase::setSupervisorProperty(CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.AutomatedRequestTypes,
195  "RefreshLogbook");
196  CorePropertySupervisorBase::setSupervisorProperty(CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.NonXMLRequestTypes,
197  "LogImage | LogReport");
198 // CorePropertySupervisorBase::setSupervisorProperty(CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.NeedUsernameRequestTypes,
199 // "CreateExperiment | RemoveExperiment | PreviewEntry | AdminRemoveRestoreEntry");
200 }
201 
202 //========================================================================================================================
203 // request
204 // Handles Web Interface requests to Logbook supervisor.
205 // Does not refresh cookie for automatic update checks.
206 void LogbookSupervisor::request(const std::string& requestType, cgicc::Cgicc& cgiIn,
207  HttpXmlDocument& xmlOut, const WebUsers::RequestUserInfo& userInfo)
208 {
209  //Commands
210  // CreateExperiment
211  // RemoveExperiment
212  // GetExperimentList
213  // SetActiveExperiment
214  // RefreshLogbook
215  // PreviewEntry
216  // ApproveEntry
217  // AdminRemoveRestoreEntr
218 
219 //
220 // cgicc::Cgicc cgiIn(in);
221 // std::string requestType;
222 // if((requestType = CgiDataUtilities::postData(cgiIn,"RequestType")) == "")
223 // requestType = cgiIn("RequestType"); //get command from form, if PreviewEntry
224 //
225 // __COUT__ << "requestType " << requestType << " files: " << cgiIn.getFiles().size() << std::endl;
226 //
227 //
228 // HttpXmlDocument xmlOut;
229 // uint64_t activeSessionIndex;
230 // std::string user;
231 // uint8_t userPermissions;
232 //
233 // //**** start LOGIN GATEWAY CODE ***//
234 // {
235 // bool automaticCommand = requestType == "RefreshLogbook"; //automatic commands should not refresh cookie code.. only user initiated commands should!
236 // bool checkLock = true;
237 // bool getUser = (requestType == "CreateExperiment") || (requestType == "RemoveExperiment") ||
238 // (requestType == "PreviewEntry") || (requestType == "AdminRemoveRestoreEntry");
239 // bool requireLock = false;
240 //
241 // if(!theRemoteWebUsers_.xmlRequestToGateway(
242 // cgiIn,
243 // out,
244 // &xmlOut,
245 // allSupervisorInfo_,
246 // &userPermissions, //acquire user's access level (optionally null pointer)
247 // !automaticCommand, //true/false refresh cookie code
248 // 1, //set access level requirement to pass gateway
249 // checkLock, //true/false enable check that system is unlocked or this user has the lock
250 // requireLock, //true/false requires this user has the lock to proceed
251 // 0,//&userWithLock, //acquire username with lock (optionally null pointer)
252 // (getUser?&user:0) //acquire username of this user (optionally null pointer)
253 // ,0//,&displayName //acquire user's Display Name
254 // ,&activeSessionIndex //acquire user's session index associated with the cookieCode
255 // ))
256 // { //failure
257 // __COUT__ << "Failed Login Gateway: " <<
258 // out->str() << std::endl; //print out return string on failure
259 // return;
260 // }
261 // }
262 // //**** end LOGIN GATEWAY CODE ***//
263 
264 
265  //to report to logbook admin status use xmlOut.addTextElementToData(XML_ADMIN_STATUS,tempStr);
266 
267  if(requestType == "CreateExperiment")
268  {
269  //check that experiment directory does not exist, and it is not in xml list
270  //create experiment
271  //create directory
272  //add to experiments list
273 //
274 // if(userPermissions < ADMIN_PERMISSIONS_THRESHOLD)
275 // {
276 // xmlOut.addTextElementToData(XML_ADMIN_STATUS,"Error - Insufficient permissions.");
277 // goto CLEANUP;
278 // }
279 //
280 // //user is admin
281 //
282 // __COUT__ << "Admin" << std::endl;
283 
284  //get creator name
285  std::string creator = userInfo.username_;
286 
287  createExperiment(CgiDataUtilities::postData(cgiIn,"Experiment"), creator, &xmlOut);
288 
289  __COUT__ << "Created" << std::endl;
290  }
291  else if(requestType == "RemoveExperiment")
292  {
293  //remove from xml list, but do not remove directory (requires manual delete so mistakes aren't made)
294 //
295 // if(userPermissions < ADMIN_PERMISSIONS_THRESHOLD)
296 // {
297 // xmlOut.addTextElementToData(XML_ADMIN_STATUS,"Error - Insufficient permissions.");
298 // goto CLEANUP;
299 // }
300 
301  //get remover name
302  std::string remover = userInfo.username_;
303  removeExperiment(CgiDataUtilities::postData(cgiIn,"Experiment"), remover, &xmlOut);
304  }
305  else if(requestType == "GetExperimentList")
306  {
307  //remove from xml list, but do not remove directory (requires manual delete so mistakes aren't made)
308  if(userInfo.permissionLevel_ >=
309  CoreSupervisorBase::getSupervisorPropertyUserPermissionsThreshold("GetExperimentListAdmin"))
310  {
311  xmlOut.addTextElementToData("is_admin","0"); //indicate not an admin
312  return;
313  }
314  //else
315 
316  xmlOut.addTextElementToData("is_admin","1"); //indicate not an admin
317  getExperiments(&xmlOut);
318  }
319  else if(requestType == "SetActiveExperiment")
320  {
321  //check that experiment exists
322  //set active experiment
323 
324 // if(userPermissions < ADMIN_PERMISSIONS_THRESHOLD)
325 // {
326 // xmlOut.addTextElementToData(XML_ADMIN_STATUS,"Error - Insufficient permissions.");
327 // goto CLEANUP;
328 // }
329 
330  webUserSetActiveExperiment(CgiDataUtilities::postData(cgiIn,"Experiment"), &xmlOut);
331  }
332  else if(requestType == "RefreshLogbook")
333  {
334  //returns logbook for currently active experiment based on date and duration parameters
335 
336  std::string Date = CgiDataUtilities::postData(cgiIn,"Date");
337  std::string Duration = CgiDataUtilities::postData(cgiIn,"Duration");
338 
339  time_t date;
340  unsigned char duration;
341  sscanf(Date.c_str(),"%li",&date); //scan for unsigned long
342  sscanf(Duration.c_str(),"%hhu",&duration); //scan for unsigned char
343 
344  __COUT__ << "date " << date << " duration " << (int)duration << std::endl;
345  std::stringstream str;
346  refreshLogbook(date, duration, &xmlOut, (std::ostringstream *)&str);
347  __COUT__ << str.str() << std::endl;
348  }
349  else if(requestType == "PreviewEntry")
350  {
351  //cleanup temporary folder
352  //NOTE: all input parameters for PreviewEntry will be attached to form
353  // so use cgiIn(xxx) to get values.
354  //increment number for each temporary preview, previewPostTempIndex_
355  //save entry and uploads to previewPath / previewPostTempIndex_ /.
356 
357  cleanUpPreviews();
358  std::string EntryText = cgiIn("EntryText");
359  __COUT__ << "EntryText " << EntryText << std::endl << std::endl;
360  std::string EntrySubject = cgiIn("EntrySubject");
361  __COUT__ << "EntrySubject " << EntrySubject << std::endl << std::endl;
362 
363  //get creator name
364  std::string creator = userInfo.username_;
365 
366  savePostPreview(EntrySubject,EntryText,cgiIn.getFiles(),creator,&xmlOut);
367  //else xmlOut.addTextElementToData(XML_STATUS,"Failed - could not get username info.");
368  }
369  else if(requestType == "ApproveEntry")
370  {
371  //If Approve = "1", then previewed Log entry specified by PreviewNumber
372  // is moved to logbook
373  //Else the specified Log entry is deleted.
374  std::string PreviewNumber = CgiDataUtilities::postData(cgiIn,"PreviewNumber");
375  std::string Approve = CgiDataUtilities::postData(cgiIn,"Approve");
376 
377  movePreviewEntry(PreviewNumber,Approve=="1",&xmlOut);
378  }
379  else if(requestType == "AdminRemoveRestoreEntry")
380  {
381 // if(userPermissions < ADMIN_PERMISSIONS_THRESHOLD)
382 // {
383 // xmlOut.addTextElementToData(XML_ADMIN_STATUS,"Error - Insufficient permissions.");
384 // goto CLEANUP;
385 // }
386 
387  std::string EntryId = CgiDataUtilities::postData(cgiIn,"EntryId");
388  bool Hide = CgiDataUtilities::postData(cgiIn,"Hide")=="1"?true:false;
389 
390  //get creator name
391  std::string hider = userInfo.username_;
392 
393  hideLogbookEntry(EntryId,Hide,hider);
394 
395  xmlOut.addTextElementToData(XML_ADMIN_STATUS,"1"); //success
396  }
397  else
398  __COUT__ << "requestType request not recognized." << std::endl;
399 }
400 
401 //========================================================================================================================
402 // request
403 // Handles Web Interface requests to Logbook supervisor.
404 // Does not refresh cookie for automatic update checks.
405 void LogbookSupervisor::nonXmlRequest(const std::string& requestType, cgicc::Cgicc& cgiIn,
406  std::ostream& out, const WebUsers::RequestUserInfo& userInfo)
407 {
408  //Commands
409  // LogImage
410  // LogReport
411 
412  if(requestType == "LogImage")
413  {
414  std::string src = CgiDataUtilities::getData(cgiIn,"src");
415  __COUT__ << " Get Log Image " << src << std::endl;
416 
417  out << "<!DOCTYPE HTML><html lang='en'><frameset col='100%' row='100%'><frame src='/WebPath/html/LogbookImage.html?urn=" <<
418  this->getApplicationDescriptor()->getLocalId() << "&src=" << src << "'></frameset></html>";
419  }
420  else if(requestType == "LogReport")
421  {
422  std::string activeExperiment = CgiDataUtilities::getData(cgiIn,"activeExperiment");
423  __COUT__ << " Start Log Report for " << activeExperiment << std::endl;
424 
425  out << "<!DOCTYPE HTML><html lang='en'><header><title>ots Logbook Reports</title></header><frameset col='100%' row='100%'><frame src='/WebPath/html/LogbookReport.html?urn=" <<
426  this->getApplicationDescriptor()->getLocalId() << "&activeExperiment=" << activeExperiment << "'></frameset></html>";
427  }
428  else
429  __COUT__ << "requestType request not recognized." << std::endl;
430 }
431 
432 //========================================================================================================================
433 //xoap::MakeSystemLogbookEntry
434 // make a system logbook entry into active experiment's logbook from Supervisor only
435 // TODO: (how to enforce?)
436 xoap::MessageReference LogbookSupervisor::MakeSystemLogbookEntry (xoap::MessageReference msg)
437 {
438  SOAPParameters parameters("EntryText");
439  // SOAPParametersV parameters(1);
440  // parameters[0].setName("EntryText");
441  SOAPUtilities::receive(msg, parameters);
442  std::string EntryText = parameters.getValue("EntryText");
443 
444  __COUT__ << "Received External Supervisor System Entry " << EntryText << std::endl;
445  __COUT__ << "Active Experiment is " << activeExperiment_ << std::endl;
446 
447  std::string retStr = "Success";
448 
449 
450  std::string logPath, logDirPath = (std::string)LOGBOOK_PATH + (std::string)LOGBOOK_LOGBOOKS_PATH +
451  (std::string)LOGBOOK_EXPERIMENT_DIR_PREFACE + activeExperiment_;
452 
453 
454  char dayIndexStr[20];
455  HttpXmlDocument logXml;
456  char fileIndex[40];
457  xercesc::DOMElement* entryEl;
458  DIR *dir;
459 
460  if(activeExperiment_ == "")
461  {
462  retStr = "Warning - Currently, no Active Experiment.";
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 Experiment 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 + activeExperiment_ + "_" + (std::string)dayIndexStr + LOGBOOK_FILE_EXTENSION;
480  __COUT__ << "logPath " << logPath << std::endl;
481 
482  logXml.loadXmlDocument(logPath); //NOTE: on failure, no need to do anything
483  //because empty XML file is valid structure
484  //entry structure:
485  // <XML_LOGBOOK_ENTRY>
486  // <XML_LOGBOOK_ENTRY_TIME>
487  // <XML_LOGBOOK_ENTRY_CREATOR>
488  // <XML_LOGBOOK_ENTRY_TEXT>
489  // <XML_LOGBOOK_ENTRY_FILE value=fileType0>
490  // <XML_LOGBOOK_ENTRY_FILE value=fileType1> ...
491  // </XML_LOGBOOK_ENTRY>
492 
493  entryEl = logXml.addTextElementToData(XML_LOGBOOK_ENTRY);
494 
495  sprintf(fileIndex,"%lu_%lu",time(0),clock()); //create unique time label for entry time(0)_clock()
496  logXml.addTextElementToParent(XML_LOGBOOK_ENTRY_TIME, fileIndex, entryEl);
497  logXml.addTextElementToParent(XML_LOGBOOK_ENTRY_CREATOR, "SYSTEM LOG", entryEl);
498  logXml.addTextElementToParent(XML_LOGBOOK_ENTRY_TEXT, EntryText, entryEl);
499  logXml.addTextElementToParent(XML_LOGBOOK_ENTRY_SUBJECT, "System Log", entryEl);
500 
501  logXml.saveXmlDocument(logPath);
502 
503  XOAP_CLEANUP:
504 
505  //fill return parameters
506  SOAPParameters retParameters("Status",retStr);
507  // SOAPParametersV retParameters(1);
508  // retParameters[0].setName("Status");
509  // retParameters[0].setValue(retStr);
510 
511  return SOAPUtilities::makeSOAPMessageReference("LogbookEntryStatusResponse",retParameters);
512 }
513 
514 //
519 //void LogbookSupervisor::LogImage(xgi::Input * in, xgi::Output * out )
520 //throw (xgi::exception::Exception)
521 //{
522 // cgicc::Cgicc cgiIn(in);
523 // std::string src = CgiDataUtilities::getData(cgiIn,"src");
524 // __COUT__ << " Get Log Image " << src << std::endl;
525 // *out << "<!DOCTYPE HTML><html lang='en'><frameset col='100%' row='100%'><frame src='/WebPath/html/LogbookImage.html?urn=" <<
526 // this->getApplicationDescriptor()->getLocalId() << "&src=" << src << "'></frameset></html>";
527 //}
528 //
535 //void LogbookSupervisor::LogReport(xgi::Input * in, xgi::Output * out )
536 //throw (xgi::exception::Exception)
537 //{
538 // cgicc::Cgicc cgiIn(in);
539 // std::string activeExperiment = CgiDataUtilities::getData(cgiIn,"activeExperiment");
540 // __COUT__ << " Start Log Report for " << activeExperiment << std::endl;
541 // *out << "<!DOCTYPE HTML><html lang='en'><header><title>ots Logbook Reports</title></header><frameset col='100%' row='100%'><frame src='/WebPath/html/LogbookReport.html?urn=" <<
542 // this->getApplicationDescriptor()->getLocalId() << "&activeExperiment=" << activeExperiment << "'></frameset></html>";
543 //}
544 
545 //========================================================================================================================
546 // getActiveExperiment
547 // load active experiment from txt file, must be first line in file
548 std::string LogbookSupervisor::getActiveExperiment()
549 {
550  FILE *fp = fopen(std::string((std::string)ACTIVE_EXPERIMENT_PATH).c_str(),"r");
551  if(!fp) activeExperiment_ = "";
552  else
553  {
554  char line[100];
555  if(!fgets(line,100,fp)) line[0] = '\0'; //if null returned, file is empty and line is untouched, so touch.
556  fclose(fp);
557 
558  //remove \n \r
559  if(line[strlen(line)-2] == '\r')
560  line[strlen(line)-2] = '\0';
561  else if(line[strlen(line)-1] == '\n')
562  line[strlen(line)-1] = '\0';
563 
564  activeExperiment_ = line;
565  }
566 
567  return activeExperiment_;
568 }
569 
570 //========================================================================================================================
571 // setActiveExperiment
572 // "" means no experiment is active
573 void LogbookSupervisor::setActiveExperiment(std::string experiment)
574 {
575  FILE *fp = fopen(std::string((std::string)ACTIVE_EXPERIMENT_PATH).c_str(),"w");
576  if(!fp)
577  {
578  __COUT__ << "FATAL ERROR!!! - file write" << std::endl;
579  return;
580  }
581 
582  fprintf(fp,"%s",experiment.c_str());
583  fclose(fp);
584 
585  if(activeExperiment_ != "" && activeExperiment_ != experiment) //old active experiment is on its way out
586  theRemoteWebUsers_.makeSystemLogbookEntry(
587  allSupervisorInfo_.getGatewayDescriptor(),
588  "Experiment was made inactive."); //make system logbook entry
589 
590  bool entryNeeded = false;
591  if(experiment != "" && activeExperiment_ != experiment) //old active experiment is on its way out
592  entryNeeded = true;
593 
594  activeExperiment_ = experiment;
595  __COUT__ << "Active Experiment set to " << activeExperiment_ << std::endl;
596 
597  if(entryNeeded)
598  theRemoteWebUsers_.makeSystemLogbookEntry(
599  allSupervisorInfo_.getGatewayDescriptor(),
600  "Experiment was made active."); //make system logbook entry
601 
602 }
603 
604 //========================================================================================================================
605 // validateExperimentName
606 // remove all chars that are not alphanumeric, dashes, or underscores
607 bool LogbookSupervisor::validateExperimentName(std::string &exp)
608 {
609  if(exp.length() < EXPERIMENT_NAME_MIN_LENTH || exp.length() > EXPERIMENT_NAME_MAX_LENTH) return false;
610  for(int i=0;i<(int)exp.length();++i)
611  if(!(
612  (exp[i] >= 'a' && exp[i] <= 'z') ||
613  (exp[i] >= 'A' && exp[i] <= 'Z') ||
614  (exp[i] >= '0' && exp[i] <= '9') ||
615  (exp[i] == '-' || exp[i] == '_') ) )
616  { exp = exp.substr(0,i) + exp.substr(i+1); --i; } //remove illegal chars and rewind i
617 
618  return true;
619 }
620 
621 //========================================================================================================================
622 // getExperiments
623 // if xmlOut, then output experiments to xml
624 // if out, then output to stream
625 void LogbookSupervisor::getExperiments(HttpXmlDocument *xmlOut, std::ostringstream *out)
626 {
627  //check that experiment listing doesn't already exist
628  HttpXmlDocument expXml;
629  if(!expXml.loadXmlDocument((std::string)LOGBOOK_EXPERIMENT_LIST_PATH))
630  {
631  __COUT__ << "Fatal Error - Experiment database." << std::endl;
632  __COUT__ << "Creating empty experiment database." << std::endl;
633 
634  expXml.addTextElementToData((std::string)XML_EXPERIMENTS_ROOT);
635  expXml.saveXmlDocument((std::string)LOGBOOK_EXPERIMENT_LIST_PATH);
636  return;
637  }
638 
639  std::vector<std::string> exps;
640  expXml.getAllMatchingValues(XML_EXPERIMENT,exps);
641 
642  if(xmlOut) xmlOut->addTextElementToData(XML_ACTIVE_EXPERIMENT, activeExperiment_);
643 
644  for(unsigned int i=0;i<exps.size();++i) //loop experiments
645  {
646  if(xmlOut) xmlOut->addTextElementToData(XML_EXPERIMENT, exps[i]);
647  if(out) *out << exps[i] << std::endl;
648  }
649 }
650 
651 //========================================================================================================================
652 // createExperiment
653 void LogbookSupervisor::createExperiment(std::string experiment, std::string creator, HttpXmlDocument *xmlOut)
654 {
655  if(!validateExperimentName(experiment))
656  {
657  if(xmlOut) xmlOut->addTextElementToData(XML_ADMIN_STATUS,"Error - Experiment name must be 3-25 characters.");
658  return;
659  }
660 
661  __COUT__ << "experiment " << experiment << std::endl;
662 
663  //check that directory doesn't already exist
664  std::string dirPath = (std::string)LOGBOOK_PATH + (std::string)LOGBOOK_LOGBOOKS_PATH +
665  (std::string)LOGBOOK_EXPERIMENT_DIR_PREFACE + experiment;
666 
667  __COUT__ << "dirPath " << dirPath << std::endl;
668 
669  bool directoryExists = false;
670  DIR *dir = opendir(dirPath.c_str());
671  if(dir)
672  {
673  closedir(dir);
674  directoryExists = true;
675  }
676 
677  //check that experiment listing doesn't already exist
678  HttpXmlDocument expXml;
679  if(!expXml.loadXmlDocument((std::string)LOGBOOK_EXPERIMENT_LIST_PATH))
680  {
681  if(xmlOut) xmlOut->addTextElementToData(XML_ADMIN_STATUS,"Fatal Error - Experiment database.");
682  return;
683  }
684 
685  std::vector<std::string> exps;
686  expXml.getAllMatchingValues(XML_EXPERIMENT,exps);
687 
688  for(unsigned int i=0;i<exps.size();++i)
689  if(experiment == exps[i])
690  {
691  if(xmlOut) xmlOut->addTextElementToData(XML_ADMIN_STATUS,"Failed - Experiment, " + experiment + ", already exists.");
692  return;
693  }
694  __COUT__ << "experiments count: " << exps.size() << std::endl;
695 
696 
697  //everything checks out, add experiment!
698  //add to experiments xml doc and save
699  // <experiments>
700  // ...
701  // <experiment_name = "xx">
702  // <create_time = "##"> <who_created = "aa">
703  xercesc::DOMElement* expEl = expXml.addTextElementToParent(XML_EXPERIMENT, experiment, XML_EXPERIMENTS_ROOT);
704  char createTime[20];
705  sprintf(createTime,"%lu",time(0));
706  expXml.addTextElementToParent(XML_EXPERIMENT_CREATE, createTime, expEl);
707  expXml.addTextElementToParent(XML_EXPERIMENT_CREATOR, creator, expEl);
708  expXml.saveXmlDocument((std::string)LOGBOOK_EXPERIMENT_LIST_PATH);
709 
710  //create directory only if doesn't already exist
711  if(directoryExists)
712  {
713 
714  //check uploads folder
715  dirPath += "/" + (std::string)LOGBOOK_UPLOADS_PATH;
716  __COUT__ << "Checking uploads directory" << std::endl;
717 
718  directoryExists = false;
719  dir = opendir(dirPath.c_str());
720  if(!dir) //check if uploads directory exists within experiment directory
721  {
722  __COUT__ << "Creating uploads directory" << std::endl;
723  if(-1 == mkdir(dirPath.c_str(),0755)) //make uploads directory
724  {
725  if(xmlOut) xmlOut->addTextElementToData(XML_ADMIN_STATUS,"Failed - uploads directory for " + experiment + " was not created.");
726  __COUT__ << "Uploads directory failure." << std::endl;
727  return;
728  }
729  }
730  else
731  closedir(dir);
732 
733  xmlOut->addTextElementToData(XML_ADMIN_STATUS,"Directory already exists for " + experiment +
734  ", re-added to list of experiments.");
735  return;
736  }
737  __COUT__ << "Creating experiment and uploads directory at: " <<
738  dirPath << std::endl;
739  if(-1 == mkdir(dirPath.c_str(),0755) ||
740  -1 == mkdir((dirPath + "/" +
741  (std::string)LOGBOOK_UPLOADS_PATH).c_str(),0755))
742  {
743  if(xmlOut) xmlOut->addTextElementToData(XML_ADMIN_STATUS,"Failed - directory, " + experiment + ", could not be created.");
744  return;
745  }
746 
747  if(xmlOut) xmlOut->addTextElementToData(XML_ADMIN_STATUS,"Experiment, " + experiment + ", successfully created.");
748 }
749 
750 //========================================================================================================================
751 // webUserSetActiveExperiment
752 // if experiment exists, set as active
753 // to clear active experiment set to ""
754 void LogbookSupervisor::webUserSetActiveExperiment(std::string experiment, HttpXmlDocument *xmlOut)
755 {
756  if(experiment == "") //clear active experiment
757  {
758  setActiveExperiment(experiment);
759  if(xmlOut) xmlOut->addTextElementToData(XML_ADMIN_STATUS,"Active experiment cleared successfully.");
760  }
761 
762  //check that experiment listing exists
763  HttpXmlDocument expXml;
764  if(!expXml.loadXmlDocument((std::string)LOGBOOK_EXPERIMENT_LIST_PATH))
765  {
766  if(xmlOut) xmlOut->addTextElementToData(XML_ADMIN_STATUS,"Fatal Error - Experiment database.");
767  return;
768  }
769  std::vector<std::string> exps;
770  expXml.getAllMatchingValues(XML_EXPERIMENT,exps);
771 
772  unsigned int i;
773  for(i=0;i<exps.size();++i)
774  if(experiment == exps[i]) break;
775 
776  if(i == exps.size()) //not found
777  {
778  if(xmlOut) xmlOut->addTextElementToData(XML_ADMIN_STATUS,"Failed - Experiment, " + experiment + ", not found.");
779  return;
780  }
781 
782  //found!
783  setActiveExperiment(experiment);
784  if(xmlOut) xmlOut->addTextElementToData(XML_ADMIN_STATUS,"Active experiment set to " + experiment + " successfully.");
785 }
786 
787 //========================================================================================================================
788 // removeExperiment
789 // remove experiment from listing only (do NOT remove logbook data directory)
790 // record remover in log file REMOVE_EXPERIMENT_LOG_PATH
791 void LogbookSupervisor::removeExperiment(std::string experiment, std::string remover, HttpXmlDocument *xmlOut)
792 {
793  __COUT__ << "experiment " << experiment << std::endl;
794 
795  //check that experiment listing exists
796  HttpXmlDocument expXml;
797  if(!expXml.loadXmlDocument((std::string)LOGBOOK_EXPERIMENT_LIST_PATH))
798  {
799  if(xmlOut) xmlOut->addTextElementToData(XML_ADMIN_STATUS,"Fatal Error - Experiment database.");
800  return;
801  }
802  std::vector<std::string> exps;
803  expXml.getAllMatchingValues(XML_EXPERIMENT,exps);
804 
805  unsigned int i;
806  for(i=0;i<exps.size();++i)
807  if(experiment == exps[i]) break;
808 
809  if(i == exps.size()) //not found
810  {
811  if(xmlOut) xmlOut->addTextElementToData(XML_ADMIN_STATUS,"Failed - Experiment, " + experiment + ", not found.");
812  return;
813  }
814 
815  //found!
816 
817  //remove experiment from xml
818  xercesc::DOMElement* parent = expXml.getMatchingElement(XML_EXPERIMENTS_ROOT);
819  xercesc::DOMElement* child = expXml.getMatchingElement(XML_EXPERIMENT,i);
820  __COUT__ << "experiments original count: " << expXml.getChildrenCount(parent) << std::endl;
821  expXml.recursiveRemoveChild(child, parent);
822  __COUT__ << "experiments new count: " << expXml.getChildrenCount(parent) << std::endl;
823 
824  //update removed experiments log
825  FILE *fp = fopen(((std::string)REMOVE_EXPERIMENT_LOG_PATH).c_str(),"a");
826  if(!fp)
827  {
828  if(xmlOut) xmlOut->addTextElementToData(XML_ADMIN_STATUS,"Fatal Error - Remove log.");
829  return;
830  }
831  fprintf(fp,"%s -- %s Experiment removed by %s.\n",asctime(localtime(&((time_t const&)(time(0))))),
832  experiment.c_str(), remover.c_str());
833  fclose(fp);
834 
835  expXml.saveXmlDocument((std::string)LOGBOOK_EXPERIMENT_LIST_PATH); //save database
836 
837  //unset from activeExperiment_ if is active experiment
838  if(activeExperiment_ == experiment)
839  setActiveExperiment(); //clear active experiment
840 
841  if(xmlOut) xmlOut->addTextElementToData(XML_ADMIN_STATUS,"Experiment, " + experiment + ", successfully removed.");
842 }
843 
844 //========================================================================================================================
845 // refreshLogbook
846 // returns all the logbook data for active experiment from starting date and back in time for
847 // duration total number of days.
848 // e.g. data = today, and duration = 1 returns logbook for today from active experiment
849 // The entries are returns from oldest to newest
850 void LogbookSupervisor::refreshLogbook(time_t date, unsigned char duration,
851  HttpXmlDocument *xmlOut, std::ostringstream *out, std::string experiment)
852 {
853  if(experiment == "") experiment = activeExperiment_; //default to active experiment
854  if(xmlOut) xmlOut->addTextElementToData(XML_ACTIVE_EXPERIMENT,experiment); //for success
855 
856  //check that directory exists
857  std::string dirPath = (std::string)LOGBOOK_PATH + (std::string)LOGBOOK_LOGBOOKS_PATH +
858  (std::string)LOGBOOK_EXPERIMENT_DIR_PREFACE + experiment;
859 
860  if(out) *out << __COUT_HDR_FL__ << "dirPath " << dirPath << std::endl;
861 
862  DIR *dir = opendir(dirPath.c_str());
863  if(!dir)
864  {
865  if(xmlOut) xmlOut->addTextElementToData(XML_STATUS,"Error - Directory for experiment, " + experiment + ", missing.");
866  if(out) *out << __COUT_HDR_FL__ << "Error - Directory missing" << std::endl;
867  return;
868  }
869 
870  unsigned int baseDay;
871 
872  if(!date) //if date is 0 take most recent day and update it
873  {
874  struct dirent *drnt;
875  unsigned int extractedDay;
876  int start, finish; //always find number after last _ and before last .
877 
878  mostRecentDayIndex_ = 0;
879  while ((drnt=readdir(dir))){
880  //if(out) *out << __COUT_HDR_FL__ << "dirContents " << drnt->d_name << std::endl;
881 
882  if(strcmp(&(drnt->d_name[strlen(drnt->d_name)-4]),".xml")) continue; //skip non logbook files
883 
884  for(finish=strlen(drnt->d_name)-1;finish>0;--finish)
885  if(drnt->d_name[finish] == '.') break;
886  if(finish == 0)
887  {
888  if(out) *out << __COUT_HDR_FL__ << "failed to find day index finish " << std::endl;
889  return;
890  }
891  for(start=finish-1;start>0;--start)
892  if(drnt->d_name[start-1] == '_') break;
893  if(start == 0)
894  {
895  if(out) *out << __COUT_HDR_FL__ << "failed to find day index start " << std::endl;
896  return;
897  }
898  drnt->d_name[finish] = '\0';
899  extractedDay = atoi((char *)(&(drnt->d_name[start])));
900  //if(out) *out << __COUT_HDR_FL__ << "dirContents " << (char *)(&(drnt->d_name[start])) << " " << extractedDay << std::endl;
901  if(!mostRecentDayIndex_ || mostRecentDayIndex_ < extractedDay) mostRecentDayIndex_ = extractedDay;
902  }
903  if(out) *out << __COUT_HDR_FL__ << "dirContents done, found most recent day: " << mostRecentDayIndex_ << std::endl;
904 
905  baseDay = mostRecentDayIndex_;
906  }
907  else
908  baseDay = (date/(60*60*24));
909  closedir(dir);
910 
911  std::string entryPath;
912  char dayIndexStr[20];
913  FILE *fp;
914 
915  //read all days selected out
916  // entries are in file as oldest at top, newest at bottom
917  // so read oldest files first to have global ordering of old to new
918  for(unsigned char i=duration;i!=0;--i)
919  {
920  sprintf(dayIndexStr,"%6.6u",baseDay-i+1); //get day index, back in time
921  entryPath = dirPath + "/" + LOGBOOK_FILE_PREFACE + experiment + "_" + (std::string)dayIndexStr + LOGBOOK_FILE_EXTENSION;
922 
923  if(out) *out << __COUT_HDR_FL__ << "Directory Entry " << entryPath << std::endl;
924 
925  fp = fopen(entryPath.c_str(),"r");
926  if(!fp)
927  {
928  if(out) *out << __COUT_HDR_FL__ << "File not found" << std::endl;
929  continue;
930  }
931  fclose(fp);
932 
933  //file found! read file out
934 
935  HttpXmlDocument logXml;
936  if(!logXml.loadXmlDocument(entryPath))
937  {
938  if(xmlOut) xmlOut->addTextElementToData(XML_STATUS,"Critical Failure - log did not load. Notify admins.");
939  if(out) *out << __COUT_HDR_FL__ << "Failure - log XML did not load" << std::endl;
940  return;
941  }
942 
943  if(xmlOut) xmlOut->copyDataChildren(logXml); //copy file to output xml
944  }
945 
946  if(xmlOut) xmlOut->addTextElementToData(XML_STATUS,"1"); //for success
947  if(out) *out << __COUT_HDR_FL__ << "Today: " << time(0)/(60*60*24) << std::endl;
948 
949  sprintf(dayIndexStr,"%lu",time(0)/(60*60*24) - mostRecentDayIndex_);
950  if(xmlOut) xmlOut->addTextElementToData(XML_MOST_RECENT_DAY,dayIndexStr); //send most recent day index
951 }
952 
953 //========================================================================================================================
954 // cleanUpPreviews
955 // cleanup logbook preview directory
956 // all names have time_t creation time + "_" + incremented index
957 void LogbookSupervisor::cleanUpPreviews()
958 {
959  std::string previewPath = (std::string)LOGBOOK_PATH + (std::string)LOGBOOK_PREVIEWS_PATH;
960 
961  DIR *dir = opendir(previewPath.c_str());
962  if(!dir)
963  {
964  __COUT__ << "Error - Previews directory missing: " << previewPath << std::endl;
965  return;
966  }
967 
968  struct dirent *entry;
969  time_t dirCreateTime;
970  unsigned int i;
971 
972  while((entry = readdir(dir))) //loop through all entries in directory and remove anything expired
973  {
974  if( strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0
975  && strcmp(entry->d_name, ".svn") != 0 )
976  {
977  //replace _ with space so sscanf works
978  for(i=0;i<strlen(entry->d_name);++i)
979  if(entry->d_name[i] == '_')
980  { entry->d_name[i] = ' '; break; }
981  sscanf(entry->d_name,"%li",&dirCreateTime);
982 
983  if((time(0) - dirCreateTime) > LOGBOOK_PREVIEW_EXPIRATION_TIME)
984  {
985  __COUT__ << "Expired" << std::endl;
986 
987  entry->d_name[i] = '_'; //put _ back
988 
989  __COUT__ << "rm -rf " << previewPath + (std::string)entry->d_name << std::endl << std::endl;
990  system(((std::string)("rm -rf " + previewPath + (std::string)entry->d_name)).c_str());
991  }
992  }
993  }
994 
995  closedir(dir);
996 }
997 
998 
999 //========================================================================================================================
1000 // savePostPreview
1001 // save post to preview directory named with time and incremented index
1002 void LogbookSupervisor::savePostPreview(std::string &subject, std::string &text, const std::vector<cgicc::FormFile> &files, std::string creator,
1003  HttpXmlDocument *xmlOut)
1004 {
1005  if(activeExperiment_ == "") //no active experiment!
1006  {
1007  if(xmlOut) xmlOut->addTextElementToData(XML_STATUS,"Failed - no active experiment currently!");
1008  return;
1009  }
1010 
1011  char fileIndex[40];
1012  sprintf(fileIndex,"%lu_%lu",time(0),clock()); //create unique time label for entry time(0)_clock()
1013  std::string previewPath = (std::string)LOGBOOK_PATH + (std::string)LOGBOOK_PREVIEWS_PATH + (std::string)fileIndex;
1014 
1015  __COUT__ << "previewPath " << previewPath << std::endl;
1016  if(-1 == mkdir(previewPath.c_str(),0755))
1017  {
1018  if(xmlOut) xmlOut->addTextElementToData(XML_STATUS,"Failed - preview could not be generated.");
1019  return;
1020  }
1021 
1022  //new directory created successfully, save text and files
1023  //entry structure:
1024  // <XML_LOGBOOK_ENTRY>
1025  // <XML_LOGBOOK_ENTRY_TIME>
1026  // <XML_LOGBOOK_ENTRY_CREATOR>
1027  // <XML_LOGBOOK_ENTRY_SUBJECT>
1028  // <XML_LOGBOOK_ENTRY_TEXT>
1029  // <XML_LOGBOOK_ENTRY_FILE value=fileType0>
1030  // <XML_LOGBOOK_ENTRY_FILE value=fileType1> ...
1031  // </XML_LOGBOOK_ENTRY>
1032 
1033  escapeLogbookEntry(text);
1034  escapeLogbookEntry(subject);
1035  __COUT__ << "~~subject " << subject << std::endl << "~~text " << text << std::endl << std::endl;
1036 
1037  HttpXmlDocument previewXml;
1038 
1039  previewXml.addTextElementToData(XML_LOGBOOK_ENTRY);
1040  previewXml.addTextElementToParent(XML_LOGBOOK_ENTRY_TIME, fileIndex, XML_LOGBOOK_ENTRY);
1041  if(xmlOut) xmlOut->addTextElementToData(XML_LOGBOOK_ENTRY_TIME,fileIndex); //return time
1042  previewXml.addTextElementToParent(XML_LOGBOOK_ENTRY_CREATOR, creator, XML_LOGBOOK_ENTRY);
1043  if(xmlOut) xmlOut->addTextElementToData(XML_LOGBOOK_ENTRY_CREATOR,creator); //return creator
1044  previewXml.addTextElementToParent(XML_LOGBOOK_ENTRY_TEXT, text, XML_LOGBOOK_ENTRY);
1045  if(xmlOut) xmlOut->addTextElementToData(XML_LOGBOOK_ENTRY_TEXT,text); //return text
1046  previewXml.addTextElementToParent(XML_LOGBOOK_ENTRY_SUBJECT, subject, XML_LOGBOOK_ENTRY);
1047  if(xmlOut) xmlOut->addTextElementToData(XML_LOGBOOK_ENTRY_SUBJECT,subject); //return subject
1048 
1049  __COUT__ << "file size " << files.size() << std::endl;
1050 
1051  std::string filename;
1052  std::ofstream myfile;
1053  for (unsigned int i=0; i<files.size(); ++i)
1054  {
1055 
1056  previewXml.addTextElementToParent(XML_LOGBOOK_ENTRY_FILE, files[i].getDataType(), XML_LOGBOOK_ENTRY);
1057  if(xmlOut) xmlOut->addTextElementToData(XML_LOGBOOK_ENTRY_FILE,files[i].getDataType()); //return file type
1058 
1059  if((filename = validateUploadFileType(files[i].getDataType())) == "") //invalid file type
1060  {
1061  if(xmlOut) xmlOut->addTextElementToData(XML_STATUS,"Failed - invalid file type, " +
1062  files[i].getDataType() + ".");
1063  return;
1064  }
1065 
1066  //file validated, so save upload to temp directory
1067  sprintf(fileIndex,"%d",i);
1068  filename = previewPath + "/" + (std::string)LOGBOOK_PREVIEW_UPLOAD_PREFACE +
1069  (std::string)fileIndex + "." + filename;
1070 
1071  __COUT__ << "file " << i << " - " << filename << std::endl;
1072  myfile.open(filename.c_str());
1073  if (myfile.is_open())
1074  {
1075  files[i].writeToStream(myfile);
1076  myfile.close();
1077  }
1078  }
1079 
1080  //save xml doc for preview entry
1081  previewXml.saveXmlDocument(previewPath + "/" + (std::string)LOGBOOK_PREVIEW_FILE);
1082 
1083  if(xmlOut) xmlOut->addTextElementToData(XML_STATUS,"1"); //1 indicates success!
1084  if(xmlOut) xmlOut->addTextElementToData(XML_PREVIEW_INDEX,"1"); //1 indicates is a preview post
1085 }
1086 
1087 //========================================================================================================================
1088 // movePreviewEntry
1089 // if approve
1090 // move entry to current active logbook
1091 // if not approve
1092 // delete directory
1093 void LogbookSupervisor::movePreviewEntry(std::string previewNumber, bool approve,
1094  HttpXmlDocument *xmlOut)
1095 {
1096 
1097  __COUT__ << "previewNumber " << previewNumber << (approve?" Accepted":" Cancelled") << std::endl;
1098 
1099  std::string sysCmd, previewPath = (std::string)LOGBOOK_PATH + (std::string)LOGBOOK_PREVIEWS_PATH + previewNumber;
1100 
1101  if (approve) {
1102  //move from preview to logbook
1103 
1104  HttpXmlDocument previewXml;
1105  previewXml.loadXmlDocument(previewPath + "/" + (std::string)LOGBOOK_PREVIEW_FILE);
1106 
1107  std::string logPath, logDirPath = (std::string)LOGBOOK_PATH + (std::string)LOGBOOK_LOGBOOKS_PATH +
1108  (std::string)LOGBOOK_EXPERIMENT_DIR_PREFACE + activeExperiment_;
1109 
1110  //check that directory exists
1111  DIR *dir = opendir(logDirPath.c_str());
1112  if(!dir)
1113  {
1114  __COUT__ << "Error - Active Experiment directory missing: " << logPath << std::endl;
1115  return;
1116  }
1117  closedir(dir);
1118 
1119  char dayIndexStr[20];
1120  sprintf(dayIndexStr,"%6.6lu",time(0)/(60*60*24)); //get today's index
1121 
1122  logPath = logDirPath + "/" + LOGBOOK_FILE_PREFACE + activeExperiment_ + "_" + (std::string)dayIndexStr + LOGBOOK_FILE_EXTENSION;
1123  __COUT__ << "logPath " << logPath << std::endl;
1124 
1125  HttpXmlDocument logXml;
1126  logXml.loadXmlDocument(logPath); //NOTE: on failure, no need to do anything
1127  //because empty XML file is valid structure
1128  //entry structure:
1129  // <XML_LOGBOOK_ENTRY>
1130  // <XML_LOGBOOK_ENTRY_TIME>
1131  // <XML_LOGBOOK_ENTRY_CREATOR>
1132  // <XML_LOGBOOK_ENTRY_TEXT>
1133  // <XML_LOGBOOK_ENTRY_FILE value=fileType0>
1134  // <XML_LOGBOOK_ENTRY_FILE value=fileType1> ...
1135  // </XML_LOGBOOK_ENTRY>
1136 
1137  logXml.copyDataChildren(previewXml); //Copy from previewXML to logXML
1138  logXml.saveXmlDocument(logPath);
1139 
1140  //Move upload files
1141  std::vector<std::string> fileTypes;
1142  previewXml.getAllMatchingValues(XML_LOGBOOK_ENTRY_FILE,fileTypes);
1143  std::string entryTimeLabel = previewXml.getMatchingValue(XML_LOGBOOK_ENTRY_TIME);
1144  std::string fileExtension, previewFilename, logFilename;
1145  char fileIndex[10];
1146  for(unsigned int i=0;i<fileTypes.size();++i)
1147  {
1148  if((fileExtension = validateUploadFileType(fileTypes[i])) == "") //invalid file type
1149  {
1150  __COUT__ << "Failed - invalid file type: " << fileTypes[i] << std::endl;
1151  continue;
1152  }
1153 
1154  //file validated, so save upload to temp directory
1155  sprintf(fileIndex,"%d",i);
1156  previewFilename = (std::string)LOGBOOK_PREVIEW_UPLOAD_PREFACE + (std::string)fileIndex + "." + fileExtension;
1157  logFilename = (std::string)LOGBOOK_PREVIEW_UPLOAD_PREFACE + entryTimeLabel + "_" +
1158  (std::string)fileIndex + "." + fileExtension;
1159 
1160  sysCmd = "mv " + (previewPath + "/" + previewFilename) + " " +
1161  (logDirPath + "/" + (std::string)LOGBOOK_UPLOADS_PATH + logFilename);
1162  __COUT__ << sysCmd << std::endl;
1163  system(sysCmd.c_str());
1164  }
1165  }
1166 
1167  //remove preview directory
1168  sysCmd = "rm -rf " + previewPath;
1169  __COUT__ << sysCmd << std::endl << std::endl;
1170  system(sysCmd.c_str());
1171 }
1172 
1173 //========================================================================================================================
1174 // validateUploadFileType
1175 // returns "" if file type is invalide, else returns file extension to use
1176 std::string LogbookSupervisor::validateUploadFileType(const std::string fileType)
1177 {
1178  for (unsigned int i=0; i<allowedFileUploadTypes_.size(); ++i)
1179  if (allowedFileUploadTypes_[i] == fileType)
1180  return matchingFileUploadTypes_[i]; //found and done
1181 
1182  return ""; //not valid, return ""
1183 }
1184 
1185 //========================================================================================================================
1186 // escapeLogbookEntry
1187 // replace html/xhtml reserved characters with equivalent.
1188 // reserved: ", ', &, <, >, \n, double-space
1189 void LogbookSupervisor::escapeLogbookEntry(std::string &entry)
1190 {
1191  //NOTE: should already be taken care of by web gui javascript! do we care to check?
1192 
1193 }
1194 
1195 //========================================================================================================================
1196 // hideLogbookEntry
1197 // NOTE: does not actually delete entry, just marks as hidden
1198 // removes/restores logbook entry. Requires admin priveleges
1199 // Locates the entry within the active experiment and if hide
1200 // appends xml fields:
1201 // XML_LOGBOOK_ENTRY_HIDDEN
1202 // XML_LOGBOOK_ENTRY_HIDER
1203 // XML_LOGBOOK_ENTRY_HIDDEN_TIME
1204 void LogbookSupervisor::hideLogbookEntry(const std::string &entryId, bool hide,const std::string &hider)
1205 {
1206  __COUT__ << "Hide=" << hide << " for entryid " << entryId << std::endl;
1207 
1208  //get path to entries file for entry at entryId
1209  char dayIndexStr[20];
1210  unsigned int i;
1211  for(i=0;i<entryId.length();++i)
1212  if(entryId[i] == '_') { dayIndexStr[i] = '\0'; break;}
1213  else
1214  dayIndexStr[i] = entryId[i];
1215  time_t days;
1216  sscanf(dayIndexStr,"%li",&days); //get seconds
1217  days /= 60*60*24; //get days
1218  sprintf(dayIndexStr,"%6.6lu",days);
1219 
1220  std::string logDirPath = (std::string)LOGBOOK_PATH + (std::string)LOGBOOK_LOGBOOKS_PATH +
1221  (std::string)LOGBOOK_EXPERIMENT_DIR_PREFACE + activeExperiment_;
1222  std::string logPath = logDirPath + "/" + LOGBOOK_FILE_PREFACE + activeExperiment_ + "_" + (std::string)dayIndexStr + LOGBOOK_FILE_EXTENSION;
1223 
1224  __COUT__ << "logPath=" << logPath << std::endl;
1225 
1226  //locate entry
1227  HttpXmlDocument logXml;
1228  if(!logXml.loadXmlDocument(logPath))
1229  {
1230  __COUT__ << "Failure - log XML did not load" << std::endl;
1231  return;
1232  }
1233 
1234  std::vector<std::string> allEntryIds;
1235  logXml.getAllMatchingValues(XML_LOGBOOK_ENTRY_TIME,allEntryIds);
1236  for(i=0;i<allEntryIds.size();++i)
1237  if(allEntryIds[i] == entryId) break;
1238  if(i == allEntryIds.size())
1239  {
1240  __COUT__ << "Failure - entry not found" << std::endl;
1241  return;
1242  }
1243 
1244  __COUT__ << "found " << logXml.getMatchingValue(XML_LOGBOOK_ENTRY_TEXT,i) << std::endl;
1245 
1246  xercesc::DOMElement* hiddenParentEl, *entryParentEl = logXml.getMatchingElement(XML_LOGBOOK_ENTRY,i); //get entry element
1247 
1248  //check if already hidden
1249  hiddenParentEl = logXml.getMatchingElementInSubtree(entryParentEl,XML_LOGBOOK_ENTRY_HIDDEN);
1250 
1251  if(hide) //remove entry
1252  {
1253  if(hiddenParentEl)
1254  {
1255  __COUT__ << "Hidden tag already applied to entry." << std::endl;
1256  return;
1257  }
1258  hiddenParentEl = logXml.addTextElementToParent(XML_LOGBOOK_ENTRY_HIDDEN,"1",entryParentEl); //add hidden parent with value "1"
1259  logXml.addTextElementToParent(XML_LOGBOOK_ENTRY_HIDER,hider,hiddenParentEl); //hider
1260  sprintf(dayIndexStr,"%lu",time(0));
1261  logXml.addTextElementToParent(XML_LOGBOOK_ENTRY_HIDDEN_TIME,dayIndexStr,hiddenParentEl); //hide time
1262  }
1263  else //restore entry
1264  {
1265  if(!hiddenParentEl)
1266  {
1267  __COUT__ << "Entry already was not hidden." << std::endl;
1268  return;
1269  }
1270 
1271  logXml.recursiveRemoveChild(hiddenParentEl,entryParentEl); //remove hidden parent
1272  }
1273  logXml.saveXmlDocument(logPath);
1274  __COUT__ << "Success." << std::endl;
1275 }
1276 
1277 
1278 
1279 
1280 
1281 
1282 
1283 
1284 
1285 
1286