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