001/*
002 *  Copyright 2020 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.mobileapp.action;
017
018import java.time.Instant;
019import java.time.LocalDate;
020import java.time.ZonedDateTime;
021import java.util.ArrayList;
022import java.util.Comparator;
023import java.util.Date;
024import java.util.HashMap;
025import java.util.List;
026import java.util.Map;
027import java.util.stream.Collectors;
028
029import org.apache.avalon.framework.service.ServiceException;
030import org.apache.avalon.framework.service.ServiceManager;
031import org.apache.cocoon.environment.Request;
032
033import org.ametys.cms.repository.Content;
034import org.ametys.cms.search.content.ContentSearcherFactory.ContentSearchSort;
035import org.ametys.core.right.RightManager;
036import org.ametys.plugins.mobileapp.PostConstants;
037import org.ametys.plugins.mobileapp.QueriesHelper;
038import org.ametys.plugins.queriesdirectory.Query;
039import org.ametys.plugins.repository.AmetysObjectIterable;
040import org.ametys.web.repository.site.Site;
041import org.ametys.web.repository.site.SiteManager;
042
043/**
044 * Returns the list of feeds for a user
045 */
046public class GetFeedsContentsAction extends AbstractLoggedAction
047{
048    /** The Ametys object resolver */
049    protected QueriesHelper _queryHelper;
050
051    /** Authentication Token Manager */
052    protected SiteManager _siteManager;
053    
054    private RightManager _rightManager;
055
056    @Override
057    public void service(ServiceManager smanager) throws ServiceException
058    {
059        super.service(smanager);
060        _queryHelper = (QueriesHelper) smanager.lookup(QueriesHelper.ROLE);
061        _siteManager = (SiteManager) smanager.lookup(SiteManager.ROLE);
062        _rightManager = (RightManager) smanager.lookup(RightManager.ROLE);
063    }
064
065    @Override
066    protected Map<String, Object> doLoggedInAction(Request request, Map<String, Object> jsonParams)
067    {
068        Map<String, Object> result = new HashMap<>();
069
070        String siteName = (String) getParameter(PostConstants.SITE_NAME, jsonParams, request);
071
072        Site site = _siteManager.getSite(siteName);
073
074        List<Query> queries = _queryHelper.getQueries(site);
075
076        List<QuerySearchresult> results = new ArrayList<>();
077
078        for (Query query : queries)
079        {
080            if (_rightManager.hasReadAccess(_currentUserProvider.getUser(), query))
081            {
082                List<ContentSearchSort> sort = _queryHelper.getSortProperty(query, queries.size() > 1);
083                AmetysObjectIterable<Content> searchResults = _queryHelper.executeQuery(query, sort, true);
084                if (searchResults != null)
085                {
086                    ContentSearchSort firstSort = sort.get(0);
087                    searchResults.stream()
088                                 .forEach(content -> results.add(new QuerySearchresult(query, firstSort, content)));
089                }
090            }
091        }
092
093        Comparator<QuerySearchresult> comparator = new Comparator<>()
094        {
095            public int compare(QuerySearchresult o1, QuerySearchresult o2)
096            {
097                Object o1Value = getDate(o1);
098                Object o2Value = getDate(o2);
099                return compareDates(o1Value, o2Value);
100            }
101
102            private Object getDate(QuerySearchresult queryResult)
103            {
104                String field = queryResult.getSort().sortField();
105                Content content = queryResult.getContent();
106                Object value;
107                if (content.hasValue(field))
108                {
109                    value = content.getValue(field, true, null);
110                }
111                else
112                {
113                    value = content.getLastValidationDate();
114                }
115                return value;
116            }
117        };
118
119        List<Map<String, String>> jsonResults;
120        if (queries.size() > 1)
121        {
122            jsonResults = results.stream()
123                .sorted(comparator)
124                .map(searchResult -> contentToJson(searchResult))
125                .collect(Collectors.toList());
126        }
127        else
128        {
129            jsonResults = results.stream()
130                    .map(searchResult -> contentToJson(searchResult))
131                    .collect(Collectors.toList());
132        }
133
134
135        result.put("items", jsonResults);
136
137        return result;
138    }
139
140    /**
141     * Transform a content into a json map
142     * @param searchResult the search result containing tho content
143     * @return a json map
144     */
145    protected Map<String, String> contentToJson(QuerySearchresult searchResult)
146    {
147        Content content = searchResult.getContent();
148        Map<String, String> result = _queryHelper.getDataForContent(content);
149
150        result.put("feed_id", searchResult.getQueryId());
151        result.put("category_name", searchResult.getQueryName());
152
153        String sortField = searchResult.getSort().sortField();
154
155        String isoDate = _queryHelper.getContentFormattedDate(content, sortField);
156        result.put("date", isoDate);
157
158        return result;
159    }
160
161    /**
162     * Compare two dates (can be {@link ZonedDateTime} and/or {@link LocalDate} and/or {@link Date}
163     * @param o1 a {@link ZonedDateTime} and/or {@link LocalDate} and/or {@link Date}
164     * @param o2 a {@link ZonedDateTime} and/or {@link LocalDate} and/or {@link Date}
165     * @return -1 if o1 is before o2, +1 if o1 is after o2, 0 if same date (not equals)
166     * @throws ClassCastException one of the object is not a {@link ZonedDateTime} or {@link LocalDate} or {@link Date}
167     */
168    protected int compareDates(Object o1, Object o2) throws ClassCastException
169    {
170        if (o1 == null && o2 == null)
171        {
172            return 0;
173        }
174        else if (o1 == null)
175        {
176            return -1;
177        }
178        else if (o2 == null)
179        {
180            return 1;
181        }
182        else if (o1 instanceof Date && o2 instanceof Date)
183        {
184            return ((Date) o1).compareTo((Date) o2);
185        }
186        else if (o1 instanceof LocalDate && o2 instanceof LocalDate)
187        {
188            return ((LocalDate) o1).compareTo((LocalDate) o2);
189        }
190        else if (o1 instanceof ZonedDateTime && o2 instanceof ZonedDateTime)
191        {
192            return ((ZonedDateTime) o1).compareTo((ZonedDateTime) o2);
193        }
194
195        Instant i1 = _queryHelper.toInstant(o1, o2);
196        Instant i2 = _queryHelper.toInstant(o2, o1);
197        if (i1 != null && i2 != null)
198        {
199            return i1.compareTo(i2);
200        }
201
202        // One of them is not null and not a LocalDate or ZonedDateTime
203        throw new ClassCastException();
204    }
205
206    /**
207     * Content fetched from a query
208     */
209    protected class QuerySearchresult
210    {
211        private Query _query;
212        private ContentSearchSort _sort;
213        private Content _content;
214
215        /**
216         * New QuerySearchresult
217         * @param query the query that found this content
218         * @param sort the sort used
219         * @param content the content itself
220         */
221        public QuerySearchresult(Query query, ContentSearchSort sort, Content content)
222        {
223            _query = query;
224            _sort = sort;
225            _content = content;
226        }
227
228        /**
229         * The query ID
230         * @return The query ID
231         */
232        public String getQueryId()
233        {
234            return _query.getId();
235        }
236        /**
237         * The query name
238         * @return The query name
239         */
240        public String getQueryName()
241        {
242            return _query.getTitle();
243        }
244
245
246        /**
247         * The sort
248         * @return The sort
249         */
250        public ContentSearchSort getSort()
251        {
252            return _sort;
253        }
254
255        /**
256         * The content
257         * @return The content
258         */
259        public Content getContent()
260        {
261            return _content;
262        }
263
264    }
265
266}