001/*
002 *  Copyright 2019 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.plugins.ugc.page;
017
018import java.util.Collection;
019import java.util.Collections;
020import java.util.Map;
021import java.util.stream.Collectors;
022
023import org.ametys.cms.contenttype.ContentType;
024import org.ametys.cms.data.ContentValue;
025import org.ametys.cms.repository.Content;
026import org.ametys.cms.repository.ContentTypeExpression;
027import org.ametys.cms.repository.LanguageExpression;
028import org.ametys.plugins.repository.AmetysObjectIterable;
029import org.ametys.plugins.repository.query.QueryHelper;
030import org.ametys.plugins.repository.query.SortCriteria;
031import org.ametys.plugins.repository.query.expression.AndExpression;
032import org.ametys.plugins.repository.query.expression.Expression;
033import org.ametys.plugins.repository.query.expression.Expression.Operator;
034import org.ametys.plugins.repository.query.expression.StringExpression;
035import org.ametys.runtime.i18n.I18nizableText;
036import org.ametys.runtime.model.Enumerator;
037import org.ametys.web.repository.page.Page;
038
039/**
040 * The type of classification for {@link UGCPage UGCPages}
041 */
042public interface ClassificationType
043{
044    /**
045     * Gets the transitional page information for the given UG Content
046     * @param ugcContent The UG Content
047     * @return the transitional page information
048     */
049    TransitionalPageInformation getTransitionalPage(Content ugcContent);
050    
051    /**
052     * Gets all transitional page information
053     * @return all the transitional page information
054     */
055    Collection<TransitionalPageInformation> allTransitionalPages();
056    
057    /**
058     * UGC pages are classified by a linked Content on their UG Content (for instance entries of a reference table)
059     */
060    static class TypeContent implements ClassificationType
061    {
062        private UGCPageHandler _ugcPageHandler;
063        private Page _rootPage;
064        private String _attributeContentType;
065        
066        TypeContent(UGCPageHandler ugcPageHandler, Page rootPage, String attributeContentType)
067        {
068            _ugcPageHandler = ugcPageHandler;
069            _rootPage = rootPage;
070            _attributeContentType = attributeContentType;
071        }
072        
073        @Override
074        public TransitionalPageInformation getTransitionalPage(Content ugcContent)
075        {
076            String classificationAttributePath = _ugcPageHandler.getClassificationAttribute(_rootPage);
077            ContentValue classificationContentValue = ugcContent.getDataHolder().getValue(classificationAttributePath);
078            return new TransitionalPageInformation.TypeContent(classificationContentValue.getContent(), _rootPage);
079        }
080        
081        @Override
082        public Collection<TransitionalPageInformation> allTransitionalPages()
083        {
084            AmetysObjectIterable<Content> allContents = _getAllContents(_rootPage, _attributeContentType);
085            return allContents.stream()
086                    .map(content -> new TransitionalPageInformation.TypeContent(content, _rootPage))
087                    .collect(Collectors.toList());
088        }
089        
090        /**
091         * Get all content with the content type id
092         * @param rootPage the root page
093         * @param contentTypeId the content type id
094         * @return the list of contents
095         */
096        protected AmetysObjectIterable<Content> _getAllContents(Page rootPage, String contentTypeId)
097        {
098            String xPathQuery = null;
099            ContentTypeExpression contentTypeExp = new ContentTypeExpression(Operator.EQ, contentTypeId);
100            
101            ContentType contentType = _ugcPageHandler._cTypeEP.getExtension(contentTypeId);
102            if (contentType.isReferenceTable())
103            {
104                if (contentType.isMultilingual())
105                {
106                    xPathQuery = QueryHelper.getXPathQuery(null, "ametys:content", contentTypeExp, null);
107                }
108                else
109                {
110                    String lang = rootPage.getSitemapName();
111                    Expression finalExpr = new AndExpression(contentTypeExp, new LanguageExpression(Operator.EQ, lang));
112
113                    xPathQuery = QueryHelper.getXPathQuery(null, "ametys:content", finalExpr, null);
114                }
115            }
116            else
117            {
118                SortCriteria sort = new SortCriteria();
119                sort.addCriterion(Content.ATTRIBUTE_TITLE, true, true);
120
121                StringExpression siteEpx = new StringExpression("site", Operator.EQ, rootPage.getSiteName());
122                String lang = rootPage.getSitemapName();
123                Expression finalExpr = new AndExpression(contentTypeExp, siteEpx, new LanguageExpression(Operator.EQ, lang));
124                
125                xPathQuery = QueryHelper.getXPathQuery(null, "ametys:content", finalExpr, sort);
126            }
127            
128            return _ugcPageHandler._resolver.query(xPathQuery);
129        }
130    }
131    
132    /**
133     * UGC pages are classified by entries of an enumerator
134     */
135    static class TypeEnum implements ClassificationType
136    {
137        private UGCPageHandler _ugcPageHandler;
138        private Page _rootPage;
139        private Enumerator<String> _enumerator;
140        
141        TypeEnum(UGCPageHandler ugcPageHandler, Page rootPage, Enumerator<String> enumerator)
142        {
143            _ugcPageHandler = ugcPageHandler;
144            _rootPage = rootPage;
145            _enumerator = enumerator;
146        }
147        
148        @Override
149        public TransitionalPageInformation getTransitionalPage(Content ugcContent)
150        {
151            String classificationAttributePath = _ugcPageHandler.getClassificationAttribute(_rootPage);
152            String key = ugcContent.getDataHolder().getValue(classificationAttributePath);
153            
154            try
155            {
156                I18nizableText i18nEntry = _enumerator.getEntry(key);
157                return new TransitionalPageInformation.TypeEnum(_ugcPageHandler, key, i18nEntry);
158            }
159            catch (Exception e)
160            {
161                _ugcPageHandler.getLogger().error("An error occurred. Can't get enumerator entry for metadata path " + classificationAttributePath + " and key " + key, e);
162                throw new IllegalArgumentException("", e);
163            }
164        }
165        
166        @Override
167        public Collection<TransitionalPageInformation> allTransitionalPages()
168        {
169            Map<String, I18nizableText> typedEntries;
170            try
171            {
172                typedEntries = _enumerator.getTypedEntries();
173            }
174            catch (Exception e)
175            {
176                String classificationAttributePath = _ugcPageHandler.getClassificationAttribute(_rootPage);
177                _ugcPageHandler.getLogger().error("An error occurred. Can't get enumerator entries for metadata path " + classificationAttributePath, e);
178                return Collections.EMPTY_SET;
179            }
180            
181            return typedEntries
182                    .entrySet()
183                    .stream()
184                    .map(e -> new TransitionalPageInformation.TypeEnum(_ugcPageHandler, e.getKey(), e.getValue()))
185                    .collect(Collectors.toList());
186        }
187    }
188    
189    /**
190     * There is no transitional page
191     */
192    static class None implements ClassificationType
193    {
194        None()
195        {  }
196        
197        @Override
198        public TransitionalPageInformation getTransitionalPage(Content ugcContent)
199        {
200            throw new IllegalStateException("There is no transitional page");
201        }
202        
203        @Override
204        public Collection<TransitionalPageInformation> allTransitionalPages()
205        {
206            return Collections.emptySet();
207        }
208    }
209}