diff --git a/src/main/resources/update/2_7.sql b/src/main/resources/update/2_7.sql new file mode 100644 index 0000000..b64b4fe --- /dev/null +++ b/src/main/resources/update/2_7.sql @@ -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); diff --git a/src/main/scala/app/PullRequestsController.scala b/src/main/scala/app/PullRequestsController.scala index ff87241..78307e7 100644 --- a/src/main/scala/app/PullRequestsController.scala +++ b/src/main/scala/app/PullRequestsController.scala @@ -12,23 +12,21 @@ 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 @@ 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 @@ 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, diff --git a/src/main/scala/app/RepositoryViewerController.scala b/src/main/scala/app/RepositoryViewerController.scala index 5b5b11b..02c2240 100644 --- a/src/main/scala/app/RepositoryViewerController.scala +++ b/src/main/scala/app/RepositoryViewerController.scala @@ -20,16 +20,16 @@ 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 @@ 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 @@ "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 @@ 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 @@ 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 } diff --git a/src/main/scala/model/BasicTemplate.scala b/src/main/scala/model/BasicTemplate.scala index 6266ebc..52e0a11 100644 --- a/src/main/scala/model/BasicTemplate.scala +++ b/src/main/scala/model/BasicTemplate.scala @@ -44,4 +44,11 @@ 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) + } + } diff --git a/src/main/scala/model/Comment.scala b/src/main/scala/model/Comment.scala new file mode 100644 index 0000000..51be46d --- /dev/null +++ b/src/main/scala/model/Comment.scala @@ -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 diff --git a/src/main/scala/model/IssueComment.scala b/src/main/scala/model/IssueComment.scala deleted file mode 100644 index 4c8ca6e..0000000 --- a/src/main/scala/model/IssueComment.scala +++ /dev/null @@ -1,34 +0,0 @@ -package model - -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 -) diff --git a/src/main/scala/model/Profile.scala b/src/main/scala/model/Profile.scala index 10e2ab1..d7ff17f 100644 --- a/src/main/scala/model/Profile.scala +++ b/src/main/scala/model/Profile.scala @@ -22,6 +22,7 @@ } with AccountComponent with ActivityComponent with CollaboratorComponent + with CommitCommentComponent with GroupMemberComponent with IssueComponent with IssueCommentComponent diff --git a/src/main/scala/service/ActivityService.scala b/src/main/scala/service/ActivityService.scala index 76107ae..a90bfb5 100644 --- a/src/main/scala/service/ActivityService.scala +++ b/src/main/scala/service/ActivityService.scala @@ -95,6 +95,15 @@ 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, diff --git a/src/main/scala/service/CommitsService.scala b/src/main/scala/service/CommitsService.scala new file mode 100644 index 0000000..c80d8c0 --- /dev/null +++ b/src/main/scala/service/CommitsService.scala @@ -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 +} diff --git a/src/main/scala/servlet/AutoUpdateListener.scala b/src/main/scala/servlet/AutoUpdateListener.scala index dc40c0c..c0eb126 100644 --- a/src/main/scala/servlet/AutoUpdateListener.scala +++ b/src/main/scala/servlet/AutoUpdateListener.scala @@ -53,6 +53,7 @@ * The history of versions. A head of this sequence is the current BitBucket version. */ val versions = Seq( + new Version(2, 7), new Version(2, 6), new Version(2, 5), new Version(2, 4), diff --git a/src/main/scala/view/helpers.scala b/src/main/scala/view/helpers.scala index 19dd2e8..9662823 100644 --- a/src/main/scala/view/helpers.scala +++ b/src/main/scala/view/helpers.scala @@ -152,6 +152,7 @@ .replaceAll("\\[branch:([^\\s]+?)/([^\\s]+?)#([^\\s]+?)\\]", (m: Match) => s"""${m.group(3)}""") .replaceAll("\\[tag:([^\\s]+?)/([^\\s]+?)#([^\\s]+?)\\]" , (m: Match) => s"""${m.group(3)}""") .replaceAll("\\[user:([^\\s]+?)\\]" , (m: Match) => user(m.group(1)).body) + .replaceAll("\\[commit:([^\\s]+?)/([^\\s]+?)\\@([^\\s]+?)\\]", (m: Match) => s"""${m.group(1)}/${m.group(2)}@${m.group(3).substring(0, 7)}""") ) /** diff --git a/src/main/twirl/helper/activities.scala.html b/src/main/twirl/helper/activities.scala.html index 9bb3f8d..34378af 100644 --- a/src/main/twirl/helper/activities.scala.html +++ b/src/main/twirl/helper/activities.scala.html @@ -10,6 +10,7 @@ @(activity.activityType match { case "open_issue" => detailActivity(activity, "activity-issue.png") case "comment_issue" => detailActivity(activity, "activity-comment.png") + case "comment_commit" => detailActivity(activity, "activity-comment.png") case "close_issue" => detailActivity(activity, "activity-issue-close.png") case "reopen_issue" => detailActivity(activity, "activity-issue-reopen.png") case "open_pullreq" => detailActivity(activity, "activity-merge.png") diff --git a/src/main/twirl/helper/attached.scala.html b/src/main/twirl/helper/attached.scala.html index fc85f82..e0fbc5e 100644 --- a/src/main/twirl/helper/attached.scala.html +++ b/src/main/twirl/helper/attached.scala.html @@ -7,18 +7,24 @@ @defining("(id=\")([\\w\\-]*)(\")".r.findFirstMatchIn(textarea.body).map(_.group(2))){ textareaId => \ No newline at end of file + diff --git a/src/main/twirl/helper/preview.scala.html b/src/main/twirl/helper/preview.scala.html index 3c0e13e..5a65c1d 100644 --- a/src/main/twirl/helper/preview.scala.html +++ b/src/main/twirl/helper/preview.scala.html @@ -34,7 +34,7 @@ } $('#preview').click(function(){ - $('#preview-area').html(' Previewing...'); + $(this).closest('#preview-area').html(' Previewing...'); $.post('@url(repository)/_preview', { content : $('#content').val(), enableWikiLink : @enableWikiLink, diff --git a/src/main/twirl/issues/commentlist.scala.html b/src/main/twirl/issues/commentlist.scala.html index 169a00d..27fa42a 100644 --- a/src/main/twirl/issues/commentlist.scala.html +++ b/src/main/twirl/issues/commentlist.scala.html @@ -1,107 +1,115 @@ -@(issue: model.Issue, - comments: List[model.IssueComment], +@(issue: Option[model.Issue], + comments: List[model.Comment], hasWritePermission: Boolean, repository: service.RepositoryService.RepositoryInfo, pullreq: Option[model.PullRequest] = None)(implicit context: app.Context) @import context._ @import view.helpers._ -
@avatar(issue.openedUserName, 48)
-
-
- @user(issue.openedUserName, styleClass="username strong") commented @helper.html.datetimeago(issue.registeredDate) - - @if(hasWritePermission || loginAccount.map(_.userName == issue.openedUserName).getOrElse(false)){ - - } - +@if(issue.isDefined){ +
@avatar(issue.get.openedUserName, 48)
+
+
+ @user(issue.get.openedUserName, styleClass="username strong") commented @helper.html.datetimeago(issue.get.registeredDate) + + @if(hasWritePermission || loginAccount.map(_.userName == issue.get.openedUserName).getOrElse(false)){ + + } + +
+
+ @markdown(issue.get.content getOrElse "No description provided.", repository, false, true, true, hasWritePermission) +
-
- @markdown(issue.content getOrElse "No description provided.", repository, false, true, true, hasWritePermission) -
-
+} -@comments.map { comment => - @if(comment.action != "close" && comment.action != "reopen" && comment.action != "delete_branch"){ -
@avatar(comment.commentedUserName, 48)
-
-
- @user(comment.commentedUserName, styleClass="username strong") - - @if(comment.action == "comment"){ - commented - } else { - @if(pullreq.isEmpty){ referenced the issue } else { referenced the pull request } - } - @helper.html.datetimeago(comment.registeredDate) - - - @if(comment.action != "commit" && comment.action != "merge" && comment.action != "refer" && - (hasWritePermission || loginAccount.map(_.userName == comment.commentedUserName).getOrElse(false))){ -   - - } - -
-
- @if(comment.action == "commit" && comment.content.split(" ").last.matches("[a-f0-9]{40}")){ - @defining(comment.content.substring(comment.content.length - 40)){ id => - - @markdown(comment.content.substring(0, comment.content.length - 41), repository, false, true, true, hasWritePermission) - } - } else { - @if(comment.action == "refer"){ - @defining(comment.content.split(":")){ case Array(issueId, rest @ _*) => - Issue #@issueId: @rest.mkString(":") +@comments.map { + case comment: model.IssueComment => { + @if(comment.action != "close" && comment.action != "reopen" && comment.action != "delete_branch"){ +
@avatar(comment.commentedUserName, 48)
+
+
+ @user(comment.commentedUserName, styleClass="username strong") + + @if(comment.action == "comment"){ + commented + } else { + @if(pullreq.isEmpty){ referenced the issue } else { referenced the pull request } + } + @helper.html.datetimeago(comment.registeredDate) + + + @if(comment.action != "commit" && comment.action != "merge" && comment.action != "refer" + && (hasWritePermission || loginAccount.map(_.userName == comment.commentedUserName).getOrElse(false))){ +   + + } + +
+
+ @if(comment.action == "commit" && comment.content.split(" ").last.matches("[a-f0-9]{40}")){ + @defining(comment.content.substring(comment.content.length - 40)){ id => + + @markdown(comment.content.substring(0, comment.content.length - 41), repository, false, true, true, hasWritePermission) } } else { - @markdown(comment.content, repository, false, true, true, hasWritePermission) + @if(comment.action == "refer"){ + @defining(comment.content.split(":")){ case Array(issueId, rest @ _*) => + Issue #@issueId: @rest.mkString(":") + } + } else { + @markdown(comment.content, repository, false, true, true, hasWritePermission) + } } +
+
+ } + @if(comment.action == "merge"){ +
+ Merged + @avatar(comment.commentedUserName, 20) + @user(comment.commentedUserName, styleClass="username strong") merged commit @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) + } + @helper.html.datetimeago(comment.registeredDate) +
+ } + @if(comment.action == "close" || comment.action == "close_comment"){ +
+ Closed + @avatar(comment.commentedUserName, 20) + @if(issue.isDefined && issue.get.isPullRequest){ + @user(comment.commentedUserName, styleClass="username strong") closed the pull request @helper.html.datetimeago(comment.registeredDate) + } else { + @user(comment.commentedUserName, styleClass="username strong") closed the issue @helper.html.datetimeago(comment.registeredDate) }
-
+ } + @if(comment.action == "reopen" || comment.action == "reopen_comment"){ +
+ Reopened + @avatar(comment.commentedUserName, 20) + @user(comment.commentedUserName, styleClass="username strong") reopened the issue @helper.html.datetimeago(comment.registeredDate) +
+ } + @if(comment.action == "delete_branch"){ +
+ Deleted + @avatar(comment.commentedUserName, 20) + @user(comment.commentedUserName, styleClass="username strong") deleted the @pullreq.map(_.requestBranch) branch @helper.html.datetimeago(comment.registeredDate) +
+ } } - @if(comment.action == "merge"){ -
- Merged - @avatar(comment.commentedUserName, 20) - @user(comment.commentedUserName, styleClass="username strong") merged commit @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) - } - @helper.html.datetimeago(comment.registeredDate) -
- } - @if(comment.action == "close" || comment.action == "close_comment"){ -
- Closed - @avatar(comment.commentedUserName, 20) - @if(issue.isPullRequest){ - @user(comment.commentedUserName, styleClass="username strong") closed the pull request @helper.html.datetimeago(comment.registeredDate) - } else { - @user(comment.commentedUserName, styleClass="username strong") closed the issue @helper.html.datetimeago(comment.registeredDate) - } -
- } - @if(comment.action == "reopen" || comment.action == "reopen_comment"){ -
- Reopened - @avatar(comment.commentedUserName, 20) - @user(comment.commentedUserName, styleClass="username strong") reopened the issue @helper.html.datetimeago(comment.registeredDate) -
- } - @if(comment.action == "delete_branch"){ -
- Deleted - @avatar(comment.commentedUserName, 20) - @user(comment.commentedUserName, styleClass="username strong") deleted the @pullreq.map(_.requestBranch) branch @helper.html.datetimeago(comment.registeredDate) -
+ case comment: model.CommitComment => { + @helper.html.commitcomment(comment, hasWritePermission, repository) } } diff --git a/src/main/twirl/issues/issue.scala.html b/src/main/twirl/issues/issue.scala.html index 5b43005..491c76d 100644 --- a/src/main/twirl/issues/issue.scala.html +++ b/src/main/twirl/issues/issue.scala.html @@ -47,7 +47,7 @@
- @commentlist(issue, comments, hasWritePermission, repository) + @commentlist(Some(issue), comments, hasWritePermission, repository) @commentform(issue, true, hasWritePermission, repository)
diff --git a/src/main/twirl/issues/issueinfo.scala.html b/src/main/twirl/issues/issueinfo.scala.html index 5de4600..0b1c5df 100644 --- a/src/main/twirl/issues/issueinfo.scala.html +++ b/src/main/twirl/issues/issueinfo.scala.html @@ -1,5 +1,5 @@ @(issue: model.Issue, - comments: List[model.IssueComment], + comments: List[model.Comment], issueLabels: List[model.Label], collaborators: List[String], milestones: List[(model.Milestone, Int, Int)], diff --git a/src/main/twirl/pulls/commits.scala.html b/src/main/twirl/pulls/commits.scala.html index fa18056..4bf9a60 100644 --- a/src/main/twirl/pulls/commits.scala.html +++ b/src/main/twirl/pulls/commits.scala.html @@ -1,4 +1,5 @@ @(commits: Seq[Seq[util.JGitUtil.CommitInfo]], + comments: Option[List[model.Comment]] = None, repository: service.RepositoryService.RepositoryInfo)(implicit context: app.Context) @import context._ @import view.helpers._ @@ -15,6 +16,14 @@ @user(commit.authorName, commit.authorEmailAddress, "username") @commit.shortMessage + + @if(comments.isDefined){ + @comments.get.flatMap @{ + case comment: model.CommitComment => Some(comment) + case other => None + }.filter(_.commitId == commit.id).size + } + @commit.id.substring(0, 7) diff --git a/src/main/twirl/pulls/compare.scala.html b/src/main/twirl/pulls/compare.scala.html index 7833131..844adc1 100644 --- a/src/main/twirl/pulls/compare.scala.html +++ b/src/main/twirl/pulls/compare.scala.html @@ -1,6 +1,7 @@ @(commits: Seq[Seq[util.JGitUtil.CommitInfo]], diffs: Seq[util.JGitUtil.DiffInfo], members: List[(String, String)], + comments: List[model.Comment], originId: String, forkedId: String, sourceId: String, @@ -81,8 +82,10 @@ } else { - @pulls.html.commits(commits, repository) - @helper.html.diff(diffs, repository, Some(commitId), Some(sourceId), true) + @pulls.html.commits(commits, Some(comments), repository) + @helper.html.diff(diffs, repository, Some(commitId), Some(sourceId), true, hasWritePermission, false) +

Showing you all comments on commits in this comparison.

+ @issues.html.commentlist(None, comments, hasWritePermission, repository, None) } } } diff --git a/src/main/twirl/pulls/conversation.scala.html b/src/main/twirl/pulls/conversation.scala.html index 70f40d4..33c923c 100644 --- a/src/main/twirl/pulls/conversation.scala.html +++ b/src/main/twirl/pulls/conversation.scala.html @@ -1,6 +1,6 @@ @(issue: model.Issue, pullreq: model.PullRequest, - comments: List[model.IssueComment], + comments: List[model.Comment], issueLabels: List[model.Label], collaborators: List[String], milestones: List[(model.Milestone, Int, Int)], @@ -8,11 +8,17 @@ hasWritePermission: Boolean, repository: service.RepositoryService.RepositoryInfo)(implicit context: app.Context) @import context._ +@import model.IssueComment @import view.helpers._
- @issues.html.commentlist(issue, comments, hasWritePermission, repository, Some(pullreq)) - @defining(comments.exists(_.action == "merge")){ merged => +
+ @issues.html.commentlist(Some(issue), comments, hasWritePermission, repository, Some(pullreq)) +
+ @defining(comments.flatMap { + case comment: IssueComment => Some(comment) + case other => None + }.exists(_.action == "merge")){ merged => @if(hasWritePermission && !issue.closed){
diff --git a/src/main/twirl/pulls/pullreq.scala.html b/src/main/twirl/pulls/pullreq.scala.html index 452ec52..cd22694 100644 --- a/src/main/twirl/pulls/pullreq.scala.html +++ b/src/main/twirl/pulls/pullreq.scala.html @@ -1,6 +1,6 @@ @(issue: model.Issue, pullreq: model.PullRequest, - comments: List[model.IssueComment], + comments: List[model.Comment], issueLabels: List[model.Label], collaborators: List[String], milestones: List[(model.Milestone, Int, Int)], @@ -36,7 +36,10 @@
@if(issue.closed) { - @comments.find(_.action == "merge").map{ comment => + @comments.flatMap @{ + case comment: model.IssueComment => Some(comment) + case _ => None + }.find(_.action == "merge").map{ comment => Merged @user(comment.commentedUserName, styleClass="username strong") merged @commits.size @plural(commits.size, "commit") @@ -59,7 +62,10 @@ }

@@ -68,10 +74,10 @@ @pulls.html.conversation(issue, pullreq, comments, issueLabels, collaborators, milestones, labels, hasWritePermission, repository)
- @pulls.html.commits(dayByDayCommits, repository) + @pulls.html.commits(dayByDayCommits, Some(comments), repository)
- @helper.html.diff(diffs, repository, Some(commits.head.id), Some(commits.last.id), true) + @helper.html.diff(diffs, repository, Some(commits.head.id), Some(commits.last.id), true, hasWritePermission, true)
} diff --git a/src/main/twirl/repo/commentform.scala.html b/src/main/twirl/repo/commentform.scala.html new file mode 100644 index 0000000..e9fe894 --- /dev/null +++ b/src/main/twirl/repo/commentform.scala.html @@ -0,0 +1,59 @@ +@(commitId: String, + fileName: Option[String] = None, + oldLineNumber: Option[Int] = None, + newLineNumber: Option[Int] = None, + hasWritePermission: Boolean, + repository: service.RepositoryService.RepositoryInfo)(implicit context: app.Context) +@import context._ +@import view.helpers._ +@if(loginAccount.isDefined){ + @if(!fileName.isDefined){

} +
+ @if(!fileName.isDefined){ +
@avatar(loginAccount.get.userName, 48)
+ } +
+
+ @helper.html.preview(repository, "", false, true, true, hasWritePermission, "width: 635px; height: 100px; max-height: 150px;", elastic = true) +
+ @if(fileName.isDefined){ +
+ + +
+ } +
+ @if(!fileName.isDefined){ +
+ +
+ } + @if(fileName.isDefined){} + @if(oldLineNumber.isDefined){} + @if(newLineNumber.isDefined){} +
+ +} diff --git a/src/main/twirl/repo/commit.scala.html b/src/main/twirl/repo/commit.scala.html index 9b7c2f0..cee46c2 100644 --- a/src/main/twirl/repo/commit.scala.html +++ b/src/main/twirl/repo/commit.scala.html @@ -2,9 +2,11 @@ commit: util.JGitUtil.CommitInfo, branches: List[String], tags: List[String], + comments: List[model.Comment], repository: service.RepositoryService.RepositoryInfo, diffs: Seq[util.JGitUtil.DiffInfo], - oldCommitId: Option[String])(implicit context: app.Context) + oldCommitId: Option[String], + hasWritePermission: Boolean)(implicit context: app.Context) @import context._ @import view.helpers._ @import util.Implicits._ @@ -81,7 +83,14 @@ - @helper.html.diff(diffs, repository, Some(commit.id), oldCommitId, true) + @helper.html.diff(diffs, repository, Some(commit.id), oldCommitId, true, hasWritePermission, true) + +
+ @issues.html.commentlist(None, comments, hasWritePermission, repository, None) +
+ @commentform(commitId = commitId, hasWritePermission = hasWritePermission, repository = repository) } }