001/* 002 * Copyright 2015 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.web.repository.site; 017 018import java.util.ArrayList; 019import java.util.HashMap; 020import java.util.List; 021import java.util.Map; 022import java.util.stream.Collectors; 023 024import org.apache.avalon.framework.parameters.Parameters; 025import org.apache.avalon.framework.service.ServiceException; 026import org.apache.avalon.framework.service.ServiceManager; 027import org.apache.cocoon.acting.ServiceableAction; 028import org.apache.cocoon.environment.ObjectModelHelper; 029import org.apache.cocoon.environment.Redirector; 030import org.apache.cocoon.environment.Request; 031import org.apache.cocoon.environment.SourceResolver; 032import org.apache.commons.lang.BooleanUtils; 033import org.apache.commons.lang.StringUtils; 034 035import org.ametys.cms.repository.Content; 036import org.ametys.core.cocoon.JSonReader; 037import org.ametys.core.group.GroupDirectoryContextHelper; 038import org.ametys.core.group.GroupDirectoryDAO; 039import org.ametys.core.right.RightManager; 040import org.ametys.core.right.RightManager.RightResult; 041import org.ametys.core.user.CurrentUserProvider; 042import org.ametys.core.user.UserIdentity; 043import org.ametys.core.user.population.PopulationContextHelper; 044import org.ametys.core.user.population.UserPopulationDAO; 045import org.ametys.plugins.repository.AmetysObject; 046import org.ametys.plugins.repository.AmetysObjectIterable; 047import org.ametys.plugins.repository.AmetysObjectResolver; 048import org.ametys.plugins.repository.query.SortCriteria; 049import org.ametys.plugins.repository.query.expression.Expression; 050import org.ametys.web.filter.SharedContentsHelper; 051import org.ametys.web.site.SiteColorsComponent; 052import org.ametys.web.site.SiteConfigurationManager; 053 054/** 055 * Action for getting the list of existing {@link Site}. 056 */ 057public class GetSitesAction extends ServiceableAction 058{ 059 /** The site manager */ 060 protected SiteManager _siteManager; 061 /** The rights manager */ 062 protected RightManager _rightManager; 063 /** The current user provider */ 064 protected CurrentUserProvider _userProvider; 065 /** The population context helper */ 066 protected PopulationContextHelper _populationContextHelper; 067 /** The group directory context helper */ 068 protected GroupDirectoryContextHelper _groupDirectoryContextHelper; 069 /** The user population DAO */ 070 protected UserPopulationDAO _userPopulationDAO; 071 /** The group directory DAO */ 072 protected GroupDirectoryDAO _groupDirectoryDAO; 073 /** Site type EP */ 074 protected SiteTypesExtensionPoint _siteTypeExtensionPoint; 075 /** Site configuration */ 076 protected SiteConfigurationManager _siteConfigurationManager; 077 /** Ametys resolver */ 078 protected AmetysObjectResolver _ametysResolver; 079 /** Handle site colors */ 080 protected SiteColorsComponent _siteColors; 081 082 @Override 083 public void service(ServiceManager smanager) throws ServiceException 084 { 085 super.service(smanager); 086 _siteManager = (SiteManager) smanager.lookup(SiteManager.ROLE); 087 _rightManager = (RightManager) smanager.lookup(RightManager.ROLE); 088 _userProvider = (CurrentUserProvider) smanager.lookup(CurrentUserProvider.ROLE); 089 _siteTypeExtensionPoint = (SiteTypesExtensionPoint) smanager.lookup(SiteTypesExtensionPoint.ROLE); 090 _siteConfigurationManager = (SiteConfigurationManager) smanager.lookup(SiteConfigurationManager.ROLE); 091 _ametysResolver = (AmetysObjectResolver) smanager.lookup(AmetysObjectResolver.ROLE); 092 _populationContextHelper = (PopulationContextHelper) smanager.lookup(PopulationContextHelper.ROLE); 093 _groupDirectoryContextHelper = (GroupDirectoryContextHelper) smanager.lookup(GroupDirectoryContextHelper.ROLE); 094 _userPopulationDAO = (UserPopulationDAO) smanager.lookup(UserPopulationDAO.ROLE); 095 _groupDirectoryDAO = (GroupDirectoryDAO) smanager.lookup(GroupDirectoryDAO.ROLE); 096 _siteColors = (SiteColorsComponent) manager.lookup(SiteColorsComponent.ROLE); 097 } 098 099 @Override 100 public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception 101 { 102 Request request = ObjectModelHelper.getRequest(objectModel); 103 Map<String, Object> result = new HashMap<>(); 104 105 UserIdentity user = _userProvider.getUser(); 106 107 String id = request.getParameter("id"); 108 109 boolean recursive = parameters.getParameterAsBoolean("recursive", BooleanUtils.toBoolean(request.getParameter("recursive"))); 110 boolean readAccessOnly = parameters.getParameterAsBoolean("readAccessOnly", BooleanUtils.toBoolean(request.getParameter("readAccessOnly"))); 111 boolean sharedSitesOnly = parameters.getParameterAsBoolean("sharedSitesOnly", BooleanUtils.toBoolean(request.getParameter("sharedSitesOnly"))); 112 113 List<Map<String, Object>> sites = new ArrayList<>(); 114 115 try (AmetysObjectIterable<Site> rootSites = _getRootSites(id);) 116 { 117 String currentSiteName = (String) request.getAttribute("siteName"); 118 119 for (Site site : rootSites) 120 { 121 sites.addAll(_rootSite2json(request, site, currentSiteName, recursive, readAccessOnly, sharedSitesOnly, user)); 122 } 123 } 124 125 result.put("sites", sites); 126 127 request.setAttribute(JSonReader.OBJECT_TO_READ, result); 128 129 return EMPTY_MAP; 130 } 131 132 /** 133 * Get root sites 134 * @param id Optionnal root id 135 * @return Ametys iterable of sites 136 */ 137 protected AmetysObjectIterable<Site> _getRootSites(String id) 138 { 139 if (StringUtils.isNotEmpty(id)) 140 { 141 AmetysObject ao = _ametysResolver.resolveById(id); 142 143 if (ao instanceof Site) 144 { 145 return ((Site) ao).getChildrenSites(); 146 } 147 } 148 return _siteManager.getRootSites(); 149 } 150 151 /** 152 * Retrieves the JSON for a root site 153 * @param request The request 154 * @param site The root site 155 * @param currentSiteName The name of the current site 156 * @param recursive True to handle child sites 157 * @param readAccessOnly Only read access site 158 * @param sharedSitesOnly Only shared sites 159 * @param user The current user 160 * @return The root site info 161 */ 162 protected List<Map<String, Object>> _rootSite2json(Request request, Site site, String currentSiteName, boolean recursive, boolean readAccessOnly, boolean sharedSitesOnly, UserIdentity user) 163 { 164 List<Map<String, Object>> sites = new ArrayList<>(); 165 166 if (recursive) 167 { 168 // on recursion, returns all sub sites on the same level. The real level is determined by the "depth" property 169 sites.addAll(_childSites2json(request, site, currentSiteName, 0, readAccessOnly, sharedSitesOnly)); 170 } 171 else 172 { 173 sites.add(_site2json(request, site, currentSiteName, 0, readAccessOnly, sharedSitesOnly)); 174 } 175 176 return sites; 177 } 178 179 /** 180 * Child site to JSON 181 * @param request The request 182 * @param site The root site 183 * @param currentSiteName The name of the current site 184 * @param depth The depth from the root site 185 * @param readAccessOnly Only read access site 186 * @param sharedSitesOnly Only shared sites 187 * @return The child sites info 188 */ 189 protected List<Map<String, Object>> _childSites2json (Request request, Site site, String currentSiteName, int depth, boolean readAccessOnly, boolean sharedSitesOnly) 190 { 191 List<Map<String, Object>> childrenAndItseft = new ArrayList<>(); 192 193 childrenAndItseft.add(_site2json(request, site, currentSiteName, depth, readAccessOnly, sharedSitesOnly)); 194 195 // Get child site recursively 196 for (Site child : site.getChildrenSites()) 197 { 198 childrenAndItseft.addAll(_childSites2json(request, child, currentSiteName, depth + 1, readAccessOnly, sharedSitesOnly)); 199 } 200 201 return childrenAndItseft; 202 } 203 204 /** 205 * Site to JSON 206 * @param request The request 207 * @param site The root site 208 * @param currentSiteName The name of the current site 209 * @param depth The depth from the root site 210 * @param readAccessOnly Only read access site 211 * @param sharedSitesOnly Only shared sites 212 * @return The site info 213 */ 214 protected Map<String, Object> _site2json (Request request, Site site, String currentSiteName, int depth, boolean readAccessOnly, boolean sharedSitesOnly) 215 { 216 Map<String, Object> object = new HashMap<>(); 217 218 // Calculate shared contents only if necessary 219 long sharedContentsCount = sharedSitesOnly ? _sharedContentsSize(site, currentSiteName) : 0; 220 221 boolean readAccessCondition = !readAccessOnly || (readAccessOnly && canRead(site, request)); 222 boolean sharedSiteCondition = !sharedSitesOnly || (sharedSitesOnly && sharedContentsCount > 0); 223 224 if (readAccessCondition && sharedSiteCondition) 225 { 226 object = _site2json(site); 227 object.put("depth", depth); 228 object.put("current", site.getName().equals(currentSiteName)); 229 object.put("sharedContentsCount", sharedContentsCount); 230 231 if (site.getChildrenSiteNames().isEmpty()) 232 { 233 object.put("sites", new ArrayList<>()); 234 } 235 } 236 return object; 237 } 238 239 /** 240 * Get the JSON representation of a site 241 * @param site The site 242 * @return The site as JSON object 243 */ 244 protected Map<String, Object> _site2json (Site site) 245 { 246 Map<String, Object> object = new HashMap<>(); 247 248 object.put("id", site.getId()); 249 object.put("name", site.getName()); 250 object.put("title", StringUtils.defaultString(site.getTitle())); 251 object.put("description", StringUtils.defaultString(site.getDescription())); 252 object.put("url", StringUtils.defaultString(site.getUrl())); 253 object.put("valid", _siteConfigurationManager.isSiteConfigurationValid(site)); 254 255 object.put("color", site.getColor()); 256 String colorIndex = site.getColor(); 257 if (!_siteColors.getColors().containsKey(colorIndex)) 258 { 259 colorIndex = _siteColors.getDefaultKey(); 260 } 261 object.put("colorIndex", colorIndex); 262 263 SiteType siteType = _siteTypeExtensionPoint.getExtension(site.getType()); 264 265 String iconGlyph = siteType.getIconGlyph(); 266 if (iconGlyph != null) 267 { 268 object.put("iconGlyph", iconGlyph); 269 } 270 271 object.put("iconSmall", siteType.getSmallIcon()); 272 object.put("iconLarge", siteType.getLargeIcon()); 273 object.put("typeLabel", siteType.getLabel()); 274 object.put("type", siteType.getId()); 275 object.put("privateType", siteType.isPrivateType()); 276 277 object.put("populations", _populationContextHelper.getUserPopulationsOnContext("/sites/" + site.getName(), true).stream() 278 .map(_userPopulationDAO::getUserPopulation) 279 .map(_userPopulationDAO::getUserPopulationAsJson) 280 .collect(Collectors.toList())); 281 object.put("populationsFO", _populationContextHelper.getUserPopulationsOnContext("/sites-fo/" + site.getName(), true).stream() 282 .map(_userPopulationDAO::getUserPopulation) 283 .map(_userPopulationDAO::getUserPopulationAsJson) 284 .collect(Collectors.toList())); 285 286 object.put("groups", _groupDirectoryContextHelper.getGroupDirectoriesOnContext("/sites/" + site.getName()).stream() 287 .map(_groupDirectoryDAO::getGroupDirectory) 288 .map(_groupDirectoryDAO::getGroupDirectory2Json) 289 .collect(Collectors.toList())); 290 object.put("groupsFO", _groupDirectoryContextHelper.getGroupDirectoriesOnContext("/sites-fo/" + site.getName()).stream() 291 .map(_groupDirectoryDAO::getGroupDirectory) 292 .map(_groupDirectoryDAO::getGroupDirectory2Json) 293 .collect(Collectors.toList())); 294 295 return object; 296 } 297 298 private long _sharedContentsSize (Site site, String currentSiteName) 299 { 300 if (currentSiteName == null) 301 { 302 return 0; 303 } 304 305 Site currentSite = _siteManager.getSite(currentSiteName); 306 Expression expr = SharedContentsHelper.getSharedContentsExpression(currentSite, site); 307 308 SortCriteria sortCriteria = new SortCriteria(); 309 sortCriteria.addCriterion("title", true, true); 310 String xPathQuery = org.ametys.plugins.repository.query.QueryHelper.getXPathQuery(null, "ametys:content", expr, sortCriteria); 311 312 AmetysObjectIterable<Content> contents = _ametysResolver.query(xPathQuery); 313 return contents.getSize(); 314 } 315 316 /** 317 * Determines if the current user has a read access on site 318 * @param site the site 319 * @param request the request 320 * @return true if current user has read access 321 */ 322 protected boolean canRead (Site site, Request request) 323 { 324 String currentSiteName = (String) request.getAttribute("siteName"); 325 326 try 327 { 328 request.setAttribute("siteName", site.getName()); 329 return _rightManager.hasRight(_userProvider.getUser(), "Web_Right_Site_See_Contents", "/cms") == RightResult.RIGHT_ALLOW; 330 } 331 finally 332 { 333 request.setAttribute("siteName", currentSiteName); 334 } 335 } 336 337}