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}