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