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