package com.tale.controller;
import com.blade.ioc.annotation.Inject;
import com.blade.jdbc.core.Take;
import com.blade.jdbc.model.Paginator;
import com.blade.kit.IPKit;
import com.blade.kit.PatternKit;
import com.blade.kit.StringKit;
import com.blade.mvc.annotation.*;
import com.blade.mvc.http.HttpMethod;
import com.blade.mvc.http.Request;
import com.blade.mvc.http.Response;
import com.blade.mvc.http.wrapper.Session;
import com.blade.mvc.view.RestResponse;
import com.tale.dto.Archive;
import com.tale.dto.ErrorCode;
import com.tale.dto.MetaDto;
import com.tale.dto.Types;
import com.tale.exception.TipException;
import com.tale.ext.Commons;
import com.tale.init.TaleConst;
import com.tale.model.Comments;
import com.tale.model.Contents;
import com.tale.model.Metas;
import com.tale.service.CommentsService;
import com.tale.service.ContentsService;
import com.tale.service.MetasService;
import com.tale.service.SiteService;
import com.tale.utils.TaleUtils;
import com.vdurmont.emoji.EmojiParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URLEncoder;
import java.util.List;
@Controller
public class IndexController extends BaseController {
private static final Logger LOGGER = LoggerFactory.getLogger(IndexController.class);
@Inject
private ContentsService contentsService;
@Inject
private MetasService metasService;
@Inject
private CommentsService commentsService;
@Inject
private SiteService siteService;
/**
* 首页
*
* @return
*/
@Route(value = "/", method = HttpMethod.GET)
public String index(Request request, @QueryParam(value = "limit", defaultValue = "12") int limit) {
return this.index(request, 1, limit);
}
/**
* 自定义页面
*/
@Route(values = {"/:cid", "/:cid.html"}, method = HttpMethod.GET)
public String page(@PathParam String cid, Request request) {
Contents contents = contentsService.getContents(cid);
if (null == contents) {
return this.render_404();
}
if (contents.getAllow_comment()) {
int cp = request.queryInt("cp", 1);
request.attribute("cp", cp);
}
request.attribute("article", contents);
updateArticleHit(contents.getCid(), contents.getHits());
if (Types.ARTICLE.equals(contents.getType())) {
return this.render("post");
}
if (Types.PAGE.equals(contents.getType())) {
return this.render("page");
}
return this.render_404();
}
/**
* 首页分页
*
* @param request
* @param page
* @param limit
* @return
*/
@Route(values = {"page/:page", "page/:page.html"}, method = HttpMethod.GET)
public String index(Request request, @PathParam int page, @QueryParam(value = "limit", defaultValue = "12") int limit) {
page = page < 0 || page > TaleConst.MAX_PAGE ? 1 : page;
Take take = new Take(Contents.class).eq("type", Types.ARTICLE).eq("status", Types.PUBLISH).page(page, limit, "created desc");
Paginator<Contents> articles = contentsService.getArticles(take);
request.attribute("articles", articles);
if (page > 1) {
this.title(request, "第" + page + "页");
}
request.attribute("is_home", true);
request.attribute("page_prefix", "/page");
return this.render("index");
}
/**
* 文章页
*/
@Route(values = {"article/:cid", "article/:cid.html"}, method = HttpMethod.GET)
public String post(Request request, @PathParam String cid) {
Contents contents = contentsService.getContents(cid);
if (null == contents || Types.DRAFT.equals(contents.getStatus())) {
return this.render_404();
}
request.attribute("article", contents);
request.attribute("is_post", true);
if (contents.getAllow_comment()) {
int cp = request.queryInt("cp", 1);
request.attribute("cp", cp);
}
updateArticleHit(contents.getCid(), contents.getHits());
return this.render("post");
}
private void updateArticleHit(Integer cid, Integer chits) {
Integer hits = cache.hget(Types.C_ARTICLE_HITS, cid.toString());
hits = null == hits ? 1 : hits + 1;
if (hits >= TaleConst.HIT_EXCEED) {
Contents temp = new Contents();
temp.setCid(cid);
temp.setHits(chits + hits);
contentsService.update(temp);
cache.hset(Types.C_ARTICLE_HITS, cid.toString(), 1);
} else {
cache.hset(Types.C_ARTICLE_HITS, cid.toString(), hits);
}
}
/**
* 分类页
*
* @return
*/
@Route(values = {"category/:keyword", "category/:keyword.html"}, method = HttpMethod.GET)
public String categories(Request request, @PathParam String keyword, @QueryParam(value = "limit", defaultValue = "12") int limit) {
return this.categories(request, keyword, 1, limit);
}
@Route(values = {"category/:keyword/:page", "category/:keyword/:page.html"}, method = HttpMethod.GET)
public String categories(Request request, @PathParam String keyword,
@PathParam int page, @QueryParam(value = "limit", defaultValue = "12") int limit) {
page = page < 0 || page > TaleConst.MAX_PAGE ? 1 : page;
MetaDto metaDto = metasService.getMeta(Types.CATEGORY, keyword);
if (null == metaDto) {
return this.render_404();
}
Paginator<Contents> contentsPaginator = contentsService.getArticles(metaDto.getMid(), page, limit);
request.attribute("articles", contentsPaginator);
request.attribute("meta", metaDto);
request.attribute("type", "分类");
request.attribute("keyword", keyword);
request.attribute("is_category", true);
request.attribute("page_prefix", "/category/" + keyword);
return this.render("page-category");
}
/**
* 标签页
*
* @param name
* @return
*/
@Route(values = {"tag/:name", "tag/:name.html"}, method = HttpMethod.GET)
public String tags(Request request, @PathParam String name, @QueryParam(value = "limit", defaultValue = "12") int limit) {
return this.tags(request, name, 1, limit);
}
/**
* 标签分页
*
* @param request
* @param name
* @param page
* @param limit
* @return
*/
@Route(values = {"tag/:name/:page", "tag/:name/:page.html"}, method = HttpMethod.GET)
public String tags(Request request, @PathParam String name, @PathParam int page, @QueryParam(value = "limit", defaultValue = "12") int limit) {
page = page < 0 || page > TaleConst.MAX_PAGE ? 1 : page;
MetaDto metaDto = metasService.getMeta(Types.TAG, name);
if (null == metaDto) {
return this.render_404();
}
Paginator<Contents> contentsPaginator = contentsService.getArticles(metaDto.getMid(), page, limit);
request.attribute("articles", contentsPaginator);
request.attribute("meta", metaDto);
request.attribute("type", "标签");
request.attribute("keyword", name);
request.attribute("is_tag", true);
request.attribute("page_prefix", "/tag/" + name);
return this.render("page-category");
}
/**
* 搜索页
*
* @param keyword
* @return
*/
@Route(values = {"search/:keyword", "search/:keyword.html"}, method = HttpMethod.GET)
public String search(Request request, @PathParam String keyword, @QueryParam(value = "limit", defaultValue = "12") int limit) {
return this.search(request, keyword, 1, limit);
}
@Route(values = {"search", "search.html"})
public String search(Request request, @QueryParam(value = "limit", defaultValue = "12") int limit) {
String keyword = request.query("s");
return this.search(request, keyword, 1, limit);
}
@Route(values = {"search/:keyword/:page", "search/:keyword/:page.html"}, method = HttpMethod.GET)
public String search(Request request, @PathParam String keyword, @PathParam int page, @QueryParam(value = "limit", defaultValue = "12") int limit) {
page = page < 0 || page > TaleConst.MAX_PAGE ? 1 : page;
Take take = new Take(Contents.class).eq("type", Types.ARTICLE).eq("status", Types.PUBLISH)
.like("title", "%" + keyword + "%").page(page, limit, "created desc");
Paginator<Contents> articles = contentsService.getArticles(take);
request.attribute("articles", articles);
request.attribute("type", "搜索");
request.attribute("keyword", keyword);
request.attribute("page_prefix", "/search/" + keyword);
return this.render("page-category");
}
/**
* 归档页
*
* @return
*/
@Route(values = {"archives", "archives.html"}, method = HttpMethod.GET)
public String archives(Request request) {
List<Archive> archives = siteService.getArchives();
request.attribute("archives", archives);
request.attribute("is_archive", true);
return this.render("archives");
}
/**
* 友链页
*
* @return
*/
@Route(values = {"links", "links.html"}, method = HttpMethod.GET)
public String links(Request request) {
List<Metas> links = metasService.getMetas(Types.LINK);
request.attribute("links", links);
return this.render("links");
}
/**
* feed页
*
* @return
*/
@Route(values = {"feed", "feed.xml"}, method = HttpMethod.GET)
public void feed(Response response) {
Paginator<Contents> contentsPaginator = contentsService.getArticles(new Take(Contents.class)
.eq("type", Types.ARTICLE).eq("status", Types.PUBLISH).eq("allow_feed", true).page(1, TaleConst.MAX_POSTS, "created desc"));
try {
String xml = TaleUtils.getRssXml(contentsPaginator.getList());
response.xml(xml);
} catch (Exception e) {
LOGGER.error("生成RSS失败", e);
}
}
/**
* 注销
*
* @param session
* @param response
*/
@Route("logout")
public void logout(Session session, Response response) {
TaleUtils.logout(session, response);
}
/**
* 评论操作
*/
@Route(value = "comment", method = HttpMethod.POST)
@JSON
public RestResponse comment(Request request, Response response,
@QueryParam Integer cid, @QueryParam Integer coid,
@QueryParam String author, @QueryParam String mail,
@QueryParam String url, @QueryParam String text, @QueryParam String _csrf_token) {
String ref = request.header("Referer");
if (StringKit.isBlank(ref) || StringKit.isBlank(_csrf_token)) {
return RestResponse.fail(ErrorCode.BAD_REQUEST);
}
if (!ref.startsWith(Commons.site_url())) {
return RestResponse.fail("非法评论来源");
}
String token = cache.hget(Types.CSRF_TOKEN, _csrf_token);
if (StringKit.isBlank(token)) {
return RestResponse.fail(ErrorCode.BAD_REQUEST);
}
if (null == cid || StringKit.isBlank(author) || StringKit.isBlank(mail) || StringKit.isBlank(text)) {
return RestResponse.fail("请输入完整后评论");
}
if (author.length() > 50) {
return RestResponse.fail("姓名过长");
}
if (!TaleUtils.isEmail(mail)) {
return RestResponse.fail("请输入正确的邮箱格式");
}
if (StringKit.isNotBlank(url) && !PatternKit.isURL(url)) {
return RestResponse.fail("请输入正确的URL格式");
}
if (text.length() > 200) {
return RestResponse.fail("请输入200个字符以内的评论");
}
String val = IPKit.getIpAddrByRequest(request.raw()) + ":" + cid;
Integer count = cache.hget(Types.COMMENTS_FREQUENCY, val);
if (null != count && count > 0) {
return RestResponse.fail("您发表评论太快了,请过会再试");
}
author = TaleUtils.cleanXSS(author);
text = TaleUtils.cleanXSS(text);
author = EmojiParser.parseToAliases(author);
text = EmojiParser.parseToAliases(text);
Comments comments = new Comments();
comments.setAuthor(author);
comments.setCid(cid);
comments.setIp(request.address());
comments.setUrl(url);
comments.setContent(text);
comments.setMail(mail);
comments.setParent(coid);
try {
commentsService.saveComment(comments);
response.cookie("tale_remember_author", URLEncoder.encode(author, "UTF-8"), 7 * 24 * 60 * 60);
response.cookie("tale_remember_mail", URLEncoder.encode(mail, "UTF-8"), 7 * 24 * 60 * 60);
if (StringKit.isNotBlank(url)) {
response.cookie("tale_remember_url", URLEncoder.encode(url, "UTF-8"), 7 * 24 * 60 * 60);
}
// 设置对每个文章30秒可以评论一次
cache.hset(Types.COMMENTS_FREQUENCY, val, 1, 30);
siteService.cleanCache(Types.C_STATISTICS);
request.attribute("del_csrf_token", token);
return RestResponse.ok();
} catch (Exception e) {
String msg = "评论发布失败";
if (e instanceof TipException) {
msg = e.getMessage();
} else {
LOGGER.error(msg, e);
}
return RestResponse.fail(msg);
}
}
}