001/* 002 * Stallion Core: A Modern Web Framework 003 * 004 * Copyright (C) 2015 - 2016 Stallion Software LLC. 005 * 006 * This program is free software: you can redistribute it and/or modify it under the terms of the 007 * GNU General Public License as published by the Free Software Foundation, either version 2 of 008 * the License, or (at your option) any later version. This program is distributed in the hope that 009 * it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 010 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 011 * License for more details. You should have received a copy of the GNU General Public License 012 * along with this program. If not, see <http://www.gnu.org/licenses/gpl-2.0.html>. 013 * 014 * 015 * 016 */ 017 018package io.stallion.dataAccess.file; 019 020import java.time.ZonedDateTime; 021import java.util.HashMap; 022import java.util.List; 023import java.util.Map; 024 025import static io.stallion.utils.Literals.*; 026 027import io.stallion.Context; 028import io.stallion.dataAccess.DataAccessRegistry; 029import io.stallion.dataAccess.DisplayableModelController; 030import io.stallion.dataAccess.filtering.FilterChain; 031import io.stallion.dataAccess.filtering.Pager; 032import io.stallion.restfulEndpoints.EndpointResource; 033import io.stallion.restfulEndpoints.EndpointsRegistry; 034import io.stallion.services.Log; 035import io.stallion.settings.ContentFolder; 036import io.stallion.settings.Settings; 037import io.stallion.templating.TemplateRenderer; 038import io.stallion.utils.DateUtils; 039import io.stallion.utils.GeneralUtils; 040 041import javax.ws.rs.GET; 042import javax.ws.rs.Path; 043import javax.ws.rs.PathParam; 044import javax.ws.rs.Produces; 045 046 047public class ListingEndpoints implements EndpointResource { 048 049 public static void register() { 050 for(ContentFolder config: Settings.instance().getFolders()) { 051 if (config.isListingEnabled()) { 052 EndpointsRegistry.instance().addResource(config.getListingRootUrl(), new ListingEndpoints(config)); 053 } 054 } 055 } 056 057 private ContentFolder config; 058 059 public ListingEndpoints(ContentFolder config) { 060 this.config = config; 061 } 062 063 public Map<String, Object> makeContext() throws Exception { 064 Map<String, Object> context = new HashMap<String, Object>(); 065 context.put("blogConfig", config); 066 context.put("postsFilter", filterChain()); 067 if (!empty(config.getListingTitle())) { 068 Context.getResponse().getMeta().setTitle(config.getListingTitle()); 069 } 070 if (!empty(config.getListingMetaDescription())) { 071 Context.getResponse().getMeta().setDescription(config.getListingMetaDescription()); 072 } 073 String blogRoot = GeneralUtils.slugify(config.getListingRootUrl()); 074 if (empty(blogRoot) || blogRoot.equals("-")) { 075 blogRoot = "root"; 076 } else if (blogRoot.startsWith("-")) { 077 blogRoot = blogRoot.substring(1); 078 } 079 Context.getResponse().getMeta().setBodyCssId("flatBlog-" + blogRoot); 080 Context.getResponse().getMeta().getCssClasses().add("st-flatBlog-" + blogRoot); 081 return context; 082 } 083 084 private DisplayableModelController<TextItem> postsController() { 085 return (DisplayableModelController<TextItem>)DataAccessRegistry.instance().get(config.getPath()); 086 } 087 088 private FilterChain<TextItem> filterChain() throws Exception { 089 return postsController().filter("published", true); 090 } 091 092 @GET 093 @Path("/") 094 @Produces("text/html") 095 public String listHome() throws Exception { 096 return listHome(0); 097 } 098 099 @GET 100 @Path("/page/:page/") 101 @Produces("text/html") 102 public String listHome(@PathParam("page") Integer page) throws Exception { 103 Map<String, Object> context = makeContext(); 104 Pager pager = filterChain() 105 .sort("publishDate", "desc") 106 .pager(page, config.getItemsPerPage()); 107 context.put("postsPager", pager); 108 if (pager.getItems().size() == 0) { 109 Context.getResponse().setStatus(404); 110 } 111 return TemplateRenderer.instance().renderTemplate(config.getListingTemplate(), context); 112 } 113 114 @GET 115 @Path("/feed/") 116 @Produces("text/xml") 117 public String feed() throws Exception { 118 return rss(); 119 } 120 121 @GET 122 @Path("/rss.xml") 123 @Produces("text/xml") 124 public String rss() throws Exception { 125 Map<String, Object> context = makeContext(); 126 Pager pager = filterChain() 127 .sort("publishDate", "desc") 128 .pager(0, 20); 129 context.put("postsPager", pager); 130 context.put("blogUrl", Context.getSettings().getSiteUrl() + config.getFullPath()); 131 ZonedDateTime buildTime = ZonedDateTime.of(2015, 1, 1, 12, 0, 0, 0, GeneralUtils.UTC); 132 if (pager.getItems().size() > 0) { 133 TextItem item = (TextItem) pager.getItems().get(0); 134 buildTime = item.getPublishDate().plusMinutes(1); 135 } 136 context.put("generator", Settings.instance().getMetaGenerator()); 137 context.put("lastBuildDate", DateUtils.formatLocalDateFromZonedDate(buildTime, "EEE, dd MMM yyyy HH:mm:ss Z")); 138 return TemplateRenderer.instance().renderTemplate( 139 getClass().getResource("/templates/rss.jinja").toString(), 140 context); 141 } 142 143 144 145 @GET 146 @Path("/archives/:year/:month/") 147 public String listByDate(@PathParam("year") String year, @PathParam("month") String month) throws Exception { 148 Map<String, Object> context = makeContext(); 149 Pager pager = filterChain() 150 .filter("year", year) 151 .filter("month", month) 152 .sort("publishDate", "desc") 153 .pager(0, 5000); 154 context.put("postsPager", pager); 155 return TemplateRenderer.instance().renderTemplate(config.getListingTemplate(), context); 156 157 } 158 159 @GET 160 @Path("/by-tag/:tag/") 161 @Produces("text/html") 162 public String listByTag(@PathParam("tag") String tag) throws Exception { 163 Map<String, Object> context = makeContext(); 164 Pager pager = filterChain() 165 .filter("tags", tag, "in") 166 .sort("publishDate", "desc") 167 .pager(0, 5000); 168 context.put("postsPager", pager); 169 return TemplateRenderer.instance().renderTemplate(config.getListingTemplate(), context); 170 } 171}