001/*
002 * (C) Copyright 2006-2018 Nuxeo (http://nuxeo.com/) and others.
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 *
016 * Contributors:
017 *     Thomas Roger <troger@nuxeo.com>
018 */
019
020package org.nuxeo.ecm.rating;
021
022import static org.nuxeo.ecm.core.schema.FacetNames.SUPER_SPACE;
023import static org.nuxeo.ecm.rating.RatingActivityStreamFilter.ACTOR_PARAMETER;
024import static org.nuxeo.ecm.rating.RatingActivityStreamFilter.ASPECT_PARAMETER;
025import static org.nuxeo.ecm.rating.RatingActivityStreamFilter.CONTEXT_PARAMETER;
026import static org.nuxeo.ecm.rating.RatingActivityStreamFilter.QUERY_TYPE_PARAMETER;
027import static org.nuxeo.ecm.rating.RatingActivityStreamFilter.QueryType.GET_ACTOR_RATINGS_FOR_OBJECT;
028import static org.nuxeo.ecm.rating.RatingActivityStreamFilter.QueryType.GET_LATEST_RATED_FOR_OBJECT;
029import static org.nuxeo.ecm.rating.RatingActivityStreamFilter.QueryType.GET_RATED_CHILDREN_FOR_CONTEXT;
030import static org.nuxeo.ecm.rating.RatingActivityStreamFilter.QueryType.GET_RATINGS_FOR_CANCEL;
031import static org.nuxeo.ecm.rating.RatingActivityStreamFilter.QueryType.GET_RATINGS_FOR_OBJECT;
032import static org.nuxeo.ecm.rating.RatingActivityStreamFilter.RATING_PARAMETER;
033import static org.nuxeo.ecm.rating.RatingActivityStreamFilter.TARGET_OBJECT_PARAMETER;
034import static org.nuxeo.ecm.rating.api.Constants.RATING_VERB_PREFIX;
035
036import java.io.Serializable;
037import java.util.HashMap;
038import java.util.Map;
039
040import org.apache.commons.logging.Log;
041import org.apache.commons.logging.LogFactory;
042import org.nuxeo.ecm.activity.ActivitiesList;
043import org.nuxeo.ecm.activity.Activity;
044import org.nuxeo.ecm.activity.ActivityBuilder;
045import org.nuxeo.ecm.activity.ActivityHelper;
046import org.nuxeo.ecm.activity.ActivityStreamService;
047import org.nuxeo.ecm.core.api.DocumentModel;
048import org.nuxeo.ecm.core.api.IdRef;
049import org.nuxeo.ecm.core.api.UnrestrictedSessionRunner;
050import org.nuxeo.ecm.rating.api.RatingService;
051import org.nuxeo.runtime.api.Framework;
052import org.nuxeo.runtime.model.DefaultComponent;
053
054/**
055 * Default implementation of {@see RatingService}.
056 *
057 * @author <a href="mailto:troger@nuxeo.com">Thomas Roger</a>
058 * @since 5.6
059 */
060public class RatingServiceImpl extends DefaultComponent implements RatingService {
061
062    private static final Log log = LogFactory.getLog(RatingServiceImpl.class);
063
064    @Override
065    public void rate(String username, int rating, String activityObject, String aspect) {
066        Activity activity = new ActivityBuilder().verb(RATING_VERB_PREFIX + aspect)
067                                                 .actor(ActivityHelper.createUserActivityObject(username))
068                                                 .target(activityObject)
069                                                 .object(String.valueOf(rating))
070                                                 .build();
071        ActivityStreamService activityStreamService = Framework.getService(ActivityStreamService.class);
072        activityStreamService.addActivity(activity);
073
074        addSuperSpaceRate(activity);
075    }
076
077    @Override
078    public void cancelRate(String username, String activityObject, String aspect) {
079        Map<String, Serializable> parameters = new HashMap<>();
080        parameters.put(QUERY_TYPE_PARAMETER, GET_RATINGS_FOR_CANCEL);
081        parameters.put(ACTOR_PARAMETER, ActivityHelper.createUserActivityObject(username));
082        parameters.put(TARGET_OBJECT_PARAMETER, activityObject);
083        parameters.put(ASPECT_PARAMETER, aspect);
084
085        ActivityStreamService activityStreamService = Framework.getService(ActivityStreamService.class);
086        ActivitiesList activities = activityStreamService.query(RatingActivityStreamFilter.ID, parameters);
087        activityStreamService.removeActivities(activities);
088    }
089
090    @Override
091    public void cancelRates(String activityObject, String aspect) {
092        Map<String, Serializable> parameters = new HashMap<>();
093        parameters.put(QUERY_TYPE_PARAMETER, GET_RATINGS_FOR_CANCEL);
094        parameters.put(TARGET_OBJECT_PARAMETER, activityObject);
095        parameters.put(ASPECT_PARAMETER, aspect);
096
097        ActivityStreamService activityStreamService = Framework.getService(ActivityStreamService.class);
098        ActivitiesList activities = activityStreamService.query(RatingActivityStreamFilter.ID, parameters);
099        activityStreamService.removeActivities(activities);
100    }
101
102    @Override
103    public boolean hasUserRated(String username, String activityObject, String aspect) {
104        Map<String, Serializable> parameters = new HashMap<>();
105        parameters.put(QUERY_TYPE_PARAMETER, GET_ACTOR_RATINGS_FOR_OBJECT);
106        parameters.put(ACTOR_PARAMETER, ActivityHelper.createUserActivityObject(username));
107        parameters.put(TARGET_OBJECT_PARAMETER, activityObject);
108        parameters.put(ASPECT_PARAMETER, aspect);
109
110        ActivityStreamService activityStreamService = Framework.getService(ActivityStreamService.class);
111        ActivitiesList activities = activityStreamService.query(RatingActivityStreamFilter.ID, parameters);
112        return !activities.isEmpty();
113    }
114
115    @Override
116    public long getRatesCount(String activityObject, String aspect) {
117        Map<String, Serializable> parameters = new HashMap<>();
118        parameters.put(QUERY_TYPE_PARAMETER, GET_RATINGS_FOR_OBJECT);
119        parameters.put(TARGET_OBJECT_PARAMETER, activityObject);
120        parameters.put(ASPECT_PARAMETER, aspect);
121
122        ActivityStreamService activityStreamService = Framework.getService(ActivityStreamService.class);
123        ActivitiesList activities = activityStreamService.query(RatingActivityStreamFilter.ID, parameters);
124        return activities.size();
125    }
126
127    @Override
128    public long getRatesCount(String activityObject, int rating, String aspect) {
129        Map<String, Serializable> parameters = new HashMap<>();
130        parameters.put(QUERY_TYPE_PARAMETER, GET_RATINGS_FOR_OBJECT);
131        parameters.put(TARGET_OBJECT_PARAMETER, activityObject);
132        parameters.put(ASPECT_PARAMETER, aspect);
133        parameters.put(RATING_PARAMETER, Integer.valueOf(rating));
134
135        ActivityStreamService activityStreamService = Framework.getService(ActivityStreamService.class);
136        ActivitiesList activities = activityStreamService.query(RatingActivityStreamFilter.ID, parameters);
137        return activities.size();
138    }
139
140    @Override
141    public long getRatesCountForUser(String username, String activityObject, String aspect) {
142        Map<String, Serializable> parameters = new HashMap<>();
143        parameters.put(QUERY_TYPE_PARAMETER, GET_ACTOR_RATINGS_FOR_OBJECT);
144        parameters.put(ACTOR_PARAMETER, ActivityHelper.createUserActivityObject(username));
145        parameters.put(TARGET_OBJECT_PARAMETER, activityObject);
146        parameters.put(ASPECT_PARAMETER, aspect);
147
148        ActivityStreamService activityStreamService = Framework.getService(ActivityStreamService.class);
149        ActivitiesList activities = activityStreamService.query(RatingActivityStreamFilter.ID, parameters);
150        return activities.size();
151    }
152
153    @Override
154    public long getRatesCountForUser(String username, String activityObject, int rating, String aspect) {
155        Map<String, Serializable> parameters = new HashMap<>();
156        parameters.put(QUERY_TYPE_PARAMETER, GET_ACTOR_RATINGS_FOR_OBJECT);
157        parameters.put(ACTOR_PARAMETER, ActivityHelper.createUserActivityObject(username));
158        parameters.put(TARGET_OBJECT_PARAMETER, activityObject);
159        parameters.put(ASPECT_PARAMETER, aspect);
160        parameters.put(RATING_PARAMETER, Integer.valueOf(rating));
161
162        ActivityStreamService activityStreamService = Framework.getService(ActivityStreamService.class);
163        ActivitiesList activities = activityStreamService.query(RatingActivityStreamFilter.ID, parameters);
164        return activities.size();
165    }
166
167    @Override
168    public double getAverageRating(String activityObject, String aspect) {
169        Map<String, Serializable> parameters = new HashMap<>();
170        parameters.put(QUERY_TYPE_PARAMETER, GET_RATINGS_FOR_OBJECT);
171        parameters.put(TARGET_OBJECT_PARAMETER, activityObject);
172        parameters.put(ASPECT_PARAMETER, aspect);
173
174        ActivityStreamService activityStreamService = Framework.getService(ActivityStreamService.class);
175        ActivitiesList activities = activityStreamService.query(RatingActivityStreamFilter.ID, parameters);
176        return computeAverage(activities);
177    }
178
179    @Override
180    public double getAverageRatingForUser(String username, String activityObject, String aspect) {
181        Map<String, Serializable> parameters = new HashMap<>();
182        parameters.put(QUERY_TYPE_PARAMETER, GET_ACTOR_RATINGS_FOR_OBJECT);
183        parameters.put(ACTOR_PARAMETER, ActivityHelper.createUserActivityObject(username));
184        parameters.put(TARGET_OBJECT_PARAMETER, activityObject);
185        parameters.put(ASPECT_PARAMETER, aspect);
186
187        ActivityStreamService activityStreamService = Framework.getService(ActivityStreamService.class);
188        ActivitiesList activities = activityStreamService.query(RatingActivityStreamFilter.ID, parameters);
189        return computeAverage(activities);
190    }
191
192    @Override
193    public ActivitiesList getRatedChildren(String activityObject, int rating, String aspect) {
194        Map<String, Serializable> parameters = new HashMap<>();
195        parameters.put(QUERY_TYPE_PARAMETER, GET_RATED_CHILDREN_FOR_CONTEXT);
196        parameters.put(CONTEXT_PARAMETER, activityObject);
197        parameters.put(ASPECT_PARAMETER, aspect);
198        parameters.put(RATING_PARAMETER, Integer.valueOf(rating));
199
200        ActivityStreamService activityStreamService = Framework.getService(ActivityStreamService.class);
201        return activityStreamService.query(RatingActivityStreamFilter.ID, parameters);
202    }
203
204    @Override
205    public ActivitiesList getLastestRatedDocByUser(String username, String aspect, int limit) {
206        Map<String, Serializable> parameters = new HashMap<>();
207        parameters.put(QUERY_TYPE_PARAMETER, GET_LATEST_RATED_FOR_OBJECT);
208        parameters.put(ACTOR_PARAMETER, ActivityHelper.createUserActivityObject(username));
209        parameters.put(ASPECT_PARAMETER, aspect);
210
211        ActivityStreamService activityStreamService = Framework.getService(ActivityStreamService.class);
212        return activityStreamService.query(RatingActivityStreamFilter.ID, parameters, 0, limit);
213    }
214
215    private double computeAverage(ActivitiesList activities) {
216        double average = 0;
217        for (Activity activity : activities) {
218            try {
219                average += Integer.valueOf(activity.getObject()).intValue();
220            } catch (NumberFormatException e) {
221                log.warn(activity.getObject() + " is not a valid rating");
222            }
223        }
224        return average / activities.size();
225    }
226
227    protected void addSuperSpaceRate(final Activity fromActivity) {
228        final String activityObject = fromActivity.getTarget();
229        if (!ActivityHelper.isDocument(activityObject)) {
230            return;
231        }
232
233        final ActivityStreamService activityStreamService = Framework.getService(ActivityStreamService.class);
234        new UnrestrictedSessionRunner(ActivityHelper.getRepositoryName(activityObject)) {
235            @Override
236            public void run() {
237                IdRef docId = new IdRef(ActivityHelper.getDocumentId(activityObject));
238                for (DocumentModel parent : session.getParentDocuments(docId)) {
239                    if (!parent.hasFacet(SUPER_SPACE)) {
240                        continue;
241                    }
242                    Activity activity = new ActivityBuilder(fromActivity).context(
243                            ActivityHelper.createDocumentActivityObject(parent)).build();
244                    activityStreamService.addActivity(activity);
245                }
246            }
247        }.runUnrestricted();
248    }
249}