1.1 --- a/src/main/kotlin/de/uapcore/lightpit/servlet/FeedServlet.kt Sat Nov 27 12:12:20 2021 +0100 1.2 +++ b/src/main/kotlin/de/uapcore/lightpit/servlet/FeedServlet.kt Sat Nov 27 13:03:57 2021 +0100 1.3 @@ -30,8 +30,10 @@ 1.4 import de.uapcore.lightpit.AbstractServlet 1.5 import de.uapcore.lightpit.HttpRequest 1.6 import de.uapcore.lightpit.dao.DataAccessObject 1.7 -import de.uapcore.lightpit.entities.IssueHistoryData 1.8 +import de.uapcore.lightpit.entities.IssueCommentHistoryEntry 1.9 import de.uapcore.lightpit.entities.IssueHistoryEntry 1.10 +import de.uapcore.lightpit.types.IssueHistoryType 1.11 +import de.uapcore.lightpit.viewmodel.CommentDiff 1.12 import de.uapcore.lightpit.viewmodel.IssueDiff 1.13 import de.uapcore.lightpit.viewmodel.IssueFeed 1.14 import de.uapcore.lightpit.viewmodel.IssueFeedEntry 1.15 @@ -46,8 +48,36 @@ 1.16 get("/%project/issues.rss", this::issues) 1.17 } 1.18 1.19 - private fun fullContent(issue: IssueHistoryData) = IssueDiff( 1.20 - issue.id, 1.21 + val diffGenerator by lazyOf(DiffRowGenerator.create() 1.22 + .showInlineDiffs(true) 1.23 + .mergeOriginalRevised(true) 1.24 + .inlineDiffByWord(true) 1.25 + .oldTag { start -> if (start) "<strike style=\"color:red\">" else "</strike>" } 1.26 + .newTag { start -> if (start) "<i style=\"color: green\">" else "</i>" } 1.27 + .build() 1.28 + ) 1.29 + 1.30 + private fun fullContent(data: IssueCommentHistoryEntry) = 1.31 + CommentDiff( 1.32 + data.issueid, 1.33 + data.commentid, 1.34 + data.subject, 1.35 + data.comment.replace("\r", "") 1.36 + ) 1.37 + 1.38 + private fun diffContent(cur: IssueCommentHistoryEntry, next: IssueCommentHistoryEntry) = 1.39 + CommentDiff( 1.40 + cur.issueid, 1.41 + cur.commentid, 1.42 + cur.subject, 1.43 + diffGenerator.generateDiffRows( 1.44 + next.comment.replace("\r", "").split('\n'), 1.45 + cur.comment.replace("\r", "").split('\n') 1.46 + ).joinToString("\n", transform = DiffRow::getOldLine) 1.47 + ) 1.48 + 1.49 + private fun fullContent(issue: IssueHistoryEntry) = IssueDiff( 1.50 + issue.issueid, 1.51 issue.subject, 1.52 issue.component, 1.53 issue.status.name, 1.54 @@ -60,19 +90,10 @@ 1.55 issue.resolved 1.56 ) 1.57 1.58 - private fun diffContent(cur: IssueHistoryData, next: IssueHistoryData): IssueDiff { 1.59 - val generator = DiffRowGenerator.create() 1.60 - .showInlineDiffs(true) 1.61 - .mergeOriginalRevised(true) 1.62 - .inlineDiffByWord(true) 1.63 - .oldTag { start -> if (start) "<strike style=\"color:red\">" else "</strike>" } 1.64 - .newTag { start -> if (start) "<i style=\"color: green\">" else "</i>" } 1.65 - .build() 1.66 - 1.67 + private fun diffContent(cur: IssueHistoryEntry, next: IssueHistoryEntry): IssueDiff { 1.68 val prev = fullContent(next) 1.69 val diff = fullContent(cur) 1.70 - 1.71 - val result = generator.generateDiffRows( 1.72 + val result = diffGenerator.generateDiffRows( 1.73 listOf( 1.74 prev.subject, prev.component, prev.status, 1.75 prev.category, prev.assignee, prev.eta, prev.affected, prev.resolved 1.76 @@ -92,7 +113,7 @@ 1.77 diff.affected = result[6].oldLine 1.78 diff.resolved = result[7].oldLine 1.79 1.80 - diff.description = generator.generateDiffRows( 1.81 + diff.description = diffGenerator.generateDiffRows( 1.82 prev.description.split('\n'), 1.83 diff.description.split('\n') 1.84 ).joinToString("\n", transform = DiffRow::getOldLine) 1.85 @@ -102,21 +123,42 @@ 1.86 1.87 /** 1.88 * Generates the feed entries. 1.89 - * Assumes that [historyEntry] is already sorted by timestamp (descending). 1.90 + * Assumes that [issueEntries] and [commentEntries] are already sorted by timestamp (descending). 1.91 */ 1.92 - private fun generateFeedEntries(historyEntry: List<IssueHistoryEntry>): List<IssueFeedEntry> = 1.93 - if (historyEntry.isEmpty()) { 1.94 + private fun generateFeedEntries( 1.95 + issueEntries: List<IssueHistoryEntry>, 1.96 + commentEntries: List<IssueCommentHistoryEntry> 1.97 + ): List<IssueFeedEntry> = 1.98 + (generateIssueFeedEntries(issueEntries) + generateCommentFeedEntries(commentEntries)).sortedByDescending { it.time } 1.99 + 1.100 + private fun generateIssueFeedEntries(entries: List<IssueHistoryEntry>): List<IssueFeedEntry> = 1.101 + if (entries.isEmpty()) { 1.102 emptyList() 1.103 } else { 1.104 - historyEntry.groupBy { it.data.id }.mapValues { (_, history) -> 1.105 + entries.groupBy { it.issueid }.mapValues { (_, history) -> 1.106 history.zipWithNext().map { (cur, next) -> 1.107 IssueFeedEntry( 1.108 - cur.time, cur.type, diffContent(cur.data, next.data) 1.109 + cur.time, cur.type, issue = diffContent(cur, next) 1.110 ) 1.111 }.plus( 1.112 - history.last().let { IssueFeedEntry(it.time, it.type, fullContent(it.data)) } 1.113 + history.last().let { IssueFeedEntry(it.time, it.type, issue = fullContent(it)) } 1.114 ) 1.115 - }.flatMap { it.value }.sortedByDescending { it.time } 1.116 + }.flatMap { it.value } 1.117 + } 1.118 + 1.119 + private fun generateCommentFeedEntries(entries: List<IssueCommentHistoryEntry>): List<IssueFeedEntry> = 1.120 + if (entries.isEmpty()) { 1.121 + emptyList() 1.122 + } else { 1.123 + entries.groupBy { it.commentid }.mapValues { (_, history) -> 1.124 + history.zipWithNext().map { (cur, next) -> 1.125 + IssueFeedEntry( 1.126 + cur.time, cur.type, comment = diffContent(cur, next) 1.127 + ) 1.128 + }.plus( 1.129 + history.last().let { IssueFeedEntry(it.time, it.type, comment = fullContent(it)) } 1.130 + ) 1.131 + }.flatMap { it.value } 1.132 } 1.133 1.134 private fun issues(http: HttpRequest, dao: DataAccessObject) { 1.135 @@ -126,6 +168,7 @@ 1.136 return 1.137 } 1.138 val assignees = http.param("assignee")?.split(',') 1.139 + val comments = http.param("comments") ?: "all" 1.140 1.141 val days = http.param("days")?.toIntOrNull() ?: 30 1.142 1.143 @@ -133,9 +176,14 @@ 1.144 val issueHistory = if (assignees == null) issuesFromDb else 1.145 issuesFromDb.filter { assignees.contains(it.currentAssignee) } 1.146 1.147 - // TODO: add comment history depending on parameter 1.148 + val commentsFromDb = dao.listIssueCommentHistory(project.id, days) 1.149 + val commentHistory = when (comments) { 1.150 + "all" -> commentsFromDb 1.151 + "new" -> commentsFromDb.filter { it.type == IssueHistoryType.NewComment } 1.152 + else -> emptyList() 1.153 + } 1.154 1.155 - http.view = IssueFeed(project, generateFeedEntries(issueHistory)) 1.156 + http.view = IssueFeed(project, generateFeedEntries(issueHistory, commentHistory)) 1.157 http.renderFeed("issues-feed") 1.158 } 1.159 } 1.160 \ No newline at end of file