otsdaq  v2_05_02_indev
WizardSupervisor.cc
1 #include "otsdaq/WizardSupervisor/WizardSupervisor.h"
2 
3 #include "otsdaq/GatewaySupervisor/GatewaySupervisor.h"
4 
5 #include "otsdaq/Macros/CoutMacros.h"
6 #include "otsdaq/MessageFacility/MessageFacility.h"
7 
8 #include <xdaq/NamespaceURI.h>
9 #include "otsdaq/CgiDataUtilities/CgiDataUtilities.h"
10 #include "otsdaq/SOAPUtilities/SOAPCommand.h"
11 #include "otsdaq/SOAPUtilities/SOAPUtilities.h"
12 #include "otsdaq/WebUsersUtilities/WebUsers.h"
13 #include "otsdaq/XmlUtilities/HttpXmlDocument.h"
14 
15 #include <dirent.h> //for DIR
16 #include <sys/stat.h> // mkdir
17 #include <chrono> // std::chrono::seconds
18 #include <fstream>
19 #include <iostream>
20 #include <string>
21 #include <thread> // std::this_thread::sleep_for
22 
23 using namespace ots;
24 
25 // clang-format off
26 
27 const std::string WizardSupervisor::WIZ_SUPERVISOR = __ENV__("OTS_CONFIGURATION_WIZARD_SUPERVISOR_SERVER");
28 const std::string WizardSupervisor::WIZ_PORT = __ENV__("PORT");
29 const std::string WizardSupervisor::SERVICE_DATA_PATH = __ENV__("SERVICE_DATA_PATH");
30 
31 #define SECURITY_FILE_NAME WizardSupervisor::SERVICE_DATA_PATH + "/OtsWizardData/security.dat"
32 #define SEQUENCE_FILE_NAME WizardSupervisor::SERVICE_DATA_PATH + "/OtsWizardData/sequence.dat"
33 #define SEQUENCE_OUT_FILE_NAME WizardSupervisor::SERVICE_DATA_PATH + "/OtsWizardData/sequence.out"
34 #define USER_IMPORT_EXPORT_PATH WizardSupervisor::SERVICE_DATA_PATH + "/"
35 
36 #define XML_STATUS "editUserData_status"
37 
38 #define XML_ADMIN_STATUS "logbook_admin_status"
39 #define XML_MOST_RECENT_DAY "most_recent_day"
40 #define XML_EXPERIMENTS_ROOT "experiments"
41 #define XML_EXPERIMENT "experiment"
42 #define XML_ACTIVE_EXPERIMENT "active_experiment"
43 #define XML_EXPERIMENT_CREATE "create_time"
44 #define XML_EXPERIMENT_CREATOR "creator"
45 
46 #define XML_LOGBOOK_ENTRY "logbook_entry"
47 #define XML_LOGBOOK_ENTRY_SUBJECT "logbook_entry_subject"
48 #define XML_LOGBOOK_ENTRY_TEXT "logbook_entry_text"
49 #define XML_LOGBOOK_ENTRY_FILE "logbook_entry_file"
50 #define XML_LOGBOOK_ENTRY_TIME "logbook_entry_time"
51 #define XML_LOGBOOK_ENTRY_CREATOR "logbook_entry_creator"
52 #define XML_LOGBOOK_ENTRY_HIDDEN "logbook_entry_hidden"
53 #define XML_LOGBOOK_ENTRY_HIDER "logbook_entry_hider"
54 #define XML_LOGBOOK_ENTRY_HIDDEN_TIME "logbook_entry_hidden_time"
55 
56 #define XML_PREVIEW_INDEX "preview_index"
57 #define LOGBOOK_PREVIEW_FILE "preview.xml"
58 
59 XDAQ_INSTANTIATOR_IMPL(WizardSupervisor)
60 
61 #undef __MF_SUBJECT__
62 #define __MF_SUBJECT__ "Wizard"
63 
64 // init allowed file upload types
65 const std::vector<std::string> WizardSupervisor::allowedFileUploadTypes_ = {
66  "image/png",
67  "image/jpeg",
68  "image/gif",
69  "image/bmp",
70  "application/pdf",
71  "application/zip",
72  "text/plain"
73 };
74 const std::vector<std::string> WizardSupervisor::matchingFileUploadTypes_ = {
75  "png",
76  "jpeg",
77  "gif",
78  "ima/bmp",
79  "pdf",
80  "zip",
81  "txt"
82 };
83 
84 // clang-format on
85 
86 //==============================================================================
87 WizardSupervisor::WizardSupervisor(xdaq::ApplicationStub* s)
88  : xdaq::Application(s)
89  , SOAPMessenger(this)
90  , supervisorClass_(getApplicationDescriptor()->getClassName())
91  , supervisorClassNoNamespace_(
92  supervisorClass_.substr(supervisorClass_.find_last_of(":") + 1, supervisorClass_.length() - supervisorClass_.find_last_of(":")))
93 {
94  __COUT__ << "Constructor started." << __E__;
95 
96  INIT_MF("." /*directory used is USER_DATA/LOG/.*/);
97 
98  // get all supervisor info, and wiz mode, macroMaker mode, or not
99  allSupervisorInfo_.init(getApplicationContext());
100 
101  xgi::bind(this, &WizardSupervisor::Default, "Default");
102  xgi::bind(this, &WizardSupervisor::verification, "Verify");
103  xgi::bind(this, &WizardSupervisor::request, "Request");
104  xgi::bind(this, &WizardSupervisor::requestIcons, "requestIcons");
105  xgi::bind(this, &WizardSupervisor::editSecurity, "editSecurity");
106  xgi::bind(this, &WizardSupervisor::UserSettings, "UserSettings");
107  xgi::bind(this, &WizardSupervisor::tooltipRequest, "TooltipRequest");
108  xgi::bind(this, &WizardSupervisor::toggleSecurityCodeGeneration, "ToggleSecurityCodeGeneration");
109  xoap::bind(this, &WizardSupervisor::supervisorSequenceCheck, "SupervisorSequenceCheck", XDAQ_NS_URI);
110  xoap::bind(this, &WizardSupervisor::supervisorLastTableGroupRequest, "SupervisorLastTableGroupRequest", XDAQ_NS_URI);
111 
112  init();
113  generateURL();
114  GatewaySupervisor::indicateOtsAlive();
115 
116  __COUT__ << "Constructor complete." << __E__;
117 } // end constructor()
118 
119 //==============================================================================
120 WizardSupervisor::~WizardSupervisor(void) { destroy(); }
121 
122 //==============================================================================
123 void WizardSupervisor::init(void)
124 {
125  // attempt to make directory structure (just in case)
126  mkdir((WizardSupervisor::SERVICE_DATA_PATH).c_str(), 0755);
127  mkdir((WizardSupervisor::SERVICE_DATA_PATH + "/OtsWizardData").c_str(), 0755);
128 
129 } // end init()
130 
131 //==============================================================================
132 void WizardSupervisor::requestIcons(xgi::Input* in, xgi::Output* out)
133 {
134  cgicc::Cgicc cgi(in);
135 
136  std::string submittedSequence = CgiDataUtilities::postData(cgi, "sequence");
137 
138  // SECURITY CHECK START ****
139  if(securityCode_.compare(submittedSequence) != 0)
140  {
141  __COUT__ << "Unauthorized Request made, security sequence doesn't match! " << time(0) << std::endl;
142  return;
143  }
144  else
145  {
146  __COUT__ << "***Successfully authenticated security sequence. " << time(0) << std::endl;
147  }
148  // SECURITY CHECK END ****
149 
150  // an icon is 7 fields.. give comma-separated
151  // 0 - subtext = text below icon
152  // 1 - altText = text for icon if image set to 0
153  // 2 - uniqueWin = if true, only one window is allowed, else multiple instances of
154  // window 3 - permissions = security level needed to see icon 4 - picfn = icon image
155  // filename, 0 for no image 5 - linkurl = url of the window to open 6 - folderPath =
156  // folder and subfolder location
157 
158  // clang-format off
159  *out << "Configure,CFG,0,1,icon-Configure.png,/urn:xdaq-application:lid=280/,/"
160 
161  << ",Table Editor,TBL,0,1,icon-ControlsDashboard.png,"
162  "/urn:xdaq-application:lid=280/?configWindowName=tableEditor,/"
163 
164  << ",Desktop Icon Editor,ICON,0,1,icon-IconEditor.png,"
165  "/WebPath/html/ConfigurationGUI_subset.html?urn=280&subsetBasePath=DesktopIconTable&"
166  "recordAlias=Icons&groupingFieldList=Status%2CForceOnlyOneInstance%2CRequiredPermissionLevel,/"
167 
168  //User Settings ------------------
169  << ",Edit User Accounts,USER,1,1,"
170  "/WebPath/images/dashboardImages/icon-Settings.png,/WebPath/html/UserSettings.html,/User Settings"
171 
172  << ",Security Settings,SEC,1,1,icon-SecuritySettings.png,"
173  "/WebPath/html/SecuritySettings.html,/User Settings"
174 
175  << ",Edit User Data,USER,1,1,icon-EditUserData.png,/WebPath/html/EditUserData.html,/User Settings"
176 
177  //end User Settings ------------------
178 
179  << ",Console,C,1,1,icon-Console.png,/urn:xdaq-application:lid=260/,/"
180 
181  //Configuration Wizards ------------------
182  << ",Front-end Wizard,CFG,0,1,icon-Configure.png,"
183  "/WebPath/html/RecordWiz_ConfigurationGUI.html?urn=280&recordAlias=Front%2Dend,Config Wizards"
184 
185  << ",Processor Wizard,CFG,0,1,icon-Configure.png,"
186  "/WebPath/html/RecordWiz_ConfigurationGUI.html?urn=280&recordAlias=Processor,Config Wizards"
187 
188  << ",artdaq Config Editor,CFG,0,1,icon-Configure.png,"
189  "/WebPath/html/ConfigurationGUI_artdaq.html?urn=280,Config Wizards"
190 
191  << ",Block Diagram,CFG,0,1,icon-Configure.png,"
192  "/WebPath/html/ConfigurationSubsetBlockDiagram.html?urn=280,Config Wizards"
193  //end Configuration Wizards ------------------
194 
195  << ",Code Editor,CODE,0,1,icon-CodeEditor.png,/urn:xdaq-application:lid=240/,/"
196 
197  //Documentation ------------------
198  << ",State Machine Screenshot,FSM-SS,1,1,icon-Physics.gif,"
199  "/WebPath/images/windowContentImages/state_machine_screenshot.png,/Documentation"
200 
201  //uniqueWin mode == 2 for new tab
202  << ",Redmine Project for otsdaq,RED,2,1,../otsdaqIcons/android-icon-36x36.png,"
203  "https://cdcvs.fnal.gov/redmine/projects/otsdaq,/Documentation"
204  //uniqueWin mode == 2 for new tab
205  << ",Homepage for otsdaq,OTS,2,1,../otsdaqIcons/android-icon-36x36.png,"
206  "https://otsdaq.fnal.gov,/Documentation"
207  //end Documentation ------------------
208 
209  //",Iterate,IT,0,1,icon-Iterate.png,/urn:xdaq-application:lid=280/?configWindowName=iterate,/"
210  //<<
211  //",Configure,CFG,0,1,icon-Configure.png,/urn:xdaq-application:lid=280/,myFolder"
212  //<<
213  //",Configure,CFG,0,1,icon-Configure.png,/urn:xdaq-application:lid=280/,/myFolder/mySub.folder"
214  //<<
215  //",Configure,CFG,0,1,icon-Configure.png,/urn:xdaq-application:lid=280/,myFolder/"
216  //<<
217 
218 
219  //",Consumer
220  // Wizard,CFG,0,1,icon-Configure.png,/WebPath/html/RecordWiz_ConfigurationGUI.html?urn=280&subsetBasePath=FEInterfaceConfiguration&recordAlias=Consumer,Config
221  // Wizards" <<
222 
223  //",DB Utilities,DB,1,1,0,http://127.0.0.1:8080/db/client.html" <<
224 
225 
226  << "";
227  // clang-format on
228  return;
229 } // end requestIcons()
230 
231 //==============================================================================
232 void WizardSupervisor::verification(xgi::Input* in, xgi::Output* out)
233 {
234  cgicc::Cgicc cgi(in);
235  std::string submittedSequence = CgiDataUtilities::getData(cgi, "code");
236  __COUT__ << "submittedSequence=" << submittedSequence << " " << time(0) << std::endl;
237 
238  std::string securityWarning = "";
239 
240  if(securityCode_.compare(submittedSequence) != 0)
241  {
242  __COUT__ << "Unauthorized Request made, security sequence doesn't match!" << std::endl;
243  *out << "Invalid code.";
244  return;
245  }
246  else
247  {
248  // defaultSequence_ = false;
249  __COUT__ << "*** Successfully authenticated security sequence "
250  << "@ " << time(0) << std::endl;
251 
252  if(defaultSequence_)
253  {
254  //__COUT__ << " UNSECURE!!!" << std::endl;
255  securityWarning = "&secure=False";
256  }
257  }
258 
259  *out << "<!DOCTYPE HTML><html lang='en'><head><title>ots wiz</title>" << GatewaySupervisor::getIconHeaderString() <<
260  // end show ots icon
261  "</head>"
262  << "<frameset col='100%' row='100%'><frame src='/WebPath/html/Wizard.html?urn=" << this->getApplicationDescriptor()->getLocalId() << securityWarning
263  << "'></frameset></html>";
264 } // end verification()
265 
266 //==============================================================================
267 void WizardSupervisor::generateURL()
268 {
269  defaultSequence_ = true;
270 
271  int length = 4;
272  FILE* fp = fopen((SEQUENCE_FILE_NAME).c_str(), "r");
273  if(fp)
274  {
275  __COUT_INFO__ << "Sequence length file found: " << SEQUENCE_FILE_NAME << std::endl;
276  char line[100];
277  fgets(line, 100, fp);
278  sscanf(line, "%d", &length);
279  fclose(fp);
280  if(length < 4)
281  length = 4; // don't allow shorter than 4
282  else
283  defaultSequence_ = false;
284  srand(time(0)); // randomize differently each "time"
285  }
286  else
287  {
288  __COUT_INFO__ << "(Reverting to default wiz security) Sequence length file NOT found: " << SEQUENCE_FILE_NAME << std::endl;
289  srand(0); // use same seed for convenience if file not found
290  }
291 
292  __COUT__ << "Sequence length = " << length << std::endl;
293 
294  securityCode_ = "";
295 
296  const char alphanum[] =
297  "0123456789"
298  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
299  "abcdefghijklmnopqrstuvwxyz";
300 
301  for(int i = 0; i < length; ++i)
302  {
303  securityCode_ += alphanum[rand() % (sizeof(alphanum) - 1)];
304  }
305 
306  __COUT__ << WizardSupervisor::WIZ_SUPERVISOR << ":" << WizardSupervisor::WIZ_PORT
307  << "/urn:xdaq-application:lid=" << this->getApplicationDescriptor()->getLocalId() << "/Verify?code=" << securityCode_ << std::endl;
308 
309  // Note: print out handled by StartOTS.sh now
310  // std::thread([&](WizardSupervisor *ptr, std::string securityCode)
311  // {printURL(ptr,securityCode);},this,securityCode_).detach();
312 
313  fp = fopen((SEQUENCE_OUT_FILE_NAME).c_str(), "w");
314  if(fp)
315  {
316  fprintf(fp, "%s", securityCode_.c_str());
317  fclose(fp);
318  }
319  else
320  __COUT_ERR__ << "Sequence output file NOT found: " << SEQUENCE_OUT_FILE_NAME << std::endl;
321 
322  return;
323 } // end generateURL()
324 
325 void WizardSupervisor::printURL(WizardSupervisor* ptr, std::string securityCode)
326 {
327  // child process
328  int i = 0;
329  for(; i < 5; ++i)
330  {
331  std::this_thread::sleep_for(std::chrono::seconds(2));
332  __COUT__ << WizardSupervisor::WIZ_SUPERVISOR << ":" << WizardSupervisor::WIZ_PORT
333  << "/urn:xdaq-application:lid=" << ptr->getApplicationDescriptor()->getLocalId() << "/Verify?code=" << securityCode << std::endl;
334  }
335 } // end printURL()
336 
337 //==============================================================================
338 void WizardSupervisor::destroy(void)
339 {
340  // called by destructor
341 }
342 
343 //==============================================================================
344 void WizardSupervisor::tooltipRequest(xgi::Input* in, xgi::Output* out)
345 {
346  cgicc::Cgicc cgi(in);
347 
348  std::string Command = CgiDataUtilities::getData(cgi, "RequestType");
349  //__COUT__ << "Command = " << Command << std::endl;
350 
351  std::string submittedSequence = CgiDataUtilities::postData(cgi, "sequence");
352 
353  // SECURITY CHECK START ****
354  if(securityCode_.compare(submittedSequence) != 0)
355  {
356  __COUT__ << "Unauthorized Request made, security sequence doesn't match!" << std::endl;
357  return;
358  }
359  // else
360  // {
361  // __COUT__ << "***Successfully authenticated security sequence." << std::endl;
362  // }
363  // SECURITY CHECK END ****
364 
365  HttpXmlDocument xmldoc;
366 
367  if(Command == "check")
368  {
369  WebUsers::tooltipCheckForUsername(WebUsers::DEFAULT_ADMIN_USERNAME,
370  &xmldoc,
371  CgiDataUtilities::getData(cgi, "srcFile"),
372  CgiDataUtilities::getData(cgi, "srcFunc"),
373  CgiDataUtilities::getData(cgi, "srcId"));
374  }
375  else if(Command == "setNeverShow")
376  {
377  WebUsers::tooltipSetNeverShowForUsername(WebUsers::DEFAULT_ADMIN_USERNAME,
378  &xmldoc,
379  CgiDataUtilities::getData(cgi, "srcFile"),
380  CgiDataUtilities::getData(cgi, "srcFunc"),
381  CgiDataUtilities::getData(cgi, "srcId"),
382  CgiDataUtilities::getData(cgi, "doNeverShow") == "1" ? true : false,
383  CgiDataUtilities::getData(cgi, "temporarySilence") == "1" ? true : false);
384  }
385  else
386  __COUT__ << "Command Request, " << Command << ", not recognized." << std::endl;
387 
388  xmldoc.outputXmlDocument((std::ostringstream*)out, false, true);
389 } // end tooltipRequest()
390 
391 //==============================================================================
392 void WizardSupervisor::toggleSecurityCodeGeneration(xgi::Input* in, xgi::Output* out)
393 {
394  cgicc::Cgicc cgi(in);
395 
396  std::string Command = CgiDataUtilities::getData(cgi, "RequestType");
397  __COUT__ << "Got to Command = " << Command << std::endl;
398 
399  std::string submittedSequence = CgiDataUtilities::postData(cgi, "sequence");
400 
401  // SECURITY CHECK START ****
402  if(securityCode_.compare(submittedSequence) != 0)
403  {
404  __COUT__ << "Unauthorized Request made, security sequence doesn't match!" << std::endl;
405  return;
406  }
407  else
408  {
409  __COUT__ << "***Successfully authenticated security sequence." << std::endl;
410  }
411  // SECURITY CHECK END ****
412 
413  HttpXmlDocument xmldoc;
414 
415  if(Command == "TurnGenerationOn")
416  {
417  __COUT__ << "Turning automatic URL Generation on with a sequence depth of 16!" << std::endl;
418  std::ofstream outfile((SEQUENCE_FILE_NAME).c_str());
419  outfile << "16" << std::endl;
420  outfile.close();
421  generateURL();
422 
423  std::thread([&](WizardSupervisor* ptr, std::string securityCode) { printURL(ptr, securityCode); }, this, securityCode_).detach();
424 
425  xmldoc.addTextElementToData("Status", "Generation_Success");
426  }
427  else
428  __COUT__ << "Command Request, " << Command << ", not recognized." << std::endl;
429 
430  xmldoc.outputXmlDocument((std::ostringstream*)out, false, true);
431 }
432 
433 //==============================================================================
434 // xoap::supervisorSequenceCheck
435 // verify cookie
436 xoap::MessageReference WizardSupervisor::supervisorSequenceCheck(xoap::MessageReference message)
437 {
438  // SOAPUtilities::receive request parameters
439  SOAPParameters parameters;
440  parameters.addParameter("sequence");
441  SOAPUtilities::receive(message, parameters);
442 
443  std::string submittedSequence = parameters.getValue("sequence");
444 
445  // If submittedSequence matches securityCode_ then return full permissions (255)
446  // else, return permissions 0
447  std::map<std::string /*groupName*/, WebUsers::permissionLevel_t> permissionMap;
448 
449  if(securityCode_ == submittedSequence)
450  permissionMap.emplace(
451  std::pair<std::string /*groupName*/, WebUsers::permissionLevel_t>(WebUsers::DEFAULT_USER_GROUP, WebUsers::PERMISSION_LEVEL_ADMIN));
452  else
453  {
454  __COUT__ << "Unauthorized Request made, security sequence doesn't match!" << std::endl;
455 
456  permissionMap.emplace(
457  std::pair<std::string /*groupName*/, WebUsers::permissionLevel_t>(WebUsers::DEFAULT_USER_GROUP, WebUsers::PERMISSION_LEVEL_INACTIVE));
458  }
459 
460  // fill return parameters
461  SOAPParameters retParameters;
462  retParameters.addParameter("Permissions", StringMacros::mapToString(permissionMap));
463 
464  return SOAPUtilities::makeSOAPMessageReference("SequenceResponse", retParameters);
465 }
466 
467 //===================================================================================================================
468 // xoap::supervisorLastTableGroupRequest
469 // return the group name and key for the last state machine activity
470 //
471 // Note: same as Supervisor::supervisorLastTableGroupRequest
472 xoap::MessageReference WizardSupervisor::supervisorLastTableGroupRequest(xoap::MessageReference message)
473 {
474  SOAPParameters parameters;
475  parameters.addParameter("ActionOfLastGroup");
476  SOAPUtilities::receive(message, parameters);
477 
478  return GatewaySupervisor::lastTableGroupRequestHandler(parameters);
479 }
480 
481 //==============================================================================
482 void WizardSupervisor::Default(xgi::Input* /*in*/, xgi::Output* out)
483 {
484  __COUT__ << "Unauthorized Request made, security sequence doesn't match!" << std::endl;
485  *out << "Unauthorized Request.";
486 }
487 
488 //==============================================================================
489 void WizardSupervisor::request(xgi::Input* in, xgi::Output* out)
490 {
491  cgicc::Cgicc cgiIn(in);
492 
493  std::string submittedSequence = CgiDataUtilities::postData(cgiIn, "sequence");
494 
495  // SECURITY CHECK START ****
496  if(securityCode_.compare(submittedSequence) != 0)
497  {
498  __COUT__ << "Unauthorized Request made, security sequence doesn't match! " << time(0) << std::endl;
499  *out << WebUsers::REQ_NO_PERMISSION_RESPONSE.c_str();
500  return;
501  }
502  else
503  {
504  __COUT__ << "***Successfully authenticated security sequence. " << time(0) << std::endl;
505  }
506  // SECURITY CHECK END ****
507 
508  std::string requestType = CgiDataUtilities::getData(cgiIn, "RequestType");
509  __COUTV__(requestType);
510 
511  HttpXmlDocument xmlOut;
512 
513  try
514  {
515  // RequestType Commands:
516  // gatewayLaunchOTS
517  // gatewayLaunchWiz
518  // addDesktopIcon
519  // getSettings
520  // accountSettings
521 
522  if(requestType == "gatewayLaunchOTS" || requestType == "gatewayLaunchWiz")
523  {
524  // NOTE: similar to ConfigurationGUI version but DOES keep active login
525  // sessions
526 
527  __COUT_WARN__ << requestType << " requestType received! " << __E__;
528  __MOUT_WARN__ << requestType << " requestType received! " << __E__;
529 
530  // now launch
531  ConfigurationManager cfgMgr;
532  if(requestType == "gatewayLaunchOTS")
533  GatewaySupervisor::launchStartOTSCommand("LAUNCH_OTS", &cfgMgr);
534  else if(requestType == "gatewayLaunchWiz")
535  GatewaySupervisor::launchStartOTSCommand("LAUNCH_WIZ", &cfgMgr);
536  }
537  else if(requestType == "addDesktopIcon")
538  {
539  GatewaySupervisor::handleAddDesktopIconRequest("admin", cgiIn, xmlOut);
540  }
541  else if(requestType == "getAppId")
542  {
543  GatewaySupervisor::handleGetApplicationIdRequest(&allSupervisorInfo_, cgiIn, xmlOut);
544  }
545  else if(requestType == "getSettings")
546  {
547  std::string accounts = CgiDataUtilities::getData(cgiIn, "accounts");
548 
549  __COUT__ << "Get Settings Request" << __E__;
550  __COUT__ << "accounts = " << accounts << __E__;
551 
552  GatewaySupervisor::theWebUsers_.insertSettingsForUser(0 /*admin UID*/, &xmlOut, accounts == "1");
553  }
554  else if(requestType == "accountSettings")
555  {
556  std::string type = CgiDataUtilities::postData(cgiIn, "type"); // updateAccount, createAccount, deleteAccount
557  int type_int = -1;
558 
559  if(type == "updateAccount")
560  type_int = GatewaySupervisor::theWebUsers_.MOD_TYPE_UPDATE;
561  else if(type == "createAccount")
562  type_int = GatewaySupervisor::theWebUsers_.MOD_TYPE_ADD;
563  else if(type == "deleteAccount")
564  type_int = GatewaySupervisor::theWebUsers_.MOD_TYPE_DELETE;
565 
566  std::string username = CgiDataUtilities::postData(cgiIn, "username");
567  std::string displayname = CgiDataUtilities::postData(cgiIn, "displayname");
568  std::string email = CgiDataUtilities::postData(cgiIn, "useremail");
569  std::string permissions = CgiDataUtilities::postData(cgiIn, "permissions");
570  std::string accounts = CgiDataUtilities::getData(cgiIn, "accounts");
571 
572  __COUT__ << "accountSettings Request" << __E__;
573  __COUT__ << "type = " << type << " - " << type_int << __E__;
574  __COUT__ << "username = " << username << __E__;
575  __COUT__ << "useremail = " << email << __E__;
576  __COUT__ << "displayname = " << displayname << __E__;
577  __COUT__ << "permissions = " << permissions << __E__;
578 
579  GatewaySupervisor::theWebUsers_.modifyAccountSettings(0 /*admin UID*/, type_int, username, displayname, email, permissions);
580 
581  __COUT__ << "accounts = " << accounts << __E__;
582 
583  GatewaySupervisor::theWebUsers_.insertSettingsForUser(0 /*admin UID*/, &xmlOut, accounts == "1");
584  }
585  else
586  {
587  __SS__ << "requestType Request '" << requestType << "' not recognized." << __E__;
588  __SS_THROW__;
589  }
590  }
591  catch(const std::runtime_error& e)
592  {
593  __SS__ << "An error was encountered handling requestType '" << requestType << "':" << e.what() << __E__;
594  __COUT__ << "\n" << ss.str();
595  xmlOut.addTextElementToData("Error", ss.str());
596  }
597  catch(...)
598  {
599  __SS__ << "An unknown error was encountered handling requestType '" << requestType << ".' "
600  << "Please check the printouts to debug." << __E__;
601  __COUT__ << "\n" << ss.str();
602  xmlOut.addTextElementToData("Error", ss.str());
603  }
604 
605  // report any errors encountered
606  {
607  unsigned int occurance = 0;
608  std::string err = xmlOut.getMatchingValue("Error", occurance++);
609  while(err != "")
610  {
611  __COUT_ERR__ << "'" << requestType << "' ERROR encountered: " << err << __E__;
612  __MOUT_ERR__ << "'" << requestType << "' ERROR encountered: " << err << __E__;
613  err = xmlOut.getMatchingValue("Error", occurance++);
614  }
615  }
616 
617  // return xml doc holding server response
618  xmlOut.outputXmlDocument((std::ostringstream*)out, false /*dispStdOut*/, true /*allowWhiteSpace*/); // Note: allow white space need for error response
619 
620 } // end request()
621 
622 //==============================================================================
623 void WizardSupervisor::editSecurity(xgi::Input* in, xgi::Output* out)
624 {
625  // if sequence doesn't match up -> return
626  cgicc::Cgicc cgi(in);
627  std::string submittedSequence = CgiDataUtilities::postData(cgi, "sequence");
628  std::string submittedSecurity = CgiDataUtilities::postData(cgi, "selection");
629 
630  // SECURITY CHECK START ****
631  if(securityCode_.compare(submittedSequence) != 0)
632  {
633  __COUT__ << "Unauthorized Request made, security sequence doesn't match!" << std::endl;
634  return;
635  }
636  else
637  {
638  __COUT__ << "***Successfully authenticated security sequence." << std::endl;
639  }
640  // SECURITY CHECK END ****
641 
642  if(submittedSecurity != "")
643  {
644  __COUT__ << "Selection exists!" << std::endl;
645  __COUT__ << submittedSecurity << std::endl;
646 
647  if(submittedSecurity == "ResetAllUserData")
648  {
649  WebUsers::deleteUserData();
650  __COUT__ << "Turning URL Generation back to default!" << std::endl;
651  // std::remove((SEQUENCE_FILE_NAME).c_str());
652  // std::remove((SEQUENCE_OUT_FILE_NAME).c_str());
653  std::ofstream newFile((SEQUENCE_FILE_NAME).c_str());
654  newFile << "4" << std::endl;
655  newFile.close();
656 
657  generateURL();
658  std::thread([&](WizardSupervisor* ptr, std::string securityCode) { printURL(ptr, securityCode); }, this, securityCode_).detach();
659  *out << "Default_URL_Generation";
660  }
661  else if(submittedSecurity == "ResetAllUserTooltips")
662  {
663  WebUsers::resetAllUserTooltips();
664  *out << submittedSecurity;
665  return;
666  }
667  else if(submittedSecurity == WebUsers::SECURITY_TYPE_DIGEST_ACCESS || submittedSecurity == WebUsers::SECURITY_TYPE_NONE)
668  {
669  // attempt to make directory structure (just in case)
670  mkdir((WizardSupervisor::SERVICE_DATA_PATH).c_str(), 0755);
671  mkdir((WizardSupervisor::SERVICE_DATA_PATH + "/OtsWizardData").c_str(), 0755);
672 
673  std::ofstream writeSecurityFile;
674 
675  writeSecurityFile.open((SECURITY_FILE_NAME).c_str());
676  if(writeSecurityFile.is_open())
677  writeSecurityFile << submittedSecurity;
678  else
679  {
680  __COUT_ERR__ << "Error writing file!" << std::endl;
681  *out << "Error";
682  return;
683  }
684 
685  writeSecurityFile.close();
686  }
687  else
688  {
689  __COUT_ERR__ << "Invalid submittedSecurity string: " << submittedSecurity << std::endl;
690  *out << "Error";
691  return;
692  }
693  }
694 
695  {
696  // Always return the file
697  std::ifstream securityFile;
698  std::string security;
699 
700  securityFile.open((SECURITY_FILE_NAME).c_str());
701  if(securityFile.is_open())
702  {
703  std::getline(securityFile, security);
704  securityFile.close();
705  }
706  else
707  security = WebUsers::SECURITY_TYPE_DEFAULT; // default security when no file exists
708 
709  *out << security;
710  }
711 
712 } // end editSecurity()
713 
714 //==============================================================================
715 void WizardSupervisor::UserSettings(xgi::Input* in, xgi::Output* out)
716 {
717  // if sequence doesn't match up -> return
718  cgicc::Cgicc cgi(in);
719  std::string submittedSequence = CgiDataUtilities::postData(cgi, "sequence");
720  std::string securityFileName = SECURITY_FILE_NAME;
721  std::string Command;
722  if((Command = CgiDataUtilities::postData(cgi, "RequestType")) == "")
723  Command = cgi("RequestType"); // get command from form, if PreviewEntry
724 
725  __COUT__ << Command << std::endl;
726  __COUT__ << "We are vewing Users' Settings!" << std::endl;
727 
728  // SECURITY CHECK START ****
729  if(securityCode_.compare(submittedSequence) != 0)
730  {
731  __COUT__ << "Unauthorized Request made, security sequence doesn't match!" << std::endl;
732  __COUT__ << submittedSequence << std::endl;
733  // return;
734  }
735  else
736  {
737  __COUT__ << "***Successfully authenticated security sequence." << std::endl;
738  }
739  // SECURITY CHECK END ****
740 
741  HttpXmlDocument xmldoc;
742  //uint64_t activeSessionIndex;
743  std::string user;
744  //uint8_t userPermissions;
745 
746  if(Command != "")
747  {
748  __COUT__ << "Action exists!" << std::endl;
749  __COUT__ << Command << std::endl;
750 
751  if(Command == "Import")
752  {
753  // cleanup temporary folder
754  // NOTE: all input parameters for User Data will be attached to form
755  // so use cgi(xxx) to get values.
756  // increment number for each temporary preview, previewPostTempIndex_
757  // save entry and uploads to previewPath / previewPostTempIndex_ /.
758 
759  // cleanUpPreviews();
760  // std::string EntryText = cgi("EntryText");
761  // __COUT__ << "EntryText " << EntryText << std::endl << std::endl;
762  // std::string EntrySubject = cgi("EntrySubject");
763  // __COUT__ << "EntrySubject " << EntrySubject << std::endl <<
764  // std::endl;
765 
766  // get creator name
767  // std::string creator = user;
768  // CgiDataUtilities::postData(cgi, "file"); CgiDataUtilities::postData(cgi,
769  // "file");//
770  __COUT__ << cgi("Entry") << std::endl;
771  __COUT__ << cgi("Filename") << std::endl;
772  __COUT__ << cgi("Imported_File") << std::endl;
773 
774  const std::vector<cgicc::FormFile> files = cgi.getFiles();
775  __COUT__ << "FormFiles: " << sizeof(files) << std::endl;
776  __COUT__ << "Number of files: " << files.size() << std::endl;
777 
778  for(unsigned int i = 0; i < files.size(); ++i)
779  {
780  std::string filename = USER_IMPORT_EXPORT_PATH + files[i].getFilename();
781  __COUT__ << filename << std::endl;
782  std::ofstream myFile;
783  myFile.open(filename.c_str());
784  files[0].writeToStream(myFile);
785  }
786 
787  __COUT__ << files[0].getFilename() << std::endl;
788  __COUT__ << "********************Files Begin********************" << std::endl;
789  for(unsigned int i = 0; i < files.size(); ++i)
790  {
791  __COUT__ << files[i].getDataType() << std::endl;
792  }
793  __COUT__ << "*********************Files End*********************" << std::endl;
794 
795  // savePostPreview(EntrySubject, EntryText, cgi.getFiles(), creator,
796  //&xmldoc); else xmldoc.addTextElementToData(XML_STATUS,"Failed - could not
797  // get username info.");
798  }
799  else if(Command == "Export")
800  {
801  __SS__ << "This has been commented out due to problems compiling. Contact "
802  "system admins."
803  << __E__;
804  __SS_THROW__;
805  //
806  // __COUT__ << "We are exporting Users' Settings!!!" << std::endl;
807  // //system('pwd');
808  //
809  // //Check for a TMP directory; if it doesn't exist, make it
810  // std::string command = "cd " + USER_IMPORT_EXPORT_PATH;
811  // std::string pathToTmp = USER_IMPORT_EXPORT_PATH + "/tmp/";
812  // std::filesystem::path tmp = pathToTmp;
813  //
814  // exec(command.c_str());
815  // __COUT__ << exec("pwd") << std::endl;
816  //
817  //
818  // if(std::filesystem::status_known(tmpDir) ?
819  // std::filesystem::exists(tmpDir) : std::filesystem::exists(tmpDir))
820  // __COUT__ << pathToTmp << " exists!" << std::endl;
821  // else
822  // __COUT__ << pathToTmp << "does not exist! Creating it now. "
823  //<< std::endl;
824  //
825  // //Zip current files into TMP directory
826  // command = std::string("tar -cvf user_settings.tar") +
827  // std::string("ActiveTableGroups.cfg ") +
828  // std::string("ConsolePreferences ") +
829  // std::string("CoreTableInfoNames.dat ") +
830  // std::string("LoginData ") +
831  // std::string("OtsWizardData ") +
832  // std::string("ProgressBarData ");
833  //
834  //
835  // //return zip
836  // if(exec("pwd").find(USER_IMPORT_EXPORT_PATH) != std::string::npos)
837  // {
838  // __COUT__ << "Found USER_DATA directory " << std::endl;
839  // system(command.c_str());
840  // __COUT__ << system("ls") << std::endl;
841  // }
842  }
843  else
844  {
845  __COUT__ << "Command request not recognized: " << Command << std::endl;
846  *out << "Error";
847  return;
848  }
849  }
850 
851  *out << "test";
852  return;
853 }
854 //==============================================================================
855 // validateUploadFileType
856 // returns "" if file type is invalid, else returns file extension to use
857 std::string WizardSupervisor::validateUploadFileType(const std::string fileType)
858 {
859  for(unsigned int i = 0; i < allowedFileUploadTypes_.size(); ++i)
860  if(allowedFileUploadTypes_[i] == fileType)
861  return matchingFileUploadTypes_[i]; // found and done
862 
863  return ""; // not valid, return ""
864 }
865 //==============================================================================
866 // cleanUpPreviews
867 // cleanup logbook preview directory
868 // all names have time_t creation time + "_" + incremented index
869 void WizardSupervisor::cleanUpPreviews()
870 {
871  std::string userData = (std::string)USER_IMPORT_EXPORT_PATH;
872 
873  DIR* dir = opendir(userData.c_str());
874  if(!dir)
875  {
876  __COUT__ << "Error - User Data directory missing: " << userData << std::endl;
877  return;
878  }
879 
880  struct dirent* entry;
881  time_t dirCreateTime;
882  unsigned int i;
883 
884  while((entry = readdir(dir))) // loop through all entries in directory and remove anything expired
885  {
886  if(strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0 && strcmp(entry->d_name, ".svn") != 0)
887  {
888  // replace _ with space so sscanf works
889  for(i = 0; i < strlen(entry->d_name); ++i)
890  if(entry->d_name[i] == '_')
891  {
892  entry->d_name[i] = ' ';
893  break;
894  }
895  sscanf(entry->d_name, "%li", &dirCreateTime);
896 
897  if((time(0) - dirCreateTime) > USER_DATA_EXPIRATION_TIME)
898  {
899  __COUT__ << "Expired" << std::endl;
900 
901  entry->d_name[i] = '_'; // put _ back
902 
903  __COUT__ << "rm -rf " << USER_IMPORT_EXPORT_PATH + (std::string)entry->d_name << std::endl << std::endl;
904  system(((std::string)("rm -rf " + userData + (std::string)entry->d_name)).c_str());
905  }
906  }
907  }
908 
909  closedir(dir);
910 }
911 
912 //==============================================================================
913 // savePostPreview
914 // save post to preview directory named with time and incremented index
915 void WizardSupervisor::savePostPreview(
916  std::string& /*subject*/, std::string& /*text*/, const std::vector<cgicc::FormFile>& /*files*/, std::string /*creator*/, HttpXmlDocument* xmldoc)
917 {
918  /*if(activeExperiment_ == "") //no active experiment!
919  {
920  if(xmldoc) xmldoc->addTextElementToData(XML_STATUS,"Failed - no active experiment
921  currently!"); return;
922  }
923 */
924  char fileIndex[40];
925  sprintf(fileIndex, "%lu_%lu", time(0),
926  clock()); // create unique time label for entry time(0)_clock()
927  std::string userDataPath = (std::string)USER_IMPORT_EXPORT_PATH + (std::string)fileIndex;
928 
929  __COUT__ << "userDataPath " << userDataPath << std::endl;
930  if(-1 == mkdir(userDataPath.c_str(), 0755))
931  {
932  if(xmldoc)
933  xmldoc->addTextElementToData(XML_STATUS, "Failed - directory could not be generated.");
934  return;
935  }
936  /*
937  //new directory created successfully, save text and files
938  //entry structure:
939  // <XML_LOGBOOK_ENTRY>
940  // <XML_LOGBOOK_ENTRY_TIME>
941  // <XML_LOGBOOK_ENTRY_CREATOR>
942  // <XML_LOGBOOK_ENTRY_SUBJECT>
943  // <XML_LOGBOOK_ENTRY_TEXT>
944  // <XML_LOGBOOK_ENTRY_FILE value=fileType0>
945  // <XML_LOGBOOK_ENTRY_FILE value=fileType1> ...
946  // </XML_LOGBOOK_ENTRY>
947 
948  escapeLogbookEntry(text);
949  escapeLogbookEntry(subject);
950  __COUT__ << "~~subject " << subject << std::endl << "~~text " << text << std::endl <<
951  std::endl;
952 
953  HttpXmlDocument previewXml;
954 
955  previewXml.addTextElementToData(XML_LOGBOOK_ENTRY);
956  previewXml.addTextElementToParent(XML_LOGBOOK_ENTRY_TIME, fileIndex,
957  XML_LOGBOOK_ENTRY); if(xmldoc)
958  xmldoc->addTextElementToData(XML_LOGBOOK_ENTRY_TIME,fileIndex); //return time
959  previewXml.addTextElementToParent(XML_LOGBOOK_ENTRY_CREATOR, creator,
960  XML_LOGBOOK_ENTRY); if(xmldoc)
961  xmldoc->addTextElementToData(XML_LOGBOOK_ENTRY_CREATOR,creator); //return creator
962  previewXml.addTextElementToParent(XML_LOGBOOK_ENTRY_TEXT, text, XML_LOGBOOK_ENTRY);
963  if(xmldoc) xmldoc->addTextElementToData(XML_LOGBOOK_ENTRY_TEXT,text); //return text
964  previewXml.addTextElementToParent(XML_LOGBOOK_ENTRY_SUBJECT, subject,
965  XML_LOGBOOK_ENTRY); if(xmldoc)
966  xmldoc->addTextElementToData(XML_LOGBOOK_ENTRY_SUBJECT,subject); //return subject
967 
968  __COUT__ << "file size " << files.size() << std::endl;
969 
970  std::string filename;
971  std::ofstream myfile;
972  for (unsigned int i=0; i<files.size(); ++i)
973  {
974 
975  previewXml.addTextElementToParent(XML_LOGBOOK_ENTRY_FILE, files[i].getDataType(),
976  XML_LOGBOOK_ENTRY); if(xmldoc)
977  xmldoc->addTextElementToData(XML_LOGBOOK_ENTRY_FILE,files[i].getDataType()); //return
978  file type
979 
980  if((filename = validateUploadFileType(files[i].getDataType())) == "") //invalid
981  file type
982  {
983  if(xmldoc) xmldoc->addTextElementToData(XML_STATUS,"Failed - invalid file
984  type, " + files[i].getDataType() + "."); return;
985  }*/
986 
987  /*//file validated, so save upload to temp directory
988  sprintf(fileIndex,"%d",i);
989  filename = previewPath + "/" + (std::string)LOGBOOK_PREVIEW_UPLOAD_PREFACE +
990  (std::string)fileIndex + "." + filename;
991 
992  __COUT__ << "file " << i << " - " << filename << std::endl;
993  myfile.open(filename.c_str());
994  if (myfile.is_open())
995  {
996  files[i].writeToStream(myfile);
997  myfile.close();
998  }
999  }*/
1000  /*
1001  //save xml doc for preview entry
1002  previewXml.saveXmlDocument(USER_IMPORT_EXPORT_PATH + "/" + (std::string)LOGBOOK_PREVIEW_FILE);
1003 
1004  if(xmldoc) xmldoc->addTextElementToData(XML_STATUS,"1"); //1 indicates success!
1005  if(xmldoc) xmldoc->addTextElementToData(XML_PREVIEW_INDEX,"1"); //1 indicates is a
1006  preview post*/
1007 }