mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-11-08 22:45:51 +01:00
Merge branch 'master' into #3_repository-search
This commit is contained in:
@@ -128,11 +128,15 @@ trait IssuesControllerBase extends ControllerBase {
|
||||
})
|
||||
|
||||
post("/:owner/:repository/issue_comments/new", commentForm)(readableUsersOnly { (form, repository) =>
|
||||
handleComment(form.issueId, Some(form.content), repository)
|
||||
handleComment(form.issueId, Some(form.content), repository)() map { id =>
|
||||
redirect("/%s/%s/issues/%d#comment-%d".format(repository.owner, repository.name, form.issueId, id))
|
||||
} getOrElse NotFound
|
||||
})
|
||||
|
||||
post("/:owner/:repository/issue_comments/state", issueStateForm)(readableUsersOnly { (form, repository) =>
|
||||
handleComment(form.issueId, form.content, repository)
|
||||
handleComment(form.issueId, form.content, repository)() map { id =>
|
||||
redirect("/%s/%s/issues/%d#comment-%d".format(repository.owner, repository.name, form.issueId, id))
|
||||
} getOrElse NotFound
|
||||
})
|
||||
|
||||
ajaxPost("/:owner/:repository/issue_comments/edit/:id", commentForm)(readableUsersOnly { (form, repository) =>
|
||||
@@ -197,79 +201,76 @@ trait IssuesControllerBase extends ControllerBase {
|
||||
})
|
||||
|
||||
ajaxPost("/:owner/:repository/issues/:id/assign")(collaboratorsOnly { repository =>
|
||||
updateAssignedUserName(repository.owner, repository.name, params("id").toInt,
|
||||
params.get("assignedUserName") filter (_.trim != ""))
|
||||
updateAssignedUserName(repository.owner, repository.name, params("id").toInt, assignedUserName("assignedUserName"))
|
||||
Ok("updated")
|
||||
})
|
||||
|
||||
ajaxPost("/:owner/:repository/issues/:id/milestone")(collaboratorsOnly { repository =>
|
||||
updateMilestoneId(repository.owner, repository.name, params("id").toInt,
|
||||
params.get("milestoneId") collect { case x if x.trim != "" => x.toInt })
|
||||
updateMilestoneId(repository.owner, repository.name, params("id").toInt, milestoneId("milestoneId"))
|
||||
Ok("updated")
|
||||
})
|
||||
|
||||
post("/:owner/:repository/issues/batchedit/state")(collaboratorsOnly { repository =>
|
||||
val owner = repository.owner
|
||||
val name = repository.name
|
||||
val userName = context.loginAccount.get.userName
|
||||
val action = params.get("value")
|
||||
|
||||
params.get("value") collect {
|
||||
case s if s == "close" => (s.capitalize, Some(s), true)
|
||||
case s if s == "reopen" => (s.capitalize, Some(s), false)
|
||||
} map { case (content, action, closed) =>
|
||||
params("checked").split(',') foreach { issueId =>
|
||||
createComment(owner, name, userName, issueId.toInt, content, action)
|
||||
updateClosed(owner, name, issueId.toInt, closed)
|
||||
}
|
||||
redirect("/%s/%s/issues".format(owner, name))
|
||||
} getOrElse NotFound
|
||||
executeBatch(repository) {
|
||||
handleComment(_, None, repository)( _ => action)
|
||||
}
|
||||
})
|
||||
|
||||
post("/:owner/:repository/issues/batchedit/label")(collaboratorsOnly { repository =>
|
||||
val owner = repository.owner
|
||||
val name = repository.name
|
||||
val labelId = params("value").toInt
|
||||
|
||||
params.get("value").map(_.toInt) map { labelId =>
|
||||
params("checked").split(',') foreach { issueId =>
|
||||
getIssueLabel(owner, name, issueId.toInt, labelId) getOrElse {
|
||||
registerIssueLabel(owner, name, issueId.toInt, labelId)
|
||||
}
|
||||
executeBatch(repository) { issueId =>
|
||||
getIssueLabel(repository.owner, repository.name, issueId, labelId) getOrElse {
|
||||
registerIssueLabel(repository.owner, repository.name, issueId, labelId)
|
||||
}
|
||||
redirect("/%s/%s/issues".format(owner, name))
|
||||
} getOrElse NotFound
|
||||
}
|
||||
})
|
||||
|
||||
post("/:owner/:repository/issues/batchedit/assign")(collaboratorsOnly { repository =>
|
||||
params("checked").split(',') foreach { issueId =>
|
||||
updateAssignedUserName(repository.owner, repository.name, issueId.toInt,
|
||||
params.get("value") filter (_.trim != ""))
|
||||
val value = assignedUserName("value")
|
||||
|
||||
executeBatch(repository) {
|
||||
updateAssignedUserName(repository.owner, repository.name, _, value)
|
||||
}
|
||||
redirect("/%s/%s/issues".format(repository.owner, repository.name))
|
||||
})
|
||||
|
||||
post("/:owner/:repository/issues/batchedit/milestone")(collaboratorsOnly { repository =>
|
||||
params("checked").split(',') foreach { issueId =>
|
||||
updateMilestoneId(repository.owner, repository.name, issueId.toInt,
|
||||
params.get("value") collect { case x if x.trim != "" => x.toInt })
|
||||
val value = milestoneId("value")
|
||||
|
||||
executeBatch(repository) {
|
||||
updateMilestoneId(repository.owner, repository.name, _, value)
|
||||
}
|
||||
redirect("/%s/%s/issues".format(repository.owner, repository.name))
|
||||
})
|
||||
|
||||
val assignedUserName = (key: String) => params.get(key) filter (_.trim != "")
|
||||
val milestoneId = (key: String) => params.get(key) collect { case x if x.trim != "" => x.toInt }
|
||||
|
||||
private def isEditable(owner: String, repository: String, author: String)(implicit context: app.Context): Boolean =
|
||||
hasWritePermission(owner, repository, context.loginAccount) || author == context.loginAccount.get.userName
|
||||
|
||||
private def handleComment(issueId: Int, content: Option[String], repository: RepositoryService.RepositoryInfo) = {
|
||||
private def executeBatch(repository: RepositoryService.RepositoryInfo)(execute: Int => Unit) = {
|
||||
params("checked").split(',') map(_.toInt) foreach execute
|
||||
redirect("/%s/%s/issues".format(repository.owner, repository.name))
|
||||
}
|
||||
|
||||
/**
|
||||
* @see
|
||||
*/
|
||||
private def handleComment(issueId: Int, content: Option[String], repository: RepositoryService.RepositoryInfo)
|
||||
(getAction: model.Issue => Option[String] =
|
||||
p1 => params.get("action").filter(_ => isEditable(p1.userName, p1.repositoryName, p1.openedUserName))) = {
|
||||
val owner = repository.owner
|
||||
val name = repository.name
|
||||
val userName = context.loginAccount.get.userName
|
||||
|
||||
getIssue(owner, name, issueId.toString) map { issue =>
|
||||
val (action, recordActivity) =
|
||||
params.get("action")
|
||||
.filter(_ => isEditable(owner, name, issue.openedUserName))
|
||||
getAction(issue)
|
||||
.collect {
|
||||
case s if s == "close" => true -> (Some(s) -> Some(recordCloseIssueActivity _))
|
||||
case s if s == "reopen" => false -> (Some(s) -> Some(recordReopenIssueActivity _))
|
||||
case "close" => true -> (Some("close") -> Some(recordCloseIssueActivity _))
|
||||
case "reopen" => false -> (Some("reopen") -> Some(recordReopenIssueActivity _))
|
||||
}
|
||||
.map { case (closed, t) =>
|
||||
updateClosed(owner, name, issueId, closed)
|
||||
@@ -277,14 +278,19 @@ trait IssuesControllerBase extends ControllerBase {
|
||||
}
|
||||
.getOrElse(None -> None)
|
||||
|
||||
val commentId = createComment(owner, name, userName, issueId, content.getOrElse(action.get.capitalize), action)
|
||||
val commentId = content
|
||||
.map ( _ -> action.map( _ + "_comment" ).getOrElse("comment") )
|
||||
.getOrElse ( action.get.capitalize -> action.get )
|
||||
match {
|
||||
case (content, action) => createComment(owner, name, userName, issueId, content, action)
|
||||
}
|
||||
|
||||
// record activity
|
||||
content foreach ( recordCommentIssueActivity(owner, name, userName, issueId, _) )
|
||||
recordActivity foreach ( _ (owner, name, userName, issueId, issue.title) )
|
||||
|
||||
redirect("/%s/%s/issues/%d#comment-%d".format(owner, name, issueId, commentId))
|
||||
} getOrElse NotFound
|
||||
commentId
|
||||
}
|
||||
}
|
||||
|
||||
private def searchIssues(filter: String, repository: RepositoryService.RepositoryInfo) = {
|
||||
|
||||
@@ -9,9 +9,9 @@ object IssueComments extends Table[IssueComment]("ISSUE_COMMENT") with IssueTemp
|
||||
def content = column[String]("CONTENT")
|
||||
def registeredDate = column[java.util.Date]("REGISTERED_DATE")
|
||||
def updatedDate = column[java.util.Date]("UPDATED_DATE")
|
||||
def * = userName ~ repositoryName ~ issueId ~ commentId ~ action.? ~ commentedUserName ~ content ~ registeredDate ~ updatedDate <> (IssueComment, IssueComment.unapply _)
|
||||
def * = userName ~ repositoryName ~ issueId ~ commentId ~ action ~ commentedUserName ~ content ~ registeredDate ~ updatedDate <> (IssueComment, IssueComment.unapply _)
|
||||
|
||||
def autoInc = userName ~ repositoryName ~ issueId ~ action.? ~ commentedUserName ~ content ~ registeredDate ~ updatedDate returning commentId
|
||||
def autoInc = userName ~ repositoryName ~ issueId ~ action ~ commentedUserName ~ content ~ registeredDate ~ updatedDate returning commentId
|
||||
def byPrimaryKey(commentId: Int) = this.commentId is commentId.bind
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ case class IssueComment(
|
||||
repositoryName: String,
|
||||
issueId: Int,
|
||||
commentId: Int,
|
||||
action: Option[String],
|
||||
action: String,
|
||||
commentedUserName: String,
|
||||
content: String,
|
||||
registeredDate: java.util.Date,
|
||||
|
||||
@@ -104,7 +104,10 @@ trait IssuesService {
|
||||
// get issues and comment count
|
||||
val issues = searchIssueQuery(owner, repository, condition, filter, userName)
|
||||
.leftJoin(Query(IssueComments)
|
||||
.filter { _.byRepository(owner, repository) }
|
||||
.filter { t =>
|
||||
(t.byRepository(owner, repository)) &&
|
||||
(t.action inSetBind Seq("comment", "close_comment", "reopen_comment"))
|
||||
}
|
||||
.groupBy { _.issueId }
|
||||
.map { case (issueId, t) => issueId ~ t.length }).on((t1, t2) => t1.issueId is t2._1)
|
||||
.sortBy { case (t1, t2) =>
|
||||
@@ -194,7 +197,7 @@ trait IssuesService {
|
||||
IssueLabels filter(_.byPrimaryKey(owner, repository, issueId, labelId)) delete
|
||||
|
||||
def createComment(owner: String, repository: String, loginUser: String,
|
||||
issueId: Int, content: String, action: Option[String]) =
|
||||
issueId: Int, content: String, action: String) =
|
||||
IssueComments.autoInc insert (
|
||||
owner,
|
||||
repository,
|
||||
|
||||
@@ -85,7 +85,7 @@ class CommitLogHook(owner: String, repository: String, userName: String) extends
|
||||
"(^|\\W)#(\\d+)(\\W|$)".r.findAllIn(commit.fullMessage).matchData.foreach { matchData =>
|
||||
val issueId = matchData.group(2)
|
||||
if(getAccountByUserName(commit.committer).isDefined && getIssue(owner, repository, issueId).isDefined){
|
||||
createComment(owner, repository, commit.committer, issueId.toInt, commit.fullMessage, Some("commit"))
|
||||
createComment(owner, repository, commit.committer, issueId.toInt, commit.fullMessage, "commit")
|
||||
}
|
||||
}
|
||||
Some(commit)
|
||||
|
||||
@@ -52,14 +52,21 @@ object JGitUtil {
|
||||
* @param id the commit id
|
||||
* @param time the commit time
|
||||
* @param committer the committer name
|
||||
* @param mailAddress the mail address of the committer
|
||||
* @param shortMessage the short message
|
||||
* @param fullMessage the full message
|
||||
* @param parents the list of parent commit id
|
||||
*/
|
||||
case class CommitInfo(id: String, time: Date, committer: String, shortMessage: String, fullMessage: String, parents: List[String]){
|
||||
case class CommitInfo(id: String, time: Date, committer: String, mailAddress: String,
|
||||
shortMessage: String, fullMessage: String, parents: List[String]){
|
||||
|
||||
def this(rev: org.eclipse.jgit.revwalk.RevCommit) = this(
|
||||
rev.getName, rev.getCommitterIdent.getWhen, rev.getCommitterIdent.getName, rev.getShortMessage, rev.getFullMessage,
|
||||
rev.getName,
|
||||
rev.getCommitterIdent.getWhen,
|
||||
rev.getCommitterIdent.getName,
|
||||
rev.getCommitterIdent.getEmailAddress,
|
||||
rev.getShortMessage,
|
||||
rev.getFullMessage,
|
||||
rev.getParents().map(_.name).toList)
|
||||
|
||||
val summary = {
|
||||
|
||||
@@ -10,16 +10,21 @@ trait AvatarImageProvider { self: RequestCache =>
|
||||
* Returns <img> which displays the avatar icon.
|
||||
* Looks up Gravatar if avatar icon has not been configured in user settings.
|
||||
*/
|
||||
protected def getAvatarImageHtml(userName: String, size: Int, tooltip: Boolean = false)(implicit context: app.Context): Html = {
|
||||
protected def getAvatarImageHtml(userName: String, size: Int,
|
||||
mailAddress: String = "", tooltip: Boolean = false)(implicit context: app.Context): Html = {
|
||||
val src = getAccountByUserName(userName).collect { case account if(account.image.isEmpty) =>
|
||||
s"""http://www.gravatar.com/avatar/${StringUtil.md5(account.mailAddress)}?s=${size}"""
|
||||
} getOrElse {
|
||||
s"""${context.path}/${userName}/_avatar"""
|
||||
if(mailAddress.nonEmpty){
|
||||
s"""http://www.gravatar.com/avatar/${StringUtil.md5(mailAddress)}?s=${size}"""
|
||||
} else {
|
||||
s"""${context.path}/${userName}/_avatar"""
|
||||
}
|
||||
}
|
||||
if(tooltip){
|
||||
Html(s"""<img src=${src} class="avatar" style="width: ${size}px; height: ${size}px;" data-toggle="tooltip" title=${userName}/>""")
|
||||
Html(s"""<img src="${src}" class="avatar" style="width: ${size}px; height: ${size}px;" data-toggle="tooltip" title=${userName}/>""")
|
||||
} else {
|
||||
Html(s"""<img src=${src} class="avatar" style="width: ${size}px; height: ${size}px;" />""")
|
||||
Html(s"""<img src="${src}" class="avatar" style="width: ${size}px; height: ${size}px;" />""")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,10 @@ object helpers extends AvatarImageProvider with LinkConverter with RequestCache
|
||||
* Looks up Gravatar if avatar icon has not been configured in user settings.
|
||||
*/
|
||||
def avatar(userName: String, size: Int, tooltip: Boolean = false)(implicit context: app.Context): Html =
|
||||
getAvatarImageHtml(userName, size, tooltip)
|
||||
getAvatarImageHtml(userName, size, "", tooltip)
|
||||
|
||||
def avatar(commit: util.JGitUtil.CommitInfo, size: Int)(implicit context: app.Context): Html =
|
||||
getAvatarImageHtml(commit.committer, size, commit.mailAddress)
|
||||
|
||||
/**
|
||||
* Converts commit id, issue id and username to the link.
|
||||
|
||||
Reference in New Issue
Block a user