otsdaq  3.03.00
DesktopIconTableImpl.cc
1 #include "otsdaq/ConfigurationInterface/ConfigurationManager.h"
2 #include "otsdaq/Macros/TablePluginMacros.h"
3 #include "otsdaq/TablePlugins/DesktopIconTable.h"
4 #include "otsdaq/TablePlugins/XDAQContextTable/XDAQContextTable.h"
5 
6 #include "otsdaq/WebUsersUtilities/WebUsers.h"
7 
8 #include <stdio.h>
9 #include <fstream> // std::fstream
10 #include <iostream>
11 using namespace ots;
12 
13 #define DESKTOP_ICONS_FILE \
14  std::string(__ENV__("SERVICE_DATA_PATH")) + "/OtsWizardData/iconList.dat"
15 
18 const std::string DesktopIconTable::COL_NAME = "IconName";
19 const std::string DesktopIconTable::COL_STATUS = TableViewColumnInfo::COL_NAME_STATUS;
20 const std::string DesktopIconTable::COL_CAPTION = "Caption";
21 const std::string DesktopIconTable::COL_ALTERNATE_TEXT = "AlternateText";
22 const std::string DesktopIconTable::COL_FORCE_ONLY_ONE_INSTANCE = "ForceOnlyOneInstance";
23 const std::string DesktopIconTable::COL_PERMISSIONS = "RequiredPermissionLevel";
24 const std::string DesktopIconTable::COL_IMAGE_URL = "ImageURL";
25 const std::string DesktopIconTable::COL_WINDOW_CONTENT_URL = "WindowContentURL";
26 const std::string DesktopIconTable::COL_APP_LINK = "LinkToApplicationTable";
27 const std::string DesktopIconTable::COL_APP_LINK_UID = "LinkToApplicationUID";
28 
29 const std::string DesktopIconTable::COL_PARAMETER_LINK = "LinkToParameterTable";
30 const std::string DesktopIconTable::COL_PARAMETER_LINK_GID = "LinkToParameterGroupID";
31 const std::string DesktopIconTable::COL_FOLDER_PATH = "FolderPath";
32 
33 const std::string DesktopIconTable::COL_PARAMETER_GID = "windowParameterGroupID";
34 const std::string DesktopIconTable::COL_PARAMETER_KEY = "windowParameterKey";
35 const std::string DesktopIconTable::COL_PARAMETER_VALUE = "windowParameterValue";
36 
37 const std::string DesktopIconTable::ICON_TABLE =
38  ConfigurationManager::DESKTOP_ICON_TABLE_NAME;
39 const std::string DesktopIconTable::PARAMETER_TABLE = "DesktopWindowParameterTable";
40 
41 // #define COL_NAME "IconName"
42 // #define COL_STATUS TableViewColumnInfo::COL_NAME_STATUS
43 // #define COL_CAPTION "Caption"
44 // #define COL_ALTERNATE_TEXT "AlternateText"
45 // #define COL_FORCE_ONLY_ONE_INSTANCE "ForceOnlyOneInstance"
46 // #define COL_REQUIRED_PERMISSION_LEVEL "RequiredPermissionLevel"
47 // #define COL_IMAGE_URL "ImageURL"
48 // #define COL_WINDOW_CONTENT_URL "WindowContentURL"
49 // #define COL_APP_LINK "LinkToApplicationTable"
50 // #define COL_PARAMETER_LINK "LinkToParameterTable"
51 // #define COL_PARAMETER_KEY "windowParameterKey"
52 // #define COL_PARAMETER_VALUE "windowParameterValue"
53 // #define COL_FOLDER_PATH "FolderPath"
54 
56 const std::string DesktopIconTable::COL_APP_ID = "Id";
57 // #define COL_APP_ID "Id"
58 
59 //==============================================================================
60 DesktopIconTable::DesktopIconTable(void) : TableBase(DesktopIconTable::ICON_TABLE)
61 {
62  // Icon list no longer passes through file! so delete it from user's $USER_DATA
63  std::system(("rm -rf " + (std::string)DESKTOP_ICONS_FILE).c_str());
64 
66  // WARNING: the names used in C++ MUST match the Table INFO //
68 }
69 
70 //==============================================================================
71 DesktopIconTable::~DesktopIconTable(void) {}
72 
73 //==============================================================================
75 {
76  // __COUT__ << "*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*" << std::endl;
77  // __COUT__ << configManager->__SELF_NODE__ << std::endl;
78 
79  unsigned int intVal;
80 
81  auto childrenMap = configManager->__SELF_NODE__.getChildren();
82 
83  ConfigurationTree contextTableNode =
84  configManager->getNode(ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME);
85  const XDAQContextTable* contextTable = configManager->getTable<XDAQContextTable>(
86  ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME);
87 
88  // find gateway host origin string, to avoid modifying icons with same host
89  std::string gatewayContextUID = contextTable->getContextOfGateway(configManager);
90 
91  activeDesktopIcons_.clear();
92 
94  bool addedAppId;
95  bool numeric;
96  unsigned int i;
97  for(auto& child : childrenMap)
98  {
99  if(!child.second.getNode(COL_STATUS).getValue<bool>())
100  continue;
101  // __COUTV__(child.first);
102 
103  activeDesktopIcons_.push_back(DesktopIconTable::DesktopIcon());
104  icon = &(activeDesktopIcons_.back());
105 
106  icon->recordUID_ = child.first;
107  icon->caption_ = child.second.getNode(COL_CAPTION).getValue<std::string>();
108  icon->alternateText_ =
109  child.second.getNode(COL_ALTERNATE_TEXT).getValue<std::string>();
110  icon->enforceOneWindowInstance_ =
111  child.second.getNode(COL_FORCE_ONLY_ONE_INSTANCE).getValue<bool>();
113  child.second.getNode(COL_PERMISSIONS).getValue<std::string>();
114  icon->imageURL_ = child.second.getNode(COL_IMAGE_URL).getValue<std::string>();
115  icon->windowContentURL_ =
116  child.second.getNode(COL_WINDOW_CONTENT_URL).getValue<std::string>();
117  icon->folderPath_ = child.second.getNode(COL_FOLDER_PATH).getValue<std::string>();
118 
119  if(icon->windowContentURL_.size() == 0)
120  {
121  __SS__ << "Illegal empty URL in Desktop Icon '" << child.first << "'"
122  << __E__;
123  __SS_THROW__;
124  }
125 
126  if(icon->folderPath_ == TableViewColumnInfo::DATATYPE_STRING_DEFAULT)
127  icon->folderPath_ = ""; // convert DEFAULT to empty string
128 
129  if(icon->permissionThresholdString_ ==
130  TableViewColumnInfo::DATATYPE_STRING_DEFAULT)
132  "1"; // convert DEFAULT to standard user allow
133 
134  numeric = true;
135  for(i = 0; i < icon->permissionThresholdString_.size(); ++i)
136  if(!(icon->permissionThresholdString_[i] >= '0' &&
137  icon->permissionThresholdString_[i] <= '9'))
138  {
139  numeric = false;
140  break;
141  }
142  // for backwards compatibility, if permissions threshold is a single number
143  // assume it is the threshold intended for the WebUsers::DEFAULT_USER_GROUP group
144  if(numeric)
146  WebUsers::DEFAULT_USER_GROUP + ":" + icon->permissionThresholdString_;
147 
148  // remove all commas from member strings because desktop icons are served to
149  // client in comma-separated string
150  icon->caption_ = removeCommas(
151  icon->caption_, false /*andHexReplace*/, true /*andHTMLReplace*/);
152  icon->alternateText_ = removeCommas(
153  icon->alternateText_, false /*andHexReplace*/, true /*andHTMLReplace*/);
154  icon->imageURL_ = removeCommas(icon->imageURL_, true /*andHexReplace*/);
155  icon->windowContentURL_ =
156  removeCommas(icon->windowContentURL_, true /*andHexReplace*/);
157  icon->folderPath_ = removeCommas(
158  icon->folderPath_, false /*andHexReplace*/, true /*andHTMLReplace*/);
159 
160  // add application origin and URN/LID to windowContentURL_, if link is given
161  addedAppId = false;
162  ConfigurationTree appLink = child.second.getNode(COL_APP_LINK);
163  if(!appLink.isDisconnected())
164  {
165  // first check app origin
166  if(icon->windowContentURL_.size() && icon->windowContentURL_[0] == '/')
167  {
168  // if starting with opening slash, then assume app should come from
169  // appLink context's origin (to avoid cross-origin issues communicating
170  // with app/supervisor)
171  try
172  {
173  std::string contextUID = contextTable->getContextOfApplication(
174  configManager,
175  appLink.getValueAsString(),
176  true /* allowOffContexts */);
177 
178  if(!appLink
179  .isEnabled()) //demoting off apps, from exception to error, to make it less annoying for users that are disabling apps
180  __COUT_WARN__
181  << "Warning! The target app '" << appLink.getValueAsString()
182  << "' is disabled, which will likely break the behavior of "
183  "the Desktop Icon '"
184  << child.first << ".' To fix, reenable the target app."
185  << __E__;
186 
187  // only prepend address if not same as gateway
188  if(contextUID != gatewayContextUID)
189  {
190  // __COUTV__(contextUID);
191  ConfigurationTree contextNode =
192  contextTableNode.getNode(contextUID);
193 
194  if(!contextNode
195  .isEnabled()) //demoting off apps, from exception to error, to make it less annoying for users that are disabling apps
196  __COUT_WARN__
197  << "Warning! The parent context '" << contextUID
198  << "' of the target app '" << appLink.getValueAsString()
199  << "' is disabled, which will likely break the behavior "
200  "of the Desktop Icon '"
201  << child.first
202  << ".' To fix, reenable the target app's parent context."
203  << __E__;
204 
205  std::string contextAddress =
206  contextNode.getNode(XDAQContextTable::colContext_.colAddress_)
207  .getValue<std::string>();
208  unsigned int contextPort =
209  contextNode.getNode(XDAQContextTable::colContext_.colPort_)
210  .getValue<unsigned int>();
211 
212  //__COUTV__(contextAddress);
213  icon->windowContentURL_ = contextAddress + ":" +
214  std::to_string(contextPort) +
215  icon->windowContentURL_;
216  //__COUTV__(icon->windowContentURL_);
217  }
218  }
219  catch(const std::runtime_error& e)
220  {
221  __SS__ << "Error finding XDAQ Application origin which was linked to "
222  "Desktop Icon '"
223  << child.first << "': " << e.what() << __E__;
224  ss << "\n\nPlease fix by disabling the Icon, enabling the App or "
225  "fixing the link in the Configurate Tree."
226  << __E__;
227  __SS_THROW__;
228  }
229  } // end app origin check
230 
231  // if last character is not '='
232  // then assume need to add "?urn="
233  if(icon->windowContentURL_[icon->windowContentURL_.size() - 1] != '=')
234  {
235  if(icon->windowContentURL_.find('?') ==
236  std::string::npos) //if no ? already
237  icon->windowContentURL_ += "?urn=";
238  else
239  icon->windowContentURL_ += "&urn=";
240  }
241 
242  // __COUT__ << "Following Application link." << std::endl;
243  appLink.getNode(COL_APP_ID).getValue(intVal);
244  icon->windowContentURL_ += std::to_string(intVal);
245 
246  // __COUT__ << "URN/LID=" << intVal << std::endl;
247  addedAppId = true;
248  }
249  // __COUTV__(icon->windowContentURL_);
250 
251  // add parameters if link is given
252  if(!child.second.getNode(COL_PARAMETER_LINK).isDisconnected())
253  {
254  // if there is no '?' found
255  // then assume need to add "?"
256  if(icon->windowContentURL_.find('?') == std::string::npos)
257  icon->windowContentURL_ += '?';
258  else if(addedAppId ||
259  icon->windowContentURL_[icon->windowContentURL_.size() - 1] !=
260  '?') // if not first parameter, add &
261  icon->windowContentURL_ += '&';
262 
263  // now add each paramter separated by &
264  auto paramGroupMap = child.second.getNode(COL_PARAMETER_LINK).getChildren();
265  bool notFirst = false;
266  for(const auto& param : paramGroupMap)
267  {
268  if(!param.second.isEnabled())
269  continue;
270 
271  if(notFirst)
272  icon->windowContentURL_ += '&';
273  else
274  notFirst = true;
275  icon->windowContentURL_ +=
276  StringMacros::encodeURIComponent(
277  param.second.getNode(COL_PARAMETER_KEY).getValue<std::string>()) +
278  "=" +
279  StringMacros::encodeURIComponent(
280  param.second.getNode(COL_PARAMETER_VALUE)
281  .getValue<std::string>());
282  }
283  }
284  } // end main icon extraction loop
285 
286 } // end init()
287 
288 //==============================================================================
291  const std::string& localURL) const
292 {
293  std::string retURL;
294  std::string contextAddress;
295 
296  if(localURL.size() && localURL[0] == '/')
297  {
298  ConfigurationTree contextTableNode =
299  configManager->getNode(ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME);
300  const XDAQContextTable* contextTable = configManager->getTable<XDAQContextTable>(
301  ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME);
302 
303  std::string gatewayContextUID = contextTable->getContextOfGateway(configManager);
304  ConfigurationTree contextNode = contextTableNode.getNode(gatewayContextUID);
305 
306  contextAddress = contextNode.getNode(XDAQContextTable::colContext_.colAddress_)
307  .getValue<std::string>();
308  unsigned int contextPort =
309  contextNode.getNode(XDAQContextTable::colContext_.colPort_)
310  .getValue<unsigned int>();
311 
312  try
313  {
314  if(__ENV__(
315  "OTS_REMOTE_ICONS_NO_PORT_FOWARDING")) //define this environment variable to not use localhost port forwarding to browser
316  contextAddress += ":" + std::to_string(contextPort);
317  else
318  contextAddress = std::string("http://") + "localhost" + ":" +
319  std::to_string(contextPort);
320  }
321  catch(...)
322  {
323  __COUTT__ << "Ignoring missing environment variable "
324  "OTS_REMOTE_ICONS_NO_PORT_FOWARDING, and assuming localhost "
325  "port forwarding to web browser."
326  << __E__;
327  contextAddress =
328  std::string("http://") + "localhost" + ":" + std::to_string(contextPort);
329  }
330  retURL = contextAddress + localURL;
331  }
332  else //if no starting '/' assume URL is already complete
333  retURL = localURL;
334 
335  //now add get parameters for remoteGateway
336  // if there is no '?' found
337  // then assume need to add "?"
338  if(retURL.find('?') == std::string::npos)
339  retURL += '?';
340  else if(retURL[retURL.size() - 1] != '?') // if not first parameter, add &
341  retURL += '&';
342  retURL += "remoteServerOrigin=" + StringMacros::encodeURIComponent(contextAddress) +
343  "&remoteServerUrnLid=" +
344  std::to_string(XDAQContextTable::XDAQApplication::GATEWAY_APP_ID);
345 
346  return retURL;
347 } // end getRemoteURL()
348 
349 //==============================================================================
350 std::string DesktopIconTable::removeCommas(const std::string& str,
351  bool andHexReplace,
352  bool andHTMLReplace)
353 {
354  std::string retStr = "";
355  retStr.reserve(str.length());
356 
357  for(unsigned int i = 0; i < str.length(); ++i)
358  if(str[i] != ',')
359  retStr += str[i];
360  else if(andHexReplace)
361  retStr += "%2C";
362  else if(andHTMLReplace)
363  retStr += "&#44;";
364 
365  return retStr;
366 } // end removeCommas()
367 
368 //==============================================================================
370  const std::vector<DesktopIconTable::DesktopIcon>& newIcons)
371 {
372  activeDesktopIcons_.clear();
373  for(const auto& newIcon : newIcons)
374  activeDesktopIcons_.push_back(newIcon);
375 
376 } // end setAllDesktopIcons
377 
378 DEFINE_OTS_TABLE(DesktopIconTable)
ConfigurationTree getNode(const std::string &nodeString, bool doNotThrowOnBrokenUIDLinks=false) const
"root/parent/parent/"
const T * getTable(const std::string &tableName) const
std::vector< std::pair< std::string, ConfigurationTree > > getChildren(std::map< std::string, TableVersion > *memberMap=0, std::string *accumulatedTreeErrors=0) const
bool isDisconnected(void) const
ConfigurationTree getNode(const std::string &nodeName, bool doNotThrowOnBrokenUIDLinks=false) const
navigating between nodes
const std::string & getValueAsString(bool returnLinkTableValue=false) const
void getValue(T &value) const
std::string getRemoteURL(ConfigurationManager *configManager, const std::string &localURL) const
Convert to remote URL assuming port forwarding to primary Gateway Port.
void init(ConfigurationManager *configManager)
Methods.
void setAllDesktopIcons(const std::vector< DesktopIconTable::DesktopIcon > &newIcons)
overwrite dynamically the init result
static const std::string COL_APP_ID
XDAQ App Column names.
static const std::string COL_NAME
std::string getContextOfApplication(ConfigurationManager *configManager, const std::string &appUID, bool allowOffContexts=false) const
only considers ON contexts and applications, unless off contexts allows
std::string getContextOfGateway(ConfigurationManager *configManager) const
only considers ON contexts and applications