Wittyshare  0.2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
WsContent.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-Today Guy Deleeuw
3  *
4  * See the LICENSE file for terms of use.
5 */
6 
7 #include <iostream>
8 #include <fstream>
9 
10 #include <boost/algorithm/string/replace.hpp>
11 #include <boost/filesystem/operations.hpp>
12 #include <boost/filesystem/exception.hpp>
13 #include <boost/filesystem/convenience.hpp>
14 #include <boost/thread.hpp>
15 
16 #include <Wt/WLogger>
17 #include <Wt/WText>
18 #include <Wt/WAnchor>
19 #include <Wt/WOverlayLoadingIndicator>
20 #include <Wt/WVBoxLayout>
21 #include <Wt/WProgressBar>
22 #include <Wt/WTheme>
23 
24 #include <User/WsUser.h>
25 
26 #include <gdcore/gdCore.h>
27 
28 #include <gdwtcore/gdFHtmlEditor.h>
29 
30 #include "WsFileResource.h"
31 #include "WsApplication.h"
32 #include "WsContent.h"
33 #include "WsSearchView.h"
34 #include "WsTemplate.h"
35 #include "WsFormConfig.h"
36 #include "WsErrorPage.h"
37 
38 using namespace Wt;
39 
40 WsContent::WsContent(WContainerWidget* parent)
41  : WContainerWidget(parent), m_bLogContent(false), m_bAllowHtmlRendering(false), m_pSiteMapView(0), m_curWForm(0)
42 {
43  // if ( WsLayoutProperties::instance()->get("global", "by_object_stylesheet", "false") == "true" )
44  if ( WString::tr("byObjectStyleSheet").narrow() == "true" )
45  wApp->useStyleSheet(wApp->theme()->resourcesUrl() + "wittyshare/Css/WsContent.css");
46  addStyleClass("WsContent");
47  if (WsLayoutProperties::instance()->get("global", "log_content", "false") == "true")
48  m_bLogContent = true;
49  m_searchPath = WsLayoutProperties::instance()->get("global", "search_path", "/Search");
50  if (WsLayoutProperties::instance()->get("global", "allow_html_rendering", "false") == "true")
51  m_bAllowHtmlRendering = true;
52  WsUser* pUser = WsApp->wsUser();
53  m_sDocumentRoot = pUser->getRootPath(); // /var/www/demo_site
54  m_httpDocumentRoot = gdWApp->getParameter("DOCUMENT_ROOT", "/var/www");
56  boost::algorithm::replace_first(m_sRelativeDocumentRoot, m_httpDocumentRoot, ""); // /demo_site
57  if ( m_bLogContent )
58  wApp->log("notice") << "WsContent::WsContent wittyshare Document Root = " << m_sDocumentRoot
59  << " http server DOCUMENT_ROOT = " << m_httpDocumentRoot
60  << " Relative DOCUMENT_ROOT = " << m_sRelativeDocumentRoot;
61 }
62 
64 {
65  WContainerWidget::clear();
66  m_pSiteMapView = 0;
67  m_curWForm = 0;
68 }
69 
71 {
72  WContainerWidget::load();
73 }
74 
76 { }
77 
78 void WsContent::buildFileUpload(const std::string& path)
79 {
80  clear();
81  addWidget(WsApp->WsModules().module("WsModFileUpload")->createContents());
82 }
83 
84 void WsContent::doEditPage(std::string path)
85 {
86  std::string newPath = path;
87  boost::algorithm::replace_first(newPath, "/Edit", "");
88  boost::algorithm::replace_first(newPath, "/SiteMap", "");
89  std::string sPathWithoutPrefix = WsApp->WsModules().pathWithoutPrefix(newPath); // ex. /SiteMap
90  std::string sysPath(m_sDocumentRoot + sPathWithoutPrefix);
91  WsUser* pUser = WsApp->wsUser();
92  NodePtr pNode = pUser->getAccessRoot()->eatPath(sPathWithoutPrefix);
93  if (!pNode.get() ) {
94  addWidget(new WsErrorPage(WsErrorPage::Error, path, pUser, "Returned node is null"));
95  return;
96  }
97  clear();
98  setOverflow(WContainerWidget::OverflowAuto);
99  WVBoxLayout* vbox = new WVBoxLayout();
100  setLayout(vbox);
101  WsFormConfig* m_formConfig = new WsFormConfig(pNode, WsApp->WsModules());
102  vbox->addWidget(m_formConfig, 0);
103  vbox->addWidget(WsApp->WsModules().module("WsModEditorUploader")->createContents());
104  std::string strExt(boost::filesystem::extension(sPathWithoutPrefix));
105  if ( strExt == ".fhtml" ) {
106  if ( !gdcore_isPathFile(sysPath) ) return;
107  gdFHtmlEditor* pEditor = new gdFHtmlEditor("", false);
108  pEditor->setCurrentPath(sysPath);
109  pEditor->readFile();
110  m_formConfig->setEditorFhtml(pEditor);
111  pEditor->resize(WLength(100, WLength::Percentage), WLength(400));
112  vbox->addWidget(pEditor, 1);
113  }
114 }
115 
117 {
118  clear();
119  setOverflow(WContainerWidget::OverflowHidden);
120  int nTmp = 0;
121  nTmp |= gdWFileView::tbUseLeftTree;
122  m_pSiteMapView = new WsSiteMapView(gdwtcore::typeOpen, (gdWFileView::tbFlags) nTmp, this);
124  resize(WLength(100, WLength::Percentage), WLength(100, WLength::Percentage));
125 }
126 
127 void WsContent::siteMapChanged(std::string newPath)
128 {
129  if ( !m_pSiteMapView )
130  buildSiteMap();
131  m_pSiteMapView->setRelativePath(newPath); // "/SiteMap/...
132 }
133 
134 void WsContent::doSearch(WString sSearch)
135 {
136  clear();
137  // addWidget(new WText("searching : " + sSearch));
138  // WVBoxLayout* vBox = new WVBoxLayout();
139  WsSearchView* srchView = new WsSearchView(sSearch.toUTF8(), this);
140  resize(WLength(100, WLength::Percentage), WLength(100, WLength::Percentage));
141  addWidget(srchView);
142  // vBox->addWidget(srchView, 1);
143  // if ( srchView->navBar() )
144  // vBox->addWidget(srchView->navBar(), 0);
145  // setLayout(vBox);
146 }
147 
148 //void WsContent::doPathChanged(std::string newPath)
149 // {
150 // WsApp->setTemplate(newPath);
151 // }
152 
153 void WsContent::viewDirectory(const std::string& path)
154 {
155  WsUser* pUser = WsApp->wsUser();
156  NodePtr pRootNode = pUser->getAccessRoot();
157  if ( !pRootNode ) {
158  wApp->log("notice") << "WsContent::viewDirectory() : Path = " << path << ", getAccessRoot() is null";
159  return;
160  }
161  NodePtr pNode = pRootNode.get()->eatPath(path);
162  if ( !pNode.get() ) {
163  wApp->log("notice") << "WsContent::viewDirectory() : Path = " << path << ", getAccessRoot() eatPath is null";
164  return;
165  }
166  std::string sInitPage = pNode.get()->getProperties().get()->get("global", "initial_page", "");
167  if ( sInitPage.size() > 0 ) {
168  std::string newPage = pNode.get()->getPath().string() + "/" + sInitPage;
169  wApp->log("notice") << "WsContent::viewDirectory() : set initial page to " << newPage;
170  return wApp->setInternalPath(newPage, true);
171  }
172  clear();
173  if ( !(pUser->isAdministrator() || pUser->isEditor()) )
174  if ( WsLayoutProperties::instance()->get("global", "use_content_directory_view", "false") == "false" ) return;
175  WsApp->hideImages(false);
176  WWidget* w = WsApp->WsModules().module("WsModDirectoryView2")->createContents();
177  WsOptions* wOpt = dynamic_cast<WsOptions*>(w);
178  wOpt->setOption("rootPath", path);
179  if ( 0 ) {
180  WVBoxLayout* vBox = new WVBoxLayout();
181  vBox->addWidget(w, 1);
182  setLayout(vBox);
183  setOverflow(WContainerWidget::OverflowHidden);
184  } else {
185  addWidget(w);
186  // resize(WLength(100, WLength::Percentage), WLength(100, WLength::Percentage));
187  setOverflow(WContainerWidget::OverflowAuto);
188  }
189 }
190 
191 void WsContent::setPath(std::string newPath)
192 {
193  std::string sPathWithoutPrefix = WsApp->WsModules().pathWithoutPrefix(newPath);
194  boost::algorithm::replace_all(sPathWithoutPrefix, "&amp;", "&");
195  if ( newPath == "/" ) newPath = WsApp->homePage();
196  WsUser* pUser = WsApp->wsUser();
197  boost::filesystem::path p(newPath);
198  std::string strExt (p.extension().string());
199  // TODO : Make this more robust
200  if ( strExt == ".itpl" ) {
201  sPathWithoutPrefix = p.parent_path().string();
202  }
203  int perms = pUser->getPermissions(sPathWithoutPrefix);
204  if ( perms == ErrorCode::NotLogged ) {
205  addWidget(new WsErrorPage(WsErrorPage::UnAuthorized, p.string(), pUser));
206  return;
207  }
208  if ( perms != GlobalConfig::Read && perms != GlobalConfig::ReadWrite) {
209  clear();
210  if(perms == ErrorCode::NotFound){
211  addWidget(new WsErrorPage(WsErrorPage::NotFound, p.string(), pUser));
212  }
213  else{
214  addWidget(new WsErrorPage(WsErrorPage::Forbidden, p.string(), pUser));
215  }
216  return;
217  }
218  if ( newPath == "/Logo" ) {
219  viewDirectory("/");
220  return;
221  }
222  std::string s;
223  try {
224  s.assign(newPath, 0, m_searchPath.size());
225  } catch (string serr) {
226  wApp->log("notice") << "WsContent::setPath : assign crash : " << newPath << " error " << serr;
227  }
228  if ( m_searchPath == s ) {
229  std::string query;
230  query.assign(newPath, m_searchPath.size(), newPath.size() - m_searchPath.size());
231  boost::algorithm::replace_first(query, "/", "");
232  return doSearch(query);
233  }
234  if ( newPath.compare(0, 8, "/SiteMap") == 0)
235  return siteMapChanged(newPath);
236  //Edit and upload only available when editor
237  if ( newPath.compare(0, 5, "/Edit") == 0)
238  if(perms == GlobalConfig::ReadWrite)
239  return doEditPage(newPath);
240  else {
241  addWidget(new WsErrorPage(WsErrorPage::Forbidden, newPath, pUser));
242  return;
243  }
244  if ( newPath.compare(0, 11, "/FileUpload") == 0 )
245  if(perms == GlobalConfig::ReadWrite )
246  return buildFileUpload(newPath);
247  else {
248  addWidget(new WsErrorPage(WsErrorPage::Forbidden, newPath, pUser));
249  return;
250  }
251  selectWidget(newPath);
252 }
253 
254 void WsContent::selectWidget(std::string path)
255 {
256  // TODO : afficher les erreurs dans un WDialogBox ou renvoyer vers page d'erreur
257  std::string sysPath(m_sDocumentRoot + path);
258  boost::filesystem::path p(path);
259  std::string strExt (p.extension().string());
260  std::string strName(p.stem().string());
261  std::string strFileName(strName + strExt);
262  std::string fileContent;
263  if ( m_bLogContent )
264  wApp->log("notice") << "WsContent::selectWidget : path = " << path << " name = " << strName << " extension = " << strExt << " system path = " << sysPath;
265  // This extension is mainly created for allowing text in a image without a link
266  if ( strExt == ".nolink" ) {
267  addWidget(new WsErrorPage(WsErrorPage::Error, path, 0, "Extension not allowed", true));
268  return;
269  }
270  // load the file in memory for some file format
271  if ( strExt == ".fhtml" ) {
272  if ( !gdcore_file_content2string(sysPath.c_str(), fileContent) ) {
273  addWidget(new WsErrorPage(WsErrorPage::NotFound, path, 0, "Cannot open URL", true));
274  if ( m_bLogContent )
275  wApp->log("notice") << "WsContent::selectWidget : cannot open : " << sysPath;
276  return;
277  }
278  if ( m_bLogContent )
279  wApp->log("notice") << "WsContent::selectWidget : file " << sysPath << " size = " << fileContent.size();
280  }
281  // .html
282  if ( strExt == ".html" ) {
283  if ( m_bLogContent )
284  wApp->log("notice") << "WsContent::selectWidget : render a html file : " << sysPath;
285  if ( !m_bAllowHtmlRendering ) {
286  addWidget(new WsErrorPage(WsErrorPage::Error, path, 0, "Rendering a html file is not allowed"));
287  return;
288  }
289  clear();
290  WsApp->hideImages(false);
291  WText* pIFrame = new WText();
292  pIFrame->setTextFormat(XHTMLUnsafeText);
293  pIFrame->setText("<iframe src='" + m_sRelativeDocumentRoot + path + "' height='98%' width='100%' frameborder='0'></iframe>");
294  addWidget(pIFrame);
295  return;
296  }
297  // .fhtml (fragmented html)
298  if ( strExt == ".fhtml" ) {
299  clear();
300  WsApp->hideImages(false);
301  WText* wtext = new WText();
302  // SD -> let fhtml have some iframe and js
303  wtext->setTextFormat(Wt::XHTMLUnsafeText);
304  wtext->setText(fileContent);
305  bool bUseLayout = false;
306  if ( !bUseLayout ) {
307  //setOverflow(WContainerWidget::OverflowAuto);
308  addWidget(wtext);
309  } else {
310  setOverflow(WContainerWidget::OverflowHidden);
311  WContainerWidget* cw = new WContainerWidget();
312  cw->setOverflow(WContainerWidget::OverflowAuto);
313  cw->addWidget(wtext);
314  WVBoxLayout* vBox = new WVBoxLayout();
315  vBox->addWidget(cw, 1);
316  setLayout(vBox);
317  }
318  return;
319  }
320  // .form
321  if ( strExt == ".form" ) {
322  if ( m_bLogContent )
323  wApp->log("notice") << "WsContent::selectWidget : render a form : " << sysPath;
324  clear();
325  m_curWForm = new gdWForm(sysPath);
326  addWidget(m_curWForm);
327  return;
328  }
329  // .itpl, Inside template : Extension that create a template in the content.
330  if ( strExt == ".itpl" ) {
331  if ( m_bLogContent )
332  wApp->log("notice") << "WsContent::selectWidget : render an inside template : " << sysPath;
333  clear();
334  WsTemplate* pTemplate = new WsTemplate(strFileName);
335  addWidget(pTemplate);
336  return;
337  }
338  // directory
339  if ( gdcore_isPathDirectory(sysPath) ) {
340  if ( m_bLogContent )
341  wApp->log("notice") << "WsContent::selectWidget : render a directory : " << sysPath;
342  viewDirectory(path);
343  return;
344  }
345  /*
346  Koen : mmm this is a tricky problem. you could do this using an internal path so that you can first let the user authenticate, if necessary, and then you redirect to a static resource with some randomly generated token in the URL so that you can serve the file
347  so the permalink is clean, like /cms/folder1/folder2/file.doc
348  if your app is deployed at / or /cms, you handle the internal path, authenticate, etc...
349  then finally, you create a random ID, and redirect to /resource/folder1/folder2/file.doc?auth=randomid
350  and this is handled by a WResource which checks the path and serves the file
351  if you prefer I can create a small example ...
352  ooops ! must run !
353  */
354  // Pdf TODO : tester ce code avec des pdf devant s'afficher dans la vue
355  if ( strExt == ".pdf" ) {
356  if ( m_bLogContent )
357  wApp->log("notice") << "WsContent::selectWidget : render a " << strExt << " file : " << sysPath;
358  // if ( !allowedPath(userUID, syspath) ) return;
359  clear();
360  WsApp->hideImages(false);
361  addWidget(new WText("Download file : " + path + " ..."));
362  return wApp->redirect(m_sRelativeDocumentRoot + path);
363  // WAnchor* m_anchor = new WAnchor(this);
364  // m_anchor->setTarget(Wt::TargetNewWindow);
365  // m_anchor->setText(path);
366  // fileResource* pRes = new fileResource(sysPath, this);
367  // m_anchor->setRef(pRes->generateUrl());
368  // m_anchor->clicked().emit(WMouseEvent());
369  // return;
370  }
371  if ( strExt == ".rss" ) {
372  if ( m_bLogContent )
373  wApp->log("notice") << "WsContent::selectWidget : render a " << strExt << " file : " << sysPath;
374  clear();
375  WsApp->hideImages(false);
376  addWidget(new WText("Download file : " + path + " ..."));
377  return wApp->redirect(m_sRelativeDocumentRoot + path);
378  }
379  for (int iModule = 0; iModule < WsApp->WsModules().modules().size(); iModule++) {
380  WsModule* curModule = WsApp->WsModules().modules()[iModule]->module;
381  if ( curModule->isLoaded() ) continue;
382  if ( (strExt.size() == 0 && strName == curModule->fileName()) || (strExt.size() > 0 && strExt == curModule->extension(strExt)) ) {
383  if ( m_bLogContent )
384  if ( strExt == curModule->extension(strExt) )
385  wApp->log("notice") << "WsContent::selectWidget : module, render a " << strExt << " file extension : " << sysPath;
386  else
387  wApp->log("notice") << "WsContent::selectWidget : module, render " << strName << " file name: " << sysPath;
388  clear();
389  WsApp->hideImages(curModule->hideImages());
390  curModule->setSysPath(sysPath);
392  WWidget* w = curModule->createContents();
393  if ( w ) {
394  if ( asString(curModule->option("useLayout")) == "true" ) {
395  WVBoxLayout* vbox = new WVBoxLayout();
396  vbox->addWidget(w, 1);
397  setLayout(vbox);
398  } else {
399  addWidget(w);
400  }
401  } else {
402  wApp->log("notice") << "WsContent::selectWidget : module, render " << curModule->moduleName() << " CANNOT call create content: ";
403  }
404  return;
405  }
406  }
407  clear();
408  addWidget(new WsErrorPage(WsErrorPage::Error, path, 0, "Unknown extension", true));
409 }
410 
411 void WsContent::doSiteMapItemSelected(gdWFileView::signalType sigType, std::string selectedPath)
412 {
413  std::string str = selectedPath;
414  if ( sigType == gdWFileView::selected )
415  boost::algorithm::replace_first(str, "/SiteMap", "");
416  wApp->setInternalPath(str, true);
417 }
418 
void doSiteMapItemSelected(gdWFileView::signalType sigType, std::string selectedPath)
Definition: WsContent.cpp:411
void setEditorFhtml(gdFHtmlEditor *pFhtmlEditor)
bool hideImages()
Definition: WsOption.cpp:169
boost::shared_ptr< WsAbstractNode > NodePtr
void setRelativePath(const std::string &relativePath)
int getPermissions(const std::string &p)
return the permissions on specific node
Definition: WsUser.cpp:81
gdWForm * m_curWForm
Definition: WsContent.h:46
const int ReadWrite
Wt::Signal< gdWFileView::signalType, std::string > & fileSelected()
Definition: WsSiteMapView.h:70
bool m_bLogContent
Definition: WsContent.h:40
void siteMapChanged(std::string newPath)
Definition: WsContent.cpp:127
void load()
Definition: WsContent.cpp:70
const int Read
void buildSiteMap()
Definition: WsContent.cpp:116
void setPath(std::string newPath)
Definition: WsContent.cpp:191
std::string m_sDocumentRoot
Definition: WsContent.h:43
void setDiffPath(const std::string &diffPath)
Set/Get the difference between the web server (example Apache /var/www) root path and the wittishare ...
Definition: WsOption.cpp:184
const int NotFound
Interface that provides differents methods for accessing the FsTree as well as other features...
Definition: WsUser.h:33
void viewDirectory(const std::string &path)
Definition: WsContent.cpp:153
void doSearch(Wt::WString sSearch)
Definition: WsContent.cpp:134
const int NotLogged
virtual Wt::WWidget * createContents(Wt::WContainerWidget *parent=0) const =0
Create the contents.
void selectWidget(std::string path)
Definition: WsContent.cpp:254
std::string m_sRelativeDocumentRoot
Definition: WsContent.h:45
const std::string & moduleName() const
Definition: WsOption.cpp:100
bool isLoaded()
Definition: WsModule.cpp:55
void setOption(const std::string &attribute, boost::any value)
Set an options if previously set, update the value.
Definition: WsOption.cpp:47
bool isEditor()
Definition: WsUser.cpp:179
const boost::any & option(const std::string &attribute) const
Get an options value.
Definition: WsOption.cpp:62
std::string m_httpDocumentRoot
Definition: WsContent.h:44
const std::string getRootPath()
return the root path of the filesystem tree, example : /var/www/demo_site
Definition: WsUser.cpp:55
const std::string & fileName() const
Definition: WsOption.cpp:120
std::string get(const std::string &section, const std::string &id, const std::string &def)
virtual void clear()
Definition: WsContent.cpp:63
std::string m_searchPath
Definition: WsContent.h:39
#define WsApp
Define a shortcut to the application instance.
Definition: WsApplication.h:62
static WsLayoutProperties * instance()
Get the singleton instance.
const std::string & extension(const std::string &extension="") const
Definition: WsOption.cpp:131
void setSysPath(const std::string &sysPath)
Set/Get the system path (example the selected file /var/www/mysite/about/me.fhtml).
Definition: WsOption.cpp:174
void doEditPage(std::string path)
Definition: WsContent.cpp:84
bool isAdministrator()
Definition: WsUser.cpp:184
NodePtr getAccessRoot()
return the root node of the access tree starting from the root
Definition: WsUser.cpp:50
void buildFileUpload(const std::string &path)
Definition: WsContent.cpp:78
bool m_bAllowHtmlRendering
Definition: WsContent.h:41
WsContent(Wt::WContainerWidget *parent=0)
Definition: WsContent.cpp:40
WsSiteMapView * m_pSiteMapView
Definition: WsContent.h:42
User class.