Java tutorial
/* /* * 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; } }