otsdaq  v2_03_00
DesktopIconTable_table.cc
1 #include "otsdaq-core/ConfigurationInterface/ConfigurationManager.h"
2 #include "otsdaq-core/Macros/TablePluginMacros.h"
3 #include "otsdaq-core/TablePluginDataFormats/DesktopIconTable.h"
4 #include "otsdaq-core/WebUsersUtilities/WebUsers.h"
5 
6 #include <stdio.h>
7 #include <fstream> // std::fstream
8 #include <iostream>
9 using namespace ots;
10 
11 #define DESKTOP_ICONS_FILE \
12  std::string(getenv("SERVICE_DATA_PATH")) + "/OtsWizardData/iconList.dat"
13 
14 // DesktopIconTable Column names
15 #define COL_NAME "IconName"
16 #define COL_STATUS TableViewColumnInfo::COL_NAME_STATUS
17 #define COL_CAPTION "Caption"
18 #define COL_ALTERNATE_TEXT "AlternateText"
19 #define COL_FORCE_ONLY_ONE_INSTANCE "ForceOnlyOneInstance"
20 #define COL_REQUIRED_PERMISSION_LEVEL "RequiredPermissionLevel"
21 #define COL_IMAGE_URL "ImageURL"
22 #define COL_WINDOW_CONTENT_URL "WindowContentURL"
23 #define COL_APP_LINK "LinkToApplicationTable"
24 #define COL_PARAMETER_LINK "LinkToParameterTable"
25 #define COL_PARAMETER_KEY "windowParameterKey"
26 #define COL_PARAMETER_VALUE "windowParameterValue"
27 #define COL_FOLDER_PATH "FolderPath"
28 
29 // XDAQ App Column names
30 #define COL_APP_ID "Id"
31 
32 //==============================================================================
33 DesktopIconTable::DesktopIconTable(void) : TableBase("DesktopIconTable")
34 {
35  // Icon list no longer passes through file! so delete it from user's $USER_DATA
36  std::system(("rm -rf " + (std::string)DESKTOP_ICONS_FILE).c_str());
37 
39  // WARNING: the names used in C++ MUST match the Table INFO //
41 
42  // <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
43  // <ROOT xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
44  // xsi:noNamespaceSchemaLocation="TableInfo.xsd"> <TABLE
45  // Name="DesktopIconTable">
46  // <VIEW Name="DESKTOP_ICON_TABLE"
47  // Type="File,Database,DatabaseTest"
48  // Description="This%20table%20is%20used%20to%20specify%20the%20Icons%20available%20on%20the%20otsdaq%20Desktop.%20%0A%0AUsually%20a%20Desktop%20Icon%20opens%20the%20GUI%20to%20an%20otsdaq%20app%2C%20but%20an%20Icon%20may%20be%20configured%20to%20open%20any%20content%20accessible%20through%20the%20user's%20browser%20(Note%3A%20the%20target%20server%20may%20have%20to%20allow%20cross-origin%20requests%20for%20full%20functionality).%20%0A%0AHere%20is%20an%20explanation%20of%20the%20features%20associated%20with%20each%20column%3A%0A%3CINDENT%3E%0A-%20IconName%3A%0A%3CINDENT%3EThis%20is%20the%20unique%20ID%20value%20for%20each%20row.%3C%2FINDENT%3E%0A-%20Status%3A%0A%3CINDENT%3EIf%20On%2C%20the%20Icon%20will%20be%20shown%20on%20the%20Desktop.%20When%20Off%2C%20the%20Icon%20will%20not%20be%20displayed.%3C%2FINDENT%3E%0A-%20Caption%3A%0A%3CINDENT%3EThis%20is%20the%20text%20shown%20underneath%20the%20Icon.%3C%2FINDENT%3E%0A-%20AlternateText%3A%0A%3CINDENT%3EIf%20the%20ImageURL%20is%20omitted%20(left%20as%20default%20or%20blank)%2C%20then%20the%20alternate%20text%20is%20used%20in%20place%20of%20the%20Icon%20image.%20This%20is%20useful%20if%20you%20have%20not%20yet%20found%20an%20image%20to%20use%20for%20a%20particular%20icon.%3C%2FINDENT%3E%0A-%20ForceOnlyOneInstance%3A%0A%3CINDENT%3EIf%20True%2C%20then%20only%20window%20is%20allowed%20on%20the%20Desktop.%20If%20False%2C%20then%20each%20time%20the%20Icon%20is%20clicked%20a%20new%20instance%20of%20the%20window%20will%20open.%20For%20example%2C%20it%20is%20common%20to%20force%20only%20one%20instance%20of%20the%20state%20machine%20window.%3C%2FINDENT%3E%0A-%20RequiredPermissionLevel%3A%0A%3CINDENT%3EThis%20value%20is%20the%20minimum%20permission%20level%20for%20a%20user%20to%20have%20access%20to%20this%20Icon.%20If%20a%20user%20has%20insufficient%20access%2C%20the%20Icon%20will%20not%20appear%20on%20their%20Desktop.%20As%20a%20reminder%2C%20permission%20levels%20go%20from%201%20(lowest)%20to%20255%20(admin-level)%3B%20and%20only%20admins%20can%20modify%20the%20access%20level%20of%20users.%3C%2FINDENT%3E%0A-%20ImageURL%3A%0A%3CINDENT%3EThis%20is%20the%20URL%20to%20the%20image%20used%20for%20the%20Icon.%20The%20native%20resolution%20for%20Icons%20is%2064%20x%2064%20pixels.%20If%20left%20as%20the%20default%20value%20or%20blank%2C%20the%20the%20AlternateText%20field%20will%20be%20used%20for%20the%20Icon%20image.%3C%2FINDENT%3E%0A-%20WindowContentURL%3A%0A%3CINDENT%3EThis%20is%20the%20URL%20of%20the%20window%20content%20that%20will%20be%20opened%20when%20the%20user%20clicks%20this%20Icon.%20The%20window%20content%20is%20usually%20an%20otsdaq%20app%20but%20may%20be%20any%20web%20content%20accessible%20through%20the%20user's%20browser.%3C%2FINDENT%3E%0A-%20LinkToApplicationTable%2FApplicationUID%3A%0A%3CINDENT%3EWhen%20the%20Icon%20refers%20to%20an%20otsdaq%20app%2C%20these%20two%20fields%20comprise%20the%20table%20link%20that%20connects%20the%20Icon%20to%20the%20app's%20ID%20-%20the%20app%20ID%20is%20used%20to%20target%20the%20app%20when%20sending%20requests.%20The%20LinkToApplicationTable%20field%20is%20the%20table%20table%20part%20of%20the%20link%20and%20the%20ApplicationUID%20field%20is%20the%20UID%20part%20of%20the%20link.%3C%2FINDENT%3E%0A-%20FolderPath%3A%0A%3CINDENT%3EThis%20field%20is%20used%20to%20organize%20Icons%20into%20folders%20on%20the%20Desktop.%20For%20example%2C%20a%20value%20of%20%22myFolder%2FmySubfolder%22%20places%20this%20Icon%20inside%20a%20folder%20named%20%22mySubFolder%22%20which%20is%20inside%20the%20folder%20%22myFolder%22%20on%20the%20Desktop.%3C%2FINDENT%3E%0A%3C%2FINDENT%3E">
49  // <COLUMN Type="UID" Name="IconName" StorageName="ICON_NAME"
50  // DataType="VARCHAR2" DataChoices=""/> <COLUMN Type="OnOff"
51  // Name="Status" StorageName="STATUS" DataType="VARCHAR2"
52  // DataChoices=""/>
53  // <COLUMN Type="Data" Name="Caption" StorageName="CAPTION"
54  // DataType="VARCHAR2" DataChoices=""/> <COLUMN Type="Data"
55  // Name="AlternateText" StorageName="ALTERNATE_TEXT" DataType="VARCHAR2"
56  // DataChoices=""/>
57  // <COLUMN Type="TrueFalse" Name="ForceOnlyOneInstance"
58  // StorageName="FORCE_ONLY_ONE_INSTANCE" DataType="VARCHAR2"
59  // DataChoices=""/>
60  // <COLUMN Type="Data" Name="RequiredPermissionLevel"
61  // StorageName="REQUIRED_PERMISSION_LEVEL" DataType="VARCHAR2"
62  // DataChoices=""/> <COLUMN Type="Data" Name="ImageURL"
63  // StorageName="IMAGE_URL" DataType="VARCHAR2" DataChoices=""/>
64  // <COLUMN Type="Data" Name="WindowContentURL"
65  // StorageName="WINDOW_CONTENT_URL" DataType="VARCHAR2" DataChoices=""/>
66  // <COLUMN Type="ChildLink-0" Name="LinkToApplicationTable"
67  // StorageName="LINK_TO_APPLICATION_TABLE" DataType="VARCHAR2"
68  // DataChoices=""/>
69  // <COLUMN Type="ChildLinkUID-0" Name="ApplicationUID"
70  // StorageName="APPLICATION_UID" DataType="VARCHAR2" DataChoices=""/>
71  // <COLUMN Type="Data" Name="FolderPath"
72  // StorageName="FOLDER_PATH" DataType="VARCHAR2" DataChoices=""/>
73  // <COLUMN Type="Comment" Name="CommentDescription"
74  // StorageName="COMMENT_DESCRIPTION" DataType="VARCHAR2" DataChoices=""/>
75  // <COLUMN Type="Author" Name="Author" StorageName="AUTHOR"
76  // DataType="VARCHAR2" DataChoices=""/>
77  // <COLUMN Type="Timestamp" Name="RecordInsertionTime"
78  // StorageName="RECORD_INSERTION_TIME" DataType="TIMESTAMP WITH TIMEZONE"
79  // DataChoices=""/>
80  // </VIEW>
81  // </TABLE>
82  // </ROOT>
83 }
84 
85 //==============================================================================
86 DesktopIconTable::~DesktopIconTable(void) {}
87 
88 //==============================================================================
89 void DesktopIconTable::init(ConfigurationManager* configManager)
90 {
91  // __COUT__ << "*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*" << std::endl;
92  // __COUT__ << configManager->__SELF_NODE__ << std::endl;
93 
94  unsigned int intVal;
95 
96  auto childrenMap = configManager->__SELF_NODE__.getChildren();
97 
98  activeDesktopIcons_.clear();
99 
101  bool addedAppId;
102  bool numeric;
103  unsigned int i;
104  for(auto& child : childrenMap)
105  {
106  if(!child.second.getNode(COL_STATUS).getValue<bool>())
107  continue;
108 
109  activeDesktopIcons_.push_back(DesktopIconTable::DesktopIcon());
110  icon = &(activeDesktopIcons_.back());
111 
112  icon->caption_ = child.second.getNode(COL_CAPTION).getValue<std::string>();
113  icon->alternateText_ =
114  child.second.getNode(COL_ALTERNATE_TEXT).getValue<std::string>();
115  icon->enforceOneWindowInstance_ =
116  child.second.getNode(COL_FORCE_ONLY_ONE_INSTANCE).getValue<bool>();
117  icon->permissionThresholdString_ =
118  child.second.getNode(COL_REQUIRED_PERMISSION_LEVEL).getValue<std::string>();
119  icon->imageURL_ = child.second.getNode(COL_IMAGE_URL).getValue<std::string>();
120  icon->windowContentURL_ =
121  child.second.getNode(COL_WINDOW_CONTENT_URL).getValue<std::string>();
122  icon->folderPath_ = child.second.getNode(COL_FOLDER_PATH).getValue<std::string>();
123 
124  if(icon->folderPath_ == TableViewColumnInfo::DATATYPE_STRING_DEFAULT)
125  icon->folderPath_ = ""; // convert DEFAULT to empty string
126 
127  numeric = true;
128  for(i = 0; i < icon->permissionThresholdString_.size(); ++i)
129  if(!(icon->permissionThresholdString_[i] >= '0' &&
130  icon->permissionThresholdString_[i] <= '9'))
131  {
132  numeric = false;
133  break;
134  }
135  // for backwards compatibility, if permissions threshold is a single number
136  // assume it is the threshold intended for the WebUsers::DEFAULT_USER_GROUP group
137  if(numeric)
138  icon->permissionThresholdString_ =
139  WebUsers::DEFAULT_USER_GROUP + ":" + icon->permissionThresholdString_;
140 
141  // remove all commas from member strings because desktop icons are served to
142  // client in comma-separated string
143  icon->caption_ = removeCommas(
144  icon->caption_, false /*andHexReplace*/, true /*andHTMLReplace*/);
145  icon->alternateText_ = removeCommas(
146  icon->alternateText_, false /*andHexReplace*/, true /*andHTMLReplace*/);
147  icon->imageURL_ = removeCommas(icon->imageURL_, true /*andHexReplace*/);
148  icon->windowContentURL_ =
149  removeCommas(icon->windowContentURL_, true /*andHexReplace*/);
150  icon->folderPath_ = removeCommas(
151  icon->folderPath_, false /*andHexReplace*/, true /*andHTMLReplace*/);
152 
153  // add URN/LID to windowContentURL_, if link is given
154  addedAppId = false;
155  if(!child.second.getNode(COL_APP_LINK).isDisconnected())
156  {
157  // if last character is not '='
158  // then assume need to add "?urn="
159  if(icon->windowContentURL_[icon->windowContentURL_.size() - 1] != '=')
160  icon->windowContentURL_ += "?urn=";
161 
162  //__COUT__ << "Following Application link." << std::endl;
163  child.second.getNode(COL_APP_LINK).getNode(COL_APP_ID).getValue(intVal);
164  icon->windowContentURL_ += std::to_string(intVal);
165 
166  //__COUT__ << "URN/LID=" << intVal << std::endl;
167  addedAppId = true;
168  }
169 
170  // add parameters if link is given
171  if(!child.second.getNode(COL_PARAMETER_LINK).isDisconnected())
172  {
173  // if there is no '?' found
174  // then assume need to add "?"
175  if(icon->windowContentURL_.find('?') == std::string::npos)
176  icon->windowContentURL_ += '?';
177  else if(addedAppId ||
178  icon->windowContentURL_[icon->windowContentURL_.size() - 1] !=
179  '?') // if not first parameter, add &
180  icon->windowContentURL_ += '&';
181 
182  // now add each paramter separated by &
183  auto paramGroupMap = child.second.getNode(COL_PARAMETER_LINK).getChildren();
184  bool notFirst = false;
185  for(const auto param : paramGroupMap)
186  {
187  if(notFirst)
188  icon->windowContentURL_ += '&';
189  else
190  notFirst = true;
191  icon->windowContentURL_ +=
192  ConfigurationManager::encodeURIComponent(
193  param.second.getNode(COL_PARAMETER_KEY).getValue<std::string>()) +
194  "=" +
195  ConfigurationManager::encodeURIComponent(
196  param.second.getNode(COL_PARAMETER_VALUE)
197  .getValue<std::string>());
198  }
199  }
200  } // end main icon extraction loop
201 
202  //
203  // //generate icons file
204  // std::fstream fs;
205  // fs.open(DESKTOP_ICONS_FILE, std::fstream::out | std::fstream::trunc);
206  // if(fs.fail())
207  // {
208  // __SS__ << "Failed to open Desktop Icons run file: " << DESKTOP_ICONS_FILE <<
209  // std::endl;
210  // __SS_THROW__;
211  // }
212  //
213  // for(auto &child:childrenMap)
214  // {
215  // child.second.getNode(COL_STATUS ).getValue(status);
216  // if(!status) continue;
217  //
218  // if(first) first = false;
219  // else fs << ",";
220  //
221  // child.second.getNode(COL_CAPTION ).getValue(val);
222  // fs << removeCommas(val, false, true);
223  // //__COUT__ << "Icon caption: " << val << std::endl;
224  //
225  // fs << ",";
226  // child.second.getNode(COL_ALTERNATE_TEXT ).getValue(val);
227  // fs << removeCommas(val, false, true);
228  //
229  // fs << ",";
230  // child.second.getNode(COL_FORCE_ONLY_ONE_INSTANCE ).getValue(status);
231  // fs << (status?"1":"0");
232  //
233  // fs << ",";
234  // child.second.getNode(COL_REQUIRED_PERMISSION_LEVEL ).getValue(val);
235  // fs << removeCommas(val);
236  //
237  // fs << ",";
238  // child.second.getNode(COL_IMAGE_URL ).getValue(val);
239  // fs << removeCommas(val,true);
240  //
241  // fs << ",";
242  // child.second.getNode(COL_WINDOW_CONTENT_URL ).getValue(val);
243  // val = removeCommas(val,true);
244  // fs << val;
245  //
246  // bool addedAppId = false;
247  // //add URN/LID if link is given
248  // if(!child.second.getNode(COL_APP_LINK ).isDisconnected())
249  // {
250  // //if last character is not '='
251  // // then assume need to add "?urn="
252  // if(val[val.size()-1] != '=')
253  // fs << "?urn=";
254  //
255  // //__COUT__ << "Following Application link." << std::endl;
256  // child.second.getNode(COL_APP_LINK ).getNode(COL_APP_ID
257  //).getValue(intVal);
258  //
259  // //__COUT__ << "URN/LID=" << intVal << std::endl;
260  // fs << intVal; //append number
261  // addedAppId = true;
262  // }
263  //
264  // //add parameters if link is given
265  // if(!child.second.getNode(COL_PARAMETER_LINK ).isDisconnected())
266  // {
267  // //if there is no '?' found
268  // // then assume need to add "?"
269  // if(val.find('?') == std::string::npos)
270  // fs << '?';
271  // else if(addedAppId ||
272  // val[val.size()-1] != '?') //if not first parameter, add &
273  // fs << '&';
274  //
275  // //now add each paramter separated by &
276  // auto paramGroupMap = child.second.getNode(COL_PARAMETER_LINK
277  //).getChildren(); bool notFirst = false; for(const auto
278  // param:paramGroupMap)
279  // {
280  // if(notFirst)
281  // fs << '&';
282  // else
283  // notFirst = true;
284  // fs << ConfigurationManager::encodeURIComponent(
285  // param.second.getNode(COL_PARAMETER_KEY).getValue<std::string>())
286  //<<
287  //"="
288  //<< ConfigurationManager::encodeURIComponent(
289  // param.second.getNode(COL_PARAMETER_VALUE).getValue<std::string>());
290  // }
291  // }
292  //
293  // fs << ",";
294  // child.second.getNode(COL_FOLDER_PATH ).getValue(val);
295  // if(val == TableViewColumnInfo::DATATYPE_STRING_DEFAULT) val = "";
296  // fs << removeCommas(val,true);
297  // }
298  //
299  // //close icons file
300  // fs.close();
301 }
302 
303 std::string DesktopIconTable::removeCommas(const std::string& str,
304  bool andHexReplace,
305  bool andHTMLReplace)
306 {
307  std::string retStr = "";
308  retStr.reserve(str.length());
309 
310  for(unsigned int i = 0; i < str.length(); ++i)
311  if(str[i] != ',')
312  retStr += str[i];
313  else if(andHexReplace)
314  retStr += "%2C";
315  else if(andHTMLReplace)
316  retStr += "&#44;";
317 
318  return retStr;
319 }
320 
321 DEFINE_OTS_TABLE(DesktopIconTable)