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

Java tutorial

Introduction

Here is the source code for ru.org.linux.topic.TopicListController.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.base.Strings;
import org.apache.commons.lang.WordUtils;
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.servlet.ModelAndView;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.view.RedirectView;
import org.springframework.web.util.UriTemplate;
import ru.org.linux.group.Group;
import ru.org.linux.group.GroupDao;
import ru.org.linux.section.Section;
import ru.org.linux.section.SectionNotFoundException;
import ru.org.linux.section.SectionService;
import ru.org.linux.site.ScriptErrorException;
import ru.org.linux.site.Template;
import ru.org.linux.tag.TagService;
import ru.org.linux.user.*;
import ru.org.linux.util.*;

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

@Controller
public class TopicListController {
    private static final UriTemplate TAG_URI_TEMPLATE = new UriTemplate("/tag/{tag}");
    private static final UriTemplate TAGS_URI_TEMPLATE = new UriTemplate("/tags/{tag}");

    @Autowired
    private SectionService sectionService;

    @Autowired
    private TopicListService topicListService;

    @Autowired
    private TopicPrepareService prepareService;

    @Autowired
    private TagService tagService;

    @Autowired
    private UserTagService userTagService;

    // TODO: ?   ??,   DAO
    @Autowired
    private GroupDao groupDao;

    // TODO: ?   ??,   DAO
    @Autowired
    private UserDao userDao;

    @RequestMapping(value = "/view-news.jsp", method = { RequestMethod.GET, RequestMethod.HEAD }, params = {
            "tag" })
    public View tagFeedOld(TopicListRequest topicListForm) {
        return new RedirectView(tagListUrl(topicListForm.getTag()));
    }

    public static String tagListUrl(String tag) {
        return TAG_URI_TEMPLATE.expand(tag).toString();
    }

    public static String tagsUrl(char letter) {
        return TAGS_URI_TEMPLATE.expand(letter).toString();
    }

    @RequestMapping(value = "/tag/{tag}", method = { RequestMethod.GET, RequestMethod.HEAD })
    public ModelAndView tagFeed(HttpServletRequest request, TopicListRequest topicListForm,
            HttpServletResponse response, @PathVariable String tag) throws Exception {
        topicListForm.setTag(tag);

        ModelAndView modelAndView = mainTopicsFeedHandler(request, topicListForm, response, null);

        boolean rss = topicListForm.getOutput() != null && "rss".equals(topicListForm.getOutput());
        if (!rss) {
            modelAndView.addObject("sectionList", sectionService.getSectionList());
        }

        Template tmpl = Template.getTemplate(request);

        if (tmpl.isSessionAuthorized()) {
            modelAndView.addObject("isShowFavoriteTagButton",
                    !userTagService.hasFavoriteTag(tmpl.getCurrentUser(), topicListForm.getTag()));

            modelAndView.addObject("isShowUnFavoriteTagButton",
                    userTagService.hasFavoriteTag(tmpl.getCurrentUser(), topicListForm.getTag()));

            if (!tmpl.isModeratorSession()) {
                modelAndView.addObject("isShowIgnoreTagButton",
                        !userTagService.hasIgnoreTag(tmpl.getCurrentUser(), topicListForm.getTag()));
                modelAndView.addObject("isShowUnIgnoreTagButton",
                        userTagService.hasIgnoreTag(tmpl.getCurrentUser(), topicListForm.getTag()));
            }
        }

        modelAndView.addObject("counter", tagService.getCounter(tag));

        modelAndView.addObject("url", tagListUrl(tag));
        modelAndView.addObject("params", null);
        modelAndView.addObject("favsCount", userTagService.countFavs(tagService.getTagId(tag)));

        modelAndView.setViewName("tag-topics");

        return modelAndView;
    }

    private ModelAndView mainTopicsFeedHandler(HttpServletRequest request, TopicListRequest topicListForm,
            HttpServletResponse response, @Nullable Group group) throws Exception {
        Section section = null;
        if (topicListForm.getSection() != null && topicListForm.getSection() != 0) {
            section = sectionService.getSection(topicListForm.getSection());
        }

        checkRequestConditions(section, group, topicListForm);
        Template tmpl = Template.getTemplate(request);

        ModelAndView modelAndView = new ModelAndView("view-news");

        modelAndView.addObject("group", group);

        if (!Strings.isNullOrEmpty(topicListForm.getTag()) || topicListForm.getSection() != null) {
            URLUtil.QueryString queryString = new URLUtil.QueryString();
            queryString.add("section", topicListForm.getSection());
            modelAndView.addObject("params", queryString.toString());
        }

        modelAndView.addObject("url", "view-news.jsp");
        if (section != null) {
            modelAndView.addObject("section", section);

            if (Strings.isNullOrEmpty(topicListForm.getTag())) {
                modelAndView.addObject("archiveLink", section.getArchiveLink());
            }
        }

        setExpireHeaders(response, topicListForm);

        modelAndView.addObject("ptitle", calculatePTitle(section, group, topicListForm));
        modelAndView.addObject("navtitle", calculateNavTitle(section, group, topicListForm));

        topicListForm.setOffset(topicListService.fixOffset(topicListForm.getOffset()));

        List<Topic> messages = topicListService.getTopicsFeed(section, group, topicListForm.getTag(),
                topicListForm.getOffset(), topicListForm.getYear(), topicListForm.getMonth());

        modelAndView.addObject("messages", prepareService.prepareMessagesForUser(messages, request.isSecure(),
                tmpl.getCurrentUser(), tmpl.getProf(), false));

        modelAndView.addObject("offsetNavigation", topicListForm.getMonth() == null);

        if (section != null && Strings.isNullOrEmpty(topicListForm.getTag())) {
            String rssLink = "/section-rss.jsp?section=" + section.getId();
            if (group != null) {
                rssLink += "&group=" + group.getId();
            }

            modelAndView.addObject("rssLink", rssLink);
        }

        return modelAndView;
    }

    /**
     * @param request
     * @param topicListForm
     * @param response
     * @return
     * @throws Exception
     */
    @RequestMapping("/gallery/")
    public ModelAndView gallery(HttpServletRequest request, TopicListRequest topicListForm,
            HttpServletResponse response) throws Exception {

        topicListForm.setSection(Section.SECTION_GALLERY);
        ModelAndView modelAndView = mainTopicsFeedHandler(request, topicListForm, response, null);

        modelAndView.addObject("url", "/gallery/");
        modelAndView.addObject("params", null);

        return modelAndView;
    }

    /**
     * @param request
     * @param topicListForm
     * @param response
     * @return
     * @throws Exception
     */
    @RequestMapping("/forum/lenta")
    public ModelAndView forum(HttpServletRequest request, TopicListRequest topicListForm,
            HttpServletResponse response) throws Exception {

        topicListForm.setSection(Section.SECTION_FORUM);
        ModelAndView modelAndView = mainTopicsFeedHandler(request, topicListForm, response, null);

        modelAndView.addObject("url", "/forum/lenta");
        modelAndView.addObject("params", null);

        return modelAndView;
    }

    /**
     * @param request
     * @param topicListForm
     * @param response
     * @return
     * @throws Exception
     */
    @RequestMapping("/polls/")
    public ModelAndView polls(HttpServletRequest request, TopicListRequest topicListForm,
            HttpServletResponse response) throws Exception {
        topicListForm.setSection(Section.SECTION_POLLS);
        ModelAndView modelAndView = mainTopicsFeedHandler(request, topicListForm, response, null);

        modelAndView.addObject("url", "/polls/");
        modelAndView.addObject("params", null);

        return modelAndView;
    }

    /**
     * @param request
     * @param topicListForm
     * @param response
     * @return
     * @throws Exception
     */
    @RequestMapping("/news/")
    public ModelAndView news(HttpServletRequest request, TopicListRequest topicListForm,
            HttpServletResponse response) throws Exception {
        topicListForm.setSection(Section.SECTION_NEWS);
        ModelAndView modelAndView = mainTopicsFeedHandler(request, topicListForm, response, null);

        modelAndView.addObject("url", "/news/");
        modelAndView.addObject("params", null);

        return modelAndView;
    }

    /**
     * @param request
     * @param topicListForm
     * @param groupName
     * @param response
     * @return
     * @throws Exception
     */
    @RequestMapping("/gallery/{group}")
    public ModelAndView galleryGroup(HttpServletRequest request, TopicListRequest topicListForm,
            @PathVariable("group") String groupName, HttpServletResponse response) throws Exception {
        topicListForm.setSection(Section.SECTION_GALLERY);
        return group(request, topicListForm, groupName, response);
    }

    /**
     * @param request
     * @param topicListForm
     * @param groupName
     * @param response
     * @return
     * @throws Exception
     */
    @RequestMapping("/news/{group}")
    public ModelAndView newsGroup(HttpServletRequest request, TopicListRequest topicListForm,
            @PathVariable("group") String groupName, HttpServletResponse response) throws Exception {
        topicListForm.setSection(Section.SECTION_NEWS);
        return group(request, topicListForm, groupName, response);
    }

    /**
     * @param request
     * @param topicListForm
     * @param groupName
     * @param response
     * @return
     * @throws Exception
     */
    @RequestMapping("/polls/{group}")
    public ModelAndView pollsGroup(HttpServletRequest request, TopicListRequest topicListForm,
            @PathVariable("group") String groupName, HttpServletResponse response) throws Exception {
        topicListForm.setSection(Section.SECTION_POLLS);
        return group(request, topicListForm, groupName, response);
    }

    /**
     * @param section
     * @param year
     * @param month
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @RequestMapping("/{section}/archive/{year}/{month}")
    public ModelAndView galleryArchive(HttpServletRequest request, @PathVariable String section,
            @PathVariable int year, @PathVariable int month, HttpServletResponse response) throws Exception {
        TopicListRequest topicListForm = new TopicListRequest();

        topicListForm.setSection(Section.getSection(section));
        topicListForm.setYear(year);
        topicListForm.setMonth(month);

        ModelAndView modelAndView = mainTopicsFeedHandler(request, topicListForm, response, null);

        modelAndView.addObject("url", "/gallery/archive/" + year + '/' + month + '/');
        modelAndView.addObject("params", null);

        return modelAndView;
    }

    /**
     * @param nick
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @RequestMapping("/people/{nick}")
    public ModelAndView showUserTopicsNew(HttpServletRequest request, TopicListRequest topicListForm,
            @PathVariable String nick, HttpServletResponse response) throws Exception {
        setExpireHeaders(response, topicListForm);

        ModelAndView modelAndView = new ModelAndView();

        Section section = null;
        if (topicListForm.getSection() != null && topicListForm.getSection() != 0) {
            section = sectionService.getSection(topicListForm.getSection());
        }

        if (topicListForm.getTag() != null) {
            tagService.checkTag(topicListForm.getTag());
        }

        User user = getUserByNickname(modelAndView, nick);

        UserInfo userInfo = userDao.getUserInfoClass(user);
        modelAndView.addObject("meLink", userInfo.getUrl());

        modelAndView.addObject("url", "/people/" + nick + '/');
        modelAndView.addObject("whoisLink", "/people/" + nick + '/' + "profile");
        // TODO: modelAndView.addObject("archiveLink", "/people/"+nick+"/archive/");

        modelAndView.addObject("ptitle", "? " + user.getNick());
        modelAndView.addObject("navtitle", "? " + user.getNick());

        modelAndView.addObject("rssLink", "/people/" + nick + "/?output=rss");

        topicListForm.setOffset(topicListService.fixOffset(topicListForm.getOffset()));
        modelAndView.addObject("offsetNavigation", true);
        modelAndView.addObject("topicListForm", topicListForm);

        List<Topic> messages = topicListService.getUserTopicsFeed(user, section, null, topicListForm.getOffset(),
                false, false);

        boolean rss = topicListForm.getOutput() != null && "rss".equals(topicListForm.getOutput());
        if (!rss) {
            if (section != null) {
                modelAndView.addObject("section", section);
            }
            modelAndView.addObject("sectionList", sectionService.getSectionList());
        }

        if (Integer.valueOf(0).equals(topicListForm.getSection())) {
            topicListForm.setSection(null);
        }
        URLUtil.QueryString queryString = new URLUtil.QueryString();
        queryString.add("section", topicListForm.getSection());
        queryString.add("tag", topicListForm.getTag());
        modelAndView.addObject("params", queryString.toString());

        prepareTopicsForPlainOrRss(request, modelAndView, topicListForm, messages);

        if (!rss) {
            modelAndView.setViewName("user-topics");
        }

        return modelAndView;
    }

    /**
     * @param nick
     * @param topicListForm
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @RequestMapping("/people/{nick}/favs")
    public ModelAndView showUserFavs(HttpServletRequest request, TopicListRequest topicListForm,
            @PathVariable String nick, HttpServletResponse response) throws Exception {
        setExpireHeaders(response, topicListForm);

        ModelAndView modelAndView = new ModelAndView();

        User user = getUserByNickname(modelAndView, nick);

        modelAndView.addObject("url", "/people/" + nick + "/favs");
        modelAndView.addObject("whoisLink", "/people/" + nick + '/' + "profile");

        modelAndView.addObject("ptitle", " ?? " + user.getNick());
        modelAndView.addObject("navtitle", " ?? " + user.getNick());

        topicListForm.setOffset(topicListService.fixOffset(topicListForm.getOffset()));
        modelAndView.addObject("offsetNavigation", true);
        modelAndView.addObject("topicListForm", topicListForm);

        List<Topic> messages = topicListService.getUserTopicsFeed(user, topicListForm.getOffset(), true, false);
        prepareTopicsForPlainOrRss(request, modelAndView, topicListForm, messages);

        modelAndView.setViewName("user-topics");

        return modelAndView;
    }

    @RequestMapping("/people/{nick}/tracked")
    public ModelAndView showUserWatches(HttpServletRequest request, TopicListRequest topicListForm,
            @PathVariable String nick, HttpServletResponse response) throws Exception {
        setExpireHeaders(response, topicListForm);

        ModelAndView modelAndView = new ModelAndView();

        User user = getUserByNickname(modelAndView, nick);

        modelAndView.addObject("url", "/people/" + nick + "/tracked");
        modelAndView.addObject("whoisLink", "/people/" + nick + '/' + "profile");

        modelAndView.addObject("ptitle", "? ?? " + user.getNick());
        modelAndView.addObject("navtitle", "? ?? " + user.getNick());

        topicListForm.setOffset(topicListService.fixOffset(topicListForm.getOffset()));
        modelAndView.addObject("offsetNavigation", true);
        modelAndView.addObject("topicListForm", topicListForm);

        List<Topic> messages = topicListService.getUserTopicsFeed(user, topicListForm.getOffset(), true, true);
        prepareTopicsForPlainOrRss(request, modelAndView, topicListForm, messages);

        modelAndView.setViewName("user-topics");

        return modelAndView;
    }

    /**
     * @param nick
     * @param output
     * @return
     */
    @RequestMapping(value = "/show-topics.jsp", method = RequestMethod.GET)
    public View showUserTopics(@RequestParam("nick") String nick,
            @RequestParam(value = "output", required = false) String output) {
        if (output != null) {
            return new RedirectView("/people/" + nick + "/?output=rss");
        }

        return new RedirectView("/people/" + nick + '/');
    }

    /**
     * @param sectionId
     * @param request
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/view-all.jsp", method = { RequestMethod.GET, RequestMethod.HEAD })
    public ModelAndView viewAll(
            @RequestParam(value = "section", required = false, defaultValue = "0") int sectionId,
            HttpServletRequest request) {
        Template tmpl = Template.getTemplate(request);

        ModelAndView modelAndView = new ModelAndView("view-all");

        Section section = null;
        if (sectionId != 0) {
            section = sectionService.getSection(sectionId);
            modelAndView.addObject("section", section);
        }

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.MONTH, -1);

        List<Topic> messages = topicListService.getAllTopicsFeed(section, calendar.getTime());
        modelAndView.addObject("messages", prepareService.prepareMessagesForUser(messages, request.isSecure(),
                tmpl.getCurrentUser(), tmpl.getProf(), false));

        List<TopicListDto.DeletedTopic> deleted = topicListService.getDeletedTopicsFeed(sectionId);

        modelAndView.addObject("deletedTopics", deleted);
        modelAndView.addObject("sections", sectionService.getSectionList());

        return modelAndView;
    }

    /**
     * @param topicListForm
     * @return
     * @throws Exception
     * @deprecated
     */
    @Deprecated
    @RequestMapping(value = "/view-news.jsp", params = { "section", "!tag" })
    public View oldLink(TopicListRequest topicListForm,
            @RequestParam(value = "group", defaultValue = "0") int groupId) throws Exception {
        StringBuilder redirectLink = new StringBuilder();
        redirectLink.append(Section.getNewsViewerLink(topicListForm.getSection()));

        if (topicListForm.getYear() != null && topicListForm.getMonth() != null) {
            redirectLink.append(topicListForm.getYear()).append('/').append(topicListForm.getMonth());
        } else if (groupId > 0) {
            Group group = groupDao.getGroup(groupId);
            redirectLink.append(group.getUrlName()).append('/');
        }

        URLUtil.QueryString queryString = new URLUtil.QueryString();
        queryString.add("offset", topicListForm.getOffset());

        String queryStr = queryString.toString();
        if (!queryStr.isEmpty()) {
            redirectLink.append('?').append(queryStr);
        }

        return new RedirectView(redirectLink.toString());
    }

    @RequestMapping("/section-rss.jsp")
    public ModelAndView showRSS(HttpServletRequest request, TopicListRequest topicListForm,
            @RequestParam(value = "group", defaultValue = "0") int groupId) throws Exception {

        final String[] filterValues = { "all", "notalks", "tech" };
        final Set<String> filterValuesSet = new HashSet<String>(Arrays.asList(filterValues));

        if (topicListForm.getFilter() != null && !filterValuesSet.contains(topicListForm.getFilter())) {
            throw new UserErrorException("?  filter");
        }
        boolean notalks = topicListForm.getFilter() != null && "notalks".equals(topicListForm.getFilter());
        boolean tech = topicListForm.getFilter() != null && "tech".equals(topicListForm.getFilter());

        if (topicListForm.getSection() == null) {
            topicListForm.setSection(1);
        }

        String userAgent = request.getHeader("User-Agent");
        final boolean feedBurner = userAgent != null && userAgent.contains("FeedBurner");

        if (topicListForm.getSection() == 1 && groupId == 0 && !notalks && !tech && !feedBurner
                && request.getParameter("noredirect") == null) {
            return new ModelAndView(new RedirectView("http://feeds.feedburner.com/org/LOR"));
        }

        Section section = sectionService.getSection(topicListForm.getSection());
        String ptitle = section.getName();

        Group group = null;
        if (groupId != 0) {
            group = groupDao.getGroup(groupId);
            ptitle += " - " + group.getTitle();
        }

        checkRequestConditions(section, group, topicListForm);

        ModelAndView modelAndView = new ModelAndView("section-rss");

        modelAndView.addObject("group", group);
        modelAndView.addObject("section", section);
        modelAndView.addObject("ptitle", ptitle);

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.MONTH, -3);

        List<Topic> messages = topicListService.getRssTopicsFeed(section, group, calendar.getTime(), notalks, tech,
                feedBurner);

        modelAndView.addObject("messages", prepareService.prepareMessages(messages, request.isSecure()));
        return modelAndView;
    }

    /**
     * @param request
     * @param modelAndView
     * @param topicListForm
     * @param messages
     */
    private void prepareTopicsForPlainOrRss(HttpServletRequest request, ModelAndView modelAndView,
            TopicListRequest topicListForm, List<Topic> messages) {
        boolean rss = topicListForm.getOutput() != null && "rss".equals(topicListForm.getOutput());
        if (rss) {
            modelAndView.addObject("messages", prepareService.prepareMessages(messages, request.isSecure()));
            modelAndView.setViewName("section-rss");
        } else {
            Template tmpl = Template.getTemplate(request);
            modelAndView.addObject("messages", prepareService.prepareMessagesForUser(messages, request.isSecure(),
                    tmpl.getCurrentUser(), tmpl.getProf(), false));

            modelAndView.setViewName("view-news");
        }
    }

    /**
     * @param modelAndView
     * @param nick
     * @return
     * @throws UserNotFoundException
     * @throws UserErrorException
     */
    private User getUserByNickname(ModelAndView modelAndView, String nick)
            throws UserNotFoundException, UserErrorException {
        User user = userDao.getUser(nick);
        if (user.getId() == User.ANONYMOUS_ID) {
            throw new UserErrorException(
                    " ? ? anonymous  ?");
        }
        modelAndView.addObject("user", user);
        return user;
    }

    private ModelAndView group(HttpServletRequest request, TopicListRequest topicListForm, String groupName,
            HttpServletResponse response) throws Exception {
        Section section = sectionService.getSection(topicListForm.getSection());

        Group group = groupDao.getGroup(section, groupName);

        ModelAndView modelAndView = mainTopicsFeedHandler(request, topicListForm, response, group);

        modelAndView.addObject("url", group.getUrl());
        modelAndView.addObject("params", null);

        return modelAndView;
    }

    /**
     * @param response
     * @param topicListForm
     */
    private static void setExpireHeaders(HttpServletResponse response, TopicListRequest topicListForm) {
        if (topicListForm.getMonth() == null) {
            response.setDateHeader("Expires", System.currentTimeMillis() + 60 * 1000);
            response.setDateHeader("Last-Modified", System.currentTimeMillis());
        } else {
            long expires = System.currentTimeMillis() + 30 * 24 * 60 * 60 * 1000L;

            Calendar calendar = Calendar.getInstance();
            calendar.set(topicListForm.getYear(), topicListForm.getMonth() - 1, 1);
            calendar.add(Calendar.MONTH, 1);

            long lastmod = calendar.getTimeInMillis();

            if (lastmod < System.currentTimeMillis()) {
                response.setDateHeader("Expires", expires);
                response.setDateHeader("Last-Modified", lastmod);
            } else {
                response.setDateHeader("Expires", System.currentTimeMillis() + 60 * 1000);
                response.setDateHeader("Last-Modified", System.currentTimeMillis());
            }
        }

    }

    /**
     * @param section
     * @param group
     * @param topicListForm
     * @throws Exception
     */
    private void checkRequestConditions(Section section, Group group, TopicListRequest topicListForm)
            throws Exception {
        if (topicListForm.getMonth() != null && topicListForm.getYear() == null) {
            throw new ServletParameterMissingException("year");
        }
        if (section == null && topicListForm.getTag() == null) {
            throw new ServletParameterException("section or tag required");
        }
        if (topicListForm.getTag() != null) {
            tagService.checkTag(topicListForm.getTag());
        }
        if (section != null && group != null && group.getSectionId() != section.getId()) {
            throw new ScriptErrorException(" #" + group.getId()
                    + "    #" + section.getId());
        }
    }

    /**
     * @param section
     * @param group
     * @param topicListForm
     * @return
     * @throws BadDateException
     */
    private static String calculatePTitle(Section section, Group group, TopicListRequest topicListForm)
            throws BadDateException {
        StringBuilder ptitle = new StringBuilder();

        if (topicListForm.getMonth() == null) {
            if (section != null) {
                ptitle.append(section.getName());
                if (group != null) {
                    ptitle.append(" - ").append(group.getTitle());
                }

                if (topicListForm.getTag() != null) {
                    ptitle.append(" - ").append(WordUtils.capitalize(topicListForm.getTag()));
                }
            } else {
                ptitle.append(topicListForm.getTag());
            }
        } else {
            ptitle.append("?: ").append(section.getName());

            if (group != null) {
                ptitle.append(" - ").append(group.getTitle());
            }

            if (topicListForm.getTag() != null) {
                ptitle.append(" - ").append(topicListForm.getTag());
            }

            ptitle.append(", ").append(topicListForm.getYear()).append(", ")
                    .append(DateUtil.getMonth(topicListForm.getMonth()));
        }
        return ptitle.toString();
    }

    /**
     * @param section
     * @param group
     * @param topicListForm
     * @return
     * @throws BadDateException
     * @throws SectionNotFoundException
     */
    private static String calculateNavTitle(Section section, Group group, TopicListRequest topicListForm)
            throws BadDateException, SectionNotFoundException {

        StringBuilder navTitle = new StringBuilder();

        if (!Strings.isNullOrEmpty(topicListForm.getTag())) {
            navTitle.append(WordUtils.capitalize(topicListForm.getTag()));

            if (section != null) {
                navTitle.append(" - ");
                navTitle.append(section.getName());
            }
        } else if (group == null) {
            if (section != null) {
                navTitle.setLength(0);
                navTitle.append(section.getName());
            }
        } else if (section != null) {
            navTitle.setLength(0);
            navTitle.append("<a href=\"").append(Section.getNewsViewerLink(group.getSectionId())).append("\">")
                    .append(section.getName()).append("</a> - <strong>").append(group.getTitle())
                    .append("</strong>");
        }
        if (topicListForm.getMonth() != null) {
            navTitle.append(" - ? ").append(topicListForm.getYear()).append(", ")
                    .append(DateUtil.getMonth(topicListForm.getMonth()));
        }
        return navTitle.toString();
    }

    @ExceptionHandler(UserNotFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ModelAndView handleUserNotFoundException() {
        return new ModelAndView("errors/code404");
    }

}