Thu, 13 May 2021 19:31:09 +0200
fixes wrong handling of feeds - only one channel per feed is allowed
1.1 --- a/src/main/kotlin/de/uapcore/lightpit/Constants.kt Thu May 13 18:01:56 2021 +0200 1.2 +++ b/src/main/kotlin/de/uapcore/lightpit/Constants.kt Thu May 13 19:31:09 2021 +0200 1.3 @@ -62,6 +62,11 @@ 1.4 const val REQ_ATTR_BASE_HREF = "base_href" 1.5 1.6 /** 1.7 + * Key for the request attribute containing the RSS feed href. 1.8 + */ 1.9 + const val REQ_ATTR_FEED_HREF = "feed_href" 1.10 + 1.11 + /** 1.12 * Key for the request attribute containing the full path information (servlet path + path info). 1.13 */ 1.14 const val REQ_ATTR_PATH = "requestPath"
2.1 --- a/src/main/kotlin/de/uapcore/lightpit/RequestMapping.kt Thu May 13 18:01:56 2021 +0200 2.2 +++ b/src/main/kotlin/de/uapcore/lightpit/RequestMapping.kt Thu May 13 19:31:09 2021 +0200 2.3 @@ -86,6 +86,12 @@ 2.4 request.setAttribute(Constants.REQ_ATTR_REDIRECT_LOCATION, baseHref + value) 2.5 } 2.6 2.7 + var feedPath = "" 2.8 + set(value) { 2.9 + field = value 2.10 + request.setAttribute(Constants.REQ_ATTR_FEED_HREF, baseHref + value) 2.11 + } 2.12 + 2.13 /** 2.14 * The view object. 2.15 * 2.16 @@ -98,9 +104,21 @@ 2.17 } 2.18 2.19 /** 2.20 + * Additional port info, if necessary. 2.21 + */ 2.22 + private val portInfo = 2.23 + if ((request.scheme == "http" && request.serverPort == 80) 2.24 + || (request.scheme == "https" && request.serverPort == 443) 2.25 + ) "" else ":${request.serverPort}" 2.26 + 2.27 + /** 2.28 * The base path of this application. 2.29 */ 2.30 - val baseHref get() = "${request.scheme}://${request.serverName}:${request.serverPort}${request.contextPath}/" 2.31 + val baseHref get() = "${request.scheme}://${request.serverName}$portInfo${request.contextPath}/" 2.32 + 2.33 + init { 2.34 + feedPath = "feed/projects.rss" 2.35 + } 2.36 2.37 private fun String.withExt(ext: String) = if (endsWith(ext)) this else plus(ext) 2.38 private fun jspPath(name: String) = Constants.JSP_PATH_PREFIX.plus(name).withExt(".jsp") 2.39 @@ -108,10 +126,15 @@ 2.40 fun param(name: String): String? = request.getParameter(name) 2.41 fun paramArray(name: String): Array<String> = request.getParameterValues(name) ?: emptyArray() 2.42 2.43 - fun forward(jsp: String) { 2.44 + private fun forward(jsp: String) { 2.45 request.getRequestDispatcher(jspPath(jsp)).forward(request, response) 2.46 } 2.47 2.48 + fun renderFeed(page: String? = null) { 2.49 + page?.let { contentPage = it } 2.50 + forward("feed") 2.51 + } 2.52 + 2.53 fun render(page: String? = null) { 2.54 page?.let { contentPage = it } 2.55 forward("site")
3.1 --- a/src/main/kotlin/de/uapcore/lightpit/servlet/FeedServlet.kt Thu May 13 18:01:56 2021 +0200 3.2 +++ b/src/main/kotlin/de/uapcore/lightpit/servlet/FeedServlet.kt Thu May 13 19:31:09 2021 +0200 3.3 @@ -28,24 +28,39 @@ 3.4 import de.uapcore.lightpit.AbstractServlet 3.5 import de.uapcore.lightpit.HttpRequest 3.6 import de.uapcore.lightpit.dao.DataAccessObject 3.7 -import de.uapcore.lightpit.entities.Issue 3.8 import de.uapcore.lightpit.util.IssueFilter 3.9 import de.uapcore.lightpit.util.IssueSorter 3.10 +import de.uapcore.lightpit.util.SpecificFilter 3.11 import de.uapcore.lightpit.viewmodel.IssueFeed 3.12 +import de.uapcore.lightpit.viewmodel.ProjectFeed 3.13 import javax.servlet.annotation.WebServlet 3.14 3.15 @WebServlet(urlPatterns = ["/feed/*"]) 3.16 class FeedServlet : AbstractServlet() { 3.17 3.18 init { 3.19 - get("/issues.rss", this::issues) 3.20 + get("/projects.rss", this::projects) 3.21 + get("/%project/issues.rss", this::issues) 3.22 + } 3.23 + 3.24 + private fun projects(http: HttpRequest, dao: DataAccessObject) { 3.25 + 3.26 + val projects = dao.listProjects() 3.27 + 3.28 + http.view = ProjectFeed(projects) 3.29 + http.renderFeed("project-feed") 3.30 } 3.31 3.32 private fun issues(http: HttpRequest, dao: DataAccessObject) { 3.33 + val project = http.pathParams["project"]?.let { dao.findProjectByNode(it) } 3.34 + if (project == null) { 3.35 + http.response.sendError(404) 3.36 + return 3.37 + } 3.38 3.39 - val issues = dao.listIssues(IssueFilter()).sortedWith(IssueSorter.DEFAULT_ISSUE_SORTER) 3.40 + val issues = dao.listIssues(IssueFilter(SpecificFilter(project))).sortedWith(IssueSorter.DEFAULT_ISSUE_SORTER) 3.41 3.42 - http.view = IssueFeed(issues.groupBy(Issue::project)) 3.43 - http.forward("issues-feed") 3.44 + http.view = IssueFeed(project, issues) 3.45 + http.renderFeed("issues-feed") 3.46 } 3.47 } 3.48 \ No newline at end of file
4.1 --- a/src/main/kotlin/de/uapcore/lightpit/servlet/ProjectServlet.kt Thu May 13 18:01:56 2021 +0200 4.2 +++ b/src/main/kotlin/de/uapcore/lightpit/servlet/ProjectServlet.kt Thu May 13 19:31:09 2021 +0200 4.3 @@ -145,12 +145,15 @@ 4.4 } 4.5 } 4.6 4.7 + private fun feedPath(project: Project) = "feed/${project.node}/issues.rss" 4.8 + 4.9 data class PathInfos( 4.10 val projectInfo: ProjectInfo, 4.11 val version: Version?, 4.12 val component: Component? 4.13 ) { 4.14 - val issuesHref by lazyOf("projects/${projectInfo.project.node}/issues/${version?.node ?: "-"}/${component?.node ?: "-"}/") 4.15 + val project = projectInfo.project 4.16 + val issuesHref by lazyOf("projects/${project.node}/issues/${version?.node ?: "-"}/${component?.node ?: "-"}/") 4.17 } 4.18 4.19 private fun withPathInfo(http: HttpRequest, dao: DataAccessObject): PathInfos? { 4.20 @@ -186,13 +189,14 @@ 4.21 withPathInfo(http, dao)?.run { 4.22 4.23 val issues = dao.listIssues(IssueFilter( 4.24 - project = SpecificFilter(projectInfo.project), 4.25 + project = SpecificFilter(project), 4.26 version = version?.let { SpecificFilter(it) } ?: AllFilter(), 4.27 component = component?.let { SpecificFilter(it) } ?: AllFilter() 4.28 )).sortedWith(DEFAULT_ISSUE_SORTER) 4.29 4.30 with(http) { 4.31 view = ProjectDetails(projectInfo, issues, version, component) 4.32 + feedPath = feedPath(project) 4.33 navigationMenu = activeProjectNavMenu( 4.34 dao.listProjects(), 4.35 projectInfo, 4.36 @@ -261,6 +265,7 @@ 4.37 projectInfo, 4.38 dao.listVersionSummaries(projectInfo.project) 4.39 ) 4.40 + feedPath = feedPath(projectInfo.project) 4.41 navigationMenu = activeProjectNavMenu( 4.42 dao.listProjects(), 4.43 projectInfo 4.44 @@ -290,6 +295,7 @@ 4.45 4.46 with(http) { 4.47 view = VersionEditView(projectInfo, version) 4.48 + feedPath = feedPath(projectInfo.project) 4.49 navigationMenu = activeProjectNavMenu( 4.50 dao.listProjects(), 4.51 projectInfo, 4.52 @@ -342,6 +348,7 @@ 4.53 projectInfo, 4.54 dao.listComponentSummaries(projectInfo.project) 4.55 ) 4.56 + feedPath = feedPath(projectInfo.project) 4.57 navigationMenu = activeProjectNavMenu( 4.58 dao.listProjects(), 4.59 projectInfo 4.60 @@ -371,6 +378,7 @@ 4.61 4.62 with(http) { 4.63 view = ComponentEditView(projectInfo, component, dao.listUsers()) 4.64 + feedPath = feedPath(projectInfo.project) 4.65 navigationMenu = activeProjectNavMenu( 4.66 dao.listProjects(), 4.67 projectInfo, 4.68 @@ -426,7 +434,9 @@ 4.69 val comments = dao.listComments(issue) 4.70 4.71 with(http) { 4.72 - view = IssueDetailView(issue, comments, projectInfo.project, version, component) 4.73 + view = IssueDetailView(issue, comments, project, version, component) 4.74 + // TODO: feed path for this particular issue 4.75 + feedPath = feedPath(projectInfo.project) 4.76 navigationMenu = activeProjectNavMenu( 4.77 dao.listProjects(), 4.78 projectInfo, 4.79 @@ -443,7 +453,7 @@ 4.80 withPathInfo(http, dao)?.run { 4.81 val issue = dao.findIssue(http.pathParams["issue"]?.toIntOrNull() ?: -1) ?: Issue( 4.82 -1, 4.83 - projectInfo.project, 4.84 + project, 4.85 ) 4.86 4.87 // pre-select component, if available in the path info 4.88 @@ -464,10 +474,11 @@ 4.89 projectInfo.versions, 4.90 projectInfo.components, 4.91 dao.listUsers(), 4.92 - projectInfo.project, 4.93 + project, 4.94 version, 4.95 component 4.96 ) 4.97 + feedPath = feedPath(projectInfo.project) 4.98 navigationMenu = activeProjectNavMenu( 4.99 dao.listProjects(), 4.100 projectInfo, 4.101 @@ -505,7 +516,7 @@ 4.102 // TODO: throw validator exception instead of using defaults 4.103 val issue = Issue( 4.104 http.param("id")?.toIntOrNull() ?: -1, 4.105 - projectInfo.project 4.106 + project 4.107 ).apply { 4.108 component = dao.findComponent(http.param("component")?.toIntOrNull() ?: -1) 4.109 category = IssueCategory.valueOf(http.param("category") ?: "") 4.110 @@ -522,9 +533,9 @@ 4.111 eta = http.param("eta")?.let { if (it.isBlank()) null else Date.valueOf(it) } 4.112 4.113 affectedVersions = http.paramArray("affected") 4.114 - .mapNotNull { param -> param.toIntOrNull()?.let { Version(it, projectInfo.project.id) } } 4.115 + .mapNotNull { param -> param.toIntOrNull()?.let { Version(it, project.id) } } 4.116 resolvedVersions = http.paramArray("resolved") 4.117 - .mapNotNull { param -> param.toIntOrNull()?.let { Version(it, projectInfo.project.id) } } 4.118 + .mapNotNull { param -> param.toIntOrNull()?.let { Version(it, project.id) } } 4.119 } 4.120 4.121 val openId = if (issue.id < 0) {
5.1 --- a/src/main/kotlin/de/uapcore/lightpit/viewmodel/Feeds.kt Thu May 13 18:01:56 2021 +0200 5.2 +++ b/src/main/kotlin/de/uapcore/lightpit/viewmodel/Feeds.kt Thu May 13 19:31:09 2021 +0200 5.3 @@ -28,6 +28,11 @@ 5.4 import de.uapcore.lightpit.entities.Issue 5.5 import de.uapcore.lightpit.entities.Project 5.6 5.7 +class ProjectFeed( 5.8 + val projects: List<Project> 5.9 +) : View() 5.10 + 5.11 class IssueFeed( 5.12 - val issues: Map<Project, List<Issue>> 5.13 + val project: Project, 5.14 + val issues: List<Issue> 5.15 ) : View() 5.16 \ No newline at end of file
6.1 --- a/src/main/resources/localization/strings.properties Thu May 13 18:01:56 2021 +0200 6.2 +++ b/src/main/resources/localization/strings.properties Thu May 13 19:31:09 2021 +0200 6.3 @@ -54,6 +54,11 @@ 6.4 error.message = Server Message 6.5 error.returnLink = Return to 6.6 error.timestamp = Timestamp 6.7 +feed.issues.description=Feed about recently updated issues. 6.8 +feed.issues.title=LightPIT Issues 6.9 +feed.projects.description=Feed about tracked projects. 6.10 +feed.projects.source=Issues 6.11 +feed.projects.title=LightPIT Projects 6.12 issue.affected-versions=Affected Versions 6.13 issue.assignee=Assignee 6.14 issue.category.Bug=Bug 6.15 @@ -126,6 +131,4 @@ 6.16 version.status.Released=Released 6.17 version.status.Unreleased=Unreleased 6.18 version.status=Status 6.19 -version=Version 6.20 -feed.issues.title=LightPIT - Issues 6.21 -feed.issues.description=Feed about recently updated issues. 6.22 \ No newline at end of file 6.23 +version=Version 6.24 \ No newline at end of file
7.1 --- a/src/main/resources/localization/strings_de.properties Thu May 13 18:01:56 2021 +0200 7.2 +++ b/src/main/resources/localization/strings_de.properties Thu May 13 19:31:09 2021 +0200 7.3 @@ -54,6 +54,11 @@ 7.4 error.message = Server Nachricht 7.5 error.returnLink = Kehre zurück zu 7.6 error.timestamp = Zeitstempel 7.7 +feed.issues.description=Feed \u00fcber k\u00fcrzlich aktualisierte Vorg\u00e4nge. 7.8 +feed.issues.title=LightPIT Vorg\u00e4nge 7.9 +feed.projects.description=Feed \u00fcber verwaltete Projekte. 7.10 +feed.projects.source=Vorg\u00e4nge 7.11 +feed.projects.title=LightPIT Projekte 7.12 issue.affected-versions=Betroffene Versionen 7.13 issue.assignee=Zugewiesen 7.14 issue.category.Bug=Fehler 7.15 @@ -127,5 +132,3 @@ 7.16 version.status.Unreleased=Unver\u00f6ffentlicht 7.17 version.status=Status 7.18 version=Version 7.19 -feed.issues.title=LightPIT - Vorg\u00e4nge 7.20 -feed.issues.description=Feed \u00fcber k\u00fcrzlich aktualisierte Vorg\u00e4nge.
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/src/main/webapp/WEB-INF/jsp/feed.jsp Thu May 13 19:31:09 2021 +0200 8.3 @@ -0,0 +1,36 @@ 8.4 +<%-- 8.5 + ~ Copyright 2021 Mike Becker. All rights reserved. 8.6 + ~ 8.7 + ~ Redistribution and use in source and binary forms, with or without 8.8 + ~ modification, are permitted provided that the following conditions are met: 8.9 + ~ 8.10 + ~ 1. Redistributions of source code must retain the above copyright 8.11 + ~ notice, this list of conditions and the following disclaimer. 8.12 + ~ 8.13 + ~ 2. Redistributions in binary form must reproduce the above copyright 8.14 + ~ notice, this list of conditions and the following disclaimer in the 8.15 + ~ documentation and/or other materials provided with the distribution. 8.16 + ~ 8.17 + ~ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 8.18 + ~ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 8.19 + ~ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 8.20 + ~ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 8.21 + ~ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 8.22 + ~ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 8.23 + ~ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 8.24 + ~ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 8.25 + ~ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 8.26 + ~ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 8.27 + --%> 8.28 +<%@page contentType="application/rss+xml;charset=UTF-8" trimDirectiveWhitespaces="true" %> 8.29 +<%@page import="de.uapcore.lightpit.Constants" %> 8.30 +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 8.31 +<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> 8.32 +<c:set scope="page" var="contentPage" value="${requestScope[Constants.REQ_ATTR_CONTENT_PAGE]}"/> 8.33 +<c:set scope="request" var="baseHref" value="${requestScope[Constants.REQ_ATTR_BASE_HREF]}"/> 8.34 +<fmt:setLocale scope="request" value="${pageContext.response.locale}"/> 8.35 +<fmt:setBundle scope="request" basename="localization.strings"/> 8.36 +<?xml version="1.0" encoding="utf-8"?> 8.37 +<rss version="2.0"> 8.38 + <c:import url="${contentPage}"/> 8.39 +</rss>
9.1 --- a/src/main/webapp/WEB-INF/jsp/issues-feed.jsp Thu May 13 18:01:56 2021 +0200 9.2 +++ b/src/main/webapp/WEB-INF/jsp/issues-feed.jsp Thu May 13 19:31:09 2021 +0200 9.3 @@ -22,37 +22,24 @@ 9.4 ~ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 9.5 ~ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 9.6 --%> 9.7 -<%@ page contentType="application/rss+xml;charset=UTF-8" trimDirectiveWhitespaces="true" %> 9.8 -<%@page import="de.uapcore.lightpit.Constants" %> 9.9 +<%@page contentType="application/rss+xml;charset=UTF-8" pageEncoding="UTF-8" %> 9.10 <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 9.11 <%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> 9.12 <jsp:useBean id="viewmodel" type="de.uapcore.lightpit.viewmodel.IssueFeed" scope="request"/> 9.13 -<c:set scope="page" var="baseHref" value="${requestScope[Constants.REQ_ATTR_BASE_HREF]}"/> 9.14 -<fmt:setLocale scope="request" value="${pageContext.response.locale}"/> 9.15 -<fmt:setBundle scope="request" basename="localization.strings"/> 9.16 -<?xml version="1.0" encoding="utf-8"?> 9.17 -<rss version="2.0"> 9.18 - <c:forEach items="${viewmodel.issues}" var="feed"> 9.19 - <c:set var="project" value="${feed.key}"/> 9.20 - <c:set var="issues" value="${feed.value}"/> 9.21 - <channel> 9.22 - <title> 9.23 - <fmt:message key="feed.issues.title"/> - <c:out value="${project.name}"/> 9.24 - </title> 9.25 - <link>${baseHref}projects/${project.node}/</link> 9.26 - <description><fmt:message key="feed.issues.description"/></description> 9.27 - <language>${pageContext.response.locale.language}</language> 9.28 +<channel> 9.29 + <title><c:out value="${viewmodel.project.name}"/> | <fmt:message key="feed.issues.title"/></title> 9.30 + <description><fmt:message key="feed.issues.description"/></description> 9.31 + <link>${baseHref}projects/${viewmodel.project.node}</link> 9.32 + <language>${pageContext.response.locale.language}</language> 9.33 9.34 - <c:forEach items="${issues}" var="issue"> 9.35 - <item> 9.36 - <title><c:if test="${not empty issue.component}"><c:out value="${issue.component.name}"/> - </c:if><c:out value="${issue.subject}"/></title> 9.37 - <description><c:out value="${issue.description}"/></description> 9.38 - <category><fmt:message key="issue.category.${issue.category}"/></category> 9.39 - <link>${baseHref}projects/${issue.project.node}/issues/-/${empty issue.component ? '-' : issue.component.node}/${issue.id}</link> 9.40 - <guid isPermaLink="true">${baseHref}projects/${issue.project.node}/issues/-/-/${issue.id}</guid> 9.41 - <pubDate><fmt:formatDate value="${issue.updated}" pattern="EEE, dd MMM yyyy HH:mm:ss zzz" /></pubDate> 9.42 - </item> 9.43 - </c:forEach> 9.44 - </channel> 9.45 + <c:forEach items="${viewmodel.issues}" var="issue"> 9.46 + <item> 9.47 + <title><c:if test="${not empty issue.component}"><c:out value="${issue.component.name}"/> - </c:if><c:out value="${issue.subject}"/></title> 9.48 + <description><c:out value="${issue.description}"/></description> 9.49 + <category><fmt:message key="issue.category.${issue.category}"/></category> 9.50 + <link>${baseHref}projects/${issue.project.node}/issues/-/${empty issue.component ? '-' : issue.component.node}/${issue.id}</link> 9.51 + <guid isPermaLink="true">${baseHref}projects/${issue.project.node}/issues/-/-/${issue.id}</guid> 9.52 + <pubDate><fmt:formatDate value="${issue.updated}" pattern="EEE, dd MMM yyyy HH:mm:ss zzz" /></pubDate> 9.53 + </item> 9.54 </c:forEach> 9.55 -</rss> 9.56 \ No newline at end of file 9.57 +</channel>
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 10.2 +++ b/src/main/webapp/WEB-INF/jsp/project-feed.jsp Thu May 13 19:31:09 2021 +0200 10.3 @@ -0,0 +1,43 @@ 10.4 +<%-- 10.5 + ~ Copyright 2021 Mike Becker. All rights reserved. 10.6 + ~ 10.7 + ~ Redistribution and use in source and binary forms, with or without 10.8 + ~ modification, are permitted provided that the following conditions are met: 10.9 + ~ 10.10 + ~ 1. Redistributions of source code must retain the above copyright 10.11 + ~ notice, this list of conditions and the following disclaimer. 10.12 + ~ 10.13 + ~ 2. Redistributions in binary form must reproduce the above copyright 10.14 + ~ notice, this list of conditions and the following disclaimer in the 10.15 + ~ documentation and/or other materials provided with the distribution. 10.16 + ~ 10.17 + ~ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 10.18 + ~ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 10.19 + ~ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 10.20 + ~ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 10.21 + ~ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 10.22 + ~ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 10.23 + ~ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 10.24 + ~ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 10.25 + ~ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 10.26 + ~ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 10.27 + --%> 10.28 +<%@page contentType="application/rss+xml;charset=UTF-8" pageEncoding="UTF-8" %> 10.29 +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 10.30 +<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> 10.31 +<jsp:useBean id="viewmodel" type="de.uapcore.lightpit.viewmodel.ProjectFeed" scope="request"/> 10.32 +<channel> 10.33 + <title><fmt:message key="feed.projects.title"/></title> 10.34 + <description><fmt:message key="feed.projects.description"/></description> 10.35 + <link>${baseHref}projects/</link> 10.36 + <language>${pageContext.response.locale.language}</language> 10.37 + 10.38 + <c:forEach items="${viewmodel.projects}" var="project"> 10.39 + <item> 10.40 + <title><c:out value="${project.name}"/></title> 10.41 + <description><c:out value="${project.description}"/></description> 10.42 + <link>${baseHref}projects/${project.node}</link> 10.43 + <source url="${baseHref}feed/${project.node}/issues.rss"><fmt:message key="feed.projects.source"/></source> 10.44 + </item> 10.45 + </c:forEach> 10.46 +</channel>
11.1 --- a/src/main/webapp/WEB-INF/jsp/site.jsp Thu May 13 18:01:56 2021 +0200 11.2 +++ b/src/main/webapp/WEB-INF/jsp/site.jsp Thu May 13 19:31:09 2021 +0200 11.3 @@ -33,6 +33,9 @@ 11.4 <%-- Make the base href easily available at request scope --%> 11.5 <c:set scope="page" var="baseHref" value="${requestScope[Constants.REQ_ATTR_BASE_HREF]}"/> 11.6 11.7 +<%-- The feed URL for this page. --%> 11.8 +<c:set scope="page" var="feedHref" value="${requestScope[Constants.REQ_ATTR_FEED_HREF]}"/> 11.9 + 11.10 <%-- Define an alias for the request path --%> 11.11 <c:set scope="page" var="requestPath" value="${requestScope[Constants.REQ_ATTR_PATH]}"/> 11.12 11.13 @@ -62,8 +65,7 @@ 11.14 <meta http-equiv="refresh" content="0; URL=${redirectLocation}"> 11.15 </c:if> 11.16 <link rel="stylesheet" href="lightpit.css" type="text/css"> 11.17 - <link rel="alternate" type="application/rss+xml" 11.18 - title="RSS" href="${baseHref}feed/issues.rss" /> 11.19 + <link rel="alternate" type="application/rss+xml" title="RSS" href="${feedHref}" /> 11.20 <c:if test="${not empty extraCss}"> 11.21 <c:forEach items="${extraCss}" var="cssFile"> 11.22 <link rel="stylesheet" href="${cssFile}" type="text/css">