ru.org.linux.comment.CommentService.java Source code

Java tutorial

Introduction

Here is the source code for ru.org.linux.comment.CommentService.java

Source

/*
/*
 * Copyright 1998-2012 Linux.org.ru
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package ru.org.linux.comment;

import com.google.common.collect.ImmutableSet;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.Errors;
import org.springframework.web.bind.WebDataBinder;
import org.xbill.DNS.TextParseException;
import ru.org.linux.auth.CaptchaService;
import ru.org.linux.auth.FloodProtector;
import ru.org.linux.auth.IPBlockDao;
import ru.org.linux.auth.IPBlockInfo;
import ru.org.linux.csrf.CSRFProtectionService;
import ru.org.linux.edithistory.EditHistoryDto;
import ru.org.linux.edithistory.EditHistoryObjectTypeEnum;
import ru.org.linux.edithistory.EditHistoryService;
import ru.org.linux.site.MemCachedSettings;
import ru.org.linux.site.MessageNotFoundException;
import ru.org.linux.site.ScriptErrorException;
import ru.org.linux.site.Template;
import ru.org.linux.spring.commons.CacheProvider;
import ru.org.linux.spring.dao.MessageText;
import ru.org.linux.spring.dao.MsgbaseDao;
import ru.org.linux.topic.Topic;
import ru.org.linux.topic.TopicDao;
import ru.org.linux.user.*;
import ru.org.linux.util.ExceptionBindingErrorProcessor;
import ru.org.linux.util.StringUtil;
import ru.org.linux.util.bbcode.LorCodeService;
import ru.org.linux.util.formatter.ToLorCodeFormatter;
import ru.org.linux.util.formatter.ToLorCodeTexFormatter;

import javax.annotation.Nonnull;
import javax.servlet.http.HttpServletRequest;
import java.beans.PropertyEditorSupport;
import java.net.UnknownHostException;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Service
public class CommentService {
    private static final Log logger = LogFactory.getLog(CommentService.class);

    @Autowired
    private CommentDao commentDao;

    @Autowired
    private TopicDao messageDao;

    @Autowired
    private UserDao userDao;

    @Autowired
    private ToLorCodeFormatter toLorCodeFormatter;

    @Autowired
    private ToLorCodeTexFormatter toLorCodeTexFormatter;

    @Autowired
    private CaptchaService captcha;

    @Autowired
    private CommentPrepareService commentPrepareService;

    @Autowired
    private FloodProtector floodProtector;

    @Autowired
    private LorCodeService lorCodeService;

    @Autowired
    private UserEventService userEventService;

    @Autowired
    private MsgbaseDao msgbaseDao;

    @Autowired
    private IgnoreListDao ignoreListDao;

    @Autowired
    private EditHistoryService editHistoryService;

    @Autowired
    private TopicDao topicDao;

    public void requestValidator(WebDataBinder binder) {
        binder.setValidator(new CommentRequestValidator());
        binder.setBindingErrorProcessor(new ExceptionBindingErrorProcessor());
    }

    public void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(Topic.class, new PropertyEditorSupport() {
            @Override
            public void setAsText(String text) throws IllegalArgumentException {
                try {
                    setValue(messageDao.getById(Integer.parseInt(text.split(",")[0])));
                } catch (MessageNotFoundException e) {
                    throw new IllegalArgumentException(e);
                }
            }
        });

        binder.registerCustomEditor(Comment.class, new PropertyEditorSupport() {
            @Override
            public void setAsText(String text) throws IllegalArgumentException {
                if (text.isEmpty() || "0".equals(text)) {
                    setValue(null);
                    return;
                }

                try {
                    setValue(commentDao.getById(Integer.parseInt(text)));
                } catch (MessageNotFoundException e) {
                    throw new IllegalArgumentException(e);
                }
            }
        });

        binder.registerCustomEditor(User.class, new UserPropertyEditor(userDao));
    }

    /**
     *  ?  ?.
     *
     * @param commentRequest  WEB-, ?? 
     * @param user            , ?  ? 
     * @param ipBlockInfo     ?  
     * @param request          ?  web-
     * @param errors             ? 
     * @throws UnknownHostException
     * @throws TextParseException
     */
    public void checkPostData(CommentRequest commentRequest, User user, IPBlockInfo ipBlockInfo,
            HttpServletRequest request, Errors errors) throws UnknownHostException, TextParseException {
        if (commentRequest.getMsg() == null) {
            errors.rejectValue("msg", null, "  ");
            commentRequest.setMsg("");
        }

        Template tmpl = Template.getTemplate(request);

        if (commentRequest.getMode() == null) {
            commentRequest.setMode(tmpl.getFormatMode());
        }

        if (!commentRequest.isPreviewMode() && (!tmpl.isSessionAuthorized() || ipBlockInfo.isCaptchaRequired())) {
            captcha.checkCaptcha(request, errors);
        }

        if (!commentRequest.isPreviewMode() && !errors.hasErrors()) {
            CSRFProtectionService.checkCSRF(request, errors);
        }

        user.checkBlocked(errors);

        IPBlockDao.checkBlockIP(ipBlockInfo, errors, user);

        if (!commentRequest.isPreviewMode() && !errors.hasErrors()) {
            floodProtector.checkDuplication(request.getRemoteAddr(), user.getScore() > 100, errors);
        }
    }

    /**
     *  ? ?.
     *
     * @param commentRequest  WEB-, ?? 
     * @param user            , ?  ? 
     * @param errors             ? 
     * @return ? ?
     */
    public String getCommentBody(CommentRequest commentRequest, User user, Errors errors) {
        String commentBody = processMessage(commentRequest.getMsg(), commentRequest.getMode());
        if (user.isAnonymous()) {
            if (commentBody.length() > 4096) {
                errors.rejectValue("msg", null, "  ?");
            }
        } else {
            if (commentBody.length() > 8192) {
                errors.rejectValue("msg", null, "  ?");
            }
        }
        return commentBody;
    }

    /**
     *   ?  WEB-?.
     *
     * @param commentRequest  WEB-, ?? 
     * @param user            , ?  ? 
     * @param request          ?  web-
     * @return  ?  WEB-?
     */
    public Comment getComment(CommentRequest commentRequest, User user, HttpServletRequest request) {
        Comment comment = null;

        if (commentRequest.getTopic() != null) {

            String title = commentRequest.getTitle();

            if (title == null) {
                title = "";
            }

            Integer replyto = commentRequest.getReplyto() != null ? commentRequest.getReplyto().getId() : null;

            int commentId = commentRequest.getOriginal() == null ? 0 : commentRequest.getOriginal().getId();

            comment = new Comment(replyto, StringUtil.escapeHtml(title), commentRequest.getTopic().getId(),
                    commentId, user.getId(), request.getHeader("user-agent"), request.getRemoteAddr());
        }
        return comment;
    }

    /**
     *   ?, ?  ? 
     *
     * @param commentRequest  WEB-, ?? 
     * @param request          ?  web-
     * @param errors             ? 
     * @return  ?
     */
    @Nonnull
    public User getCommentUser(CommentRequest commentRequest, HttpServletRequest request, Errors errors) {
        Template tmpl = Template.getTemplate(request);

        User currentUser = tmpl.getCurrentUser();

        if (currentUser != null) {
            return currentUser;
        }

        if (commentRequest.getNick() != null) {
            if (commentRequest.getPassword() == null) {
                errors.reject(null, "?? ?");
            }

            return commentRequest.getNick();
        } else {
            return userDao.getAnonymous();
        }
    }

    public void prepareReplyto(CommentRequest add, Map<String, Object> formParams, HttpServletRequest request)
            throws UserNotFoundException {
        if (add.getReplyto() != null) {
            formParams.put("onComment",
                    commentPrepareService.prepareCommentForReplayto(add.getReplyto(), request.isSecure()));
        }
    }

    /**
     *   ?.
     *
     * @param comment         ?
     * @param commentBody    ? ?
     * @param remoteAddress  IP-?, ?    
     * @param xForwardedFor  IP-?  , ?    
     * @return    ?
     * @throws MessageNotFoundException
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public int create(Comment comment, String commentBody, String remoteAddress, String xForwardedFor)
            throws MessageNotFoundException {

        int commentId = commentDao.saveNewMessage(comment, commentBody);

        /* ?  */
        Set<User> userRefs = lorCodeService.getReplierFromMessage(commentBody);
        userEventService.addUserRefEvent(userRefs.toArray(new User[userRefs.size()]), comment.getTopicId(),
                commentId);

        /*      */
        if (comment.getReplyTo() != 0) {
            try {
                Comment parentComment = commentDao.getById(comment.getReplyTo());

                if (parentComment.getUserid() != comment.getUserid()) {
                    User parentAuthor = userDao.getUserCached(parentComment.getUserid());

                    if (!parentAuthor.isAnonymous()) {
                        Set<Integer> ignoreList = ignoreListDao.get(parentAuthor);

                        if (!ignoreList.contains(comment.getUserid())) {
                            userEventService.addReplyEvent(parentAuthor, comment.getTopicId(), commentId);
                        }
                    }
                }
            } catch (UserNotFoundException e) {
                throw new RuntimeException(e);
            }
        }

        String logMessage = makeLogString("??  " + commentId, remoteAddress,
                xForwardedFor);
        logger.info(logMessage);

        return commentId;
    }

    /**
     *  ?.
     *
     * @param oldComment      ? ?
     * @param newComment       ?
     * @param commentBody    ?  ?
     * @param remoteAddress  IP-?, ?    
     * @param xForwardedFor  IP-?  , ?    
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void edit(Comment oldComment, Comment newComment, String commentBody, String remoteAddress,
            String xForwardedFor) {
        commentDao.edit(oldComment, newComment, commentBody);

        /* ?  */
        Set<User> newUserRefs = lorCodeService.getReplierFromMessage(commentBody);

        MessageText messageText = msgbaseDao.getMessageText(oldComment.getId());
        Set<User> oldUserRefs = lorCodeService.getReplierFromMessage(messageText.getText());
        Set<User> userRefs = new HashSet<User>();
        /* ?  ,  ??. ?   ??? */
        for (User user : newUserRefs) {
            if (!oldUserRefs.contains(user)) {
                userRefs.add(user);
            }
        }

        userEventService.addUserRefEvent(userRefs.toArray(new User[userRefs.size()]), oldComment.getTopicId(),
                oldComment.getId());

        /*   ? ?  ? ,     ? ?  */
        topicDao.updateLastModifiedToCurrentTime(oldComment.getTopicId());

        String logMessage = makeLogString("  " + oldComment.getId(),
                remoteAddress, xForwardedFor);
        logger.info(logMessage);

    }

    /**
     * ,     .
     *
     * @param comment   ?
     * @return true ? ? ,  false
     */
    public boolean isHaveAnswers(Comment comment) {
        return commentDao.isHaveAnswers(comment.getId());
    }

    /**
     *   ?   
     *
     * @param id   ?
     * @return  ?
     * @throws MessageNotFoundException ?   
     */
    public Comment getById(int id) throws MessageNotFoundException {
        return commentDao.getById(id);
    }

    /**
     *  ? ? ? ?.
     *
     * @param editor              ,  
     * @param original             (? )
     * @param originalMessageText ? ? ?
     * @param comment              
     * @param messageText          ? ?
     */
    public void addEditHistoryItem(User editor, Comment original, String originalMessageText, Comment comment,
            String messageText) {

        EditHistoryDto editHistoryDto = new EditHistoryDto();
        editHistoryDto.setMsgid(original.getId());
        editHistoryDto.setObjectType(EditHistoryObjectTypeEnum.COMMENT);
        editHistoryDto.setEditor(editor.getId());

        boolean modified = false;
        if (!original.getTitle().equals(comment.getTitle())) {
            editHistoryDto.setOldtitle(original.getTitle());
            modified = true;
        }

        if (!originalMessageText.equals(messageText)) {
            editHistoryDto.setOldmessage(originalMessageText);
            modified = true;
        }

        if (modified) {
            editHistoryService.insert(editHistoryDto);
        }

    }

    /**
     *    ?  .
     *
     * @param editor   ,  
     * @param original  (? )
     * @param comment   
     */
    public void updateLatestEditorInfo(User editor, Comment original, Comment comment) {
        List<EditHistoryDto> editHistoryDtoList = editHistoryService.getEditInfo(original.getId(),
                EditHistoryObjectTypeEnum.COMMENT);

        commentDao.updateLatestEditorInfo(original.getId(), editor.getId(), comment.getPostdate(),
                editHistoryDtoList.size());
    }

    /**
     * ? , ?   ?  -  ?
     *
     * @param msgid      id ? ??
     * @param reason      ?
     * @param user         ?
     * @param scoreBonus -  
     * @throws ScriptErrorException  ? ?   ? 
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public boolean deleteComment(int msgid, String reason, User user, int scoreBonus) throws ScriptErrorException {

        if (commentDao.getReplaysCount(msgid) != 0) {
            throw new ScriptErrorException(
                    "??   ? ");
        }

        boolean deleted = commentDao.deleteComment(msgid, reason, user, scoreBonus);

        if (deleted) {
            commentDao.updateStatsAfterDelete(msgid, 1);
        }

        return deleted;
    }

    /**
     * ?  .
     *
     * @param topicId     id 
     * @param showDeleted ? ? 
     * @return ??  
     */
    private List<Comment> getCommentList(int topicId, boolean showDeleted) {
        return commentDao.getCommentList(topicId, showDeleted);
    }

    /**
     * ?  .
     *
     * @param topic       
     * @param showDeleted ? ? 
     * @return ??  
     */
    @Nonnull
    public CommentList getCommentList(@Nonnull Topic topic, boolean showDeleted) {
        if (showDeleted) {
            return new CommentList(getCommentList(topic.getId(), showDeleted), topic.getLastModified().getTime());
        } else {
            CacheProvider mcc = MemCachedSettings.getCache();

            String cacheId = "commentList?msgid=" + topic.getId();

            CommentList commentList = (CommentList) mcc.getFromCache(cacheId);

            if (commentList == null || commentList.getLastmod() != topic.getLastModified().getTime()) {
                commentList = new CommentList(getCommentList(topic.getId(), showDeleted),
                        topic.getLastModified().getTime());
                mcc.storeToCache(cacheId, commentList);
            }

            return commentList;
        }
    }

    /**
     *    .
     *
     * @param msgid    ?
     * @param user   , ? 
     * @param score  ? ?? ?   ?
     * @return ??    
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public List<Integer> deleteReplys(int msgid, User user, boolean score) {
        return commentDao.doDeleteReplys(msgid, user, score);
    }

    /**
     *  , ?  ip     ,     ??  ?
     *
     * @param ip        ip ?  ? ?? ( ???  ?)
     * @param timeDelta   ? ( ???  ?)
     * @param moderator ?-
     * @param reason     ?, ?  ? ? ? 
     * @return ?? id  ?
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public DeleteCommentResult deleteCommentsByIPAddress(String ip, Timestamp timeDelta, final User moderator,
            final String reason) {
        return commentDao.deleteCommentsByIPAddress(ip, timeDelta, moderator, reason);
    }

    /**
     *  ??  ?.
     *
     * @param user     ?
     * @param limit   ? ?    
     * @param offset  ? ?    
     * @return ??  ?
     */
    public List<CommentDao.CommentsListItem> getUserComments(User user, int limit, int offset) {
        return commentDao.getUserComments(user.getId(), limit, offset);
    }

    /**
     *  ?? ?   ?.
     *
     * @param user   ?
     * @return ??   ?
     */
    public List<CommentDao.DeletedListItem> getDeletedComments(User user) {
        return commentDao.getDeletedComments(user.getId());
    }

    /**
     *   ??  ?    ? ? ?   
     *
     * @param user       ? ?
     * @param moderator ?-
     * @param reason     
     * @return ??  
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public DeleteCommentResult deleteAllCommentsAndBlock(User user, final User moderator, String reason) {
        userDao.blockWithoutTransaction(user, moderator, reason);

        List<Integer> deletedTopicIds = messageDao.deleteAllByUser(user, moderator);

        List<Integer> deletedCommentIds = commentDao.deleteAllByUser(user, moderator);

        return new DeleteCommentResult(deletedTopicIds, deletedCommentIds, null);
    }

    /**
     *  ?  -.
     *
     * @param message        ?
     * @param remoteAddress  IP-?, ?    
     * @param xForwardedFor  IP-?  , ?    
     * @return ?, ? ? ?  -
     */
    private static String makeLogString(String message, String remoteAddress, String xForwardedFor) {
        StringBuilder logMessage = new StringBuilder();

        logMessage.append(message).append("; ip: ").append(remoteAddress);

        if (xForwardedFor != null) {
            logMessage.append(" XFF:").append(xForwardedFor);
        }

        return logMessage.toString();
    }

    /**
     *   ? ?? ? (LorCode  Tex).
     *
     * @param msg   ? ?
     * @param mode   
     * @return ? ?
     */
    private String processMessage(String msg, String mode) {
        if ("ntobr".equals(mode)) {
            return toLorCodeFormatter.format(msg, true);
        } else {
            return toLorCodeTexFormatter.format(msg);
        }
    }

    @Nonnull
    public Set<Integer> makeHideSet(CommentList comments, int filterChain, Set<Integer> ignoreList)
            throws SQLException, UserNotFoundException {
        if (filterChain == CommentFilter.FILTER_NONE) {
            return ImmutableSet.of();
        }

        Set<Integer> hideSet = new HashSet<Integer>();

        /* hide anonymous */
        if ((filterChain & CommentFilter.FILTER_ANONYMOUS) > 0) {
            comments.getRoot().hideAnonymous(userDao, hideSet);
        }

        /* hide ignored */
        if ((filterChain & CommentFilter.FILTER_IGNORED) > 0) {
            if (ignoreList != null && !ignoreList.isEmpty()) {
                comments.getRoot().hideIgnored(hideSet, ignoreList);
            }
        }

        return hideSet;
    }
}