$treeview $search $mathjax $extrastylesheet
otsdaq_utilities
v2_03_00
$projectbrief
|
$projectbrief
|
$searchbox |
00001 #include "otsdaq-utilities/Logbook/LogbookSupervisor.h" 00002 //#include "otsdaq-core/MessageFacility/MessageFacility.h" 00003 //#include "otsdaq-core/Macros/CoutMacros.h" 00004 //#include "otsdaq-core/CgiDataUtilities/CgiDataUtilities.h" 00005 //#include "otsdaq-core/XmlUtilities/HttpXmlDocument.h" 00006 //#include "otsdaq-core/SOAPUtilities/SOAPUtilities.h" 00007 //#include "otsdaq-core/SOAPUtilities/SOAPParameters.h" 00008 // 00009 //#include <xdaq/NamespaceURI.h> 00010 // 00011 //#include <iostream> 00012 //#include <fstream> 00013 //#include <string> 00014 #include <dirent.h> //for DIR 00015 #include <sys/stat.h> //for mkdir 00016 //#include <thread> // std::thread 00017 00018 using namespace ots; 00019 00020 const std::string LOGBOOK_PATH = getenv("LOGBOOK_DATA_PATH") + std::string("/"); 00021 #define LOGBOOK_EXPERIMENT_LIST_PATH LOGBOOK_PATH + "experiment_list.xml" 00022 #define LOGBOOK_EXPERIMENT_DIR_PREFACE "log_" 00023 #define LOGBOOK_UPLOADS_PATH "uploads/" // within experiment directory 00024 #define LOGBOOK_LOGBOOKS_PATH "logbooks/" 00025 #define LOGBOOK_PREVIEWS_PATH "previews/" 00026 #define LOGBOOK_FILE_PREFACE "entries_" 00027 #define LOGBOOK_FILE_EXTENSION ".xml" 00028 00029 #define ACTIVE_EXPERIMENT_PATH LOGBOOK_PATH + "active_experiment.txt" 00030 #define REMOVE_EXPERIMENT_LOG_PATH LOGBOOK_PATH + "removed_experiments.log" 00031 00032 #define XML_ADMIN_STATUS "logbook_admin_status" 00033 #define XML_STATUS "logbook_status" 00034 #define XML_MOST_RECENT_DAY "most_recent_day" 00035 #define XML_EXPERIMENTS_ROOT "experiments" 00036 #define XML_EXPERIMENT "experiment" 00037 #define XML_ACTIVE_EXPERIMENT "active_experiment" 00038 #define XML_EXPERIMENT_CREATE "create_time" 00039 #define XML_EXPERIMENT_CREATOR "creator" 00040 00041 #define XML_LOGBOOK_ENTRY "logbook_entry" 00042 #define XML_LOGBOOK_ENTRY_SUBJECT "logbook_entry_subject" 00043 #define XML_LOGBOOK_ENTRY_TEXT "logbook_entry_text" 00044 #define XML_LOGBOOK_ENTRY_FILE "logbook_entry_file" 00045 #define XML_LOGBOOK_ENTRY_TIME "logbook_entry_time" 00046 #define XML_LOGBOOK_ENTRY_CREATOR "logbook_entry_creator" 00047 #define XML_LOGBOOK_ENTRY_HIDDEN "logbook_entry_hidden" 00048 #define XML_LOGBOOK_ENTRY_HIDER "logbook_entry_hider" 00049 #define XML_LOGBOOK_ENTRY_HIDDEN_TIME "logbook_entry_hidden_time" 00050 00051 #define XML_PREVIEW_INDEX "preview_index" 00052 #define LOGBOOK_PREVIEW_FILE "preview.xml" 00053 #define LOGBOOK_PREVIEW_UPLOAD_PREFACE "upload_" 00054 00055 XDAQ_INSTANTIATOR_IMPL(LogbookSupervisor) 00056 00057 #undef __MF_SUBJECT__ 00058 #define __MF_SUBJECT__ "Logbook" 00059 00060 //======================================================================================================================== 00061 // sendmail ~~ 00062 // Helper function to send emails to the subscriber list of the active experiment 00063 int sendmail(const char* to, const char* from, const char* subject, const char* message) 00064 { 00065 int retval = -1; 00066 FILE* mailpipe = popen("/usr/lib/sendmail -t", "w"); 00067 if(mailpipe != NULL) 00068 { 00069 fprintf(mailpipe, "To: %s\n", to); 00070 fprintf(mailpipe, "From: %s\n", from); 00071 fprintf(mailpipe, "Subject: %s\n\n", subject); 00072 fwrite(message, 1, strlen(message), mailpipe); 00073 fwrite(".\n", 1, 2, mailpipe); 00074 pclose(mailpipe); 00075 retval = 0; 00076 } 00077 else 00078 { 00079 perror("Failed to invoke sendmail"); 00080 } 00081 return retval; 00082 } 00083 00084 //======================================================================================================================== 00085 LogbookSupervisor::LogbookSupervisor(xdaq::ApplicationStub* stub) 00086 : CoreSupervisorBase(stub) 00087 , allowedFileUploadTypes_({"image/png", 00088 "image/jpeg", 00089 "image/gif", 00090 "image/bmp", 00091 "application/pdf", 00092 "application/zip", 00093 "text/plain"}) // init allowed file upload types 00094 , matchingFileUploadTypes_({"png", 00095 "jpeg", 00096 "gif", 00097 "bmp", 00098 "pdf", 00099 "zip", 00100 "txt"}) // init allowed file upload types 00101 { 00102 INIT_MF("LogbookSupervisor"); 00103 00104 // xgi::bind (this, &LogbookSupervisor::Default, "Default" ); 00105 // xgi::bind (this, &LogbookSupervisor::Log, "Log" ); 00106 // xgi::bind (this, &LogbookSupervisor::LogImage, "LogImage" ); 00107 // xgi::bind (this, &LogbookSupervisor::LogReport, "LogReport" ); 00108 00109 xoap::bind(this, 00110 &LogbookSupervisor::MakeSystemLogbookEntry, 00111 "MakeSystemLogbookEntry", 00112 XDAQ_NS_URI); 00113 00114 init(); 00115 00116 // TODO allow admins to subscribe email addresses to the active experiment 00117 // sendmail("rrivera@fnal.gov","ots-instance@otsdaq.fnal.gov","My 00118 // Subject","Message\nHello!\n\nwhats up."); 00119 } 00120 00121 //======================================================================================================================== 00122 LogbookSupervisor::~LogbookSupervisor(void) { destroy(); } 00123 //======================================================================================================================== 00124 void LogbookSupervisor::init(void) 00125 { 00126 // called by constructor 00127 // allSupervisorInfo_.init(getApplicationContext()); 00128 00129 if(1) // check if LOGBOOK_PATH and subpaths event exist?! (if not, attempt to create) 00130 { 00131 std::string path = LOGBOOK_PATH; 00132 DIR* dir = opendir(path.c_str()); 00133 if(dir) 00134 closedir(dir); 00135 else if(-1 == mkdir(path.c_str(), 0755)) 00136 { 00137 // lets create the service folder (for first time) 00138 std::stringstream ss; 00139 ss << __COUT_HDR_FL__ << "Service directory creation failed: " << path 00140 << std::endl; 00141 __SS_THROW__; 00142 } 00143 00144 path = LOGBOOK_PATH + LOGBOOK_UPLOADS_PATH; 00145 dir = opendir(path.c_str()); 00146 if(dir) 00147 closedir(dir); 00148 else if(-1 == mkdir((path).c_str(), 0755)) 00149 { 00150 // lets create the service folder (for first time) 00151 __SS__ << "Service directory creation failed: " << path << std::endl; 00152 __SS_THROW__; 00153 } 00154 00155 path = LOGBOOK_PATH + LOGBOOK_LOGBOOKS_PATH; 00156 dir = opendir(path.c_str()); 00157 if(dir) 00158 closedir(dir); 00159 else if(-1 == mkdir(path.c_str(), 0755)) 00160 { 00161 // lets create the service folder (for first time) 00162 __SS__ << "Service directory creation failed: " << path << std::endl; 00163 __SS_THROW__; 00164 } 00165 } 00166 00167 getActiveExperiment(); // init active experiment 00168 __COUT__ << "Active Experiment is " << activeExperiment_ << std::endl; 00169 mostRecentDayIndex_ = 0; 00170 } 00171 00172 //======================================================================================================================== 00173 void LogbookSupervisor::destroy(void) 00174 { 00175 // called by destructor 00176 } 00177 00178 //======================================================================================================================== 00179 void LogbookSupervisor::defaultPage(xgi::Input* in, xgi::Output* out) 00180 { 00181 __COUT__ << " active experiment " << activeExperiment_ << std::endl; 00182 *out << "<!DOCTYPE HTML><html lang='en'><frameset col='100%' row='100%'><frame " 00183 "src='/WebPath/html/Logbook.html?urn=" 00184 << this->getApplicationDescriptor()->getLocalId() 00185 << "&active_experiment=" << activeExperiment_ << "'></frameset></html>"; 00186 } 00187 00188 //======================================================================================================================== 00189 // setSupervisorPropertyDefaults 00190 // override to set defaults for supervisor property values (before user settings 00191 // override) 00192 void LogbookSupervisor::setSupervisorPropertyDefaults() 00193 { 00194 CorePropertySupervisorBase::setSupervisorProperty( 00195 CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.UserPermissionsThreshold, 00196 std::string() + 00197 "*=1 | CreateExperiment=-1 | RemoveExperiment=-1 | GetExperimentListAdmin=-1 " 00198 "| SetActiveExperiment=-1" + 00199 " | AdminRemoveRestoreEntry=-1"); 00200 } 00201 00202 //======================================================================================================================== 00203 // forceSupervisorPropertyValues 00204 // override to force supervisor property values (and ignore user settings) 00205 void LogbookSupervisor::forceSupervisorPropertyValues() 00206 { 00207 CorePropertySupervisorBase::setSupervisorProperty( 00208 CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.AutomatedRequestTypes, 00209 "RefreshLogbook"); 00210 CorePropertySupervisorBase::setSupervisorProperty( 00211 CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.NonXMLRequestTypes, 00212 "LogImage | LogReport"); 00213 // CorePropertySupervisorBase::setSupervisorProperty(CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.NeedUsernameRequestTypes, 00214 // "CreateExperiment | RemoveExperiment | PreviewEntry | 00215 // AdminRemoveRestoreEntry"); 00216 } 00217 00218 //======================================================================================================================== 00219 // request 00220 // Handles Web Interface requests to Logbook supervisor. 00221 // Does not refresh cookie for automatic update checks. 00222 void LogbookSupervisor::request(const std::string& requestType, 00223 cgicc::Cgicc& cgiIn, 00224 HttpXmlDocument& xmlOut, 00225 const WebUsers::RequestUserInfo& userInfo) 00226 { 00227 // Commands 00228 // CreateExperiment 00229 // RemoveExperiment 00230 // GetExperimentList 00231 // SetActiveExperiment 00232 // RefreshLogbook 00233 // PreviewEntry 00234 // ApproveEntry 00235 // AdminRemoveRestoreEntr 00236 00237 // 00238 // cgicc::Cgicc cgiIn(in); 00239 // std::string requestType; 00240 // if((requestType = CgiDataUtilities::postData(cgiIn,"RequestType")) == "") 00241 // requestType = cgiIn("RequestType"); //get command from form, if PreviewEntry 00242 // 00243 // __COUT__ << "requestType " << requestType << " files: " << cgiIn.getFiles().size() 00244 //<< std::endl; 00245 // 00246 // 00247 // HttpXmlDocument xmlOut; 00248 // uint64_t activeSessionIndex; 00249 // std::string user; 00250 // uint8_t userPermissions; 00251 // 00252 // //**** start LOGIN GATEWAY CODE ***// 00253 // { 00254 // bool automaticCommand = requestType == "RefreshLogbook"; //automatic commands 00255 // should not refresh cookie code.. only user initiated commands should! bool 00256 // checkLock = true; bool getUser = (requestType == "CreateExperiment") || 00257 //(requestType == "RemoveExperiment") || 00258 // (requestType == "PreviewEntry") || (requestType == 00259 //"AdminRemoveRestoreEntry"); bool requireLock = false; 00260 // 00261 // if(!theRemoteWebUsers_.xmlRequestToGateway( 00262 // cgiIn, 00263 // out, 00264 // &xmlOut, 00265 // allSupervisorInfo_, 00266 // &userPermissions, //acquire user's access level (optionally null 00267 // pointer) !automaticCommand, //true/false refresh cookie 00268 // code 1, //set access level requirement to pass gateway 00269 // checkLock, //true/false enable check that system is 00270 // unlocked or this user has the lock requireLock, 00271 // //true/false requires this user has the lock to proceed 00272 // 0,//&userWithLock, 00274 // (getUser?&user:0) //acquire username of this user 00275 //(optionally 00276 // null pointer) ,0//,&displayName //acquire user's Display 00277 // Name 00278 // ,&activeSessionIndex //acquire user's session index associated 00279 // with the cookieCode 00280 // )) 00281 // { //failure 00282 // __COUT__ << "Failed Login Gateway: " << 00283 // out->str() << std::endl; //print out return string on failure 00284 // return; 00285 // } 00286 // } 00287 // //**** end LOGIN GATEWAY CODE ***// 00288 00289 // to report to logbook admin status use 00290 // xmlOut.addTextElementToData(XML_ADMIN_STATUS,tempStr); 00291 00292 if(requestType == "CreateExperiment") 00293 { 00294 // check that experiment directory does not exist, and it is not in xml list 00295 // create experiment 00296 // create directory 00297 // add to experiments list 00298 // 00299 // if(userPermissions < ADMIN_PERMISSIONS_THRESHOLD) 00300 // { 00301 // xmlOut.addTextElementToData(XML_ADMIN_STATUS,"Error - Insufficient 00302 // permissions."); goto CLEANUP; 00303 // } 00304 // 00305 // //user is admin 00306 // 00307 // __COUT__ << "Admin" << std::endl; 00308 00309 // get creator name 00310 std::string creator = userInfo.username_; 00311 00312 createExperiment( 00313 CgiDataUtilities::postData(cgiIn, "Experiment"), creator, &xmlOut); 00314 00315 __COUT__ << "Created" << std::endl; 00316 } 00317 else if(requestType == "RemoveExperiment") 00318 { 00319 // remove from xml list, but do not remove directory (requires manual delete so 00320 // mistakes aren't made) 00321 // 00322 // if(userPermissions < ADMIN_PERMISSIONS_THRESHOLD) 00323 // { 00324 // xmlOut.addTextElementToData(XML_ADMIN_STATUS,"Error - Insufficient 00325 // permissions."); goto CLEANUP; 00326 // } 00327 00328 // get remover name 00329 std::string remover = userInfo.username_; 00330 removeExperiment( 00331 CgiDataUtilities::postData(cgiIn, "Experiment"), remover, &xmlOut); 00332 } 00333 else if(requestType == "GetExperimentList") 00334 { 00335 // remove from xml list, but do not remove directory (requires manual delete so 00336 // mistakes aren't made) 00337 if(userInfo.permissionLevel_ >= 00338 CoreSupervisorBase::getSupervisorPropertyUserPermissionsThreshold( 00339 "GetExperimentListAdmin")) 00340 { 00341 xmlOut.addTextElementToData("is_admin", "0"); // indicate not an admin 00342 return; 00343 } 00344 // else 00345 00346 xmlOut.addTextElementToData("is_admin", "1"); // indicate not an admin 00347 getExperiments(&xmlOut); 00348 } 00349 else if(requestType == "SetActiveExperiment") 00350 { 00351 // check that experiment exists 00352 // set active experiment 00353 00354 // if(userPermissions < ADMIN_PERMISSIONS_THRESHOLD) 00355 // { 00356 // xmlOut.addTextElementToData(XML_ADMIN_STATUS,"Error - Insufficient 00357 // permissions."); goto CLEANUP; 00358 // } 00359 00360 webUserSetActiveExperiment(CgiDataUtilities::postData(cgiIn, "Experiment"), 00361 &xmlOut); 00362 } 00363 else if(requestType == "RefreshLogbook") 00364 { 00365 // returns logbook for currently active experiment based on date and duration 00366 // parameters 00367 00368 std::string Date = CgiDataUtilities::postData(cgiIn, "Date"); 00369 std::string Duration = CgiDataUtilities::postData(cgiIn, "Duration"); 00370 00371 time_t date; 00372 unsigned char duration; 00373 sscanf(Date.c_str(), "%li", &date); // scan for unsigned long 00374 sscanf(Duration.c_str(), "%hhu", &duration); // scan for unsigned char 00375 00376 __COUT__ << "date " << date << " duration " << (int)duration << std::endl; 00377 std::stringstream str; 00378 refreshLogbook(date, duration, &xmlOut, (std::ostringstream*)&str); 00379 __COUT__ << str.str() << std::endl; 00380 } 00381 else if(requestType == "PreviewEntry") 00382 { 00383 // cleanup temporary folder 00384 // NOTE: all input parameters for PreviewEntry will be attached to form 00385 // so use cgiIn(xxx) to get values. 00386 // increment number for each temporary preview, previewPostTempIndex_ 00387 // save entry and uploads to previewPath / previewPostTempIndex_ /. 00388 00389 cleanUpPreviews(); 00390 std::string EntryText = cgiIn("EntryText"); 00391 __COUT__ << "EntryText " << EntryText << std::endl << std::endl; 00392 std::string EntrySubject = cgiIn("EntrySubject"); 00393 __COUT__ << "EntrySubject " << EntrySubject << std::endl << std::endl; 00394 00395 // get creator name 00396 std::string creator = userInfo.username_; 00397 00398 savePostPreview(EntrySubject, EntryText, cgiIn.getFiles(), creator, &xmlOut); 00399 // else xmlOut.addTextElementToData(XML_STATUS,"Failed - could not get username 00400 // info."); 00401 } 00402 else if(requestType == "ApproveEntry") 00403 { 00404 // If Approve = "1", then previewed Log entry specified by PreviewNumber 00405 // is moved to logbook 00406 // Else the specified Log entry is deleted. 00407 std::string PreviewNumber = CgiDataUtilities::postData(cgiIn, "PreviewNumber"); 00408 std::string Approve = CgiDataUtilities::postData(cgiIn, "Approve"); 00409 00410 movePreviewEntry(PreviewNumber, Approve == "1", &xmlOut); 00411 } 00412 else if(requestType == "AdminRemoveRestoreEntry") 00413 { 00414 // if(userPermissions < ADMIN_PERMISSIONS_THRESHOLD) 00415 // { 00416 // xmlOut.addTextElementToData(XML_ADMIN_STATUS,"Error - Insufficient 00417 // permissions."); goto CLEANUP; 00418 // } 00419 00420 std::string EntryId = CgiDataUtilities::postData(cgiIn, "EntryId"); 00421 bool Hide = CgiDataUtilities::postData(cgiIn, "Hide") == "1" ? true : false; 00422 00423 // get creator name 00424 std::string hider = userInfo.username_; 00425 00426 hideLogbookEntry(EntryId, Hide, hider); 00427 00428 xmlOut.addTextElementToData(XML_ADMIN_STATUS, "1"); // success 00429 } 00430 else 00431 __COUT__ << "requestType request not recognized." << std::endl; 00432 } 00433 00434 //======================================================================================================================== 00435 // request 00436 // Handles Web Interface requests to Logbook supervisor. 00437 // Does not refresh cookie for automatic update checks. 00438 void LogbookSupervisor::nonXmlRequest(const std::string& requestType, 00439 cgicc::Cgicc& cgiIn, 00440 std::ostream& out, 00441 const WebUsers::RequestUserInfo& userInfo) 00442 { 00443 // Commands 00444 // LogImage 00445 // LogReport 00446 00447 if(requestType == "LogImage") 00448 { 00449 std::string src = CgiDataUtilities::getData(cgiIn, "src"); 00450 __COUT__ << " Get Log Image " << src << std::endl; 00451 00452 out << "<!DOCTYPE HTML><html lang='en'><frameset col='100%' row='100%'><frame " 00453 "src='/WebPath/html/LogbookImage.html?urn=" 00454 << this->getApplicationDescriptor()->getLocalId() << "&src=" << src 00455 << "'></frameset></html>"; 00456 } 00457 else if(requestType == "LogReport") 00458 { 00459 std::string activeExperiment = 00460 CgiDataUtilities::getData(cgiIn, "activeExperiment"); 00461 __COUT__ << " Start Log Report for " << activeExperiment << std::endl; 00462 00463 out << "<!DOCTYPE HTML><html lang='en'><header><title>ots Logbook " 00464 "Reports</title></header><frameset col='100%' row='100%'><frame " 00465 "src='/WebPath/html/LogbookReport.html?urn=" 00466 << this->getApplicationDescriptor()->getLocalId() 00467 << "&activeExperiment=" << activeExperiment << "'></frameset></html>"; 00468 } 00469 else 00470 __COUT__ << "requestType request not recognized." << std::endl; 00471 } 00472 00473 //======================================================================================================================== 00474 // xoap::MakeSystemLogbookEntry 00475 // make a system logbook entry into active experiment's logbook from Supervisor only 00476 // TODO: (how to enforce?) 00477 xoap::MessageReference LogbookSupervisor::MakeSystemLogbookEntry( 00478 xoap::MessageReference msg) 00479 { 00480 SOAPParameters parameters("EntryText"); 00481 // SOAPParametersV parameters(1); 00482 // parameters[0].setName("EntryText"); 00483 SOAPUtilities::receive(msg, parameters); 00484 std::string EntryText = parameters.getValue("EntryText"); 00485 00486 __COUT__ << "Received External Supervisor System Entry " << EntryText << std::endl; 00487 __COUT__ << "Active Experiment is " << activeExperiment_ << std::endl; 00488 00489 std::string retStr = "Success"; 00490 00491 std::string logPath, 00492 logDirPath = (std::string)LOGBOOK_PATH + (std::string)LOGBOOK_LOGBOOKS_PATH + 00493 (std::string)LOGBOOK_EXPERIMENT_DIR_PREFACE + activeExperiment_; 00494 00495 char dayIndexStr[20]; 00496 HttpXmlDocument logXml; 00497 char fileIndex[40]; 00498 xercesc::DOMElement* entryEl; 00499 DIR* dir; 00500 00501 if(activeExperiment_ == "") 00502 { 00503 retStr = "Warning - Currently, no Active Experiment."; 00504 __COUT__ << retStr << std::endl; 00505 goto XOAP_CLEANUP; 00506 } 00507 00508 // check that directory exists 00509 dir = opendir(logDirPath.c_str()); 00510 if(!dir) 00511 { 00512 retStr = "Error - Active Experiment directory missing."; 00513 __COUT__ << retStr << std::endl; 00514 goto XOAP_CLEANUP; 00515 } 00516 closedir(dir); 00517 00518 sprintf(dayIndexStr, "%6.6lu", time(0) / (60 * 60 * 24)); // get today's index 00519 00520 logPath = logDirPath + "/" + LOGBOOK_FILE_PREFACE + activeExperiment_ + "_" + 00521 (std::string)dayIndexStr + LOGBOOK_FILE_EXTENSION; 00522 __COUT__ << "logPath " << logPath << std::endl; 00523 00524 logXml.loadXmlDocument(logPath); // NOTE: on failure, no need to do anything 00525 // because empty XML file is valid structure 00526 // entry structure: 00527 // <XML_LOGBOOK_ENTRY> 00528 // <XML_LOGBOOK_ENTRY_TIME> 00529 // <XML_LOGBOOK_ENTRY_CREATOR> 00530 // <XML_LOGBOOK_ENTRY_TEXT> 00531 // <XML_LOGBOOK_ENTRY_FILE value=fileType0> 00532 // <XML_LOGBOOK_ENTRY_FILE value=fileType1> ... 00533 // </XML_LOGBOOK_ENTRY> 00534 00535 entryEl = logXml.addTextElementToData(XML_LOGBOOK_ENTRY); 00536 00537 sprintf(fileIndex, 00538 "%lu_%lu", 00539 time(0), 00540 clock()); // create unique time label for entry time(0)_clock() 00541 logXml.addTextElementToParent(XML_LOGBOOK_ENTRY_TIME, fileIndex, entryEl); 00542 logXml.addTextElementToParent(XML_LOGBOOK_ENTRY_CREATOR, "SYSTEM LOG", entryEl); 00543 logXml.addTextElementToParent(XML_LOGBOOK_ENTRY_TEXT, EntryText, entryEl); 00544 logXml.addTextElementToParent(XML_LOGBOOK_ENTRY_SUBJECT, "System Log", entryEl); 00545 00546 logXml.saveXmlDocument(logPath); 00547 00548 XOAP_CLEANUP: 00549 00550 // fill return parameters 00551 SOAPParameters retParameters("Status", retStr); 00552 // SOAPParametersV retParameters(1); 00553 // retParameters[0].setName("Status"); 00554 // retParameters[0].setValue(retStr); 00555 00556 return SOAPUtilities::makeSOAPMessageReference("LogbookEntryStatusResponse", 00557 retParameters); 00558 } 00559 00560 // 00567 // void LogbookSupervisor::LogImage(xgi::Input * in, xgi::Output * out ) 00568 // throw (xgi::exception::Exception) 00569 //{ 00570 // cgicc::Cgicc cgiIn(in); 00571 // std::string src = CgiDataUtilities::getData(cgiIn,"src"); 00572 // __COUT__ << " Get Log Image " << src << std::endl; 00573 // *out << "<!DOCTYPE HTML><html lang='en'><frameset col='100%' row='100%'><frame 00574 // src='/WebPath/html/LogbookImage.html?urn=" << 00575 // this->getApplicationDescriptor()->getLocalId() << "&src=" << src << 00576 //"'></frameset></html>"; 00577 //} 00578 // 00585 // void LogbookSupervisor::LogReport(xgi::Input * in, xgi::Output * out ) 00586 // throw (xgi::exception::Exception) 00587 //{ 00588 // cgicc::Cgicc cgiIn(in); 00589 // std::string activeExperiment = CgiDataUtilities::getData(cgiIn,"activeExperiment"); 00590 // __COUT__ << " Start Log Report for " << activeExperiment << std::endl; 00591 // *out << "<!DOCTYPE HTML><html lang='en'><header><title>ots Logbook 00592 // Reports</title></header><frameset col='100%' row='100%'><frame 00593 // src='/WebPath/html/LogbookReport.html?urn=" << 00594 // this->getApplicationDescriptor()->getLocalId() << "&activeExperiment=" << 00595 // activeExperiment << "'></frameset></html>"; 00596 //} 00597 00598 //======================================================================================================================== 00599 // getActiveExperiment 00600 // load active experiment from txt file, must be first line in file 00601 std::string LogbookSupervisor::getActiveExperiment() 00602 { 00603 FILE* fp = fopen(std::string((std::string)ACTIVE_EXPERIMENT_PATH).c_str(), "r"); 00604 if(!fp) 00605 activeExperiment_ = ""; 00606 else 00607 { 00608 char line[100]; 00609 if(!fgets(line, 100, fp)) 00610 line[0] = 00611 '\0'; // if null returned, file is empty and line is untouched, so touch. 00612 fclose(fp); 00613 00614 // remove \n \r 00615 if(line[strlen(line) - 2] == '\r') 00616 line[strlen(line) - 2] = '\0'; 00617 else if(line[strlen(line) - 1] == '\n') 00618 line[strlen(line) - 1] = '\0'; 00619 00620 activeExperiment_ = line; 00621 } 00622 00623 return activeExperiment_; 00624 } 00625 00626 //======================================================================================================================== 00627 // setActiveExperiment 00628 // "" means no experiment is active 00629 void LogbookSupervisor::setActiveExperiment(std::string experiment) 00630 { 00631 FILE* fp = fopen(std::string((std::string)ACTIVE_EXPERIMENT_PATH).c_str(), "w"); 00632 if(!fp) 00633 { 00634 __COUT__ << "FATAL ERROR!!! - file write" << std::endl; 00635 return; 00636 } 00637 00638 fprintf(fp, "%s", experiment.c_str()); 00639 fclose(fp); 00640 00641 if(activeExperiment_ != "" && 00642 activeExperiment_ != experiment) // old active experiment is on its way out 00643 theRemoteWebUsers_.makeSystemLogbookEntry( 00644 allSupervisorInfo_.getGatewayDescriptor(), 00645 "Experiment was made inactive."); // make system logbook entry 00646 00647 bool entryNeeded = false; 00648 if(experiment != "" && 00649 activeExperiment_ != experiment) // old active experiment is on its way out 00650 entryNeeded = true; 00651 00652 activeExperiment_ = experiment; 00653 __COUT__ << "Active Experiment set to " << activeExperiment_ << std::endl; 00654 00655 if(entryNeeded) 00656 theRemoteWebUsers_.makeSystemLogbookEntry( 00657 allSupervisorInfo_.getGatewayDescriptor(), 00658 "Experiment was made active."); // make system logbook entry 00659 } 00660 00661 //======================================================================================================================== 00662 // validateExperimentName 00663 // remove all chars that are not alphanumeric, dashes, or underscores 00664 bool LogbookSupervisor::validateExperimentName(std::string& exp) 00665 { 00666 if(exp.length() < EXPERIMENT_NAME_MIN_LENTH || 00667 exp.length() > EXPERIMENT_NAME_MAX_LENTH) 00668 return false; 00669 for(int i = 0; i < (int)exp.length(); ++i) 00670 if(!((exp[i] >= 'a' && exp[i] <= 'z') || (exp[i] >= 'A' && exp[i] <= 'Z') || 00671 (exp[i] >= '0' && exp[i] <= '9') || (exp[i] == '-' || exp[i] == '_'))) 00672 { 00673 exp = exp.substr(0, i) + exp.substr(i + 1); 00674 --i; 00675 } // remove illegal chars and rewind i 00676 00677 return true; 00678 } 00679 00680 //======================================================================================================================== 00681 // getExperiments 00682 // if xmlOut, then output experiments to xml 00683 // if out, then output to stream 00684 void LogbookSupervisor::getExperiments(HttpXmlDocument* xmlOut, std::ostringstream* out) 00685 { 00686 // check that experiment listing doesn't already exist 00687 HttpXmlDocument expXml; 00688 if(!expXml.loadXmlDocument((std::string)LOGBOOK_EXPERIMENT_LIST_PATH)) 00689 { 00690 __COUT__ << "Fatal Error - Experiment database." << std::endl; 00691 __COUT__ << "Creating empty experiment database." << std::endl; 00692 00693 expXml.addTextElementToData((std::string)XML_EXPERIMENTS_ROOT); 00694 expXml.saveXmlDocument((std::string)LOGBOOK_EXPERIMENT_LIST_PATH); 00695 return; 00696 } 00697 00698 std::vector<std::string> exps; 00699 expXml.getAllMatchingValues(XML_EXPERIMENT, exps); 00700 00701 if(xmlOut) 00702 xmlOut->addTextElementToData(XML_ACTIVE_EXPERIMENT, activeExperiment_); 00703 00704 for(unsigned int i = 0; i < exps.size(); ++i) // loop experiments 00705 { 00706 if(xmlOut) 00707 xmlOut->addTextElementToData(XML_EXPERIMENT, exps[i]); 00708 if(out) 00709 *out << exps[i] << std::endl; 00710 } 00711 } 00712 00713 //======================================================================================================================== 00714 // createExperiment 00715 void LogbookSupervisor::createExperiment(std::string experiment, 00716 std::string creator, 00717 HttpXmlDocument* xmlOut) 00718 { 00719 if(!validateExperimentName(experiment)) 00720 { 00721 if(xmlOut) 00722 xmlOut->addTextElementToData( 00723 XML_ADMIN_STATUS, "Error - Experiment name must be 3-25 characters."); 00724 return; 00725 } 00726 00727 __COUT__ << "experiment " << experiment << std::endl; 00728 00729 // check that directory doesn't already exist 00730 std::string dirPath = (std::string)LOGBOOK_PATH + (std::string)LOGBOOK_LOGBOOKS_PATH + 00731 (std::string)LOGBOOK_EXPERIMENT_DIR_PREFACE + experiment; 00732 00733 __COUT__ << "dirPath " << dirPath << std::endl; 00734 00735 bool directoryExists = false; 00736 DIR* dir = opendir(dirPath.c_str()); 00737 if(dir) 00738 { 00739 closedir(dir); 00740 directoryExists = true; 00741 } 00742 00743 // check that experiment listing doesn't already exist 00744 HttpXmlDocument expXml; 00745 if(!expXml.loadXmlDocument((std::string)LOGBOOK_EXPERIMENT_LIST_PATH)) 00746 { 00747 if(xmlOut) 00748 xmlOut->addTextElementToData(XML_ADMIN_STATUS, 00749 "Fatal Error - Experiment database."); 00750 return; 00751 } 00752 00753 std::vector<std::string> exps; 00754 expXml.getAllMatchingValues(XML_EXPERIMENT, exps); 00755 00756 for(unsigned int i = 0; i < exps.size(); ++i) 00757 if(experiment == exps[i]) 00758 { 00759 if(xmlOut) 00760 xmlOut->addTextElementToData( 00761 XML_ADMIN_STATUS, 00762 "Failed - Experiment, " + experiment + ", already exists."); 00763 return; 00764 } 00765 __COUT__ << "experiments count: " << exps.size() << std::endl; 00766 00767 // everything checks out, add experiment! 00768 // add to experiments xml doc and save 00769 // <experiments> 00770 // ... 00771 // <experiment_name = "xx"> 00772 // <create_time = "##"> <who_created = "aa"> 00773 xercesc::DOMElement* expEl = 00774 expXml.addTextElementToParent(XML_EXPERIMENT, experiment, XML_EXPERIMENTS_ROOT); 00775 char createTime[20]; 00776 sprintf(createTime, "%lu", time(0)); 00777 expXml.addTextElementToParent(XML_EXPERIMENT_CREATE, createTime, expEl); 00778 expXml.addTextElementToParent(XML_EXPERIMENT_CREATOR, creator, expEl); 00779 expXml.saveXmlDocument((std::string)LOGBOOK_EXPERIMENT_LIST_PATH); 00780 00781 // create directory only if doesn't already exist 00782 if(directoryExists) 00783 { 00784 // check uploads folder 00785 dirPath += "/" + (std::string)LOGBOOK_UPLOADS_PATH; 00786 __COUT__ << "Checking uploads directory" << std::endl; 00787 00788 directoryExists = false; 00789 dir = opendir(dirPath.c_str()); 00790 if(!dir) // check if uploads directory exists within experiment directory 00791 { 00792 __COUT__ << "Creating uploads directory" << std::endl; 00793 if(-1 == mkdir(dirPath.c_str(), 0755)) // make uploads directory 00794 { 00795 if(xmlOut) 00796 xmlOut->addTextElementToData(XML_ADMIN_STATUS, 00797 "Failed - uploads directory for " + 00798 experiment + " was not created."); 00799 __COUT__ << "Uploads directory failure." << std::endl; 00800 return; 00801 } 00802 } 00803 else 00804 closedir(dir); 00805 00806 xmlOut->addTextElementToData(XML_ADMIN_STATUS, 00807 "Directory already exists for " + experiment + 00808 ", re-added to list of experiments."); 00809 return; 00810 } 00811 __COUT__ << "Creating experiment and uploads directory at: " << dirPath << std::endl; 00812 if(-1 == mkdir(dirPath.c_str(), 0755) || 00813 -1 == mkdir((dirPath + "/" + (std::string)LOGBOOK_UPLOADS_PATH).c_str(), 0755)) 00814 { 00815 if(xmlOut) 00816 xmlOut->addTextElementToData( 00817 XML_ADMIN_STATUS, 00818 "Failed - directory, " + experiment + ", could not be created."); 00819 return; 00820 } 00821 00822 if(xmlOut) 00823 xmlOut->addTextElementToData( 00824 XML_ADMIN_STATUS, "Experiment, " + experiment + ", successfully created."); 00825 } 00826 00827 //======================================================================================================================== 00828 // webUserSetActiveExperiment 00829 // if experiment exists, set as active 00830 // to clear active experiment set to "" 00831 void LogbookSupervisor::webUserSetActiveExperiment(std::string experiment, 00832 HttpXmlDocument* xmlOut) 00833 { 00834 if(experiment == "") // clear active experiment 00835 { 00836 setActiveExperiment(experiment); 00837 if(xmlOut) 00838 xmlOut->addTextElementToData(XML_ADMIN_STATUS, 00839 "Active experiment cleared successfully."); 00840 } 00841 00842 // check that experiment listing exists 00843 HttpXmlDocument expXml; 00844 if(!expXml.loadXmlDocument((std::string)LOGBOOK_EXPERIMENT_LIST_PATH)) 00845 { 00846 if(xmlOut) 00847 xmlOut->addTextElementToData(XML_ADMIN_STATUS, 00848 "Fatal Error - Experiment database."); 00849 return; 00850 } 00851 std::vector<std::string> exps; 00852 expXml.getAllMatchingValues(XML_EXPERIMENT, exps); 00853 00854 unsigned int i; 00855 for(i = 0; i < exps.size(); ++i) 00856 if(experiment == exps[i]) 00857 break; 00858 00859 if(i == exps.size()) // not found 00860 { 00861 if(xmlOut) 00862 xmlOut->addTextElementToData( 00863 XML_ADMIN_STATUS, "Failed - Experiment, " + experiment + ", not found."); 00864 return; 00865 } 00866 00867 // found! 00868 setActiveExperiment(experiment); 00869 if(xmlOut) 00870 xmlOut->addTextElementToData( 00871 XML_ADMIN_STATUS, 00872 "Active experiment set to " + experiment + " successfully."); 00873 } 00874 00875 //======================================================================================================================== 00876 // removeExperiment 00877 // remove experiment from listing only (do NOT remove logbook data directory) 00878 // record remover in log file REMOVE_EXPERIMENT_LOG_PATH 00879 void LogbookSupervisor::removeExperiment(std::string experiment, 00880 std::string remover, 00881 HttpXmlDocument* xmlOut) 00882 { 00883 __COUT__ << "experiment " << experiment << std::endl; 00884 00885 // check that experiment listing exists 00886 HttpXmlDocument expXml; 00887 if(!expXml.loadXmlDocument((std::string)LOGBOOK_EXPERIMENT_LIST_PATH)) 00888 { 00889 if(xmlOut) 00890 xmlOut->addTextElementToData(XML_ADMIN_STATUS, 00891 "Fatal Error - Experiment database."); 00892 return; 00893 } 00894 std::vector<std::string> exps; 00895 expXml.getAllMatchingValues(XML_EXPERIMENT, exps); 00896 00897 unsigned int i; 00898 for(i = 0; i < exps.size(); ++i) 00899 if(experiment == exps[i]) 00900 break; 00901 00902 if(i == exps.size()) // not found 00903 { 00904 if(xmlOut) 00905 xmlOut->addTextElementToData( 00906 XML_ADMIN_STATUS, "Failed - Experiment, " + experiment + ", not found."); 00907 return; 00908 } 00909 00910 // found! 00911 00912 // remove experiment from xml 00913 xercesc::DOMElement* parent = expXml.getMatchingElement(XML_EXPERIMENTS_ROOT); 00914 xercesc::DOMElement* child = expXml.getMatchingElement(XML_EXPERIMENT, i); 00915 __COUT__ << "experiments original count: " << expXml.getChildrenCount(parent) 00916 << std::endl; 00917 expXml.recursiveRemoveChild(child, parent); 00918 __COUT__ << "experiments new count: " << expXml.getChildrenCount(parent) << std::endl; 00919 00920 // update removed experiments log 00921 FILE* fp = fopen(((std::string)REMOVE_EXPERIMENT_LOG_PATH).c_str(), "a"); 00922 if(!fp) 00923 { 00924 if(xmlOut) 00925 xmlOut->addTextElementToData(XML_ADMIN_STATUS, "Fatal Error - Remove log."); 00926 return; 00927 } 00928 fprintf(fp, 00929 "%s -- %s Experiment removed by %s.\n", 00930 asctime(localtime(&((time_t const&)(time(0))))), 00931 experiment.c_str(), 00932 remover.c_str()); 00933 fclose(fp); 00934 00935 expXml.saveXmlDocument((std::string)LOGBOOK_EXPERIMENT_LIST_PATH); // save database 00936 00937 // unset from activeExperiment_ if is active experiment 00938 if(activeExperiment_ == experiment) 00939 setActiveExperiment(); // clear active experiment 00940 00941 if(xmlOut) 00942 xmlOut->addTextElementToData( 00943 XML_ADMIN_STATUS, "Experiment, " + experiment + ", successfully removed."); 00944 } 00945 00946 //======================================================================================================================== 00947 // refreshLogbook 00948 // returns all the logbook data for active experiment from starting date and back in 00949 // time for duration total number of days. 00950 // e.g. data = today, and duration = 1 returns logbook for today from active 00951 // experiment The entries are returns from oldest to newest 00952 void LogbookSupervisor::refreshLogbook(time_t date, 00953 unsigned char duration, 00954 HttpXmlDocument* xmlOut, 00955 std::ostringstream* out, 00956 std::string experiment) 00957 { 00958 if(experiment == "") 00959 experiment = activeExperiment_; // default to active experiment 00960 if(xmlOut) 00961 xmlOut->addTextElementToData(XML_ACTIVE_EXPERIMENT, experiment); // for success 00962 00963 // check that directory exists 00964 std::string dirPath = (std::string)LOGBOOK_PATH + (std::string)LOGBOOK_LOGBOOKS_PATH + 00965 (std::string)LOGBOOK_EXPERIMENT_DIR_PREFACE + experiment; 00966 00967 if(out) 00968 *out << __COUT_HDR_FL__ << "dirPath " << dirPath << std::endl; 00969 00970 DIR* dir = opendir(dirPath.c_str()); 00971 if(!dir) 00972 { 00973 if(xmlOut) 00974 xmlOut->addTextElementToData( 00975 XML_STATUS, 00976 "Error - Directory for experiment, " + experiment + ", missing."); 00977 if(out) 00978 *out << __COUT_HDR_FL__ << "Error - Directory missing" << std::endl; 00979 return; 00980 } 00981 00982 unsigned int baseDay; 00983 00984 if(!date) // if date is 0 take most recent day and update it 00985 { 00986 struct dirent* drnt; 00987 unsigned int extractedDay; 00988 int start, finish; // always find number after last _ and before last . 00989 00990 mostRecentDayIndex_ = 0; 00991 while((drnt = readdir(dir))) 00992 { 00993 // if(out) *out << __COUT_HDR_FL__ << "dirContents " << drnt->d_name << 00994 // std::endl; 00995 00996 if(strcmp(&(drnt->d_name[strlen(drnt->d_name) - 4]), ".xml")) 00997 continue; // skip non logbook files 00998 00999 for(finish = strlen(drnt->d_name) - 1; finish > 0; --finish) 01000 if(drnt->d_name[finish] == '.') 01001 break; 01002 if(finish == 0) 01003 { 01004 if(out) 01005 *out << __COUT_HDR_FL__ << "failed to find day index finish " 01006 << std::endl; 01007 return; 01008 } 01009 for(start = finish - 1; start > 0; --start) 01010 if(drnt->d_name[start - 1] == '_') 01011 break; 01012 if(start == 0) 01013 { 01014 if(out) 01015 *out << __COUT_HDR_FL__ << "failed to find day index start " 01016 << std::endl; 01017 return; 01018 } 01019 drnt->d_name[finish] = '\0'; 01020 extractedDay = atoi((char*)(&(drnt->d_name[start]))); 01021 // if(out) *out << __COUT_HDR_FL__ << "dirContents " << (char 01022 // *)(&(drnt->d_name[start])) << " " << extractedDay << std::endl; 01023 if(!mostRecentDayIndex_ || mostRecentDayIndex_ < extractedDay) 01024 mostRecentDayIndex_ = extractedDay; 01025 } 01026 if(out) 01027 *out << __COUT_HDR_FL__ 01028 << "dirContents done, found most recent day: " << mostRecentDayIndex_ 01029 << std::endl; 01030 01031 baseDay = mostRecentDayIndex_; 01032 } 01033 else 01034 baseDay = (date / (60 * 60 * 24)); 01035 closedir(dir); 01036 01037 std::string entryPath; 01038 char dayIndexStr[20]; 01039 FILE* fp; 01040 01041 // read all days selected out 01042 // entries are in file as oldest at top, newest at bottom 01043 // so read oldest files first to have global ordering of old to new 01044 for(unsigned char i = duration; i != 0; --i) 01045 { 01046 sprintf(dayIndexStr, "%6.6u", baseDay - i + 1); // get day index, back in time 01047 entryPath = dirPath + "/" + LOGBOOK_FILE_PREFACE + experiment + "_" + 01048 (std::string)dayIndexStr + LOGBOOK_FILE_EXTENSION; 01049 01050 if(out) 01051 *out << __COUT_HDR_FL__ << "Directory Entry " << entryPath << std::endl; 01052 01053 fp = fopen(entryPath.c_str(), "r"); 01054 if(!fp) 01055 { 01056 if(out) 01057 *out << __COUT_HDR_FL__ << "File not found" << std::endl; 01058 continue; 01059 } 01060 fclose(fp); 01061 01062 // file found! read file out 01063 01064 HttpXmlDocument logXml; 01065 if(!logXml.loadXmlDocument(entryPath)) 01066 { 01067 if(xmlOut) 01068 xmlOut->addTextElementToData( 01069 XML_STATUS, "Critical Failure - log did not load. Notify admins."); 01070 if(out) 01071 *out << __COUT_HDR_FL__ << "Failure - log XML did not load" << std::endl; 01072 return; 01073 } 01074 01075 if(xmlOut) 01076 xmlOut->copyDataChildren(logXml); // copy file to output xml 01077 } 01078 01079 if(xmlOut) 01080 xmlOut->addTextElementToData(XML_STATUS, "1"); // for success 01081 if(out) 01082 *out << __COUT_HDR_FL__ << "Today: " << time(0) / (60 * 60 * 24) << std::endl; 01083 01084 sprintf(dayIndexStr, "%lu", time(0) / (60 * 60 * 24) - mostRecentDayIndex_); 01085 if(xmlOut) 01086 xmlOut->addTextElementToData(XML_MOST_RECENT_DAY, 01087 dayIndexStr); // send most recent day index 01088 } 01089 01090 //======================================================================================================================== 01091 // cleanUpPreviews 01092 // cleanup logbook preview directory 01093 // all names have time_t creation time + "_" + incremented index 01094 void LogbookSupervisor::cleanUpPreviews() 01095 { 01096 std::string previewPath = 01097 (std::string)LOGBOOK_PATH + (std::string)LOGBOOK_PREVIEWS_PATH; 01098 01099 DIR* dir = opendir(previewPath.c_str()); 01100 if(!dir) 01101 { 01102 __COUT__ << "Error - Previews directory missing: " << previewPath << std::endl; 01103 return; 01104 } 01105 01106 struct dirent* entry; 01107 time_t dirCreateTime; 01108 unsigned int i; 01109 01110 while( 01111 (entry = readdir( 01112 dir))) // loop through all entries in directory and remove anything expired 01113 { 01114 if(strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0 && 01115 strcmp(entry->d_name, ".svn") != 0) 01116 { 01117 // replace _ with space so sscanf works 01118 for(i = 0; i < strlen(entry->d_name); ++i) 01119 if(entry->d_name[i] == '_') 01120 { 01121 entry->d_name[i] = ' '; 01122 break; 01123 } 01124 sscanf(entry->d_name, "%li", &dirCreateTime); 01125 01126 if((time(0) - dirCreateTime) > LOGBOOK_PREVIEW_EXPIRATION_TIME) 01127 { 01128 __COUT__ << "Expired" << std::endl; 01129 01130 entry->d_name[i] = '_'; // put _ back 01131 01132 __COUT__ << "rm -rf " << previewPath + (std::string)entry->d_name 01133 << std::endl 01134 << std::endl; 01135 system( 01136 ((std::string)("rm -rf " + previewPath + (std::string)entry->d_name)) 01137 .c_str()); 01138 } 01139 } 01140 } 01141 01142 closedir(dir); 01143 } 01144 01145 //======================================================================================================================== 01146 // savePostPreview 01147 // save post to preview directory named with time and incremented index 01148 void LogbookSupervisor::savePostPreview(std::string& subject, 01149 std::string& text, 01150 const std::vector<cgicc::FormFile>& files, 01151 std::string creator, 01152 HttpXmlDocument* xmlOut) 01153 { 01154 if(activeExperiment_ == "") // no active experiment! 01155 { 01156 if(xmlOut) 01157 xmlOut->addTextElementToData(XML_STATUS, 01158 "Failed - no active experiment currently!"); 01159 return; 01160 } 01161 01162 char fileIndex[40]; 01163 sprintf(fileIndex, 01164 "%lu_%lu", 01165 time(0), 01166 clock()); // create unique time label for entry time(0)_clock() 01167 std::string previewPath = (std::string)LOGBOOK_PATH + 01168 (std::string)LOGBOOK_PREVIEWS_PATH + (std::string)fileIndex; 01169 01170 __COUT__ << "previewPath " << previewPath << std::endl; 01171 if(-1 == mkdir(previewPath.c_str(), 0755)) 01172 { 01173 if(xmlOut) 01174 xmlOut->addTextElementToData(XML_STATUS, 01175 "Failed - preview could not be generated."); 01176 return; 01177 } 01178 01179 // new directory created successfully, save text and files 01180 // entry structure: 01181 // <XML_LOGBOOK_ENTRY> 01182 // <XML_LOGBOOK_ENTRY_TIME> 01183 // <XML_LOGBOOK_ENTRY_CREATOR> 01184 // <XML_LOGBOOK_ENTRY_SUBJECT> 01185 // <XML_LOGBOOK_ENTRY_TEXT> 01186 // <XML_LOGBOOK_ENTRY_FILE value=fileType0> 01187 // <XML_LOGBOOK_ENTRY_FILE value=fileType1> ... 01188 // </XML_LOGBOOK_ENTRY> 01189 01190 escapeLogbookEntry(text); 01191 escapeLogbookEntry(subject); 01192 __COUT__ << "~~subject " << subject << std::endl 01193 << "~~text " << text << std::endl 01194 << std::endl; 01195 01196 HttpXmlDocument previewXml; 01197 01198 previewXml.addTextElementToData(XML_LOGBOOK_ENTRY); 01199 previewXml.addTextElementToParent( 01200 XML_LOGBOOK_ENTRY_TIME, fileIndex, XML_LOGBOOK_ENTRY); 01201 if(xmlOut) 01202 xmlOut->addTextElementToData(XML_LOGBOOK_ENTRY_TIME, fileIndex); // return time 01203 previewXml.addTextElementToParent( 01204 XML_LOGBOOK_ENTRY_CREATOR, creator, XML_LOGBOOK_ENTRY); 01205 if(xmlOut) 01206 xmlOut->addTextElementToData(XML_LOGBOOK_ENTRY_CREATOR, 01207 creator); // return creator 01208 previewXml.addTextElementToParent(XML_LOGBOOK_ENTRY_TEXT, text, XML_LOGBOOK_ENTRY); 01209 if(xmlOut) 01210 xmlOut->addTextElementToData(XML_LOGBOOK_ENTRY_TEXT, text); // return text 01211 previewXml.addTextElementToParent( 01212 XML_LOGBOOK_ENTRY_SUBJECT, subject, XML_LOGBOOK_ENTRY); 01213 if(xmlOut) 01214 xmlOut->addTextElementToData(XML_LOGBOOK_ENTRY_SUBJECT, 01215 subject); // return subject 01216 01217 __COUT__ << "file size " << files.size() << std::endl; 01218 01219 std::string filename; 01220 std::ofstream myfile; 01221 for(unsigned int i = 0; i < files.size(); ++i) 01222 { 01223 previewXml.addTextElementToParent( 01224 XML_LOGBOOK_ENTRY_FILE, files[i].getDataType(), XML_LOGBOOK_ENTRY); 01225 if(xmlOut) 01226 xmlOut->addTextElementToData(XML_LOGBOOK_ENTRY_FILE, 01227 files[i].getDataType()); // return file type 01228 01229 if((filename = validateUploadFileType(files[i].getDataType())) == 01230 "") // invalid file type 01231 { 01232 if(xmlOut) 01233 xmlOut->addTextElementToData( 01234 XML_STATUS, 01235 "Failed - invalid file type, " + files[i].getDataType() + "."); 01236 return; 01237 } 01238 01239 // file validated, so save upload to temp directory 01240 sprintf(fileIndex, "%d", i); 01241 filename = previewPath + "/" + (std::string)LOGBOOK_PREVIEW_UPLOAD_PREFACE + 01242 (std::string)fileIndex + "." + filename; 01243 01244 __COUT__ << "file " << i << " - " << filename << std::endl; 01245 myfile.open(filename.c_str()); 01246 if(myfile.is_open()) 01247 { 01248 files[i].writeToStream(myfile); 01249 myfile.close(); 01250 } 01251 } 01252 01253 // save xml doc for preview entry 01254 previewXml.saveXmlDocument(previewPath + "/" + (std::string)LOGBOOK_PREVIEW_FILE); 01255 01256 if(xmlOut) 01257 xmlOut->addTextElementToData(XML_STATUS, "1"); // 1 indicates success! 01258 if(xmlOut) 01259 xmlOut->addTextElementToData(XML_PREVIEW_INDEX, 01260 "1"); // 1 indicates is a preview post 01261 } 01262 01263 //======================================================================================================================== 01264 // movePreviewEntry 01265 // if approve 01266 // move entry to current active logbook 01267 // if not approve 01268 // delete directory 01269 void LogbookSupervisor::movePreviewEntry(std::string previewNumber, 01270 bool approve, 01271 HttpXmlDocument* xmlOut) 01272 { 01273 __COUT__ << "previewNumber " << previewNumber 01274 << (approve ? " Accepted" : " Cancelled") << std::endl; 01275 01276 std::string sysCmd, previewPath = (std::string)LOGBOOK_PATH + 01277 (std::string)LOGBOOK_PREVIEWS_PATH + previewNumber; 01278 01279 if(approve) 01280 { 01281 // move from preview to logbook 01282 01283 HttpXmlDocument previewXml; 01284 previewXml.loadXmlDocument(previewPath + "/" + (std::string)LOGBOOK_PREVIEW_FILE); 01285 01286 std::string logPath, 01287 logDirPath = (std::string)LOGBOOK_PATH + (std::string)LOGBOOK_LOGBOOKS_PATH + 01288 (std::string)LOGBOOK_EXPERIMENT_DIR_PREFACE + activeExperiment_; 01289 01290 // check that directory exists 01291 DIR* dir = opendir(logDirPath.c_str()); 01292 if(!dir) 01293 { 01294 __COUT__ << "Error - Active Experiment directory missing: " << logPath 01295 << std::endl; 01296 return; 01297 } 01298 closedir(dir); 01299 01300 char dayIndexStr[20]; 01301 sprintf(dayIndexStr, "%6.6lu", time(0) / (60 * 60 * 24)); // get today's index 01302 01303 logPath = logDirPath + "/" + LOGBOOK_FILE_PREFACE + activeExperiment_ + "_" + 01304 (std::string)dayIndexStr + LOGBOOK_FILE_EXTENSION; 01305 __COUT__ << "logPath " << logPath << std::endl; 01306 01307 HttpXmlDocument logXml; 01308 logXml.loadXmlDocument(logPath); // NOTE: on failure, no need to do anything 01309 // because empty XML file is valid structure 01310 // entry structure: 01311 // <XML_LOGBOOK_ENTRY> 01312 // <XML_LOGBOOK_ENTRY_TIME> 01313 // <XML_LOGBOOK_ENTRY_CREATOR> 01314 // <XML_LOGBOOK_ENTRY_TEXT> 01315 // <XML_LOGBOOK_ENTRY_FILE value=fileType0> 01316 // <XML_LOGBOOK_ENTRY_FILE value=fileType1> ... 01317 // </XML_LOGBOOK_ENTRY> 01318 01319 logXml.copyDataChildren(previewXml); // Copy from previewXML to logXML 01320 logXml.saveXmlDocument(logPath); 01321 01322 // Move upload files 01323 std::vector<std::string> fileTypes; 01324 previewXml.getAllMatchingValues(XML_LOGBOOK_ENTRY_FILE, fileTypes); 01325 std::string entryTimeLabel = previewXml.getMatchingValue(XML_LOGBOOK_ENTRY_TIME); 01326 std::string fileExtension, previewFilename, logFilename; 01327 char fileIndex[10]; 01328 for(unsigned int i = 0; i < fileTypes.size(); ++i) 01329 { 01330 if((fileExtension = validateUploadFileType(fileTypes[i])) == 01331 "") // invalid file type 01332 { 01333 __COUT__ << "Failed - invalid file type: " << fileTypes[i] << std::endl; 01334 continue; 01335 } 01336 01337 // file validated, so save upload to temp directory 01338 sprintf(fileIndex, "%d", i); 01339 previewFilename = (std::string)LOGBOOK_PREVIEW_UPLOAD_PREFACE + 01340 (std::string)fileIndex + "." + fileExtension; 01341 logFilename = (std::string)LOGBOOK_PREVIEW_UPLOAD_PREFACE + entryTimeLabel + 01342 "_" + (std::string)fileIndex + "." + fileExtension; 01343 01344 sysCmd = "mv " + (previewPath + "/" + previewFilename) + " " + 01345 (logDirPath + "/" + (std::string)LOGBOOK_UPLOADS_PATH + logFilename); 01346 __COUT__ << sysCmd << std::endl; 01347 system(sysCmd.c_str()); 01348 } 01349 } 01350 01351 // remove preview directory 01352 sysCmd = "rm -rf " + previewPath; 01353 __COUT__ << sysCmd << std::endl << std::endl; 01354 system(sysCmd.c_str()); 01355 } 01356 01357 //======================================================================================================================== 01358 // validateUploadFileType 01359 // returns "" if file type is invalide, else returns file extension to use 01360 std::string LogbookSupervisor::validateUploadFileType(const std::string fileType) 01361 { 01362 for(unsigned int i = 0; i < allowedFileUploadTypes_.size(); ++i) 01363 if(allowedFileUploadTypes_[i] == fileType) 01364 return matchingFileUploadTypes_[i]; // found and done 01365 01366 return ""; // not valid, return "" 01367 } 01368 01369 //======================================================================================================================== 01370 // escapeLogbookEntry 01371 // replace html/xhtml reserved characters with equivalent. 01372 // reserved: ", ', &, <, >, \n, double-space 01373 void LogbookSupervisor::escapeLogbookEntry(std::string& entry) 01374 { 01375 // NOTE: should already be taken care of by web gui javascript! do we care to check? 01376 } 01377 01378 //======================================================================================================================== 01379 // hideLogbookEntry 01380 // NOTE: does not actually delete entry, just marks as hidden 01381 // removes/restores logbook entry. Requires admin priveleges 01382 // Locates the entry within the active experiment and if hide 01383 // appends xml fields: 01384 // XML_LOGBOOK_ENTRY_HIDDEN 01385 // XML_LOGBOOK_ENTRY_HIDER 01386 // XML_LOGBOOK_ENTRY_HIDDEN_TIME 01387 void LogbookSupervisor::hideLogbookEntry(const std::string& entryId, 01388 bool hide, 01389 const std::string& hider) 01390 { 01391 __COUT__ << "Hide=" << hide << " for entryid " << entryId << std::endl; 01392 01393 // get path to entries file for entry at entryId 01394 char dayIndexStr[20]; 01395 unsigned int i; 01396 for(i = 0; i < entryId.length(); ++i) 01397 if(entryId[i] == '_') 01398 { 01399 dayIndexStr[i] = '\0'; 01400 break; 01401 } 01402 else 01403 dayIndexStr[i] = entryId[i]; 01404 time_t days; 01405 sscanf(dayIndexStr, "%li", &days); // get seconds 01406 days /= 60 * 60 * 24; // get days 01407 sprintf(dayIndexStr, "%6.6lu", days); 01408 01409 std::string logDirPath = 01410 (std::string)LOGBOOK_PATH + (std::string)LOGBOOK_LOGBOOKS_PATH + 01411 (std::string)LOGBOOK_EXPERIMENT_DIR_PREFACE + activeExperiment_; 01412 std::string logPath = logDirPath + "/" + LOGBOOK_FILE_PREFACE + activeExperiment_ + 01413 "_" + (std::string)dayIndexStr + LOGBOOK_FILE_EXTENSION; 01414 01415 __COUT__ << "logPath=" << logPath << std::endl; 01416 01417 // locate entry 01418 HttpXmlDocument logXml; 01419 if(!logXml.loadXmlDocument(logPath)) 01420 { 01421 __COUT__ << "Failure - log XML did not load" << std::endl; 01422 return; 01423 } 01424 01425 std::vector<std::string> allEntryIds; 01426 logXml.getAllMatchingValues(XML_LOGBOOK_ENTRY_TIME, allEntryIds); 01427 for(i = 0; i < allEntryIds.size(); ++i) 01428 if(allEntryIds[i] == entryId) 01429 break; 01430 if(i == allEntryIds.size()) 01431 { 01432 __COUT__ << "Failure - entry not found" << std::endl; 01433 return; 01434 } 01435 01436 __COUT__ << "found " << logXml.getMatchingValue(XML_LOGBOOK_ENTRY_TEXT, i) 01437 << std::endl; 01438 01439 xercesc::DOMElement *hiddenParentEl, *entryParentEl = logXml.getMatchingElement( 01440 XML_LOGBOOK_ENTRY, i); // get entry element 01441 01442 // check if already hidden 01443 hiddenParentEl = 01444 logXml.getMatchingElementInSubtree(entryParentEl, XML_LOGBOOK_ENTRY_HIDDEN); 01445 01446 if(hide) // remove entry 01447 { 01448 if(hiddenParentEl) 01449 { 01450 __COUT__ << "Hidden tag already applied to entry." << std::endl; 01451 return; 01452 } 01453 hiddenParentEl = logXml.addTextElementToParent( 01454 XML_LOGBOOK_ENTRY_HIDDEN, 01455 "1", 01456 entryParentEl); // add hidden parent with value "1" 01457 logXml.addTextElementToParent( 01458 XML_LOGBOOK_ENTRY_HIDER, hider, hiddenParentEl); // hider 01459 sprintf(dayIndexStr, "%lu", time(0)); 01460 logXml.addTextElementToParent( 01461 XML_LOGBOOK_ENTRY_HIDDEN_TIME, dayIndexStr, hiddenParentEl); // hide time 01462 } 01463 else // restore entry 01464 { 01465 if(!hiddenParentEl) 01466 { 01467 __COUT__ << "Entry already was not hidden." << std::endl; 01468 return; 01469 } 01470 01471 logXml.recursiveRemoveChild(hiddenParentEl, 01472 entryParentEl); // remove hidden parent 01473 } 01474 logXml.saveXmlDocument(logPath); 01475 __COUT__ << "Success." << std::endl; 01476 }