26 package de.uapcore.lightpit.servlet |
26 package de.uapcore.lightpit.servlet |
27 |
27 |
28 import de.uapcore.lightpit.AbstractServlet |
28 import de.uapcore.lightpit.AbstractServlet |
29 import de.uapcore.lightpit.HttpRequest |
29 import de.uapcore.lightpit.HttpRequest |
30 import de.uapcore.lightpit.dao.DataAccessObject |
30 import de.uapcore.lightpit.dao.DataAccessObject |
31 import de.uapcore.lightpit.util.IssueFilter |
31 import de.uapcore.lightpit.entities.IssueHistoryData |
32 import de.uapcore.lightpit.util.IssueSorter |
32 import de.uapcore.lightpit.entities.IssueHistoryEntry |
33 import de.uapcore.lightpit.util.SpecificFilter |
33 import de.uapcore.lightpit.viewmodel.IssueDiff |
34 import de.uapcore.lightpit.viewmodel.IssueFeed |
34 import de.uapcore.lightpit.viewmodel.IssueFeed |
|
35 import de.uapcore.lightpit.viewmodel.IssueFeedEntry |
|
36 import java.text.SimpleDateFormat |
35 import javax.servlet.annotation.WebServlet |
37 import javax.servlet.annotation.WebServlet |
36 |
38 |
37 @WebServlet(urlPatterns = ["/feed/*"]) |
39 @WebServlet(urlPatterns = ["/feed/*"]) |
38 class FeedServlet : AbstractServlet() { |
40 class FeedServlet : AbstractServlet() { |
39 |
41 |
40 init { |
42 init { |
41 get("/%project/issues.rss", this::issues) |
43 get("/%project/issues.rss", this::issues) |
42 } |
44 } |
43 |
45 |
|
46 private fun String.convertLF() = replace("\r", "").replace("\n", "<br>") |
|
47 |
|
48 private fun fullContent(issue: IssueHistoryData) = IssueDiff( |
|
49 issue.id, |
|
50 issue.subject, |
|
51 issue.component, |
|
52 issue.status.name, |
|
53 issue.category.name, |
|
54 issue.subject, |
|
55 issue.description.convertLF(), |
|
56 issue.assignee, |
|
57 issue.eta?.let { SimpleDateFormat("dd.MM.yyyy").format(it) } ?: "", |
|
58 issue.affected, |
|
59 issue.resolved |
|
60 ) |
|
61 |
|
62 private fun diffContent(cur: IssueHistoryData, next: IssueHistoryData): IssueDiff { |
|
63 val prev = fullContent(next) |
|
64 val diff = fullContent(cur) |
|
65 // TODO: compute and apply diff |
|
66 return diff |
|
67 } |
|
68 |
|
69 /** |
|
70 * Generates the feed entries. |
|
71 * Assumes that [historyEntry] is already sorted by timestamp (descending). |
|
72 */ |
|
73 private fun generateFeedEntries(historyEntry: List<IssueHistoryEntry>) = |
|
74 if (historyEntry.isEmpty()) emptyList() |
|
75 else historyEntry.zipWithNext().map { (cur, next) -> |
|
76 IssueFeedEntry( |
|
77 cur.time, cur.type, diffContent(cur.data, next.data) |
|
78 ) |
|
79 }.plus( |
|
80 historyEntry.last().let { IssueFeedEntry(it.time, it.type, fullContent(it.data)) } |
|
81 ) |
|
82 |
44 private fun issues(http: HttpRequest, dao: DataAccessObject) { |
83 private fun issues(http: HttpRequest, dao: DataAccessObject) { |
45 val project = http.pathParams["project"]?.let { dao.findProjectByNode(it) } |
84 val project = http.pathParams["project"]?.let { dao.findProjectByNode(it) } |
46 if (project == null) { |
85 if (project == null) { |
47 http.response.sendError(404) |
86 http.response.sendError(404) |
48 return |
87 return |
49 } |
88 } |
50 |
89 |
51 // TODO: add a timestamp filter (e.g. last 30 days) |
90 val days = http.param("days")?.toIntOrNull() ?: 30 |
52 val issues = dao.listIssues(IssueFilter(SpecificFilter(project))).sortedWith(IssueSorter.DEFAULT_ISSUE_SORTER) |
|
53 |
91 |
54 http.view = IssueFeed(project, issues) |
92 val issueHistory = dao.listIssueHistory(project.id, days) |
|
93 // TODO: add comment history depending on parameter |
|
94 |
|
95 http.view = IssueFeed(project, generateFeedEntries(issueHistory)) |
55 http.renderFeed("issues-feed") |
96 http.renderFeed("issues-feed") |
56 } |
97 } |
57 } |
98 } |