001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.ui.apps.sitemanager; 029 030import org.opencms.file.CmsObject; 031import org.opencms.file.CmsResource; 032import org.opencms.letsencrypt.CmsLetsEncryptConfiguration.Trigger; 033import org.opencms.main.CmsException; 034import org.opencms.main.CmsLog; 035import org.opencms.main.OpenCms; 036import org.opencms.site.CmsSite; 037import org.opencms.ui.A_CmsUI; 038import org.opencms.ui.CmsCssIcon; 039import org.opencms.ui.CmsVaadinUtils; 040import org.opencms.ui.FontOpenCms; 041import org.opencms.ui.apps.A_CmsWorkplaceApp; 042import org.opencms.ui.apps.I_CmsAppUIContext; 043import org.opencms.ui.apps.I_CmsCRUDApp; 044import org.opencms.ui.apps.Messages; 045import org.opencms.ui.apps.sitemanager.CmsSitesTable.TableProperty; 046import org.opencms.ui.components.CmsBasicDialog; 047import org.opencms.ui.components.CmsBasicDialog.DialogWidth; 048import org.opencms.ui.components.CmsInfoButton; 049import org.opencms.ui.components.CmsToolBar; 050import org.opencms.ui.components.OpenCmsTheme; 051 052import java.util.LinkedHashMap; 053import java.util.List; 054import java.util.Map; 055import java.util.Set; 056 057import org.apache.commons.logging.Log; 058 059import com.vaadin.server.ExternalResource; 060import com.vaadin.server.FontAwesome; 061import com.vaadin.server.Resource; 062import com.vaadin.ui.Button; 063import com.vaadin.ui.Button.ClickEvent; 064import com.vaadin.ui.Button.ClickListener; 065import com.vaadin.ui.Component; 066import com.vaadin.ui.UI; 067import com.vaadin.ui.Window; 068import com.vaadin.ui.themes.ValoTheme; 069import com.vaadin.v7.event.FieldEvents.TextChangeEvent; 070import com.vaadin.v7.event.FieldEvents.TextChangeListener; 071import com.vaadin.v7.ui.TextField; 072 073/** 074 * Manager class for the Site manager app. 075 */ 076 077public class CmsSiteManager extends A_CmsWorkplaceApp implements I_CmsCRUDApp<CmsSite> { 078 079 /**Bundel name for the sites which are used as templates for new sites.*/ 080 public static final String BUNDLE_NAME = "siteMacroBundle"; 081 082 /**Constant.*/ 083 public static final String FAVICON = "favicon.ico"; 084 085 /** Name of the macros folder for site templates.*/ 086 public static final String MACRO_FOLDER = ".macros"; 087 088 /** The add project path name. */ 089 public static final String PATH_NAME_ADD = "newSite"; 090 091 /** The edit project path name. */ 092 public static final String PATH_NAME_EDIT = "editSite"; 093 094 /**The global settings path name. */ 095 public static final String PATH_NAME_GLOBAL = "global"; 096 097 /**The webserver setting path name. */ 098 public static final String PATH_NAME_WEBSERVER = "webserver"; 099 100 /**path attribute to transmit root of a site to be edited. */ 101 public static final String SITE_ROOT = "siteRoot"; 102 103 /** The logger for this class. */ 104 static Log LOG = CmsLog.getLog(CmsSiteManager.class.getName()); 105 106 /**Path to the sites folder.*/ 107 static final String PATH_SITES = "/sites/"; 108 109 /** The currently opened dialog window. */ 110 protected Window m_dialogWindow; 111 112 /** The site table. */ 113 protected CmsSitesTable m_sitesTable; 114 115 /** The file table filter input. */ 116 protected TextField m_siteTableFilter; 117 118 /**Info Button. */ 119 private CmsInfoButton m_infoButton; 120 121 /**The publish button.*/ 122 private Button m_publishButton; 123 124 /** The root cms object. */ 125 private CmsObject m_rootCms; 126 127 /** 128 * Method to check if a folder under given path contains a bundle for macro resolving.<p> 129 * 130 * @param cms CmsObject 131 * @param folderPathRoot root path of folder 132 * @return true if macros bundle found 133 */ 134 public static boolean isFolderWithMacros(CmsObject cms, String folderPathRoot) { 135 136 if (!CmsResource.isFolder(folderPathRoot)) { 137 folderPathRoot = folderPathRoot.concat("/"); 138 } 139 try { 140 cms.readResource(folderPathRoot + MACRO_FOLDER); 141 cms.readResource(folderPathRoot + MACRO_FOLDER + "/" + BUNDLE_NAME + "_desc"); 142 } catch (CmsException e) { 143 return false; 144 } 145 return true; 146 } 147 148 /** 149 * Check if LetsEncrypt updates are configured to be triggered by webserver configuration updates.<p> 150 * 151 * @return true if LetsEncrypt updates are configured to be triggered by webserver configuration updates 152 */ 153 public static boolean isLetsEncryptConfiguredForWebserverThread() { 154 155 return (OpenCms.getLetsEncryptConfig() != null) 156 && OpenCms.getLetsEncryptConfig().isValidAndEnabled() 157 && (OpenCms.getLetsEncryptConfig().getTrigger() == Trigger.webserverThread); 158 } 159 160 /** 161 * Centers the currently open window. 162 */ 163 public void centerWindow() { 164 165 if (m_dialogWindow != null) { 166 m_dialogWindow.center(); 167 } 168 } 169 170 /** 171 * Closes the current dialog window and updates the sites table if requested.<p> 172 * 173 * @param updateTable <code>true</code> to update the sites table 174 */ 175 public void closeDialogWindow(boolean updateTable) { 176 177 if (m_dialogWindow != null) { 178 m_dialogWindow.close(); 179 m_dialogWindow = null; 180 } 181 if (updateTable) { 182 A_CmsUI.get().reload(); 183 } 184 } 185 186 /** 187 * @see org.opencms.ui.apps.I_CmsCRUDApp#createElement(java.lang.Object) 188 */ 189 public void createElement(CmsSite element) { 190 191 try { 192 OpenCms.getSiteManager().addSite(getRootCmsObject(), element); 193 } catch (CmsException e) { 194 LOG.error("unable to save site", e); 195 } 196 197 } 198 199 /** 200 * @see org.opencms.ui.apps.I_CmsCRUDApp#defaultAction(java.lang.String) 201 */ 202 public void defaultAction(String elementId) { 203 204 openEditDialog(elementId); 205 206 } 207 208 /** 209 * @see org.opencms.ui.apps.I_CmsCRUDApp#deleteElements(java.util.List) 210 */ 211 public void deleteElements(List<String> elementId) { 212 213 for (String siteRoot : elementId) { 214 try { 215 CmsSite site = getElement(siteRoot); 216 if (site != null) { 217 OpenCms.getSiteManager().removeSite(getRootCmsObject(), site); 218 } 219 } catch (CmsException e) { 220 LOG.error("Unable to delete site", e); 221 } 222 } 223 updateInfo(); 224 } 225 226 /** 227 * @see org.opencms.ui.apps.I_CmsCRUDApp#getAllElements() 228 */ 229 public List<CmsSite> getAllElements() { 230 231 List<CmsSite> res = OpenCms.getSiteManager().getAvailableSites(getRootCmsObject(), false); 232 return res; 233 } 234 235 /** 236 * Get corrupted sites.<p> 237 * 238 * @return List<CmsSite> 239 */ 240 public List<CmsSite> getCorruptedSites() { 241 242 return OpenCms.getSiteManager().getAvailableCorruptedSites(getRootCmsObject(), true); 243 } 244 245 /** 246 * @see org.opencms.ui.apps.I_CmsCRUDApp#getElement(java.lang.String) 247 */ 248 public CmsSite getElement(String elementId) { 249 250 return OpenCms.getSiteManager().getSiteForSiteRoot(elementId); 251 } 252 253 /** 254 * Returns the fav icon path for the given site.<p> 255 * 256 * @param siteRoot the site root 257 * 258 * @return the icon path 259 */ 260 public Resource getFavIcon(String siteRoot) { 261 262 CmsResource iconResource = null; 263 try { 264 iconResource = getRootCmsObject().readResource(siteRoot + "/" + CmsSiteManager.FAVICON); 265 } catch (CmsException e) { 266 //no favicon there 267 } 268 if (iconResource != null) { 269 return new ExternalResource( 270 OpenCms.getLinkManager().getPermalink(getRootCmsObject(), iconResource.getRootPath())); 271 } 272 return new CmsCssIcon(OpenCmsTheme.ICON_SITE); 273 } 274 275 /** 276 * @see org.opencms.ui.apps.A_CmsWorkplaceApp#initUI(org.opencms.ui.apps.I_CmsAppUIContext) 277 */ 278 @Override 279 public void initUI(I_CmsAppUIContext context) { 280 281 context.addPublishButton(changes -> { 282 A_CmsUI.get().reload(); 283 }); 284 super.initUI(context); 285 } 286 287 /** 288 * Opens the delete dialog for the given sites.<p> 289 * 290 * @param data the site roots 291 */ 292 public void openDeleteDialog(Set<String> data) { 293 294 CmsDeleteSiteDialog form = new CmsDeleteSiteDialog(this, data); 295 openDialog(form, CmsVaadinUtils.getMessageText(Messages.GUI_SITE_DELETE_0)); 296 } 297 298 /** 299 * Opens the edit site dialog.<p> 300 * 301 * @param siteRoot the site root of the site to edit, if <code>null</code> 302 */ 303 public void openEditDialog(String siteRoot) { 304 305 CmsEditSiteForm form; 306 String caption; 307 if (siteRoot != null) { 308 form = new CmsEditSiteForm(m_rootCms, this, siteRoot); 309 caption = CmsVaadinUtils.getMessageText( 310 Messages.GUI_SITE_CONFIGURATION_EDIT_1, 311 m_sitesTable.getContainer().getItem(siteRoot).getItemProperty(TableProperty.Title).getValue()); 312 } else { 313 form = new CmsEditSiteForm(m_rootCms, this); 314 caption = CmsVaadinUtils.getMessageText(Messages.GUI_SITE_ADD_0); 315 } 316 openDialog(form, caption); 317 } 318 319 /** 320 * Opens the global settings dialog.<p> 321 */ 322 public void openSettingsDailog() { 323 324 CmsGlobalForm form = new CmsGlobalForm(this); 325 openDialog(form, CmsVaadinUtils.getMessageText(Messages.GUI_SITE_GLOBAL_CONFIGURATION_0)); 326 } 327 328 /** 329 * Opens the update server configuration dialog.<p> 330 */ 331 public void openUpdateServerConfigDailog() { 332 333 CmsWebServerConfigForm form = new CmsWebServerConfigForm(this); 334 openDialog(form, CmsVaadinUtils.getMessageText(Messages.GUI_SITE_WEBSERVERCONFIG_0)); 335 } 336 337 /** 338 * @see org.opencms.ui.apps.I_CmsCRUDApp#writeElement(java.lang.Object) 339 */ 340 public void writeElement(CmsSite element) { 341 342 try { 343 OpenCms.getSiteManager().updateSite(m_rootCms, getElement(element.getSiteRoot()), element); 344 } catch (CmsException e) { 345 LOG.error("Unabel to update site", e); 346 } 347 //updateInfo(); 348 //m_sitesTable.loadSites(); 349 } 350 351 /** 352 * Creates the table holdings all available sites. 353 * @return a vaadin table component 354 */ 355 356 protected CmsSitesTable createSitesTable() { 357 358 CmsSitesTable table = new CmsSitesTable(this); 359 table.loadSites(); 360 return table; 361 } 362 363 /** 364 * @see org.opencms.ui.apps.A_CmsWorkplaceApp#getBreadCrumbForState(java.lang.String) 365 */ 366 @Override 367 protected LinkedHashMap<String, String> getBreadCrumbForState(String state) { 368 369 LinkedHashMap<String, String> crumbs = new LinkedHashMap<String, String>(); 370 crumbs.put("", CmsVaadinUtils.getMessageText(Messages.GUI_SITE_MANAGER_TITLE_SHORT_0)); 371 return crumbs; 372 } 373 374 /** 375 * @see org.opencms.ui.apps.A_CmsWorkplaceApp#getComponentForState(java.lang.String) 376 */ 377 @Override 378 protected Component getComponentForState(String state) { 379 380 m_sitesTable = createSitesTable(); 381 382 m_rootLayout.setMainHeightFull(true); 383 m_siteTableFilter = new TextField(); 384 m_siteTableFilter.setIcon(FontOpenCms.FILTER); 385 m_siteTableFilter.setInputPrompt( 386 Messages.get().getBundle(UI.getCurrent().getLocale()).key(Messages.GUI_EXPLORER_FILTER_0)); 387 m_siteTableFilter.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON); 388 m_siteTableFilter.setWidth("200px"); 389 m_siteTableFilter.addTextChangeListener(new TextChangeListener() { 390 391 private static final long serialVersionUID = 1L; 392 393 public void textChange(TextChangeEvent event) { 394 395 m_sitesTable.filter(event.getText()); 396 } 397 }); 398 m_infoLayout.addComponent(m_siteTableFilter); 399 addToolbarButtons(); 400 return m_sitesTable; 401 } 402 403 /** 404 * Returns the root cms object.<p> 405 * 406 * @return the root cms object 407 */ 408 protected CmsObject getRootCmsObject() { 409 410 if (m_rootCms == null) { 411 412 m_rootCms = getOfflineCmsObject(A_CmsUI.getCmsObject()); 413 m_rootCms.getRequestContext().setSiteRoot(""); 414 415 } 416 return m_rootCms; 417 } 418 419 /** 420 * @see org.opencms.ui.apps.A_CmsWorkplaceApp#getSubNavEntries(java.lang.String) 421 */ 422 @Override 423 protected List<NavEntry> getSubNavEntries(String state) { 424 425 return null; 426 } 427 428 /** 429 * Opens a given dialog.<p> 430 * 431 * @param dialog to be shown 432 * @param windowCaption caption of window 433 */ 434 protected void openDialog(CmsBasicDialog dialog, String windowCaption) { 435 436 if (m_dialogWindow != null) { 437 m_dialogWindow.close(); 438 } 439 440 m_dialogWindow = CmsBasicDialog.prepareWindow(DialogWidth.wide); 441 m_dialogWindow.setContent(dialog); 442 m_dialogWindow.setCaption(windowCaption); 443 444 A_CmsUI.get().addWindow(m_dialogWindow); 445 m_dialogWindow.center(); 446 } 447 448 /** 449 * Update the info button.<p> 450 */ 451 protected void updateInfo() { 452 453 m_infoButton.replaceData(getInfoMap()); 454 } 455 456 /** 457 * Adds the toolbar buttons.<p> 458 */ 459 private void addToolbarButtons() { 460 461 Button add = CmsToolBar.createButton(FontOpenCms.WAND, CmsVaadinUtils.getMessageText(Messages.GUI_SITE_ADD_0)); 462 add.addClickListener(new ClickListener() { 463 464 private static final long serialVersionUID = 1L; 465 466 public void buttonClick(ClickEvent event) { 467 468 openEditDialog(null); 469 } 470 }); 471 m_uiContext.addToolbarButton(add); 472 473 Button settings = CmsToolBar.createButton( 474 FontOpenCms.SETTINGS, 475 CmsVaadinUtils.getMessageText(Messages.GUI_SITE_GLOBAL_0)); 476 settings.addClickListener(new ClickListener() { 477 478 private static final long serialVersionUID = 1L; 479 480 public void buttonClick(ClickEvent event) { 481 482 openSettingsDailog(); 483 } 484 }); 485 m_uiContext.addToolbarButton(settings); 486 if (OpenCms.getSiteManager().isConfigurableWebServer() || isLetsEncryptConfiguredForWebserverThread()) { 487 Button webServer = CmsToolBar.createButton( 488 FontAwesome.SERVER, 489 CmsVaadinUtils.getMessageText(Messages.GUI_SITE_WEBSERVERCONFIG_0)); 490 webServer.addClickListener(new ClickListener() { 491 492 private static final long serialVersionUID = 1L; 493 494 public void buttonClick(ClickEvent event) { 495 496 openUpdateServerConfigDailog(); 497 } 498 }); 499 m_uiContext.addToolbarButton(webServer); 500 } 501 502 m_infoButton = new CmsInfoButton(getInfoMap()); 503 504 m_infoButton.setWindowCaption(CmsVaadinUtils.getMessageText(Messages.GUI_SITE_STATISTICS_CAPTION_0)); 505 m_infoButton.setDescription(CmsVaadinUtils.getMessageText(Messages.GUI_SITE_STATISTICS_CAPTION_0)); 506 m_uiContext.addToolbarButton(m_infoButton); 507 } 508 509 /** 510 * Get info map.<p> 511 * 512 * @return map of sites info 513 */ 514 private Map<String, String> getInfoMap() { 515 516 Map<String, String> infos = new LinkedHashMap<String, String>(); 517 int corruptedSites = getCorruptedSites().size(); 518 infos.put( 519 CmsVaadinUtils.getMessageText(Messages.GUI_SITE_STATISTICS_NUM_WEBSITES_0), 520 String.valueOf(getAllElements().size() + corruptedSites)); 521 522 if (corruptedSites > 0) { 523 infos.put( 524 CmsVaadinUtils.getMessageText(Messages.GUI_SITE_STATISTICS_NUM_CORRUPTED_WEBSITES_0), 525 String.valueOf(corruptedSites)); 526 } 527 528 return infos; 529 } 530}