otsdaq  v2_01_00
DesktopIconConfiguration_configuration.cc
1 #include "otsdaq-core/ConfigurationPluginDataFormats/DesktopIconConfiguration.h"
2 #include "otsdaq-core/Macros/ConfigurationPluginMacros.h"
3 #include "otsdaq-core/ConfigurationInterface/ConfigurationManager.h"
4 #include "otsdaq-core/WebUsersUtilities/WebUsers.h"
5 
6 #include <iostream>
7 #include <fstream> // std::fstream
8 #include <stdio.h>
9 using namespace ots;
10 
11 #define DESKTOP_ICONS_FILE std::string(getenv("SERVICE_DATA_PATH")) + "/OtsWizardData/iconList.dat"
12 
13 //DesktopIconConfiguration Column names
14 #define COL_NAME "IconName"
15 #define COL_STATUS ViewColumnInfo::COL_NAME_STATUS
16 #define COL_CAPTION "Caption"
17 #define COL_ALTERNATE_TEXT "AlternateText"
18 #define COL_FORCE_ONLY_ONE_INSTANCE "ForceOnlyOneInstance"
19 #define COL_REQUIRED_PERMISSION_LEVEL "RequiredPermissionLevel"
20 #define COL_IMAGE_URL "ImageURL"
21 #define COL_WINDOW_CONTENT_URL "WindowContentURL"
22 #define COL_APP_LINK "LinkToApplicationConfiguration"
23 #define COL_PARAMETER_LINK "LinkToParameterConfiguration"
24 #define COL_PARAMETER_KEY "windowParameterKey"
25 #define COL_PARAMETER_VALUE "windowParameterValue"
26 #define COL_FOLDER_PATH "FolderPath"
27 
28 //XDAQ App Column names
29 #define COL_APP_ID "Id"
30 
31 
32 
33 //==============================================================================
34 DesktopIconConfiguration::DesktopIconConfiguration(void) :
35  ConfigurationBase("DesktopIconConfiguration")
36 {
37  //Icon list no longer passes through file! so delete it from user's $USER_DATA
38  std::system(("rm -rf " + (std::string)DESKTOP_ICONS_FILE).c_str());
39 
41  //WARNING: the names used in C++ MUST match the Configuration INFO //
43 
44  // <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
45 // <ROOT xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ConfigurationInfo.xsd">
46 // <CONFIGURATION Name="DesktopIconConfiguration">
47 // <VIEW Name="DESKTOP_ICON_CONFIGURATION" Type="File,Database,DatabaseTest" 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-%20LinkToApplicationConfiguration%2FApplicationUID%3A%0A%3CINDENT%3EWhen%20the%20Icon%20refers%20to%20an%20otsdaq%20app%2C%20these%20two%20fields%20comprise%20the%20configuration%20link%20that%20connects%20the%20Icon%20to%20the%20app's%20ID%20-%20the%20app%20ID%20is%20used%20to%20target%20the%20app%20when%20sending%20requests.%20The%20LinkToApplicationConfiguration%20field%20is%20the%20configuration%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">
48 // <COLUMN Type="UID" Name="IconName" StorageName="ICON_NAME" DataType="VARCHAR2" DataChoices=""/>
49 // <COLUMN Type="OnOff" Name="Status" StorageName="STATUS" DataType="VARCHAR2" DataChoices=""/>
50 // <COLUMN Type="Data" Name="Caption" StorageName="CAPTION" DataType="VARCHAR2" DataChoices=""/>
51 // <COLUMN Type="Data" Name="AlternateText" StorageName="ALTERNATE_TEXT" DataType="VARCHAR2" DataChoices=""/>
52 // <COLUMN Type="TrueFalse" Name="ForceOnlyOneInstance" StorageName="FORCE_ONLY_ONE_INSTANCE" DataType="VARCHAR2" DataChoices=""/>
53 // <COLUMN Type="Data" Name="RequiredPermissionLevel" StorageName="REQUIRED_PERMISSION_LEVEL" DataType="VARCHAR2" DataChoices=""/>
54 // <COLUMN Type="Data" Name="ImageURL" StorageName="IMAGE_URL" DataType="VARCHAR2" DataChoices=""/>
55 // <COLUMN Type="Data" Name="WindowContentURL" StorageName="WINDOW_CONTENT_URL" DataType="VARCHAR2" DataChoices=""/>
56 // <COLUMN Type="ChildLink-0" Name="LinkToApplicationConfiguration" StorageName="LINK_TO_APPLICATION_CONFIGURATION" DataType="VARCHAR2" DataChoices=""/>
57 // <COLUMN Type="ChildLinkUID-0" Name="ApplicationUID" StorageName="APPLICATION_UID" DataType="VARCHAR2" DataChoices=""/>
58 // <COLUMN Type="Data" Name="FolderPath" StorageName="FOLDER_PATH" DataType="VARCHAR2" DataChoices=""/>
59 // <COLUMN Type="Comment" Name="CommentDescription" StorageName="COMMENT_DESCRIPTION" DataType="VARCHAR2" DataChoices=""/>
60 // <COLUMN Type="Author" Name="Author" StorageName="AUTHOR" DataType="VARCHAR2" DataChoices=""/>
61 // <COLUMN Type="Timestamp" Name="RecordInsertionTime" StorageName="RECORD_INSERTION_TIME" DataType="TIMESTAMP WITH TIMEZONE" DataChoices=""/>
62 // </VIEW>
63 // </CONFIGURATION>
64 // </ROOT>
65 
66 }
67 
68 //==============================================================================
69 DesktopIconConfiguration::~DesktopIconConfiguration(void)
70 {}
71 
72 //==============================================================================
73 void DesktopIconConfiguration::init(ConfigurationManager *configManager)
74 {
75 // __COUT__ << "*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*" << std::endl;
76 // __COUT__ << configManager->__SELF_NODE__ << std::endl;
77 
78 
79  unsigned int intVal;
80 
81  auto childrenMap = configManager->__SELF_NODE__.getChildren();
82 
83  activeDesktopIcons_.clear();
84 
86  bool addedAppId;
87  bool numeric;
88  unsigned int i;
89  for(auto &child:childrenMap)
90  {
91  if(!child.second.getNode(COL_STATUS ).getValue<bool>()) continue;
92 
93  activeDesktopIcons_.push_back(DesktopIconConfiguration::DesktopIcon());
94  icon = &(activeDesktopIcons_.back());
95 
96  icon->caption_ = child.second.getNode(COL_CAPTION ).getValue<std::string>();
97  icon->alternateText_ = child.second.getNode(COL_ALTERNATE_TEXT ).getValue<std::string>();
98  icon->enforceOneWindowInstance_ = child.second.getNode(COL_FORCE_ONLY_ONE_INSTANCE ).getValue<bool>();
99  icon->permissionThresholdString_ = child.second.getNode(COL_REQUIRED_PERMISSION_LEVEL).getValue<std::string>();
100  icon->imageURL_ = child.second.getNode(COL_IMAGE_URL ).getValue<std::string>();
101  icon->windowContentURL_ = child.second.getNode(COL_WINDOW_CONTENT_URL ).getValue<std::string>();
102  icon->folderPath_ = child.second.getNode(COL_FOLDER_PATH ).getValue<std::string>();
103 
104  if(icon->folderPath_ == ViewColumnInfo::DATATYPE_STRING_DEFAULT) icon->folderPath_ = ""; //convert DEFAULT to empty string
105 
106  numeric = true;
107  for(i=0;i<icon->permissionThresholdString_.size();++i)
108  if(!(icon->permissionThresholdString_[i] >= '0' &&
109  icon->permissionThresholdString_[i] <= '9'))
110  {
111  numeric = false;
112  break;
113  }
114  //for backwards compatibility, if permissions threshold is a single number
115  // assume it is the threshold intended for the WebUsers::DEFAULT_USER_GROUP group
116  if(numeric)
117  icon->permissionThresholdString_ = WebUsers::DEFAULT_USER_GROUP + ":" + icon->permissionThresholdString_;
118 
119  //remove all commas from member strings because desktop icons are served to client in comma-separated string
120  icon->caption_ = removeCommas(icon->caption_, false /*andHexReplace*/, true /*andHTMLReplace*/);
121  icon->alternateText_ = removeCommas(icon->alternateText_, false /*andHexReplace*/, true /*andHTMLReplace*/);
122  icon->imageURL_ = removeCommas(icon->imageURL_, true /*andHexReplace*/);
123  icon->windowContentURL_ = removeCommas(icon->windowContentURL_, true /*andHexReplace*/);
124  icon->folderPath_ = removeCommas(icon->folderPath_, false /*andHexReplace*/, true /*andHTMLReplace*/);
125 
126  //add URN/LID to windowContentURL_, if link is given
127  addedAppId = false;
128  if(!child.second.getNode(COL_APP_LINK ).isDisconnected())
129  {
130  //if last character is not '='
131  // then assume need to add "?urn="
132  if(icon->windowContentURL_[icon->windowContentURL_.size()-1] != '=')
133  icon->windowContentURL_ += "?urn=";
134 
135  //__COUT__ << "Following Application link." << std::endl;
136  child.second.getNode(COL_APP_LINK ).getNode(COL_APP_ID ).getValue(intVal);
137  icon->windowContentURL_ += std::to_string(intVal);
138 
139  //__COUT__ << "URN/LID=" << intVal << std::endl;
140  addedAppId = true;
141  }
142 
143  //add parameters if link is given
144  if(!child.second.getNode(COL_PARAMETER_LINK ).isDisconnected())
145  {
146  //if there is no '?' found
147  // then assume need to add "?"
148  if(icon->windowContentURL_.find('?') == std::string::npos)
149  icon->windowContentURL_ += '?';
150  else if(addedAppId ||
151  icon->windowContentURL_[icon->windowContentURL_.size()-1] != '?') //if not first parameter, add &
152  icon->windowContentURL_ += '&';
153 
154  //now add each paramter separated by &
155  auto paramGroupMap = child.second.getNode(COL_PARAMETER_LINK ).getChildren();
156  bool notFirst = false;
157  for(const auto param:paramGroupMap)
158  {
159  if(notFirst)
160  icon->windowContentURL_ += '&';
161  else
162  notFirst = true;
163  icon->windowContentURL_ += ConfigurationManager::encodeURIComponent(
164  param.second.getNode(COL_PARAMETER_KEY).getValue<std::string>()) +
165  "=" + ConfigurationManager::encodeURIComponent(
166  param.second.getNode(COL_PARAMETER_VALUE).getValue<std::string>());
167  }
168  }
169  } //end main icon extraction loop
170 
171 //
172 // //generate icons file
173 // std::fstream fs;
174 // fs.open(DESKTOP_ICONS_FILE, std::fstream::out | std::fstream::trunc);
175 // if(fs.fail())
176 // {
177 // __SS__ << "Failed to open Desktop Icons run file: " << DESKTOP_ICONS_FILE << std::endl;
178 // throw std::runtime_error(ss.str());
179 // }
180 //
181 // for(auto &child:childrenMap)
182 // {
183 // child.second.getNode(COL_STATUS ).getValue(status);
184 // if(!status) continue;
185 //
186 // if(first) first = false;
187 // else fs << ",";
188 //
189 // child.second.getNode(COL_CAPTION ).getValue(val);
190 // fs << removeCommas(val, false, true);
191 // //__COUT__ << "Icon caption: " << val << std::endl;
192 //
193 // fs << ",";
194 // child.second.getNode(COL_ALTERNATE_TEXT ).getValue(val);
195 // fs << removeCommas(val, false, true);
196 //
197 // fs << ",";
198 // child.second.getNode(COL_FORCE_ONLY_ONE_INSTANCE ).getValue(status);
199 // fs << (status?"1":"0");
200 //
201 // fs << ",";
202 // child.second.getNode(COL_REQUIRED_PERMISSION_LEVEL ).getValue(val);
203 // fs << removeCommas(val);
204 //
205 // fs << ",";
206 // child.second.getNode(COL_IMAGE_URL ).getValue(val);
207 // fs << removeCommas(val,true);
208 //
209 // fs << ",";
210 // child.second.getNode(COL_WINDOW_CONTENT_URL ).getValue(val);
211 // val = removeCommas(val,true);
212 // fs << val;
213 //
214 // bool addedAppId = false;
215 // //add URN/LID if link is given
216 // if(!child.second.getNode(COL_APP_LINK ).isDisconnected())
217 // {
218 // //if last character is not '='
219 // // then assume need to add "?urn="
220 // if(val[val.size()-1] != '=')
221 // fs << "?urn=";
222 //
223 // //__COUT__ << "Following Application link." << std::endl;
224 // child.second.getNode(COL_APP_LINK ).getNode(COL_APP_ID ).getValue(intVal);
225 //
226 // //__COUT__ << "URN/LID=" << intVal << std::endl;
227 // fs << intVal; //append number
228 // addedAppId = true;
229 // }
230 //
231 // //add parameters if link is given
232 // if(!child.second.getNode(COL_PARAMETER_LINK ).isDisconnected())
233 // {
234 // //if there is no '?' found
235 // // then assume need to add "?"
236 // if(val.find('?') == std::string::npos)
237 // fs << '?';
238 // else if(addedAppId ||
239 // val[val.size()-1] != '?') //if not first parameter, add &
240 // fs << '&';
241 //
242 // //now add each paramter separated by &
243 // auto paramGroupMap = child.second.getNode(COL_PARAMETER_LINK ).getChildren();
244 // bool notFirst = false;
245 // for(const auto param:paramGroupMap)
246 // {
247 // if(notFirst)
248 // fs << '&';
249 // else
250 // notFirst = true;
251 // fs << ConfigurationManager::encodeURIComponent(
252 // param.second.getNode(COL_PARAMETER_KEY).getValue<std::string>()) << "=" <<
253 // ConfigurationManager::encodeURIComponent(
254 // param.second.getNode(COL_PARAMETER_VALUE).getValue<std::string>());
255 // }
256 // }
257 //
258 // fs << ",";
259 // child.second.getNode(COL_FOLDER_PATH ).getValue(val);
260 // if(val == ViewColumnInfo::DATATYPE_STRING_DEFAULT) val = "";
261 // fs << removeCommas(val,true);
262 // }
263 //
264 // //close icons file
265 // fs.close();
266 }
267 
268 std::string DesktopIconConfiguration::removeCommas(const std::string &str,
269  bool andHexReplace, bool andHTMLReplace)
270 {
271  std::string retStr = "";
272  retStr.reserve(str.length());
273 
274  for(unsigned int i=0;i<str.length();++i)
275  if(str[i] != ',')
276  retStr += str[i];
277  else if(andHexReplace)
278  retStr += "%2C";
279  else if(andHTMLReplace)
280  retStr += "&#44;";
281 
282  return retStr;
283 }
284 
285 DEFINE_OTS_CONFIGURATION(DesktopIconConfiguration)