001/*
002 *  Copyright 2011 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.filter;
017
018import java.util.ArrayList;
019import java.util.Collection;
020import java.util.Collections;
021import java.util.HashSet;
022import java.util.List;
023import java.util.Set;
024
025import org.ametys.cms.data.type.ModelItemTypeConstants;
026import org.ametys.cms.repository.Content;
027import org.ametys.cms.search.query.AndQuery;
028import org.ametys.cms.search.query.OrQuery;
029import org.ametys.cms.search.query.Query;
030import org.ametys.plugins.repository.AmetysObjectIterable;
031import org.ametys.plugins.repository.AmetysRepositoryException;
032import org.ametys.plugins.repository.query.expression.AndExpression;
033import org.ametys.plugins.repository.query.expression.Expression;
034import org.ametys.plugins.repository.query.expression.Expression.Operator;
035import org.ametys.plugins.repository.query.expression.MetadataExpression;
036import org.ametys.plugins.repository.query.expression.NotExpression;
037import org.ametys.plugins.repository.query.expression.OrExpression;
038import org.ametys.plugins.repository.query.expression.StringExpression;
039import org.ametys.runtime.model.type.ModelItemType;
040import org.ametys.web.repository.SiteAwareAmetysObject;
041import org.ametys.web.repository.content.jcr.DefaultSharedContent;
042import org.ametys.web.repository.site.Site;
043import org.ametys.web.search.query.ContentPrivacyQuery;
044import org.ametys.web.search.query.SiteQuery;
045
046/**
047 * Helper for creating expression for shared contents
048 */
049public final class SharedContentsHelper
050{
051    private SharedContentsHelper()
052    {
053        // empty constructor
054    }
055    
056    /**
057     * Copy the title of the source content to the target content
058     * @param srcContent The source content
059     * @param targetContent The shared target content
060     * @throws AmetysRepositoryException if an error occurs.
061     */
062    public static void copyTitle(Content srcContent, DefaultSharedContent targetContent) throws AmetysRepositoryException
063    {
064        ModelItemType type = srcContent.getType(Content.ATTRIBUTE_TITLE);
065        if (ModelItemTypeConstants.MULTILINGUAL_STRING_ELEMENT_TYPE_ID.equals(type.getId()))
066        {
067            targetContent.getDataHolder().setValue(Content.ATTRIBUTE_TITLE, srcContent.getValue(Content.ATTRIBUTE_TITLE));
068        }
069        else
070        {
071            targetContent.getDataHolder().setValue(Content.ATTRIBUTE_TITLE, srcContent.getTitle());
072        }
073    }
074    
075    /**
076     * Get the expression for shared contents
077     * @param currentSite the current site
078     * @param site the site of contents to find
079     * @return the expression to aware of privacy of contents or null if sites are equals
080     */
081    public static Expression getSharedContentsExpression (Site currentSite, Site site)
082    {
083        String siteName = site.getName();
084        List<String> siteNames = new ArrayList<>();
085        siteNames.add(siteName);
086        
087        if (!siteName.equals(currentSite.getName()))
088        {
089            String privacy = site.getValue("content-privacy", true, null);
090            boolean isClosed = currentSite.hasAncestor(siteName) || currentSite.hasDescendant(siteName);
091            
092            if (isClosed)
093            {
094                if ("private".equals(privacy))
095                {
096                    return getSharedContentsExpressionForPrivateClosedSites(siteNames);
097                }
098                else
099                {
100                    return getSharedContentsExpressionForPublicOrProtectedClosedSites(siteNames);
101                }
102            }
103            else
104            {
105                if ("public".equals(privacy))
106                {
107                    return getSharedContentsExpressionForPublicOutsideSites(siteNames);
108                }
109                else
110                {
111                    return getSharedContentsExpressionForPrivateOrProtectedOutsideSites(siteNames);
112                }
113            }
114        }
115        
116        return null;
117    }
118    
119    /**
120     * Get the expression for shared contents
121     * @param currentSite the current site
122     * @param sites all sites
123     * @return the expression to aware of privacy of contents
124     */
125    public static Expression getSharedContentsExpression (Site currentSite, AmetysObjectIterable<Site> sites)
126    {
127        List<String> privateClosedSites = new ArrayList<>();
128        List<String> publicOrProtectedClosedSites = new ArrayList<>();
129        List<String> publicOutsideSites = new ArrayList<>();
130        List<String> privateOrProtectedOutsideSites = new ArrayList<>();
131        
132        for (Site site : sites)
133        {
134            String siteName = site.getName();
135            if (!siteName.equals(currentSite.getName()))
136            {
137                String privacy = site.getValue("content-privacy", false, "public");
138                boolean isClosed = currentSite.hasAncestor(siteName) || currentSite.hasDescendant(siteName);
139                
140                if (isClosed)
141                {
142                    if ("private".equals(privacy))
143                    {
144                        privateClosedSites.add(siteName);
145                    }
146                    else
147                    {
148                        publicOrProtectedClosedSites.add(siteName);
149                    }
150                }
151                else
152                {
153                    if ("public".equals(privacy))
154                    {
155                        publicOutsideSites.add(siteName);
156                    }
157                    else
158                    {
159                        privateOrProtectedOutsideSites.add(siteName);
160                    }
161                }
162            }
163        }
164        
165        List<Expression> exprs = new ArrayList<>();
166        
167        Expression expr0 = new StringExpression(SiteAwareAmetysObject.METADATA_SITE, Operator.EQ, currentSite.getName()); 
168        exprs.add(expr0);
169        
170        Expression expr1 = getSharedContentsExpressionForPrivateClosedSites(privateClosedSites);
171        if (expr1 != null)
172        {
173            exprs.add(expr1);
174        }
175        
176        Expression expr2 = getSharedContentsExpressionForPublicOrProtectedClosedSites(publicOrProtectedClosedSites);
177        if (expr2 != null)
178        {
179            exprs.add(expr2);
180        }
181        
182        Expression expr3 = getSharedContentsExpressionForPublicOutsideSites(publicOutsideSites);
183        if (expr3 != null)
184        {
185            exprs.add(expr3);
186        }
187        
188        Expression expr4 = getSharedContentsExpressionForPrivateOrProtectedOutsideSites(privateOrProtectedOutsideSites);
189        if (expr4 != null)
190        {
191            exprs.add(expr4);
192        }
193        
194        return new OrExpression(exprs.toArray(new Expression[exprs.size()]));
195    }
196    
197    /**
198     * Get the expression corresponding to the shared contents of privates sites
199     * @param siteNames the site names of private and closed sites
200     * @return the expression corresponding to the shared contents of privates sites
201     */
202    public static Expression getSharedContentsExpressionForPrivateClosedSites (List<String> siteNames)
203    {
204        if (siteNames.isEmpty())
205        {
206            return null;
207        }
208        
209        Expression expr = new OrExpression(new StringExpression("privacy", Operator.EQ, "public"), new StringExpression("privacy", Operator.EQ, "protected"));
210        Expression[] sitesExpr = new Expression[siteNames.size()];
211        
212        int i = 0;
213        for (String siteName : siteNames)
214        {
215            sitesExpr[i] = new StringExpression(SiteAwareAmetysObject.METADATA_SITE, Operator.EQ, siteName);
216            i++;
217        }
218        
219        return new AndExpression(new OrExpression(sitesExpr), expr);
220    }
221    
222    /**
223     * Get the expression corresponding to the shared contents of public or protected sites
224     * @param siteNames the list of public or protected sites
225     * @return the expression corresponding to the shared contents of public or protected sites
226     */
227    public static  Expression getSharedContentsExpressionForPublicOrProtectedClosedSites (List<String> siteNames)
228    {
229        if (siteNames.isEmpty())
230        {
231            return null;
232        }
233        
234        Expression expr = new OrExpression(new NotExpression(new MetadataExpression("privacy")), new StringExpression("privacy", Operator.NE, "private"));
235        Expression[] sitesExpr = new Expression[siteNames.size()];
236        
237        int i = 0;
238        for (String siteName : siteNames)
239        {
240            sitesExpr[i] = new StringExpression(SiteAwareAmetysObject.METADATA_SITE, Operator.EQ, siteName);
241            i++;
242        }
243        
244        return new AndExpression(new OrExpression(sitesExpr), expr);
245    }
246    
247    /**
248     * Get the expression corresponding to the shared contents of public sites
249     * @param siteNames the list of public sites
250     * @return the expression corresponding to the shared contents of public sites
251     */
252    public static  Expression getSharedContentsExpressionForPublicOutsideSites (List<String> siteNames)
253    {
254        if (siteNames.isEmpty())
255        {
256            return null;
257        }
258        
259        Expression expr = new OrExpression(new NotExpression(new MetadataExpression("privacy")), new StringExpression("privacy", Operator.EQ, "public"));     
260        Expression[] sitesExpr = new Expression[siteNames.size()];
261        
262        int i = 0;
263        for (String siteName : siteNames)
264        {
265            sitesExpr[i] = new StringExpression(SiteAwareAmetysObject.METADATA_SITE, Operator.EQ, siteName);
266            i++;
267        }
268        
269        return new AndExpression(new OrExpression(sitesExpr), expr);
270    }
271    
272    /**
273     * Get the expression corresponding to the shared contents of private or protected sites
274     * @param siteNames the list of private or protected sites
275     * @return the expression corresponding to the shared contents of private or protected sites
276     */
277    public static  Expression getSharedContentsExpressionForPrivateOrProtectedOutsideSites (List<String> siteNames)
278    {
279        if (siteNames.isEmpty())
280        {
281            return null;
282        }
283        
284        Expression expr = new StringExpression("privacy", Operator.EQ, "public");     
285        Expression[] sitesExpr = new Expression[siteNames.size()];
286        
287        int i = 0;
288        for (String siteName : siteNames)
289        {
290            sitesExpr[i] = new StringExpression(SiteAwareAmetysObject.METADATA_SITE, Operator.EQ, siteName);
291            i++;
292        }
293        
294        return new AndExpression(new OrExpression(sitesExpr), expr);
295    }
296    
297    /**
298     * Get the expression for shared contents
299     * @param currentSite the current site
300     * @param site the site of contents to find
301     * @return the expression to aware of privacy of contents or null if sites are equals
302     */
303    public static Query getContentAccessQuery(Site currentSite, Site site)
304    {
305        String siteName = site.getName();
306        
307        if (!siteName.equals(currentSite.getName()))
308        {
309            String privacy = site.getValue("content-privacy", false, "public");
310            boolean isClosed = currentSite.hasAncestor(siteName) || currentSite.hasDescendant(siteName);
311            
312            if (isClosed)
313            {
314                if ("private".equals(privacy))
315                {
316                    return getContentAccessQueryForPrivateClosedSites(Collections.singleton(siteName));
317                }
318                else
319                {
320                    return getContentAccessQueryForPublicOrProtectedClosedSites(Collections.singleton(siteName));
321                }
322            }
323            else
324            {
325                if ("public".equals(privacy))
326                {
327                    return getContentAccessQueryForPublicOutsideSites(Collections.singleton(siteName));
328                }
329                else
330                {
331                    return getContentAccessQueryForPrivateOrProtectedOutsideSites(Collections.singleton(siteName));
332                }
333            }
334        }
335        
336        return null;
337    }
338    
339    /**
340     * Get the expression for shared contents
341     * @param currentSite the current site
342     * @param sites all sites
343     * @return the expression to aware of privacy of contents
344     */
345    public static Query getContentAccessQuery(Site currentSite, Iterable<Site> sites)
346    {
347        Set<String> privateClosedSites = new HashSet<>();
348        Set<String> publicOrProtectedClosedSites = new HashSet<>();
349        Set<String> publicOutsideSites = new HashSet<>();
350        Set<String> privateOrProtectedOutsideSites = new HashSet<>();
351        boolean containsCurrent = false;
352        
353        for (Site site : sites)
354        {
355            String siteName = site.getName();
356            if (!siteName.equals(currentSite.getName()))
357            {
358                String privacy = site.getValue("content-privacy", false, "public");
359                boolean isClosed = currentSite.hasAncestor(siteName) || currentSite.hasDescendant(siteName);
360                
361                if (isClosed)
362                {
363                    if ("private".equals(privacy))
364                    {
365                        privateClosedSites.add(siteName);
366                    }
367                    else
368                    {
369                        publicOrProtectedClosedSites.add(siteName);
370                    }
371                }
372                else
373                {
374                    if ("public".equals(privacy))
375                    {
376                        publicOutsideSites.add(siteName);
377                    }
378                    else
379                    {
380                        privateOrProtectedOutsideSites.add(siteName);
381                    }
382                }
383            }
384            else
385            {
386                containsCurrent = true;
387            }
388        }
389        
390        List<Query> queries = new ArrayList<>();
391        
392        if (containsCurrent)
393        {
394            Query expr0 = new SiteQuery(currentSite.getName()); 
395            queries.add(expr0);
396        }
397        
398        Query expr1 = getContentAccessQueryForPrivateClosedSites(privateClosedSites);
399        if (expr1 != null)
400        {
401            queries.add(expr1);
402        }
403        
404        Query expr2 = getContentAccessQueryForPublicOrProtectedClosedSites(publicOrProtectedClosedSites);
405        if (expr2 != null)
406        {
407            queries.add(expr2);
408        }
409        
410        Query expr3 = getContentAccessQueryForPublicOutsideSites(publicOutsideSites);
411        if (expr3 != null)
412        {
413            queries.add(expr3);
414        }
415        
416        Query expr4 = getContentAccessQueryForPrivateOrProtectedOutsideSites(privateOrProtectedOutsideSites);
417        if (expr4 != null)
418        {
419            queries.add(expr4);
420        }
421        
422        return new OrQuery(queries);
423    }
424    
425    /**
426     * Get the expression corresponding to the shared contents of privates sites
427     * @param siteNames the site names of private and closed sites
428     * @return the expression corresponding to the shared contents of privates sites
429     */
430    public static Query getContentAccessQueryForPrivateClosedSites(Collection<String> siteNames)
431    {
432        if (siteNames.isEmpty())
433        {
434            return null;
435        }
436        
437        return new AndQuery(new SiteQuery(siteNames), new ContentPrivacyQuery("public", "protected"));
438    }
439    
440    /**
441     * Get the expression corresponding to the shared contents of public or protected sites
442     * @param siteNames the list of public or protected sites
443     * @return the expression corresponding to the shared contents of public or protected sites
444     */
445    public static Query getContentAccessQueryForPublicOrProtectedClosedSites(Collection<String> siteNames)
446    {
447        if (siteNames.isEmpty())
448        {
449            return null;
450        }
451        
452        Query privacyQuery = new ContentPrivacyQuery(org.ametys.cms.search.query.Query.Operator.NE, "private");
453        
454        return new AndQuery(new SiteQuery(siteNames), privacyQuery);
455    }
456    
457    /**
458     * Get the expression corresponding to the shared contents of public sites
459     * @param siteNames the list of public sites
460     * @return the expression corresponding to the shared contents of public sites
461     */
462    public static Query getContentAccessQueryForPublicOutsideSites(Collection<String> siteNames)
463    {
464        if (siteNames.isEmpty())
465        {
466            return null;
467        }
468        
469        return new AndQuery(new SiteQuery(siteNames), new ContentPrivacyQuery("public"));
470    }
471    
472    /**
473     * Get the expression corresponding to the shared contents of private or protected sites
474     * @param siteNames the list of private or protected sites
475     * @return the expression corresponding to the shared contents of private or protected sites
476     */
477    public static Query getContentAccessQueryForPrivateOrProtectedOutsideSites(Collection<String> siteNames)
478    {
479        if (siteNames.isEmpty())
480        {
481            return null;
482        }
483        
484        return new AndQuery(new SiteQuery(siteNames), new ContentPrivacyQuery("public"));
485    }
486    
487}