package io.kaif.service.impl;
import java.time.Instant;
import java.util.List;
import javax.annotation.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.google.common.base.Preconditions;
import io.kaif.flake.FlakeId;
import io.kaif.model.account.AccountDao;
import io.kaif.model.account.Authorization;
import io.kaif.model.article.Article;
import io.kaif.model.article.ArticleDao;
import io.kaif.model.debate.Debate;
import io.kaif.model.debate.DebateDao;
import io.kaif.model.vote.ArticleVoter;
import io.kaif.model.vote.DebateVoter;
import io.kaif.model.vote.HonorRollDao;
import io.kaif.model.vote.HonorRollVoter;
import io.kaif.model.vote.VoteDao;
import io.kaif.model.vote.VoteState;
import io.kaif.model.zone.Zone;
import io.kaif.model.zone.ZoneDao;
import io.kaif.model.zone.ZoneInfo;
import io.kaif.service.VoteService;
import io.kaif.web.support.AccessDeniedException;
@Service
@Transactional
public class VoteServiceImpl implements VoteService {
@Autowired
private ArticleDao articleDao;
@Autowired
private VoteDao voteDao;
@Autowired
private ZoneDao zoneDao;
@Autowired
private DebateDao debateDao;
@Autowired
private AccountDao accountDao;
@Autowired
private HonorRollDao honorRollDao;
private ZoneInfo checkVoteAuthority(Zone zone, Authorization authorization) {
// relax verification when voting, no check zone and account in Database because voting
// is not critical
ZoneInfo zoneInfo = zoneDao.loadZoneWithCache(zone);
if (!zoneInfo.canUpVote(authorization)) {
throw new AccessDeniedException("not allow vote in zone: " + zone + " auth:" + authorization);
}
return zoneInfo;
}
@Override
public List<DebateVoter> listDebateVoters(Authorization voter, FlakeId articleId) {
return voteDao.listDebateVotersByArticle(voter.authenticatedId(), articleId);
}
@Override
public void voteArticle(VoteState newState,
FlakeId articleId,
Authorization authorization,
VoteState previousState,
long previousCount) {
//no support down vote yet
Preconditions.checkArgument(newState != VoteState.DOWN);
// note that cached article may have stale data (such as not yet change total vote yet),
// despite above code already change it.
Article cachedArticle = articleDao.loadArticleWithCache(articleId);
ZoneInfo zoneInfo = checkVoteAuthority(cachedArticle.getZone(), authorization);
voteDao.voteArticle(newState,
articleId,
authorization.authenticatedId(),
previousState,
previousCount,
Instant.now());
int upVoteDelta = newState.upVoteDeltaFrom(previousState);
int downVoteDelta = newState.downVoteDeltaFrom(previousState);
articleDao.changeTotalVote(articleId, upVoteDelta, downVoteDelta);
if (zoneInfo.canContributeVoteStats() && !authorization.authenticatedId()
.equals(cachedArticle.getAuthorId())) {
accountDao.changeTotalVotedArticle(cachedArticle.getAuthorId(), upVoteDelta, downVoteDelta);
honorRollDao.updateRotateVoteStats(HonorRollVoter.createByVote(cachedArticle,
upVoteDelta,
downVoteDelta));
}
}
@Override
public void voteDebate(VoteState newState,
FlakeId debateId,
Authorization voter,
VoteState previousState,
long previousCount) {
// note: cached debate may have stale data, such total vote not change yet
Debate cachedDebate = debateDao.loadDebateWithCache(debateId);
ZoneInfo zoneInfo = checkVoteAuthority(cachedDebate.getZone(), voter);
voteDao.voteDebate(newState,
cachedDebate.getArticleId(),
debateId,
voter.authenticatedId(),
previousState,
previousCount,
Instant.now());
int upVoteDelta = newState.upVoteDeltaFrom(previousState);
int downVoteDelta = newState.downVoteDeltaFrom(previousState);
debateDao.changeTotalVote(debateId, upVoteDelta, downVoteDelta);
// total debate vote score only count citizen zone. (tourist zone like /z/test
// or kVoting will not count)
if (zoneInfo.canContributeVoteStats() && !voter.authenticatedId()
.equals(cachedDebate.getDebaterId())) {
accountDao.changeTotalVotedDebate(cachedDebate.getDebaterId(), upVoteDelta, downVoteDelta);
honorRollDao.updateRotateVoteStats(HonorRollVoter.createByVote(cachedDebate,
upVoteDelta,
downVoteDelta));
}
}
@Override
public List<ArticleVoter> listArticleVoters(Authorization voter, List<FlakeId> articleIds) {
return voteDao.listArticleVoters(voter.authenticatedId(), articleIds);
}
@Override
public List<DebateVoter> listDebateVotersByIds(Authorization voter, List<FlakeId> debateIds) {
return voteDao.listDebateVotersByIds(voter.authenticatedId(), debateIds);
}
@Override
public List<Article> listUpVotedArticles(Authorization voter, @Nullable FlakeId startArticleId) {
return voteDao.listUpVotedArticles(voter.authenticatedId(),
startArticleId,
ArticleServiceImpl.PAGE_SIZE);
}
}