001/*
002 *  Copyright 2018 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.cms.repository;
017
018import java.util.ArrayList;
019import java.util.Arrays;
020import java.util.HashMap;
021import java.util.List;
022import java.util.Map;
023
024import org.apache.avalon.framework.component.Component;
025import org.apache.avalon.framework.service.ServiceException;
026import org.apache.avalon.framework.service.ServiceManager;
027import org.apache.avalon.framework.service.Serviceable;
028import org.apache.cocoon.xml.AttributesImpl;
029import org.apache.cocoon.xml.XMLUtils;
030import org.apache.commons.lang3.ArrayUtils;
031import org.xml.sax.ContentHandler;
032import org.xml.sax.SAXException;
033
034import org.ametys.cms.repository.ReactionableObject.ReactionType;
035import org.ametys.core.user.UserIdentity;
036import org.ametys.plugins.core.user.UserHelper;
037import org.ametys.plugins.repository.data.holder.ModelLessDataHolder;
038import org.ametys.plugins.repository.data.holder.ModifiableModelLessDataHolder;
039import org.ametys.plugins.repository.data.holder.group.ModifiableModelLessComposite;
040
041/**
042 * Helper class which provides methods to manage reactions on a object
043 */
044public final class ReactionableObjectHelper implements Serviceable, Component
045{
046    /** The Avalon role */
047    public static final String ROLE = ReactionableObjectHelper.class.getName();
048    
049    private UserHelper _userHelper;
050    
051    public void service(ServiceManager smanager) throws ServiceException
052    {
053        _userHelper = (UserHelper) smanager.lookup(UserHelper.ROLE);
054    }
055    
056    /**
057     * Add a user reaction
058     * @param unversionedDataHolder the unversioned data holder
059     * @param user the issuer of reaction
060     * @param reactionType the reaction type
061     */
062    public static void addReaction(ModifiableModelLessDataHolder unversionedDataHolder, UserIdentity user, ReactionType reactionType)
063    {
064        ModifiableModelLessComposite reactionHolder = _getReactionsHolder(unversionedDataHolder, reactionType);
065        
066        UserIdentity[] userArray = _getUsers(reactionHolder);
067        if (!ArrayUtils.contains(userArray, user))
068        {
069            UserIdentity[] newUserArray = ArrayUtils.add(userArray, user);
070            reactionHolder.setValue("users", newUserArray);
071        }
072    }
073
074    /**
075     * Remove a user reaction
076     * @param unversionedDataHolder the unversioned data holder
077     * @param user the issuer of reaction to remove
078     * @param reactionType the reaction type
079     */
080    public static void removeReaction(ModifiableModelLessDataHolder unversionedDataHolder, UserIdentity user, ReactionType reactionType)
081    {
082        ModifiableModelLessComposite reactionHolder = _getReactionsHolder(unversionedDataHolder, reactionType);
083        
084        UserIdentity[] userArray = _getUsers(reactionHolder);
085        if (ArrayUtils.contains(userArray, user))
086        {
087            UserIdentity[] newUserArray = ArrayUtils.removeElement(userArray, user);
088            reactionHolder.setValue("users", newUserArray);
089        }
090    }
091    
092    /**
093     * Get the issuers of a reaction
094     * @param unversionedDataHolder the unversioned data holder
095     * @param reactionType the reaction type
096     * @return the issuers of a reaction as a List
097     */
098    public static List<UserIdentity> getReactionUsers(ModifiableModelLessDataHolder unversionedDataHolder, ReactionType reactionType)
099    {
100        ModifiableModelLessComposite reactionHolder = _getReactionsHolder(unversionedDataHolder, reactionType);
101        UserIdentity[] userArray = _getUsers(reactionHolder);
102        return Arrays.asList(userArray);
103    }
104    
105    /**
106     * Generates SAX events for the given object's reactions.
107     * @param reactionable the {@link ReactionableObject}.
108     * @param contentHandler the ContentHandler receiving SAX events.
109     * @throws SAXException if an error occurs during the SAX events generation.
110     */
111    public void saxReactions(ReactionableObject reactionable, ContentHandler contentHandler) throws SAXException
112    {
113        XMLUtils.startElement(contentHandler, "reactions");
114
115        for (ReactionType reactionType : ReactionType.values())
116        {
117            List<UserIdentity> actors = reactionable.getReactionUsers(reactionType);
118            if (!actors.isEmpty())
119            {
120                AttributesImpl attrs = new AttributesImpl();
121                attrs.addCDATAAttribute("type", reactionType.name());
122                XMLUtils.startElement(contentHandler, "reaction", attrs);
123    
124                for (UserIdentity actor : actors)
125                {
126                    _userHelper.saxUserIdentity(actor, contentHandler, "actor");
127                }
128    
129                XMLUtils.endElement(contentHandler, "reaction");
130            }
131        }
132        XMLUtils.endElement(contentHandler, "reactions");
133    }
134    
135    /**
136     * Get the reactions to JSON format
137     * @param reactionable the reactionable object
138     * @return the reactions as JSON
139     */
140    public List<Map<String, Object>> reactionsToJson(ReactionableObject reactionable)
141    {
142        List<Map<String, Object>> reactions2json = new ArrayList<>();
143        for (ReactionType reactionType : ReactionType.values())
144        {
145            List<UserIdentity> actors = reactionable.getReactionUsers(reactionType);
146            if (!actors.isEmpty())
147            {
148                Map<String, Object> reaction2json = new HashMap<>();
149                
150                reaction2json.put("type", reactionType.name());
151                
152                List<Map<String, Object>> actors2json = new ArrayList<>();
153                for (UserIdentity actor : actors)
154                {
155                    actors2json.add(_userHelper.user2json(actor));
156                }
157                
158                reaction2json.put("actors", actors2json);
159                
160                reactions2json.add(reaction2json);
161            }
162        }
163        
164        return reactions2json;
165    }
166    
167    private static ModifiableModelLessComposite _getReactionsHolder(ModifiableModelLessDataHolder unversionedDataHolder, ReactionType reactionType)
168    {
169        return unversionedDataHolder.getComposite(reactionType.name().toLowerCase(), true);
170    }
171    
172    private static UserIdentity[] _getUsers(ModelLessDataHolder dataHolder)
173    {
174        if (dataHolder.hasValue("users") && !dataHolder.isMultiple("users"))
175        {
176            UserIdentity user = dataHolder.getValue("users");
177            return new UserIdentity[] {user};
178        }
179        else
180        {
181            return dataHolder.getValue("users", new UserIdentity[0]);
182        }
183    }
184}