Permalink
Browse files

Merge pull request #564 from mrkm4ntr/coment-for-diff

(refs #9) Comments for commit and diff
  • Loading branch information...
takezoe committed Nov 27, 2014
2 parents 823c52e + af58e99 commit c23985c1a7a8c95a09d3283aa8b538d72b75689e
Showing with 742 additions and 178 deletions.
  1. +16 −0 src/main/resources/update/2_7.sql
  2. +6 −6 src/main/scala/app/PullRequestsController.scala
  3. +91 −5 src/main/scala/app/RepositoryViewerController.scala
  4. +7 −0 src/main/scala/model/BasicTemplate.scala
  5. +76 −0 src/main/scala/model/Comment.scala
  6. +0 −34 src/main/scala/model/IssueComment.scala
  7. +1 −0 src/main/scala/model/Profile.scala
  8. +9 −0 src/main/scala/service/ActivityService.scala
  9. +49 −0 src/main/scala/service/CommitsService.scala
  10. +1 −0 src/main/scala/servlet/AutoUpdateListener.scala
  11. +1 −0 src/main/scala/view/helpers.scala
  12. +1 −0 src/main/twirl/helper/activities.scala.html
  13. +17 −11 src/main/twirl/helper/attached.scala.html
  14. +30 −0 src/main/twirl/helper/commitcomment.scala.html
  15. +66 −3 src/main/twirl/helper/diff.scala.html
  16. +1 −1 src/main/twirl/helper/preview.scala.html
  17. +151 −88 src/main/twirl/issues/commentlist.scala.html
  18. +1 −1 src/main/twirl/issues/issue.scala.html
  19. +1 −1 src/main/twirl/issues/issueinfo.scala.html
  20. +9 −0 src/main/twirl/pulls/commits.scala.html
  21. +5 −2 src/main/twirl/pulls/compare.scala.html
  22. +9 −3 src/main/twirl/pulls/conversation.scala.html
  23. +11 −5 src/main/twirl/pulls/pullreq.scala.html
  24. +59 −0 src/main/twirl/repo/commentform.scala.html
  25. +20 −2 src/main/twirl/repo/commit.scala.html
  26. +45 −0 src/main/twirl/repo/editcomment.scala.html
  27. +1 −1 src/main/twirl/wiki/compare.scala.html
  28. +38 −1 src/main/webapp/assets/common/css/gitbucket.css
  29. +3 −3 src/main/webapp/assets/common/js/gitbucket.js
  30. +5 −9 src/main/webapp/assets/common/js/validation.js
  31. +12 −2 src/main/webapp/assets/vendors/jsdifflib/diffview.js
@@ -0,0 +1,16 @@
CREATE TABLE COMMIT_COMMENT (
USER_NAME VARCHAR(100) NOT NULL,
REPOSITORY_NAME VARCHAR(100) NOT NULL,
COMMIT_ID VARCHAR(100) NOT NULL,
COMMENT_ID INT AUTO_INCREMENT,
COMMENTED_USER_NAME VARCHAR(100) NOT NULL,
CONTENT TEXT NOT NULL,
FILE_NAME NVARCHAR(100),
OLD_LINE_NUMBER INT,
NEW_LINE_NUMBER INT,
REGISTERED_DATE TIMESTAMP NOT NULL,
UPDATED_DATE TIMESTAMP NOT NULL
);

ALTER TABLE COMMIT_COMMENT ADD CONSTRAINT IDX_COMMIT_COMMENT_PK PRIMARY KEY (COMMENT_ID);
ALTER TABLE COMMIT_COMMENT ADD CONSTRAINT IDX_COMMIT_COMMENT_1 UNIQUE (USER_NAME, REPOSITORY_NAME, COMMIT_ID, COMMENT_ID);
@@ -12,23 +12,21 @@ import scala.collection.JavaConverters._
import org.eclipse.jgit.lib.{ObjectId, CommitBuilder, PersonIdent}
import service.IssuesService._
import service.PullRequestService._
import util.JGitUtil.DiffInfo
import util.JGitUtil.CommitInfo
import org.slf4j.LoggerFactory
import org.eclipse.jgit.merge.MergeStrategy
import org.eclipse.jgit.errors.NoMergeBaseException
import service.WebHookService.WebHookPayload
import util.JGitUtil.DiffInfo
import scala.Some
import util.JGitUtil.CommitInfo


class PullRequestsController extends PullRequestsControllerBase
with RepositoryService with AccountService with IssuesService with PullRequestService with MilestonesService with LabelsService
with ActivityService with WebHookService with ReferrerAuthenticator with CollaboratorsAuthenticator
with CommitsService with ActivityService with WebHookService with ReferrerAuthenticator with CollaboratorsAuthenticator

trait PullRequestsControllerBase extends ControllerBase {
self: RepositoryService with AccountService with IssuesService with MilestonesService with LabelsService
with ActivityService with PullRequestService with WebHookService with ReferrerAuthenticator with CollaboratorsAuthenticator =>
with CommitsService with ActivityService with PullRequestService with WebHookService with ReferrerAuthenticator with CollaboratorsAuthenticator =>

private val logger = LoggerFactory.getLogger(classOf[PullRequestsControllerBase])

@@ -81,7 +79,8 @@ trait PullRequestsControllerBase extends ControllerBase {

pulls.html.pullreq(
issue, pullreq,
getComments(owner, name, issueId),
(commits.flatten.map(commit => getCommitComments(owner, name, commit.id)).flatten.toList ::: getComments(owner, name, issueId))
.sortWith((a, b) => a.registeredDate before b.registeredDate),
getIssueLabels(owner, name, issueId),
(getCollaborators(owner, name) ::: (if(getAccountByUserName(owner).get.isGroupAccount) Nil else List(owner))).sorted,
getMilestonesWithIssueCount(owner, name),
@@ -281,6 +280,7 @@ trait PullRequestsControllerBase extends ControllerBase {
case (Some(userName), Some(repositoryName)) => (userName, repositoryName) :: getForkedRepositories(userName, repositoryName)
case _ => (forkedRepository.owner, forkedRepository.name) :: getForkedRepositories(forkedRepository.owner, forkedRepository.name)
},
commits.flatten.map(commit => getCommitComments(forkedRepository.owner, forkedRepository.name, commit.id)).flatten.toList,
originBranch,
forkedBranch,
oldId.getName,
@@ -20,16 +20,16 @@ import org.eclipse.jgit.revwalk.RevCommit
import service.WebHookService.WebHookPayload

class RepositoryViewerController extends RepositoryViewerControllerBase
with RepositoryService with AccountService with ActivityService with IssuesService with WebHookService
with ReferrerAuthenticator with CollaboratorsAuthenticator
with RepositoryService with AccountService with ActivityService with IssuesService with WebHookService with CommitsService
with ReadableUsersAuthenticator with ReferrerAuthenticator with CollaboratorsAuthenticator


/**
* The repository viewer.
*/
trait RepositoryViewerControllerBase extends ControllerBase {
self: RepositoryService with AccountService with ActivityService with IssuesService with WebHookService
with ReferrerAuthenticator with CollaboratorsAuthenticator =>
self: RepositoryService with AccountService with ActivityService with IssuesService with WebHookService with CommitsService
with ReadableUsersAuthenticator with ReferrerAuthenticator with CollaboratorsAuthenticator =>

ArchiveCommand.registerFormat("zip", new ZipFormat)
ArchiveCommand.registerFormat("tar.gz", new TgzFormat)
@@ -52,6 +52,13 @@ trait RepositoryViewerControllerBase extends ControllerBase {
fileName: String
)

case class CommentForm(
fileName: Option[String],
oldLineNumber: Option[Int],
newLineNumber: Option[Int],
content: String
)

val editorForm = mapping(
"branch" -> trim(label("Branch", text(required))),
"path" -> trim(label("Path", text())),
@@ -70,6 +77,13 @@ trait RepositoryViewerControllerBase extends ControllerBase {
"fileName" -> trim(label("Filename", text(required)))
)(DeleteForm.apply)

val commentForm = mapping(
"fileName" -> trim(label("Filename", optional(text()))),
"oldLineNumber" -> trim(label("Old line number", optional(number()))),
"newLineNumber" -> trim(label("New line number", optional(number()))),
"content" -> trim(label("Content", text(required)))
)(CommentForm.apply)

/**
* Returns converted HTML from Markdown for preview.
*/
@@ -221,12 +235,81 @@ trait RepositoryViewerControllerBase extends ControllerBase {
repo.html.commit(id, new JGitUtil.CommitInfo(revCommit),
JGitUtil.getBranchesOfCommit(git, revCommit.getName),
JGitUtil.getTagsOfCommit(git, revCommit.getName),
repository, diffs, oldCommitId)
getCommitComments(repository.owner, repository.name, id),
repository, diffs, oldCommitId, hasWritePermission(repository.owner, repository.name, context.loginAccount))
}
}
}
})

post("/:owner/:repository/commit/:id/comment/new", commentForm)(readableUsersOnly { (form, repository) =>
val id = params("id")
createCommitComment(repository.owner, repository.name, id, context.loginAccount.get.userName, form.content,
form.fileName, form.oldLineNumber, form.newLineNumber)
recordCommentCommitActivity(repository.owner, repository.name, context.loginAccount.get.userName, id, form.content)
redirect(s"/${repository.owner}/${repository.name}/commit/${id}")
})

ajaxGet("/:owner/:repository/commit/:id/comment/_form")(readableUsersOnly { repository =>
val id = params("id")
val fileName = params.get("fileName")
val oldLineNumber = params.get("oldLineNumber") flatMap {b => Some(b.toInt)}
val newLineNumber = params.get("newLineNumber") flatMap {b => Some(b.toInt)}
repo.html.commentform(
commitId = id,
fileName, oldLineNumber, newLineNumber,
hasWritePermission = hasWritePermission(repository.owner, repository.name, context.loginAccount),
repository = repository
)
})

ajaxPost("/:owner/:repository/commit/:id/comment/_data/new", commentForm)(readableUsersOnly { (form, repository) =>
val id = params("id")
val commentId = createCommitComment(repository.owner, repository.name, id, context.loginAccount.get.userName,
form.content, form.fileName, form.oldLineNumber, form.newLineNumber)
recordCommentCommitActivity(repository.owner, repository.name, context.loginAccount.get.userName, id, form.content)
helper.html.commitcomment(getCommitComment(repository.owner, repository.name, commentId.toString).get,
hasWritePermission(repository.owner, repository.name, context.loginAccount), repository)
})

ajaxGet("/:owner/:repository/commit_comments/_data/:id")(readableUsersOnly { repository =>
getCommitComment(repository.owner, repository.name, params("id")) map { x =>
if(isEditable(x.userName, x.repositoryName, x.commentedUserName)){
params.get("dataType") collect {
case t if t == "html" => repo.html.editcomment(
x.content, x.commentId, x.userName, x.repositoryName)
} getOrElse {
contentType = formats("json")
org.json4s.jackson.Serialization.write(
Map("content" -> view.Markdown.toHtml(x.content,
repository, false, true, true, isEditable(x.userName, x.repositoryName, x.commentedUserName))
))
}
} else Unauthorized
} getOrElse NotFound
})

ajaxPost("/:owner/:repository/commit_comments/edit/:id", commentForm)(readableUsersOnly { (form, repository) =>
defining(repository.owner, repository.name){ case (owner, name) =>
getCommitComment(owner, name, params("id")).map { comment =>
if(isEditable(owner, name, comment.commentedUserName)){
updateCommitComment(comment.commentId, form.content)
redirect(s"/${owner}/${name}/commit_comments/_data/${comment.commentId}")
} else Unauthorized
} getOrElse NotFound
}
})

ajaxPost("/:owner/:repository/commit_comments/delete/:id")(readableUsersOnly { repository =>
defining(repository.owner, repository.name){ case (owner, name) =>
getCommitComment(owner, name, params("id")).map { comment =>
if(isEditable(owner, name, comment.commentedUserName)){
Ok(deleteCommitComment(comment.commentId))
} else Unauthorized
} getOrElse NotFound
}
})

/**
* Displays branches.
*/
@@ -461,4 +544,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
file
}
}

private def isEditable(owner: String, repository: String, author: String)(implicit context: app.Context): Boolean =
hasWritePermission(owner, repository, context.loginAccount) || author == context.loginAccount.get.userName
}
@@ -44,4 +44,11 @@ protected[model] trait TemplateComponent { self: Profile =>
byRepository(userName, repositoryName) && (this.milestoneId === milestoneId)
}

trait CommitTemplate extends BasicTemplate { self: Table[_] =>
val commitId = column[String]("COMMIT_ID")

def byCommit(owner: String, repository: String, commitId: String) =
byRepository(owner, repository) && (this.commitId === commitId)
}

}
@@ -0,0 +1,76 @@
package model

trait Comment {
val commentedUserName: String
val registeredDate: java.util.Date
}

trait IssueCommentComponent extends TemplateComponent { self: Profile =>
import profile.simple._
import self._

lazy val IssueComments = new TableQuery(tag => new IssueComments(tag)){
def autoInc = this returning this.map(_.commentId)
}

class IssueComments(tag: Tag) extends Table[IssueComment](tag, "ISSUE_COMMENT") with IssueTemplate {
val commentId = column[Int]("COMMENT_ID", O AutoInc)
val action = column[String]("ACTION")
val commentedUserName = column[String]("COMMENTED_USER_NAME")
val content = column[String]("CONTENT")
val registeredDate = column[java.util.Date]("REGISTERED_DATE")
val updatedDate = column[java.util.Date]("UPDATED_DATE")
def * = (userName, repositoryName, issueId, commentId, action, commentedUserName, content, registeredDate, updatedDate) <> (IssueComment.tupled, IssueComment.unapply)

def byPrimaryKey(commentId: Int) = this.commentId === commentId.bind
}
}

case class IssueComment (
userName: String,
repositoryName: String,
issueId: Int,
commentId: Int = 0,
action: String,
commentedUserName: String,
content: String,
registeredDate: java.util.Date,
updatedDate: java.util.Date
) extends Comment

trait CommitCommentComponent extends TemplateComponent { self: Profile =>
import profile.simple._
import self._

lazy val CommitComments = new TableQuery(tag => new CommitComments(tag)){
def autoInc = this returning this.map(_.commentId)
}

class CommitComments(tag: Tag) extends Table[CommitComment](tag, "COMMIT_COMMENT") with CommitTemplate {
val commentId = column[Int]("COMMENT_ID", O AutoInc)
val commentedUserName = column[String]("COMMENTED_USER_NAME")
val content = column[String]("CONTENT")
val fileName = column[Option[String]]("FILE_NAME")
val oldLine = column[Option[Int]]("OLD_LINE_NUMBER")
val newLine = column[Option[Int]]("NEW_LINE_NUMBER")
val registeredDate = column[java.util.Date]("REGISTERED_DATE")
val updatedDate = column[java.util.Date]("UPDATED_DATE")
def * = (userName, repositoryName, commitId, commentId, commentedUserName, content, fileName, oldLine, newLine, registeredDate, updatedDate) <> (CommitComment.tupled, CommitComment.unapply)

def byPrimaryKey(commentId: Int) = this.commentId === commentId.bind
}
}

case class CommitComment(
userName: String,
repositoryName: String,
commitId: String,
commentId: Int = 0,
commentedUserName: String,
content: String,
fileName: Option[String],
oldLine: Option[Int],
newLine: Option[Int],
registeredDate: java.util.Date,
updatedDate: java.util.Date
) extends Comment

This file was deleted.

Oops, something went wrong.
@@ -22,6 +22,7 @@ object Profile extends {
} with AccountComponent
with ActivityComponent
with CollaboratorComponent
with CommitCommentComponent
with GroupMemberComponent
with IssueComponent
with IssueCommentComponent
@@ -95,6 +95,15 @@ trait ActivityService {
Some(cut(comment, 200)),
currentDate)

def recordCommentCommitActivity(userName: String, repositoryName: String, activityUserName: String, commitId: String, comment: String)
(implicit s: Session): Unit =
Activities insert Activity(userName, repositoryName, activityUserName,
"comment_commit",
s"[user:${activityUserName}] commented on commit [commit:${userName}/${repositoryName}@${commitId}]",
Some(cut(comment, 200)),
currentDate
)

def recordCreateWikiPageActivity(userName: String, repositoryName: String, activityUserName: String, pageName: String)
(implicit s: Session): Unit =
Activities insert Activity(userName, repositoryName, activityUserName,
@@ -0,0 +1,49 @@
package service

import scala.slick.jdbc.{StaticQuery => Q}
import Q.interpolation

import model.Profile._
import profile.simple._
import model.CommitComment
import util.Implicits._
import util.StringUtil._


trait CommitsService {

def getCommitComments(owner: String, repository: String, commitId: String)(implicit s: Session) =
CommitComments filter (_.byCommit(owner, repository, commitId)) list

def getCommitComment(owner: String, repository: String, commentId: String)(implicit s: Session) =
if (commentId forall (_.isDigit))
CommitComments filter { t =>
t.byPrimaryKey(commentId.toInt) && t.byRepository(owner, repository)
} firstOption
else
None

def createCommitComment(owner: String, repository: String, commitId: String, loginUser: String,
content: String, fileName: Option[String], oldLine: Option[Int], newLine: Option[Int])(implicit s: Session): Int =
CommitComments.autoInc insert CommitComment(
userName = owner,
repositoryName = repository,
commitId = commitId,
commentedUserName = loginUser,
content = content,
fileName = fileName,
oldLine = oldLine,
newLine = newLine,
registeredDate = currentDate,
updatedDate = currentDate)

def updateCommitComment(commentId: Int, content: String)(implicit s: Session) =
CommitComments
.filter (_.byPrimaryKey(commentId))
.map { t =>
t.content -> t.updatedDate
}.update (content, currentDate)

def deleteCommitComment(commentId: Int)(implicit s: Session) =
CommitComments filter (_.byPrimaryKey(commentId)) delete
}
Oops, something went wrong.

0 comments on commit c23985c

Please sign in to comment.