// // Copyright (c) 2011 Linkeos. // // This file is part of Elveos.org. // Elveos.org is free software: you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // Elveos.org 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 General Public License for // more details. // You should have received a copy of the GNU General Public License along // with Elveos.org. If not, see http://www.gnu.org/licenses/. // package com.bloatit.model; import java.util.EnumSet; import com.bloatit.common.Log; import com.bloatit.data.DaoKudosable; import com.bloatit.data.DaoKudosable.PopularityState; import com.bloatit.data.DaoMember.Role; import com.bloatit.model.lists.KudosList; import com.bloatit.model.right.Action; import com.bloatit.model.right.AuthToken; import com.bloatit.model.right.RgtKudosable; import com.bloatit.model.right.UnauthorizedOperationException; import com.bloatit.model.right.UnauthorizedOperationException.SpecialCode; public abstract class Kudosable<T extends DaoKudosable> extends UserContent<T> implements KudosableInterface { public Kudosable(final T dao) { super(dao); } /* * (non-Javadoc) * @see com.bloatit.model.KudosableInterface#canKudos() */ @Override public EnumSet<SpecialCode> canVoteUp() { return canVote(1); } /* * (non-Javadoc) * @see com.bloatit.model.KudosableInterface#canUnkudos() */ @Override public EnumSet<SpecialCode> canVoteDown() { return canVote(-1); } private final EnumSet<SpecialCode> canVote(final int sign) { final EnumSet<SpecialCode> errors = EnumSet.noneOf(SpecialCode.class); // See if we can kudos. if (!canAccess(new RgtKudosable.Kudos(), Action.WRITE)) { errors.add(SpecialCode.NOTHING_SPECIAL); } if (getDao().isPopularityLocked()) { errors.add(SpecialCode.KUDOSABLE_LOCKED); } if (!AuthToken.isAuthenticated()) { errors.add(SpecialCode.AUTHENTICATION_NEEDED); // Stop tests here: the other tests need an AuthToken return errors; } if (AuthToken.getMember().getRole() == Role.ADMIN) { // Stop here. The member is an admin. He must be able to kudos // everything. return errors; } // I cannot kudos my own content. if (getRights().isOwner()) { errors.add(SpecialCode.OWNED_BY_ME); } // Only one kudos per person if (getDao().hasKudosed(AuthToken.getMember().getDao())) { errors.add(SpecialCode.ALREADY_VOTED); } // Make sure we are in the right position final Member member = AuthToken.getMember(); final int influence = member.calculateInfluence(); if (sign == -1 && influence < ModelConfiguration.getKudosableMinKarmaToUnkudos()) { errors.add(SpecialCode.INFLUENCE_LOW_ON_VOTE_DOWN); } if (sign == 1 && influence < ModelConfiguration.getKudosableMinKarmaToKudos()) { errors.add(SpecialCode.INFLUENCE_LOW_ON_VOTE_UP); } return errors; } /* * (non-Javadoc) * @see com.bloatit.model.KudosableInterface#unkudos() */ @Override public final int voteDown() throws UnauthorizedOperationException { final int vote = vote(-1); notifyKudos(false); return vote; } /* * (non-Javadoc) * @see com.bloatit.model.KudosableInterface#kudos() */ @Override public final int voteUp() throws UnauthorizedOperationException { final int vote = vote(1); notifyKudos(true); return vote; } private int vote(final int sign) throws UnauthorizedOperationException { final EnumSet<SpecialCode> canKudos = canVote(sign); if (!canKudos.isEmpty()) { throw new UnauthorizedOperationException(canKudos.iterator().next()); } // Make sure we are in the right position final Member member = AuthToken.getMember(); final int influence = member.calculateInfluence(); if (influence > 0) { // getMember().addToKarma(sign * influence); calculateNewState(getPopularity(), getDao().addKudos(member.getDao(), DaoGetter.get(AuthToken.getAsTeam()), sign * influence)); } return influence * sign; } private void calculateNewState(final int oldPop, final int newPop) { switch (getState()) { case PENDING: if (newPop >= turnValid()) { setStateUnprotected(PopularityState.VALIDATED); getMember().addToKarma(1); notifyValid(); } else if (newPop <= turnHidden() && newPop > turnRejected()) { setStateUnprotected(PopularityState.HIDDEN); getMember().addToKarma(-1); notifyHidden(); } else if (newPop <= turnRejected()) { setStateUnprotected(PopularityState.REJECTED); getMember().addToKarma(-2); notifyRejected(); } // NO BREAK IT IS OK !! case VALIDATED: if (newPop <= turnPending()) { setStateUnprotected(PopularityState.PENDING); getMember().addToKarma(-1); notifyPending(); } else { final int oldKarma = (oldPop - turnValid()) / ModelConfiguration.getKudosableStepToGainKarma(); final int newKarma = (oldPop - turnValid()) / ModelConfiguration.getKudosableStepToGainKarma(); getMember().addToKarma(newKarma - oldKarma); } break; case HIDDEN: case REJECTED: if (newPop >= turnPending() && newPop < turnValid()) { setStateUnprotected(PopularityState.PENDING); getMember().addToKarma(2); notifyPending(); } else if (newPop >= turnValid()) { setStateUnprotected(PopularityState.VALIDATED); getMember().addToKarma(3); notifyValid(); } else if (newPop <= turnPending() && newPop > turnHidden()) { setStateUnprotected(PopularityState.HIDDEN); getMember().addToKarma(1); notifyValid(); } break; default: assert false; break; } } private void setStateUnprotected(final PopularityState newState) { if (getState() != newState) { Log.model().info("Kudosable: " + getId() + " change from state: " + this.getState() + ", to: " + newState); } getDao().setState(newState); } public void setState(final PopularityState newState) throws UnauthorizedOperationException { if (!getRights().hasAdminUserPrivilege()) { throw new UnauthorizedOperationException(SpecialCode.ADMIN_ONLY); } setStateUnprotected(newState); } @Override protected void delete(final boolean delOrder) throws UnauthorizedOperationException { for (final Kudos kudos : getKudos()) { kudos.delete(delOrder); } super.delete(delOrder); } private KudosList getKudos() { return new KudosList(getDao().getKudos()); } @Override public void lockPopularity() throws UnauthorizedOperationException { if (!getRights().hasAdminUserPrivilege()) { throw new UnauthorizedOperationException(SpecialCode.ADMIN_ONLY); } getDao().lockPopularity(); } @Override public void unlockPopularity() throws UnauthorizedOperationException { if (!getRights().hasAdminUserPrivilege()) { throw new UnauthorizedOperationException(SpecialCode.ADMIN_ONLY); } getDao().unlockPopularity(); } @Override public final PopularityState getState() { return getDao().getState(); } @Override public boolean isPopularityLocked() throws UnauthorizedOperationException { return getDao().isPopularityLocked(); } @Override public final int getPopularity() { return getDao().getPopularity(); } @Override public int getUserVoteValue() { if (!AuthToken.isAuthenticated()) { return 0; } return getDao().getVote(AuthToken.getMember().getDao()); } /** * You can redefine me if you want to customize the state calculation * limits. * * @return The popularity to for a Kudosable to reach to turn to * {@link PopularityState#PENDING} state. */ protected int turnPending() { return ModelConfiguration.getKudosableDefaultTurnPending(); } /** * You can redefine me if you want to customize the state calculation * limits. * * @return The popularity to for a Kudosable to reach to turn to * {@link PopularityState#VALIDATED} state. */ protected int turnValid() { return ModelConfiguration.getKudosableDefaultTurnValid(); } /** * You can redefine me if you want to customize the state calculation * limits. * * @return The popularity to for a Kudosable to reach to turn to * {@link PopularityState#REJECTED} state. */ protected int turnRejected() { return ModelConfiguration.getKudosableDefaultTurnRejected(); } /** * You can redefine me if you want to customize the state calculation * limits. * * @return The popularity to for a Kudosable to reach to turn to * {@link PopularityState#HIDDEN} state. */ protected int turnHidden() { return ModelConfiguration.getKudosableDefaultTurnHidden(); } /** * This method is called each time this Kudosable is kudosed. * * @param positif true if it is a kudos false if it is an unKudos. */ protected void notifyKudos(final boolean positif) { // Implement me if you wish } /** * This method is called each time this Kudosable change its state to valid. */ protected void notifyValid() { // Implement me if you wish } /** * This method is called each time this Kudosable change its state to * pending. */ protected void notifyPending() { // Implement me if you wish } /** * This method is called each time this Kudosable change its state to * rejected. */ protected void notifyRejected() { // Implement me if you wish } /** * This method is called each time this Kudosable change its state to * Hidden. */ private void notifyHidden() { // Implement me if you wish } }