/* * See the NOTICE file distributed with this work for additional * information regarding copyright ownership. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.xwiki.ratings.internal; import java.util.List; import javax.inject.Inject; import javax.inject.Provider; import org.slf4j.Logger; import org.xwiki.model.reference.DocumentReference; import org.xwiki.observation.ObservationManager; import org.xwiki.ratings.AverageRating; import org.xwiki.ratings.Rating; import org.xwiki.ratings.RatingsConfiguration; import org.xwiki.ratings.RatingsException; import org.xwiki.ratings.RatingsManager; import org.xwiki.ratings.ReputationException; import com.xpn.xwiki.XWiki; import com.xpn.xwiki.XWikiContext; import com.xpn.xwiki.XWikiException; import com.xpn.xwiki.doc.XWikiDocument; import com.xpn.xwiki.objects.BaseObject; /** * @version $Id: 2878b55a1406b5dabd637f9f05a725713f50c4c7 $ * @see RatingsManager * @since 6.4M3 */ public abstract class AbstractRatingsManager implements RatingsManager { @Inject protected ObservationManager observationManager; @Inject private Logger logger; @Inject private Provider<XWikiContext> xcontextProvider; @Inject private RatingsConfiguration ratingsConfiguration; @Override public String getRatingsClassName() { return RATINGS_CLASSNAME; } /** * Gets the average ratings class. * * @return the XWiki document representing the AverageRatingsClass. */ public String getAverageRatingsClassName() { return AVERAGE_RATINGS_CLASSNAME; } /** * Gets the ratings configuration component. * * @return the ratingsConfiguration representing the RatingsConfiguration component. */ protected RatingsConfiguration getRatingsConfiguration() { return ratingsConfiguration; } /** * Retrieves the XWiki context from the current execution context. * * @return the XWiki context * @throws RuntimeException if there was an error retrieving the context */ protected XWikiContext getXWikiContext() { return this.xcontextProvider.get(); } /** * Retrieves the XWiki private API object. * * @return The XWiki private API object */ protected XWiki getXWiki() { return getXWikiContext().getWiki(); } /** * Checks if ratings are active. * * @return answer to: are ratings active? */ public boolean hasRatings() { int result = (int) getXWiki().ParamAsLong("xwiki.ratings", 0); return (getXWiki().getXWikiPreferenceAsInt("ratings", result, getXWikiContext()) == 1); } @Override public boolean isAverageRatingStored(DocumentReference documentRef) { String result = getXWiki().Param("xwiki.ratings.averagerating.stored", "1"); result = getXWiki().getXWikiPreference("ratings_averagerating_stored", result, getXWikiContext()); return (ratingsConfiguration.getConfigurationParameter(documentRef, RatingsManager.RATINGS_CONFIG_CLASS_FIELDNAME_STORE_AVERAGE_RATING, result).equals("1")); } @Override public boolean isReputationStored(DocumentReference documentRef) { String result = getXWiki().Param("xwiki.ratings.reputation.stored", "0"); result = getXWiki().getXWikiPreference("ratings_reputation_stored", result, getXWikiContext()); return (ratingsConfiguration.getConfigurationParameter(documentRef, RatingsManager.RATINGS_CONFIG_CLASS_FIELDNAME_REPUTATION_STORED, result).equals("1")); } @Override public boolean hasReputation(DocumentReference documentRef) { String result = getXWiki().Param("xwiki.ratings.reputation", "0"); result = getXWiki().getXWikiPreference("ratings_reputation", result, getXWikiContext()); return (ratingsConfiguration.getConfigurationParameter(documentRef, RatingsManager.RATINGS_CONFIG_CLASS_FIELDNAME_REPUTATION, result).equals("1")); } @Override public String[] getDefaultReputationMethods(DocumentReference documentRef) { String method = getXWiki().Param("xwiki.ratings.reputation.defaultmethod", RATING_REPUTATION_METHOD_DEFAULT); method = getXWiki().getXWikiPreference("ratings_reputation_defaultmethod", method, getXWikiContext()); method = ratingsConfiguration.getConfigurationParameter(documentRef, RatingsManager.RATINGS_CONFIG_CLASS_FIELDNAME_REPUTATION_METHOD, method); return method.split(","); } @Override public void updateAverageRatings(DocumentReference documentRef, Rating rating, int oldVote) throws RatingsException { String[] methods = getDefaultReputationMethods(documentRef); for (int i = 0; i < methods.length; i++) { updateAverageRating(documentRef, rating, oldVote, methods[i]); } } @Override public AverageRating getAverageRatingFromQuery(String fromsql, String wheresql) throws RatingsException { return getAverageRatingFromQuery(fromsql, wheresql, RATING_REPUTATION_METHOD_AVERAGE); } @Override public AverageRating getAverageRating(DocumentReference documentRef) throws RatingsException { return getAverageRating(documentRef, RATING_REPUTATION_METHOD_AVERAGE); } @Override public AverageRating getAverageRatingFromQuery(String fromsql, String wheresql, String method) throws RatingsException { try { String fromsql2 = fromsql + ", BaseObject as avgobj, FloatProperty as avgvote, StringProperty as avgmethod "; String wheresql2 = (wheresql.equals("") ? "where " : wheresql + " and ") + "doc.fullName=avgobj.name and avgobj.className='" + getAverageRatingsClassName() + "' and avgobj.id=avgvote.id.id and avgvote.id.name='" + AVERAGERATING_CLASS_FIELDNAME_AVERAGEVOTE + "' and avgobj.id=avgmethod.id.id and avgmethod.id.name='" + AVERAGERATING_CLASS_FIELDNAME_AVERAGEVOTE_METHOD + "' and avgmethod.value='" + method + "'"; String sql = "select sum(avgvote.value) as vote, count(avgvote.value) as nbvotes from XWikiDocument as doc " + fromsql2 + wheresql2; if (logger.isDebugEnabled()) { logger.debug("Running average rating with sql " + sql); } getXWikiContext().put("lastsql", sql); List result = getXWiki().getStore().search(sql, 0, 0, getXWikiContext()); float vote = ((Number) ((Object[]) result.get(0))[0]).floatValue(); int nbvotes = ((Number) ((Object[]) result.get(0))[1]).intValue(); AverageRating avgr = new MemoryAverageRating(null, nbvotes, vote / nbvotes, method); return avgr; } catch (XWikiException e) { throw new RatingsException(e); } } @Override public boolean removeRating(Rating rating) throws RatingsException { return rating.remove(); } @Override public AverageRating getUserReputation(DocumentReference username) throws ReputationException { try { return getAverageRating(username, RatingsManager.RATING_REPUTATION_METHOD_AVERAGE); } catch (RatingsException e) { throw new ReputationException(e); } } @Override public AverageRating calcAverageRating(DocumentReference documentRef, String method) throws RatingsException { int nbVotes = 0; int balancedNbVotes = 0; float totalVote = 0; float averageVote = 0; List<Rating> ratings = getRatings(documentRef, 0, 0, true); if (ratings == null) { return null; } for (Rating rating : ratings) { if (method.equals(RATING_REPUTATION_METHOD_BALANCED)) { DocumentReference author = rating.getAuthor(); // in case we are evaluating the average rating of a user // we should not include votes of himself to a user if (!author.equals(documentRef)) { AverageRating reputation = getUserReputation(author); if ((reputation == null) || (reputation.getAverageVote() == 0)) { totalVote += rating.getVote(); balancedNbVotes++; } else { totalVote += rating.getVote() * reputation.getAverageVote(); balancedNbVotes += reputation.getAverageVote(); } } } else { totalVote += rating.getVote(); balancedNbVotes++; } nbVotes++; } if (balancedNbVotes != 0) { averageVote = totalVote / balancedNbVotes; } return new MemoryAverageRating(documentRef, nbVotes, averageVote, method); } @Override public void updateAverageRating(DocumentReference documentRef, Rating rating, int oldVote, String method) throws RatingsException { // we only update if we are in stored mode and if the vote changed if (isAverageRatingStored(documentRef) && oldVote != rating.getVote()) { AverageRating aRating = calcAverageRating(documentRef, method); AverageRating averageRating = getAverageRating(documentRef, method, true); averageRating.setAverageVote(aRating.getAverageVote()); averageRating.setNbVotes(aRating.getNbVotes()); averageRating.save(); /* * StoredAverageRating averageRating = (StoredAverageRating) getAverageRating(container, method, true, * context); int diffTotal = rating.getVote() - oldVote; int diffNbVotes = (oldVote==0) ? 1 : 0; int * oldNbVotes = averageRating.getNbVotes(); averageRating.setNbVotes(oldNbVotes + diffNbVotes); * averageRating.setAverageVote((averageRating.getAverageVote()*oldNbVotes + diffTotal) / (oldNbVotes + * diffNbVotes)); */ } } @Override public void updateUserReputation(DocumentReference author, AverageRating voterRating) throws RatingsException { try { // We should update the user rating AverageRating rating = getAverageRating(author, voterRating.getMethod(), true); rating.setAverageVote(voterRating.getAverageVote()); rating.setMethod(voterRating.getMethod()); rating.setNbVotes(voterRating.getNbVotes()); rating.save(); } catch (XWikiException e) { throw new RatingsException(e); } } @Override public AverageRating getAverageRating(DocumentReference documentRef, String method) throws RatingsException { return getAverageRating(documentRef, method, false); } @Override public AverageRating getAverageRating(DocumentReference documentRef, String method, boolean create) throws RatingsException { try { if (isAverageRatingStored(documentRef)) { String className = getAverageRatingsClassName(); XWikiDocument doc = getXWikiContext().getWiki().getDocument(documentRef, getXWikiContext()); BaseObject averageRatingObject = doc.getObject(className, RatingsManager.AVERAGERATING_CLASS_FIELDNAME_AVERAGEVOTE_METHOD, method, false); if (averageRatingObject == null) { if (!create) { return calcAverageRating(documentRef, method); } // initiate a new average rating object averageRatingObject = doc.newObject(className, getXWikiContext()); averageRatingObject.setStringValue(RatingsManager.AVERAGERATING_CLASS_FIELDNAME_AVERAGEVOTE_METHOD, method); } return new StoredAverageRating(doc, averageRatingObject, getXWikiContext()); } else { return calcAverageRating(documentRef, method); } } catch (XWikiException e) { throw new RatingsException(e); } } }