diff --git a/doc/comment_action.md b/doc/comment_action.md index d56bd7e..55d154b 100644 --- a/doc/comment_action.md +++ b/doc/comment_action.md @@ -6,17 +6,22 @@ To determine if it was any operation, you see the `ACTION` column. And in the case of some actions, `CONTENT` column value contains additional information. -|ACTION |CONTENT | -|---------------|-----------------| -|comment |comment | -|close_comment |comment | -|reopen_comment |comment | -|close |"Close" | -|reopen |"Reopen" | -|commit |comment commitId | -|merge |comment | -|delete_branch |branchName | -|refer |issueId:title | +|ACTION |CONTENT | +|----------------|----------------------| +|comment |comment | +|close_comment |comment | +|reopen_comment |comment | +|close |"Close" | +|reopen |"Reopen" | +|commit |comment commitId | +|merge |comment | +|delete_branch |branchName | +|refer |issueId:title | +|add_label |labelName | +|delete_label |labelName | +|change_priority |oldPriority:priority | +|change_milestone|oldMilestone:milestone| +|assign |oldAssigned:assigned | ### comment @@ -54,3 +59,23 @@ This value is saved when other issue or issue comment contains reference to the issue like `#issueId`. At the same time, store id and title of the referrer issue as `id:title`. + +### add_label + +This value is saved when users have added the label. + +### delete_label + +This value is saved when users have deleted the label. + +### change_priority + +This value is saved when users have changed the priority. + +### change_milestone + +This value is saved when users have changed the milestone. + +### assign + +This value is saved when users have assign issue/PR to user or remove the assign. diff --git a/src/main/scala/gitbucket/core/controller/DashboardController.scala b/src/main/scala/gitbucket/core/controller/DashboardController.scala index 81e3085..f422ba5 100644 --- a/src/main/scala/gitbucket/core/controller/DashboardController.scala +++ b/src/main/scala/gitbucket/core/controller/DashboardController.scala @@ -8,7 +8,7 @@ class DashboardController extends DashboardControllerBase with IssuesService with PullRequestService with RepositoryService with AccountService with CommitsService - with UsersAuthenticator + with LabelsService with PrioritiesService with MilestonesService with UsersAuthenticator trait DashboardControllerBase extends ControllerBase { self: IssuesService with PullRequestService with RepositoryService with AccountService diff --git a/src/main/scala/gitbucket/core/controller/IndexController.scala b/src/main/scala/gitbucket/core/controller/IndexController.scala index bdfab51..f5390b4 100644 --- a/src/main/scala/gitbucket/core/controller/IndexController.scala +++ b/src/main/scala/gitbucket/core/controller/IndexController.scala @@ -20,6 +20,9 @@ with AccountService with RepositorySearchService with IssuesService + with LabelsService + with MilestonesService + with PrioritiesService with UsersAuthenticator with ReferrerAuthenticator with AccountFederationService diff --git a/src/main/scala/gitbucket/core/controller/IssuesController.scala b/src/main/scala/gitbucket/core/controller/IssuesController.scala index 4472863..a23a0d3 100644 --- a/src/main/scala/gitbucket/core/controller/IssuesController.scala +++ b/src/main/scala/gitbucket/core/controller/IssuesController.scala @@ -271,25 +271,25 @@ ajaxPost("/:owner/:repository/issues/:id/label/new")(writableUsersOnly { repository => defining(params("id").toInt){ issueId => - registerIssueLabel(repository.owner, repository.name, issueId, params("labelId").toInt) + registerIssueLabel(repository.owner, repository.name, issueId, params("labelId").toInt, true) html.labellist(getIssueLabels(repository.owner, repository.name, issueId)) } }) ajaxPost("/:owner/:repository/issues/:id/label/delete")(writableUsersOnly { repository => defining(params("id").toInt){ issueId => - deleteIssueLabel(repository.owner, repository.name, issueId, params("labelId").toInt) + deleteIssueLabel(repository.owner, repository.name, issueId, params("labelId").toInt, true) html.labellist(getIssueLabels(repository.owner, repository.name, issueId)) } }) ajaxPost("/:owner/:repository/issues/:id/assign")(writableUsersOnly { repository => - updateAssignedUserName(repository.owner, repository.name, params("id").toInt, assignedUserName("assignedUserName")) + updateAssignedUserName(repository.owner, repository.name, params("id").toInt, assignedUserName("assignedUserName"), true) Ok("updated") }) ajaxPost("/:owner/:repository/issues/:id/milestone")(writableUsersOnly { repository => - updateMilestoneId(repository.owner, repository.name, params("id").toInt, milestoneId("milestoneId")) + updateMilestoneId(repository.owner, repository.name, params("id").toInt, milestoneId("milestoneId"), true) milestoneId("milestoneId").map { milestoneId => getMilestonesWithIssueCount(repository.owner, repository.name) .find(_._1.milestoneId == milestoneId).map { case (_, openCount, closeCount) => @@ -299,7 +299,8 @@ }) ajaxPost("/:owner/:repository/issues/:id/priority")(writableUsersOnly { repository => - updatePriorityId(repository.owner, repository.name, params("id").toInt, priorityId("priorityId")) + val priority = priorityId("priorityId") + updatePriorityId(repository.owner, repository.name, params("id").toInt, priority, true) Ok("updated") }) @@ -325,7 +326,7 @@ params("value").toIntOpt.map{ labelId => executeBatch(repository) { issueId => getIssueLabel(repository.owner, repository.name, issueId, labelId) getOrElse { - registerIssueLabel(repository.owner, repository.name, issueId, labelId) + registerIssueLabel(repository.owner, repository.name, issueId, labelId, true) } } } getOrElse NotFound() @@ -334,7 +335,7 @@ post("/:owner/:repository/issues/batchedit/assign")(writableUsersOnly { repository => defining(assignedUserName("value")){ value => executeBatch(repository) { - updateAssignedUserName(repository.owner, repository.name, _, value) + updateAssignedUserName(repository.owner, repository.name, _, value, true) } } }) @@ -342,7 +343,7 @@ post("/:owner/:repository/issues/batchedit/milestone")(writableUsersOnly { repository => defining(milestoneId("value")){ value => executeBatch(repository) { - updateMilestoneId(repository.owner, repository.name, _, value) + updateMilestoneId(repository.owner, repository.name, _, value, true) } } }) @@ -350,7 +351,7 @@ post("/:owner/:repository/issues/batchedit/priority")(writableUsersOnly { repository => defining(priorityId("value")){ value => executeBatch(repository) { - updatePriorityId(repository.owner, repository.name, _, value) + updatePriorityId(repository.owner, repository.name, _, value, true) } } }) diff --git a/src/main/scala/gitbucket/core/controller/LabelsController.scala b/src/main/scala/gitbucket/core/controller/LabelsController.scala index 4f42475..9ab083e 100644 --- a/src/main/scala/gitbucket/core/controller/LabelsController.scala +++ b/src/main/scala/gitbucket/core/controller/LabelsController.scala @@ -1,7 +1,7 @@ package gitbucket.core.controller import gitbucket.core.issues.labels.html -import gitbucket.core.service.{RepositoryService, AccountService, IssuesService, LabelsService} +import gitbucket.core.service.{RepositoryService, AccountService, IssuesService, LabelsService, MilestonesService, PrioritiesService} import gitbucket.core.util.{ReferrerAuthenticator, WritableUsersAuthenticator} import gitbucket.core.util.Implicits._ import gitbucket.core.util.SyntaxSugars._ @@ -10,8 +10,9 @@ import org.scalatra.Ok class LabelsController extends LabelsControllerBase - with LabelsService with IssuesService with RepositoryService with AccountService -with ReferrerAuthenticator with WritableUsersAuthenticator + with IssuesService with RepositoryService with AccountService + with LabelsService with PrioritiesService with MilestonesService + with ReferrerAuthenticator with WritableUsersAuthenticator trait LabelsControllerBase extends ControllerBase { self: LabelsService with IssuesService with RepositoryService diff --git a/src/main/scala/gitbucket/core/controller/PrioritiesController.scala b/src/main/scala/gitbucket/core/controller/PrioritiesController.scala index dee6cbb..2141ffe 100644 --- a/src/main/scala/gitbucket/core/controller/PrioritiesController.scala +++ b/src/main/scala/gitbucket/core/controller/PrioritiesController.scala @@ -1,7 +1,7 @@ package gitbucket.core.controller import gitbucket.core.issues.priorities.html -import gitbucket.core.service.{RepositoryService, AccountService, IssuesService, PrioritiesService} +import gitbucket.core.service.{RepositoryService, AccountService, IssuesService, LabelsService, MilestonesService, PrioritiesService} import gitbucket.core.util.{ReferrerAuthenticator, WritableUsersAuthenticator} import gitbucket.core.util.Implicits._ import gitbucket.core.util.SyntaxSugars._ @@ -10,8 +10,9 @@ import org.scalatra.Ok class PrioritiesController extends PrioritiesControllerBase - with PrioritiesService with IssuesService with RepositoryService with AccountService -with ReferrerAuthenticator with WritableUsersAuthenticator + with IssuesService with RepositoryService with AccountService + with LabelsService with PrioritiesService with MilestonesService + with ReferrerAuthenticator with WritableUsersAuthenticator trait PrioritiesControllerBase extends ControllerBase { self: PrioritiesService with IssuesService with RepositoryService diff --git a/src/main/scala/gitbucket/core/controller/RepositoryViewerController.scala b/src/main/scala/gitbucket/core/controller/RepositoryViewerController.scala index 2c5688a..312a828 100644 --- a/src/main/scala/gitbucket/core/controller/RepositoryViewerController.scala +++ b/src/main/scala/gitbucket/core/controller/RepositoryViewerController.scala @@ -32,6 +32,7 @@ class RepositoryViewerController extends RepositoryViewerControllerBase with RepositoryService with AccountService with ActivityService with IssuesService with WebHookService with CommitsService + with LabelsService with MilestonesService with PrioritiesService with ReadableUsersAuthenticator with ReferrerAuthenticator with WritableUsersAuthenticator with PullRequestService with CommitStatusService with WebHookPullRequestService with WebHookPullRequestReviewCommentService with ProtectedBranchService diff --git a/src/main/scala/gitbucket/core/service/IssuesService.scala b/src/main/scala/gitbucket/core/service/IssuesService.scala index 2283c17..f081d9c 100644 --- a/src/main/scala/gitbucket/core/service/IssuesService.scala +++ b/src/main/scala/gitbucket/core/service/IssuesService.scala @@ -4,6 +4,7 @@ import gitbucket.core.util.StringUtil._ import gitbucket.core.util.Implicits._ import gitbucket.core.util.SyntaxSugars._ +import gitbucket.core.controller.Context import gitbucket.core.model.{Issue, PullRequest, IssueComment, IssueLabel, Label, Account, Repository, CommitState, Role} import gitbucket.core.model.Profile._ import gitbucket.core.model.Profile.profile._ @@ -11,7 +12,7 @@ import gitbucket.core.model.Profile.dateColumnType trait IssuesService { - self: AccountService with RepositoryService => + self: AccountService with RepositoryService with LabelsService with PrioritiesService with MilestonesService => import IssuesService._ def getIssue(owner: String, repository: String, issueId: String)(implicit s: Session) = @@ -321,11 +322,35 @@ } get } - def registerIssueLabel(owner: String, repository: String, issueId: Int, labelId: Int)(implicit s: Session): Int = { + def registerIssueLabel(owner: String, repository: String, issueId: Int, labelId: Int, insertComment: Boolean = false)(implicit context: Context, s: Session): Int = { + if (insertComment) { + IssueComments insert IssueComment( + userName = owner, + repositoryName = repository, + issueId = issueId, + action = "add_label", + commentedUserName = context.loginAccount.map(_.userName).getOrElse("Unknown user"), + content = getLabel(owner, repository, labelId).map(_.labelName).getOrElse("Unknown label"), + registeredDate = currentDate, + updatedDate = currentDate + ) + } IssueLabels insert IssueLabel(owner, repository, issueId, labelId) } - def deleteIssueLabel(owner: String, repository: String, issueId: Int, labelId: Int)(implicit s: Session): Int = { + def deleteIssueLabel(owner: String, repository: String, issueId: Int, labelId: Int, insertComment: Boolean = false)(implicit context: Context, s: Session): Int = { + if (insertComment) { + IssueComments insert IssueComment( + userName = owner, + repositoryName = repository, + issueId = issueId, + action = "delete_label", + commentedUserName = context.loginAccount.map(_.userName).getOrElse("Unknown user"), + content = getLabel(owner, repository, labelId).map(_.labelName).getOrElse("Unknown label"), + registeredDate = currentDate, + updatedDate = currentDate + ) + } IssueLabels filter(_.byPrimaryKey(owner, repository, issueId, labelId)) delete } @@ -350,15 +375,57 @@ .update(title, content, currentDate) } - def updateAssignedUserName(owner: String, repository: String, issueId: Int, assignedUserName: Option[String])(implicit s: Session): Int = { + def updateAssignedUserName(owner: String, repository: String, issueId: Int, assignedUserName: Option[String], insertComment: Boolean = false)(implicit context: Context, s: Session): Int = { + if (insertComment) { + val oldAssigned = getIssue(owner, repository, s"${issueId}").get.assignedUserName.getOrElse("Not assigned") + val assigned = assignedUserName.getOrElse("Not assigned") + IssueComments insert IssueComment( + userName = owner, + repositoryName = repository, + issueId = issueId, + action = "assign", + commentedUserName = context.loginAccount.map(_.userName).getOrElse("Unknown user"), + content = s"${oldAssigned}:${assigned}", + registeredDate = currentDate, + updatedDate = currentDate + ) + } Issues.filter(_.byPrimaryKey(owner, repository, issueId)).map(t => (t.assignedUserName?, t.updatedDate)).update(assignedUserName, currentDate) } - def updateMilestoneId(owner: String, repository: String, issueId: Int, milestoneId: Option[Int])(implicit s: Session): Int = { + def updateMilestoneId(owner: String, repository: String, issueId: Int, milestoneId: Option[Int], insertComment: Boolean = false)(implicit context: Context, s: Session): Int = { + if (insertComment) { + val oldMilestoneName = getIssue(owner, repository, s"${issueId}").get.milestoneId.map(getMilestone(owner, repository, _).map(_.title).getOrElse("Unknown milestone")).getOrElse("No milestone") + val milestoneName = milestoneId.map(getMilestone(owner, repository, _).map(_.title).getOrElse("Unknown milestone")).getOrElse("No milestone") + IssueComments insert IssueComment( + userName = owner, + repositoryName = repository, + issueId = issueId, + action = "change_milestone", + commentedUserName = context.loginAccount.map(_.userName).getOrElse("Unknown user"), + content = s"${oldMilestoneName}:${milestoneName}", + registeredDate = currentDate, + updatedDate = currentDate + ) + } Issues.filter(_.byPrimaryKey(owner, repository, issueId)).map(t => (t.milestoneId?, t.updatedDate)).update(milestoneId, currentDate) } - def updatePriorityId(owner: String, repository: String, issueId: Int, priorityId: Option[Int])(implicit s: Session): Int = { + def updatePriorityId(owner: String, repository: String, issueId: Int, priorityId: Option[Int], insertComment: Boolean = false)(implicit context: Context, s: Session): Int = { + if (insertComment) { + val oldPriorityName = getIssue(owner, repository, s"${issueId}").get.priorityId.map(getPriority(owner, repository, _).map(_.priorityName).getOrElse("Unknown priority")).getOrElse("No priority") + val priorityName = priorityId.map(getPriority(owner, repository, _).map(_.priorityName).getOrElse("Unknown priority")).getOrElse("No priority") + IssueComments insert IssueComment( + userName = owner, + repositoryName = repository, + issueId = issueId, + action = "change_priority", + commentedUserName = context.loginAccount.map(_.userName).getOrElse("Unknown user"), + content = s"${oldPriorityName}:${priorityName}", + registeredDate = currentDate, + updatedDate = currentDate + ) + } Issues.filter(_.byPrimaryKey(owner, repository, issueId)).map(t => (t.priorityId?, t.updatedDate)).update(priorityId, currentDate) } diff --git a/src/main/scala/gitbucket/core/service/RequestCache.scala b/src/main/scala/gitbucket/core/service/RequestCache.scala index bd03cd8..5e2e754 100644 --- a/src/main/scala/gitbucket/core/service/RequestCache.scala +++ b/src/main/scala/gitbucket/core/service/RequestCache.scala @@ -11,7 +11,8 @@ * It may be called many times in one request, so each method stores * its result into the cache which available during a request. */ -trait RequestCache extends SystemSettingsService with AccountService with IssuesService with RepositoryService { +trait RequestCache extends SystemSettingsService with AccountService with IssuesService with RepositoryService + with LabelsService with MilestonesService with PrioritiesService { private implicit def context2Session(implicit context: Context): Session = request2Session(context.request) diff --git a/src/main/scala/gitbucket/core/servlet/GitRepositoryServlet.scala b/src/main/scala/gitbucket/core/servlet/GitRepositoryServlet.scala index 1583e76..eac61a0 100644 --- a/src/main/scala/gitbucket/core/servlet/GitRepositoryServlet.scala +++ b/src/main/scala/gitbucket/core/servlet/GitRepositoryServlet.scala @@ -185,7 +185,8 @@ class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl: String, sshUrl: Option[String]) extends PostReceiveHook with PreReceiveHook with RepositoryService with AccountService with IssuesService with ActivityService with PullRequestService with WebHookService - with WebHookPullRequestService with CommitsService { + with LabelsService with PrioritiesService with MilestonesService + with WebHookPullRequestService with CommitsService { private val logger = LoggerFactory.getLogger(classOf[CommitLogHook]) private var existIds: Seq[String] = Nil diff --git a/src/main/twirl/gitbucket/core/issues/commentlist.scala.html b/src/main/twirl/gitbucket/core/issues/commentlist.scala.html index 6f913c9..43621f0 100644 --- a/src/main/twirl/gitbucket/core/issues/commentlist.scala.html +++ b/src/main/twirl/gitbucket/core/issues/commentlist.scala.html @@ -5,6 +5,43 @@ pullreq: Option[gitbucket.core.model.PullRequest] = None)(implicit context: gitbucket.core.controller.Context) @import gitbucket.core.view.helpers @import gitbucket.core.model.CommitComment +@issueOrPullRequest()={ @if(issue.exists(_.isPullRequest))( "pull request" )else( "issue" ) } +@showFormatedComment(comment: gitbucket.core.model.IssueComment)={ +
@pullreq.map(_.commitIdTo.substring(0, 7))
into
+ @if(pullreq.get.requestUserName == repository.owner){
+ @pullreq.map(_.branch)
from @pullreq.map(_.requestBranch)
+ } else {
+ @pullreq.map(_.userName):@pullreq.map(_.branch)
from @pullreq.map(_.requestUserName):@pullreq.map(_.requestBranch)
+ }
+ @gitbucket.core.helper.html.datetimeago(comment.registeredDate)
+ @pullreq.map(_.commitIdTo.substring(0, 7))
into
- @if(pullreq.get.requestUserName == repository.owner){
- @pullreq.map(_.branch)
from @pullreq.map(_.requestBranch)
- } else {
- @pullreq.map(_.userName):@pullreq.map(_.branch)
from @pullreq.map(_.requestUserName):@pullreq.map(_.requestBranch)
- }
- @gitbucket.core.helper.html.datetimeago(comment.registeredDate)
+ }
+ case "reopen" | "reopen_comment" => {
+ @if(comment.action == "reopen_comment"){
+ @showFormatedComment(comment)
+ }
+ @pullreq.map(_.requestBranch)
branch
+ @gitbucket.core.helper.html.datetimeago(comment.registeredDate)
+ @comment.content
label
+ @gitbucket.core.helper.html.datetimeago(comment.registeredDate)
+ @pullreq.map(_.requestBranch)
branch
- @gitbucket.core.helper.html.datetimeago(comment.registeredDate)
+ }
+ case "delete_label" => {
+ @comment.content
label
+ @gitbucket.core.helper.html.datetimeago(comment.registeredDate)
+ @comment.content.split(":")(0)
to @comment.content.split(":")(1)
+ @gitbucket.core.helper.html.datetimeago(comment.registeredDate)
+ @comment.content.split(":")(0)
to @comment.content.split(":")(1)
+ @gitbucket.core.helper.html.datetimeago(comment.registeredDate)
+ @comment.content.split(":")(0)
to @comment.content.split(":")(1)
+ @gitbucket.core.helper.html.datetimeago(comment.registeredDate)
+