ru.org.linux.topic.TopicController.java Source code

Java tutorial

Introduction

Here is the source code for ru.org.linux.topic.TopicController.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.topic;

import com.google.common.collect.ImmutableSet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView;
import ru.org.linux.auth.AccessViolationException;
import ru.org.linux.auth.AuthUtil;
import ru.org.linux.auth.IPBlockDao;
import ru.org.linux.auth.IPBlockInfo;
import ru.org.linux.comment.*;
import ru.org.linux.group.Group;
import ru.org.linux.paginator.PagesInfo;
import ru.org.linux.section.Section;
import ru.org.linux.section.SectionScrollModeEnum;
import ru.org.linux.section.SectionService;
import ru.org.linux.site.BadInputException;
import ru.org.linux.site.MessageNotFoundException;
import ru.org.linux.site.Template;
import ru.org.linux.spring.Configuration;
import ru.org.linux.user.IgnoreListDao;
import ru.org.linux.user.ProfileProperties;
import ru.org.linux.user.User;
import ru.org.linux.util.LorURL;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

@Controller
public class TopicController {
    public static final int RSS_DEFAULT = 20;
    @Autowired
    private SectionService sectionService;

    @Autowired
    private TopicDao messageDao;

    @Autowired
    private CommentPrepareService prepareService;

    @Autowired
    private TopicPrepareService messagePrepareService;

    @Autowired
    private CommentService commentService;

    @Autowired
    private IgnoreListDao ignoreListDao;

    @Autowired
    private Configuration configuration;

    @Autowired
    private IPBlockDao ipBlockDao;

    @Autowired
    private TopicPermissionService permissionService;

    @RequestMapping("/{section:(?:forum)|(?:news)|(?:polls)|(?:gallery)}/{group}/{id}")
    public ModelAndView getMessageNewMain(WebRequest webRequest, HttpServletRequest request,
            HttpServletResponse response, @RequestParam(value = "filter", required = false) String filter,
            @RequestParam(value = "cid", required = false) Integer cid, @PathVariable("section") String sectionName,
            @PathVariable("group") String groupName, @PathVariable("id") int msgid) throws Exception {
        if (cid != null) {
            return jumpMessage(request, msgid, cid);
        }

        Section section = sectionService.getSectionByName(sectionName);

        return getMessageNew(section, webRequest, request, response, 0, filter, groupName, msgid);
    }

    @RequestMapping("/{section:(?:forum)|(?:news)|(?:polls)|(?:gallery)}/{group}/{id}/page{page}")
    public ModelAndView getMessageNewPage(WebRequest webRequest, HttpServletRequest request,
            HttpServletResponse response, @RequestParam(value = "filter", required = false) String filter,
            @PathVariable("section") String sectionName, @PathVariable("group") String groupName,
            @PathVariable("id") int msgid, @PathVariable("page") int page) throws Exception {
        Section section = sectionService.getSectionByName(sectionName);

        return getMessageNew(section, webRequest, request, response, page, filter, groupName, msgid);
    }

    private static int getDefaultFilter(ProfileProperties prof, boolean emptyIgnoreList) {
        int filterMode = CommentFilter.FILTER_IGNORED;

        if (!prof.isShowAnonymous()) {
            filterMode += CommentFilter.FILTER_ANONYMOUS;
        }

        if (emptyIgnoreList) {
            filterMode &= ~CommentFilter.FILTER_IGNORED;
        }

        return filterMode;
    }

    private static PagesInfo buildPages(Topic topic, int messagesPerPage, int filterMode, int defaultFilterMode,
            int currentPage) {
        TopicLinkBuilder base = TopicLinkBuilder.baseLink(topic).lastmod(messagesPerPage);

        if (filterMode != defaultFilterMode) {
            base = base.filter(filterMode);
        }

        List<String> out = new ArrayList<>();

        for (int i = 0; i < topic.getPageCount(messagesPerPage); i++) {
            out.add(base.page(i).build());
        }

        return new PagesInfo(out, currentPage);
    }

    private ModelAndView getMessageNew(Section section, WebRequest webRequest, HttpServletRequest request,
            HttpServletResponse response, int page, String filter, String groupName, int msgid) throws Exception {
        Topic topic = messageDao.getById(msgid);
        Template tmpl = Template.getTemplate(request);

        PreparedTopic preparedMessage = messagePrepareService.prepareTopic(topic, request.isSecure(),
                tmpl.getCurrentUser());
        Group group = preparedMessage.getGroup();

        if (!group.getUrlName().equals(groupName) || group.getSectionId() != section.getId()) {
            return new ModelAndView(new RedirectView(topic.getLink()));
        }

        Map<String, Object> params = new HashMap<>();

        boolean showDeleted = request.getParameter("deleted") != null;
        if (showDeleted) {
            page = -1;
        }

        boolean rss = request.getParameter("output") != null && "rss".equals(request.getParameter("output"));

        if (rss && topic.isExpired()) {
            throw new MessageNotFoundException(topic.getId(), "no more comments");
        }

        if (!tmpl.isModeratorSession()) {
            if (showDeleted && !"POST".equals(request.getMethod())) {
                return new ModelAndView(new RedirectView(topic.getLink()));
            }
        }

        if (page == -1 && !tmpl.isSessionAuthorized()) {
            return new ModelAndView(new RedirectView(topic.getLink()));
        }

        int pages = topic.getPageCount(tmpl.getProf().getMessages());

        if (page >= pages && (page > 0 || pages > 0)) {
            if (pages == 0) {
                return new ModelAndView(new RedirectView(topic.getLink()));
            } else {
                return new ModelAndView(new RedirectView(topic.getLinkPage(pages - 1)));
            }
        }

        if (showDeleted) {
            if (!tmpl.isSessionAuthorized()) {
                throw new BadInputException("    ??");
            }
        }

        params.put("showDeleted", showDeleted);

        User currentUser = AuthUtil.getCurrentUser();

        if (topic.isExpired() && showDeleted && !tmpl.isModeratorSession()) {
            throw new MessageNotFoundException(topic.getId(),
                    "? ?    ? ");
        }

        permissionService.checkView(topic, currentUser);

        if (group.getCommentsRestriction() == -1 && !tmpl.isSessionAuthorized()) {
            throw new AccessViolationException(" ? ? ?");
        }

        params.put("message", topic);
        params.put("preparedMessage", preparedMessage);

        if (topic.isExpired()) {
            response.setDateHeader("Expires", System.currentTimeMillis() + 30 * 24 * 60 * 60 * 1000L);
        }

        CommentList comments = commentService.getCommentList(topic, showDeleted);

        if (!rss) {
            params.put("page", page);
            params.put("group", group);
            params.put("showAdsense", !tmpl.isSessionAuthorized() || !tmpl.getProf().isHideAdsense());

            if (!tmpl.isSessionAuthorized()) { // because users have IgnoreList and memories
                String etag = getEtag(topic, tmpl);
                response.setHeader("Etag", etag);

                if (request.getHeader("If-None-Match") != null) {
                    if (etag.equals(request.getHeader("If-None-Match"))) {
                        response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                        return null;
                    }
                } else if (checkLastModified(webRequest, topic)) {
                    return null;
                }
            }

            params.put("messageMenu", messagePrepareService.getTopicMenu(preparedMessage, currentUser,
                    request.isSecure(), tmpl.getProf(), true));

            Set<Integer> ignoreList;

            if (currentUser != null) {
                ignoreList = ignoreListDao.get(currentUser);
            } else {
                ignoreList = ImmutableSet.of();
            }

            int defaultFilterMode = getDefaultFilter(tmpl.getProf(), ignoreList.isEmpty());
            int filterMode;

            if (filter != null) {
                filterMode = CommentFilter.parseFilterChain(filter);

                if (!ignoreList.isEmpty() && filterMode == CommentFilter.FILTER_ANONYMOUS) {
                    filterMode += CommentFilter.FILTER_IGNORED;
                }
            } else {
                filterMode = defaultFilterMode;
            }

            params.put("filterMode", CommentFilter.toString(filterMode));
            params.put("defaultFilterMode", CommentFilter.toString(defaultFilterMode));

            loadTopicScroller(params, topic, currentUser, !ignoreList.isEmpty());

            Set<Integer> hideSet = commentService.makeHideSet(comments, filterMode, ignoreList);

            CommentFilter cv = new CommentFilter(comments);

            boolean reverse = tmpl.getProf().isShowNewFirst();

            List<Comment> commentsFiltred = cv.getCommentsForPage(reverse, page, tmpl.getProf().getMessages(),
                    hideSet);
            List<Comment> commentsFull = cv.getCommentsForPage(reverse, page, tmpl.getProf().getMessages(),
                    ImmutableSet.<Integer>of());

            params.put("unfilteredCount", commentsFull.size());

            List<PreparedComment> commentsPrepared = prepareService.prepareCommentList(comments, commentsFiltred,
                    request.isSecure(), tmpl, topic);

            params.put("commentsPrepared", commentsPrepared);

            IPBlockInfo ipBlockInfo = ipBlockDao.getBlockInfo(request.getRemoteAddr());
            params.put("ipBlockInfo", ipBlockInfo);

            if (pages > 1 && !showDeleted) {
                params.put("pages",
                        buildPages(topic, tmpl.getProf().getMessages(), filterMode, defaultFilterMode, page));
            }
        } else {
            CommentFilter cv = new CommentFilter(comments);

            List<Comment> commentsFiltred = cv.getCommentsForPage(true, 0, RSS_DEFAULT, ImmutableSet.<Integer>of());

            List<PreparedRSSComment> commentsPrepared = prepareService.prepareCommentListRSS(commentsFiltred,
                    request.isSecure());

            params.put("commentsPrepared", commentsPrepared);
            LorURL lorURL = new LorURL(configuration.getMainURI(), configuration.getMainUrl());
            params.put("mainURL", lorURL.fixScheme(request.isSecure()));
        }

        return new ModelAndView(rss ? "view-message-rss" : "view-message", params);
    }

    private void loadTopicScroller(Map<String, Object> params, Topic topic, User currentUser,
            boolean useIgnoreList) {
        Topic prevMessage;
        Topic nextMessage;

        if (useIgnoreList) {
            prevMessage = messageDao.getPreviousMessage(topic, currentUser);
            nextMessage = messageDao.getNextMessage(topic, currentUser);
        } else {
            prevMessage = messageDao.getPreviousMessage(topic, null);
            nextMessage = messageDao.getNextMessage(topic, null);
        }

        params.put("prevMessage", prevMessage);
        params.put("nextMessage", nextMessage);

        Boolean topScroller;
        SectionScrollModeEnum sectionScroller = sectionService.getScrollMode(topic.getSectionId());

        if (prevMessage == null && nextMessage == null) {
            topScroller = false;
        } else {
            topScroller = sectionScroller != SectionScrollModeEnum.NO_SCROLL;
        }
        params.put("topScroller", topScroller);

        Boolean bottomScroller = sectionScroller != SectionScrollModeEnum.NO_SCROLL;
        params.put("bottomScroller", bottomScroller);
    }

    /**
     * ? ? ? ?? /view-message.jsp
     * @param msgid id 
     * @param page ? 
     * @param lastmod  ? ??
     * @param filter 
     * @param output ?
     * @return     
     * @throws Exception ? ??
     */
    @RequestMapping("/view-message.jsp")
    public ModelAndView getMessageOld(@RequestParam("msgid") int msgid,
            @RequestParam(value = "page", required = false) Integer page,
            @RequestParam(value = "lastmod", required = false) Long lastmod,
            @RequestParam(value = "filter", required = false) String filter,
            @RequestParam(required = false) String output) throws Exception {
        Topic topic = messageDao.getById(msgid);

        StringBuilder link = new StringBuilder(topic.getLink());

        StringBuilder params = new StringBuilder();

        if (page != null) {
            link.append("/page").append(page);
        }

        if (lastmod != null && !topic.isExpired()) {
            params.append("?lastmod=").append(topic.getLastModified().getTime());
        }

        if (filter != null) {
            if (params.length() == 0) {
                params.append('?');
            } else {
                params.append('&');
            }
            params.append("filter=").append(filter);
        }

        if (output != null) {
            if (params.length() == 0) {
                params.append('?');
            } else {
                params.append('&');
            }
            params.append("output=").append(output);
        }

        link.append(params);

        return new ModelAndView(new RedirectView(link.toString()));
    }

    private static boolean checkLastModified(WebRequest webRequest, Topic message) {
        try {
            return webRequest.checkNotModified(message.getLastModified().getTime());
        } catch (IllegalArgumentException ignored) {
            return false;
        }
    }

    private static String getEtag(Topic message, Template tmpl) {
        String nick = tmpl.getNick();

        String userAddon = nick != null ? ('-' + nick) : "";

        if (!tmpl.isUsingDefaultProfile()) {
            userAddon += tmpl.getProf().getTimestamp();
        }

        return "msg-" + message.getId() + '-' + message.getLastModified().getTime() + userAddon;
    }

    private ModelAndView jumpMessage(HttpServletRequest request, int msgid, int cid) throws Exception {
        Template tmpl = Template.getTemplate(request);
        Topic topic = messageDao.getById(msgid);

        CommentList comments = commentService.getCommentList(topic, false);
        CommentNode node = comments.getNode(cid);

        boolean deleted = false;

        if (node == null && tmpl.isModeratorSession()) {
            comments = commentService.getCommentList(topic, true);
            node = comments.getNode(cid);
            deleted = true;
        }

        if (node == null) {
            throw new MessageNotFoundException(topic, cid,
                    " #" + cid + "     ??");
        }

        int pagenum = deleted ? 0 : comments.getCommentPage(node.getComment(), tmpl.getProf());

        TopicLinkBuilder redirectUrl = TopicLinkBuilder.pageLink(topic, pagenum)
                .lastmod(tmpl.getProf().getMessages()).comment(cid);

        if (deleted) {
            redirectUrl = redirectUrl.showDeleted();
        }

        if (tmpl.isSessionAuthorized() && !deleted) {
            Set<Integer> ignoreList = ignoreListDao.get(tmpl.getCurrentUser());

            Set<Integer> hideSet = commentService.makeHideSet(comments,
                    getDefaultFilter(tmpl.getProf(), ignoreList.isEmpty()), ignoreList);

            if (hideSet.contains(node.getComment().getId())) {
                redirectUrl = redirectUrl.filter(CommentFilter.FILTER_NONE);
            }
        }

        return new ModelAndView(new RedirectView(redirectUrl.build()));
    }

    @RequestMapping(value = "/jump-message.jsp", method = { RequestMethod.GET, RequestMethod.HEAD })
    public ModelAndView jumpMessage(HttpServletRequest request, @RequestParam int msgid,
            @RequestParam(required = false) Integer page, @RequestParam(required = false) Integer cid)
            throws Exception {
        if (cid != null) {
            return jumpMessage(request, msgid, cid);
        }

        Topic topic = messageDao.getById(msgid);

        TopicLinkBuilder builder;

        if (page != null) {
            builder = TopicLinkBuilder.pageLink(topic, page);
        } else {
            builder = TopicLinkBuilder.baseLink(topic);
        }

        return new ModelAndView(new RedirectView(builder.build()));
    }

    @ExceptionHandler(MessageNotFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ModelAndView handleMessageNotFoundException(MessageNotFoundException ex) {
        if (ex.getTopic() != null) {
            ModelAndView mav = new ModelAndView("errors/good-penguin");
            Topic topic = ex.getTopic();
            mav.addObject("msgTitle", ": ??  ??");
            mav.addObject("msgHeader", "    ??");

            mav.addObject("msgMessage", String.format(
                    " %d   <a href=\"%s\">%s</a>    ??",
                    ex.getId(), topic.getLink(), topic.getTitle()));
            return mav;
        } else {
            return new ModelAndView("errors/code404");
        }
    }

}