001package org.deepamehta.plugins.review;
002
003import de.deepamehta.core.ChildTopics;
004import de.deepamehta.core.Topic;
005import de.deepamehta.core.TopicType;
006import de.deepamehta.core.model.AssociationDefinitionModel;
007import de.deepamehta.core.osgi.PluginActivator;
008import de.deepamehta.core.service.Transactional;
009import java.util.Collection;
010import java.util.logging.Logger;
011import javax.ws.rs.*;
012import javax.ws.rs.core.MediaType;
013import org.deepamehta.plugins.review.service.ReviewService;
014
015
016
017/**
018 * A very stupid plugin for counting likes/dislikes on any kind of topics in DeepaMehta.
019 *
020 * * Counting values seperately as "Good" and "So-so", depends on introducing Migration2 to your application model.
021 * * Counting values as one accumulate "Score", depends on introducing Migration1 to your application model.
022 *
023 * @author Malte Reißig (<malte@mikromedia.de>)
024 * @website https://github.com/mukil/dm4-reviews
025 * @version 0.3.7
026 *
027 */
028
029@Path("/review")
030@Consumes(MediaType.APPLICATION_JSON)
031@Produces(MediaType.APPLICATION_JSON)
032public class ReviewPlugin extends PluginActivator implements ReviewService {
033
034    private Logger log = Logger.getLogger(getClass().getName());
035
036    public final static String SCORE_TYPE_URI = "org.deepamehta.reviews.score";
037    public final static String GOOD_TYPE_URI = "org.deepamehta.reviews.good";
038    public final static String SOSO_TYPE_URI = "org.deepamehta.reviews.soso";
039
040
041    /** Increments the number of supportive voices (yelling "Good!").
042     * @param resourceId
043     **/
044    
045    @GET
046    @Path("/good/{id}")
047    @Produces("application/json")
048    @Override
049    @Transactional
050    public Topic addToGood(@PathParam("id") long resourceId) {
051        Topic topic = null;
052        try {
053            topic = dms.getTopic(resourceId);
054            TopicType typeDef = dms.getTopicType(topic.getTypeUri());
055            Collection<AssociationDefinitionModel> typeModel = typeDef.getModel().getAssocDefs();
056            boolean hasGoodTypeDef = false;
057            for (AssociationDefinitionModel associationDefinitionModel : typeModel) {
058                if (associationDefinitionModel.getChildTypeUri().equals(GOOD_TYPE_URI)) hasGoodTypeDef = true;
059            }
060            if (hasGoodTypeDef) {
061                topic.loadChildTopics(GOOD_TYPE_URI);
062                addOne(topic.getChildTopics(), GOOD_TYPE_URI);
063                dms.updateTopic(topic.getModel()); // ### timestamp bug in 4.4
064            } else {
065                throw new WebApplicationException(new RuntimeException("The TypeDefinition (model) of the given topic "
066                        + "does not contain the \"org.deepamehta.reviews.good\"-type"));
067            }
068        } catch (Exception e) {
069            throw new RuntimeException("something went wrong", e);
070        }
071        return topic;
072    }
073    
074    
075    /** Increments the number of supportive voices (yelling "Well, so so.").
076     * @param resourceId
077     **/
078
079    @GET
080    @Path("/soso/{id}")
081    @Produces("application/json")
082    @Override
083    @Transactional
084    public Topic addToSoso(@PathParam("id") long resourceId) {
085        Topic topic = null;
086        try {
087            topic = dms.getTopic(resourceId);
088            TopicType typeDef = dms.getTopicType(topic.getTypeUri());
089            Collection<AssociationDefinitionModel> typeModel = typeDef.getModel().getAssocDefs();
090            boolean hasSosoTypeDef = false;
091            for (AssociationDefinitionModel associationDefinitionModel : typeModel) {
092                if (associationDefinitionModel.getChildTypeUri().equals(SOSO_TYPE_URI)) hasSosoTypeDef = true;
093            }
094            if (hasSosoTypeDef) {
095                topic.loadChildTopics(SOSO_TYPE_URI);
096                addOne(topic.getChildTopics(), SOSO_TYPE_URI);
097                dms.updateTopic(topic.getModel()); // ### timestamp bug in 4.4
098            } else {
099                throw new WebApplicationException(new RuntimeException("The TypeDefinition (model) of the given topic "
100                        + "does not contain the \"org.deepamehta.reviews.soso\"-type"));
101            }
102        } catch (Exception e) {
103            throw new RuntimeException("something went wrong", e);
104        }
105        return topic;
106    }
107
108    /** Increments the score of any given topic.
109     * @param resourceId
110     **/
111
112    @GET
113    @Path("/upvote/{id}")
114    @Produces("application/json")
115    @Override
116    @Transactional
117    public Topic upvoteResourceById(@PathParam("id") long resourceId) {
118        Topic topic = null;
119        try {
120            topic = dms.getTopic(resourceId);
121            TopicType typeDef = dms.getTopicType(topic.getTypeUri());
122            Collection<AssociationDefinitionModel> typeModel = typeDef.getModel().getAssocDefs();
123            boolean hasScoreTypeDef = false;
124            for (AssociationDefinitionModel associationDefinitionModel : typeModel) {
125                if (associationDefinitionModel.getChildTypeUri().equals(SCORE_TYPE_URI)) hasScoreTypeDef = true;
126            }
127            if (hasScoreTypeDef) {
128                topic.loadChildTopics(SCORE_TYPE_URI);
129                addOne(topic.getChildTopics(), SCORE_TYPE_URI);
130                dms.updateTopic(topic.getModel()); // ### timestamp bug in 4.4
131            } else {
132                throw new RuntimeException("The TypeDefinition (model) of the given topic "
133                        + "does not contain the \"org.deepamehta.reviews.score\"-type");
134            }
135        } catch (Exception e) {
136            throw new RuntimeException("something went wrong", e);
137        }
138        return topic;
139    }
140
141    /** Decrements the score of any given topic.
142     * @param resourceId
143     * @param clientState */
144
145    @GET
146    @Path("/downvote/{id}")
147    @Produces("application/json")
148    @Override
149    @Transactional
150    public Topic downvoteResourceById(@PathParam("id") long resourceId) {
151        Topic topic = null;
152        try {
153            topic = dms.getTopic(resourceId);
154            TopicType typeDef = dms.getTopicType(topic.getTypeUri());
155            Collection<AssociationDefinitionModel> typeModel = typeDef.getModel().getAssocDefs();
156            boolean hasScoreTypeDef = false;
157            for (AssociationDefinitionModel associationDefinitionModel : typeModel) {
158                if (associationDefinitionModel.getChildTypeUri().equals(SCORE_TYPE_URI)) hasScoreTypeDef = true;
159            }
160            if (hasScoreTypeDef) {
161                topic.loadChildTopics(SCORE_TYPE_URI);
162                substractOne(topic.getChildTopics(), SCORE_TYPE_URI);
163                dms.updateTopic(topic.getModel()); // ### timestamp bug in 4.4
164            } else {
165                throw new RuntimeException("The TypeDefinition (model) of the given topic "
166                        + "does not contain the \"org.deepamehta.reviews.score\"-type");
167            }
168        } catch (Exception e) {
169            throw new RuntimeException("something went wrong", e);
170        }
171        return topic;
172    }
173    
174    private void addOne (ChildTopics childTopics, String childTypeUri) {
175        int score = 1;
176        try {
177            if (!childTopics.getModel().has(childTypeUri)) {
178                // initialize with +1
179                childTopics.set(childTypeUri, score);
180            } else {
181                // add 1
182                score = childTopics.getModel().getInt(childTypeUri) + 1;
183                childTopics.set(childTypeUri, score); 
184            }
185        } catch (ClassCastException ce) {
186            // dm4-webclient has written a string into our dm4.core.numbers field
187            String value = "1";
188            try {
189                score = Integer.parseInt(childTopics.getModel().getString(childTypeUri));
190                value = "" + (score + 1);
191            } catch (NumberFormatException ne) {
192                // initialize string number (cause this is the type written to neo4j by dm4-core via dm4-webclient)
193                // with "1"
194            }
195            childTopics.set(childTypeUri, value);
196        }
197    }
198    
199    private void substractOne (ChildTopics childTopics, String childTypeUri) {
200        int score = -1;
201        try {
202            if (!childTopics.getModel().has(childTypeUri)) {
203                // initialize with -1
204                childTopics.set(childTypeUri, score);
205            } else {
206                // subtract 1
207                score = childTopics.getModel().getInt(childTypeUri) - 1;
208                childTopics.set(childTypeUri, score);
209            }
210        } catch (ClassCastException ce) {
211            // dm4-webclient has written a string into our dm4.core.numbers field
212            String value = "-1";
213            try {
214                score = Integer.parseInt(childTopics.getModel().getString(childTypeUri));
215                value = "" + (score - 1);
216            } catch (NumberFormatException ne) {
217                // initialize string number (cause this is the type written to neo4j by dm4-core via dm4-webclient)
218                // with "-1"
219            }
220            childTopics.set(childTypeUri, value);
221        }
222    }
223
224}