mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-11-01 19:15:59 +01:00
update scalafmt
This commit is contained in:
@@ -1,12 +1,14 @@
|
||||
version = "1.5.1"
|
||||
version = "3.7.15"
|
||||
project.git = true
|
||||
|
||||
maxColumn = 120
|
||||
docstrings = JavaDoc
|
||||
docstrings.style = keep
|
||||
|
||||
align.tokens = ["%", "%%", {code = "=>", owner = "Case"}]
|
||||
align.openParenCallSite = false
|
||||
align.openParenDefnSite = false
|
||||
continuationIndent.callSite = 2
|
||||
continuationIndent.defnSite = 2
|
||||
danglingParentheses = true
|
||||
danglingParentheses.preset = true
|
||||
runner.dialect = scala213source3
|
||||
rewrite.trailingCommas.style = keep
|
||||
|
||||
95
build.sbt
95
build.sbt
@@ -30,47 +30,47 @@ resolvers ++= Seq(
|
||||
)
|
||||
|
||||
libraryDependencies ++= Seq(
|
||||
"org.eclipse.jgit" % "org.eclipse.jgit.http.server" % JgitVersion,
|
||||
"org.eclipse.jgit" % "org.eclipse.jgit.archive" % JgitVersion,
|
||||
"org.scalatra" %% "scalatra-javax" % ScalatraVersion,
|
||||
"org.scalatra" %% "scalatra-json-javax" % ScalatraVersion,
|
||||
"org.scalatra" %% "scalatra-forms-javax" % ScalatraVersion,
|
||||
"org.json4s" %% "json4s-jackson" % "4.0.6",
|
||||
"commons-io" % "commons-io" % "2.15.0",
|
||||
"io.github.gitbucket" % "solidbase" % "1.0.5",
|
||||
"io.github.gitbucket" % "markedj" % "1.0.18",
|
||||
"org.apache.commons" % "commons-compress" % "1.25.0",
|
||||
"org.apache.commons" % "commons-email" % "1.5",
|
||||
"commons-net" % "commons-net" % "3.10.0",
|
||||
"org.apache.httpcomponents" % "httpclient" % "4.5.14",
|
||||
"org.apache.sshd" % "apache-sshd" % "2.11.0" exclude ("org.slf4j", "slf4j-jdk14") exclude ("org.apache.sshd", "sshd-mina") exclude ("org.apache.sshd", "sshd-netty"),
|
||||
"org.apache.tika" % "tika-core" % "2.9.1",
|
||||
"com.github.takezoe" %% "blocking-slick" % "0.0.14",
|
||||
"com.novell.ldap" % "jldap" % "2009-10-07",
|
||||
"com.h2database" % "h2" % "1.4.199",
|
||||
"org.mariadb.jdbc" % "mariadb-java-client" % "2.7.6",
|
||||
"org.postgresql" % "postgresql" % "42.6.0",
|
||||
"ch.qos.logback" % "logback-classic" % "1.4.11",
|
||||
"com.zaxxer" % "HikariCP" % "4.0.3" exclude ("org.slf4j", "slf4j-api"),
|
||||
"com.typesafe" % "config" % "1.4.3",
|
||||
"fr.brouillard.oss.security.xhub" % "xhub4j-core" % "1.1.0",
|
||||
"io.github.java-diff-utils" % "java-diff-utils" % "4.12",
|
||||
"org.cache2k" % "cache2k-all" % "1.6.0.Final",
|
||||
"net.coobird" % "thumbnailator" % "0.4.20",
|
||||
"com.github.zafarkhaja" % "java-semver" % "0.9.0",
|
||||
"com.nimbusds" % "oauth2-oidc-sdk" % "11.6",
|
||||
"org.eclipse.jetty" % "jetty-webapp" % JettyVersion % "provided",
|
||||
"javax.servlet" % "javax.servlet-api" % "3.1.0" % "provided",
|
||||
"junit" % "junit" % "4.13.2" % "test",
|
||||
"org.scalatra" %% "scalatra-scalatest-javax" % ScalatraVersion % "test",
|
||||
"org.mockito" % "mockito-core" % "5.7.0" % "test",
|
||||
"com.dimafeng" %% "testcontainers-scala" % "0.41.0" % "test",
|
||||
"org.testcontainers" % "mysql" % "1.19.2" % "test",
|
||||
"org.testcontainers" % "postgresql" % "1.19.2" % "test",
|
||||
"net.i2p.crypto" % "eddsa" % "0.3.0",
|
||||
"is.tagomor.woothee" % "woothee-java" % "1.11.0",
|
||||
"org.ec4j.core" % "ec4j-core" % "0.3.0",
|
||||
"org.kohsuke" % "github-api" % "1.317" % "test"
|
||||
"org.eclipse.jgit" % "org.eclipse.jgit.http.server" % JgitVersion,
|
||||
"org.eclipse.jgit" % "org.eclipse.jgit.archive" % JgitVersion,
|
||||
"org.scalatra" %% "scalatra-javax" % ScalatraVersion,
|
||||
"org.scalatra" %% "scalatra-json-javax" % ScalatraVersion,
|
||||
"org.scalatra" %% "scalatra-forms-javax" % ScalatraVersion,
|
||||
"org.json4s" %% "json4s-jackson" % "4.0.6",
|
||||
"commons-io" % "commons-io" % "2.15.0",
|
||||
"io.github.gitbucket" % "solidbase" % "1.0.5",
|
||||
"io.github.gitbucket" % "markedj" % "1.0.18",
|
||||
"org.apache.commons" % "commons-compress" % "1.25.0",
|
||||
"org.apache.commons" % "commons-email" % "1.5",
|
||||
"commons-net" % "commons-net" % "3.10.0",
|
||||
"org.apache.httpcomponents" % "httpclient" % "4.5.14",
|
||||
"org.apache.sshd" % "apache-sshd" % "2.11.0" exclude ("org.slf4j", "slf4j-jdk14") exclude ("org.apache.sshd", "sshd-mina") exclude ("org.apache.sshd", "sshd-netty"),
|
||||
"org.apache.tika" % "tika-core" % "2.9.1",
|
||||
"com.github.takezoe" %% "blocking-slick" % "0.0.14",
|
||||
"com.novell.ldap" % "jldap" % "2009-10-07",
|
||||
"com.h2database" % "h2" % "1.4.199",
|
||||
"org.mariadb.jdbc" % "mariadb-java-client" % "2.7.6",
|
||||
"org.postgresql" % "postgresql" % "42.6.0",
|
||||
"ch.qos.logback" % "logback-classic" % "1.4.11",
|
||||
"com.zaxxer" % "HikariCP" % "4.0.3" exclude ("org.slf4j", "slf4j-api"),
|
||||
"com.typesafe" % "config" % "1.4.3",
|
||||
"fr.brouillard.oss.security.xhub" % "xhub4j-core" % "1.1.0",
|
||||
"io.github.java-diff-utils" % "java-diff-utils" % "4.12",
|
||||
"org.cache2k" % "cache2k-all" % "1.6.0.Final",
|
||||
"net.coobird" % "thumbnailator" % "0.4.20",
|
||||
"com.github.zafarkhaja" % "java-semver" % "0.9.0",
|
||||
"com.nimbusds" % "oauth2-oidc-sdk" % "11.6",
|
||||
"org.eclipse.jetty" % "jetty-webapp" % JettyVersion % "provided",
|
||||
"javax.servlet" % "javax.servlet-api" % "3.1.0" % "provided",
|
||||
"junit" % "junit" % "4.13.2" % "test",
|
||||
"org.scalatra" %% "scalatra-scalatest-javax" % ScalatraVersion % "test",
|
||||
"org.mockito" % "mockito-core" % "5.7.0" % "test",
|
||||
"com.dimafeng" %% "testcontainers-scala" % "0.41.0" % "test",
|
||||
"org.testcontainers" % "mysql" % "1.19.2" % "test",
|
||||
"org.testcontainers" % "postgresql" % "1.19.2" % "test",
|
||||
"net.i2p.crypto" % "eddsa" % "0.3.0",
|
||||
"is.tagomor.woothee" % "woothee-java" % "1.11.0",
|
||||
"org.ec4j.core" % "ec4j-core" % "0.3.0",
|
||||
"org.kohsuke" % "github-api" % "1.317" % "test"
|
||||
)
|
||||
|
||||
// Compiler settings
|
||||
@@ -115,8 +115,8 @@ assembly / assemblyMergeStrategy := {
|
||||
|
||||
// Exclude a war file from published artifacts
|
||||
signedArtifacts := {
|
||||
signedArtifacts.value.filterNot {
|
||||
case (_, file) => file.getName.endsWith(".war") || file.getName.endsWith(".war.asc")
|
||||
signedArtifacts.value.filterNot { case (_, file) =>
|
||||
file.getName.endsWith(".war") || file.getName.endsWith(".war.asc")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,10 +205,9 @@ executableKey := {
|
||||
"md5" -> "MD5",
|
||||
"sha1" -> "SHA-1",
|
||||
"sha256" -> "SHA-256"
|
||||
).foreach {
|
||||
case (extension, algorithm) =>
|
||||
val checksumFile = workDir / (warName + "." + extension)
|
||||
Checksums generate (outputFile, checksumFile, algorithm)
|
||||
).foreach { case (extension, algorithm) =>
|
||||
val checksumFile = workDir / (warName + "." + extension)
|
||||
Checksums generate (outputFile, checksumFile, algorithm)
|
||||
}
|
||||
|
||||
// done
|
||||
@@ -289,5 +288,5 @@ Jetty / javaOptions ++= Seq(
|
||||
"-Xdebug",
|
||||
"-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000",
|
||||
"-Dorg.eclipse.jetty.annotations.AnnotationParser.LEVEL=OFF",
|
||||
//"-Ddev-features=keep-session"
|
||||
// "-Ddev-features=keep-session"
|
||||
)
|
||||
|
||||
@@ -76,21 +76,20 @@ object GitBucketCoreModule
|
||||
import JDBCUtil._
|
||||
|
||||
val conn = context.get(Solidbase.CONNECTION).asInstanceOf[Connection]
|
||||
val list = conn.select("SELECT * FROM ACTIVITY ORDER BY ACTIVITY_ID") {
|
||||
rs =>
|
||||
Activity(
|
||||
activityId = UUID.randomUUID().toString,
|
||||
userName = rs.getString("USER_NAME"),
|
||||
repositoryName = rs.getString("REPOSITORY_NAME"),
|
||||
activityUserName = rs.getString("ACTIVITY_USER_NAME"),
|
||||
activityType = rs.getString("ACTIVITY_TYPE"),
|
||||
message = rs.getString("MESSAGE"),
|
||||
additionalInfo = {
|
||||
val additionalInfo = rs.getString("ADDITIONAL_INFO")
|
||||
if (rs.wasNull()) None else Some(additionalInfo)
|
||||
},
|
||||
activityDate = rs.getTimestamp("ACTIVITY_DATE")
|
||||
)
|
||||
val list = conn.select("SELECT * FROM ACTIVITY ORDER BY ACTIVITY_ID") { rs =>
|
||||
Activity(
|
||||
activityId = UUID.randomUUID().toString,
|
||||
userName = rs.getString("USER_NAME"),
|
||||
repositoryName = rs.getString("REPOSITORY_NAME"),
|
||||
activityUserName = rs.getString("ACTIVITY_USER_NAME"),
|
||||
activityType = rs.getString("ACTIVITY_TYPE"),
|
||||
message = rs.getString("MESSAGE"),
|
||||
additionalInfo = {
|
||||
val additionalInfo = rs.getString("ADDITIONAL_INFO")
|
||||
if (rs.wasNull()) None else Some(additionalInfo)
|
||||
},
|
||||
activityDate = rs.getTimestamp("ACTIVITY_DATE")
|
||||
)
|
||||
}
|
||||
Using.resource(new FileOutputStream(ActivityLog, true)) { out =>
|
||||
list.foreach { activity =>
|
||||
|
||||
@@ -66,16 +66,17 @@ object ApiBranchProtection {
|
||||
}
|
||||
}
|
||||
|
||||
implicit val enforcementLevelSerializer: CustomSerializer[EnforcementLevel] = new CustomSerializer[EnforcementLevel](
|
||||
format =>
|
||||
implicit val enforcementLevelSerializer: CustomSerializer[EnforcementLevel] =
|
||||
new CustomSerializer[EnforcementLevel](format =>
|
||||
(
|
||||
{
|
||||
case JString("off") => Off
|
||||
case JString("non_admins") => NonAdmins
|
||||
case JString("everyone") => Everyone
|
||||
}, {
|
||||
case x: EnforcementLevel => JString(x.name)
|
||||
},
|
||||
{ case x: EnforcementLevel =>
|
||||
JString(x.name)
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -14,7 +14,8 @@ case class ApiComment(id: Int, user: ApiUser, body: String, created_at: Date, up
|
||||
isPullRequest: Boolean
|
||||
) {
|
||||
val html_url = ApiPath(
|
||||
s"/${repositoryName.fullName}/${if (isPullRequest) { "pull" } else { "issues" }}/${issueId}#comment-${id}"
|
||||
s"/${repositoryName.fullName}/${if (isPullRequest) { "pull" }
|
||||
else { "issues" }}/${issueId}#comment-${id}"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,8 @@ object ApiCommits {
|
||||
}
|
||||
|
||||
File(
|
||||
filename = if (diff.changeType == ChangeType.DELETE) { diff.oldPath } else { diff.newPath },
|
||||
filename = if (diff.changeType == ChangeType.DELETE) { diff.oldPath }
|
||||
else { diff.newPath },
|
||||
additions = additions,
|
||||
deletions = deletions,
|
||||
changes = additions + deletions,
|
||||
@@ -106,7 +107,9 @@ object ApiCommits {
|
||||
message = commitInfo.shortMessage,
|
||||
comment_count = commentCount,
|
||||
tree = Tree(
|
||||
url = ApiPath(s"/api/v3/repos/${repositoryName.fullName}/tree/${commitInfo.id}"), // TODO This endpoint has not been implemented yet.
|
||||
url = ApiPath(
|
||||
s"/api/v3/repos/${repositoryName.fullName}/tree/${commitInfo.id}"
|
||||
), // TODO This endpoint has not been implemented yet.
|
||||
sha = commitInfo.id
|
||||
)
|
||||
),
|
||||
@@ -114,7 +117,9 @@ object ApiCommits {
|
||||
committer = ApiUser(committer),
|
||||
parents = commitInfo.parents.map { parent =>
|
||||
Tree(
|
||||
url = ApiPath(s"/api/v3/repos/${repositoryName.fullName}/tree/${parent}"), // TODO This endpoint has not been implemented yet.
|
||||
url = ApiPath(
|
||||
s"/api/v3/repos/${repositoryName.fullName}/tree/${parent}"
|
||||
), // TODO This endpoint has not been implemented yet.
|
||||
sha = parent
|
||||
)
|
||||
},
|
||||
|
||||
@@ -22,16 +22,15 @@ object ApiContents {
|
||||
ApiContents("dir", fileInfo.name, fileInfo.path, fileInfo.commitId, None, None)(repositoryName)
|
||||
} else {
|
||||
content
|
||||
.map(
|
||||
arr =>
|
||||
ApiContents(
|
||||
"file",
|
||||
fileInfo.name,
|
||||
fileInfo.path,
|
||||
fileInfo.id.getName,
|
||||
Some(Base64.getEncoder.encodeToString(arr)),
|
||||
Some("base64")
|
||||
)(repositoryName)
|
||||
.map(arr =>
|
||||
ApiContents(
|
||||
"file",
|
||||
fileInfo.name,
|
||||
fileInfo.path,
|
||||
fileInfo.id.getName,
|
||||
Some(Base64.getEncoder.encodeToString(arr)),
|
||||
Some("base64")
|
||||
)(repositoryName)
|
||||
)
|
||||
.getOrElse(ApiContents("file", fileInfo.name, fileInfo.path, fileInfo.commitId, None, None)(repositoryName))
|
||||
}
|
||||
|
||||
@@ -23,7 +23,8 @@ case class ApiIssue(
|
||||
val id = 0 // dummy id
|
||||
val assignee = assignees.headOption
|
||||
val comments_url = ApiPath(s"/api/v3/repos/${repositoryName.fullName}/issues/${number}/comments")
|
||||
val html_url = ApiPath(s"/${repositoryName.fullName}/${if (isPullRequest) { "pull" } else { "issues" }}/${number}")
|
||||
val html_url = ApiPath(s"/${repositoryName.fullName}/${if (isPullRequest) { "pull" }
|
||||
else { "issues" }}/${number}")
|
||||
val pull_request = if (isPullRequest) {
|
||||
Some(
|
||||
Map(
|
||||
@@ -54,7 +55,8 @@ object ApiIssue {
|
||||
assignees = assignees,
|
||||
labels = labels,
|
||||
milestone = milestone,
|
||||
state = if (issue.closed) { "closed" } else { "open" },
|
||||
state = if (issue.closed) { "closed" }
|
||||
else { "open" },
|
||||
body = issue.content.getOrElse(""),
|
||||
created_at = issue.registeredDate,
|
||||
updated_at = issue.updatedDate
|
||||
|
||||
@@ -27,10 +27,10 @@ case class ApiPullRequest(
|
||||
val id = 0 // dummy id
|
||||
val assignee = assignees.headOption
|
||||
val html_url = ApiPath(s"${base.repo.html_url.path}/pull/${number}")
|
||||
//val diff_url = ApiPath(s"${base.repo.html_url.path}/pull/${number}.diff")
|
||||
//val patch_url = ApiPath(s"${base.repo.html_url.path}/pull/${number}.patch")
|
||||
// val diff_url = ApiPath(s"${base.repo.html_url.path}/pull/${number}.diff")
|
||||
// val patch_url = ApiPath(s"${base.repo.html_url.path}/pull/${number}.patch")
|
||||
val url = ApiPath(s"${base.repo.url.path}/pulls/${number}")
|
||||
//val issue_url = ApiPath(s"${base.repo.url.path}/issues/${number}")
|
||||
// val issue_url = ApiPath(s"${base.repo.url.path}/issues/${number}")
|
||||
val commits_url = ApiPath(s"${base.repo.url.path}/pulls/${number}/commits")
|
||||
val review_comments_url = ApiPath(s"${base.repo.url.path}/pulls/${number}/comments")
|
||||
val review_comment_url = ApiPath(s"${base.repo.url.path}/pulls/comments/{number}")
|
||||
@@ -69,7 +69,8 @@ object ApiPullRequest {
|
||||
)
|
||||
|
||||
case class Commit(sha: String, ref: String, repo: ApiRepository)(baseOwner: String) {
|
||||
val label = if (baseOwner == repo.owner.login) { ref } else { s"${repo.owner.login}:${ref}" }
|
||||
val label = if (baseOwner == repo.owner.login) { ref }
|
||||
else { s"${repo.owner.login}:${ref}" }
|
||||
val user = repo.owner
|
||||
}
|
||||
|
||||
|
||||
@@ -40,12 +40,12 @@ object ApiRef {
|
||||
ApiRef(
|
||||
ref = s"refs/tags/${tagInfo.name}",
|
||||
url = ApiPath(s"/api/v3/repos/${repositoryName.fullName}/git/refs/tags/${tagInfo.name}"),
|
||||
//the GH api distinguishes between "releases" and plain git tags
|
||||
//for "releases", the api returns a reference to the release object (with type `tag`)
|
||||
//this would be something like s"/api/v3/repos/${repositoryName.fullName}/git/tags/<hash-of-tag>"
|
||||
//with a hash for the tag, which I do not fully understand
|
||||
//since this is not yet implemented in GB, we always return a link to the plain `commit` object,
|
||||
//which GH does for tags that are not annotated
|
||||
// the GH api distinguishes between "releases" and plain git tags
|
||||
// for "releases", the api returns a reference to the release object (with type `tag`)
|
||||
// this would be something like s"/api/v3/repos/${repositoryName.fullName}/git/tags/<hash-of-tag>"
|
||||
// with a hash for the tag, which I do not fully understand
|
||||
// since this is not yet implemented in GB, we always return a link to the plain `commit` object,
|
||||
// which GH does for tags that are not annotated
|
||||
`object` = ApiRefCommit(
|
||||
sha = tagInfo.objectId,
|
||||
url = ApiPath(s"/api/v3/repos/${repositoryName.fullName}/commits/${tagInfo.objectId}"),
|
||||
|
||||
@@ -24,7 +24,8 @@ object ApiUser {
|
||||
def apply(user: Account): ApiUser = ApiUser(
|
||||
login = user.userName,
|
||||
email = user.mailAddress,
|
||||
`type` = if (user.isGroupAccount) { "Organization" } else { "User" },
|
||||
`type` = if (user.isGroupAccount) { "Organization" }
|
||||
else { "User" },
|
||||
site_admin = user.isAdmin,
|
||||
created_at = user.registeredDate
|
||||
)
|
||||
|
||||
@@ -15,13 +15,12 @@ object JsonFormat {
|
||||
|
||||
val parserISO = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'")
|
||||
|
||||
val jsonFormats = Serialization.formats(NoTypeHints) + new CustomSerializer[Date](
|
||||
format =>
|
||||
(
|
||||
{
|
||||
case JString(s) =>
|
||||
Try(Date.from(Instant.parse(s))).getOrElse(throw new MappingException("Can't convert " + s + " to Date"))
|
||||
}, { case x: Date => JString(OffsetDateTime.ofInstant(x.toInstant, ZoneId.of("UTC")).format(parserISO)) }
|
||||
val jsonFormats = Serialization.formats(NoTypeHints) + new CustomSerializer[Date](format =>
|
||||
(
|
||||
{ case JString(s) =>
|
||||
Try(Date.from(Instant.parse(s))).getOrElse(throw new MappingException("Can't convert " + s + " to Date"))
|
||||
},
|
||||
{ case x: Date => JString(OffsetDateTime.ofInstant(x.toInstant, ZoneId.of("UTC")).format(parserISO)) }
|
||||
)
|
||||
) + FieldSerializer[ApiUser]() +
|
||||
FieldSerializer[ApiGroup]() +
|
||||
@@ -48,29 +47,32 @@ object JsonFormat {
|
||||
ApiBranchProtection.enforcementLevelSerializer
|
||||
|
||||
def apiPathSerializer(c: Context) =
|
||||
new CustomSerializer[ApiPath](
|
||||
_ =>
|
||||
({
|
||||
new CustomSerializer[ApiPath](_ =>
|
||||
(
|
||||
{
|
||||
case JString(s) if s.startsWith(c.baseUrl) => ApiPath(s.substring(c.baseUrl.length))
|
||||
case JString(s) => throw new MappingException("Can't convert " + s + " to ApiPath")
|
||||
}, {
|
||||
case ApiPath(path) => JString(c.baseUrl + path)
|
||||
})
|
||||
},
|
||||
{ case ApiPath(path) =>
|
||||
JString(c.baseUrl + path)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
def sshPathSerializer(c: Context) =
|
||||
new CustomSerializer[SshPath](
|
||||
_ =>
|
||||
({
|
||||
new CustomSerializer[SshPath](_ =>
|
||||
(
|
||||
{
|
||||
case JString(s) if c.sshUrl.exists(sshUrl => s.startsWith(sshUrl)) =>
|
||||
SshPath(s.substring(c.sshUrl.get.length))
|
||||
case JString(s) => throw new MappingException("Can't convert " + s + " to ApiPath")
|
||||
}, {
|
||||
case SshPath(path) =>
|
||||
c.sshUrl.map { sshUrl =>
|
||||
JString(sshUrl + path)
|
||||
} getOrElse JNothing
|
||||
})
|
||||
},
|
||||
{ case SshPath(path) =>
|
||||
c.sshUrl.map { sshUrl =>
|
||||
JString(sshUrl + path)
|
||||
} getOrElse JNothing
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
/**
|
||||
|
||||
@@ -215,9 +215,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
"events" -> accountWebhookEvents,
|
||||
"ctype" -> label("ctype", text()),
|
||||
"token" -> optional(trim(label("token", text(maxlength(100)))))
|
||||
)(
|
||||
(url, events, ctype, token) => AccountWebHookForm(url, events, WebHookContentType.valueOf(ctype), token)
|
||||
)
|
||||
)((url, events, ctype, token) => AccountWebHookForm(url, events, WebHookContentType.valueOf(ctype), token))
|
||||
|
||||
/**
|
||||
* Provides duplication check for web hook url. duplicated from RepositorySettingsController.scala
|
||||
@@ -340,22 +338,21 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
|
||||
post("/:userName/_edit", editForm)(oneselfOnly { form =>
|
||||
val userName = params("userName")
|
||||
getAccountByUserName(userName).map {
|
||||
account =>
|
||||
updateAccount(
|
||||
account.copy(
|
||||
password = form.password.map(pbkdf2_sha256).getOrElse(account.password),
|
||||
fullName = form.fullName,
|
||||
mailAddress = form.mailAddress,
|
||||
description = form.description,
|
||||
url = form.url
|
||||
)
|
||||
getAccountByUserName(userName).map { account =>
|
||||
updateAccount(
|
||||
account.copy(
|
||||
password = form.password.map(pbkdf2_sha256).getOrElse(account.password),
|
||||
fullName = form.fullName,
|
||||
mailAddress = form.mailAddress,
|
||||
description = form.description,
|
||||
url = form.url
|
||||
)
|
||||
)
|
||||
|
||||
updateImage(userName, form.fileId, form.clearImage)
|
||||
updateAccountExtraMailAddresses(userName, form.extraMailAddresses.filter(_ != ""))
|
||||
flash.update("info", "Account information has been updated.")
|
||||
redirect(s"/${userName}/_edit")
|
||||
updateImage(userName, form.fileId, form.clearImage)
|
||||
updateAccountExtraMailAddresses(userName, form.extraMailAddresses.filter(_ != ""))
|
||||
flash.update("info", "Account information has been updated.")
|
||||
redirect(s"/${userName}/_edit")
|
||||
|
||||
} getOrElse NotFound()
|
||||
})
|
||||
@@ -363,12 +360,11 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
get("/:userName/_delete")(oneselfOnly {
|
||||
val userName = params("userName")
|
||||
|
||||
getAccountByUserName(userName, true).map {
|
||||
account =>
|
||||
if (isLastAdministrator(account)) {
|
||||
flash.update("error", "Account can't be removed because this is last one administrator.")
|
||||
redirect(s"/${userName}/_edit")
|
||||
} else {
|
||||
getAccountByUserName(userName, true).map { account =>
|
||||
if (isLastAdministrator(account)) {
|
||||
flash.update("error", "Account can't be removed because this is last one administrator.")
|
||||
redirect(s"/${userName}/_edit")
|
||||
} else {
|
||||
// // Remove repositories
|
||||
// getRepositoryNamesOfUser(userName).foreach { repositoryName =>
|
||||
// deleteRepository(userName, repositoryName)
|
||||
@@ -376,10 +372,10 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
// FileUtils.deleteDirectory(getWikiRepositoryDir(userName, repositoryName))
|
||||
// FileUtils.deleteDirectory(getTemporaryDir(userName, repositoryName))
|
||||
// }
|
||||
suspendAccount(account)
|
||||
session.invalidate
|
||||
redirect("/")
|
||||
}
|
||||
suspendAccount(account)
|
||||
session.invalidate
|
||||
redirect("/")
|
||||
}
|
||||
} getOrElse NotFound()
|
||||
})
|
||||
|
||||
@@ -406,7 +402,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
get("/:userName/_gpg")(oneselfOnly {
|
||||
val userName = params("userName")
|
||||
getAccountByUserName(userName).map { x =>
|
||||
//html.ssh(x, getPublicKeys(x.userName))
|
||||
// html.ssh(x, getPublicKeys(x.userName))
|
||||
html.gpg(x, getGpgPublicKeys(x.userName))
|
||||
} getOrElse NotFound()
|
||||
})
|
||||
@@ -525,9 +521,8 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
get("/:userName/_hooks/edit")(managersOnly {
|
||||
val userName = params("userName")
|
||||
getAccountByUserName(userName).flatMap { account =>
|
||||
getAccountWebHook(userName, params("url")).map {
|
||||
case (webhook, events) =>
|
||||
html.edithook(webhook, events, account, false)
|
||||
getAccountWebHook(userName, params("url")).map { case (webhook, events) =>
|
||||
html.edithook(webhook, events, account, false)
|
||||
}
|
||||
} getOrElse NotFound()
|
||||
})
|
||||
@@ -584,11 +579,10 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
"url" -> url,
|
||||
"request" -> Await.result(
|
||||
reqFuture
|
||||
.map(
|
||||
req =>
|
||||
Map(
|
||||
"headers" -> _headers(req.getAllHeaders),
|
||||
"payload" -> json
|
||||
.map(req =>
|
||||
Map(
|
||||
"headers" -> _headers(req.getAllHeaders),
|
||||
"payload" -> json
|
||||
)
|
||||
)
|
||||
.recover(toErrorMap),
|
||||
@@ -596,12 +590,11 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
),
|
||||
"response" -> Await.result(
|
||||
resFuture
|
||||
.map(
|
||||
res =>
|
||||
Map(
|
||||
"status" -> res.getStatusLine(),
|
||||
"body" -> EntityUtils.toString(res.getEntity()),
|
||||
"headers" -> _headers(res.getAllHeaders())
|
||||
.map(res =>
|
||||
Map(
|
||||
"status" -> res.getStatusLine(),
|
||||
"body" -> EntityUtils.toString(res.getEntity()),
|
||||
"headers" -> _headers(res.getAllHeaders())
|
||||
)
|
||||
)
|
||||
.recover(toErrorMap),
|
||||
@@ -788,83 +781,83 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
* Create new repository.
|
||||
*/
|
||||
post("/new", newRepositoryForm)(usersOnly { form =>
|
||||
context.withLoginAccount {
|
||||
loginAccount =>
|
||||
if (context.settings.basicBehavior.repositoryOperation.create || loginAccount.isAdmin) {
|
||||
LockUtil.lock(s"${form.owner}/${form.name}") {
|
||||
if (getRepository(form.owner, form.name).isDefined) {
|
||||
// redirect to the repository if repository already exists
|
||||
redirect(s"/${form.owner}/${form.name}")
|
||||
} else if (!canCreateRepository(form.owner, loginAccount)) {
|
||||
// Permission error
|
||||
Forbidden()
|
||||
} else {
|
||||
// create repository asynchronously
|
||||
createRepository(
|
||||
loginAccount,
|
||||
form.owner,
|
||||
form.name,
|
||||
form.description,
|
||||
form.isPrivate,
|
||||
form.initOption,
|
||||
form.sourceUrl,
|
||||
context.settings.defaultBranch
|
||||
)
|
||||
// redirect to the repository
|
||||
redirect(s"/${form.owner}/${form.name}")
|
||||
}
|
||||
context.withLoginAccount { loginAccount =>
|
||||
if (context.settings.basicBehavior.repositoryOperation.create || loginAccount.isAdmin) {
|
||||
LockUtil.lock(s"${form.owner}/${form.name}") {
|
||||
if (getRepository(form.owner, form.name).isDefined) {
|
||||
// redirect to the repository if repository already exists
|
||||
redirect(s"/${form.owner}/${form.name}")
|
||||
} else if (!canCreateRepository(form.owner, loginAccount)) {
|
||||
// Permission error
|
||||
Forbidden()
|
||||
} else {
|
||||
// create repository asynchronously
|
||||
createRepository(
|
||||
loginAccount,
|
||||
form.owner,
|
||||
form.name,
|
||||
form.description,
|
||||
form.isPrivate,
|
||||
form.initOption,
|
||||
form.sourceUrl,
|
||||
context.settings.defaultBranch
|
||||
)
|
||||
// redirect to the repository
|
||||
redirect(s"/${form.owner}/${form.name}")
|
||||
}
|
||||
} else Forbidden()
|
||||
}
|
||||
} else Forbidden()
|
||||
}
|
||||
})
|
||||
|
||||
get("/:owner/:repository/fork")(readableUsersOnly { repository =>
|
||||
context.withLoginAccount {
|
||||
loginAccount =>
|
||||
if (repository.repository.options.allowFork && (context.settings.basicBehavior.repositoryOperation.fork || loginAccount.isAdmin)) {
|
||||
val loginUserName = loginAccount.userName
|
||||
val groups = getGroupsByUserName(loginUserName)
|
||||
groups match {
|
||||
case _: List[String] =>
|
||||
val managerPermissions = groups.map { group =>
|
||||
val members = getGroupMembers(group)
|
||||
context.loginAccount.exists(
|
||||
x =>
|
||||
members.exists { member =>
|
||||
member.userName == x.userName && member.isManager
|
||||
}
|
||||
)
|
||||
}
|
||||
helper.html.forkrepository(
|
||||
repository,
|
||||
(groups zip managerPermissions).sortBy(_._1)
|
||||
context.withLoginAccount { loginAccount =>
|
||||
if (
|
||||
repository.repository.options.allowFork && (context.settings.basicBehavior.repositoryOperation.fork || loginAccount.isAdmin)
|
||||
) {
|
||||
val loginUserName = loginAccount.userName
|
||||
val groups = getGroupsByUserName(loginUserName)
|
||||
groups match {
|
||||
case _: List[String] =>
|
||||
val managerPermissions = groups.map { group =>
|
||||
val members = getGroupMembers(group)
|
||||
context.loginAccount.exists(x =>
|
||||
members.exists { member =>
|
||||
member.userName == x.userName && member.isManager
|
||||
}
|
||||
)
|
||||
case _ => redirect(s"/${loginUserName}")
|
||||
}
|
||||
} else BadRequest()
|
||||
}
|
||||
helper.html.forkrepository(
|
||||
repository,
|
||||
(groups zip managerPermissions).sortBy(_._1)
|
||||
)
|
||||
case _ => redirect(s"/${loginUserName}")
|
||||
}
|
||||
} else BadRequest()
|
||||
}
|
||||
})
|
||||
|
||||
post("/:owner/:repository/fork", accountForm)(readableUsersOnly { (form, repository) =>
|
||||
context.withLoginAccount {
|
||||
loginAccount =>
|
||||
if (repository.repository.options.allowFork && (context.settings.basicBehavior.repositoryOperation.fork || loginAccount.isAdmin)) {
|
||||
val loginUserName = loginAccount.userName
|
||||
val accountName = form.accountName
|
||||
context.withLoginAccount { loginAccount =>
|
||||
if (
|
||||
repository.repository.options.allowFork && (context.settings.basicBehavior.repositoryOperation.fork || loginAccount.isAdmin)
|
||||
) {
|
||||
val loginUserName = loginAccount.userName
|
||||
val accountName = form.accountName
|
||||
|
||||
if (getRepository(accountName, repository.name).isDefined) {
|
||||
// redirect to the repository if repository already exists
|
||||
redirect(s"/${accountName}/${repository.name}")
|
||||
} else if (!canCreateRepository(accountName, loginAccount)) {
|
||||
// Permission error
|
||||
Forbidden()
|
||||
} else {
|
||||
// fork repository asynchronously
|
||||
forkRepository(accountName, repository, loginUserName)
|
||||
// redirect to the repository
|
||||
redirect(s"/${accountName}/${repository.name}")
|
||||
}
|
||||
} else Forbidden()
|
||||
if (getRepository(accountName, repository.name).isDefined) {
|
||||
// redirect to the repository if repository already exists
|
||||
redirect(s"/${accountName}/${repository.name}")
|
||||
} else if (!canCreateRepository(accountName, loginAccount)) {
|
||||
// Permission error
|
||||
Forbidden()
|
||||
} else {
|
||||
// fork repository asynchronously
|
||||
forkRepository(accountName, repository, loginUserName)
|
||||
// redirect to the repository
|
||||
redirect(s"/${accountName}/${repository.name}")
|
||||
}
|
||||
} else Forbidden()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -891,9 +884,11 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
|
||||
private def members: Constraint = new Constraint() {
|
||||
override def validate(name: String, value: String, messages: Messages): Option[String] = {
|
||||
if (value.split(",").exists {
|
||||
_.split(":") match { case Array(userName, isManager) => isManager.toBoolean }
|
||||
}) None
|
||||
if (
|
||||
value.split(",").exists {
|
||||
_.split(":") match { case Array(userName, isManager) => isManager.toBoolean }
|
||||
}
|
||||
) None
|
||||
else Some("Must select one manager at least.")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -423,10 +423,11 @@ trait AccountManagementControllerBase extends ControllerBase {
|
||||
messages: Messages
|
||||
): Option[String] = {
|
||||
val extraMailAddresses = params.view.filterKeys(k => k.startsWith("extraMailAddresses"))
|
||||
if (extraMailAddresses.exists {
|
||||
case (k, v) =>
|
||||
v.contains(value)
|
||||
}) {
|
||||
if (
|
||||
extraMailAddresses.exists { case (k, v) =>
|
||||
v.contains(value)
|
||||
}
|
||||
) {
|
||||
Some("These mail addresses are duplicated.")
|
||||
} else {
|
||||
getAccountByMailAddress(value, true)
|
||||
@@ -446,10 +447,11 @@ trait AccountManagementControllerBase extends ControllerBase {
|
||||
messages: Messages
|
||||
): Option[String] = {
|
||||
val extraMailAddresses = params.view.filterKeys(k => k.startsWith("extraMailAddresses"))
|
||||
if (Some(value) == params.optionValue("mailAddress") || extraMailAddresses.count {
|
||||
case (k, v) =>
|
||||
v.contains(value)
|
||||
} > 1) {
|
||||
if (
|
||||
Some(value) == params.optionValue("mailAddress") || extraMailAddresses.count { case (k, v) =>
|
||||
v.contains(value)
|
||||
} > 1
|
||||
) {
|
||||
Some("These mail addresses are duplicated.")
|
||||
} else {
|
||||
getAccountByMailAddress(value, true)
|
||||
|
||||
@@ -75,59 +75,57 @@ class FileUploadController
|
||||
post("/wiki/:owner/:repository") {
|
||||
setMultipartConfig()
|
||||
// Don't accept not logged-in users
|
||||
session.get(Keys.Session.LoginAccount).collect {
|
||||
case loginAccount: Account =>
|
||||
val owner = params("owner")
|
||||
val repository = params("repository")
|
||||
session.get(Keys.Session.LoginAccount).collect { case loginAccount: Account =>
|
||||
val owner = params("owner")
|
||||
val repository = params("repository")
|
||||
|
||||
// Check whether logged-in user is collaborator
|
||||
onlyWikiEditable(owner, repository, loginAccount) {
|
||||
execute(
|
||||
{ (file, fileId) =>
|
||||
val fileName = file.getName
|
||||
LockUtil.lock(s"${owner}/${repository}/wiki") {
|
||||
Using.resource(Git.open(Directory.getWikiRepositoryDir(owner, repository))) {
|
||||
git =>
|
||||
val builder = DirCache.newInCore.builder()
|
||||
val inserter = git.getRepository.newObjectInserter()
|
||||
val headId = git.getRepository.resolve(Constants.HEAD + "^{commit}")
|
||||
// Check whether logged-in user is collaborator
|
||||
onlyWikiEditable(owner, repository, loginAccount) {
|
||||
execute(
|
||||
{ (file, fileId) =>
|
||||
val fileName = file.getName
|
||||
LockUtil.lock(s"${owner}/${repository}/wiki") {
|
||||
Using.resource(Git.open(Directory.getWikiRepositoryDir(owner, repository))) { git =>
|
||||
val builder = DirCache.newInCore.builder()
|
||||
val inserter = git.getRepository.newObjectInserter()
|
||||
val headId = git.getRepository.resolve(Constants.HEAD + "^{commit}")
|
||||
|
||||
if (headId != null) {
|
||||
JGitUtil.processTree(git, headId) { (path, tree) =>
|
||||
if (path != fileName) {
|
||||
builder.add(JGitUtil.createDirCacheEntry(path, tree.getEntryFileMode, tree.getEntryObjectId))
|
||||
}
|
||||
}
|
||||
if (headId != null) {
|
||||
JGitUtil.processTree(git, headId) { (path, tree) =>
|
||||
if (path != fileName) {
|
||||
builder.add(JGitUtil.createDirCacheEntry(path, tree.getEntryFileMode, tree.getEntryObjectId))
|
||||
}
|
||||
|
||||
val bytes = IOUtils.toByteArray(file.getInputStream)
|
||||
builder.add(
|
||||
JGitUtil.createDirCacheEntry(
|
||||
fileName,
|
||||
FileMode.REGULAR_FILE,
|
||||
inserter.insert(Constants.OBJ_BLOB, bytes)
|
||||
)
|
||||
)
|
||||
builder.finish()
|
||||
|
||||
val newHeadId = JGitUtil.createNewCommit(
|
||||
git,
|
||||
inserter,
|
||||
headId,
|
||||
builder.getDirCache.writeTree(inserter),
|
||||
Constants.HEAD,
|
||||
loginAccount.fullName,
|
||||
loginAccount.mailAddress,
|
||||
s"Uploaded ${fileName}"
|
||||
)
|
||||
|
||||
fileName
|
||||
}
|
||||
}
|
||||
|
||||
val bytes = IOUtils.toByteArray(file.getInputStream)
|
||||
builder.add(
|
||||
JGitUtil.createDirCacheEntry(
|
||||
fileName,
|
||||
FileMode.REGULAR_FILE,
|
||||
inserter.insert(Constants.OBJ_BLOB, bytes)
|
||||
)
|
||||
)
|
||||
builder.finish()
|
||||
|
||||
val newHeadId = JGitUtil.createNewCommit(
|
||||
git,
|
||||
inserter,
|
||||
headId,
|
||||
builder.getDirCache.writeTree(inserter),
|
||||
Constants.HEAD,
|
||||
loginAccount.fullName,
|
||||
loginAccount.mailAddress,
|
||||
s"Uploaded ${fileName}"
|
||||
)
|
||||
|
||||
fileName
|
||||
}
|
||||
},
|
||||
_ => true
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => true
|
||||
)
|
||||
}
|
||||
} getOrElse BadRequest()
|
||||
}
|
||||
|
||||
@@ -135,20 +133,19 @@ class FileUploadController
|
||||
setMultipartConfigForLargeFile()
|
||||
session
|
||||
.get(Keys.Session.LoginAccount)
|
||||
.collect {
|
||||
case _: Account =>
|
||||
val owner = params("owner")
|
||||
val repository = params("repository")
|
||||
val tag = multiParams("splat").head
|
||||
execute(
|
||||
{ (file, fileId) =>
|
||||
FileUtils.writeByteArrayToFile(
|
||||
new File(getReleaseFilesDir(owner, repository), FileUtil.checkFilename(tag + "/" + fileId)),
|
||||
file.get()
|
||||
)
|
||||
},
|
||||
_ => true
|
||||
)
|
||||
.collect { case _: Account =>
|
||||
val owner = params("owner")
|
||||
val repository = params("repository")
|
||||
val tag = multiParams("splat").head
|
||||
execute(
|
||||
{ (file, fileId) =>
|
||||
FileUtils.writeByteArrayToFile(
|
||||
new File(getReleaseFilesDir(owner, repository), FileUtil.checkFilename(tag + "/" + fileId)),
|
||||
file.get()
|
||||
)
|
||||
},
|
||||
_ => true
|
||||
)
|
||||
}
|
||||
.getOrElse(BadRequest())
|
||||
}
|
||||
@@ -158,9 +155,12 @@ class FileUploadController
|
||||
setMultipartConfig()
|
||||
session.get(Keys.Session.LoginAccount).collect {
|
||||
case loginAccount: Account if loginAccount.isAdmin =>
|
||||
execute({ (file, fileId) =>
|
||||
request2Session(request).conn.importAsSQL(file.getInputStream)
|
||||
}, _ => true)
|
||||
execute(
|
||||
{ (file, fileId) =>
|
||||
request2Session(request).conn.importAsSQL(file.getInputStream)
|
||||
},
|
||||
_ => true
|
||||
)
|
||||
}
|
||||
redirect("/admin/data")
|
||||
}
|
||||
|
||||
@@ -151,10 +151,9 @@ trait IndexControllerBase extends ControllerBase {
|
||||
val redirectURI = new URI(s"$baseUrl/signin/oidc")
|
||||
session.get(Keys.Session.OidcAuthContext) match {
|
||||
case Some(context: OidcAuthContext) =>
|
||||
authenticate(params.toMap, redirectURI, context.state, context.nonce, oidc).map {
|
||||
case (jwt, account) =>
|
||||
session.setAttribute(Keys.Session.OidcSessionContext, OidcSessionContext(jwt))
|
||||
signin(account, context.redirectBackURI)
|
||||
authenticate(params.toMap, redirectURI, context.state, context.nonce, oidc).map { case (jwt, account) =>
|
||||
session.setAttribute(Keys.Session.OidcSessionContext, OidcSessionContext(jwt))
|
||||
signin(account, context.redirectBackURI)
|
||||
} orElse {
|
||||
flash.update("error", "Sorry, authentication failed. Please try again.")
|
||||
session.invalidate()
|
||||
@@ -172,12 +171,11 @@ trait IndexControllerBase extends ControllerBase {
|
||||
|
||||
get("/signout") {
|
||||
context.settings.oidc.foreach { oidc =>
|
||||
session.get(Keys.Session.OidcSessionContext).foreach {
|
||||
case context: OidcSessionContext =>
|
||||
val redirectURI = new URI(baseUrl)
|
||||
val authenticationRequest = createOIDLogoutRequest(oidc.issuer, oidc.clientID, redirectURI, context.token)
|
||||
session.invalidate()
|
||||
redirect(authenticationRequest.toURI.toString)
|
||||
session.get(Keys.Session.OidcSessionContext).foreach { case context: OidcSessionContext =>
|
||||
val redirectURI = new URI(baseUrl)
|
||||
val authenticationRequest = createOIDLogoutRequest(oidc.issuer, oidc.clientID, redirectURI, context.token)
|
||||
session.invalidate()
|
||||
redirect(authenticationRequest.toURI.toString)
|
||||
}
|
||||
}
|
||||
session.invalidate()
|
||||
@@ -244,9 +242,9 @@ trait IndexControllerBase extends ControllerBase {
|
||||
.map { t =>
|
||||
Map(
|
||||
"label" -> s"${avatar(t.userName, 16)}<b>@${StringUtil.escapeHtml(
|
||||
StringUtil.cutTail(t.userName, 25, "...")
|
||||
)}</b> ${StringUtil
|
||||
.escapeHtml(StringUtil.cutTail(t.fullName, 25, "..."))}",
|
||||
StringUtil.cutTail(t.userName, 25, "...")
|
||||
)}</b> ${StringUtil
|
||||
.escapeHtml(StringUtil.cutTail(t.fullName, 25, "..."))}",
|
||||
"value" -> t.userName
|
||||
)
|
||||
}
|
||||
@@ -269,12 +267,13 @@ trait IndexControllerBase extends ControllerBase {
|
||||
get("/:owner/:repository/search")(referrersOnly { repository =>
|
||||
val query = params.getOrElse("q", "").trim
|
||||
val target = params.getOrElse("type", "code")
|
||||
val page = try {
|
||||
val i = params.getOrElse("page", "1").toInt
|
||||
if (i <= 0) 1 else i
|
||||
} catch {
|
||||
case _: NumberFormatException => 1
|
||||
}
|
||||
val page =
|
||||
try {
|
||||
val i = params.getOrElse("page", "1").toInt
|
||||
if (i <= 0) 1 else i
|
||||
} catch {
|
||||
case _: NumberFormatException => 1
|
||||
}
|
||||
|
||||
target.toLowerCase match {
|
||||
case "issues" =>
|
||||
|
||||
@@ -101,27 +101,26 @@ trait IssuesControllerBase extends ControllerBase {
|
||||
|
||||
get("/:owner/:repository/issues/:id")(referrersOnly { repository =>
|
||||
val issueId = params("id")
|
||||
getIssue(repository.owner, repository.name, issueId) map {
|
||||
issue =>
|
||||
if (issue.isPullRequest) {
|
||||
redirect(s"/${repository.owner}/${repository.name}/pull/${issueId}")
|
||||
} else {
|
||||
html.issue(
|
||||
issue,
|
||||
getComments(repository.owner, repository.name, issueId.toInt),
|
||||
getIssueLabels(repository.owner, repository.name, issueId.toInt),
|
||||
getIssueAssignees(repository.owner, repository.name, issueId.toInt),
|
||||
getAssignableUserNames(repository.owner, repository.name),
|
||||
getMilestonesWithIssueCount(repository.owner, repository.name),
|
||||
getPriorities(repository.owner, repository.name),
|
||||
getLabels(repository.owner, repository.name),
|
||||
getCustomFieldsWithValue(repository.owner, repository.name, issueId.toInt).filter(_._1.enableForIssues),
|
||||
isIssueEditable(repository),
|
||||
isIssueManageable(repository),
|
||||
isIssueCommentManageable(repository),
|
||||
repository
|
||||
)
|
||||
}
|
||||
getIssue(repository.owner, repository.name, issueId) map { issue =>
|
||||
if (issue.isPullRequest) {
|
||||
redirect(s"/${repository.owner}/${repository.name}/pull/${issueId}")
|
||||
} else {
|
||||
html.issue(
|
||||
issue,
|
||||
getComments(repository.owner, repository.name, issueId.toInt),
|
||||
getIssueLabels(repository.owner, repository.name, issueId.toInt),
|
||||
getIssueAssignees(repository.owner, repository.name, issueId.toInt),
|
||||
getAssignableUserNames(repository.owner, repository.name),
|
||||
getMilestonesWithIssueCount(repository.owner, repository.name),
|
||||
getPriorities(repository.owner, repository.name),
|
||||
getLabels(repository.owner, repository.name),
|
||||
getCustomFieldsWithValue(repository.owner, repository.name, issueId.toInt).filter(_._1.enableForIssues),
|
||||
isIssueEditable(repository),
|
||||
isIssueManageable(repository),
|
||||
isIssueCommentManageable(repository),
|
||||
repository
|
||||
)
|
||||
}
|
||||
} getOrElse NotFound()
|
||||
})
|
||||
|
||||
@@ -142,130 +141,120 @@ trait IssuesControllerBase extends ControllerBase {
|
||||
})
|
||||
|
||||
post("/:owner/:repository/issues/new", issueCreateForm)(readableUsersOnly { (form, repository) =>
|
||||
context.withLoginAccount {
|
||||
loginAccount =>
|
||||
if (isIssueEditable(repository)) { // TODO Should this check is provided by authenticator?
|
||||
val issue = createIssue(
|
||||
repository,
|
||||
form.title,
|
||||
form.content,
|
||||
form.assigneeUserNames.toSeq.flatMap(_.split(",")),
|
||||
form.milestoneId,
|
||||
form.priorityId,
|
||||
form.labelNames.toSeq.flatMap(_.split(",")),
|
||||
loginAccount
|
||||
)
|
||||
context.withLoginAccount { loginAccount =>
|
||||
if (isIssueEditable(repository)) { // TODO Should this check is provided by authenticator?
|
||||
val issue = createIssue(
|
||||
repository,
|
||||
form.title,
|
||||
form.content,
|
||||
form.assigneeUserNames.toSeq.flatMap(_.split(",")),
|
||||
form.milestoneId,
|
||||
form.priorityId,
|
||||
form.labelNames.toSeq.flatMap(_.split(",")),
|
||||
loginAccount
|
||||
)
|
||||
|
||||
// Insert custom field values
|
||||
params.toMap.foreach {
|
||||
case (key, value) =>
|
||||
if (key.startsWith("custom-field-")) {
|
||||
getCustomField(
|
||||
repository.owner,
|
||||
repository.name,
|
||||
key.replaceFirst("^custom-field-", "").toInt
|
||||
).foreach { field =>
|
||||
CustomFieldBehavior.validate(field, value, messages) match {
|
||||
case None =>
|
||||
insertOrUpdateCustomFieldValue(field, repository.owner, repository.name, issue.issueId, value)
|
||||
case Some(_) => halt(400)
|
||||
}
|
||||
}
|
||||
// Insert custom field values
|
||||
params.toMap.foreach { case (key, value) =>
|
||||
if (key.startsWith("custom-field-")) {
|
||||
getCustomField(
|
||||
repository.owner,
|
||||
repository.name,
|
||||
key.replaceFirst("^custom-field-", "").toInt
|
||||
).foreach { field =>
|
||||
CustomFieldBehavior.validate(field, value, messages) match {
|
||||
case None =>
|
||||
insertOrUpdateCustomFieldValue(field, repository.owner, repository.name, issue.issueId, value)
|
||||
case Some(_) => halt(400)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
redirect(s"/${issue.userName}/${issue.repositoryName}/issues/${issue.issueId}")
|
||||
} else Unauthorized()
|
||||
redirect(s"/${issue.userName}/${issue.repositoryName}/issues/${issue.issueId}")
|
||||
} else Unauthorized()
|
||||
}
|
||||
})
|
||||
|
||||
ajaxPost("/:owner/:repository/issues/edit_title/:id", issueTitleEditForm)(readableUsersOnly { (title, repository) =>
|
||||
context.withLoginAccount {
|
||||
loginAccount =>
|
||||
getIssue(repository.owner, repository.name, params("id")).map {
|
||||
issue =>
|
||||
if (isEditableContent(repository.owner, repository.name, issue.openedUserName, loginAccount)) {
|
||||
if (issue.title != title) {
|
||||
// update issue
|
||||
updateIssue(repository.owner, repository.name, issue.issueId, title, issue.content)
|
||||
// extract references and create refer comment
|
||||
createReferComment(repository.owner, repository.name, issue.copy(title = title), title, loginAccount)
|
||||
createComment(
|
||||
repository.owner,
|
||||
repository.name,
|
||||
loginAccount.userName,
|
||||
issue.issueId,
|
||||
issue.title + "\r\n" + title,
|
||||
"change_title"
|
||||
)
|
||||
}
|
||||
redirect(s"/${repository.owner}/${repository.name}/issues/_data/${issue.issueId}")
|
||||
} else Unauthorized()
|
||||
} getOrElse NotFound()
|
||||
context.withLoginAccount { loginAccount =>
|
||||
getIssue(repository.owner, repository.name, params("id")).map { issue =>
|
||||
if (isEditableContent(repository.owner, repository.name, issue.openedUserName, loginAccount)) {
|
||||
if (issue.title != title) {
|
||||
// update issue
|
||||
updateIssue(repository.owner, repository.name, issue.issueId, title, issue.content)
|
||||
// extract references and create refer comment
|
||||
createReferComment(repository.owner, repository.name, issue.copy(title = title), title, loginAccount)
|
||||
createComment(
|
||||
repository.owner,
|
||||
repository.name,
|
||||
loginAccount.userName,
|
||||
issue.issueId,
|
||||
issue.title + "\r\n" + title,
|
||||
"change_title"
|
||||
)
|
||||
}
|
||||
redirect(s"/${repository.owner}/${repository.name}/issues/_data/${issue.issueId}")
|
||||
} else Unauthorized()
|
||||
} getOrElse NotFound()
|
||||
}
|
||||
})
|
||||
|
||||
ajaxPost("/:owner/:repository/issues/edit/:id", issueEditForm)(readableUsersOnly { (content, repository) =>
|
||||
context.withLoginAccount {
|
||||
loginAccount =>
|
||||
getIssue(repository.owner, repository.name, params("id")).map { issue =>
|
||||
if (isEditableContent(repository.owner, repository.name, issue.openedUserName, loginAccount)) {
|
||||
// update issue
|
||||
updateIssue(repository.owner, repository.name, issue.issueId, issue.title, content)
|
||||
// extract references and create refer comment
|
||||
createReferComment(repository.owner, repository.name, issue, content.getOrElse(""), loginAccount)
|
||||
context.withLoginAccount { loginAccount =>
|
||||
getIssue(repository.owner, repository.name, params("id")).map { issue =>
|
||||
if (isEditableContent(repository.owner, repository.name, issue.openedUserName, loginAccount)) {
|
||||
// update issue
|
||||
updateIssue(repository.owner, repository.name, issue.issueId, issue.title, content)
|
||||
// extract references and create refer comment
|
||||
createReferComment(repository.owner, repository.name, issue, content.getOrElse(""), loginAccount)
|
||||
|
||||
redirect(s"/${repository.owner}/${repository.name}/issues/_data/${issue.issueId}")
|
||||
} else Unauthorized()
|
||||
} getOrElse NotFound()
|
||||
redirect(s"/${repository.owner}/${repository.name}/issues/_data/${issue.issueId}")
|
||||
} else Unauthorized()
|
||||
} getOrElse NotFound()
|
||||
}
|
||||
})
|
||||
|
||||
post("/:owner/:repository/issue_comments/new", commentForm)(readableUsersOnly { (form, repository) =>
|
||||
context.withLoginAccount {
|
||||
loginAccount =>
|
||||
getIssue(repository.owner, repository.name, form.issueId.toString).flatMap { issue =>
|
||||
val actionOpt =
|
||||
params
|
||||
.get("action")
|
||||
.filter(_ => isEditableContent(issue.userName, issue.repositoryName, issue.openedUserName, loginAccount))
|
||||
handleComment(issue, Some(form.content), repository, actionOpt) map {
|
||||
case (issue, id) =>
|
||||
redirect(
|
||||
s"/${repository.owner}/${repository.name}/${if (issue.isPullRequest) "pull" else "issues"}/${form.issueId}#comment-${id}"
|
||||
)
|
||||
}
|
||||
} getOrElse NotFound()
|
||||
context.withLoginAccount { loginAccount =>
|
||||
getIssue(repository.owner, repository.name, form.issueId.toString).flatMap { issue =>
|
||||
val actionOpt =
|
||||
params
|
||||
.get("action")
|
||||
.filter(_ => isEditableContent(issue.userName, issue.repositoryName, issue.openedUserName, loginAccount))
|
||||
handleComment(issue, Some(form.content), repository, actionOpt) map { case (issue, id) =>
|
||||
redirect(
|
||||
s"/${repository.owner}/${repository.name}/${if (issue.isPullRequest) "pull" else "issues"}/${form.issueId}#comment-${id}"
|
||||
)
|
||||
}
|
||||
} getOrElse NotFound()
|
||||
}
|
||||
})
|
||||
|
||||
post("/:owner/:repository/issue_comments/state", issueStateForm)(readableUsersOnly { (form, repository) =>
|
||||
context.withLoginAccount {
|
||||
loginAccount =>
|
||||
getIssue(repository.owner, repository.name, form.issueId.toString).flatMap { issue =>
|
||||
val actionOpt =
|
||||
params
|
||||
.get("action")
|
||||
.filter(_ => isEditableContent(issue.userName, issue.repositoryName, issue.openedUserName, loginAccount))
|
||||
handleComment(issue, form.content, repository, actionOpt) map {
|
||||
case (issue, id) =>
|
||||
redirect(
|
||||
s"/${repository.owner}/${repository.name}/${if (issue.isPullRequest) "pull" else "issues"}/${form.issueId}#comment-${id}"
|
||||
)
|
||||
}
|
||||
} getOrElse NotFound()
|
||||
context.withLoginAccount { loginAccount =>
|
||||
getIssue(repository.owner, repository.name, form.issueId.toString).flatMap { issue =>
|
||||
val actionOpt =
|
||||
params
|
||||
.get("action")
|
||||
.filter(_ => isEditableContent(issue.userName, issue.repositoryName, issue.openedUserName, loginAccount))
|
||||
handleComment(issue, form.content, repository, actionOpt) map { case (issue, id) =>
|
||||
redirect(
|
||||
s"/${repository.owner}/${repository.name}/${if (issue.isPullRequest) "pull" else "issues"}/${form.issueId}#comment-${id}"
|
||||
)
|
||||
}
|
||||
} getOrElse NotFound()
|
||||
}
|
||||
})
|
||||
|
||||
ajaxPost("/:owner/:repository/issue_comments/edit/:id", commentForm)(readableUsersOnly { (form, repository) =>
|
||||
context.withLoginAccount {
|
||||
loginAccount =>
|
||||
getComment(repository.owner, repository.name, params("id")).map { comment =>
|
||||
if (isEditableContent(repository.owner, repository.name, comment.commentedUserName, loginAccount)) {
|
||||
updateComment(repository.owner, repository.name, comment.issueId, comment.commentId, form.content)
|
||||
redirect(s"/${repository.owner}/${repository.name}/issue_comments/_data/${comment.commentId}")
|
||||
} else Unauthorized()
|
||||
} getOrElse NotFound()
|
||||
context.withLoginAccount { loginAccount =>
|
||||
getComment(repository.owner, repository.name, params("id")).map { comment =>
|
||||
if (isEditableContent(repository.owner, repository.name, comment.commentedUserName, loginAccount)) {
|
||||
updateComment(repository.owner, repository.name, comment.issueId, comment.commentId, form.content)
|
||||
redirect(s"/${repository.owner}/${repository.name}/issue_comments/_data/${comment.commentId}")
|
||||
} else Unauthorized()
|
||||
} getOrElse NotFound()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -280,65 +269,61 @@ trait IssuesControllerBase extends ControllerBase {
|
||||
})
|
||||
|
||||
ajaxGet("/:owner/:repository/issues/_data/:id")(readableUsersOnly { repository =>
|
||||
context.withLoginAccount {
|
||||
loginAccount =>
|
||||
getIssue(repository.owner, repository.name, params("id")) map {
|
||||
x =>
|
||||
if (isEditableContent(x.userName, x.repositoryName, x.openedUserName, loginAccount)) {
|
||||
params.get("dataType") collect {
|
||||
case t if t == "html" => html.editissue(x.content, x.issueId, repository)
|
||||
} getOrElse {
|
||||
contentType = formats("json")
|
||||
org.json4s.jackson.Serialization.write(
|
||||
Map(
|
||||
"title" -> x.title,
|
||||
"content" -> Markdown.toHtml(
|
||||
markdown = x.content getOrElse "No description given.",
|
||||
repository = repository,
|
||||
branch = repository.repository.defaultBranch,
|
||||
enableWikiLink = false,
|
||||
enableRefsLink = true,
|
||||
enableAnchor = true,
|
||||
enableLineBreaks = true,
|
||||
enableTaskList = true,
|
||||
hasWritePermission = true
|
||||
)
|
||||
)
|
||||
context.withLoginAccount { loginAccount =>
|
||||
getIssue(repository.owner, repository.name, params("id")) map { x =>
|
||||
if (isEditableContent(x.userName, x.repositoryName, x.openedUserName, loginAccount)) {
|
||||
params.get("dataType") collect {
|
||||
case t if t == "html" => html.editissue(x.content, x.issueId, repository)
|
||||
} getOrElse {
|
||||
contentType = formats("json")
|
||||
org.json4s.jackson.Serialization.write(
|
||||
Map(
|
||||
"title" -> x.title,
|
||||
"content" -> Markdown.toHtml(
|
||||
markdown = x.content getOrElse "No description given.",
|
||||
repository = repository,
|
||||
branch = repository.repository.defaultBranch,
|
||||
enableWikiLink = false,
|
||||
enableRefsLink = true,
|
||||
enableAnchor = true,
|
||||
enableLineBreaks = true,
|
||||
enableTaskList = true,
|
||||
hasWritePermission = true
|
||||
)
|
||||
}
|
||||
} else Unauthorized()
|
||||
} getOrElse NotFound()
|
||||
)
|
||||
)
|
||||
}
|
||||
} else Unauthorized()
|
||||
} getOrElse NotFound()
|
||||
}
|
||||
})
|
||||
|
||||
ajaxGet("/:owner/:repository/issue_comments/_data/:id")(readableUsersOnly { repository =>
|
||||
context.withLoginAccount {
|
||||
loginAccount =>
|
||||
getComment(repository.owner, repository.name, params("id")) map {
|
||||
x =>
|
||||
if (isEditableContent(x.userName, x.repositoryName, x.commentedUserName, loginAccount)) {
|
||||
params.get("dataType") collect {
|
||||
case t if t == "html" => html.editcomment(x.content, x.commentId, repository)
|
||||
} getOrElse {
|
||||
contentType = formats("json")
|
||||
org.json4s.jackson.Serialization.write(
|
||||
Map(
|
||||
"content" -> view.Markdown.toHtml(
|
||||
markdown = x.content,
|
||||
repository = repository,
|
||||
branch = repository.repository.defaultBranch,
|
||||
enableWikiLink = false,
|
||||
enableRefsLink = true,
|
||||
enableAnchor = true,
|
||||
enableLineBreaks = true,
|
||||
enableTaskList = true,
|
||||
hasWritePermission = true
|
||||
)
|
||||
)
|
||||
context.withLoginAccount { loginAccount =>
|
||||
getComment(repository.owner, repository.name, params("id")) map { x =>
|
||||
if (isEditableContent(x.userName, x.repositoryName, x.commentedUserName, loginAccount)) {
|
||||
params.get("dataType") collect {
|
||||
case t if t == "html" => html.editcomment(x.content, x.commentId, repository)
|
||||
} getOrElse {
|
||||
contentType = formats("json")
|
||||
org.json4s.jackson.Serialization.write(
|
||||
Map(
|
||||
"content" -> view.Markdown.toHtml(
|
||||
markdown = x.content,
|
||||
repository = repository,
|
||||
branch = repository.repository.defaultBranch,
|
||||
enableWikiLink = false,
|
||||
enableRefsLink = true,
|
||||
enableAnchor = true,
|
||||
enableLineBreaks = true,
|
||||
enableTaskList = true,
|
||||
hasWritePermission = true
|
||||
)
|
||||
}
|
||||
} else Unauthorized()
|
||||
} getOrElse NotFound()
|
||||
)
|
||||
)
|
||||
}
|
||||
} else Unauthorized()
|
||||
} getOrElse NotFound()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -377,9 +362,8 @@ trait IssuesControllerBase extends ControllerBase {
|
||||
milestoneId("milestoneId").map { milestoneId =>
|
||||
getMilestonesWithIssueCount(repository.owner, repository.name)
|
||||
.find(_._1.milestoneId == milestoneId)
|
||||
.map {
|
||||
case (_, openCount, closeCount) =>
|
||||
gitbucket.core.issues.milestones.html.progress(openCount + closeCount, closeCount)
|
||||
.map { case (_, openCount, closeCount) =>
|
||||
gitbucket.core.issues.milestones.html.progress(openCount + closeCount, closeCount)
|
||||
} getOrElse NotFound()
|
||||
} getOrElse Ok()
|
||||
})
|
||||
@@ -460,7 +444,7 @@ trait IssuesControllerBase extends ControllerBase {
|
||||
post("/:owner/:repository/issues/batchedit/assign")(writableUsersOnly { repository =>
|
||||
val value = assignedUserName("value")
|
||||
executeBatch(repository) {
|
||||
//updateAssignedUserName(repository.owner, repository.name, _, value, true)
|
||||
// updateAssignedUserName(repository.owner, repository.name, _, value, true)
|
||||
value match {
|
||||
case Some(assignedUserName) =>
|
||||
registerIssueAssignee(repository.owner, repository.name, _, assignedUserName, true)
|
||||
@@ -510,9 +494,9 @@ trait IssuesControllerBase extends ControllerBase {
|
||||
.map { t =>
|
||||
Map(
|
||||
"label" -> s"""${if (t.isPullRequest) "<i class='octicon octicon-git-pull-request'></i>"
|
||||
else "<i class='octicon octicon-issue-opened'></i>"}<b> #${StringUtil
|
||||
.escapeHtml(t.issueId.toString)} ${StringUtil
|
||||
.escapeHtml(StringUtil.cutTail(t.title, 50, "..."))}</b>""",
|
||||
else "<i class='octicon octicon-issue-opened'></i>"}<b> #${StringUtil
|
||||
.escapeHtml(t.issueId.toString)} ${StringUtil
|
||||
.escapeHtml(StringUtil.cutTail(t.title, 50, "..."))}</b>""",
|
||||
"value" -> t.issueId.toString
|
||||
)
|
||||
}
|
||||
@@ -565,8 +549,8 @@ trait IssuesControllerBase extends ControllerBase {
|
||||
/**
|
||||
* Tests whether an issue or a comment is editable by a logged-in user.
|
||||
*/
|
||||
private def isEditableContent(owner: String, repository: String, author: String, loginAccount: Account)(
|
||||
implicit context: Context
|
||||
private def isEditableContent(owner: String, repository: String, author: String, loginAccount: Account)(implicit
|
||||
context: Context
|
||||
): Boolean = {
|
||||
hasDeveloperRole(owner, repository, context.loginAccount) || author == loginAccount.userName
|
||||
}
|
||||
@@ -574,8 +558,8 @@ trait IssuesControllerBase extends ControllerBase {
|
||||
/**
|
||||
* Tests whether an issue comment is deletable by a logged-in user.
|
||||
*/
|
||||
private def isDeletableComment(owner: String, repository: String, author: String, loginAccount: Account)(
|
||||
implicit context: Context
|
||||
private def isDeletableComment(owner: String, repository: String, author: String, loginAccount: Account)(implicit
|
||||
context: Context
|
||||
): Boolean = {
|
||||
hasOwnerRole(owner, repository, context.loginAccount) || author == loginAccount.userName
|
||||
}
|
||||
|
||||
@@ -30,12 +30,14 @@ trait PreProcessControllerBase extends ControllerBase {
|
||||
* But if it's not allowed, demands authentication except some paths.
|
||||
*/
|
||||
get(!context.settings.basicBehavior.allowAnonymousAccess, context.loginAccount.isEmpty) {
|
||||
if (!context.currentPath.startsWith("/assets") && !context.currentPath.startsWith("/signin") &&
|
||||
!context.currentPath.startsWith("/register") && !context.currentPath.endsWith("/info/refs") &&
|
||||
!context.currentPath.startsWith("/plugin-assets") &&
|
||||
!PluginRegistry().getAnonymousAccessiblePaths().exists { path =>
|
||||
context.currentPath.startsWith(path)
|
||||
}) {
|
||||
if (
|
||||
!context.currentPath.startsWith("/assets") && !context.currentPath.startsWith("/signin") &&
|
||||
!context.currentPath.startsWith("/register") && !context.currentPath.endsWith("/info/refs") &&
|
||||
!context.currentPath.startsWith("/plugin-assets") &&
|
||||
!PluginRegistry().getAnonymousAccessiblePaths().exists { path =>
|
||||
context.currentPath.startsWith(path)
|
||||
}
|
||||
) {
|
||||
Unauthorized()
|
||||
} else {
|
||||
pass()
|
||||
|
||||
@@ -113,149 +113,141 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
})
|
||||
|
||||
get("/:owner/:repository/pull/:id")(referrersOnly { repository =>
|
||||
params("id").toIntOpt.flatMap {
|
||||
issueId =>
|
||||
getPullRequest(repository.owner, repository.name, issueId) map {
|
||||
case (issue, pullreq) =>
|
||||
val (commits, diffs) =
|
||||
getRequestCompareInfo(
|
||||
repository.owner,
|
||||
repository.name,
|
||||
pullreq.commitIdFrom,
|
||||
repository.owner,
|
||||
repository.name,
|
||||
pullreq.commitIdTo
|
||||
)
|
||||
params("id").toIntOpt.flatMap { issueId =>
|
||||
getPullRequest(repository.owner, repository.name, issueId) map { case (issue, pullreq) =>
|
||||
val (commits, diffs) =
|
||||
getRequestCompareInfo(
|
||||
repository.owner,
|
||||
repository.name,
|
||||
pullreq.commitIdFrom,
|
||||
repository.owner,
|
||||
repository.name,
|
||||
pullreq.commitIdTo
|
||||
)
|
||||
|
||||
html.conversation(
|
||||
issue,
|
||||
pullreq,
|
||||
commits.flatten,
|
||||
getPullRequestComments(repository.owner, repository.name, issue.issueId, commits.flatten),
|
||||
diffs.size,
|
||||
getIssueLabels(repository.owner, repository.name, issueId),
|
||||
getIssueAssignees(repository.owner, repository.name, issueId),
|
||||
getAssignableUserNames(repository.owner, repository.name),
|
||||
getMilestonesWithIssueCount(repository.owner, repository.name),
|
||||
getPriorities(repository.owner, repository.name),
|
||||
getLabels(repository.owner, repository.name),
|
||||
getCustomFieldsWithValue(repository.owner, repository.name, issueId).filter(_._1.enableForPullRequests),
|
||||
isEditable(repository),
|
||||
isManageable(repository),
|
||||
hasDeveloperRole(pullreq.requestUserName, pullreq.requestRepositoryName, context.loginAccount),
|
||||
repository,
|
||||
getRepository(pullreq.requestUserName, pullreq.requestRepositoryName),
|
||||
flash.iterator.map(f => f._1 -> f._2.toString).toMap
|
||||
)
|
||||
}
|
||||
html.conversation(
|
||||
issue,
|
||||
pullreq,
|
||||
commits.flatten,
|
||||
getPullRequestComments(repository.owner, repository.name, issue.issueId, commits.flatten),
|
||||
diffs.size,
|
||||
getIssueLabels(repository.owner, repository.name, issueId),
|
||||
getIssueAssignees(repository.owner, repository.name, issueId),
|
||||
getAssignableUserNames(repository.owner, repository.name),
|
||||
getMilestonesWithIssueCount(repository.owner, repository.name),
|
||||
getPriorities(repository.owner, repository.name),
|
||||
getLabels(repository.owner, repository.name),
|
||||
getCustomFieldsWithValue(repository.owner, repository.name, issueId).filter(_._1.enableForPullRequests),
|
||||
isEditable(repository),
|
||||
isManageable(repository),
|
||||
hasDeveloperRole(pullreq.requestUserName, pullreq.requestRepositoryName, context.loginAccount),
|
||||
repository,
|
||||
getRepository(pullreq.requestUserName, pullreq.requestRepositoryName),
|
||||
flash.iterator.map(f => f._1 -> f._2.toString).toMap
|
||||
)
|
||||
}
|
||||
} getOrElse NotFound()
|
||||
})
|
||||
|
||||
get("/:owner/:repository/pull/:id/commits")(referrersOnly { repository =>
|
||||
params("id").toIntOpt.flatMap {
|
||||
issueId =>
|
||||
getPullRequest(repository.owner, repository.name, issueId) map {
|
||||
case (issue, pullreq) =>
|
||||
val (commits, diffs) =
|
||||
getRequestCompareInfo(
|
||||
repository.owner,
|
||||
repository.name,
|
||||
pullreq.commitIdFrom,
|
||||
repository.owner,
|
||||
repository.name,
|
||||
pullreq.commitIdTo
|
||||
)
|
||||
params("id").toIntOpt.flatMap { issueId =>
|
||||
getPullRequest(repository.owner, repository.name, issueId) map { case (issue, pullreq) =>
|
||||
val (commits, diffs) =
|
||||
getRequestCompareInfo(
|
||||
repository.owner,
|
||||
repository.name,
|
||||
pullreq.commitIdFrom,
|
||||
repository.owner,
|
||||
repository.name,
|
||||
pullreq.commitIdTo
|
||||
)
|
||||
|
||||
val commitsWithStatus = commits.map { day =>
|
||||
day.map { commit =>
|
||||
(commit, getCommitStatusWithSummary(repository.owner, repository.name, commit.id))
|
||||
}
|
||||
}
|
||||
|
||||
html.commits(
|
||||
issue,
|
||||
pullreq,
|
||||
commitsWithStatus,
|
||||
getPullRequestComments(repository.owner, repository.name, issue.issueId, commits.flatten),
|
||||
diffs.size,
|
||||
isManageable(repository),
|
||||
repository
|
||||
)
|
||||
val commitsWithStatus = commits.map { day =>
|
||||
day.map { commit =>
|
||||
(commit, getCommitStatusWithSummary(repository.owner, repository.name, commit.id))
|
||||
}
|
||||
}
|
||||
|
||||
html.commits(
|
||||
issue,
|
||||
pullreq,
|
||||
commitsWithStatus,
|
||||
getPullRequestComments(repository.owner, repository.name, issue.issueId, commits.flatten),
|
||||
diffs.size,
|
||||
isManageable(repository),
|
||||
repository
|
||||
)
|
||||
}
|
||||
} getOrElse NotFound()
|
||||
})
|
||||
|
||||
get("/:owner/:repository/pull/:id/files")(referrersOnly { repository =>
|
||||
params("id").toIntOpt.flatMap {
|
||||
issueId =>
|
||||
getPullRequest(repository.owner, repository.name, issueId) map {
|
||||
case (issue, pullreq) =>
|
||||
val (commits, diffs) =
|
||||
getRequestCompareInfo(
|
||||
repository.owner,
|
||||
repository.name,
|
||||
pullreq.commitIdFrom,
|
||||
repository.owner,
|
||||
repository.name,
|
||||
pullreq.commitIdTo
|
||||
)
|
||||
params("id").toIntOpt.flatMap { issueId =>
|
||||
getPullRequest(repository.owner, repository.name, issueId) map { case (issue, pullreq) =>
|
||||
val (commits, diffs) =
|
||||
getRequestCompareInfo(
|
||||
repository.owner,
|
||||
repository.name,
|
||||
pullreq.commitIdFrom,
|
||||
repository.owner,
|
||||
repository.name,
|
||||
pullreq.commitIdTo
|
||||
)
|
||||
|
||||
html.files(
|
||||
issue,
|
||||
pullreq,
|
||||
diffs,
|
||||
commits.flatten,
|
||||
getPullRequestComments(repository.owner, repository.name, issue.issueId, commits.flatten),
|
||||
isManageable(repository),
|
||||
repository
|
||||
)
|
||||
}
|
||||
html.files(
|
||||
issue,
|
||||
pullreq,
|
||||
diffs,
|
||||
commits.flatten,
|
||||
getPullRequestComments(repository.owner, repository.name, issue.issueId, commits.flatten),
|
||||
isManageable(repository),
|
||||
repository
|
||||
)
|
||||
}
|
||||
} getOrElse NotFound()
|
||||
})
|
||||
|
||||
ajaxGet("/:owner/:repository/pull/:id/mergeguide")(referrersOnly { repository =>
|
||||
params("id").toIntOpt.flatMap {
|
||||
issueId =>
|
||||
getPullRequest(repository.owner, repository.name, issueId) map {
|
||||
case (issue, pullreq) =>
|
||||
val conflictMessage = LockUtil.lock(s"${repository.owner}/${repository.name}") {
|
||||
checkConflict(repository.owner, repository.name, pullreq.branch, issueId)
|
||||
}
|
||||
val hasMergePermission = hasDeveloperRole(repository.owner, repository.name, context.loginAccount)
|
||||
val branchProtection = getProtectedBranchInfo(repository.owner, repository.name, pullreq.branch)
|
||||
val mergeStatus = PullRequestService.MergeStatus(
|
||||
conflictMessage = conflictMessage,
|
||||
commitStatuses = getCommitStatuses(repository.owner, repository.name, pullreq.commitIdTo),
|
||||
branchProtection = branchProtection,
|
||||
branchIsOutOfDate = JGitUtil.getShaByRef(repository.owner, repository.name, pullreq.branch) != Some(
|
||||
pullreq.commitIdFrom
|
||||
),
|
||||
needStatusCheck = context.loginAccount.forall { u =>
|
||||
branchProtection.needStatusCheck(u.userName)
|
||||
},
|
||||
hasUpdatePermission = hasDeveloperRole(
|
||||
params("id").toIntOpt.flatMap { issueId =>
|
||||
getPullRequest(repository.owner, repository.name, issueId) map { case (issue, pullreq) =>
|
||||
val conflictMessage = LockUtil.lock(s"${repository.owner}/${repository.name}") {
|
||||
checkConflict(repository.owner, repository.name, pullreq.branch, issueId)
|
||||
}
|
||||
val hasMergePermission = hasDeveloperRole(repository.owner, repository.name, context.loginAccount)
|
||||
val branchProtection = getProtectedBranchInfo(repository.owner, repository.name, pullreq.branch)
|
||||
val mergeStatus = PullRequestService.MergeStatus(
|
||||
conflictMessage = conflictMessage,
|
||||
commitStatuses = getCommitStatuses(repository.owner, repository.name, pullreq.commitIdTo),
|
||||
branchProtection = branchProtection,
|
||||
branchIsOutOfDate = JGitUtil.getShaByRef(repository.owner, repository.name, pullreq.branch) != Some(
|
||||
pullreq.commitIdFrom
|
||||
),
|
||||
needStatusCheck = context.loginAccount.forall { u =>
|
||||
branchProtection.needStatusCheck(u.userName)
|
||||
},
|
||||
hasUpdatePermission = hasDeveloperRole(
|
||||
pullreq.requestUserName,
|
||||
pullreq.requestRepositoryName,
|
||||
context.loginAccount
|
||||
) &&
|
||||
context.loginAccount.exists { u =>
|
||||
!getProtectedBranchInfo(
|
||||
pullreq.requestUserName,
|
||||
pullreq.requestRepositoryName,
|
||||
context.loginAccount
|
||||
) &&
|
||||
context.loginAccount.exists { u =>
|
||||
!getProtectedBranchInfo(
|
||||
pullreq.requestUserName,
|
||||
pullreq.requestRepositoryName,
|
||||
pullreq.requestBranch
|
||||
).needStatusCheck(u.userName)
|
||||
},
|
||||
hasMergePermission = hasMergePermission,
|
||||
commitIdTo = pullreq.commitIdTo
|
||||
)
|
||||
html.mergeguide(
|
||||
mergeStatus,
|
||||
issue,
|
||||
pullreq,
|
||||
repository,
|
||||
getRepository(pullreq.requestUserName, pullreq.requestRepositoryName).get
|
||||
)
|
||||
}
|
||||
pullreq.requestBranch
|
||||
).needStatusCheck(u.userName)
|
||||
},
|
||||
hasMergePermission = hasMergePermission,
|
||||
commitIdTo = pullreq.commitIdTo
|
||||
)
|
||||
html.mergeguide(
|
||||
mergeStatus,
|
||||
issue,
|
||||
pullreq,
|
||||
repository,
|
||||
getRepository(pullreq.requestUserName, pullreq.requestRepositoryName).get
|
||||
)
|
||||
}
|
||||
} getOrElse NotFound()
|
||||
})
|
||||
|
||||
@@ -314,7 +306,9 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
} else {
|
||||
LockUtil.lock(s"${owner}/${name}") {
|
||||
val alias =
|
||||
if (pullreq.repositoryName == pullreq.requestRepositoryName && pullreq.userName == pullreq.requestUserName) {
|
||||
if (
|
||||
pullreq.repositoryName == pullreq.requestRepositoryName && pullreq.userName == pullreq.requestUserName
|
||||
) {
|
||||
pullreq.branch
|
||||
} else {
|
||||
s"${pullreq.userName}:${pullreq.branch}"
|
||||
@@ -383,29 +377,27 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
val headBranch = params.get("head")
|
||||
(forkedRepository.repository.originUserName, forkedRepository.repository.originRepositoryName) match {
|
||||
case (Some(originUserName), Some(originRepositoryName)) =>
|
||||
getRepository(originUserName, originRepositoryName).map {
|
||||
originRepository =>
|
||||
Using.resources(
|
||||
Git.open(getRepositoryDir(originUserName, originRepositoryName)),
|
||||
Git.open(getRepositoryDir(forkedRepository.owner, forkedRepository.name))
|
||||
) { (oldGit, newGit) =>
|
||||
val newBranch = headBranch.getOrElse(JGitUtil.getDefaultBranch(newGit, forkedRepository).get._2)
|
||||
val oldBranch = originRepository.branchList
|
||||
.find(_ == newBranch)
|
||||
.getOrElse(JGitUtil.getDefaultBranch(oldGit, originRepository).get._2)
|
||||
getRepository(originUserName, originRepositoryName).map { originRepository =>
|
||||
Using.resources(
|
||||
Git.open(getRepositoryDir(originUserName, originRepositoryName)),
|
||||
Git.open(getRepositoryDir(forkedRepository.owner, forkedRepository.name))
|
||||
) { (oldGit, newGit) =>
|
||||
val newBranch = headBranch.getOrElse(JGitUtil.getDefaultBranch(newGit, forkedRepository).get._2)
|
||||
val oldBranch = originRepository.branchList
|
||||
.find(_ == newBranch)
|
||||
.getOrElse(JGitUtil.getDefaultBranch(oldGit, originRepository).get._2)
|
||||
|
||||
redirect(
|
||||
s"/${forkedRepository.owner}/${forkedRepository.name}/compare/${originUserName}:${oldBranch}...${newBranch}"
|
||||
)
|
||||
}
|
||||
redirect(
|
||||
s"/${forkedRepository.owner}/${forkedRepository.name}/compare/${originUserName}:${oldBranch}...${newBranch}"
|
||||
)
|
||||
}
|
||||
} getOrElse NotFound()
|
||||
case _ =>
|
||||
Using.resource(Git.open(getRepositoryDir(forkedRepository.owner, forkedRepository.name))) { git =>
|
||||
JGitUtil.getDefaultBranch(git, forkedRepository).map {
|
||||
case (_, defaultBranch) =>
|
||||
redirect(
|
||||
s"/${forkedRepository.owner}/${forkedRepository.name}/compare/${defaultBranch}...${headBranch.getOrElse(defaultBranch)}"
|
||||
)
|
||||
JGitUtil.getDefaultBranch(git, forkedRepository).map { case (_, defaultBranch) =>
|
||||
redirect(
|
||||
s"/${forkedRepository.owner}/${forkedRepository.name}/compare/${defaultBranch}...${headBranch.getOrElse(defaultBranch)}"
|
||||
)
|
||||
} getOrElse {
|
||||
redirect(s"/${forkedRepository.owner}/${forkedRepository.name}")
|
||||
}
|
||||
@@ -445,8 +437,10 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
val (originOwner, originId) = parseCompareIdentifier(origin, forkedRepository.owner)
|
||||
val (forkedOwner, forkedId) = parseCompareIdentifier(forked, forkedRepository.owner)
|
||||
|
||||
(for (originRepositoryName <- getOriginRepositoryName(originOwner, forkedOwner, forkedRepository);
|
||||
originRepository <- getRepository(originOwner, originRepositoryName)) yield {
|
||||
(for (
|
||||
originRepositoryName <- getOriginRepositoryName(originOwner, forkedOwner, forkedRepository);
|
||||
originRepository <- getRepository(originOwner, originRepositoryName)
|
||||
) yield {
|
||||
val (oldId, newId) =
|
||||
getPullRequestCommitFromTo(originRepository, forkedRepository, originId, forkedId)
|
||||
|
||||
@@ -566,87 +560,88 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
val (originOwner, tmpOriginBranch) = parseCompareIdentifier(origin, forkedRepository.owner)
|
||||
val (forkedOwner, tmpForkedBranch) = parseCompareIdentifier(forked, forkedRepository.owner)
|
||||
|
||||
(for (originRepositoryName <- if (originOwner == forkedOwner) {
|
||||
Some(forkedRepository.name)
|
||||
} else {
|
||||
forkedRepository.repository.originRepositoryName.orElse {
|
||||
getForkedRepositories(forkedRepository.owner, forkedRepository.name)
|
||||
.find(_.userName == originOwner)
|
||||
.map(_.repositoryName)
|
||||
}
|
||||
};
|
||||
originRepository <- getRepository(originOwner, originRepositoryName)) yield {
|
||||
(for (
|
||||
originRepositoryName <-
|
||||
if (originOwner == forkedOwner) {
|
||||
Some(forkedRepository.name)
|
||||
} else {
|
||||
forkedRepository.repository.originRepositoryName.orElse {
|
||||
getForkedRepositories(forkedRepository.owner, forkedRepository.name)
|
||||
.find(_.userName == originOwner)
|
||||
.map(_.repositoryName)
|
||||
}
|
||||
};
|
||||
originRepository <- getRepository(originOwner, originRepositoryName)
|
||||
) yield {
|
||||
Using.resources(
|
||||
Git.open(getRepositoryDir(originRepository.owner, originRepository.name)),
|
||||
Git.open(getRepositoryDir(forkedRepository.owner, forkedRepository.name))
|
||||
) {
|
||||
case (oldGit, newGit) =>
|
||||
val originBranch = JGitUtil.getDefaultBranch(oldGit, originRepository, tmpOriginBranch).get._2
|
||||
val forkedBranch = JGitUtil.getDefaultBranch(newGit, forkedRepository, tmpForkedBranch).get._2
|
||||
val conflict = LockUtil.lock(s"${originRepository.owner}/${originRepository.name}") {
|
||||
checkConflict(
|
||||
originRepository.owner,
|
||||
originRepository.name,
|
||||
originBranch,
|
||||
forkedRepository.owner,
|
||||
forkedRepository.name,
|
||||
forkedBranch
|
||||
)
|
||||
}
|
||||
html.mergecheck(conflict.isDefined)
|
||||
) { case (oldGit, newGit) =>
|
||||
val originBranch = JGitUtil.getDefaultBranch(oldGit, originRepository, tmpOriginBranch).get._2
|
||||
val forkedBranch = JGitUtil.getDefaultBranch(newGit, forkedRepository, tmpForkedBranch).get._2
|
||||
val conflict = LockUtil.lock(s"${originRepository.owner}/${originRepository.name}") {
|
||||
checkConflict(
|
||||
originRepository.owner,
|
||||
originRepository.name,
|
||||
originBranch,
|
||||
forkedRepository.owner,
|
||||
forkedRepository.name,
|
||||
forkedBranch
|
||||
)
|
||||
}
|
||||
html.mergecheck(conflict.isDefined)
|
||||
}
|
||||
}) getOrElse NotFound()
|
||||
})
|
||||
|
||||
post("/:owner/:repository/pulls/new", pullRequestForm)(readableUsersOnly { (form, repository) =>
|
||||
context.withLoginAccount {
|
||||
loginAccount =>
|
||||
val manageable = isManageable(repository)
|
||||
context.withLoginAccount { loginAccount =>
|
||||
val manageable = isManageable(repository)
|
||||
|
||||
val issueId = insertIssue(
|
||||
owner = repository.owner,
|
||||
repository = repository.name,
|
||||
loginUser = loginAccount.userName,
|
||||
title = form.title,
|
||||
content = form.content,
|
||||
milestoneId = if (manageable) form.milestoneId else None,
|
||||
priorityId = if (manageable) form.priorityId else None,
|
||||
isPullRequest = true
|
||||
)
|
||||
val issueId = insertIssue(
|
||||
owner = repository.owner,
|
||||
repository = repository.name,
|
||||
loginUser = loginAccount.userName,
|
||||
title = form.title,
|
||||
content = form.content,
|
||||
milestoneId = if (manageable) form.milestoneId else None,
|
||||
priorityId = if (manageable) form.priorityId else None,
|
||||
isPullRequest = true
|
||||
)
|
||||
|
||||
createPullRequest(
|
||||
originRepository = repository,
|
||||
issueId = issueId,
|
||||
originBranch = form.targetBranch,
|
||||
requestUserName = form.requestUserName,
|
||||
requestRepositoryName = form.requestRepositoryName,
|
||||
requestBranch = form.requestBranch,
|
||||
commitIdFrom = form.commitIdFrom,
|
||||
commitIdTo = form.commitIdTo,
|
||||
isDraft = form.isDraft,
|
||||
loginAccount = loginAccount,
|
||||
settings = context.settings
|
||||
)
|
||||
createPullRequest(
|
||||
originRepository = repository,
|
||||
issueId = issueId,
|
||||
originBranch = form.targetBranch,
|
||||
requestUserName = form.requestUserName,
|
||||
requestRepositoryName = form.requestRepositoryName,
|
||||
requestBranch = form.requestBranch,
|
||||
commitIdFrom = form.commitIdFrom,
|
||||
commitIdTo = form.commitIdTo,
|
||||
isDraft = form.isDraft,
|
||||
loginAccount = loginAccount,
|
||||
settings = context.settings
|
||||
)
|
||||
|
||||
if (manageable) {
|
||||
// insert assignees
|
||||
form.assigneeUserNames.foreach { value =>
|
||||
value.split(",").foreach { userName =>
|
||||
registerIssueAssignee(repository.owner, repository.name, issueId, userName)
|
||||
}
|
||||
if (manageable) {
|
||||
// insert assignees
|
||||
form.assigneeUserNames.foreach { value =>
|
||||
value.split(",").foreach { userName =>
|
||||
registerIssueAssignee(repository.owner, repository.name, issueId, userName)
|
||||
}
|
||||
// insert labels
|
||||
form.labelNames.foreach { value =>
|
||||
val labels = getLabels(repository.owner, repository.name)
|
||||
value.split(",").foreach { labelName =>
|
||||
labels.find(_.labelName == labelName).map { label =>
|
||||
registerIssueLabel(repository.owner, repository.name, issueId, label.labelId)
|
||||
}
|
||||
}
|
||||
// insert labels
|
||||
form.labelNames.foreach { value =>
|
||||
val labels = getLabels(repository.owner, repository.name)
|
||||
value.split(",").foreach { labelName =>
|
||||
labels.find(_.labelName == labelName).map { label =>
|
||||
registerIssueLabel(repository.owner, repository.name, issueId, label.labelId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
redirect(s"/${repository.owner}/${repository.name}/pull/${issueId}")
|
||||
redirect(s"/${repository.owner}/${repository.name}/pull/${issueId}")
|
||||
}
|
||||
})
|
||||
|
||||
@@ -656,24 +651,23 @@ trait PullRequestsControllerBase extends ControllerBase {
|
||||
context.loginAccount.map(x => Seq(x.mailAddress) ++ getAccountExtraMailAddresses(x.userName)).getOrElse(Nil)
|
||||
|
||||
val branches =
|
||||
Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) {
|
||||
git =>
|
||||
JGitUtil
|
||||
.getBranches(
|
||||
git = git,
|
||||
defaultBranch = repository.repository.defaultBranch,
|
||||
origin = repository.repository.originUserName.isEmpty
|
||||
)
|
||||
.filter { x =>
|
||||
x.mergeInfo.map(_.ahead).getOrElse(0) > 0 && x.mergeInfo.map(_.behind).getOrElse(0) == 0 &&
|
||||
x.commitTime.getTime > thresholdTime &&
|
||||
mailAddresses.contains(x.committerEmailAddress)
|
||||
}
|
||||
.sortBy { br =>
|
||||
(br.mergeInfo.isEmpty, br.commitTime)
|
||||
}
|
||||
.map(_.name)
|
||||
.reverse
|
||||
Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) { git =>
|
||||
JGitUtil
|
||||
.getBranches(
|
||||
git = git,
|
||||
defaultBranch = repository.repository.defaultBranch,
|
||||
origin = repository.repository.originUserName.isEmpty
|
||||
)
|
||||
.filter { x =>
|
||||
x.mergeInfo.map(_.ahead).getOrElse(0) > 0 && x.mergeInfo.map(_.behind).getOrElse(0) == 0 &&
|
||||
x.commitTime.getTime > thresholdTime &&
|
||||
mailAddresses.contains(x.committerEmailAddress)
|
||||
}
|
||||
.sortBy { br =>
|
||||
(br.mergeInfo.isEmpty, br.commitTime)
|
||||
}
|
||||
.map(_.name)
|
||||
.reverse
|
||||
}
|
||||
|
||||
val targetRepository = (for {
|
||||
|
||||
@@ -106,33 +106,31 @@ trait ReleaseControllerBase extends ControllerBase {
|
||||
})
|
||||
|
||||
post("/:owner/:repository/releases/*/create", releaseForm)(writableUsersOnly { (form, repository) =>
|
||||
context.withLoginAccount {
|
||||
loginAccount =>
|
||||
val tagName = multiParams("splat").head
|
||||
context.withLoginAccount { loginAccount =>
|
||||
val tagName = multiParams("splat").head
|
||||
|
||||
// Insert into RELEASE
|
||||
createRelease(repository.owner, repository.name, form.name, form.content, tagName, loginAccount)
|
||||
// Insert into RELEASE
|
||||
createRelease(repository.owner, repository.name, form.name, form.content, tagName, loginAccount)
|
||||
|
||||
// Insert into RELEASE_ASSET
|
||||
val files = params.toMap.collect {
|
||||
case (name, value) if name.startsWith("file:") =>
|
||||
val Array(_, fileId) = name.split(":")
|
||||
(fileId, value)
|
||||
}
|
||||
files.foreach {
|
||||
case (fileId, fileName) =>
|
||||
val size =
|
||||
new File(
|
||||
getReleaseFilesDir(repository.owner, repository.name),
|
||||
FileUtil.checkFilename(tagName + "/" + fileId)
|
||||
).length
|
||||
createReleaseAsset(repository.owner, repository.name, tagName, fileId, fileName, size, loginAccount)
|
||||
}
|
||||
// Insert into RELEASE_ASSET
|
||||
val files = params.toMap.collect {
|
||||
case (name, value) if name.startsWith("file:") =>
|
||||
val Array(_, fileId) = name.split(":")
|
||||
(fileId, value)
|
||||
}
|
||||
files.foreach { case (fileId, fileName) =>
|
||||
val size =
|
||||
new File(
|
||||
getReleaseFilesDir(repository.owner, repository.name),
|
||||
FileUtil.checkFilename(tagName + "/" + fileId)
|
||||
).length
|
||||
createReleaseAsset(repository.owner, repository.name, tagName, fileId, fileName, size, loginAccount)
|
||||
}
|
||||
|
||||
val releaseInfo = ReleaseInfo(repository.owner, repository.name, loginAccount.userName, form.name, tagName)
|
||||
recordActivity(releaseInfo)
|
||||
val releaseInfo = ReleaseInfo(repository.owner, repository.name, loginAccount.userName, form.name, tagName)
|
||||
recordActivity(releaseInfo)
|
||||
|
||||
redirect(s"/${repository.owner}/${repository.name}/releases/${tagName}")
|
||||
redirect(s"/${repository.owner}/${repository.name}/releases/${tagName}")
|
||||
}
|
||||
})
|
||||
|
||||
@@ -171,48 +169,45 @@ trait ReleaseControllerBase extends ControllerBase {
|
||||
})
|
||||
|
||||
post("/:owner/:repository/releases/*/edit", releaseForm)(writableUsersOnly { (form, repository) =>
|
||||
context.withLoginAccount {
|
||||
loginAccount =>
|
||||
val tagName = multiParams("splat").head
|
||||
context.withLoginAccount { loginAccount =>
|
||||
val tagName = multiParams("splat").head
|
||||
|
||||
getRelease(repository.owner, repository.name, tagName)
|
||||
.map {
|
||||
release =>
|
||||
// Update RELEASE
|
||||
updateRelease(repository.owner, repository.name, tagName, form.name, form.content)
|
||||
getRelease(repository.owner, repository.name, tagName)
|
||||
.map { release =>
|
||||
// Update RELEASE
|
||||
updateRelease(repository.owner, repository.name, tagName, form.name, form.content)
|
||||
|
||||
// Delete and Insert RELEASE_ASSET
|
||||
val assets = getReleaseAssets(repository.owner, repository.name, tagName)
|
||||
deleteReleaseAssets(repository.owner, repository.name, tagName)
|
||||
// Delete and Insert RELEASE_ASSET
|
||||
val assets = getReleaseAssets(repository.owner, repository.name, tagName)
|
||||
deleteReleaseAssets(repository.owner, repository.name, tagName)
|
||||
|
||||
val files = params.toMap.collect {
|
||||
case (name, value) if name.startsWith("file:") =>
|
||||
val Array(_, fileId) = name.split(":")
|
||||
(fileId, value)
|
||||
}
|
||||
files.foreach {
|
||||
case (fileId, fileName) =>
|
||||
val size =
|
||||
new File(
|
||||
getReleaseFilesDir(repository.owner, repository.name),
|
||||
FileUtil.checkFilename(tagName + "/" + fileId)
|
||||
).length
|
||||
createReleaseAsset(repository.owner, repository.name, tagName, fileId, fileName, size, loginAccount)
|
||||
}
|
||||
|
||||
assets.foreach { asset =>
|
||||
if (!files.exists { case (fileId, _) => fileId == asset.fileName }) {
|
||||
val file = new File(
|
||||
getReleaseFilesDir(repository.owner, repository.name),
|
||||
FileUtil.checkFilename(release.tag + "/" + asset.fileName)
|
||||
)
|
||||
FileUtils.forceDelete(file)
|
||||
}
|
||||
}
|
||||
|
||||
redirect(s"/${release.userName}/${release.repositoryName}/releases/${tagName}")
|
||||
val files = params.toMap.collect {
|
||||
case (name, value) if name.startsWith("file:") =>
|
||||
val Array(_, fileId) = name.split(":")
|
||||
(fileId, value)
|
||||
}
|
||||
.getOrElse(NotFound())
|
||||
files.foreach { case (fileId, fileName) =>
|
||||
val size =
|
||||
new File(
|
||||
getReleaseFilesDir(repository.owner, repository.name),
|
||||
FileUtil.checkFilename(tagName + "/" + fileId)
|
||||
).length
|
||||
createReleaseAsset(repository.owner, repository.name, tagName, fileId, fileName, size, loginAccount)
|
||||
}
|
||||
|
||||
assets.foreach { asset =>
|
||||
if (!files.exists { case (fileId, _) => fileId == asset.fileName }) {
|
||||
val file = new File(
|
||||
getReleaseFilesDir(repository.owner, repository.name),
|
||||
FileUtil.checkFilename(release.tag + "/" + asset.fileName)
|
||||
)
|
||||
FileUtils.forceDelete(file)
|
||||
}
|
||||
}
|
||||
|
||||
redirect(s"/${release.userName}/${release.repositoryName}/releases/${tagName}")
|
||||
}
|
||||
.getOrElse(NotFound())
|
||||
}
|
||||
})
|
||||
|
||||
@@ -237,9 +232,12 @@ trait ReleaseControllerBase extends ControllerBase {
|
||||
val assets = getReleaseAssetsMap(repository.owner, repository.name, releases)
|
||||
|
||||
val tagsWithReleases = tagsToDisplay.map { tag =>
|
||||
(tag, releases.find(_.tag == tag.name).map { release =>
|
||||
(release, assets(release))
|
||||
})
|
||||
(
|
||||
tag,
|
||||
releases.find(_.tag == tag.name).map { release =>
|
||||
(release, assets(release))
|
||||
}
|
||||
)
|
||||
}
|
||||
tagsWithReleases
|
||||
}
|
||||
|
||||
@@ -286,93 +286,90 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
||||
Array(h.getName, h.getValue)
|
||||
}
|
||||
|
||||
Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) {
|
||||
git =>
|
||||
import scala.concurrent.duration._
|
||||
import scala.concurrent._
|
||||
import scala.jdk.CollectionConverters._
|
||||
import scala.util.control.NonFatal
|
||||
import org.apache.http.util.EntityUtils
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) { git =>
|
||||
import scala.concurrent.duration._
|
||||
import scala.concurrent._
|
||||
import scala.jdk.CollectionConverters._
|
||||
import scala.util.control.NonFatal
|
||||
import org.apache.http.util.EntityUtils
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
|
||||
val url = params("url")
|
||||
val token = Some(params("token"))
|
||||
val ctype = WebHookContentType.valueOf(params("ctype"))
|
||||
val dummyWebHookInfo = RepositoryWebHook(
|
||||
userName = repository.owner,
|
||||
repositoryName = repository.name,
|
||||
url = url,
|
||||
ctype = ctype,
|
||||
token = token
|
||||
val url = params("url")
|
||||
val token = Some(params("token"))
|
||||
val ctype = WebHookContentType.valueOf(params("ctype"))
|
||||
val dummyWebHookInfo = RepositoryWebHook(
|
||||
userName = repository.owner,
|
||||
repositoryName = repository.name,
|
||||
url = url,
|
||||
ctype = ctype,
|
||||
token = token
|
||||
)
|
||||
val dummyPayload = {
|
||||
val ownerAccount = getAccountByUserName(repository.owner).get
|
||||
val commits =
|
||||
if (JGitUtil.isEmpty(git)) List.empty
|
||||
else
|
||||
git.log
|
||||
.add(git.getRepository.resolve(repository.repository.defaultBranch))
|
||||
.setMaxCount(4)
|
||||
.call
|
||||
.iterator
|
||||
.asScala
|
||||
.map(new CommitInfo(_))
|
||||
.toList
|
||||
val pushedCommit = commits.drop(1)
|
||||
|
||||
WebHookPushPayload(
|
||||
git = git,
|
||||
sender = ownerAccount,
|
||||
refName = "refs/heads/" + repository.repository.defaultBranch,
|
||||
repositoryInfo = repository,
|
||||
commits = pushedCommit,
|
||||
repositoryOwner = ownerAccount,
|
||||
oldId = commits.lastOption.map(_.id).map(ObjectId.fromString).getOrElse(ObjectId.zeroId()),
|
||||
newId = commits.headOption.map(_.id).map(ObjectId.fromString).getOrElse(ObjectId.zeroId())
|
||||
)
|
||||
val dummyPayload = {
|
||||
val ownerAccount = getAccountByUserName(repository.owner).get
|
||||
val commits =
|
||||
if (JGitUtil.isEmpty(git)) List.empty
|
||||
else
|
||||
git.log
|
||||
.add(git.getRepository.resolve(repository.repository.defaultBranch))
|
||||
.setMaxCount(4)
|
||||
.call
|
||||
.iterator
|
||||
.asScala
|
||||
.map(new CommitInfo(_))
|
||||
.toList
|
||||
val pushedCommit = commits.drop(1)
|
||||
}
|
||||
|
||||
WebHookPushPayload(
|
||||
git = git,
|
||||
sender = ownerAccount,
|
||||
refName = "refs/heads/" + repository.repository.defaultBranch,
|
||||
repositoryInfo = repository,
|
||||
commits = pushedCommit,
|
||||
repositoryOwner = ownerAccount,
|
||||
oldId = commits.lastOption.map(_.id).map(ObjectId.fromString).getOrElse(ObjectId.zeroId()),
|
||||
newId = commits.headOption.map(_.id).map(ObjectId.fromString).getOrElse(ObjectId.zeroId())
|
||||
)
|
||||
}
|
||||
val (webHook, json, reqFuture, resFuture) =
|
||||
callWebHook(WebHook.Push, List(dummyWebHookInfo), dummyPayload, context.settings).head
|
||||
|
||||
val (webHook, json, reqFuture, resFuture) =
|
||||
callWebHook(WebHook.Push, List(dummyWebHookInfo), dummyPayload, context.settings).head
|
||||
val toErrorMap: PartialFunction[Throwable, Map[String, String]] = {
|
||||
case e: java.net.UnknownHostException => Map("error" -> ("Unknown host " + e.getMessage))
|
||||
case e: java.lang.IllegalArgumentException => Map("error" -> ("invalid url"))
|
||||
case e: org.apache.http.client.ClientProtocolException => Map("error" -> ("invalid url"))
|
||||
case NonFatal(e) => Map("error" -> (s"${e.getClass} ${e.getMessage}"))
|
||||
}
|
||||
|
||||
val toErrorMap: PartialFunction[Throwable, Map[String, String]] = {
|
||||
case e: java.net.UnknownHostException => Map("error" -> ("Unknown host " + e.getMessage))
|
||||
case e: java.lang.IllegalArgumentException => Map("error" -> ("invalid url"))
|
||||
case e: org.apache.http.client.ClientProtocolException => Map("error" -> ("invalid url"))
|
||||
case NonFatal(e) => Map("error" -> (s"${e.getClass} ${e.getMessage}"))
|
||||
}
|
||||
|
||||
contentType = formats("json")
|
||||
org.json4s.jackson.Serialization.write(
|
||||
Map(
|
||||
"url" -> url,
|
||||
"request" -> Await.result(
|
||||
reqFuture
|
||||
.map(
|
||||
req =>
|
||||
Map(
|
||||
"headers" -> _headers(req.getAllHeaders),
|
||||
"payload" -> json
|
||||
)
|
||||
contentType = formats("json")
|
||||
org.json4s.jackson.Serialization.write(
|
||||
Map(
|
||||
"url" -> url,
|
||||
"request" -> Await.result(
|
||||
reqFuture
|
||||
.map(req =>
|
||||
Map(
|
||||
"headers" -> _headers(req.getAllHeaders),
|
||||
"payload" -> json
|
||||
)
|
||||
.recover(toErrorMap),
|
||||
20 seconds
|
||||
),
|
||||
"response" -> Await.result(
|
||||
resFuture
|
||||
.map(
|
||||
res =>
|
||||
Map(
|
||||
"status" -> res.getStatusLine.getStatusCode,
|
||||
"body" -> EntityUtils.toString(res.getEntity()),
|
||||
"headers" -> _headers(res.getAllHeaders())
|
||||
)
|
||||
)
|
||||
.recover(toErrorMap),
|
||||
20 seconds
|
||||
),
|
||||
"response" -> Await.result(
|
||||
resFuture
|
||||
.map(res =>
|
||||
Map(
|
||||
"status" -> res.getStatusLine.getStatusCode,
|
||||
"body" -> EntityUtils.toString(res.getEntity()),
|
||||
"headers" -> _headers(res.getAllHeaders())
|
||||
)
|
||||
.recover(toErrorMap),
|
||||
20 seconds
|
||||
)
|
||||
)
|
||||
.recover(toErrorMap),
|
||||
20 seconds
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -380,9 +377,8 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
||||
* Display the web hook edit page.
|
||||
*/
|
||||
get("/:owner/:repository/settings/hooks/edit")(ownerOnly { repository =>
|
||||
getWebHook(repository.owner, repository.name, params("url")).map {
|
||||
case (webhook, events) =>
|
||||
html.edithook(webhook, events, repository, false)
|
||||
getWebHook(repository.owner, repository.name, params("url")).map { case (webhook, events) =>
|
||||
html.edithook(webhook, events, repository, false)
|
||||
} getOrElse NotFound()
|
||||
})
|
||||
|
||||
@@ -406,23 +402,22 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
||||
* Rename repository.
|
||||
*/
|
||||
post("/:owner/:repository/settings/rename", renameForm)(ownerOnly { (form, repository) =>
|
||||
context.withLoginAccount {
|
||||
loginAccount =>
|
||||
if (context.settings.basicBehavior.repositoryOperation.rename || loginAccount.isAdmin) {
|
||||
if (repository.name != form.repositoryName) {
|
||||
// Update database and move git repository
|
||||
renameRepository(repository.owner, repository.name, repository.owner, form.repositoryName)
|
||||
// Record activity log
|
||||
val renameInfo = RenameRepositoryInfo(
|
||||
repository.owner,
|
||||
form.repositoryName,
|
||||
loginAccount.userName,
|
||||
repository.name
|
||||
)
|
||||
recordActivity(renameInfo)
|
||||
}
|
||||
redirect(s"/${repository.owner}/${form.repositoryName}")
|
||||
} else Forbidden()
|
||||
context.withLoginAccount { loginAccount =>
|
||||
if (context.settings.basicBehavior.repositoryOperation.rename || loginAccount.isAdmin) {
|
||||
if (repository.name != form.repositoryName) {
|
||||
// Update database and move git repository
|
||||
renameRepository(repository.owner, repository.name, repository.owner, form.repositoryName)
|
||||
// Record activity log
|
||||
val renameInfo = RenameRepositoryInfo(
|
||||
repository.owner,
|
||||
form.repositoryName,
|
||||
loginAccount.userName,
|
||||
repository.name
|
||||
)
|
||||
recordActivity(renameInfo)
|
||||
}
|
||||
redirect(s"/${repository.owner}/${form.repositoryName}")
|
||||
} else Forbidden()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -430,24 +425,23 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
||||
* Transfer repository ownership.
|
||||
*/
|
||||
post("/:owner/:repository/settings/transfer", transferForm)(ownerOnly { (form, repository) =>
|
||||
context.withLoginAccount {
|
||||
loginAccount =>
|
||||
if (context.settings.basicBehavior.repositoryOperation.transfer || loginAccount.isAdmin) {
|
||||
// Change repository owner
|
||||
if (repository.owner != form.newOwner) {
|
||||
// Update database and move git repository
|
||||
renameRepository(repository.owner, repository.name, form.newOwner, repository.name)
|
||||
// Record activity log
|
||||
val renameInfo = RenameRepositoryInfo(
|
||||
form.newOwner,
|
||||
repository.name,
|
||||
loginAccount.userName,
|
||||
repository.owner
|
||||
)
|
||||
recordActivity(renameInfo)
|
||||
}
|
||||
redirect(s"/${form.newOwner}/${repository.name}")
|
||||
} else Forbidden()
|
||||
context.withLoginAccount { loginAccount =>
|
||||
if (context.settings.basicBehavior.repositoryOperation.transfer || loginAccount.isAdmin) {
|
||||
// Change repository owner
|
||||
if (repository.owner != form.newOwner) {
|
||||
// Update database and move git repository
|
||||
renameRepository(repository.owner, repository.name, form.newOwner, repository.name)
|
||||
// Record activity log
|
||||
val renameInfo = RenameRepositoryInfo(
|
||||
form.newOwner,
|
||||
repository.name,
|
||||
loginAccount.userName,
|
||||
repository.owner
|
||||
)
|
||||
recordActivity(renameInfo)
|
||||
}
|
||||
redirect(s"/${form.newOwner}/${repository.name}")
|
||||
} else Forbidden()
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -55,16 +55,14 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
||||
"bindAddress" -> mapping(
|
||||
"host" -> trim(label("Bind SSH host", optional(text()))),
|
||||
"port" -> trim(label("Bind SSH port", optional(number()))),
|
||||
)(
|
||||
(hostOption, portOption) =>
|
||||
hostOption.map(h => SshAddress(h, portOption.getOrElse(DefaultSshPort), GenericSshUser))
|
||||
)((hostOption, portOption) =>
|
||||
hostOption.map(h => SshAddress(h, portOption.getOrElse(DefaultSshPort), GenericSshUser))
|
||||
),
|
||||
"publicAddress" -> mapping(
|
||||
"host" -> trim(label("Public SSH host", optional(text()))),
|
||||
"port" -> trim(label("Public SSH port", optional(number()))),
|
||||
)(
|
||||
(hostOption, portOption) =>
|
||||
hostOption.map(h => SshAddress(h, portOption.getOrElse(PublicSshPort), GenericSshUser))
|
||||
)((hostOption, portOption) =>
|
||||
hostOption.map(h => SshAddress(h, portOption.getOrElse(PublicSshPort), GenericSshUser))
|
||||
),
|
||||
)(Ssh.apply),
|
||||
"useSMTP" -> trim(label("SMTP", boolean())),
|
||||
@@ -251,28 +249,27 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
||||
val conn = request2Session(request).conn
|
||||
val meta = conn.getMetaData
|
||||
val tables = ListBuffer[Table]()
|
||||
Using.resource(meta.getTables(null, "%", "%", Array("TABLE", "VIEW"))) {
|
||||
rs =>
|
||||
while (rs.next()) {
|
||||
val tableName = rs.getString("TABLE_NAME")
|
||||
Using.resource(meta.getTables(null, "%", "%", Array("TABLE", "VIEW"))) { rs =>
|
||||
while (rs.next()) {
|
||||
val tableName = rs.getString("TABLE_NAME")
|
||||
|
||||
val pkColumns = ListBuffer[String]()
|
||||
Using.resource(meta.getPrimaryKeys(null, null, tableName)) { rs =>
|
||||
while (rs.next()) {
|
||||
pkColumns += rs.getString("COLUMN_NAME").toUpperCase
|
||||
}
|
||||
val pkColumns = ListBuffer[String]()
|
||||
Using.resource(meta.getPrimaryKeys(null, null, tableName)) { rs =>
|
||||
while (rs.next()) {
|
||||
pkColumns += rs.getString("COLUMN_NAME").toUpperCase
|
||||
}
|
||||
|
||||
val columns = ListBuffer[Column]()
|
||||
Using.resource(meta.getColumns(null, "%", tableName, "%")) { rs =>
|
||||
while (rs.next()) {
|
||||
val columnName = rs.getString("COLUMN_NAME").toUpperCase
|
||||
columns += Column(columnName, pkColumns.contains(columnName))
|
||||
}
|
||||
}
|
||||
|
||||
tables += Table(tableName.toUpperCase, columns.toSeq)
|
||||
}
|
||||
|
||||
val columns = ListBuffer[Column]()
|
||||
Using.resource(meta.getColumns(null, "%", tableName, "%")) { rs =>
|
||||
while (rs.next()) {
|
||||
val columnName = rs.getString("COLUMN_NAME").toUpperCase
|
||||
columns += Column(columnName, pkColumns.contains(columnName))
|
||||
}
|
||||
}
|
||||
|
||||
tables += Table(tableName.toUpperCase, columns.toSeq)
|
||||
}
|
||||
}
|
||||
html.dbviewer(tables.toSeq)
|
||||
})
|
||||
@@ -285,28 +282,26 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
||||
if (trimmedQuery.nonEmpty) {
|
||||
try {
|
||||
val conn = request2Session(request).conn
|
||||
Using.resource(conn.prepareStatement(query)) {
|
||||
stmt =>
|
||||
if (trimmedQuery.toUpperCase.startsWith("SELECT")) {
|
||||
Using.resource(stmt.executeQuery()) {
|
||||
rs =>
|
||||
val meta = rs.getMetaData
|
||||
val columns = for (i <- 1 to meta.getColumnCount) yield {
|
||||
meta.getColumnName(i)
|
||||
}
|
||||
val result = ListBuffer[Map[String, String]]()
|
||||
while (rs.next()) {
|
||||
val row = columns.map { columnName =>
|
||||
columnName -> Option(rs.getObject(columnName)).map(_.toString).getOrElse("<NULL>")
|
||||
}.toMap
|
||||
result += row
|
||||
}
|
||||
Ok(Serialization.write(Map("type" -> "query", "columns" -> columns, "rows" -> result)))
|
||||
Using.resource(conn.prepareStatement(query)) { stmt =>
|
||||
if (trimmedQuery.toUpperCase.startsWith("SELECT")) {
|
||||
Using.resource(stmt.executeQuery()) { rs =>
|
||||
val meta = rs.getMetaData
|
||||
val columns = for (i <- 1 to meta.getColumnCount) yield {
|
||||
meta.getColumnName(i)
|
||||
}
|
||||
} else {
|
||||
val rows = stmt.executeUpdate()
|
||||
Ok(Serialization.write(Map("type" -> "update", "rows" -> rows)))
|
||||
val result = ListBuffer[Map[String, String]]()
|
||||
while (rs.next()) {
|
||||
val row = columns.map { columnName =>
|
||||
columnName -> Option(rs.getObject(columnName)).map(_.toString).getOrElse("<NULL>")
|
||||
}.toMap
|
||||
result += row
|
||||
}
|
||||
Ok(Serialization.write(Map("type" -> "query", "columns" -> columns, "rows" -> result)))
|
||||
}
|
||||
} else {
|
||||
val rows = stmt.executeUpdate()
|
||||
Ok(Serialization.write(Map("type" -> "update", "rows" -> rows)))
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
case e: Exception =>
|
||||
@@ -323,7 +318,9 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
||||
post("/admin/system", form)(adminOnly { form =>
|
||||
saveSystemSettings(form)
|
||||
|
||||
if (form.ssh.bindAddress != context.settings.sshBindAddress || form.ssh.publicAddress != context.settings.sshPublicAddress) {
|
||||
if (
|
||||
form.ssh.bindAddress != context.settings.sshBindAddress || form.ssh.publicAddress != context.settings.sshPublicAddress
|
||||
) {
|
||||
SshServer.stop()
|
||||
for {
|
||||
bindAddress <- form.ssh.bindAddress
|
||||
@@ -420,44 +417,43 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
||||
|
||||
post("/admin/users/:name/_edituser", editUserForm)(adminOnly { form =>
|
||||
val userName = params("userName")
|
||||
getAccountByUserName(userName, true).map {
|
||||
account =>
|
||||
if (account.isAdmin && (form.isRemoved || !form.isAdmin) && isLastAdministrator(account)) {
|
||||
flash.update("error", "Account can't be turned off because this is last one administrator.")
|
||||
redirect(s"/admin/users/${userName}/_edituser")
|
||||
} else {
|
||||
if (form.isRemoved) {
|
||||
// Remove repositories
|
||||
// getRepositoryNamesOfUser(userName).foreach { repositoryName =>
|
||||
// deleteRepository(userName, repositoryName)
|
||||
// FileUtils.deleteDirectory(getRepositoryDir(userName, repositoryName))
|
||||
// FileUtils.deleteDirectory(getWikiRepositoryDir(userName, repositoryName))
|
||||
// FileUtils.deleteDirectory(getTemporaryDir(userName, repositoryName))
|
||||
// }
|
||||
// Remove from GROUP_MEMBER and COLLABORATOR
|
||||
removeUserRelatedData(userName)
|
||||
}
|
||||
|
||||
updateAccount(
|
||||
account.copy(
|
||||
password = form.password.map(pbkdf2_sha256).getOrElse(account.password),
|
||||
fullName = form.fullName,
|
||||
mailAddress = form.mailAddress,
|
||||
isAdmin = form.isAdmin,
|
||||
description = form.description,
|
||||
url = form.url,
|
||||
isRemoved = form.isRemoved
|
||||
)
|
||||
)
|
||||
|
||||
updateImage(userName, form.fileId, form.clearImage)
|
||||
updateAccountExtraMailAddresses(userName, form.extraMailAddresses.filter(_ != ""))
|
||||
|
||||
// call hooks
|
||||
if (form.isRemoved) PluginRegistry().getAccountHooks.foreach(_.deleted(userName))
|
||||
|
||||
redirect("/admin/users")
|
||||
getAccountByUserName(userName, true).map { account =>
|
||||
if (account.isAdmin && (form.isRemoved || !form.isAdmin) && isLastAdministrator(account)) {
|
||||
flash.update("error", "Account can't be turned off because this is last one administrator.")
|
||||
redirect(s"/admin/users/${userName}/_edituser")
|
||||
} else {
|
||||
if (form.isRemoved) {
|
||||
// Remove repositories
|
||||
// getRepositoryNamesOfUser(userName).foreach { repositoryName =>
|
||||
// deleteRepository(userName, repositoryName)
|
||||
// FileUtils.deleteDirectory(getRepositoryDir(userName, repositoryName))
|
||||
// FileUtils.deleteDirectory(getWikiRepositoryDir(userName, repositoryName))
|
||||
// FileUtils.deleteDirectory(getTemporaryDir(userName, repositoryName))
|
||||
// }
|
||||
// Remove from GROUP_MEMBER and COLLABORATOR
|
||||
removeUserRelatedData(userName)
|
||||
}
|
||||
|
||||
updateAccount(
|
||||
account.copy(
|
||||
password = form.password.map(pbkdf2_sha256).getOrElse(account.password),
|
||||
fullName = form.fullName,
|
||||
mailAddress = form.mailAddress,
|
||||
isAdmin = form.isAdmin,
|
||||
description = form.description,
|
||||
url = form.url,
|
||||
isRemoved = form.isRemoved
|
||||
)
|
||||
)
|
||||
|
||||
updateImage(userName, form.fileId, form.clearImage)
|
||||
updateAccountExtraMailAddresses(userName, form.extraMailAddresses.filter(_ != ""))
|
||||
|
||||
// call hooks
|
||||
if (form.isRemoved) PluginRegistry().getAccountHooks.foreach(_.deleted(userName))
|
||||
|
||||
redirect("/admin/users")
|
||||
}
|
||||
} getOrElse NotFound()
|
||||
})
|
||||
|
||||
@@ -498,13 +494,12 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
||||
}
|
||||
.toList
|
||||
|
||||
getAccountByUserName(groupName, true).map {
|
||||
account =>
|
||||
updateGroup(groupName, form.description, form.url, form.isRemoved)
|
||||
getAccountByUserName(groupName, true).map { account =>
|
||||
updateGroup(groupName, form.description, form.url, form.isRemoved)
|
||||
|
||||
if (form.isRemoved) {
|
||||
// Remove from GROUP_MEMBER
|
||||
updateGroupMembers(form.groupName, Nil)
|
||||
if (form.isRemoved) {
|
||||
// Remove from GROUP_MEMBER
|
||||
updateGroupMembers(form.groupName, Nil)
|
||||
// // Remove repositories
|
||||
// getRepositoryNamesOfUser(form.groupName).foreach { repositoryName =>
|
||||
// deleteRepository(groupName, repositoryName)
|
||||
@@ -512,9 +507,9 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
||||
// FileUtils.deleteDirectory(getWikiRepositoryDir(groupName, repositoryName))
|
||||
// FileUtils.deleteDirectory(getTemporaryDir(groupName, repositoryName))
|
||||
// }
|
||||
} else {
|
||||
// Update GROUP_MEMBER
|
||||
updateGroupMembers(form.groupName, members)
|
||||
} else {
|
||||
// Update GROUP_MEMBER
|
||||
updateGroupMembers(form.groupName, members)
|
||||
// // Update COLLABORATOR for group repositories
|
||||
// getRepositoryNamesOfUser(form.groupName).foreach { repositoryName =>
|
||||
// removeCollaborators(form.groupName, repositoryName)
|
||||
@@ -522,10 +517,10 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
||||
// addCollaborator(form.groupName, repositoryName, userName)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
updateImage(form.groupName, form.fileId, form.clearImage)
|
||||
redirect("/admin/users")
|
||||
updateImage(form.groupName, form.fileId, form.clearImage)
|
||||
redirect("/admin/users")
|
||||
|
||||
} getOrElse NotFound()
|
||||
})
|
||||
@@ -565,9 +560,11 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
||||
private def members: Constraint =
|
||||
new Constraint() {
|
||||
override def validate(name: String, value: String, messages: Messages): Option[String] = {
|
||||
if (value.split(",").exists {
|
||||
_.split(":") match { case Array(userName, isManager) => isManager.toBoolean }
|
||||
}) None
|
||||
if (
|
||||
value.split(",").exists {
|
||||
_.split(":") match { case Array(userName, isManager) => isManager.toBoolean }
|
||||
}
|
||||
) None
|
||||
else Some("Must select one manager at least.")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,9 +84,8 @@ trait ValidationSupport extends FormSupport { self: ServletBase with JacksonJson
|
||||
* Converts errors to JSON.
|
||||
*/
|
||||
private def toJson(errors: Seq[(String, String)]): JObject =
|
||||
JObject(errors.map {
|
||||
case (key, value) =>
|
||||
JField(key, JString(value))
|
||||
JObject(errors.map { case (key, value) =>
|
||||
JField(key, JString(value))
|
||||
}.toList)
|
||||
|
||||
}
|
||||
|
||||
@@ -146,39 +146,37 @@ trait WikiControllerBase extends ControllerBase {
|
||||
})
|
||||
|
||||
get("/:owner/:repository/wiki/:page/_revert/:commitId")(readableUsersOnly { repository =>
|
||||
context.withLoginAccount {
|
||||
loginAccount =>
|
||||
if (isEditable(repository)) {
|
||||
val pageName = StringUtil.urlDecode(params("page"))
|
||||
val Array(from, to) = params("commitId").split("\\.\\.\\.")
|
||||
val branch = getWikiBranch(repository.owner, repository.name)
|
||||
context.withLoginAccount { loginAccount =>
|
||||
if (isEditable(repository)) {
|
||||
val pageName = StringUtil.urlDecode(params("page"))
|
||||
val Array(from, to) = params("commitId").split("\\.\\.\\.")
|
||||
val branch = getWikiBranch(repository.owner, repository.name)
|
||||
|
||||
if (revertWikiPage(repository.owner, repository.name, from, to, loginAccount, Some(pageName), branch)) {
|
||||
redirect(s"/${repository.owner}/${repository.name}/wiki/${StringUtil.urlEncode(pageName)}")
|
||||
} else {
|
||||
flash.update("info", "This patch was not able to be reversed.")
|
||||
redirect(
|
||||
s"/${repository.owner}/${repository.name}/wiki/${StringUtil.urlEncode(pageName)}/_compare/${from}...${to}"
|
||||
)
|
||||
}
|
||||
} else Unauthorized()
|
||||
if (revertWikiPage(repository.owner, repository.name, from, to, loginAccount, Some(pageName), branch)) {
|
||||
redirect(s"/${repository.owner}/${repository.name}/wiki/${StringUtil.urlEncode(pageName)}")
|
||||
} else {
|
||||
flash.update("info", "This patch was not able to be reversed.")
|
||||
redirect(
|
||||
s"/${repository.owner}/${repository.name}/wiki/${StringUtil.urlEncode(pageName)}/_compare/${from}...${to}"
|
||||
)
|
||||
}
|
||||
} else Unauthorized()
|
||||
}
|
||||
})
|
||||
|
||||
get("/:owner/:repository/wiki/_revert/:commitId")(readableUsersOnly { repository =>
|
||||
context.withLoginAccount {
|
||||
loginAccount =>
|
||||
if (isEditable(repository)) {
|
||||
val Array(from, to) = params("commitId").split("\\.\\.\\.")
|
||||
val branch = getWikiBranch(repository.owner, repository.name)
|
||||
context.withLoginAccount { loginAccount =>
|
||||
if (isEditable(repository)) {
|
||||
val Array(from, to) = params("commitId").split("\\.\\.\\.")
|
||||
val branch = getWikiBranch(repository.owner, repository.name)
|
||||
|
||||
if (revertWikiPage(repository.owner, repository.name, from, to, loginAccount, None, branch)) {
|
||||
redirect(s"/${repository.owner}/${repository.name}/wiki")
|
||||
} else {
|
||||
flash.update("info", "This patch was not able to be reversed.")
|
||||
redirect(s"/${repository.owner}/${repository.name}/wiki/_compare/${from}...${to}")
|
||||
}
|
||||
} else Unauthorized()
|
||||
if (revertWikiPage(repository.owner, repository.name, from, to, loginAccount, None, branch)) {
|
||||
redirect(s"/${repository.owner}/${repository.name}/wiki")
|
||||
} else {
|
||||
flash.update("info", "This patch was not able to be reversed.")
|
||||
redirect(s"/${repository.owner}/${repository.name}/wiki/_compare/${from}...${to}")
|
||||
}
|
||||
} else Unauthorized()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -192,36 +190,34 @@ trait WikiControllerBase extends ControllerBase {
|
||||
})
|
||||
|
||||
post("/:owner/:repository/wiki/_edit", editForm)(readableUsersOnly { (form, repository) =>
|
||||
context.withLoginAccount {
|
||||
loginAccount =>
|
||||
if (isEditable(repository)) {
|
||||
saveWikiPage(
|
||||
repository.owner,
|
||||
repository.name,
|
||||
form.currentPageName,
|
||||
form.pageName,
|
||||
appendNewLine(convertLineSeparator(form.content, "LF"), "LF"),
|
||||
loginAccount,
|
||||
form.message.getOrElse(""),
|
||||
Some(form.id)
|
||||
).foreach {
|
||||
commitId =>
|
||||
updateLastActivityDate(repository.owner, repository.name)
|
||||
val wikiEditInfo =
|
||||
EditWikiPageInfo(repository.owner, repository.name, loginAccount.userName, form.pageName, commitId)
|
||||
recordActivity(wikiEditInfo)
|
||||
callWebHookOf(repository.owner, repository.name, WebHook.Gollum, context.settings) {
|
||||
getAccountByUserName(repository.owner).map { repositoryUser =>
|
||||
WebHookGollumPayload("edited", form.pageName, commitId, repository, repositoryUser, loginAccount)
|
||||
}
|
||||
}
|
||||
context.withLoginAccount { loginAccount =>
|
||||
if (isEditable(repository)) {
|
||||
saveWikiPage(
|
||||
repository.owner,
|
||||
repository.name,
|
||||
form.currentPageName,
|
||||
form.pageName,
|
||||
appendNewLine(convertLineSeparator(form.content, "LF"), "LF"),
|
||||
loginAccount,
|
||||
form.message.getOrElse(""),
|
||||
Some(form.id)
|
||||
).foreach { commitId =>
|
||||
updateLastActivityDate(repository.owner, repository.name)
|
||||
val wikiEditInfo =
|
||||
EditWikiPageInfo(repository.owner, repository.name, loginAccount.userName, form.pageName, commitId)
|
||||
recordActivity(wikiEditInfo)
|
||||
callWebHookOf(repository.owner, repository.name, WebHook.Gollum, context.settings) {
|
||||
getAccountByUserName(repository.owner).map { repositoryUser =>
|
||||
WebHookGollumPayload("edited", form.pageName, commitId, repository, repositoryUser, loginAccount)
|
||||
}
|
||||
}
|
||||
if (notReservedPageName(form.pageName)) {
|
||||
redirect(s"/${repository.owner}/${repository.name}/wiki/${StringUtil.urlEncode(form.pageName)}")
|
||||
} else {
|
||||
redirect(s"/${repository.owner}/${repository.name}/wiki")
|
||||
}
|
||||
} else Unauthorized()
|
||||
}
|
||||
if (notReservedPageName(form.pageName)) {
|
||||
redirect(s"/${repository.owner}/${repository.name}/wiki/${StringUtil.urlEncode(form.pageName)}")
|
||||
} else {
|
||||
redirect(s"/${repository.owner}/${repository.name}/wiki")
|
||||
}
|
||||
} else Unauthorized()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -232,64 +228,61 @@ trait WikiControllerBase extends ControllerBase {
|
||||
})
|
||||
|
||||
post("/:owner/:repository/wiki/_new", newForm)(readableUsersOnly { (form, repository) =>
|
||||
context.withLoginAccount {
|
||||
loginAccount =>
|
||||
if (isEditable(repository)) {
|
||||
saveWikiPage(
|
||||
repository.owner,
|
||||
repository.name,
|
||||
form.currentPageName,
|
||||
form.pageName,
|
||||
form.content,
|
||||
loginAccount,
|
||||
form.message.getOrElse(""),
|
||||
None
|
||||
).foreach {
|
||||
commitId =>
|
||||
updateLastActivityDate(repository.owner, repository.name)
|
||||
val createWikiPageInfo =
|
||||
CreateWikiPageInfo(repository.owner, repository.name, loginAccount.userName, form.pageName)
|
||||
recordActivity(createWikiPageInfo)
|
||||
callWebHookOf(repository.owner, repository.name, WebHook.Gollum, context.settings) {
|
||||
getAccountByUserName(repository.owner).map { repositoryUser =>
|
||||
WebHookGollumPayload("created", form.pageName, commitId, repository, repositoryUser, loginAccount)
|
||||
}
|
||||
}
|
||||
context.withLoginAccount { loginAccount =>
|
||||
if (isEditable(repository)) {
|
||||
saveWikiPage(
|
||||
repository.owner,
|
||||
repository.name,
|
||||
form.currentPageName,
|
||||
form.pageName,
|
||||
form.content,
|
||||
loginAccount,
|
||||
form.message.getOrElse(""),
|
||||
None
|
||||
).foreach { commitId =>
|
||||
updateLastActivityDate(repository.owner, repository.name)
|
||||
val createWikiPageInfo =
|
||||
CreateWikiPageInfo(repository.owner, repository.name, loginAccount.userName, form.pageName)
|
||||
recordActivity(createWikiPageInfo)
|
||||
callWebHookOf(repository.owner, repository.name, WebHook.Gollum, context.settings) {
|
||||
getAccountByUserName(repository.owner).map { repositoryUser =>
|
||||
WebHookGollumPayload("created", form.pageName, commitId, repository, repositoryUser, loginAccount)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (notReservedPageName(form.pageName)) {
|
||||
redirect(s"/${repository.owner}/${repository.name}/wiki/${StringUtil.urlEncode(form.pageName)}")
|
||||
} else {
|
||||
redirect(s"/${repository.owner}/${repository.name}/wiki")
|
||||
}
|
||||
} else Unauthorized()
|
||||
if (notReservedPageName(form.pageName)) {
|
||||
redirect(s"/${repository.owner}/${repository.name}/wiki/${StringUtil.urlEncode(form.pageName)}")
|
||||
} else {
|
||||
redirect(s"/${repository.owner}/${repository.name}/wiki")
|
||||
}
|
||||
} else Unauthorized()
|
||||
}
|
||||
})
|
||||
|
||||
get("/:owner/:repository/wiki/:page/_delete")(readableUsersOnly { repository =>
|
||||
context.withLoginAccount {
|
||||
loginAccount =>
|
||||
if (isEditable(repository)) {
|
||||
val pageName = StringUtil.urlDecode(params("page"))
|
||||
deleteWikiPage(
|
||||
repository.owner,
|
||||
repository.name,
|
||||
pageName,
|
||||
loginAccount.fullName,
|
||||
loginAccount.mailAddress,
|
||||
s"Destroyed ${pageName}"
|
||||
)
|
||||
val deleteWikiInfo = DeleteWikiInfo(
|
||||
repository.owner,
|
||||
repository.name,
|
||||
loginAccount.userName,
|
||||
pageName
|
||||
)
|
||||
recordActivity(deleteWikiInfo)
|
||||
updateLastActivityDate(repository.owner, repository.name)
|
||||
context.withLoginAccount { loginAccount =>
|
||||
if (isEditable(repository)) {
|
||||
val pageName = StringUtil.urlDecode(params("page"))
|
||||
deleteWikiPage(
|
||||
repository.owner,
|
||||
repository.name,
|
||||
pageName,
|
||||
loginAccount.fullName,
|
||||
loginAccount.mailAddress,
|
||||
s"Destroyed ${pageName}"
|
||||
)
|
||||
val deleteWikiInfo = DeleteWikiInfo(
|
||||
repository.owner,
|
||||
repository.name,
|
||||
loginAccount.userName,
|
||||
pageName
|
||||
)
|
||||
recordActivity(deleteWikiInfo)
|
||||
updateLastActivityDate(repository.owner, repository.name)
|
||||
|
||||
redirect(s"/${repository.owner}/${repository.name}/wiki")
|
||||
} else Unauthorized()
|
||||
redirect(s"/${repository.owner}/${repository.name}/wiki")
|
||||
} else Unauthorized()
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -58,27 +58,25 @@ trait ApiGitReferenceControllerBase extends ControllerBase {
|
||||
* https://docs.github.com/en/free-pro-team@latest/rest/reference/git#create-a-reference
|
||||
*/
|
||||
post("/api/v3/repos/:owner/:repository/git/refs")(writableUsersOnly { repository =>
|
||||
extractFromJsonBody[CreateARef].map {
|
||||
data =>
|
||||
Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) {
|
||||
git =>
|
||||
val ref = git.getRepository.findRef(data.ref)
|
||||
if (ref == null) {
|
||||
val update = git.getRepository.updateRef(data.ref)
|
||||
update.setNewObjectId(ObjectId.fromString(data.sha))
|
||||
val result = update.update()
|
||||
result match {
|
||||
case Result.NEW =>
|
||||
JsonFormat(
|
||||
ApiRef
|
||||
.fromRef(RepositoryName(repository.owner, repository.name), git.getRepository.findRef(data.ref))
|
||||
)
|
||||
case _ => UnprocessableEntity(result.name())
|
||||
}
|
||||
} else {
|
||||
UnprocessableEntity("Ref already exists.")
|
||||
}
|
||||
extractFromJsonBody[CreateARef].map { data =>
|
||||
Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) { git =>
|
||||
val ref = git.getRepository.findRef(data.ref)
|
||||
if (ref == null) {
|
||||
val update = git.getRepository.updateRef(data.ref)
|
||||
update.setNewObjectId(ObjectId.fromString(data.sha))
|
||||
val result = update.update()
|
||||
result match {
|
||||
case Result.NEW =>
|
||||
JsonFormat(
|
||||
ApiRef
|
||||
.fromRef(RepositoryName(repository.owner, repository.name), git.getRepository.findRef(data.ref))
|
||||
)
|
||||
case _ => UnprocessableEntity(result.name())
|
||||
}
|
||||
} else {
|
||||
UnprocessableEntity("Ref already exists.")
|
||||
}
|
||||
}
|
||||
} getOrElse BadRequest()
|
||||
})
|
||||
|
||||
@@ -88,24 +86,23 @@ trait ApiGitReferenceControllerBase extends ControllerBase {
|
||||
*/
|
||||
patch("/api/v3/repos/:owner/:repository/git/refs/*")(writableUsersOnly { repository =>
|
||||
val refName = multiParams("splat").mkString("/")
|
||||
extractFromJsonBody[UpdateARef].map {
|
||||
data =>
|
||||
Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) { git =>
|
||||
val ref = git.getRepository.findRef(refName)
|
||||
if (ref == null) {
|
||||
UnprocessableEntity("Ref does not exist.")
|
||||
} else {
|
||||
val update = git.getRepository.updateRef(ref.getName)
|
||||
update.setNewObjectId(ObjectId.fromString(data.sha))
|
||||
update.setForceUpdate(data.force)
|
||||
val result = update.update()
|
||||
result match {
|
||||
case Result.FORCED | Result.FAST_FORWARD | Result.NO_CHANGE =>
|
||||
JsonFormat(ApiRef.fromRef(RepositoryName(repository), git.getRepository.findRef(refName)))
|
||||
case _ => UnprocessableEntity(result.name())
|
||||
}
|
||||
extractFromJsonBody[UpdateARef].map { data =>
|
||||
Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) { git =>
|
||||
val ref = git.getRepository.findRef(refName)
|
||||
if (ref == null) {
|
||||
UnprocessableEntity("Ref does not exist.")
|
||||
} else {
|
||||
val update = git.getRepository.updateRef(ref.getName)
|
||||
update.setNewObjectId(ObjectId.fromString(data.sha))
|
||||
update.setForceUpdate(data.force)
|
||||
val result = update.update()
|
||||
result match {
|
||||
case Result.FORCED | Result.FAST_FORWARD | Result.NO_CHANGE =>
|
||||
JsonFormat(ApiRef.fromRef(RepositoryName(repository), git.getRepository.findRef(refName)))
|
||||
case _ => UnprocessableEntity(result.name())
|
||||
}
|
||||
}
|
||||
}
|
||||
} getOrElse BadRequest()
|
||||
})
|
||||
|
||||
|
||||
@@ -23,9 +23,8 @@ trait ApiIssueCommentControllerBase extends ControllerBase {
|
||||
issueId <- params("id").toIntOpt
|
||||
comments = getCommentsForApi(repository.owner, repository.name, issueId)
|
||||
} yield {
|
||||
JsonFormat(comments.map {
|
||||
case (issueComment, user, issue) =>
|
||||
ApiComment(issueComment, RepositoryName(repository), issueId, ApiUser(user), issue.isPullRequest)
|
||||
JsonFormat(comments.map { case (issueComment, user, issue) =>
|
||||
ApiComment(issueComment, RepositoryName(repository), issueId, ApiUser(user), issue.isPullRequest)
|
||||
})
|
||||
}) getOrElse NotFound()
|
||||
})
|
||||
|
||||
@@ -29,7 +29,7 @@ trait ApiIssueControllerBase extends ControllerBase {
|
||||
val page = IssueSearchCondition.page(request)
|
||||
// TODO: more api spec condition
|
||||
val condition = IssueSearchCondition(request)
|
||||
//val baseOwner = getAccountByUserName(repository.owner).get
|
||||
// val baseOwner = getAccountByUserName(repository.owner).get
|
||||
|
||||
val issues: List[(Issue, Account, List[Account])] =
|
||||
searchIssueByApi(
|
||||
@@ -39,17 +39,16 @@ trait ApiIssueControllerBase extends ControllerBase {
|
||||
repos = repository.owner -> repository.name
|
||||
)
|
||||
|
||||
JsonFormat(issues.map {
|
||||
case (issue, issueUser, assigneeUsers) =>
|
||||
ApiIssue(
|
||||
issue = issue,
|
||||
repositoryName = RepositoryName(repository),
|
||||
user = ApiUser(issueUser),
|
||||
assignees = assigneeUsers.map(ApiUser(_)),
|
||||
labels = getIssueLabels(repository.owner, repository.name, issue.issueId)
|
||||
.map(ApiLabel(_, RepositoryName(repository))),
|
||||
issue.milestoneId.flatMap { getApiMilestone(repository, _) }
|
||||
)
|
||||
JsonFormat(issues.map { case (issue, issueUser, assigneeUsers) =>
|
||||
ApiIssue(
|
||||
issue = issue,
|
||||
repositoryName = RepositoryName(repository),
|
||||
user = ApiUser(issueUser),
|
||||
assignees = assigneeUsers.map(ApiUser(_)),
|
||||
labels = getIssueLabels(repository.owner, repository.name, issue.issueId)
|
||||
.map(ApiLabel(_, RepositoryName(repository))),
|
||||
issue.milestoneId.flatMap { getApiMilestone(repository, _) }
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -126,7 +125,7 @@ trait ApiIssueControllerBase extends ControllerBase {
|
||||
*/
|
||||
|
||||
/*
|
||||
* vii. Unlock an issue
|
||||
* https://developer.github.com/v3/issues/#unlock-an-issue
|
||||
*/
|
||||
* vii. Unlock an issue
|
||||
* https://developer.github.com/v3/issues/#unlock-an-issue
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -69,25 +69,24 @@ trait ApiIssueLabelControllerBase extends ControllerBase {
|
||||
data <- extractFromJsonBody[CreateALabel] if data.isValid
|
||||
} yield {
|
||||
LockUtil.lock(RepositoryName(repository).fullName) {
|
||||
getLabel(repository.owner, repository.name, params("labelName")).map {
|
||||
label =>
|
||||
if (getLabel(repository.owner, repository.name, data.name).isEmpty) {
|
||||
updateLabel(repository.owner, repository.name, label.labelId, data.name, data.color)
|
||||
JsonFormat(
|
||||
ApiLabel(
|
||||
getLabel(repository.owner, repository.name, label.labelId).get,
|
||||
RepositoryName(repository)
|
||||
)
|
||||
getLabel(repository.owner, repository.name, params("labelName")).map { label =>
|
||||
if (getLabel(repository.owner, repository.name, data.name).isEmpty) {
|
||||
updateLabel(repository.owner, repository.name, label.labelId, data.name, data.color)
|
||||
JsonFormat(
|
||||
ApiLabel(
|
||||
getLabel(repository.owner, repository.name, label.labelId).get,
|
||||
RepositoryName(repository)
|
||||
)
|
||||
} else {
|
||||
// TODO ApiError should support errors field to enhance compatibility of GitHub API
|
||||
UnprocessableEntity(
|
||||
ApiError(
|
||||
"Validation Failed",
|
||||
Some("https://developer.github.com/v3/issues/labels/#create-a-label")
|
||||
)
|
||||
)
|
||||
} else {
|
||||
// TODO ApiError should support errors field to enhance compatibility of GitHub API
|
||||
UnprocessableEntity(
|
||||
ApiError(
|
||||
"Validation Failed",
|
||||
Some("https://developer.github.com/v3/issues/labels/#create-a-label")
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
} getOrElse NotFound()
|
||||
}
|
||||
}) getOrElse NotFound()
|
||||
@@ -189,7 +188,7 @@ trait ApiIssueLabelControllerBase extends ControllerBase {
|
||||
})
|
||||
|
||||
/*
|
||||
* xi Get labels for every issue in a milestone
|
||||
* https://developer.github.com/v3/issues/labels/#get-labels-for-every-issue-in-a-milestone
|
||||
*/
|
||||
* xi Get labels for every issue in a milestone
|
||||
* https://developer.github.com/v3/issues/labels/#get-labels-for-every-issue-in-a-milestone
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -16,8 +16,10 @@ trait ApiIssueMilestoneControllerBase extends ControllerBase {
|
||||
get("/api/v3/repos/:owner/:repository/milestones")(referrersOnly { repository =>
|
||||
val state = params.getOrElse("state", "all")
|
||||
// TODO "sort", "direction" params should be implemented.
|
||||
val apiMilestones = (for (milestoneWithIssue <- getMilestonesWithIssueCount(repository.owner, repository.name)
|
||||
.sortBy(p => p._1.milestoneId))
|
||||
val apiMilestones = (for (
|
||||
milestoneWithIssue <- getMilestonesWithIssueCount(repository.owner, repository.name)
|
||||
.sortBy(p => p._1.milestoneId)
|
||||
)
|
||||
yield {
|
||||
ApiMilestone(
|
||||
repository.repository,
|
||||
|
||||
@@ -71,6 +71,6 @@ trait ApiOrganizationControllerBase extends ControllerBase {
|
||||
*/
|
||||
|
||||
/*
|
||||
* should implement delete an organization API?
|
||||
*/
|
||||
* should implement delete an organization API?
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -48,19 +48,18 @@ trait ApiPullRequestControllerBase extends ControllerBase {
|
||||
repos = repository.owner -> repository.name
|
||||
)
|
||||
|
||||
JsonFormat(issues.map {
|
||||
case (issue, issueUser, commentCount, pullRequest, headRepo, headOwner, assignees) =>
|
||||
ApiPullRequest(
|
||||
issue = issue,
|
||||
pullRequest = pullRequest,
|
||||
headRepo = ApiRepository(headRepo, ApiUser(headOwner)),
|
||||
baseRepo = ApiRepository(repository, ApiUser(baseOwner)),
|
||||
user = ApiUser(issueUser),
|
||||
labels = getIssueLabels(repository.owner, repository.name, issue.issueId)
|
||||
.map(ApiLabel(_, RepositoryName(repository))),
|
||||
assignees = assignees.map(ApiUser.apply),
|
||||
mergedComment = getMergedComment(repository.owner, repository.name, issue.issueId)
|
||||
)
|
||||
JsonFormat(issues.map { case (issue, issueUser, commentCount, pullRequest, headRepo, headOwner, assignees) =>
|
||||
ApiPullRequest(
|
||||
issue = issue,
|
||||
pullRequest = pullRequest,
|
||||
headRepo = ApiRepository(headRepo, ApiUser(headOwner)),
|
||||
baseRepo = ApiRepository(repository, ApiUser(baseOwner)),
|
||||
user = ApiUser(issueUser),
|
||||
labels = getIssueLabels(repository.owner, repository.name, issue.issueId)
|
||||
.map(ApiLabel(_, RepositoryName(repository))),
|
||||
assignees = assignees.map(ApiUser.apply),
|
||||
mergedComment = getMergedComment(repository.owner, repository.name, issue.issueId)
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -89,38 +88,37 @@ trait ApiPullRequestControllerBase extends ControllerBase {
|
||||
case Left(createPullReq) =>
|
||||
val (reqOwner, reqBranch) = parseCompareIdentifier(createPullReq.head, repository.owner)
|
||||
getRepository(reqOwner, repository.name)
|
||||
.flatMap {
|
||||
forkedRepository =>
|
||||
getPullRequestCommitFromTo(repository, forkedRepository, createPullReq.base, reqBranch) match {
|
||||
case (Some(commitIdFrom), Some(commitIdTo)) =>
|
||||
val issueId = insertIssue(
|
||||
owner = repository.owner,
|
||||
repository = repository.name,
|
||||
loginUser = context.loginAccount.get.userName,
|
||||
title = createPullReq.title,
|
||||
content = createPullReq.body,
|
||||
milestoneId = None,
|
||||
priorityId = None,
|
||||
isPullRequest = true
|
||||
)
|
||||
.flatMap { forkedRepository =>
|
||||
getPullRequestCommitFromTo(repository, forkedRepository, createPullReq.base, reqBranch) match {
|
||||
case (Some(commitIdFrom), Some(commitIdTo)) =>
|
||||
val issueId = insertIssue(
|
||||
owner = repository.owner,
|
||||
repository = repository.name,
|
||||
loginUser = context.loginAccount.get.userName,
|
||||
title = createPullReq.title,
|
||||
content = createPullReq.body,
|
||||
milestoneId = None,
|
||||
priorityId = None,
|
||||
isPullRequest = true
|
||||
)
|
||||
|
||||
createPullRequest(
|
||||
originRepository = repository,
|
||||
issueId = issueId,
|
||||
originBranch = createPullReq.base,
|
||||
requestUserName = reqOwner,
|
||||
requestRepositoryName = repository.name,
|
||||
requestBranch = reqBranch,
|
||||
commitIdFrom = commitIdFrom.getName,
|
||||
commitIdTo = commitIdTo.getName,
|
||||
isDraft = createPullReq.draft.getOrElse(false),
|
||||
loginAccount = context.loginAccount.get,
|
||||
settings = context.settings
|
||||
)
|
||||
getApiPullRequest(repository, issueId).map(JsonFormat(_))
|
||||
case _ =>
|
||||
None
|
||||
}
|
||||
createPullRequest(
|
||||
originRepository = repository,
|
||||
issueId = issueId,
|
||||
originBranch = createPullReq.base,
|
||||
requestUserName = reqOwner,
|
||||
requestRepositoryName = repository.name,
|
||||
requestBranch = reqBranch,
|
||||
commitIdFrom = commitIdFrom.getName,
|
||||
commitIdTo = commitIdTo.getName,
|
||||
isDraft = createPullReq.draft.getOrElse(false),
|
||||
loginAccount = context.loginAccount.get,
|
||||
settings = context.settings
|
||||
)
|
||||
getApiPullRequest(repository, issueId).map(JsonFormat(_))
|
||||
case _ =>
|
||||
None
|
||||
}
|
||||
}
|
||||
.getOrElse {
|
||||
NotFound()
|
||||
@@ -128,28 +126,27 @@ trait ApiPullRequestControllerBase extends ControllerBase {
|
||||
case Right(createPullReqAlt) =>
|
||||
val (reqOwner, reqBranch) = parseCompareIdentifier(createPullReqAlt.head, repository.owner)
|
||||
getRepository(reqOwner, repository.name)
|
||||
.flatMap {
|
||||
forkedRepository =>
|
||||
getPullRequestCommitFromTo(repository, forkedRepository, createPullReqAlt.base, reqBranch) match {
|
||||
case (Some(commitIdFrom), Some(commitIdTo)) =>
|
||||
changeIssueToPullRequest(repository.owner, repository.name, createPullReqAlt.issue)
|
||||
createPullRequest(
|
||||
originRepository = repository,
|
||||
issueId = createPullReqAlt.issue,
|
||||
originBranch = createPullReqAlt.base,
|
||||
requestUserName = reqOwner,
|
||||
requestRepositoryName = repository.name,
|
||||
requestBranch = reqBranch,
|
||||
commitIdFrom = commitIdFrom.getName,
|
||||
commitIdTo = commitIdTo.getName,
|
||||
isDraft = false,
|
||||
loginAccount = context.loginAccount.get,
|
||||
settings = context.settings
|
||||
)
|
||||
getApiPullRequest(repository, createPullReqAlt.issue).map(JsonFormat(_))
|
||||
case _ =>
|
||||
None
|
||||
}
|
||||
.flatMap { forkedRepository =>
|
||||
getPullRequestCommitFromTo(repository, forkedRepository, createPullReqAlt.base, reqBranch) match {
|
||||
case (Some(commitIdFrom), Some(commitIdTo)) =>
|
||||
changeIssueToPullRequest(repository.owner, repository.name, createPullReqAlt.issue)
|
||||
createPullRequest(
|
||||
originRepository = repository,
|
||||
issueId = createPullReqAlt.issue,
|
||||
originBranch = createPullReqAlt.base,
|
||||
requestUserName = reqOwner,
|
||||
requestRepositoryName = repository.name,
|
||||
requestBranch = reqBranch,
|
||||
commitIdFrom = commitIdFrom.getName,
|
||||
commitIdTo = commitIdTo.getName,
|
||||
isDraft = false,
|
||||
loginAccount = context.loginAccount.get,
|
||||
settings = context.settings
|
||||
)
|
||||
getApiPullRequest(repository, createPullReqAlt.issue).map(JsonFormat(_))
|
||||
case _ =>
|
||||
None
|
||||
}
|
||||
}
|
||||
.getOrElse {
|
||||
NotFound()
|
||||
@@ -190,26 +187,24 @@ trait ApiPullRequestControllerBase extends ControllerBase {
|
||||
get("/api/v3/repos/:owner/:repository/pulls/:id/commits")(referrersOnly { repository =>
|
||||
val owner = repository.owner
|
||||
val name = repository.name
|
||||
params("id").toIntOpt.flatMap {
|
||||
issueId =>
|
||||
getPullRequest(owner, name, issueId) map {
|
||||
case (issue, pullreq) =>
|
||||
Using.resource(Git.open(getRepositoryDir(owner, name))) { git =>
|
||||
val oldId = git.getRepository.resolve(pullreq.commitIdFrom)
|
||||
val newId = git.getRepository.resolve(pullreq.commitIdTo)
|
||||
val repoFullName = RepositoryName(repository)
|
||||
val commits = git.log
|
||||
.addRange(oldId, newId)
|
||||
.call
|
||||
.iterator
|
||||
.asScala
|
||||
.map { c =>
|
||||
ApiCommitListItem(new CommitInfo(c), repoFullName)
|
||||
}
|
||||
.toList
|
||||
JsonFormat(commits)
|
||||
params("id").toIntOpt.flatMap { issueId =>
|
||||
getPullRequest(owner, name, issueId) map { case (issue, pullreq) =>
|
||||
Using.resource(Git.open(getRepositoryDir(owner, name))) { git =>
|
||||
val oldId = git.getRepository.resolve(pullreq.commitIdFrom)
|
||||
val newId = git.getRepository.resolve(pullreq.commitIdTo)
|
||||
val repoFullName = RepositoryName(repository)
|
||||
val commits = git.log
|
||||
.addRange(oldId, newId)
|
||||
.call
|
||||
.iterator
|
||||
.asScala
|
||||
.map { c =>
|
||||
ApiCommitListItem(new CommitInfo(c), repoFullName)
|
||||
}
|
||||
.toList
|
||||
JsonFormat(commits)
|
||||
}
|
||||
}
|
||||
} getOrElse NotFound()
|
||||
})
|
||||
/*
|
||||
@@ -240,8 +235,8 @@ trait ApiPullRequestControllerBase extends ControllerBase {
|
||||
*/
|
||||
put("/api/v3/repos/:owner/:repository/pulls/:id/merge")(referrersOnly { repository =>
|
||||
(for {
|
||||
//TODO: crash when body is empty
|
||||
//TODO: Implement sha parameter
|
||||
// TODO: crash when body is empty
|
||||
// TODO: Implement sha parameter
|
||||
data <- extractFromJsonBody[MergeAPullRequest]
|
||||
issueId <- params("id").toIntOpt
|
||||
(issue, pullReq) <- getPullRequest(repository.owner, repository.name, issueId)
|
||||
@@ -273,7 +268,7 @@ trait ApiPullRequestControllerBase extends ControllerBase {
|
||||
repository,
|
||||
issueId,
|
||||
context.loginAccount.get,
|
||||
data.commit_message.getOrElse(""), //TODO: Implement commit_title
|
||||
data.commit_message.getOrElse(""), // TODO: Implement commit_title
|
||||
strategy,
|
||||
pullReq.isDraft,
|
||||
context.settings
|
||||
|
||||
@@ -119,40 +119,39 @@ trait ApiReleaseControllerBase extends ControllerBase {
|
||||
* ix. Upload a release asset
|
||||
* https://developer.github.com/v3/repos/releases/#upload-a-release-asset
|
||||
*/
|
||||
post("/api/v3/repos/:owner/:repository/releases/:tag/assets")(writableUsersOnly {
|
||||
repository =>
|
||||
val name = params("name")
|
||||
val tag = params("tag")
|
||||
getRelease(repository.owner, repository.name, tag)
|
||||
.map { release =>
|
||||
val fileId = FileUtil.generateFileId
|
||||
val buf = new Array[Byte](request.inputStream.available())
|
||||
request.inputStream.read(buf)
|
||||
FileUtils.writeByteArrayToFile(
|
||||
new File(
|
||||
getReleaseFilesDir(repository.owner, repository.name),
|
||||
FileUtil.checkFilename(tag + "/" + fileId)
|
||||
),
|
||||
buf
|
||||
)
|
||||
createReleaseAsset(
|
||||
repository.owner,
|
||||
repository.name,
|
||||
tag,
|
||||
fileId,
|
||||
name,
|
||||
request.contentLength.getOrElse(0),
|
||||
context.loginAccount.get
|
||||
)
|
||||
getReleaseAsset(repository.owner, repository.name, tag, fileId)
|
||||
.map { asset =>
|
||||
JsonFormat(ApiReleaseAsset(asset, RepositoryName(repository)))
|
||||
}
|
||||
.getOrElse {
|
||||
ApiError("Unknown error")
|
||||
}
|
||||
}
|
||||
.getOrElse(NotFound())
|
||||
post("/api/v3/repos/:owner/:repository/releases/:tag/assets")(writableUsersOnly { repository =>
|
||||
val name = params("name")
|
||||
val tag = params("tag")
|
||||
getRelease(repository.owner, repository.name, tag)
|
||||
.map { release =>
|
||||
val fileId = FileUtil.generateFileId
|
||||
val buf = new Array[Byte](request.inputStream.available())
|
||||
request.inputStream.read(buf)
|
||||
FileUtils.writeByteArrayToFile(
|
||||
new File(
|
||||
getReleaseFilesDir(repository.owner, repository.name),
|
||||
FileUtil.checkFilename(tag + "/" + fileId)
|
||||
),
|
||||
buf
|
||||
)
|
||||
createReleaseAsset(
|
||||
repository.owner,
|
||||
repository.name,
|
||||
tag,
|
||||
fileId,
|
||||
name,
|
||||
request.contentLength.getOrElse(0),
|
||||
context.loginAccount.get
|
||||
)
|
||||
getReleaseAsset(repository.owner, repository.name, tag, fileId)
|
||||
.map { asset =>
|
||||
JsonFormat(ApiReleaseAsset(asset, RepositoryName(repository)))
|
||||
}
|
||||
.getOrElse {
|
||||
ApiError("Unknown error")
|
||||
}
|
||||
}
|
||||
.getOrElse(NotFound())
|
||||
})
|
||||
|
||||
/**
|
||||
@@ -176,7 +175,7 @@ trait ApiReleaseControllerBase extends ControllerBase {
|
||||
*/
|
||||
|
||||
/*
|
||||
* xii. Delete a release asset
|
||||
* https://developer.github.com/v3/repos/releases/#edit-a-release-asset
|
||||
*/
|
||||
* xii. Delete a release asset
|
||||
* https://developer.github.com/v3/repos/releases/#edit-a-release-asset
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -47,21 +47,20 @@ trait ApiRepositoryBranchControllerBase extends ControllerBase {
|
||||
* https://docs.github.com/en/rest/reference/repos#get-a-branch
|
||||
*/
|
||||
get("/api/v3/repos/:owner/:repository/branches/*")(referrersOnly { repository =>
|
||||
Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) {
|
||||
git =>
|
||||
(for {
|
||||
branch <- params.get("splat") if repository.branchList.contains(branch)
|
||||
br <- getBranches(
|
||||
git,
|
||||
repository.repository.defaultBranch,
|
||||
repository.repository.originUserName.isEmpty
|
||||
).find(_.name == branch)
|
||||
} yield {
|
||||
val protection = getProtectedBranchInfo(repository.owner, repository.name, branch)
|
||||
JsonFormat(
|
||||
ApiBranch(branch, ApiBranchCommit(br.commitId), ApiBranchProtection(protection))(RepositoryName(repository))
|
||||
)
|
||||
}) getOrElse NotFound()
|
||||
Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) { git =>
|
||||
(for {
|
||||
branch <- params.get("splat") if repository.branchList.contains(branch)
|
||||
br <- getBranches(
|
||||
git,
|
||||
repository.repository.defaultBranch,
|
||||
repository.repository.originUserName.isEmpty
|
||||
).find(_.name == branch)
|
||||
} yield {
|
||||
val protection = getProtectedBranchInfo(repository.owner, repository.name, branch)
|
||||
JsonFormat(
|
||||
ApiBranch(branch, ApiBranchCommit(br.commitId), ApiBranchProtection(protection))(RepositoryName(repository))
|
||||
)
|
||||
}) getOrElse NotFound()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -275,30 +274,29 @@ trait ApiRepositoryBranchControllerBase extends ControllerBase {
|
||||
*/
|
||||
patch("/api/v3/repos/:owner/:repository/branches/*")(ownerOnly { repository =>
|
||||
import gitbucket.core.api._
|
||||
Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) {
|
||||
git =>
|
||||
(for {
|
||||
branch <- params.get("splat") if repository.branchList.contains(branch)
|
||||
protection <- extractFromJsonBody[ApiBranchProtection.EnablingAndDisabling].map(_.protection)
|
||||
br <- getBranches(
|
||||
git,
|
||||
repository.repository.defaultBranch,
|
||||
repository.repository.originUserName.isEmpty
|
||||
).find(_.name == branch)
|
||||
} yield {
|
||||
if (protection.enabled) {
|
||||
enableBranchProtection(
|
||||
repository.owner,
|
||||
repository.name,
|
||||
branch,
|
||||
protection.status.enforcement_level == ApiBranchProtection.Everyone,
|
||||
protection.status.contexts
|
||||
)
|
||||
} else {
|
||||
disableBranchProtection(repository.owner, repository.name, branch)
|
||||
}
|
||||
JsonFormat(ApiBranch(branch, ApiBranchCommit(br.commitId), protection)(RepositoryName(repository)))
|
||||
}) getOrElse NotFound()
|
||||
Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) { git =>
|
||||
(for {
|
||||
branch <- params.get("splat") if repository.branchList.contains(branch)
|
||||
protection <- extractFromJsonBody[ApiBranchProtection.EnablingAndDisabling].map(_.protection)
|
||||
br <- getBranches(
|
||||
git,
|
||||
repository.repository.defaultBranch,
|
||||
repository.repository.originUserName.isEmpty
|
||||
).find(_.name == branch)
|
||||
} yield {
|
||||
if (protection.enabled) {
|
||||
enableBranchProtection(
|
||||
repository.owner,
|
||||
repository.name,
|
||||
branch,
|
||||
protection.status.enforcement_level == ApiBranchProtection.Everyone,
|
||||
protection.status.contexts
|
||||
)
|
||||
} else {
|
||||
disableBranchProtection(repository.owner, repository.name, branch)
|
||||
}
|
||||
JsonFormat(ApiBranch(branch, ApiBranchCommit(br.commitId), protection)(RepositoryName(repository)))
|
||||
}) getOrElse NotFound()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -43,56 +43,53 @@ trait ApiRepositoryCommitControllerBase extends ControllerBase {
|
||||
val path = params.get("path").filter(_.nonEmpty)
|
||||
val since = params.get("since").filter(_.nonEmpty)
|
||||
val until = params.get("until").filter(_.nonEmpty)
|
||||
Using.resource(Git.open(getRepositoryDir(owner, name))) {
|
||||
git =>
|
||||
val repo = git.getRepository
|
||||
Using.resource(new RevWalk(repo)) {
|
||||
revWalk =>
|
||||
val objectId = repo.resolve(sha)
|
||||
revWalk.markStart(revWalk.parseCommit(objectId))
|
||||
if (path.nonEmpty) {
|
||||
revWalk.setTreeFilter(
|
||||
AndTreeFilter.create(PathFilterGroup.createFromStrings(path.get), TreeFilter.ANY_DIFF)
|
||||
)
|
||||
}
|
||||
val revfilters = new ListBuffer[(RevFilter)]()
|
||||
if (author.nonEmpty) {
|
||||
revfilters += AuthorRevFilter.create(author.get)
|
||||
}
|
||||
if (since.nonEmpty) {
|
||||
revfilters += CommitTimeRevFilter.after(
|
||||
Date.from(LocalDateTime.parse(since.get, ISO_DATE_TIME).toInstant(ZoneOffset.UTC))
|
||||
)
|
||||
}
|
||||
if (until.nonEmpty) {
|
||||
revfilters += CommitTimeRevFilter.before(
|
||||
Date.from(LocalDateTime.parse(until.get, ISO_DATE_TIME).toInstant(ZoneOffset.UTC))
|
||||
)
|
||||
}
|
||||
if (page > 1) {
|
||||
revfilters += SkipRevFilter.create(page * per_page - 2)
|
||||
}
|
||||
revfilters += MaxCountRevFilter.create(per_page);
|
||||
revWalk.setRevFilter(
|
||||
if (revfilters.size > 1) {
|
||||
AndRevFilter.create(revfilters.toArray)
|
||||
} else {
|
||||
revfilters(0)
|
||||
}
|
||||
)
|
||||
JsonFormat(revWalk.asScala.map {
|
||||
commit =>
|
||||
val commitInfo = new CommitInfo(commit)
|
||||
ApiCommits(
|
||||
repositoryName = RepositoryName(repository),
|
||||
commitInfo = commitInfo,
|
||||
diffs = JGitUtil.getDiffs(git, commitInfo.parents.headOption, commitInfo.id, false, true),
|
||||
author = getAccount(commitInfo.authorName, commitInfo.authorEmailAddress),
|
||||
committer = getAccount(commitInfo.committerName, commitInfo.committerEmailAddress),
|
||||
commentCount = getCommitComment(repository.owner, repository.name, commitInfo.id).size
|
||||
)
|
||||
})
|
||||
Using.resource(Git.open(getRepositoryDir(owner, name))) { git =>
|
||||
val repo = git.getRepository
|
||||
Using.resource(new RevWalk(repo)) { revWalk =>
|
||||
val objectId = repo.resolve(sha)
|
||||
revWalk.markStart(revWalk.parseCommit(objectId))
|
||||
if (path.nonEmpty) {
|
||||
revWalk.setTreeFilter(
|
||||
AndTreeFilter.create(PathFilterGroup.createFromStrings(path.get), TreeFilter.ANY_DIFF)
|
||||
)
|
||||
}
|
||||
val revfilters = new ListBuffer[(RevFilter)]()
|
||||
if (author.nonEmpty) {
|
||||
revfilters += AuthorRevFilter.create(author.get)
|
||||
}
|
||||
if (since.nonEmpty) {
|
||||
revfilters += CommitTimeRevFilter.after(
|
||||
Date.from(LocalDateTime.parse(since.get, ISO_DATE_TIME).toInstant(ZoneOffset.UTC))
|
||||
)
|
||||
}
|
||||
if (until.nonEmpty) {
|
||||
revfilters += CommitTimeRevFilter.before(
|
||||
Date.from(LocalDateTime.parse(until.get, ISO_DATE_TIME).toInstant(ZoneOffset.UTC))
|
||||
)
|
||||
}
|
||||
if (page > 1) {
|
||||
revfilters += SkipRevFilter.create(page * per_page - 2)
|
||||
}
|
||||
revfilters += MaxCountRevFilter.create(per_page);
|
||||
revWalk.setRevFilter(
|
||||
if (revfilters.size > 1) {
|
||||
AndRevFilter.create(revfilters.toArray)
|
||||
} else {
|
||||
revfilters(0)
|
||||
}
|
||||
)
|
||||
JsonFormat(revWalk.asScala.map { commit =>
|
||||
val commitInfo = new CommitInfo(commit)
|
||||
ApiCommits(
|
||||
repositoryName = RepositoryName(repository),
|
||||
commitInfo = commitInfo,
|
||||
diffs = JGitUtil.getDiffs(git, commitInfo.parents.headOption, commitInfo.id, false, true),
|
||||
author = getAccount(commitInfo.authorName, commitInfo.authorEmailAddress),
|
||||
committer = getAccount(commitInfo.committerName, commitInfo.committerEmailAddress),
|
||||
commentCount = getCommitComment(repository.owner, repository.name, commitInfo.id).size
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -105,24 +102,23 @@ trait ApiRepositoryCommitControllerBase extends ControllerBase {
|
||||
val name = repository.name
|
||||
val sha = params("sha")
|
||||
|
||||
Using.resource(Git.open(getRepositoryDir(owner, name))) {
|
||||
git =>
|
||||
val repo = git.getRepository
|
||||
val objectId = repo.resolve(sha)
|
||||
val commitInfo = Using.resource(new RevWalk(repo)) { revWalk =>
|
||||
new CommitInfo(revWalk.parseCommit(objectId))
|
||||
}
|
||||
Using.resource(Git.open(getRepositoryDir(owner, name))) { git =>
|
||||
val repo = git.getRepository
|
||||
val objectId = repo.resolve(sha)
|
||||
val commitInfo = Using.resource(new RevWalk(repo)) { revWalk =>
|
||||
new CommitInfo(revWalk.parseCommit(objectId))
|
||||
}
|
||||
|
||||
JsonFormat(
|
||||
ApiCommits(
|
||||
repositoryName = RepositoryName(repository),
|
||||
commitInfo = commitInfo,
|
||||
diffs = JGitUtil.getDiffs(git, commitInfo.parents.headOption, commitInfo.id, false, true),
|
||||
author = getAccount(commitInfo.authorName, commitInfo.authorEmailAddress),
|
||||
committer = getAccount(commitInfo.committerName, commitInfo.committerEmailAddress),
|
||||
commentCount = getCommitComment(repository.owner, repository.name, sha).size
|
||||
)
|
||||
JsonFormat(
|
||||
ApiCommits(
|
||||
repositoryName = RepositoryName(repository),
|
||||
commitInfo = commitInfo,
|
||||
diffs = JGitUtil.getDiffs(git, commitInfo.parents.headOption, commitInfo.id, false, true),
|
||||
author = getAccount(commitInfo.authorName, commitInfo.authorEmailAddress),
|
||||
committer = getAccount(commitInfo.committerName, commitInfo.committerEmailAddress),
|
||||
commentCount = getCommitComment(repository.owner, repository.name, sha).size
|
||||
)
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -19,17 +19,16 @@ trait ApiRepositoryContentsControllerBase extends ControllerBase {
|
||||
* https://docs.github.com/en/rest/reference/repos#get-a-repository-readme
|
||||
*/
|
||||
get("/api/v3/repos/:owner/:repository/readme")(referrersOnly { repository =>
|
||||
Using.resource(Git.open(getRepositoryDir(params("owner"), params("repository")))) {
|
||||
git =>
|
||||
val refStr = params.getOrElse("ref", repository.repository.defaultBranch)
|
||||
val files = getFileList(git, refStr, ".", maxFiles = context.settings.repositoryViewer.maxFiles)
|
||||
files // files should be sorted alphabetically.
|
||||
.find { file =>
|
||||
!file.isDirectory && RepositoryService.readmeFiles.contains(file.name.toLowerCase)
|
||||
} match {
|
||||
case Some(x) => getContents(repository = repository, path = x.name, refStr = refStr, ignoreCase = true)
|
||||
case _ => NotFound()
|
||||
}
|
||||
Using.resource(Git.open(getRepositoryDir(params("owner"), params("repository")))) { git =>
|
||||
val refStr = params.getOrElse("ref", repository.repository.defaultBranch)
|
||||
val files = getFileList(git, refStr, ".", maxFiles = context.settings.repositoryViewer.maxFiles)
|
||||
files // files should be sorted alphabetically.
|
||||
.find { file =>
|
||||
!file.isDirectory && RepositoryService.readmeFiles.contains(file.name.toLowerCase)
|
||||
} match {
|
||||
case Some(x) => getContents(repository = repository, path = x.name, refStr = refStr, ignoreCase = true)
|
||||
case _ => NotFound()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -134,67 +133,65 @@ trait ApiRepositoryContentsControllerBase extends ControllerBase {
|
||||
* requested #2112
|
||||
*/
|
||||
put("/api/v3/repos/:owner/:repository/contents/*")(writableUsersOnly { repository =>
|
||||
context.withLoginAccount {
|
||||
loginAccount =>
|
||||
JsonFormat(for {
|
||||
data <- extractFromJsonBody[CreateAFile]
|
||||
} yield {
|
||||
val branch = data.branch.getOrElse(repository.repository.defaultBranch)
|
||||
val commit = Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) { git =>
|
||||
val revCommit = JGitUtil.getRevCommitFromId(git, git.getRepository.resolve(branch))
|
||||
revCommit.name
|
||||
}
|
||||
val paths = multiParams("splat").head.split("/")
|
||||
val path = paths.take(paths.size - 1).toList.mkString("/")
|
||||
Using.resource(Git.open(getRepositoryDir(params("owner"), params("repository")))) {
|
||||
git =>
|
||||
val fileInfo = getFileInfo(git, commit, path, false)
|
||||
context.withLoginAccount { loginAccount =>
|
||||
JsonFormat(for {
|
||||
data <- extractFromJsonBody[CreateAFile]
|
||||
} yield {
|
||||
val branch = data.branch.getOrElse(repository.repository.defaultBranch)
|
||||
val commit = Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) { git =>
|
||||
val revCommit = JGitUtil.getRevCommitFromId(git, git.getRepository.resolve(branch))
|
||||
revCommit.name
|
||||
}
|
||||
val paths = multiParams("splat").head.split("/")
|
||||
val path = paths.take(paths.size - 1).toList.mkString("/")
|
||||
Using.resource(Git.open(getRepositoryDir(params("owner"), params("repository")))) { git =>
|
||||
val fileInfo = getFileInfo(git, commit, path, false)
|
||||
|
||||
fileInfo match {
|
||||
case Some(f) if !data.sha.contains(f.id.getName) =>
|
||||
ApiError(
|
||||
"The blob SHA is not matched.",
|
||||
Some("https://docs.github.com/en/rest/reference/repos#create-or-update-file-contents")
|
||||
fileInfo match {
|
||||
case Some(f) if !data.sha.contains(f.id.getName) =>
|
||||
ApiError(
|
||||
"The blob SHA is not matched.",
|
||||
Some("https://docs.github.com/en/rest/reference/repos#create-or-update-file-contents")
|
||||
)
|
||||
case _ =>
|
||||
commitFile(
|
||||
repository,
|
||||
branch,
|
||||
path,
|
||||
Some(paths.last),
|
||||
data.sha.map(_ => paths.last),
|
||||
StringUtil.base64Decode(data.content),
|
||||
data.message,
|
||||
commit,
|
||||
loginAccount,
|
||||
data.committer.map(_.name).getOrElse(loginAccount.fullName),
|
||||
data.committer.map(_.email).getOrElse(loginAccount.mailAddress),
|
||||
context.settings
|
||||
) match {
|
||||
case Left(error) =>
|
||||
ApiError(s"Failed to commit a file: ${error}", None)
|
||||
case Right((_, None)) =>
|
||||
ApiError("Failed to commit a file.", None)
|
||||
case Right((commitId, Some(blobId))) =>
|
||||
Map(
|
||||
"content" -> ApiContents(
|
||||
"file",
|
||||
paths.last,
|
||||
path,
|
||||
blobId.name,
|
||||
Some(data.content),
|
||||
Some("base64")
|
||||
)(RepositoryName(repository)),
|
||||
"commit" -> ApiCommit(
|
||||
git,
|
||||
RepositoryName(repository),
|
||||
new CommitInfo(JGitUtil.getRevCommitFromId(git, commitId))
|
||||
)
|
||||
)
|
||||
case _ =>
|
||||
commitFile(
|
||||
repository,
|
||||
branch,
|
||||
path,
|
||||
Some(paths.last),
|
||||
data.sha.map(_ => paths.last),
|
||||
StringUtil.base64Decode(data.content),
|
||||
data.message,
|
||||
commit,
|
||||
loginAccount,
|
||||
data.committer.map(_.name).getOrElse(loginAccount.fullName),
|
||||
data.committer.map(_.email).getOrElse(loginAccount.mailAddress),
|
||||
context.settings
|
||||
) match {
|
||||
case Left(error) =>
|
||||
ApiError(s"Failed to commit a file: ${error}", None)
|
||||
case Right((_, None)) =>
|
||||
ApiError("Failed to commit a file.", None)
|
||||
case Right((commitId, Some(blobId))) =>
|
||||
Map(
|
||||
"content" -> ApiContents(
|
||||
"file",
|
||||
paths.last,
|
||||
path,
|
||||
blobId.name,
|
||||
Some(data.content),
|
||||
Some("base64")
|
||||
)(RepositoryName(repository)),
|
||||
"commit" -> ApiCommit(
|
||||
git,
|
||||
RepositoryName(repository),
|
||||
new CommitInfo(JGitUtil.getRevCommitFromId(git, commitId))
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -205,9 +202,9 @@ trait ApiRepositoryContentsControllerBase extends ControllerBase {
|
||||
*/
|
||||
|
||||
/*
|
||||
* vi. Download a repository archive (tar/zip)
|
||||
* https://docs.github.com/en/rest/reference/repos#download-a-repository-archive-tar
|
||||
* https://docs.github.com/en/rest/reference/repos#download-a-repository-archive-zip
|
||||
*/
|
||||
* vi. Download a repository archive (tar/zip)
|
||||
* https://docs.github.com/en/rest/reference/repos#download-a-repository-archive-tar
|
||||
* https://docs.github.com/en/rest/reference/repos#download-a-repository-archive-zip
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
@@ -47,9 +47,8 @@ trait ApiRepositoryStatusControllerBase extends ControllerBase {
|
||||
ref <- params.get("ref")
|
||||
sha <- JGitUtil.getShaByRef(repository.owner, repository.name, ref)
|
||||
} yield {
|
||||
JsonFormat(getCommitStatusesWithCreator(repository.owner, repository.name, sha).map {
|
||||
case (status, creator) =>
|
||||
ApiCommitStatus(status, ApiUser(creator))
|
||||
JsonFormat(getCommitStatusesWithCreator(repository.owner, repository.name, sha).map { case (status, creator) =>
|
||||
ApiCommitStatus(status, ApiUser(creator))
|
||||
})
|
||||
}) getOrElse NotFound()
|
||||
})
|
||||
|
||||
@@ -113,8 +113,8 @@ trait ApiRepositoryWebhookControllerBase extends ControllerBase {
|
||||
*/
|
||||
|
||||
/*
|
||||
* vi. Test the push repository webhook
|
||||
* https://docs.github.com/en/rest/reference/repos#test-the-push-repository-webhook
|
||||
*/
|
||||
* vi. Test the push repository webhook
|
||||
* https://docs.github.com/en/rest/reference/repos#test-the-push-repository-webhook
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
@@ -40,8 +40,8 @@ case class CustomField(
|
||||
)
|
||||
|
||||
trait CustomFieldBehavior {
|
||||
def createHtml(repository: RepositoryInfo, fieldId: Int, fieldName: String, constraints: Option[String])(
|
||||
implicit context: Context
|
||||
def createHtml(repository: RepositoryInfo, fieldId: Int, fieldName: String, constraints: Option[String])(implicit
|
||||
context: Context
|
||||
): String
|
||||
def fieldHtml(
|
||||
repository: RepositoryInfo,
|
||||
@@ -51,8 +51,8 @@ trait CustomFieldBehavior {
|
||||
constraints: Option[String],
|
||||
value: String,
|
||||
editable: Boolean
|
||||
)(
|
||||
implicit context: Context
|
||||
)(implicit
|
||||
context: Context
|
||||
): String
|
||||
def validate(name: String, constraints: Option[String], value: String, messages: Messages): Option[String]
|
||||
}
|
||||
@@ -151,11 +151,11 @@ object CustomFieldBehavior {
|
||||
sb.append("""<div>""")
|
||||
if (value == "") {
|
||||
sb.append(s"""<span id="label-custom-field-$fieldId"><span class="muted small">No ${StringUtil.escapeHtml(
|
||||
fieldName
|
||||
)}</span></span>""")
|
||||
fieldName
|
||||
)}</span></span>""")
|
||||
} else {
|
||||
sb.append(s"""<span id="label-custom-field-$fieldId"><span class="muted small">${StringUtil
|
||||
.escapeHtml(value)}</span></span>""")
|
||||
.escapeHtml(value)}</span></span>""")
|
||||
}
|
||||
sb.toString()
|
||||
} else {
|
||||
@@ -179,21 +179,19 @@ object CustomFieldBehavior {
|
||||
val options = new StringBuilder()
|
||||
options.append(
|
||||
s"""<li><a href="javascript:void(0);" class="custom-field-option-$fieldId" data-value=""><i class="octicon octicon-x"></i> Clear ${StringUtil
|
||||
.escapeHtml(fieldName)}</a></li>"""
|
||||
.escapeHtml(fieldName)}</a></li>"""
|
||||
)
|
||||
constraints.foreach {
|
||||
x =>
|
||||
x.split(",").map(_.trim).foreach {
|
||||
item =>
|
||||
options.append(s"""<li>
|
||||
constraints.foreach { x =>
|
||||
x.split(",").map(_.trim).foreach { item =>
|
||||
options.append(s"""<li>
|
||||
| <a href="javascript:void(0);" class="custom-field-option-$fieldId" data-value="${StringUtil
|
||||
.escapeHtml(item)}">
|
||||
.escapeHtml(item)}">
|
||||
| ${gitbucket.core.helper.html.checkicon(value.contains(item))}
|
||||
| ${StringUtil.escapeHtml(item)}
|
||||
| </a>
|
||||
|</li>
|
||||
|""".stripMargin)
|
||||
}
|
||||
}
|
||||
}
|
||||
Html(options.toString())
|
||||
}
|
||||
@@ -205,11 +203,11 @@ object CustomFieldBehavior {
|
||||
value match {
|
||||
case None =>
|
||||
sb.append(s"""<span id="label-custom-field-$fieldId"><span class="muted small">No ${StringUtil.escapeHtml(
|
||||
fieldName
|
||||
)}</span></span>""")
|
||||
fieldName
|
||||
)}</span></span>""")
|
||||
case Some(value) =>
|
||||
sb.append(s"""<span id="label-custom-field-$fieldId"><span class="muted small">${StringUtil
|
||||
.escapeHtml(value)}</span></span>""")
|
||||
.escapeHtml(value)}</span></span>""")
|
||||
}
|
||||
if (value.isEmpty || issueId.isEmpty) {
|
||||
sb.append(s"""<input type="hidden" id="custom-field-$fieldId" name="custom-field-$fieldId" value=""/>""")
|
||||
@@ -220,7 +218,7 @@ object CustomFieldBehavior {
|
||||
| $$('#custom-field-$fieldId').val(value);
|
||||
| if (value == '') {
|
||||
| $$('#label-custom-field-$fieldId').html($$('<span class="muted small">').text('No ${StringUtil
|
||||
.escapeHtml(fieldName)}'));
|
||||
.escapeHtml(fieldName)}'));
|
||||
| } else {
|
||||
| $$('#label-custom-field-$fieldId').html($$('<span class="muted small">').text(value));
|
||||
| $$('a.custom-field-option-$fieldId[data-value=' + value + '] i').addClass('octicon-check');
|
||||
@@ -237,7 +235,7 @@ object CustomFieldBehavior {
|
||||
| $$('a.custom-field-option-$fieldId i.octicon-check').removeClass('octicon-check');
|
||||
| if (value == '') {
|
||||
| $$('#label-custom-field-$fieldId').html($$('<span class="muted small">').text('No ${StringUtil
|
||||
.escapeHtml(fieldName)}'));
|
||||
.escapeHtml(fieldName)}'));
|
||||
| } else {
|
||||
| $$('#label-custom-field-$fieldId').html($$('<span class="muted small">').text(value));
|
||||
| $$('a.custom-field-option-$fieldId[data-value=' + value + '] i').addClass('octicon-check');
|
||||
@@ -296,14 +294,14 @@ object CustomFieldBehavior {
|
||||
constraints: Option[String],
|
||||
value: String,
|
||||
editable: Boolean
|
||||
)(
|
||||
implicit context: Context
|
||||
)(implicit
|
||||
context: Context
|
||||
): String = {
|
||||
val sb = new StringBuilder
|
||||
if (value.nonEmpty) {
|
||||
sb.append(
|
||||
s"""<span id="custom-field-$fieldId-label" class="custom-field-label">${StringUtil
|
||||
.escapeHtml(value)}</span>"""
|
||||
.escapeHtml(value)}</span>"""
|
||||
)
|
||||
} else {
|
||||
if (editable) {
|
||||
|
||||
@@ -53,24 +53,24 @@ trait RepositoryComponent extends TemplateComponent { self: Profile =>
|
||||
safeMode
|
||||
)
|
||||
).shaped.<>(
|
||||
{
|
||||
case (repository, options) =>
|
||||
Repository(
|
||||
repository._1,
|
||||
repository._2,
|
||||
repository._3,
|
||||
repository._4,
|
||||
repository._5,
|
||||
repository._6,
|
||||
repository._7,
|
||||
repository._8,
|
||||
repository._9,
|
||||
repository._10,
|
||||
repository._11,
|
||||
repository._12,
|
||||
RepositoryOptions.tupled.apply(options)
|
||||
)
|
||||
}, { (r: Repository) =>
|
||||
{ case (repository, options) =>
|
||||
Repository(
|
||||
repository._1,
|
||||
repository._2,
|
||||
repository._3,
|
||||
repository._4,
|
||||
repository._5,
|
||||
repository._6,
|
||||
repository._7,
|
||||
repository._8,
|
||||
repository._9,
|
||||
repository._10,
|
||||
repository._11,
|
||||
repository._12,
|
||||
RepositoryOptions.tupled.apply(options)
|
||||
)
|
||||
},
|
||||
{ (r: Repository) =>
|
||||
Some(
|
||||
(
|
||||
(
|
||||
|
||||
@@ -41,8 +41,8 @@ trait GitRepositoryFilter {
|
||||
* @param session the database session
|
||||
* @return true if allow accessing to repository, otherwise false.
|
||||
*/
|
||||
def filter(path: String, userName: Option[String], settings: SystemSettings, isUpdating: Boolean)(
|
||||
implicit session: Session
|
||||
def filter(path: String, userName: Option[String], settings: SystemSettings, isUpdating: Boolean)(implicit
|
||||
session: Session
|
||||
): Boolean
|
||||
|
||||
}
|
||||
|
||||
@@ -9,16 +9,16 @@ import profile.api._
|
||||
trait IssueHook {
|
||||
|
||||
def created(issue: Issue, repository: RepositoryInfo)(implicit session: Session, context: Context): Unit = ()
|
||||
def addedComment(commentId: Int, content: String, issue: Issue, repository: RepositoryInfo)(
|
||||
implicit session: Session,
|
||||
def addedComment(commentId: Int, content: String, issue: Issue, repository: RepositoryInfo)(implicit
|
||||
session: Session,
|
||||
context: Context
|
||||
): Unit = ()
|
||||
def deletedComment(commentId: Int, issue: Issue, repository: RepositoryInfo)(
|
||||
implicit session: Session,
|
||||
def deletedComment(commentId: Int, issue: Issue, repository: RepositoryInfo)(implicit
|
||||
session: Session,
|
||||
context: Context
|
||||
): Unit = ()
|
||||
def updatedComment(commentId: Int, content: String, issue: Issue, repository: RepositoryInfo)(
|
||||
implicit session: Session,
|
||||
def updatedComment(commentId: Int, content: String, issue: Issue, repository: RepositoryInfo)(implicit
|
||||
session: Session,
|
||||
context: Context
|
||||
): Unit = ()
|
||||
def closed(issue: Issue, repository: RepositoryInfo)(implicit session: Session, context: Context): Unit = ()
|
||||
@@ -29,12 +29,12 @@ trait IssueHook {
|
||||
assigner: Option[String],
|
||||
assigned: Option[String],
|
||||
oldAssigned: Option[String]
|
||||
)(
|
||||
implicit session: Session,
|
||||
)(implicit
|
||||
session: Session,
|
||||
context: Context
|
||||
): Unit = ()
|
||||
def closedByCommitComment(issue: Issue, repository: RepositoryInfo, message: String, pusher: Account)(
|
||||
implicit session: Session
|
||||
def closedByCommitComment(issue: Issue, repository: RepositoryInfo, message: String, pusher: Account)(implicit
|
||||
session: Session
|
||||
): Unit = ()
|
||||
|
||||
}
|
||||
|
||||
@@ -340,25 +340,20 @@ abstract class Plugin {
|
||||
* Register plugin functionality to PluginRegistry.
|
||||
*/
|
||||
def initialize(registry: PluginRegistry, context: ServletContext, settings: SystemSettings): Unit = {
|
||||
(images ++ images(registry, context, settings)).foreach {
|
||||
case (id, in) =>
|
||||
registry.addImage(id, in)
|
||||
(images ++ images(registry, context, settings)).foreach { case (id, in) =>
|
||||
registry.addImage(id, in)
|
||||
}
|
||||
(controllers ++ controllers(registry, context, settings)).foreach {
|
||||
case (path, controller) =>
|
||||
registry.addController(path, controller)
|
||||
(controllers ++ controllers(registry, context, settings)).foreach { case (path, controller) =>
|
||||
registry.addController(path, controller)
|
||||
}
|
||||
(anonymousAccessiblePaths ++ anonymousAccessiblePaths(registry, context, settings)).foreach {
|
||||
case (path) =>
|
||||
registry.addAnonymousAccessiblePath(path)
|
||||
(anonymousAccessiblePaths ++ anonymousAccessiblePaths(registry, context, settings)).foreach { case (path) =>
|
||||
registry.addAnonymousAccessiblePath(path)
|
||||
}
|
||||
(javaScripts ++ javaScripts(registry, context, settings)).foreach {
|
||||
case (path, script) =>
|
||||
registry.addJavaScript(path, script)
|
||||
(javaScripts ++ javaScripts(registry, context, settings)).foreach { case (path, script) =>
|
||||
registry.addJavaScript(path, script)
|
||||
}
|
||||
(renderers ++ renderers(registry, context, settings)).foreach {
|
||||
case (extension, renderer) =>
|
||||
registry.addRenderer(extension, renderer)
|
||||
(renderers ++ renderers(registry, context, settings)).foreach { case (extension, renderer) =>
|
||||
registry.addRenderer(extension, renderer)
|
||||
}
|
||||
(repositoryRoutings ++ repositoryRoutings(registry, context, settings)).foreach { routing =>
|
||||
registry.addRepositoryRouting(routing)
|
||||
|
||||
@@ -80,7 +80,7 @@ class PluginRegistry {
|
||||
def getAnonymousAccessiblePaths(): Seq[String] = anonymousAccessiblePaths.asScala.toSeq
|
||||
|
||||
def addJavaScript(path: String, script: String): Unit =
|
||||
javaScripts.add((path, script)) //javaScripts += ((path, script))
|
||||
javaScripts.add((path, script)) // javaScripts += ((path, script))
|
||||
|
||||
def getJavaScript(currentPath: String): List[String] =
|
||||
javaScripts.asScala.filter(x => currentPath.matches(x._1)).toList.map(_._2)
|
||||
|
||||
@@ -13,8 +13,8 @@ trait ReceiveHook {
|
||||
command: ReceiveCommand,
|
||||
pusher: String,
|
||||
mergePullRequest: Boolean
|
||||
)(
|
||||
implicit session: Session
|
||||
)(implicit
|
||||
session: Session
|
||||
): Option[String] = None
|
||||
|
||||
def postReceive(
|
||||
@@ -24,8 +24,8 @@ trait ReceiveHook {
|
||||
command: ReceiveCommand,
|
||||
pusher: String,
|
||||
mergePullRequest: Boolean
|
||||
)(
|
||||
implicit session: Session
|
||||
)(implicit
|
||||
session: Session
|
||||
): Unit = ()
|
||||
|
||||
}
|
||||
|
||||
@@ -37,9 +37,8 @@ trait AccessTokenService {
|
||||
def getAccountByAccessToken(token: String)(implicit s: Session): Option[Account] =
|
||||
Accounts
|
||||
.join(AccessTokens)
|
||||
.filter {
|
||||
case (ac, t) =>
|
||||
(ac.userName === t.userName) && (t.tokenHash === tokenToHash(token).bind) && (ac.removed === false.bind)
|
||||
.filter { case (ac, t) =>
|
||||
(ac.userName === t.userName) && (t.tokenHash === tokenToHash(token).bind) && (ac.removed === false.bind)
|
||||
}
|
||||
.map { case (ac, t) => ac }
|
||||
.firstOption
|
||||
|
||||
@@ -51,8 +51,8 @@ trait AccountFederationService {
|
||||
* @param preferredUserName Username
|
||||
* @return Available username
|
||||
*/
|
||||
def findAvailableUserName(preferredUserName: Option[String], mailAddress: String)(
|
||||
implicit s: Session
|
||||
def findAvailableUserName(preferredUserName: Option[String], mailAddress: String)(implicit
|
||||
s: Session
|
||||
): Option[String] = {
|
||||
preferredUserName
|
||||
.flatMap(n => extractSafeStringForUserName(n))
|
||||
|
||||
@@ -19,8 +19,8 @@ trait AccountService {
|
||||
|
||||
private val logger = LoggerFactory.getLogger(classOf[AccountService])
|
||||
|
||||
def authenticate(settings: SystemSettings, userName: String, password: String)(
|
||||
implicit s: Session
|
||||
def authenticate(settings: SystemSettings, userName: String, password: String)(implicit
|
||||
s: Session
|
||||
): Option[Account] = {
|
||||
val account = if (password.isEmpty) {
|
||||
None
|
||||
@@ -58,8 +58,8 @@ trait AccountService {
|
||||
/**
|
||||
* Authenticate by LDAP.
|
||||
*/
|
||||
private def ldapAuthentication(settings: SystemSettings, userName: String, password: String)(
|
||||
implicit s: Session
|
||||
private def ldapAuthentication(settings: SystemSettings, userName: String, password: String)(implicit
|
||||
s: Session
|
||||
): Option[Account] = {
|
||||
LDAPUtil.authenticate(settings.ldap.get, userName, password) match {
|
||||
case Right(ldapUserInfo) => {
|
||||
@@ -112,15 +112,15 @@ trait AccountService {
|
||||
def getAccountByUserName(userName: String, includeRemoved: Boolean = false)(implicit s: Session): Option[Account] =
|
||||
Accounts filter (t => (t.userName === userName.bind).&&(t.removed === false.bind, !includeRemoved)) firstOption
|
||||
|
||||
def getAccountByUserNameIgnoreCase(userName: String, includeRemoved: Boolean = false)(
|
||||
implicit s: Session
|
||||
def getAccountByUserNameIgnoreCase(userName: String, includeRemoved: Boolean = false)(implicit
|
||||
s: Session
|
||||
): Option[Account] =
|
||||
Accounts filter (
|
||||
t => (t.userName.toLowerCase === userName.toLowerCase.bind).&&(t.removed === false.bind, !includeRemoved)
|
||||
Accounts filter (t =>
|
||||
(t.userName.toLowerCase === userName.toLowerCase.bind).&&(t.removed === false.bind, !includeRemoved)
|
||||
) firstOption
|
||||
|
||||
def getAccountsByUserNames(userNames: Set[String], knowns: Set[Account], includeRemoved: Boolean = false)(
|
||||
implicit s: Session
|
||||
def getAccountsByUserNames(userNames: Set[String], knowns: Set[Account], includeRemoved: Boolean = false)(implicit
|
||||
s: Session
|
||||
): Map[String, Account] = {
|
||||
val map = knowns.map(a => a.userName -> a).toMap
|
||||
val needs = userNames -- map.keySet
|
||||
@@ -135,17 +135,15 @@ trait AccountService {
|
||||
}
|
||||
}
|
||||
|
||||
def getAccountByMailAddress(mailAddress: String, includeRemoved: Boolean = false)(
|
||||
implicit s: Session
|
||||
def getAccountByMailAddress(mailAddress: String, includeRemoved: Boolean = false)(implicit
|
||||
s: Session
|
||||
): Option[Account] =
|
||||
(Accounts joinLeft AccountExtraMailAddresses on { case (a, e) => a.userName === e.userName })
|
||||
.filter {
|
||||
case (a, x) =>
|
||||
((a.mailAddress.toLowerCase === mailAddress.toLowerCase.bind) ||
|
||||
(x.map { e =>
|
||||
e.extraMailAddress.toLowerCase === mailAddress.toLowerCase.bind
|
||||
}
|
||||
.getOrElse(false.bind))).&&(a.removed === false.bind, !includeRemoved)
|
||||
.filter { case (a, x) =>
|
||||
((a.mailAddress.toLowerCase === mailAddress.toLowerCase.bind) ||
|
||||
(x.map { e =>
|
||||
e.extraMailAddress.toLowerCase === mailAddress.toLowerCase.bind
|
||||
}.getOrElse(false.bind))).&&(a.removed === false.bind, !includeRemoved)
|
||||
}
|
||||
.map { case (a, e) => a } firstOption
|
||||
|
||||
@@ -267,8 +265,8 @@ trait AccountService {
|
||||
group
|
||||
}
|
||||
|
||||
def updateGroup(groupName: String, description: Option[String], url: Option[String], removed: Boolean)(
|
||||
implicit s: Session
|
||||
def updateGroup(groupName: String, description: Option[String], url: Option[String], removed: Boolean)(implicit
|
||||
s: Session
|
||||
): Unit =
|
||||
Accounts
|
||||
.filter(_.userName === groupName.bind)
|
||||
@@ -277,9 +275,8 @@ trait AccountService {
|
||||
|
||||
def updateGroupMembers(groupName: String, members: List[(String, Boolean)])(implicit s: Session): Unit = {
|
||||
GroupMembers.filter(_.groupName === groupName.bind).delete
|
||||
members.foreach {
|
||||
case (userName, isManager) =>
|
||||
GroupMembers insert GroupMember(groupName, userName, isManager)
|
||||
members.foreach { case (userName, isManager) =>
|
||||
GroupMembers insert GroupMember(groupName, userName, isManager)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,8 +315,8 @@ trait AccountService {
|
||||
/*
|
||||
* For account preference
|
||||
*/
|
||||
def getAccountPreference(userName: String)(
|
||||
implicit s: Session
|
||||
def getAccountPreference(userName: String)(implicit
|
||||
s: Session
|
||||
): Option[AccountPreference] = {
|
||||
AccountPreferences filter (_.byPrimaryKey(userName)) firstOption
|
||||
}
|
||||
|
||||
@@ -43,9 +43,8 @@ trait ActivityService {
|
||||
|
||||
def getRecentActivitiesByRepos(repos: Set[(String, String)])(implicit context: Context): List[Activity] = {
|
||||
getActivities(includePublic = true) { activity =>
|
||||
repos.exists {
|
||||
case (userName, repositoryName) =>
|
||||
activity.userName == userName && activity.repositoryName == repositoryName
|
||||
repos.exists { case (userName, repositoryName) =>
|
||||
activity.userName == userName && activity.repositoryName == repositoryName
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,10 +64,12 @@ trait ActivityService {
|
||||
.get()
|
||||
) { reader =>
|
||||
var json: String = null
|
||||
while (list.length < 50 && {
|
||||
json = reader.readLine();
|
||||
json
|
||||
} != null) {
|
||||
while (
|
||||
list.length < 50 && {
|
||||
json = reader.readLine();
|
||||
json
|
||||
} != null
|
||||
) {
|
||||
val activity = read[Activity](json)
|
||||
if (filter(activity)) {
|
||||
list += activity
|
||||
|
||||
@@ -47,8 +47,8 @@ trait CommitStatusService {
|
||||
)
|
||||
}
|
||||
|
||||
def getCommitStatusWithSummary(userName: String, repositoryName: String, sha: String)(
|
||||
implicit s: Session
|
||||
def getCommitStatusWithSummary(userName: String, repositoryName: String, sha: String)(implicit
|
||||
s: Session
|
||||
): Option[(CommitState, List[CommitStatus])] = {
|
||||
val statuses = getCommitStatuses(userName, repositoryName, sha)
|
||||
if (statuses.isEmpty) {
|
||||
@@ -62,18 +62,18 @@ trait CommitStatusService {
|
||||
def getCommitStatus(userName: String, repositoryName: String, id: Int)(implicit s: Session): Option[CommitStatus] =
|
||||
CommitStatuses.filter(t => t.byPrimaryKey(id) && t.byRepository(userName, repositoryName)).firstOption
|
||||
|
||||
def getCommitStatus(userName: String, repositoryName: String, sha: String, context: String)(
|
||||
implicit s: Session
|
||||
def getCommitStatus(userName: String, repositoryName: String, sha: String, context: String)(implicit
|
||||
s: Session
|
||||
): Option[CommitStatus] =
|
||||
CommitStatuses.filter(t => t.byCommit(userName, repositoryName, sha) && t.context === context.bind).firstOption
|
||||
|
||||
def getCommitStatuses(userName: String, repositoryName: String, sha: String)(
|
||||
implicit s: Session
|
||||
def getCommitStatuses(userName: String, repositoryName: String, sha: String)(implicit
|
||||
s: Session
|
||||
): List[CommitStatus] =
|
||||
byCommitStatus(userName, repositoryName, sha).list
|
||||
|
||||
def getRecentStatusContexts(userName: String, repositoryName: String, time: java.util.Date)(
|
||||
implicit s: Session
|
||||
def getRecentStatusContexts(userName: String, repositoryName: String, time: java.util.Date)(implicit
|
||||
s: Session
|
||||
): List[String] =
|
||||
CommitStatuses
|
||||
.filter(t => t.byRepository(userName, repositoryName))
|
||||
@@ -82,8 +82,8 @@ trait CommitStatusService {
|
||||
.map(_._1)
|
||||
.list
|
||||
|
||||
def getCommitStatusesWithCreator(userName: String, repositoryName: String, sha: String)(
|
||||
implicit s: Session
|
||||
def getCommitStatusesWithCreator(userName: String, repositoryName: String, sha: String)(implicit
|
||||
s: Session
|
||||
): List[(CommitStatus, Account)] =
|
||||
byCommitStatus(userName, repositoryName, sha)
|
||||
.join(Accounts)
|
||||
|
||||
@@ -18,8 +18,8 @@ import org.apache.commons.io.FileUtils
|
||||
trait CommitsService {
|
||||
self: ActivityService with PullRequestService with WebHookPullRequestReviewCommentService =>
|
||||
|
||||
def getCommitComments(owner: String, repository: String, commitId: String, includePullRequest: Boolean)(
|
||||
implicit s: Session
|
||||
def getCommitComments(owner: String, repository: String, commitId: String, includePullRequest: Boolean)(implicit
|
||||
s: Session
|
||||
) =
|
||||
CommitComments filter { t =>
|
||||
t.byCommit(owner, repository, commitId) && (t.issueId.isEmpty || includePullRequest)
|
||||
@@ -79,21 +79,20 @@ trait CommitsService {
|
||||
val comment = getCommitComment(repository.owner, repository.name, commentId.toString).get
|
||||
issueId match {
|
||||
case Some(issueId) =>
|
||||
getPullRequest(repository.owner, repository.name, issueId).foreach {
|
||||
case (issue, pullRequest) =>
|
||||
val pullRequestCommentInfo =
|
||||
PullRequestCommentInfo(repository.owner, repository.name, loginAccount.userName, content, issueId)
|
||||
recordActivity(pullRequestCommentInfo)
|
||||
PluginRegistry().getPullRequestHooks.foreach(_.addedComment(commentId, content, issue, repository))
|
||||
callPullRequestReviewCommentWebHook(
|
||||
"create",
|
||||
comment,
|
||||
repository,
|
||||
issue,
|
||||
pullRequest,
|
||||
loginAccount,
|
||||
context.settings
|
||||
)
|
||||
getPullRequest(repository.owner, repository.name, issueId).foreach { case (issue, pullRequest) =>
|
||||
val pullRequestCommentInfo =
|
||||
PullRequestCommentInfo(repository.owner, repository.name, loginAccount.userName, content, issueId)
|
||||
recordActivity(pullRequestCommentInfo)
|
||||
PluginRegistry().getPullRequestHooks.foreach(_.addedComment(commentId, content, issue, repository))
|
||||
callPullRequestReviewCommentWebHook(
|
||||
"create",
|
||||
comment,
|
||||
repository,
|
||||
issue,
|
||||
pullRequest,
|
||||
loginAccount,
|
||||
context.settings
|
||||
)
|
||||
}
|
||||
case None =>
|
||||
val commitCommentInfo =
|
||||
@@ -104,8 +103,8 @@ trait CommitsService {
|
||||
commentId
|
||||
}
|
||||
|
||||
def updateCommitCommentPosition(commentId: Int, commitId: String, oldLine: Option[Int], newLine: Option[Int])(
|
||||
implicit s: Session
|
||||
def updateCommitCommentPosition(commentId: Int, commitId: String, oldLine: Option[Int], newLine: Option[Int])(implicit
|
||||
s: Session
|
||||
): Unit =
|
||||
CommitComments
|
||||
.filter(_.byPrimaryKey(commentId))
|
||||
|
||||
@@ -9,8 +9,8 @@ trait CustomFieldsService {
|
||||
def getCustomFields(owner: String, repository: String)(implicit s: Session): List[CustomField] =
|
||||
CustomFields.filter(_.byRepository(owner, repository)).sortBy(_.fieldId asc).list
|
||||
|
||||
def getCustomFieldsWithValue(owner: String, repository: String, issueId: Int)(
|
||||
implicit s: Session
|
||||
def getCustomFieldsWithValue(owner: String, repository: String, issueId: Int)(implicit
|
||||
s: Session
|
||||
): List[(CustomField, Option[IssueCustomField])] = {
|
||||
CustomFields
|
||||
.filter(_.byRepository(owner, repository))
|
||||
@@ -52,8 +52,8 @@ trait CustomFieldsService {
|
||||
constraints: Option[String],
|
||||
enableForIssues: Boolean,
|
||||
enableForPullRequests: Boolean
|
||||
)(
|
||||
implicit s: Session
|
||||
)(implicit
|
||||
s: Session
|
||||
): Unit =
|
||||
CustomFields
|
||||
.filter(_.byPrimaryKey(owner, repository, fieldId))
|
||||
|
||||
@@ -17,10 +17,9 @@ trait GpgKeyService {
|
||||
|
||||
def addGpgPublicKey(userName: String, title: String, publicKey: String)(implicit s: Session): Unit = {
|
||||
val pubKeyOf = new BcPGPObjectFactory(new ArmoredInputStream(new ByteArrayInputStream(publicKey.getBytes)))
|
||||
pubKeyOf.iterator().asScala.foreach {
|
||||
case keyRing: PGPPublicKeyRing =>
|
||||
val key = keyRing.getPublicKey()
|
||||
GpgKeys.insert(GpgKey(userName = userName, gpgKeyId = key.getKeyID, title = title, publicKey = publicKey))
|
||||
pubKeyOf.iterator().asScala.foreach { case keyRing: PGPPublicKeyRing =>
|
||||
val key = keyRing.getPublicKey()
|
||||
GpgKeys.insert(GpgKey(userName = userName, gpgKeyId = key.getKeyID, title = title, publicKey = publicKey))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -134,8 +134,8 @@ trait HandleCommentService {
|
||||
}
|
||||
}
|
||||
|
||||
def deleteCommentByApi(repoInfo: RepositoryInfo, comment: IssueComment, issue: Issue)(
|
||||
implicit context: Context,
|
||||
def deleteCommentByApi(repoInfo: RepositoryInfo, comment: IssueComment, issue: Issue)(implicit
|
||||
context: Context,
|
||||
s: Session
|
||||
): Option[IssueComment] = context.loginAccount.flatMap { _ =>
|
||||
comment.action match {
|
||||
|
||||
@@ -41,8 +41,8 @@ trait IssuesService {
|
||||
IssueComments filter (_.byIssue(owner, repository, issueId)) sortBy (_.commentId asc) list
|
||||
|
||||
/** @return IssueComment and commentedUser and Issue */
|
||||
def getCommentsForApi(owner: String, repository: String, issueId: Int)(
|
||||
implicit s: Session
|
||||
def getCommentsForApi(owner: String, repository: String, issueId: Int)(implicit
|
||||
s: Session
|
||||
): List[(IssueComment, Account, Issue)] =
|
||||
IssueComments
|
||||
.filter(_.byIssue(owner, repository, issueId))
|
||||
@@ -54,8 +54,8 @@ trait IssuesService {
|
||||
.map { case t1 ~ t2 ~ t3 => (t1, t2, t3) }
|
||||
.list
|
||||
|
||||
def getMergedComment(owner: String, repository: String, issueId: Int)(
|
||||
implicit s: Session
|
||||
def getMergedComment(owner: String, repository: String, issueId: Int)(implicit
|
||||
s: Session
|
||||
): Option[(IssueComment, Account)] = {
|
||||
IssueComments
|
||||
.filter(_.byIssue(owner, repository, issueId))
|
||||
@@ -74,8 +74,8 @@ trait IssuesService {
|
||||
else None
|
||||
}
|
||||
|
||||
def getCommentForApi(owner: String, repository: String, commentId: Int)(
|
||||
implicit s: Session
|
||||
def getCommentForApi(owner: String, repository: String, commentId: Int)(implicit
|
||||
s: Session
|
||||
): Option[(IssueComment, Account, Issue)] =
|
||||
IssueComments
|
||||
.filter(_.byRepository(owner, repository))
|
||||
@@ -91,17 +91,16 @@ trait IssuesService {
|
||||
def getIssueLabels(owner: String, repository: String, issueId: Int)(implicit s: Session): List[Label] = {
|
||||
IssueLabels
|
||||
.join(Labels)
|
||||
.on {
|
||||
case t1 ~ t2 =>
|
||||
t1.byLabel(t2.userName, t2.repositoryName, t2.labelId)
|
||||
.on { case t1 ~ t2 =>
|
||||
t1.byLabel(t2.userName, t2.repositoryName, t2.labelId)
|
||||
}
|
||||
.filter { case t1 ~ t2 => t1.byIssue(owner, repository, issueId) }
|
||||
.map { case t1 ~ t2 => t2 }
|
||||
.list
|
||||
}
|
||||
|
||||
def getIssueLabel(owner: String, repository: String, issueId: Int, labelId: Int)(
|
||||
implicit s: Session
|
||||
def getIssueLabel(owner: String, repository: String, issueId: Int, labelId: Int)(implicit
|
||||
s: Session
|
||||
): Option[IssueLabel] = {
|
||||
IssueLabels filter (_.byPrimaryKey(owner, repository, issueId, labelId)) firstOption
|
||||
}
|
||||
@@ -114,8 +113,8 @@ trait IssuesService {
|
||||
* @param repos Tuple of the repository owner and the repository name
|
||||
* @return the count of the search result
|
||||
*/
|
||||
def countIssue(condition: IssueSearchCondition, searchOption: IssueSearchOption, repos: (String, String)*)(
|
||||
implicit s: Session
|
||||
def countIssue(condition: IssueSearchCondition, searchOption: IssueSearchOption, repos: (String, String)*)(implicit
|
||||
s: Session
|
||||
): Int = {
|
||||
Query(searchIssueQuery(repos, condition, searchOption).length).first
|
||||
}
|
||||
@@ -136,22 +135,18 @@ trait IssuesService {
|
||||
|
||||
searchIssueQuery(Seq(owner -> repository), condition.copy(labels = Set.empty), IssueSearchOption.Issues)
|
||||
.join(IssueLabels)
|
||||
.on {
|
||||
case t1 ~ t2 =>
|
||||
t1.byIssue(t2.userName, t2.repositoryName, t2.issueId)
|
||||
.on { case t1 ~ t2 =>
|
||||
t1.byIssue(t2.userName, t2.repositoryName, t2.issueId)
|
||||
}
|
||||
.join(Labels)
|
||||
.on {
|
||||
case t1 ~ t2 ~ t3 =>
|
||||
t2.byLabel(t3.userName, t3.repositoryName, t3.labelId)
|
||||
.on { case t1 ~ t2 ~ t3 =>
|
||||
t2.byLabel(t3.userName, t3.repositoryName, t3.labelId)
|
||||
}
|
||||
.groupBy {
|
||||
case t1 ~ t2 ~ t3 =>
|
||||
t3.labelName
|
||||
.groupBy { case t1 ~ t2 ~ t3 =>
|
||||
t3.labelName
|
||||
}
|
||||
.map {
|
||||
case (labelName, t) =>
|
||||
labelName -> t.length
|
||||
.map { case (labelName, t) =>
|
||||
labelName -> t.length
|
||||
}
|
||||
.list
|
||||
.toMap
|
||||
@@ -173,17 +168,14 @@ trait IssuesService {
|
||||
|
||||
searchIssueQuery(Seq(owner -> repository), condition.copy(labels = Set.empty), IssueSearchOption.Issues)
|
||||
.join(Priorities)
|
||||
.on {
|
||||
case t1 ~ t2 =>
|
||||
t1.byPriority(t2.userName, t2.repositoryName, t2.priorityId)
|
||||
.on { case t1 ~ t2 =>
|
||||
t1.byPriority(t2.userName, t2.repositoryName, t2.priorityId)
|
||||
}
|
||||
.groupBy {
|
||||
case t1 ~ t2 =>
|
||||
t2.priorityName
|
||||
.groupBy { case t1 ~ t2 =>
|
||||
t2.priorityName
|
||||
}
|
||||
.map {
|
||||
case (priorityName, t) =>
|
||||
priorityName -> t.length
|
||||
.map { case (priorityName, t) =>
|
||||
priorityName -> t.length
|
||||
}
|
||||
.list
|
||||
.toMap
|
||||
@@ -221,19 +213,18 @@ trait IssuesService {
|
||||
.joinLeft(IssueAssignees)
|
||||
.on { case t1 ~ t2 ~ i ~ t3 ~ t4 ~ t5 ~ t6 ~ t7 ~ t8 => t1.byIssue(t8.userName, t8.repositoryName, t8.issueId) }
|
||||
.sortBy { case t1 ~ t2 ~ i ~ t3 ~ t4 ~ t5 ~ t6 ~ t7 ~ t8 => i asc }
|
||||
.map {
|
||||
case t1 ~ t2 ~ i ~ t3 ~ t4 ~ t5 ~ t6 ~ t7 ~ t8 =>
|
||||
(
|
||||
t1,
|
||||
t2.commentCount,
|
||||
t4.map(_.labelId),
|
||||
t4.map(_.labelName),
|
||||
t4.map(_.color),
|
||||
t5.map(_.title),
|
||||
t6.map(_.priorityName),
|
||||
t7.map(_.commitIdTo),
|
||||
t8.map(_.assigneeUserName)
|
||||
)
|
||||
.map { case t1 ~ t2 ~ i ~ t3 ~ t4 ~ t5 ~ t6 ~ t7 ~ t8 =>
|
||||
(
|
||||
t1,
|
||||
t2.commentCount,
|
||||
t4.map(_.labelId),
|
||||
t4.map(_.labelName),
|
||||
t4.map(_.color),
|
||||
t5.map(_.title),
|
||||
t6.map(_.priorityName),
|
||||
t7.map(_.commitIdTo),
|
||||
t8.map(_.assigneeUserName)
|
||||
)
|
||||
}
|
||||
.list
|
||||
.splitWith { (c1, c2) =>
|
||||
@@ -264,8 +255,8 @@ trait IssuesService {
|
||||
/** for api
|
||||
* @return (issue, issueUser, Seq(assigneeUsers))
|
||||
*/
|
||||
def searchIssueByApi(condition: IssueSearchCondition, offset: Int, limit: Int, repos: (String, String)*)(
|
||||
implicit s: Session
|
||||
def searchIssueByApi(condition: IssueSearchCondition, offset: Int, limit: Int, repos: (String, String)*)(implicit
|
||||
s: Session
|
||||
): List[(Issue, Account, List[Account])] = {
|
||||
// get issues and comment count and labels
|
||||
searchIssueQueryBase(condition, IssueSearchOption.Issues, offset, limit, repos)
|
||||
@@ -278,13 +269,11 @@ trait IssuesService {
|
||||
.sortBy { case t1 ~ t2 ~ i ~ t3 ~ t4 ~ t5 => i asc }
|
||||
.map { case t1 ~ t2 ~ i ~ t3 ~ t4 ~ t5 => (t1, t3, t5) }
|
||||
.list
|
||||
.groupBy {
|
||||
case (issue, account, _) =>
|
||||
(issue, account)
|
||||
.groupBy { case (issue, account, _) =>
|
||||
(issue, account)
|
||||
}
|
||||
.map {
|
||||
case (_, values) =>
|
||||
(values.head._1, values.head._2, values.flatMap(_._3))
|
||||
.map { case (_, values) =>
|
||||
(values.head._1, values.head._2, values.flatMap(_._3))
|
||||
}
|
||||
.toList
|
||||
}
|
||||
@@ -312,21 +301,19 @@ trait IssuesService {
|
||||
.sortBy { case t1 ~ t2 ~ i ~ t3 ~ t4 ~ t5 ~ t6 ~ t7 ~ t8 => i asc }
|
||||
.map { case t1 ~ t2 ~ i ~ t3 ~ t4 ~ t5 ~ t6 ~ t7 ~ t8 => (t1, t5, t2.commentCount, t3, t4, t6, t8) }
|
||||
.list
|
||||
.groupBy {
|
||||
case (issue, openedUser, commentCount, pullRequest, repository, account, assignedUser) =>
|
||||
(issue, openedUser, commentCount, pullRequest, repository, account)
|
||||
.groupBy { case (issue, openedUser, commentCount, pullRequest, repository, account, assignedUser) =>
|
||||
(issue, openedUser, commentCount, pullRequest, repository, account)
|
||||
}
|
||||
.map {
|
||||
case (_, values) =>
|
||||
(
|
||||
values.head._1,
|
||||
values.head._2,
|
||||
values.head._3,
|
||||
values.head._4,
|
||||
values.head._5,
|
||||
values.head._6,
|
||||
values.flatMap(_._7)
|
||||
)
|
||||
.map { case (_, values) =>
|
||||
(
|
||||
values.head._1,
|
||||
values.head._2,
|
||||
values.head._3,
|
||||
values.head._4,
|
||||
values.head._5,
|
||||
values.head._6,
|
||||
values.flatMap(_._7)
|
||||
)
|
||||
}
|
||||
.toList
|
||||
}
|
||||
@@ -344,30 +331,29 @@ trait IssuesService {
|
||||
t1.byIssue(t2.userName, t2.repositoryName, t2.issueId)
|
||||
}
|
||||
.sortBy { case (t1, t2) => t1.issueId desc }
|
||||
.sortBy {
|
||||
case (t1, t2) =>
|
||||
condition.sort match {
|
||||
case "created" =>
|
||||
condition.direction match {
|
||||
case "asc" => t1.registeredDate asc
|
||||
case "desc" => t1.registeredDate desc
|
||||
}
|
||||
case "comments" =>
|
||||
condition.direction match {
|
||||
case "asc" => t2.commentCount asc
|
||||
case "desc" => t2.commentCount desc
|
||||
}
|
||||
case "updated" =>
|
||||
condition.direction match {
|
||||
case "asc" => t1.updatedDate asc
|
||||
case "desc" => t1.updatedDate desc
|
||||
}
|
||||
case "priority" =>
|
||||
condition.direction match {
|
||||
case "asc" => t2.priority asc
|
||||
case "desc" => t2.priority desc
|
||||
}
|
||||
}
|
||||
.sortBy { case (t1, t2) =>
|
||||
condition.sort match {
|
||||
case "created" =>
|
||||
condition.direction match {
|
||||
case "asc" => t1.registeredDate asc
|
||||
case "desc" => t1.registeredDate desc
|
||||
}
|
||||
case "comments" =>
|
||||
condition.direction match {
|
||||
case "asc" => t2.commentCount asc
|
||||
case "desc" => t2.commentCount desc
|
||||
}
|
||||
case "updated" =>
|
||||
condition.direction match {
|
||||
case "asc" => t1.updatedDate asc
|
||||
case "desc" => t1.updatedDate desc
|
||||
}
|
||||
case "priority" =>
|
||||
condition.direction match {
|
||||
case "asc" => t2.priority asc
|
||||
case "desc" => t2.priority desc
|
||||
}
|
||||
}
|
||||
}
|
||||
.drop(offset)
|
||||
.take(limit)
|
||||
@@ -380,8 +366,8 @@ trait IssuesService {
|
||||
repos: Seq[(String, String)],
|
||||
condition: IssueSearchCondition,
|
||||
searchOption: IssueSearchOption
|
||||
)(
|
||||
implicit s: Session
|
||||
)(implicit
|
||||
s: Session
|
||||
) = {
|
||||
val query = Issues filter { t1 =>
|
||||
(if (repos.sizeIs == 1) {
|
||||
@@ -395,14 +381,14 @@ trait IssuesService {
|
||||
case _ => t1.closed === true || t1.closed === false
|
||||
}).&&(t1.milestoneId.? isEmpty, condition.milestone.contains(None))
|
||||
.&&(t1.priorityId.? isEmpty, condition.priority.contains(None))
|
||||
//.&&(t1.assignedUserName.? isEmpty, condition.assigned == Some(None))
|
||||
// .&&(t1.assignedUserName.? isEmpty, condition.assigned == Some(None))
|
||||
.&&(t1.openedUserName === condition.author.get.bind, condition.author.isDefined) &&
|
||||
(searchOption match {
|
||||
case IssueSearchOption.Issues => t1.pullRequest === false
|
||||
case IssueSearchOption.PullRequests => t1.pullRequest === true
|
||||
case IssueSearchOption.Both => t1.pullRequest === false || t1.pullRequest === true
|
||||
})
|
||||
// Milestone filter
|
||||
// Milestone filter
|
||||
.&&(
|
||||
Milestones filter { t2 =>
|
||||
(t2.byPrimaryKey(t1.userName, t1.repositoryName, t1.milestoneId)) &&
|
||||
@@ -451,40 +437,46 @@ trait IssuesService {
|
||||
// Mentioned filter
|
||||
.&&(
|
||||
(t1.openedUserName === condition.mentioned.get.bind) || (IssueAssignees filter { t1 =>
|
||||
t1.byIssue(t1.userName, t1.repositoryName, t1.issueId) && t1.assigneeUserName === condition.mentioned.get.bind
|
||||
t1.byIssue(
|
||||
t1.userName,
|
||||
t1.repositoryName,
|
||||
t1.issueId
|
||||
) && t1.assigneeUserName === condition.mentioned.get.bind
|
||||
} exists) ||
|
||||
(IssueComments filter { t2 =>
|
||||
(t2.byIssue(t1.userName, t1.repositoryName, t1.issueId)) && (t2.commentedUserName === condition.mentioned.get.bind)
|
||||
(t2.byIssue(
|
||||
t1.userName,
|
||||
t1.repositoryName,
|
||||
t1.issueId
|
||||
)) && (t2.commentedUserName === condition.mentioned.get.bind)
|
||||
} exists),
|
||||
condition.mentioned.isDefined
|
||||
)
|
||||
}
|
||||
|
||||
condition.others.foldLeft(query) {
|
||||
case (query, cond) =>
|
||||
def condQuery(f: Rep[String] => Rep[Boolean]): Query[Profile.Issues, Issue, Seq] = {
|
||||
query.filter { t1 =>
|
||||
IssueCustomFields
|
||||
.join(CustomFields)
|
||||
.on { (t2, t3) =>
|
||||
t2.userName === t3.userName && t2.repositoryName === t3.repositoryName && t2.fieldId === t3.fieldId
|
||||
}
|
||||
.filter {
|
||||
case (t2, t3) =>
|
||||
t1.byIssue(t2.userName, t2.repositoryName, t2.issueId) && t3.fieldName === cond.name.bind && f(
|
||||
t2.value
|
||||
)
|
||||
condition.others.foldLeft(query) { case (query, cond) =>
|
||||
def condQuery(f: Rep[String] => Rep[Boolean]): Query[Profile.Issues, Issue, Seq] = {
|
||||
query.filter { t1 =>
|
||||
IssueCustomFields
|
||||
.join(CustomFields)
|
||||
.on { (t2, t3) =>
|
||||
t2.userName === t3.userName && t2.repositoryName === t3.repositoryName && t2.fieldId === t3.fieldId
|
||||
}
|
||||
.filter { case (t2, t3) =>
|
||||
t1.byIssue(t2.userName, t2.repositoryName, t2.issueId) && t3.fieldName === cond.name.bind && f(
|
||||
t2.value
|
||||
)
|
||||
} exists
|
||||
}
|
||||
}
|
||||
cond.operator match {
|
||||
case "eq" => condQuery(_ === cond.value.bind)
|
||||
case "lt" => condQuery(_ < cond.value.bind)
|
||||
case "gt" => condQuery(_ > cond.value.bind)
|
||||
case "lte" => condQuery(_ <= cond.value.bind)
|
||||
case "gte" => condQuery(_ >= cond.value.bind)
|
||||
case _ => throw new IllegalArgumentException("Unsupported operator")
|
||||
}
|
||||
}
|
||||
cond.operator match {
|
||||
case "eq" => condQuery(_ === cond.value.bind)
|
||||
case "lt" => condQuery(_ < cond.value.bind)
|
||||
case "gt" => condQuery(_ > cond.value.bind)
|
||||
case "lte" => condQuery(_ <= cond.value.bind)
|
||||
case "gte" => condQuery(_ >= cond.value.bind)
|
||||
case _ => throw new IllegalArgumentException("Unsupported operator")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -523,11 +515,12 @@ trait IssuesService {
|
||||
.filter(_.byPrimaryKey(owner, repository))
|
||||
.map(_.issueId)
|
||||
.update(id) > 0
|
||||
} get
|
||||
} get
|
||||
}
|
||||
|
||||
def registerIssueLabel(owner: String, repository: String, issueId: Int, labelId: Int, insertComment: Boolean = false)(
|
||||
implicit context: Context,
|
||||
implicit
|
||||
context: Context,
|
||||
s: Session
|
||||
): Int = {
|
||||
if (insertComment) {
|
||||
@@ -546,7 +539,8 @@ trait IssuesService {
|
||||
}
|
||||
|
||||
def deleteIssueLabel(owner: String, repository: String, issueId: Int, labelId: Int, insertComment: Boolean = false)(
|
||||
implicit context: Context,
|
||||
implicit
|
||||
context: Context,
|
||||
s: Session
|
||||
): Int = {
|
||||
if (insertComment) {
|
||||
@@ -564,8 +558,8 @@ trait IssuesService {
|
||||
IssueLabels filter (_.byPrimaryKey(owner, repository, issueId, labelId)) delete
|
||||
}
|
||||
|
||||
def deleteAllIssueLabels(owner: String, repository: String, issueId: Int, insertComment: Boolean = false)(
|
||||
implicit context: Context,
|
||||
def deleteAllIssueLabels(owner: String, repository: String, issueId: Int, insertComment: Boolean = false)(implicit
|
||||
context: Context,
|
||||
s: Session
|
||||
): Int = {
|
||||
if (insertComment) {
|
||||
@@ -604,8 +598,8 @@ trait IssuesService {
|
||||
)
|
||||
}
|
||||
|
||||
def updateIssue(owner: String, repository: String, issueId: Int, title: String, content: Option[String])(
|
||||
implicit s: Session
|
||||
def updateIssue(owner: String, repository: String, issueId: Int, title: String, content: Option[String])(implicit
|
||||
s: Session
|
||||
): Int = {
|
||||
Issues
|
||||
.filter(_.byPrimaryKey(owner, repository, issueId))
|
||||
@@ -624,8 +618,8 @@ trait IssuesService {
|
||||
.update(true)
|
||||
}
|
||||
|
||||
def getIssueAssignees(owner: String, repository: String, issueId: Int)(
|
||||
implicit s: Session
|
||||
def getIssueAssignees(owner: String, repository: String, issueId: Int)(implicit
|
||||
s: Session
|
||||
): List[IssueAssignee] = {
|
||||
IssueAssignees.filter(_.byIssue(owner, repository, issueId)).sortBy(_.assigneeUserName).list
|
||||
}
|
||||
@@ -636,8 +630,8 @@ trait IssuesService {
|
||||
issueId: Int,
|
||||
assigneeUserName: String,
|
||||
insertComment: Boolean = false
|
||||
)(
|
||||
implicit context: Context,
|
||||
)(implicit
|
||||
context: Context,
|
||||
s: Session
|
||||
): Int = {
|
||||
val assigner = context.loginAccount.map(_.userName)
|
||||
@@ -665,8 +659,8 @@ trait IssuesService {
|
||||
issueId: Int,
|
||||
assigneeUserName: String,
|
||||
insertComment: Boolean = false
|
||||
)(
|
||||
implicit context: Context,
|
||||
)(implicit
|
||||
context: Context,
|
||||
s: Session
|
||||
): Int = {
|
||||
val assigner = context.loginAccount.map(_.userName)
|
||||
@@ -688,8 +682,8 @@ trait IssuesService {
|
||||
IssueAssignees filter (_.byPrimaryKey(owner, repository, issueId, assigneeUserName)) delete
|
||||
}
|
||||
|
||||
def deleteAllIssueAssignees(owner: String, repository: String, issueId: Int, insertComment: Boolean = false)(
|
||||
implicit context: Context,
|
||||
def deleteAllIssueAssignees(owner: String, repository: String, issueId: Int, insertComment: Boolean = false)(implicit
|
||||
context: Context,
|
||||
s: Session
|
||||
): Int = {
|
||||
val assigner = context.loginAccount.map(_.userName)
|
||||
@@ -773,15 +767,15 @@ trait IssuesService {
|
||||
.update(priorityId, currentDate)
|
||||
}
|
||||
|
||||
def updateComment(owner: String, repository: String, issueId: Int, commentId: Int, content: String)(
|
||||
implicit s: Session
|
||||
def updateComment(owner: String, repository: String, issueId: Int, commentId: Int, content: String)(implicit
|
||||
s: Session
|
||||
): Int = {
|
||||
Issues.filter(_.byPrimaryKey(owner, repository, issueId)).map(_.updatedDate).update(currentDate)
|
||||
IssueComments.filter(_.byPrimaryKey(commentId)).map(t => (t.content, t.updatedDate)).update(content, currentDate)
|
||||
}
|
||||
|
||||
def deleteComment(owner: String, repository: String, issueId: Int, commentId: Int)(
|
||||
implicit context: Context,
|
||||
def deleteComment(owner: String, repository: String, issueId: Int, commentId: Int)(implicit
|
||||
context: Context,
|
||||
s: Session
|
||||
): Int = {
|
||||
Issues.filter(_.byPrimaryKey(owner, repository, issueId)).map(_.updatedDate).update(currentDate)
|
||||
@@ -820,10 +814,10 @@ trait IssuesService {
|
||||
* @param query the keywords separated by whitespace.
|
||||
* @return issues with comment count and matched content of issue or comment
|
||||
*/
|
||||
def searchIssuesByKeyword(owner: String, repository: String, query: String, pullRequest: Boolean)(
|
||||
implicit s: Session
|
||||
def searchIssuesByKeyword(owner: String, repository: String, query: String, pullRequest: Boolean)(implicit
|
||||
s: Session
|
||||
): List[(Issue, Int, String)] = {
|
||||
//import slick.driver.JdbcDriver.likeEncode
|
||||
// import slick.driver.JdbcDriver.likeEncode
|
||||
val keywords = splitWords(query.toLowerCase)
|
||||
|
||||
// Search Issue
|
||||
@@ -832,61 +826,52 @@ trait IssuesService {
|
||||
t.byRepository(owner, repository) && t.pullRequest === pullRequest.bind
|
||||
}
|
||||
.join(IssueOutline)
|
||||
.on {
|
||||
case (t1, t2) =>
|
||||
t1.byIssue(t2.userName, t2.repositoryName, t2.issueId)
|
||||
.on { case (t1, t2) =>
|
||||
t1.byIssue(t2.userName, t2.repositoryName, t2.issueId)
|
||||
}
|
||||
.filter {
|
||||
case (t1, t2) =>
|
||||
keywords
|
||||
.map { keyword =>
|
||||
(t1.title.toLowerCase.like(s"%${likeEncode(keyword)}%", '^')) ||
|
||||
(t1.content.toLowerCase.like(s"%${likeEncode(keyword)}%", '^'))
|
||||
}
|
||||
.reduceLeft(_ && _)
|
||||
.filter { case (t1, t2) =>
|
||||
keywords
|
||||
.map { keyword =>
|
||||
(t1.title.toLowerCase.like(s"%${likeEncode(keyword)}%", '^')) ||
|
||||
(t1.content.toLowerCase.like(s"%${likeEncode(keyword)}%", '^'))
|
||||
}
|
||||
.reduceLeft(_ && _)
|
||||
}
|
||||
.map {
|
||||
case (t1, t2) =>
|
||||
(t1, 0, t1.content.?, t2.commentCount)
|
||||
.map { case (t1, t2) =>
|
||||
(t1, 0, t1.content.?, t2.commentCount)
|
||||
}
|
||||
|
||||
// Search IssueComment
|
||||
val comments = IssueComments
|
||||
.filter(_.byRepository(owner, repository))
|
||||
.join(Issues)
|
||||
.on {
|
||||
case (t1, t2) =>
|
||||
t1.byIssue(t2.userName, t2.repositoryName, t2.issueId)
|
||||
.on { case (t1, t2) =>
|
||||
t1.byIssue(t2.userName, t2.repositoryName, t2.issueId)
|
||||
}
|
||||
.join(IssueOutline)
|
||||
.on {
|
||||
case ((t1, t2), t3) =>
|
||||
t2.byIssue(t3.userName, t3.repositoryName, t3.issueId)
|
||||
.on { case ((t1, t2), t3) =>
|
||||
t2.byIssue(t3.userName, t3.repositoryName, t3.issueId)
|
||||
}
|
||||
.filter {
|
||||
case ((t1, t2), t3) =>
|
||||
t2.pullRequest === pullRequest.bind &&
|
||||
keywords
|
||||
.map { query =>
|
||||
t1.content.toLowerCase.like(s"%${likeEncode(query)}%", '^')
|
||||
}
|
||||
.reduceLeft(_ && _)
|
||||
.filter { case ((t1, t2), t3) =>
|
||||
t2.pullRequest === pullRequest.bind &&
|
||||
keywords
|
||||
.map { query =>
|
||||
t1.content.toLowerCase.like(s"%${likeEncode(query)}%", '^')
|
||||
}
|
||||
.reduceLeft(_ && _)
|
||||
}
|
||||
.map {
|
||||
case ((t1, t2), t3) =>
|
||||
(t2, t1.commentId, t1.content.?, t3.commentCount)
|
||||
.map { case ((t1, t2), t3) =>
|
||||
(t2, t1.commentId, t1.content.?, t3.commentCount)
|
||||
}
|
||||
|
||||
issues
|
||||
.union(comments)
|
||||
.sortBy {
|
||||
case (issue, commentId, _, _) =>
|
||||
issue.issueId.desc -> commentId
|
||||
.sortBy { case (issue, commentId, _, _) =>
|
||||
issue.issueId.desc -> commentId
|
||||
}
|
||||
.list
|
||||
.splitWith {
|
||||
case ((issue1, _, _, _), (issue2, _, _, _)) =>
|
||||
issue1.issueId == issue2.issueId
|
||||
.splitWith { case ((issue1, _, _, _), (issue2, _, _, _)) =>
|
||||
issue1.issueId == issue2.issueId
|
||||
}
|
||||
.map {
|
||||
_.head match {
|
||||
@@ -896,8 +881,8 @@ trait IssuesService {
|
||||
.toList
|
||||
}
|
||||
|
||||
def closeIssuesFromMessage(message: String, userName: String, owner: String, repository: String)(
|
||||
implicit s: Session
|
||||
def closeIssuesFromMessage(message: String, userName: String, owner: String, repository: String)(implicit
|
||||
s: Session
|
||||
): Seq[Int] = {
|
||||
extractCloseId(message).flatMap { issueId =>
|
||||
for (issue <- getIssue(owner, repository, issueId) if !issue.closed) yield {
|
||||
@@ -911,37 +896,37 @@ trait IssuesService {
|
||||
def createReferComment(owner: String, repository: String, fromIssue: Issue, message: String, loginAccount: Account)(
|
||||
implicit s: Session
|
||||
): Unit = {
|
||||
extractGlobalIssueId(message).foreach {
|
||||
case (_referredOwner, _referredRepository, referredIssueId) =>
|
||||
val referredOwner = _referredOwner.getOrElse(owner)
|
||||
val referredRepository = _referredRepository.getOrElse(repository)
|
||||
getRepository(referredOwner, referredRepository).foreach { repo =>
|
||||
if (isReadable(repo.repository, Option(loginAccount))) {
|
||||
getIssue(referredOwner, referredRepository, referredIssueId.get).foreach { _ =>
|
||||
val (content, action) = if (owner == referredOwner && repository == referredRepository) {
|
||||
(s"${fromIssue.issueId}:${fromIssue.title}", "refer")
|
||||
} else {
|
||||
(s"${fromIssue.issueId}:${owner}:${repository}:${fromIssue.title}", "refer_global")
|
||||
}
|
||||
referredIssueId.foreach(
|
||||
x =>
|
||||
// Not add if refer comment already exist.
|
||||
if (!getComments(referredOwner, referredRepository, x.toInt).exists { x =>
|
||||
(x.action == "refer" || x.action == "refer_global") && x.content == content
|
||||
}) {
|
||||
createComment(
|
||||
referredOwner,
|
||||
referredRepository,
|
||||
loginAccount.userName,
|
||||
x.toInt,
|
||||
content,
|
||||
action
|
||||
)
|
||||
}
|
||||
)
|
||||
extractGlobalIssueId(message).foreach { case (_referredOwner, _referredRepository, referredIssueId) =>
|
||||
val referredOwner = _referredOwner.getOrElse(owner)
|
||||
val referredRepository = _referredRepository.getOrElse(repository)
|
||||
getRepository(referredOwner, referredRepository).foreach { repo =>
|
||||
if (isReadable(repo.repository, Option(loginAccount))) {
|
||||
getIssue(referredOwner, referredRepository, referredIssueId.get).foreach { _ =>
|
||||
val (content, action) = if (owner == referredOwner && repository == referredRepository) {
|
||||
(s"${fromIssue.issueId}:${fromIssue.title}", "refer")
|
||||
} else {
|
||||
(s"${fromIssue.issueId}:${owner}:${repository}:${fromIssue.title}", "refer_global")
|
||||
}
|
||||
referredIssueId.foreach(x =>
|
||||
// Not add if refer comment already exist.
|
||||
if (
|
||||
!getComments(referredOwner, referredRepository, x.toInt).exists { x =>
|
||||
(x.action == "refer" || x.action == "refer_global") && x.content == content
|
||||
}
|
||||
) {
|
||||
createComment(
|
||||
referredOwner,
|
||||
referredRepository,
|
||||
loginAccount.userName,
|
||||
x.toInt,
|
||||
content,
|
||||
action
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -958,13 +943,13 @@ trait IssuesService {
|
||||
def getAssignableUserNames(owner: String, repository: String)(implicit s: Session): List[String] = {
|
||||
(getCollaboratorUserNames(owner, repository, Seq(Role.ADMIN, Role.DEVELOPER)) :::
|
||||
(getAccountByUserName(owner) match {
|
||||
case Some(x) if x.isGroupAccount =>
|
||||
getGroupMembers(owner).map(_.userName)
|
||||
case Some(_) =>
|
||||
List(owner)
|
||||
case None =>
|
||||
Nil
|
||||
})).distinct.sorted
|
||||
case Some(x) if x.isGroupAccount =>
|
||||
getGroupMembers(owner).map(_.userName)
|
||||
case Some(_) =>
|
||||
List(owner)
|
||||
case None =>
|
||||
Nil
|
||||
})).distinct.sorted
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1090,9 +1075,8 @@ object IssuesService {
|
||||
dim(0) -> dim(1)
|
||||
}
|
||||
.groupBy(_._1)
|
||||
.map {
|
||||
case (key, values) =>
|
||||
key -> values.map(_._2).toSeq
|
||||
.map { case (key, values) =>
|
||||
key -> values.map(_._2).toSeq
|
||||
}
|
||||
|
||||
val (sort, direction) = conditions.get("sort").flatMap(_.headOption).getOrElse("created-desc") match {
|
||||
@@ -1123,9 +1107,8 @@ object IssuesService {
|
||||
val dim = x.split(">")
|
||||
dim(0) -> ("gt", dim(1))
|
||||
}
|
||||
.map {
|
||||
case (key, (operator, value)) =>
|
||||
CustomFieldCondition(key.stripPrefix("custom."), value, operator)
|
||||
.map { case (key, (operator, value)) =>
|
||||
CustomFieldCondition(key.stripPrefix("custom."), value, operator)
|
||||
}
|
||||
.toSeq
|
||||
|
||||
@@ -1134,7 +1117,7 @@ object IssuesService {
|
||||
conditions.get("milestone").flatMap(_.headOption) match {
|
||||
case None => None
|
||||
case Some("none") => Some(None)
|
||||
case Some(x) => Some(Some(x)) //milestones.get(x).map(x => Some(x))
|
||||
case Some(x) => Some(Some(x)) // milestones.get(x).map(x => Some(x))
|
||||
},
|
||||
conditions.get("priority").map(_.headOption), // TODO
|
||||
conditions.get("author").flatMap(_.headOption),
|
||||
|
||||
@@ -30,8 +30,8 @@ trait LabelsService {
|
||||
createLabel(owner, repository, labelName, color)
|
||||
}
|
||||
|
||||
def updateLabel(owner: String, repository: String, labelId: Int, labelName: String, color: String)(
|
||||
implicit s: Session
|
||||
def updateLabel(owner: String, repository: String, labelId: Int, labelName: String, color: String)(implicit
|
||||
s: Session
|
||||
): Unit =
|
||||
Labels
|
||||
.filter(_.byPrimaryKey(owner, repository, labelId))
|
||||
|
||||
@@ -121,8 +121,8 @@ trait MergeService {
|
||||
afterCommitId: ObjectId,
|
||||
loginAccount: Account,
|
||||
settings: SystemSettings
|
||||
)(
|
||||
implicit s: Session,
|
||||
)(implicit
|
||||
s: Session,
|
||||
c: JsonFormat.Context
|
||||
): Unit = {
|
||||
callWebHookOf(repository.owner, repository.name, WebHook.Push, settings) {
|
||||
@@ -220,7 +220,14 @@ trait MergeService {
|
||||
requestRepositoryName: String,
|
||||
requestBranch: String
|
||||
): Option[String] =
|
||||
tryMergeRemote(userName, repositoryName, branch, requestUserName, requestRepositoryName, requestBranch).left.toOption
|
||||
tryMergeRemote(
|
||||
userName,
|
||||
repositoryName,
|
||||
branch,
|
||||
requestUserName,
|
||||
requestRepositoryName,
|
||||
requestBranch
|
||||
).left.toOption
|
||||
|
||||
def pullRemote(
|
||||
localRepository: RepositoryInfo,
|
||||
@@ -236,84 +243,90 @@ trait MergeService {
|
||||
val localRepositoryName = localRepository.name
|
||||
val remoteUserName = remoteRepository.owner
|
||||
val remoteRepositoryName = remoteRepository.name
|
||||
tryMergeRemote(localUserName, localRepositoryName, localBranch, remoteUserName, remoteRepositoryName, remoteBranch).map {
|
||||
case (newTreeId, oldBaseId, oldHeadId) =>
|
||||
Using.resource(Git.open(getRepositoryDir(localUserName, localRepositoryName))) { git =>
|
||||
val existIds = JGitUtil.getAllCommitIds(git).toSet
|
||||
tryMergeRemote(
|
||||
localUserName,
|
||||
localRepositoryName,
|
||||
localBranch,
|
||||
remoteUserName,
|
||||
remoteRepositoryName,
|
||||
remoteBranch
|
||||
).map { case (newTreeId, oldBaseId, oldHeadId) =>
|
||||
Using.resource(Git.open(getRepositoryDir(localUserName, localRepositoryName))) { git =>
|
||||
val existIds = JGitUtil.getAllCommitIds(git).toSet
|
||||
|
||||
val committer = new PersonIdent(loginAccount.fullName, loginAccount.mailAddress)
|
||||
val newCommit =
|
||||
Util.createMergeCommit(git.getRepository, newTreeId, committer, message, Seq(oldBaseId, oldHeadId))
|
||||
Util.updateRefs(git.getRepository, s"refs/heads/${localBranch}", newCommit, false, committer, Some("merge"))
|
||||
val committer = new PersonIdent(loginAccount.fullName, loginAccount.mailAddress)
|
||||
val newCommit =
|
||||
Util.createMergeCommit(git.getRepository, newTreeId, committer, message, Seq(oldBaseId, oldHeadId))
|
||||
Util.updateRefs(git.getRepository, s"refs/heads/${localBranch}", newCommit, false, committer, Some("merge"))
|
||||
|
||||
val commits = git.log
|
||||
.addRange(oldBaseId, newCommit)
|
||||
.call
|
||||
.iterator
|
||||
.asScala
|
||||
.map(c => new JGitUtil.CommitInfo(c))
|
||||
.toList
|
||||
val commits = git.log
|
||||
.addRange(oldBaseId, newCommit)
|
||||
.call
|
||||
.iterator
|
||||
.asScala
|
||||
.map(c => new JGitUtil.CommitInfo(c))
|
||||
.toList
|
||||
|
||||
commits.foreach { commit =>
|
||||
if (!existIds.contains(commit.id)) {
|
||||
createIssueComment(localUserName, localRepositoryName, commit)
|
||||
}
|
||||
}
|
||||
|
||||
// record activity
|
||||
val pushInfo = PushInfo(
|
||||
localUserName,
|
||||
localRepositoryName,
|
||||
loginAccount.userName,
|
||||
localBranch,
|
||||
commits
|
||||
)
|
||||
recordActivity(pushInfo)
|
||||
|
||||
// close issue by commit message
|
||||
if (localBranch == localRepository.repository.defaultBranch) {
|
||||
commits.foreach { commit =>
|
||||
if (!existIds.contains(commit.id)) {
|
||||
createIssueComment(localUserName, localRepositoryName, commit)
|
||||
}
|
||||
}
|
||||
|
||||
// record activity
|
||||
val pushInfo = PushInfo(
|
||||
localUserName,
|
||||
localRepositoryName,
|
||||
loginAccount.userName,
|
||||
localBranch,
|
||||
commits
|
||||
)
|
||||
recordActivity(pushInfo)
|
||||
|
||||
// close issue by commit message
|
||||
if (localBranch == localRepository.repository.defaultBranch) {
|
||||
commits.foreach { commit =>
|
||||
closeIssuesFromMessage(commit.fullMessage, loginAccount.userName, localUserName, localRepositoryName)
|
||||
.foreach { issueId =>
|
||||
getIssue(localRepository.owner, localRepository.name, issueId.toString).foreach { issue =>
|
||||
callIssuesWebHook("closed", localRepository, issue, loginAccount, settings)
|
||||
val closeIssueInfo = CloseIssueInfo(
|
||||
localRepository.owner,
|
||||
localRepository.name,
|
||||
localUserName,
|
||||
issue.issueId,
|
||||
issue.title
|
||||
closeIssuesFromMessage(commit.fullMessage, loginAccount.userName, localUserName, localRepositoryName)
|
||||
.foreach { issueId =>
|
||||
getIssue(localRepository.owner, localRepository.name, issueId.toString).foreach { issue =>
|
||||
callIssuesWebHook("closed", localRepository, issue, loginAccount, settings)
|
||||
val closeIssueInfo = CloseIssueInfo(
|
||||
localRepository.owner,
|
||||
localRepository.name,
|
||||
localUserName,
|
||||
issue.issueId,
|
||||
issue.title
|
||||
)
|
||||
recordActivity(closeIssueInfo)
|
||||
PluginRegistry().getIssueHooks
|
||||
.foreach(
|
||||
_.closedByCommitComment(issue, localRepository, commit.fullMessage, loginAccount)
|
||||
)
|
||||
recordActivity(closeIssueInfo)
|
||||
PluginRegistry().getIssueHooks
|
||||
.foreach(
|
||||
_.closedByCommitComment(issue, localRepository, commit.fullMessage, loginAccount)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pullRequest.foreach { pullRequest =>
|
||||
callWebHookOf(localRepository.owner, localRepository.name, WebHook.Push, settings) {
|
||||
for {
|
||||
ownerAccount <- getAccountByUserName(localRepository.owner)
|
||||
} yield {
|
||||
WebHookService.WebHookPushPayload(
|
||||
git,
|
||||
loginAccount,
|
||||
pullRequest.requestBranch,
|
||||
localRepository,
|
||||
commits,
|
||||
ownerAccount,
|
||||
oldId = oldBaseId,
|
||||
newId = newCommit
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pullRequest.foreach { pullRequest =>
|
||||
callWebHookOf(localRepository.owner, localRepository.name, WebHook.Push, settings) {
|
||||
for {
|
||||
ownerAccount <- getAccountByUserName(localRepository.owner)
|
||||
} yield {
|
||||
WebHookService.WebHookPushPayload(
|
||||
git,
|
||||
loginAccount,
|
||||
pullRequest.requestBranch,
|
||||
localRepository,
|
||||
commits,
|
||||
ownerAccount,
|
||||
oldId = oldBaseId,
|
||||
newId = newCommit
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
oldBaseId
|
||||
}
|
||||
oldBaseId
|
||||
}.toOption
|
||||
}
|
||||
|
||||
@@ -621,11 +634,12 @@ object MergeService {
|
||||
|
||||
def checkConflictForce(): Option[String] = {
|
||||
val merger = MergeStrategy.RECURSIVE.newMerger(git.getRepository, true)
|
||||
val conflicted = try {
|
||||
!merger.merge(mergeBaseTip, mergeTip)
|
||||
} catch {
|
||||
case e: NoMergeBaseException => true
|
||||
}
|
||||
val conflicted =
|
||||
try {
|
||||
!merger.merge(mergeBaseTip, mergeTip)
|
||||
} catch {
|
||||
case e: NoMergeBaseException => true
|
||||
}
|
||||
val mergeTipCommit = Using.resource(new RevWalk(git.getRepository))(_.parseCommit(mergeTip))
|
||||
val committer = mergeTipCommit.getCommitterIdent
|
||||
|
||||
|
||||
@@ -46,8 +46,8 @@ trait MilestonesService {
|
||||
def getMilestone(owner: String, repository: String, milestoneId: Int)(implicit s: Session): Option[Milestone] =
|
||||
Milestones.filter(_.byPrimaryKey(owner, repository, milestoneId)).firstOption
|
||||
|
||||
def getMilestonesWithIssueCount(owner: String, repository: String)(
|
||||
implicit s: Session
|
||||
def getMilestonesWithIssueCount(owner: String, repository: String)(implicit
|
||||
s: Session
|
||||
): List[(Milestone, Int, Int)] = {
|
||||
val counts = Issues
|
||||
.filter { t =>
|
||||
@@ -78,13 +78,12 @@ trait MilestonesService {
|
||||
def getApiMilestone(repository: RepositoryInfo, milestoneId: Int)(implicit s: Session): Option[ApiMilestone] = {
|
||||
getMilestonesWithIssueCount(repository.owner, repository.name)
|
||||
.find(p => p._1.milestoneId == milestoneId)
|
||||
.map(
|
||||
milestoneWithIssue =>
|
||||
ApiMilestone(
|
||||
repository.repository,
|
||||
milestoneWithIssue._1,
|
||||
milestoneWithIssue._2,
|
||||
milestoneWithIssue._3
|
||||
.map(milestoneWithIssue =>
|
||||
ApiMilestone(
|
||||
repository.repository,
|
||||
milestoneWithIssue._1,
|
||||
milestoneWithIssue._2,
|
||||
milestoneWithIssue._3
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -59,12 +59,11 @@ trait PrioritiesService {
|
||||
Priorities
|
||||
.filter(_.byRepository(owner, repository))
|
||||
.list
|
||||
.foreach(
|
||||
p =>
|
||||
Priorities
|
||||
.filter(_.byPrimaryKey(owner, repository, p.priorityId))
|
||||
.map(_.ordering)
|
||||
.update(order.get(p.priorityId).get)
|
||||
.foreach(p =>
|
||||
Priorities
|
||||
.filter(_.byPrimaryKey(owner, repository, p.priorityId))
|
||||
.map(_.ordering)
|
||||
.update(order.get(p.priorityId).get)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -93,12 +92,11 @@ trait PrioritiesService {
|
||||
.map(_.isDefault)
|
||||
.update(false)
|
||||
|
||||
priorityId.foreach(
|
||||
id =>
|
||||
Priorities
|
||||
.filter(_.byPrimaryKey(owner, repository, id))
|
||||
.map(_.isDefault)
|
||||
.update(true)
|
||||
priorityId.foreach(id =>
|
||||
Priorities
|
||||
.filter(_.byPrimaryKey(owner, repository, id))
|
||||
.map(_.isDefault)
|
||||
.update(true)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ import org.eclipse.jgit.transport.{ReceiveCommand, ReceivePack}
|
||||
|
||||
trait ProtectedBranchService {
|
||||
import ProtectedBranchService._
|
||||
private def getProtectedBranchInfoOpt(owner: String, repository: String, branch: String)(
|
||||
implicit session: Session
|
||||
private def getProtectedBranchInfoOpt(owner: String, repository: String, branch: String)(implicit
|
||||
session: Session
|
||||
): Option[ProtectedBranchInfo] =
|
||||
ProtectedBranches
|
||||
.joinLeft(ProtectedBranchContexts)
|
||||
@@ -22,13 +22,12 @@ trait ProtectedBranchService {
|
||||
.map { p =>
|
||||
p._1 -> p._2.flatMap(_._2)
|
||||
}
|
||||
.map {
|
||||
case (t1, contexts) =>
|
||||
new ProtectedBranchInfo(t1.userName, t1.repositoryName, t1.branch, true, contexts, t1.statusCheckAdmin)
|
||||
.map { case (t1, contexts) =>
|
||||
new ProtectedBranchInfo(t1.userName, t1.repositoryName, t1.branch, true, contexts, t1.statusCheckAdmin)
|
||||
}
|
||||
|
||||
def getProtectedBranchInfo(owner: String, repository: String, branch: String)(
|
||||
implicit session: Session
|
||||
def getProtectedBranchInfo(owner: String, repository: String, branch: String)(implicit
|
||||
session: Session
|
||||
): ProtectedBranchInfo =
|
||||
getProtectedBranchInfoOpt(owner, repository, branch).getOrElse(
|
||||
ProtectedBranchInfo.disabled(owner, repository, branch)
|
||||
@@ -88,9 +87,11 @@ object ProtectedBranchService {
|
||||
val branch = command.getRefName.stripPrefix("refs/heads/")
|
||||
if (branch != command.getRefName) {
|
||||
val repositoryInfo = getRepository(owner, repository)
|
||||
if (command.getType == ReceiveCommand.Type.DELETE && repositoryInfo.exists(
|
||||
_.repository.defaultBranch == branch
|
||||
)) {
|
||||
if (
|
||||
command.getType == ReceiveCommand.Type.DELETE && repositoryInfo.exists(
|
||||
_.repository.defaultBranch == branch
|
||||
)
|
||||
) {
|
||||
Some(s"refusing to delete the branch: ${command.getRefName}.")
|
||||
} else {
|
||||
getProtectedBranchInfo(owner, repository, branch).getStopReason(
|
||||
@@ -128,15 +129,14 @@ object ProtectedBranchService {
|
||||
|
||||
def isAdministrator(pusher: String)(implicit session: Session): Boolean =
|
||||
pusher == owner || getGroupMembers(owner).exists(gm => gm.userName == pusher && gm.isManager) ||
|
||||
getCollaborators(owner, repository).exists {
|
||||
case (collaborator, isGroup) =>
|
||||
if (collaborator.role == Role.ADMIN.name) {
|
||||
if (isGroup) {
|
||||
getGroupMembers(collaborator.collaboratorName).exists(gm => gm.userName == pusher)
|
||||
} else {
|
||||
collaborator.collaboratorName == pusher
|
||||
}
|
||||
} else false
|
||||
getCollaborators(owner, repository).exists { case (collaborator, isGroup) =>
|
||||
if (collaborator.role == Role.ADMIN.name) {
|
||||
if (isGroup) {
|
||||
getGroupMembers(collaborator.collaboratorName).exists(gm => gm.userName == pusher)
|
||||
} else {
|
||||
collaborator.collaboratorName == pusher
|
||||
}
|
||||
} else false
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -144,8 +144,8 @@ object ProtectedBranchService {
|
||||
* Can't be deleted
|
||||
* Can't have changes merged into them until required status checks pass
|
||||
*/
|
||||
def getStopReason(isAllowNonFastForwards: Boolean, command: ReceiveCommand, pusher: String)(
|
||||
implicit session: Session
|
||||
def getStopReason(isAllowNonFastForwards: Boolean, command: ReceiveCommand, pusher: String)(implicit
|
||||
session: Session
|
||||
): Option[String] = {
|
||||
if (enabled) {
|
||||
command.getType() match {
|
||||
|
||||
@@ -34,8 +34,8 @@ trait PullRequestService {
|
||||
with ActivityService =>
|
||||
import PullRequestService._
|
||||
|
||||
def getPullRequest(owner: String, repository: String, issueId: Int)(
|
||||
implicit s: Session
|
||||
def getPullRequest(owner: String, repository: String, issueId: Int)(implicit
|
||||
s: Session
|
||||
): Option[(Issue, PullRequest)] =
|
||||
getIssue(owner, repository, issueId.toString).flatMap { issue =>
|
||||
PullRequests.filter(_.byPrimaryKey(owner, repository, issueId)).firstOption.map { pullreq =>
|
||||
@@ -43,24 +43,24 @@ trait PullRequestService {
|
||||
}
|
||||
}
|
||||
|
||||
def updateCommitId(owner: String, repository: String, issueId: Int, commitIdTo: String, commitIdFrom: String)(
|
||||
implicit s: Session
|
||||
def updateCommitId(owner: String, repository: String, issueId: Int, commitIdTo: String, commitIdFrom: String)(implicit
|
||||
s: Session
|
||||
): Unit =
|
||||
PullRequests
|
||||
.filter(_.byPrimaryKey(owner, repository, issueId))
|
||||
.map(pr => pr.commitIdTo -> pr.commitIdFrom)
|
||||
.update((commitIdTo, commitIdFrom))
|
||||
|
||||
def updateDraftToPullRequest(owner: String, repository: String, issueId: Int)(
|
||||
implicit s: Session
|
||||
def updateDraftToPullRequest(owner: String, repository: String, issueId: Int)(implicit
|
||||
s: Session
|
||||
): Unit =
|
||||
PullRequests
|
||||
.filter(_.byPrimaryKey(owner, repository, issueId))
|
||||
.map(pr => pr.isDraft)
|
||||
.update(false)
|
||||
|
||||
def updateBaseBranch(owner: String, repository: String, issueId: Int, baseBranch: String, commitIdTo: String)(
|
||||
implicit s: Session
|
||||
def updateBaseBranch(owner: String, repository: String, issueId: Int, baseBranch: String, commitIdTo: String)(implicit
|
||||
s: Session
|
||||
): Unit = {
|
||||
PullRequests
|
||||
.filter(_.byPrimaryKey(owner, repository, issueId))
|
||||
@@ -68,19 +68,18 @@ trait PullRequestService {
|
||||
.update((baseBranch, commitIdTo))
|
||||
}
|
||||
|
||||
def getPullRequestCountGroupByUser(closed: Boolean, owner: Option[String], repository: Option[String])(
|
||||
implicit s: Session
|
||||
def getPullRequestCountGroupByUser(closed: Boolean, owner: Option[String], repository: Option[String])(implicit
|
||||
s: Session
|
||||
): List[PullRequestCount] =
|
||||
PullRequests
|
||||
.join(Issues)
|
||||
.on { (t1, t2) =>
|
||||
t1.byPrimaryKey(t2.userName, t2.repositoryName, t2.issueId)
|
||||
}
|
||||
.filter {
|
||||
case (t1, t2) =>
|
||||
(t2.closed === closed.bind)
|
||||
.&&(t1.userName === owner.get.bind, owner.isDefined)
|
||||
.&&(t1.repositoryName === repository.get.bind, repository.isDefined)
|
||||
.filter { case (t1, t2) =>
|
||||
(t2.closed === closed.bind)
|
||||
.&&(t1.userName === owner.get.bind, owner.isDefined)
|
||||
.&&(t1.repositoryName === repository.get.bind, repository.isDefined)
|
||||
}
|
||||
.groupBy { case (t1, t2) => t2.openedUserName }
|
||||
.map { case (userName, t) => userName -> t.length }
|
||||
@@ -182,12 +181,11 @@ trait PullRequestService {
|
||||
.on { (t1, t2) =>
|
||||
t1.byPrimaryKey(t2.userName, t2.repositoryName, t2.issueId)
|
||||
}
|
||||
.filter {
|
||||
case (t1, t2) =>
|
||||
(t1.requestUserName === userName.bind)
|
||||
.&&(t1.requestRepositoryName === repositoryName.bind)
|
||||
.&&(t1.requestBranch === branch.bind)
|
||||
.&&(t2.closed === closed.get.bind, closed.isDefined)
|
||||
.filter { case (t1, t2) =>
|
||||
(t1.requestUserName === userName.bind)
|
||||
.&&(t1.requestRepositoryName === repositoryName.bind)
|
||||
.&&(t1.requestBranch === branch.bind)
|
||||
.&&(t2.closed === closed.get.bind, closed.isDefined)
|
||||
}
|
||||
.map { case (t1, t2) => t1 }
|
||||
.list
|
||||
@@ -200,12 +198,11 @@ trait PullRequestService {
|
||||
.on { (t1, t2) =>
|
||||
t1.byPrimaryKey(t2.userName, t2.repositoryName, t2.issueId)
|
||||
}
|
||||
.filter {
|
||||
case (t1, t2) =>
|
||||
(t1.requestUserName === userName.bind)
|
||||
.&&(t1.requestRepositoryName === repositoryName.bind)
|
||||
.&&(t1.branch === branch.bind)
|
||||
.&&(t2.closed === closed.get.bind, closed.isDefined)
|
||||
.filter { case (t1, t2) =>
|
||||
(t1.requestUserName === userName.bind)
|
||||
.&&(t1.requestRepositoryName === repositoryName.bind)
|
||||
.&&(t1.branch === branch.bind)
|
||||
.&&(t2.closed === closed.get.bind, closed.isDefined)
|
||||
}
|
||||
.map { case (t1, t2) => t1 }
|
||||
.list
|
||||
@@ -217,22 +214,21 @@ trait PullRequestService {
|
||||
* 2. return if exists pull request to other branch
|
||||
* 2. return None
|
||||
*/
|
||||
def getPullRequestFromBranch(userName: String, repositoryName: String, branch: String, defaultBranch: String)(
|
||||
implicit s: Session
|
||||
def getPullRequestFromBranch(userName: String, repositoryName: String, branch: String, defaultBranch: String)(implicit
|
||||
s: Session
|
||||
): Option[(PullRequest, Issue)] =
|
||||
PullRequests
|
||||
.join(Issues)
|
||||
.on { (t1, t2) =>
|
||||
t1.byPrimaryKey(t2.userName, t2.repositoryName, t2.issueId)
|
||||
}
|
||||
.filter {
|
||||
case (t1, t2) =>
|
||||
(t1.requestUserName === userName.bind) &&
|
||||
(t1.requestRepositoryName === repositoryName.bind) &&
|
||||
(t1.requestBranch === branch.bind) &&
|
||||
(t1.userName === userName.bind) &&
|
||||
(t1.repositoryName === repositoryName.bind) &&
|
||||
(t2.closed === false.bind)
|
||||
.filter { case (t1, t2) =>
|
||||
(t1.requestUserName === userName.bind) &&
|
||||
(t1.requestRepositoryName === repositoryName.bind) &&
|
||||
(t1.requestBranch === branch.bind) &&
|
||||
(t1.userName === userName.bind) &&
|
||||
(t1.repositoryName === repositoryName.bind) &&
|
||||
(t2.closed === false.bind)
|
||||
}
|
||||
.sortBy { case (t1, t2) => t1.branch =!= defaultBranch.bind }
|
||||
.firstOption
|
||||
@@ -247,8 +243,8 @@ trait PullRequestService {
|
||||
pusherAccount: Account,
|
||||
action: String,
|
||||
settings: SystemSettings
|
||||
)(
|
||||
implicit s: Session,
|
||||
)(implicit
|
||||
s: Session,
|
||||
c: JsonFormat.Context
|
||||
): Unit = {
|
||||
getPullRequestsByRequest(owner, repository, branch, Some(false)).foreach { pullreq =>
|
||||
@@ -273,10 +269,9 @@ trait PullRequestService {
|
||||
(file, commentId, Left(oldLine))
|
||||
}
|
||||
.groupBy { case (file, _, _) => file }
|
||||
.map {
|
||||
case (file, comments) =>
|
||||
file ->
|
||||
comments.map { case (_, commentId, lineNumber) => (commentId, lineNumber) }
|
||||
.map { case (file, comments) =>
|
||||
file ->
|
||||
comments.map { case (_, commentId, lineNumber) => (commentId, lineNumber) }
|
||||
}
|
||||
|
||||
// Update comments position
|
||||
@@ -312,64 +307,63 @@ trait PullRequestService {
|
||||
body: Option[String],
|
||||
state: Option[String],
|
||||
base: Option[String]
|
||||
)(
|
||||
implicit s: Session,
|
||||
)(implicit
|
||||
s: Session,
|
||||
c: JsonFormat.Context
|
||||
): Unit = {
|
||||
getPullRequest(repository.owner, repository.name, issueId).foreach {
|
||||
case (issue, pr) =>
|
||||
if (Repositories.filter(_.byRepository(pr.userName, pr.repositoryName)).exists.run) {
|
||||
// Update base branch
|
||||
base.foreach { _base =>
|
||||
if (pr.branch != _base) {
|
||||
Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) { git =>
|
||||
getBranches(git, repository.repository.defaultBranch, origin = true)
|
||||
.find(_.name == _base)
|
||||
.foreach(br => updateBaseBranch(repository.owner, repository.name, issueId, br.name, br.commitId))
|
||||
}
|
||||
createComment(
|
||||
repository.owner,
|
||||
repository.name,
|
||||
loginAccount.userName,
|
||||
issue.issueId,
|
||||
pr.branch + "\r\n" + _base,
|
||||
"change_base_branch"
|
||||
)
|
||||
getPullRequest(repository.owner, repository.name, issueId).foreach { case (issue, pr) =>
|
||||
if (Repositories.filter(_.byRepository(pr.userName, pr.repositoryName)).exists.run) {
|
||||
// Update base branch
|
||||
base.foreach { _base =>
|
||||
if (pr.branch != _base) {
|
||||
Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) { git =>
|
||||
getBranches(git, repository.repository.defaultBranch, origin = true)
|
||||
.find(_.name == _base)
|
||||
.foreach(br => updateBaseBranch(repository.owner, repository.name, issueId, br.name, br.commitId))
|
||||
}
|
||||
createComment(
|
||||
repository.owner,
|
||||
repository.name,
|
||||
loginAccount.userName,
|
||||
issue.issueId,
|
||||
pr.branch + "\r\n" + _base,
|
||||
"change_base_branch"
|
||||
)
|
||||
}
|
||||
// Update title and content
|
||||
title.foreach { _title =>
|
||||
updateIssue(repository.owner, repository.name, issueId, _title, body)
|
||||
if (issue.title != _title) {
|
||||
createComment(
|
||||
repository.owner,
|
||||
repository.name,
|
||||
loginAccount.userName,
|
||||
issue.issueId,
|
||||
issue.title + "\r\n" + _title,
|
||||
"change_title"
|
||||
)
|
||||
}
|
||||
}
|
||||
// Update state
|
||||
val action = (state, issue.closed) match {
|
||||
case (Some("open"), true) =>
|
||||
updateClosed(repository.owner, repository.name, issueId, closed = false)
|
||||
"reopened"
|
||||
case (Some("closed"), false) =>
|
||||
updateClosed(repository.owner, repository.name, issueId, closed = true)
|
||||
"closed"
|
||||
case _ => "edited"
|
||||
}
|
||||
// Call web hook
|
||||
callPullRequestWebHookByRequestBranch(
|
||||
action,
|
||||
getRepository(repository.owner, repository.name).get,
|
||||
pr.requestBranch,
|
||||
loginAccount,
|
||||
settings
|
||||
)
|
||||
}
|
||||
// Update title and content
|
||||
title.foreach { _title =>
|
||||
updateIssue(repository.owner, repository.name, issueId, _title, body)
|
||||
if (issue.title != _title) {
|
||||
createComment(
|
||||
repository.owner,
|
||||
repository.name,
|
||||
loginAccount.userName,
|
||||
issue.issueId,
|
||||
issue.title + "\r\n" + _title,
|
||||
"change_title"
|
||||
)
|
||||
}
|
||||
}
|
||||
// Update state
|
||||
val action = (state, issue.closed) match {
|
||||
case (Some("open"), true) =>
|
||||
updateClosed(repository.owner, repository.name, issueId, closed = false)
|
||||
"reopened"
|
||||
case (Some("closed"), false) =>
|
||||
updateClosed(repository.owner, repository.name, issueId, closed = true)
|
||||
"closed"
|
||||
case _ => "edited"
|
||||
}
|
||||
// Call web hook
|
||||
callPullRequestWebHookByRequestBranch(
|
||||
action,
|
||||
getRepository(repository.owner, repository.name).get,
|
||||
pr.requestBranch,
|
||||
loginAccount,
|
||||
settings
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -388,15 +382,14 @@ trait PullRequestService {
|
||||
.on { (t1, t2) =>
|
||||
t1.byPrimaryKey(t2.userName, t2.repositoryName, t2.issueId)
|
||||
}
|
||||
.filter {
|
||||
case (t1, t2) =>
|
||||
(t1.userName === userName.bind) &&
|
||||
(t1.repositoryName === repositoryName.bind) &&
|
||||
(t1.branch === toBranch.bind) &&
|
||||
(t1.requestUserName === userName.bind) &&
|
||||
(t1.requestRepositoryName === repositoryName.bind) &&
|
||||
(t1.requestBranch === fromBranch.bind) &&
|
||||
(t1.commitIdTo === commitId.bind)
|
||||
.filter { case (t1, t2) =>
|
||||
(t1.userName === userName.bind) &&
|
||||
(t1.repositoryName === repositoryName.bind) &&
|
||||
(t1.branch === toBranch.bind) &&
|
||||
(t1.requestUserName === userName.bind) &&
|
||||
(t1.requestRepositoryName === repositoryName.bind) &&
|
||||
(t1.requestBranch === fromBranch.bind) &&
|
||||
(t1.commitIdTo === commitId.bind)
|
||||
}
|
||||
.firstOption
|
||||
}
|
||||
@@ -412,63 +405,61 @@ trait PullRequestService {
|
||||
|
||||
val (_, diffs) = getRequestCompareInfo(userName, repositoryName, oldCommitId, userName, repositoryName, newCommitId)
|
||||
|
||||
val patchs = positions.map {
|
||||
case (file, _) =>
|
||||
diffs
|
||||
.find(x => x.oldPath == file)
|
||||
.map { diff =>
|
||||
(diff.oldContent, diff.newContent) match {
|
||||
case (Some(oldContent), Some(newContent)) => {
|
||||
val oldLines = convertLineSeparator(oldContent, "LF").split("\n")
|
||||
val newLines = convertLineSeparator(newContent, "LF").split("\n")
|
||||
file -> Option(DiffUtils.diff(oldLines.toList.asJava, newLines.toList.asJava))
|
||||
}
|
||||
case _ =>
|
||||
file -> None
|
||||
val patchs = positions.map { case (file, _) =>
|
||||
diffs
|
||||
.find(x => x.oldPath == file)
|
||||
.map { diff =>
|
||||
(diff.oldContent, diff.newContent) match {
|
||||
case (Some(oldContent), Some(newContent)) => {
|
||||
val oldLines = convertLineSeparator(oldContent, "LF").split("\n")
|
||||
val newLines = convertLineSeparator(newContent, "LF").split("\n")
|
||||
file -> Option(DiffUtils.diff(oldLines.toList.asJava, newLines.toList.asJava))
|
||||
}
|
||||
case _ =>
|
||||
file -> None
|
||||
}
|
||||
.getOrElse {
|
||||
file -> None
|
||||
}
|
||||
}
|
||||
.getOrElse {
|
||||
file -> None
|
||||
}
|
||||
}
|
||||
|
||||
positions.foreach {
|
||||
case (file, comments) =>
|
||||
patchs(file) match {
|
||||
case Some(patch) =>
|
||||
file -> comments.foreach {
|
||||
case (commentId, lineNumber) =>
|
||||
lineNumber match {
|
||||
case Left(oldLine) => updateCommitCommentPosition(commentId, newCommitId, Some(oldLine), None)
|
||||
case Right(newLine) =>
|
||||
var counter = newLine
|
||||
patch.getDeltas.asScala.filter(_.getSource.getPosition < newLine).foreach { delta =>
|
||||
delta.getType match {
|
||||
case DeltaType.CHANGE =>
|
||||
if (delta.getSource.getPosition <= newLine - 1 && newLine <= delta.getSource.getPosition + delta.getTarget.getLines.size) {
|
||||
counter = -1
|
||||
} else {
|
||||
counter = counter + (delta.getTarget.getLines.size - delta.getSource.getLines.size)
|
||||
}
|
||||
case DeltaType.INSERT => counter = counter + delta.getTarget.getLines.size
|
||||
case DeltaType.DELETE => counter = counter - delta.getSource.getLines.size
|
||||
case DeltaType.EQUAL => // Do nothing
|
||||
positions.foreach { case (file, comments) =>
|
||||
patchs(file) match {
|
||||
case Some(patch) =>
|
||||
file -> comments.foreach { case (commentId, lineNumber) =>
|
||||
lineNumber match {
|
||||
case Left(oldLine) => updateCommitCommentPosition(commentId, newCommitId, Some(oldLine), None)
|
||||
case Right(newLine) =>
|
||||
var counter = newLine
|
||||
patch.getDeltas.asScala.filter(_.getSource.getPosition < newLine).foreach { delta =>
|
||||
delta.getType match {
|
||||
case DeltaType.CHANGE =>
|
||||
if (
|
||||
delta.getSource.getPosition <= newLine - 1 && newLine <= delta.getSource.getPosition + delta.getTarget.getLines.size
|
||||
) {
|
||||
counter = -1
|
||||
} else {
|
||||
counter = counter + (delta.getTarget.getLines.size - delta.getSource.getLines.size)
|
||||
}
|
||||
}
|
||||
if (counter >= 0) {
|
||||
updateCommitCommentPosition(commentId, newCommitId, None, Some(counter))
|
||||
}
|
||||
case DeltaType.INSERT => counter = counter + delta.getTarget.getLines.size
|
||||
case DeltaType.DELETE => counter = counter - delta.getSource.getLines.size
|
||||
case DeltaType.EQUAL => // Do nothing
|
||||
}
|
||||
}
|
||||
if (counter >= 0) {
|
||||
updateCommitCommentPosition(commentId, newCommitId, None, Some(counter))
|
||||
}
|
||||
}
|
||||
case _ =>
|
||||
comments.foreach {
|
||||
case (commentId, lineNumber) =>
|
||||
lineNumber match {
|
||||
case Right(oldLine) => updateCommitCommentPosition(commentId, newCommitId, Some(oldLine), None)
|
||||
case Left(newLine) => updateCommitCommentPosition(commentId, newCommitId, None, Some(newLine))
|
||||
}
|
||||
}
|
||||
case _ =>
|
||||
comments.foreach { case (commentId, lineNumber) =>
|
||||
lineNumber match {
|
||||
case Right(oldLine) => updateCommitCommentPosition(commentId, newCommitId, Some(oldLine), None)
|
||||
case Left(newLine) => updateCommitCommentPosition(commentId, newCommitId, None, Some(newLine))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -540,20 +531,19 @@ trait PullRequestService {
|
||||
(commits, diffs)
|
||||
}
|
||||
|
||||
def getPullRequestComments(userName: String, repositoryName: String, issueId: Int, commits: Seq[CommitInfo])(
|
||||
implicit s: Session
|
||||
def getPullRequestComments(userName: String, repositoryName: String, issueId: Int, commits: Seq[CommitInfo])(implicit
|
||||
s: Session
|
||||
): Seq[Comment] = {
|
||||
(commits.flatMap(commit => getCommitComments(userName, repositoryName, commit.id, true)) ++ getComments(
|
||||
userName,
|
||||
repositoryName,
|
||||
issueId
|
||||
)).groupBy {
|
||||
case x: IssueComment => (Some(x.commentId), None, None, None)
|
||||
case x: CommitComment if x.fileName.isEmpty => (Some(x.commentId), None, None, None)
|
||||
case x: CommitComment => (None, x.fileName, x.originalOldLine, x.originalNewLine)
|
||||
case x => throw new MatchError(x)
|
||||
}
|
||||
.toSeq
|
||||
case x: IssueComment => (Some(x.commentId), None, None, None)
|
||||
case x: CommitComment if x.fileName.isEmpty => (Some(x.commentId), None, None, None)
|
||||
case x: CommitComment => (None, x.fileName, x.originalOldLine, x.originalNewLine)
|
||||
case x => throw new MatchError(x)
|
||||
}.toSeq
|
||||
.map {
|
||||
// Normal comment
|
||||
case ((Some(_), _, _, _), comments) =>
|
||||
@@ -578,8 +568,8 @@ trait PullRequestService {
|
||||
.sortWith(_.registeredDate before _.registeredDate)
|
||||
}
|
||||
|
||||
def markMergeAndClosePullRequest(userName: String, owner: String, repository: String, pull: PullRequest)(
|
||||
implicit s: Session
|
||||
def markMergeAndClosePullRequest(userName: String, owner: String, repository: String, pull: PullRequest)(implicit
|
||||
s: Session
|
||||
): Unit = {
|
||||
createComment(owner, repository, userName, pull.issueId, "Merged by user", "merge")
|
||||
createComment(owner, repository, userName, pull.issueId, "Close", "close")
|
||||
@@ -609,33 +599,32 @@ trait PullRequestService {
|
||||
Using.resources(
|
||||
Git.open(getRepositoryDir(originRepository.owner, originRepository.name)),
|
||||
Git.open(getRepositoryDir(forkedRepository.owner, forkedRepository.name))
|
||||
) {
|
||||
case (oldGit, newGit) =>
|
||||
if (originRepository.branchList.contains(originId)) {
|
||||
val forkedId2 =
|
||||
forkedRepository.tags.collectFirst { case x if x.name == forkedId => x.commitId }.getOrElse(forkedId)
|
||||
) { case (oldGit, newGit) =>
|
||||
if (originRepository.branchList.contains(originId)) {
|
||||
val forkedId2 =
|
||||
forkedRepository.tags.collectFirst { case x if x.name == forkedId => x.commitId }.getOrElse(forkedId)
|
||||
|
||||
val originId2 = JGitUtil.getForkedCommitId(
|
||||
oldGit,
|
||||
newGit,
|
||||
originRepository.owner,
|
||||
originRepository.name,
|
||||
originId,
|
||||
forkedRepository.owner,
|
||||
forkedRepository.name,
|
||||
forkedId2
|
||||
)
|
||||
val originId2 = JGitUtil.getForkedCommitId(
|
||||
oldGit,
|
||||
newGit,
|
||||
originRepository.owner,
|
||||
originRepository.name,
|
||||
originId,
|
||||
forkedRepository.owner,
|
||||
forkedRepository.name,
|
||||
forkedId2
|
||||
)
|
||||
|
||||
(Option(oldGit.getRepository.resolve(originId2)), Option(newGit.getRepository.resolve(forkedId2)))
|
||||
(Option(oldGit.getRepository.resolve(originId2)), Option(newGit.getRepository.resolve(forkedId2)))
|
||||
|
||||
} else {
|
||||
val originId2 =
|
||||
originRepository.tags.collectFirst { case x if x.name == originId => x.commitId }.getOrElse(originId)
|
||||
val forkedId2 =
|
||||
forkedRepository.tags.collectFirst { case x if x.name == forkedId => x.commitId }.getOrElse(forkedId)
|
||||
} else {
|
||||
val originId2 =
|
||||
originRepository.tags.collectFirst { case x if x.name == originId => x.commitId }.getOrElse(originId)
|
||||
val forkedId2 =
|
||||
forkedRepository.tags.collectFirst { case x if x.name == forkedId => x.commitId }.getOrElse(forkedId)
|
||||
|
||||
(Option(oldGit.getRepository.resolve(originId2)), Option(newGit.getRepository.resolve(forkedId2)))
|
||||
}
|
||||
(Option(oldGit.getRepository.resolve(originId2)), Option(newGit.getRepository.resolve(forkedId2)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -661,8 +650,8 @@ object PullRequestService {
|
||||
val statuses: List[CommitStatus] =
|
||||
commitStatuses ++ (branchProtection.contexts.toSet -- commitStatuses.map(_.context).toSet)
|
||||
.map(CommitStatus.pending(branchProtection.owner, branchProtection.repository, _))
|
||||
val hasRequiredStatusProblem = needStatusCheck && branchProtection.contexts.exists(
|
||||
context => statuses.find(_.context == context).map(_.state) != Some(CommitState.SUCCESS)
|
||||
val hasRequiredStatusProblem = needStatusCheck && branchProtection.contexts.exists(context =>
|
||||
statuses.find(_.context == context).map(_.state) != Some(CommitState.SUCCESS)
|
||||
)
|
||||
val hasProblem = hasRequiredStatusProblem || hasConflict || (statuses.nonEmpty && CommitState.combine(
|
||||
statuses.map(_.state).toSet
|
||||
|
||||
@@ -36,14 +36,14 @@ trait ReleaseService {
|
||||
ReleaseAssets.filter(x => x.byTag(owner, repository, tag)).list
|
||||
}
|
||||
|
||||
def getReleaseAssetsMap(owner: String, repository: String, releases: Seq[ReleaseTag])(
|
||||
implicit s: Session
|
||||
def getReleaseAssetsMap(owner: String, repository: String, releases: Seq[ReleaseTag])(implicit
|
||||
s: Session
|
||||
): Map[ReleaseTag, Seq[ReleaseAsset]] = {
|
||||
releases.map(rel => (rel -> getReleaseAssets(owner, repository, rel.tag))).toMap
|
||||
}
|
||||
|
||||
def getReleaseAsset(owner: String, repository: String, tag: String, fileId: String)(
|
||||
implicit s: Session
|
||||
def getReleaseAsset(owner: String, repository: String, tag: String, fileId: String)(implicit
|
||||
s: Session
|
||||
): Option[ReleaseAsset] = {
|
||||
ReleaseAssets.filter(x => x.byPrimaryKey(owner, repository, tag, fileId)) firstOption
|
||||
}
|
||||
@@ -76,8 +76,8 @@ trait ReleaseService {
|
||||
ReleaseTags.filter(x => x.byRepository(owner, repository)).sortBy(x => x.updatedDate).list
|
||||
}
|
||||
|
||||
def getReleases(owner: String, repository: String, tags: Seq[JGitUtil.TagInfo])(
|
||||
implicit s: Session
|
||||
def getReleases(owner: String, repository: String, tags: Seq[JGitUtil.TagInfo])(implicit
|
||||
s: Session
|
||||
): Seq[ReleaseTag] = {
|
||||
ReleaseTags
|
||||
.filter(x => x.byRepository(owner, repository))
|
||||
@@ -89,8 +89,8 @@ trait ReleaseService {
|
||||
ReleaseTags.filter(_.byTag(owner, repository, tag)).firstOption
|
||||
}
|
||||
|
||||
def updateRelease(owner: String, repository: String, tag: String, title: String, content: Option[String])(
|
||||
implicit s: Session
|
||||
def updateRelease(owner: String, repository: String, tag: String, title: String, content: Option[String])(implicit
|
||||
s: Session
|
||||
): Int = {
|
||||
ReleaseTags
|
||||
.filter(_.byPrimaryKey(owner, repository, tag))
|
||||
|
||||
@@ -65,7 +65,8 @@ trait RepositoryCommitFileService {
|
||||
path,
|
||||
newFileName,
|
||||
oldFileName,
|
||||
if (content.nonEmpty) { content.getBytes(charset) } else { Array.emptyByteArray },
|
||||
if (content.nonEmpty) { content.getBytes(charset) }
|
||||
else { Array.emptyByteArray },
|
||||
message,
|
||||
commit,
|
||||
loginAccount,
|
||||
|
||||
@@ -92,7 +92,7 @@ trait RepositoryCreationService {
|
||||
RepositoryCreationService.startCreation(owner, name)
|
||||
try {
|
||||
Database() withTransaction { implicit session =>
|
||||
//val ownerAccount = getAccountByUserName(owner).get
|
||||
// val ownerAccount = getAccountByUserName(owner).get
|
||||
val loginUserName = loginAccount.userName
|
||||
|
||||
val copyRepositoryDir = if (initOption == "COPY") {
|
||||
@@ -214,9 +214,8 @@ trait RepositoryCreationService {
|
||||
// Set default collaborators for the private fork
|
||||
if (repository.repository.isPrivate) {
|
||||
// Copy collaborators from the source repository
|
||||
getCollaborators(repository.owner, repository.name).foreach {
|
||||
case (collaborator, _) =>
|
||||
addCollaborator(accountName, repository.name, collaborator.collaboratorName, collaborator.role)
|
||||
getCollaborators(repository.owner, repository.name).foreach { case (collaborator, _) =>
|
||||
addCollaborator(accountName, repository.name, collaborator.collaboratorName, collaborator.role)
|
||||
}
|
||||
// Register an owner of the source repository as a collaborator
|
||||
addCollaborator(accountName, repository.name, repository.owner, Role.ADMIN.name)
|
||||
|
||||
@@ -14,26 +14,25 @@ import scala.util.Using
|
||||
trait RepositorySearchService { self: IssuesService =>
|
||||
import RepositorySearchService._
|
||||
|
||||
def countIssues(owner: String, repository: String, query: String, pullRequest: Boolean)(
|
||||
implicit session: Session
|
||||
def countIssues(owner: String, repository: String, query: String, pullRequest: Boolean)(implicit
|
||||
session: Session
|
||||
): Int =
|
||||
searchIssuesByKeyword(owner, repository, query, pullRequest).length
|
||||
|
||||
def searchIssues(owner: String, repository: String, query: String, pullRequest: Boolean)(
|
||||
implicit session: Session
|
||||
def searchIssues(owner: String, repository: String, query: String, pullRequest: Boolean)(implicit
|
||||
session: Session
|
||||
): List[IssueSearchResult] =
|
||||
searchIssuesByKeyword(owner, repository, query, pullRequest).map {
|
||||
case (issue, commentCount, content) =>
|
||||
IssueSearchResult(
|
||||
issue.issueId,
|
||||
issue.isPullRequest,
|
||||
issue.title,
|
||||
issue.closed,
|
||||
issue.openedUserName,
|
||||
issue.registeredDate,
|
||||
commentCount,
|
||||
getHighlightText(content, query)._1
|
||||
)
|
||||
searchIssuesByKeyword(owner, repository, query, pullRequest).map { case (issue, commentCount, content) =>
|
||||
IssueSearchResult(
|
||||
issue.issueId,
|
||||
issue.isPullRequest,
|
||||
issue.title,
|
||||
issue.closed,
|
||||
issue.openedUserName,
|
||||
issue.registeredDate,
|
||||
commentCount,
|
||||
getHighlightText(content, query)._1
|
||||
)
|
||||
}
|
||||
|
||||
def countFiles(owner: String, repository: String, query: String): Int =
|
||||
@@ -48,10 +47,9 @@ trait RepositorySearchService { self: IssuesService =>
|
||||
} else {
|
||||
val files = searchRepositoryFiles(git, query)
|
||||
val commits = JGitUtil.getLatestCommitFromPaths(git, files.map(_._1), "HEAD")
|
||||
files.map {
|
||||
case (path, text) =>
|
||||
val (highlightText, lineNumber) = getHighlightText(text, query)
|
||||
FileSearchResult(path, commits(path).getCommitterIdent.getWhen, highlightText, lineNumber)
|
||||
files.map { case (path, text) =>
|
||||
val (highlightText, lineNumber) = getHighlightText(text, query)
|
||||
FileSearchResult(path, commits(path).getCommitterIdent.getWhen, highlightText, lineNumber)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -68,15 +66,14 @@ trait RepositorySearchService { self: IssuesService =>
|
||||
} else {
|
||||
val files = searchRepositoryFiles(git, query)
|
||||
val commits = JGitUtil.getLatestCommitFromPaths(git, files.map(_._1), "HEAD")
|
||||
files.map {
|
||||
case (path, text) =>
|
||||
val (highlightText, lineNumber) = getHighlightText(text, query)
|
||||
FileSearchResult(
|
||||
path.stripSuffix(".md"),
|
||||
commits(path).getCommitterIdent.getWhen,
|
||||
highlightText,
|
||||
lineNumber
|
||||
)
|
||||
files.map { case (path, text) =>
|
||||
val (highlightText, lineNumber) = getHighlightText(text, query)
|
||||
FileSearchResult(
|
||||
path.stripSuffix(".md"),
|
||||
commits(path).getCommitterIdent.getWhen,
|
||||
highlightText,
|
||||
lineNumber
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,12 +187,11 @@ trait RepositoryService {
|
||||
val newLabelMap =
|
||||
Labels.filter(_.byRepository(newUserName, newRepositoryName)).map(x => (x.labelName, x.labelId)).list.toMap
|
||||
IssueLabels.insertAll(
|
||||
issueLabels.map(
|
||||
x =>
|
||||
x.copy(
|
||||
labelId = newLabelMap(oldLabelMap(x.labelId)),
|
||||
userName = newUserName,
|
||||
repositoryName = newRepositoryName
|
||||
issueLabels.map(x =>
|
||||
x.copy(
|
||||
labelId = newLabelMap(oldLabelMap(x.labelId)),
|
||||
userName = newUserName,
|
||||
repositoryName = newRepositoryName
|
||||
)
|
||||
): _*
|
||||
)
|
||||
@@ -275,12 +274,11 @@ trait RepositoryService {
|
||||
(x.userName, x.repositoryName)
|
||||
}
|
||||
.list
|
||||
.foreach {
|
||||
case (userName, repositoryName) =>
|
||||
Repositories
|
||||
.filter(_.byRepository(userName, repositoryName))
|
||||
.map(x => (x.originUserName ?, x.originRepositoryName ?))
|
||||
.update(None, None)
|
||||
.foreach { case (userName, repositoryName) =>
|
||||
Repositories
|
||||
.filter(_.byRepository(userName, repositoryName))
|
||||
.map(x => (x.originUserName ?, x.originRepositoryName ?))
|
||||
.update(None, None)
|
||||
}
|
||||
|
||||
// Update PARENT_USER_NAME and PARENT_REPOSITORY_NAME
|
||||
@@ -292,12 +290,11 @@ trait RepositoryService {
|
||||
(x.userName, x.repositoryName)
|
||||
}
|
||||
.list
|
||||
.foreach {
|
||||
case (userName, repositoryName) =>
|
||||
Repositories
|
||||
.filter(_.byRepository(userName, repositoryName))
|
||||
.map(x => (x.parentUserName ?, x.parentRepositoryName ?))
|
||||
.update(None, None)
|
||||
.foreach { case (userName, repositoryName) =>
|
||||
Repositories
|
||||
.filter(_.byRepository(userName, repositoryName))
|
||||
.map(x => (x.parentUserName ?, x.parentRepositoryName ?))
|
||||
.update(None, None)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,31 +318,29 @@ trait RepositoryService {
|
||||
(Repositories
|
||||
.join(Accounts)
|
||||
.on(_.userName === _.userName)
|
||||
.filter {
|
||||
case (t1, t2) =>
|
||||
t1.byRepository(userName, repositoryName) && t2.removed === false.bind
|
||||
} firstOption) map {
|
||||
case (repository, account) =>
|
||||
// for getting issue count and pull request count
|
||||
val issues = Issues
|
||||
.filter { t =>
|
||||
t.byRepository(repository.userName, repository.repositoryName) && (t.closed === false.bind)
|
||||
}
|
||||
.map(_.pullRequest)
|
||||
.list
|
||||
.filter { case (t1, t2) =>
|
||||
t1.byRepository(userName, repositoryName) && t2.removed === false.bind
|
||||
} firstOption) map { case (repository, account) =>
|
||||
// for getting issue count and pull request count
|
||||
val issues = Issues
|
||||
.filter { t =>
|
||||
t.byRepository(repository.userName, repository.repositoryName) && (t.closed === false.bind)
|
||||
}
|
||||
.map(_.pullRequest)
|
||||
.list
|
||||
|
||||
new RepositoryInfo(
|
||||
JGitUtil.getRepositoryInfo(repository.userName, repository.repositoryName),
|
||||
repository,
|
||||
issues.count(_ == false),
|
||||
issues.count(_ == true),
|
||||
getForkedCount(
|
||||
repository.originUserName.getOrElse(repository.userName),
|
||||
repository.originRepositoryName.getOrElse(repository.repositoryName)
|
||||
),
|
||||
getOpenMilestones(repository.userName, repository.repositoryName),
|
||||
getRepositoryManagers(repository.userName, repository.repositoryName)
|
||||
)
|
||||
new RepositoryInfo(
|
||||
JGitUtil.getRepositoryInfo(repository.userName, repository.repositoryName),
|
||||
repository,
|
||||
issues.count(_ == false),
|
||||
issues.count(_ == true),
|
||||
getForkedCount(
|
||||
repository.originUserName.getOrElse(repository.userName),
|
||||
repository.originRepositoryName.getOrElse(repository.repositoryName)
|
||||
),
|
||||
getOpenMilestones(repository.userName, repository.repositoryName),
|
||||
getRepositoryManagers(repository.userName, repository.repositoryName)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -396,8 +391,8 @@ trait RepositoryService {
|
||||
* Returns the list of repositories which are owned by the specified user.
|
||||
* This list includes group repositories if the specified user is a member of the group.
|
||||
*/
|
||||
def getUserRepositories(userName: String, withoutPhysicalInfo: Boolean = false)(
|
||||
implicit s: Session
|
||||
def getUserRepositories(userName: String, withoutPhysicalInfo: Boolean = false)(implicit
|
||||
s: Session
|
||||
): List[RepositoryInfo] = {
|
||||
Repositories
|
||||
.filter { t1 =>
|
||||
@@ -464,15 +459,14 @@ trait RepositoryService {
|
||||
Repositories
|
||||
.join(Accounts)
|
||||
.on(_.userName === _.userName)
|
||||
.filter {
|
||||
case (t1, t2) =>
|
||||
(t2.removed === false.bind) && ((t1.isPrivate === false.bind && !limit.bind) || (t1.userName === x.userName) ||
|
||||
(t1.userName in GroupMembers.filter(_.userName === x.userName.bind).map(_.groupName)) ||
|
||||
(Collaborators.filter { t3 =>
|
||||
t3.byRepository(t1.userName, t1.repositoryName) &&
|
||||
((t3.collaboratorName === x.userName.bind) ||
|
||||
.filter { case (t1, t2) =>
|
||||
(t2.removed === false.bind) && ((t1.isPrivate === false.bind && !limit.bind) || (t1.userName === x.userName) ||
|
||||
(t1.userName in GroupMembers.filter(_.userName === x.userName.bind).map(_.groupName)) ||
|
||||
(Collaborators.filter { t3 =>
|
||||
t3.byRepository(t1.userName, t1.repositoryName) &&
|
||||
((t3.collaboratorName === x.userName.bind) ||
|
||||
(t3.collaboratorName in GroupMembers.filter(_.userName === x.userName.bind).map(_.groupName)))
|
||||
} exists))
|
||||
} exists))
|
||||
}
|
||||
.map { case (t1, t2) => t1 }
|
||||
// for Guests
|
||||
@@ -483,17 +477,16 @@ trait RepositoryService {
|
||||
.filter { case (t1, t2) => t1.isPrivate === false.bind && t2.removed === false.bind }
|
||||
.map { case (t1, t2) => t1 }
|
||||
}).filter { t =>
|
||||
repositoryUserName.map { userName =>
|
||||
t.userName === userName.bind
|
||||
} getOrElse LiteralColumn(true)
|
||||
}
|
||||
.sortBy(_.lastActivityDate desc)
|
||||
repositoryUserName.map { userName =>
|
||||
t.userName === userName.bind
|
||||
} getOrElse LiteralColumn(true)
|
||||
}.sortBy(_.lastActivityDate desc)
|
||||
.list
|
||||
.map(createRepositoryInfo(_, withoutPhysicalInfo))
|
||||
}
|
||||
|
||||
private def createRepositoryInfo(repository: Repository, withoutPhysicalInfo: Boolean = false)(
|
||||
implicit s: Session
|
||||
private def createRepositoryInfo(repository: Repository, withoutPhysicalInfo: Boolean = false)(implicit
|
||||
s: Session
|
||||
): RepositoryInfo = {
|
||||
new RepositoryInfo(
|
||||
if (withoutPhysicalInfo) {
|
||||
@@ -586,8 +579,8 @@ trait RepositoryService {
|
||||
)
|
||||
}
|
||||
|
||||
def saveRepositoryDefaultBranch(userName: String, repositoryName: String, defaultBranch: String)(
|
||||
implicit s: Session
|
||||
def saveRepositoryDefaultBranch(userName: String, repositoryName: String, defaultBranch: String)(implicit
|
||||
s: Session
|
||||
): Unit =
|
||||
Repositories
|
||||
.filter(_.byRepository(userName, repositoryName))
|
||||
@@ -599,16 +592,16 @@ trait RepositoryService {
|
||||
/**
|
||||
* Add collaborator (user or group) to the repository.
|
||||
*/
|
||||
def addCollaborator(userName: String, repositoryName: String, collaboratorName: String, role: String)(
|
||||
implicit s: Session
|
||||
def addCollaborator(userName: String, repositoryName: String, collaboratorName: String, role: String)(implicit
|
||||
s: Session
|
||||
): Unit =
|
||||
Collaborators insert Collaborator(userName, repositoryName, collaboratorName, role)
|
||||
|
||||
/**
|
||||
* Remove specified collaborator from the repository.
|
||||
*/
|
||||
def removeCollaborator(userName: String, repositoryName: String, collaboratorName: String)(
|
||||
implicit s: Session
|
||||
def removeCollaborator(userName: String, repositoryName: String, collaboratorName: String)(implicit
|
||||
s: Session
|
||||
): Unit =
|
||||
Collaborators.filter(_.byPrimaryKey(userName, repositoryName, collaboratorName)).delete
|
||||
|
||||
@@ -634,8 +627,8 @@ trait RepositoryService {
|
||||
* Returns the list of all collaborator name and permission which is sorted with ascending order.
|
||||
* If a group is added as a collaborator, this method returns users who are belong to that group.
|
||||
*/
|
||||
def getCollaboratorUserNames(userName: String, repositoryName: String, filter: Seq[Role] = Nil)(
|
||||
implicit s: Session
|
||||
def getCollaboratorUserNames(userName: String, repositoryName: String, filter: Seq[Role] = Nil)(implicit
|
||||
s: Session
|
||||
): List[String] = {
|
||||
val q1 = Collaborators
|
||||
.join(Accounts)
|
||||
@@ -669,8 +662,8 @@ trait RepositoryService {
|
||||
}
|
||||
}
|
||||
|
||||
def hasDeveloperRole(owner: String, repository: String, loginAccount: Option[Account])(
|
||||
implicit s: Session
|
||||
def hasDeveloperRole(owner: String, repository: String, loginAccount: Option[Account])(implicit
|
||||
s: Session
|
||||
): Boolean = {
|
||||
loginAccount match {
|
||||
case Some(a) if (a.isAdmin) => true
|
||||
@@ -731,7 +724,7 @@ trait RepositoryService {
|
||||
(t.originUserName === userName.bind) && (t.originRepositoryName === repositoryName.bind)
|
||||
}
|
||||
.sortBy(_.userName asc)
|
||||
.list //.map(t => t.userName -> t.repositoryName).list
|
||||
.list // .map(t => t.userName -> t.repositoryName).list
|
||||
|
||||
private val templateExtensions = Seq("md", "markdown")
|
||||
|
||||
|
||||
@@ -25,8 +25,8 @@ trait RequestCache
|
||||
private implicit def context2Session(implicit context: Context): Session =
|
||||
request2Session(context.request)
|
||||
|
||||
def getIssueFromCache(userName: String, repositoryName: String, issueId: String)(
|
||||
implicit context: Context
|
||||
def getIssueFromCache(userName: String, repositoryName: String, issueId: String)(implicit
|
||||
context: Context
|
||||
): Option[Issue] = {
|
||||
context.cache(s"issue.${userName}/${repositoryName}#${issueId}") {
|
||||
super.getIssue(userName, repositoryName, issueId)
|
||||
@@ -45,19 +45,18 @@ trait RequestCache
|
||||
}
|
||||
}
|
||||
|
||||
def getRepositoryInfoFromCache(userName: String, repositoryName: String)(
|
||||
implicit context: Context
|
||||
def getRepositoryInfoFromCache(userName: String, repositoryName: String)(implicit
|
||||
context: Context
|
||||
): Option[Repository] = {
|
||||
context.cache(s"repository.${userName}/${repositoryName}") {
|
||||
Repositories
|
||||
.join(Accounts)
|
||||
.on(_.userName === _.userName)
|
||||
.filter {
|
||||
case (t1, t2) =>
|
||||
t1.byRepository(userName, repositoryName) && t2.removed === false.bind
|
||||
.filter { case (t1, t2) =>
|
||||
t1.byRepository(userName, repositoryName) && t2.removed === false.bind
|
||||
}
|
||||
.map {
|
||||
case (t1, t2) => t1
|
||||
.map { case (t1, t2) =>
|
||||
t1
|
||||
}
|
||||
.firstOption
|
||||
}
|
||||
|
||||
@@ -45,8 +45,8 @@ trait WebHookService {
|
||||
private val logger = LoggerFactory.getLogger(classOf[WebHookService])
|
||||
|
||||
/** get All WebHook informations of repository */
|
||||
def getWebHooks(owner: String, repository: String)(
|
||||
implicit s: Session
|
||||
def getWebHooks(owner: String, repository: String)(implicit
|
||||
s: Session
|
||||
): List[(RepositoryWebHook, Set[WebHook.Event])] =
|
||||
RepositoryWebHooks
|
||||
.filter(_.byRepository(owner, repository))
|
||||
@@ -63,8 +63,8 @@ trait WebHookService {
|
||||
.sortBy(_._1.url)
|
||||
|
||||
/** get All WebHook informations of repository event */
|
||||
def getWebHooksByEvent(owner: String, repository: String, event: WebHook.Event)(
|
||||
implicit s: Session
|
||||
def getWebHooksByEvent(owner: String, repository: String, event: WebHook.Event)(implicit
|
||||
s: Session
|
||||
): List[RepositoryWebHook] =
|
||||
RepositoryWebHooks
|
||||
.filter(_.byRepository(owner, repository))
|
||||
@@ -78,8 +78,8 @@ trait WebHookService {
|
||||
.distinct
|
||||
|
||||
/** get All WebHook information from repository to url */
|
||||
def getWebHook(owner: String, repository: String, url: String)(
|
||||
implicit s: Session
|
||||
def getWebHook(owner: String, repository: String, url: String)(implicit
|
||||
s: Session
|
||||
): Option[(RepositoryWebHook, Set[WebHook.Event])] =
|
||||
RepositoryWebHooks
|
||||
.filter(_.byRepositoryUrl(owner, repository, url))
|
||||
@@ -95,8 +95,8 @@ trait WebHookService {
|
||||
.headOption
|
||||
|
||||
/** get All WebHook informations of repository */
|
||||
def getWebHookById(id: Int)(
|
||||
implicit s: Session
|
||||
def getWebHookById(id: Int)(implicit
|
||||
s: Session
|
||||
): Option[(RepositoryWebHook, Set[WebHook.Event])] =
|
||||
RepositoryWebHooks
|
||||
.filter(_.byId(id))
|
||||
@@ -451,8 +451,8 @@ trait WebHookPullRequestService extends WebHookService {
|
||||
}
|
||||
|
||||
/** @return Map[(issue, issueUser, pullRequest, baseOwner, headOwner), webHooks] */
|
||||
def getPullRequestsByRequestForWebhook(userName: String, repositoryName: String, branch: String)(
|
||||
implicit s: Session
|
||||
def getPullRequestsByRequestForWebhook(userName: String, repositoryName: String, branch: String)(implicit
|
||||
s: Session
|
||||
): Map[(Issue, Account, PullRequest, Account, Account), List[RepositoryWebHook]] =
|
||||
(for {
|
||||
is <- Issues if is.closed === false.bind
|
||||
@@ -652,8 +652,8 @@ object WebHookService {
|
||||
) extends FieldSerializable
|
||||
with WebHookPayload {
|
||||
val compare = commits.size match {
|
||||
case 0 => ApiPath(s"/${repository.full_name}") // maybe test hook on un-initialized repository
|
||||
case 1 => ApiPath(s"/${repository.full_name}/commit/${after}")
|
||||
case 0 => ApiPath(s"/${repository.full_name}") // maybe test hook on un-initialized repository
|
||||
case 1 => ApiPath(s"/${repository.full_name}/commit/${after}")
|
||||
case _ if before.forall(_ == '0') => ApiPath(s"/${repository.full_name}/compare/${commits.head.id}^...${after}")
|
||||
case _ => ApiPath(s"/${repository.full_name}/compare/${before}...${after}")
|
||||
}
|
||||
@@ -878,15 +878,14 @@ object WebHookService {
|
||||
sender: Account
|
||||
): WebHookGollumPayload = {
|
||||
WebHookGollumPayload(
|
||||
pages = pages.map {
|
||||
case (action, pageName, sha) =>
|
||||
WebHookGollumPagePayload(
|
||||
action = action,
|
||||
page_name = pageName,
|
||||
title = pageName,
|
||||
sha = sha,
|
||||
html_url = ApiPath(s"/${RepositoryName(repository).fullName}/wiki/${StringUtil.urlDecode(pageName)}")
|
||||
)
|
||||
pages = pages.map { case (action, pageName, sha) =>
|
||||
WebHookGollumPagePayload(
|
||||
action = action,
|
||||
page_name = pageName,
|
||||
title = pageName,
|
||||
sha = sha,
|
||||
html_url = ApiPath(s"/${RepositoryName(repository).fullName}/wiki/${StringUtil.urlDecode(pageName)}")
|
||||
)
|
||||
},
|
||||
repository = ApiRepository(repository, repositoryUser),
|
||||
sender = ApiUser(sender)
|
||||
|
||||
@@ -20,8 +20,10 @@ abstract class ControllerFilter extends Filter {
|
||||
requestPath + "/"
|
||||
}
|
||||
|
||||
if (!checkPath.startsWith("/upload/") && !checkPath.startsWith("/git/") && !checkPath.startsWith("/git-lfs/") &&
|
||||
!checkPath.startsWith("/assets/") && !checkPath.startsWith("/plugin-assets/")) {
|
||||
if (
|
||||
!checkPath.startsWith("/upload/") && !checkPath.startsWith("/git/") && !checkPath.startsWith("/git-lfs/") &&
|
||||
!checkPath.startsWith("/assets/") && !checkPath.startsWith("/plugin-assets/")
|
||||
) {
|
||||
val continue = process(request, response, checkPath)
|
||||
if (!continue) {
|
||||
return ()
|
||||
@@ -41,33 +43,29 @@ class CompositeScalatraFilter extends ControllerFilter {
|
||||
}
|
||||
|
||||
override def init(filterConfig: FilterConfig): Unit = {
|
||||
filters.foreach {
|
||||
case (filter, _) =>
|
||||
filter.init(filterConfig)
|
||||
filters.foreach { case (filter, _) =>
|
||||
filter.init(filterConfig)
|
||||
}
|
||||
}
|
||||
|
||||
override def destroy(): Unit = {
|
||||
filters.foreach {
|
||||
case (filter, _) =>
|
||||
filter.destroy()
|
||||
filters.foreach { case (filter, _) =>
|
||||
filter.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
override def process(request: ServletRequest, response: ServletResponse, checkPath: String): Boolean = {
|
||||
filters
|
||||
.filter {
|
||||
case (_, path) =>
|
||||
val start = path.replaceFirst("/\\*$", "/")
|
||||
checkPath.startsWith(start)
|
||||
.filter { case (_, path) =>
|
||||
val start = path.replaceFirst("/\\*$", "/")
|
||||
checkPath.startsWith(start)
|
||||
}
|
||||
.foreach {
|
||||
case (filter, _) =>
|
||||
val mockChain = new MockFilterChain()
|
||||
filter.doFilter(request, response, mockChain)
|
||||
if (mockChain.continue == false) {
|
||||
return false
|
||||
}
|
||||
.foreach { case (filter, _) =>
|
||||
val mockChain = new MockFilterChain()
|
||||
filter.doFilter(request, response, mockChain)
|
||||
if (mockChain.continue == false) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
|
||||
@@ -43,10 +43,9 @@ class GitAuthenticationFilter extends Filter with RepositoryService with Account
|
||||
try {
|
||||
PluginRegistry()
|
||||
.getRepositoryRouting(request.gitRepositoryPath)
|
||||
.map {
|
||||
case GitRepositoryRouting(_, _, filter) =>
|
||||
// served by plug-ins
|
||||
pluginRepository(request, wrappedResponse, chain, settings, isUpdating, filter)
|
||||
.map { case GitRepositoryRouting(_, _, filter) =>
|
||||
// served by plug-ins
|
||||
pluginRepository(request, wrappedResponse, chain, settings, isUpdating, filter)
|
||||
|
||||
}
|
||||
.getOrElse {
|
||||
@@ -130,19 +129,17 @@ class GitAuthenticationFilter extends Filter with RepositoryService with Account
|
||||
}
|
||||
}
|
||||
case None =>
|
||||
() =>
|
||||
{
|
||||
logger.debug(s"Repository ${repositoryOwner}/${repositoryName} is not found.")
|
||||
response.sendError(HttpServletResponse.SC_NOT_FOUND)
|
||||
}
|
||||
() => {
|
||||
logger.debug(s"Repository ${repositoryOwner}/${repositoryName} is not found.")
|
||||
response.sendError(HttpServletResponse.SC_NOT_FOUND)
|
||||
}
|
||||
}
|
||||
}
|
||||
case _ =>
|
||||
() =>
|
||||
{
|
||||
logger.debug(s"Not enough path arguments: ${request.paths.mkString(", ")}")
|
||||
response.sendError(HttpServletResponse.SC_NOT_FOUND)
|
||||
}
|
||||
() => {
|
||||
logger.debug(s"Not enough path arguments: ${request.paths.mkString(", ")}")
|
||||
response.sendError(HttpServletResponse.SC_NOT_FOUND)
|
||||
}
|
||||
}
|
||||
|
||||
action()
|
||||
@@ -159,8 +156,8 @@ class GitAuthenticationFilter extends Filter with RepositoryService with Account
|
||||
* @param s database session
|
||||
* @return an account or none
|
||||
*/
|
||||
private def authenticateByHeader(authorizationHeader: String, settings: SystemSettings)(
|
||||
implicit s: Session
|
||||
private def authenticateByHeader(authorizationHeader: String, settings: SystemSettings)(implicit
|
||||
s: Session
|
||||
): Option[Account] = {
|
||||
val Array(username, password) = AuthUtil.decodeAuthHeader(authorizationHeader).split(":", 2)
|
||||
authenticate(settings, username, password).orElse {
|
||||
|
||||
@@ -171,10 +171,9 @@ class GitBucketRepositoryResolver extends RepositoryResolver[HttpServletRequest]
|
||||
// Rewrite repository path if routing is marched
|
||||
PluginRegistry()
|
||||
.getRepositoryRouting("/" + name)
|
||||
.map {
|
||||
case GitRepositoryRouting(urlPattern, localPath, _) =>
|
||||
val path = urlPattern.r.replaceFirstIn(name, localPath)
|
||||
new FileRepository(new File(Directory.GitBucketHome, path))
|
||||
.map { case GitRepositoryRouting(urlPattern, localPath, _) =>
|
||||
val path = urlPattern.r.replaceFirstIn(name, localPath)
|
||||
new FileRepository(new File(Directory.GitBucketHome, path))
|
||||
}
|
||||
.getOrElse {
|
||||
new FileRepository(new File(Directory.RepositoryHome, name))
|
||||
@@ -341,7 +340,11 @@ class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl:
|
||||
pushedIds.add(commit.id)
|
||||
createIssueComment(owner, repository, commit)
|
||||
// close issues
|
||||
if (refName(1) == "heads" && branchName == defaultBranch && command.getType == ReceiveCommand.Type.UPDATE) {
|
||||
if (
|
||||
refName(
|
||||
1
|
||||
) == "heads" && branchName == defaultBranch && command.getType == ReceiveCommand.Type.UPDATE
|
||||
) {
|
||||
getAccountByUserName(pusher).foreach { pusherAccount =>
|
||||
closeIssuesFromMessage(commit.fullMessage, pusher, owner, repository).foreach { issueId =>
|
||||
getIssue(owner, repository, issueId.toString).foreach { issue =>
|
||||
@@ -362,9 +365,11 @@ class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl:
|
||||
// set PR as merged
|
||||
val pulls = getPullRequestsByBranch(owner, repository, branchName, Some(false))
|
||||
pulls.foreach { pull =>
|
||||
if (commits.exists { c =>
|
||||
c.id == pull.commitIdTo
|
||||
}) {
|
||||
if (
|
||||
commits.exists { c =>
|
||||
c.id == pull.commitIdTo
|
||||
}
|
||||
) {
|
||||
markMergeAndClosePullRequest(pusher, owner, repository, pull)
|
||||
getAccountByUserName(pusher).foreach { pusherAccount =>
|
||||
callPullRequestWebHook("closed", repositoryInfo, pull.issueId, pusherAccount, settings)
|
||||
@@ -490,40 +495,38 @@ class WikiCommitHook(owner: String, repository: String, pusher: String, baseUrl:
|
||||
}
|
||||
}
|
||||
|
||||
commitIds.foreach {
|
||||
case (oldCommitId, newCommitId) =>
|
||||
val commits = Using.resource(Git.open(Directory.getWikiRepositoryDir(owner, repository))) { git =>
|
||||
JGitUtil.getCommitLog(git, oldCommitId, newCommitId).flatMap { commit =>
|
||||
val diffs = JGitUtil.getDiffs(git, None, commit.id, false, false)
|
||||
diffs.collect {
|
||||
case diff if diff.newPath.toLowerCase.endsWith(".md") =>
|
||||
val action = mapToAction(diff.changeType)
|
||||
val fileName = diff.newPath
|
||||
updateLastActivityDate(owner, repository)
|
||||
buildWikiRecord(action, owner, repository, commit, fileName).foreach(recordActivity)
|
||||
(action, fileName, commit.id)
|
||||
}
|
||||
commitIds.foreach { case (oldCommitId, newCommitId) =>
|
||||
val commits = Using.resource(Git.open(Directory.getWikiRepositoryDir(owner, repository))) { git =>
|
||||
JGitUtil.getCommitLog(git, oldCommitId, newCommitId).flatMap { commit =>
|
||||
val diffs = JGitUtil.getDiffs(git, None, commit.id, false, false)
|
||||
diffs.collect {
|
||||
case diff if diff.newPath.toLowerCase.endsWith(".md") =>
|
||||
val action = mapToAction(diff.changeType)
|
||||
val fileName = diff.newPath
|
||||
updateLastActivityDate(owner, repository)
|
||||
buildWikiRecord(action, owner, repository, commit, fileName).foreach(recordActivity)
|
||||
(action, fileName, commit.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val pages = commits
|
||||
.groupBy { case (_, fileName, _) => fileName }
|
||||
.map {
|
||||
case (fileName, commits) =>
|
||||
val (commitHeadAction, _, _) = commits.head
|
||||
val (_, _, commitLastId) = commits.last
|
||||
(commitHeadAction, fileName, commitLastId)
|
||||
}
|
||||
|
||||
callWebHookOf(owner, repository, WebHook.Gollum, settings) {
|
||||
for {
|
||||
pusherAccount <- getAccountByUserName(pusher)
|
||||
repositoryUser <- getAccountByUserName(owner)
|
||||
repositoryInfo <- getRepository(owner, repository)
|
||||
} yield {
|
||||
WebHookGollumPayload(pages.toSeq, repositoryInfo, repositoryUser, pusherAccount)
|
||||
}
|
||||
val pages = commits
|
||||
.groupBy { case (_, fileName, _) => fileName }
|
||||
.map { case (fileName, commits) =>
|
||||
val (commitHeadAction, _, _) = commits.head
|
||||
val (_, _, commitLastId) = commits.last
|
||||
(commitHeadAction, fileName, commitLastId)
|
||||
}
|
||||
|
||||
callWebHookOf(owner, repository, WebHook.Gollum, settings) {
|
||||
for {
|
||||
pusherAccount <- getAccountByUserName(pusher)
|
||||
repositoryUser <- getAccountByUserName(owner)
|
||||
repositoryInfo <- getRepository(owner, repository)
|
||||
} yield {
|
||||
WebHookGollumPayload(pages.toSeq, repositoryInfo, repositoryUser, pusherAccount)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
|
||||
@@ -153,8 +153,8 @@ class InitializeListener extends ServletContextListener with SystemSettingsServi
|
||||
logger.info(s"Extract to ${file.getAbsolutePath}")
|
||||
|
||||
FileUtils.forceMkdirParent(file)
|
||||
Using.resources(in, new FileOutputStream(file)) {
|
||||
case (in, out) => IOUtils.copy(in, out)
|
||||
Using.resources(in, new FileOutputStream(file)) { case (in, out) =>
|
||||
IOUtils.copy(in, out)
|
||||
}
|
||||
}
|
||||
case _ => ()
|
||||
|
||||
@@ -16,32 +16,31 @@ class PluginAssetsServlet extends HttpServlet {
|
||||
|
||||
assetsMappings
|
||||
.find { case (prefix, _, _) => path.startsWith("/plugin-assets" + prefix) }
|
||||
.foreach {
|
||||
case (prefix, resourcePath, classLoader) =>
|
||||
val ifNoneMatch = req.getHeader("If-None-Match")
|
||||
PluginRegistry.getPluginInfoFromClassLoader(classLoader).map { info =>
|
||||
val etag = s""""${info.pluginJar.lastModified}"""" // ETag must wrapped with double quote
|
||||
if (ifNoneMatch == etag) {
|
||||
resp.setStatus(304)
|
||||
} else {
|
||||
val resourceName = path.substring(("/plugin-assets" + prefix).length)
|
||||
Option(classLoader.getResourceAsStream(resourcePath.stripPrefix("/") + resourceName))
|
||||
.map { in =>
|
||||
try {
|
||||
val bytes = IOUtils.toByteArray(in)
|
||||
resp.setContentLength(bytes.length)
|
||||
resp.setContentType(FileUtil.getMimeType(path, bytes))
|
||||
resp.setHeader("ETag", etag)
|
||||
resp.getOutputStream.write(bytes)
|
||||
} finally {
|
||||
in.close()
|
||||
}
|
||||
.foreach { case (prefix, resourcePath, classLoader) =>
|
||||
val ifNoneMatch = req.getHeader("If-None-Match")
|
||||
PluginRegistry.getPluginInfoFromClassLoader(classLoader).map { info =>
|
||||
val etag = s""""${info.pluginJar.lastModified}"""" // ETag must wrapped with double quote
|
||||
if (ifNoneMatch == etag) {
|
||||
resp.setStatus(304)
|
||||
} else {
|
||||
val resourceName = path.substring(("/plugin-assets" + prefix).length)
|
||||
Option(classLoader.getResourceAsStream(resourcePath.stripPrefix("/") + resourceName))
|
||||
.map { in =>
|
||||
try {
|
||||
val bytes = IOUtils.toByteArray(in)
|
||||
resp.setContentLength(bytes.length)
|
||||
resp.setContentType(FileUtil.getMimeType(path, bytes))
|
||||
resp.setHeader("ETag", etag)
|
||||
resp.getOutputStream.write(bytes)
|
||||
} finally {
|
||||
in.close()
|
||||
}
|
||||
.getOrElse {
|
||||
resp.setStatus(404)
|
||||
}
|
||||
}
|
||||
}
|
||||
.getOrElse {
|
||||
resp.setStatus(404)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,32 +14,29 @@ class PluginControllerFilter extends ControllerFilter {
|
||||
}
|
||||
|
||||
override def destroy(): Unit = {
|
||||
PluginRegistry().getControllers().foreach {
|
||||
case (controller, _) =>
|
||||
controller.destroy()
|
||||
PluginRegistry().getControllers().foreach { case (controller, _) =>
|
||||
controller.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
override def process(request: ServletRequest, response: ServletResponse, checkPath: String): Boolean = {
|
||||
PluginRegistry()
|
||||
.getControllers()
|
||||
.filter {
|
||||
case (_, path) =>
|
||||
val start = path.replaceFirst("/\\*$", "/")
|
||||
checkPath.startsWith(start)
|
||||
.filter { case (_, path) =>
|
||||
val start = path.replaceFirst("/\\*$", "/")
|
||||
checkPath.startsWith(start)
|
||||
}
|
||||
.foreach {
|
||||
case (controller, _) =>
|
||||
controller match {
|
||||
case x: ControllerBase if (x.config == null) => x.init(filterConfig)
|
||||
case _ => ()
|
||||
}
|
||||
val mockChain = new MockFilterChain()
|
||||
controller.doFilter(request, response, mockChain)
|
||||
.foreach { case (controller, _) =>
|
||||
controller match {
|
||||
case x: ControllerBase if (x.config == null) => x.init(filterConfig)
|
||||
case _ => ()
|
||||
}
|
||||
val mockChain = new MockFilterChain()
|
||||
controller.doFilter(request, response, mockChain)
|
||||
|
||||
if (mockChain.continue == false) {
|
||||
return false
|
||||
}
|
||||
if (mockChain.continue == false) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
|
||||
@@ -101,8 +101,8 @@ abstract class DefaultGitCommand(val owner: String, val repoName: String) extend
|
||||
}
|
||||
}
|
||||
|
||||
protected def isReadableUser(authType: AuthType, repositoryInfo: RepositoryService.RepositoryInfo)(
|
||||
implicit session: Session
|
||||
protected def isReadableUser(authType: AuthType, repositoryInfo: RepositoryService.RepositoryInfo)(implicit
|
||||
session: Session
|
||||
): Boolean = {
|
||||
authType match {
|
||||
case AuthType.UserAuthType(username) => {
|
||||
@@ -120,8 +120,8 @@ abstract class DefaultGitCommand(val owner: String, val repoName: String) extend
|
||||
}
|
||||
}
|
||||
|
||||
protected def isWritableUser(authType: AuthType, repositoryInfo: RepositoryService.RepositoryInfo)(
|
||||
implicit session: Session
|
||||
protected def isWritableUser(authType: AuthType, repositoryInfo: RepositoryService.RepositoryInfo)(implicit
|
||||
session: Session
|
||||
): Boolean = {
|
||||
authType match {
|
||||
case AuthType.UserAuthType(username) => {
|
||||
|
||||
@@ -56,8 +56,8 @@ class PublicKeyAuthenticator(genericUser: String)
|
||||
}
|
||||
}
|
||||
|
||||
private def authenticateLoginUser(userName: String, key: PublicKey, session: ServerSession)(
|
||||
implicit s: Session
|
||||
private def authenticateLoginUser(userName: String, key: PublicKey, session: ServerSession)(implicit
|
||||
s: Session
|
||||
): Boolean = {
|
||||
val authenticated = getPublicKeys(userName).map(_.publicKey).flatMap(SshUtil.str2PublicKey).contains(key)
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ object DatabaseConfig {
|
||||
ConfigFactory.parseFile(file)
|
||||
}
|
||||
|
||||
private lazy val dbUrl = getValue("db.url", config.getString) //config.getString("db.url")
|
||||
private lazy val dbUrl = getValue("db.url", config.getString) // config.getString("db.url")
|
||||
|
||||
def url(directory: Option[String]): String = {
|
||||
val sb = new StringBuilder()
|
||||
|
||||
@@ -18,7 +18,7 @@ object Directory {
|
||||
case None => {
|
||||
val oldHome = new File(System.getProperty("user.home"), "gitbucket")
|
||||
if (oldHome.exists && oldHome.isDirectory && new File(oldHome, "version").exists) {
|
||||
//FileUtils.moveDirectory(oldHome, newHome)
|
||||
// FileUtils.moveDirectory(oldHome, newHome)
|
||||
oldHome
|
||||
} else {
|
||||
new File(System.getProperty("user.home"), ".gitbucket")
|
||||
|
||||
@@ -12,9 +12,8 @@ import org.bouncycastle.openpgp.operator.bc.BcPGPContentVerifierBuilderProvider
|
||||
object GpgUtil {
|
||||
def str2GpgKeyId(keyStr: String): Option[Long] = {
|
||||
val pubKeyOf = new BcPGPObjectFactory(new ArmoredInputStream(new ByteArrayInputStream(keyStr.getBytes)))
|
||||
pubKeyOf.iterator().asScala.collectFirst {
|
||||
case keyRing: PGPPublicKeyRing =>
|
||||
keyRing.getPublicKey().getKeyID
|
||||
pubKeyOf.iterator().asScala.collectFirst { case keyRing: PGPPublicKeyRing =>
|
||||
keyRing.getPublicKey().getKeyID
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,23 +36,22 @@ object GpgUtil {
|
||||
new BcPGPObjectFactory(new ArmoredInputStream(new ByteArrayInputStream(signInfo.signArmored)))
|
||||
.iterator()
|
||||
.asScala
|
||||
.flatMap {
|
||||
case signList: PGPSignatureList =>
|
||||
signList
|
||||
.iterator()
|
||||
.asScala
|
||||
.flatMap { sign =>
|
||||
getGpgKey(sign.getKeyID)
|
||||
.map { pubKey =>
|
||||
sign.init(new BcPGPContentVerifierBuilderProvider, pubKey)
|
||||
sign.update(signInfo.target)
|
||||
(sign, pubKey)
|
||||
}
|
||||
.collect {
|
||||
case (sign, pubKey) if sign.verify() =>
|
||||
JGitUtil.GpgVerifyInfo(pubKey.getUserIDs.next, pubKey.getKeyID.toHexString.toUpperCase)
|
||||
}
|
||||
}
|
||||
.flatMap { case signList: PGPSignatureList =>
|
||||
signList
|
||||
.iterator()
|
||||
.asScala
|
||||
.flatMap { sign =>
|
||||
getGpgKey(sign.getKeyID)
|
||||
.map { pubKey =>
|
||||
sign.init(new BcPGPContentVerifierBuilderProvider, pubKey)
|
||||
sign.update(signInfo.target)
|
||||
(sign, pubKey)
|
||||
}
|
||||
.collect {
|
||||
case (sign, pubKey) if sign.verify() =>
|
||||
JGitUtil.GpgVerifyInfo(pubKey.getUserIDs.next, pubKey.getKeyID.toHexString.toUpperCase)
|
||||
}
|
||||
}
|
||||
}
|
||||
.toList
|
||||
.headOption
|
||||
|
||||
@@ -54,12 +54,11 @@ object JDBCUtil {
|
||||
|
||||
private def execute[T](sql: String, params: Any*)(f: (PreparedStatement) => T): T = {
|
||||
Using.resource(conn.prepareStatement(sql)) { stmt =>
|
||||
params.zipWithIndex.foreach {
|
||||
case (p, i) =>
|
||||
p match {
|
||||
case x: Int => stmt.setInt(i + 1, x)
|
||||
case x: String => stmt.setString(i + 1, x)
|
||||
}
|
||||
params.zipWithIndex.foreach { case (p, i) =>
|
||||
p match {
|
||||
case x: Int => stmt.setInt(i + 1, x)
|
||||
case x: String => stmt.setString(i + 1, x)
|
||||
}
|
||||
}
|
||||
f(stmt)
|
||||
}
|
||||
@@ -136,19 +135,18 @@ object JDBCUtil {
|
||||
sb.append(columns.map(_._1).mkString(", "))
|
||||
sb.append(") VALUES (")
|
||||
|
||||
val values = columns.map {
|
||||
case (columnName, columnType) =>
|
||||
if (rs.getObject(columnName) == null) {
|
||||
null
|
||||
} else {
|
||||
columnType match {
|
||||
case Types.BOOLEAN | Types.BIT => rs.getBoolean(columnName)
|
||||
case Types.VARCHAR | Types.CLOB | Types.CHAR | Types.LONGVARCHAR => rs.getString(columnName)
|
||||
case Types.INTEGER => rs.getInt(columnName)
|
||||
case Types.BIGINT => rs.getLong(columnName)
|
||||
case Types.TIMESTAMP => rs.getTimestamp(columnName)
|
||||
}
|
||||
val values = columns.map { case (columnName, columnType) =>
|
||||
if (rs.getObject(columnName) == null) {
|
||||
null
|
||||
} else {
|
||||
columnType match {
|
||||
case Types.BOOLEAN | Types.BIT => rs.getBoolean(columnName)
|
||||
case Types.VARCHAR | Types.CLOB | Types.CHAR | Types.LONGVARCHAR => rs.getString(columnName)
|
||||
case Types.INTEGER => rs.getInt(columnName)
|
||||
case Types.BIGINT => rs.getLong(columnName)
|
||||
case Types.TIMESTAMP => rs.getTimestamp(columnName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val columnValues = values.map {
|
||||
|
||||
@@ -454,27 +454,26 @@ object JGitUtil {
|
||||
def appendLastCommits(
|
||||
fileList: List[(ObjectId, FileMode, String, String, Option[String])]
|
||||
): List[(ObjectId, FileMode, String, String, Option[String], Option[RevCommit])] = {
|
||||
fileList.map {
|
||||
case (id, mode, name, path, opt) =>
|
||||
if (maxFiles > 0 && fileList.size >= maxFiles) {
|
||||
// Don't attempt to get the last commit if the number of files is very large.
|
||||
(id, mode, name, path, opt, None)
|
||||
} else if (commitCount < 10000) {
|
||||
(id, mode, name, path, opt, Some(getCommit(path)))
|
||||
} else if (isCacheEnabled()) {
|
||||
// Use in-memory cache if the commit count is too big.
|
||||
val cached = objectCommitCache.getEntry(id)
|
||||
if (cached == null) {
|
||||
val commit = getCommit(path)
|
||||
objectCommitCache.put(id, commit)
|
||||
(id, mode, name, path, opt, Some(commit))
|
||||
} else {
|
||||
(id, mode, name, path, opt, Some(cached.getValue))
|
||||
}
|
||||
} else {
|
||||
fileList.map { case (id, mode, name, path, opt) =>
|
||||
if (maxFiles > 0 && fileList.size >= maxFiles) {
|
||||
// Don't attempt to get the last commit if the number of files is very large.
|
||||
(id, mode, name, path, opt, None)
|
||||
} else if (commitCount < 10000) {
|
||||
(id, mode, name, path, opt, Some(getCommit(path)))
|
||||
} else if (isCacheEnabled()) {
|
||||
// Use in-memory cache if the commit count is too big.
|
||||
val cached = objectCommitCache.getEntry(id)
|
||||
if (cached == null) {
|
||||
val commit = getCommit(path)
|
||||
objectCommitCache.put(id, commit)
|
||||
(id, mode, name, path, opt, Some(commit))
|
||||
} else {
|
||||
(id, mode, name, path, opt, Some(cached.getValue))
|
||||
}
|
||||
} else {
|
||||
val commit = getCommit(path)
|
||||
(id, mode, name, path, opt, Some(commit))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -503,23 +502,22 @@ object JGitUtil {
|
||||
|
||||
appendLastCommits(fileList)
|
||||
.map(simplifyPath)
|
||||
.map {
|
||||
case (objectId, fileMode, name, path, linkUrl, commit) =>
|
||||
FileInfo(
|
||||
objectId,
|
||||
fileMode == FileMode.TREE || fileMode == FileMode.GITLINK,
|
||||
name,
|
||||
path,
|
||||
getSummaryMessage(
|
||||
commit.map(_.getFullMessage).getOrElse(""),
|
||||
commit.map(_.getShortMessage).getOrElse("")
|
||||
),
|
||||
commit.map(_.getName).getOrElse(""),
|
||||
commit.map(_.getAuthorIdent.getWhen).orNull,
|
||||
commit.map(_.getAuthorIdent.getName).getOrElse(""),
|
||||
commit.map(_.getAuthorIdent.getEmailAddress).getOrElse(""),
|
||||
linkUrl
|
||||
)
|
||||
.map { case (objectId, fileMode, name, path, linkUrl, commit) =>
|
||||
FileInfo(
|
||||
objectId,
|
||||
fileMode == FileMode.TREE || fileMode == FileMode.GITLINK,
|
||||
name,
|
||||
path,
|
||||
getSummaryMessage(
|
||||
commit.map(_.getFullMessage).getOrElse(""),
|
||||
commit.map(_.getShortMessage).getOrElse("")
|
||||
),
|
||||
commit.map(_.getName).getOrElse(""),
|
||||
commit.map(_.getAuthorIdent.getWhen).orNull,
|
||||
commit.map(_.getAuthorIdent.getName).getOrElse(""),
|
||||
commit.map(_.getAuthorIdent.getEmailAddress).getOrElse(""),
|
||||
linkUrl
|
||||
)
|
||||
}
|
||||
.sortWith { (file1, file2) =>
|
||||
(file1.isDirectory, file2.isDirectory) match {
|
||||
@@ -714,10 +712,9 @@ object JGitUtil {
|
||||
toCommit.getParentCount match {
|
||||
case 0 =>
|
||||
df.scan(
|
||||
new EmptyTreeIterator(),
|
||||
new CanonicalTreeParser(null, git.getRepository.newObjectReader(), toCommit.getTree)
|
||||
)
|
||||
.asScala
|
||||
new EmptyTreeIterator(),
|
||||
new CanonicalTreeParser(null, git.getRepository.newObjectReader(), toCommit.getTree)
|
||||
).asScala
|
||||
case _ => df.scan(toCommit.getParent(0), toCommit.getTree).asScala
|
||||
}
|
||||
case Some(from) =>
|
||||
@@ -788,8 +785,10 @@ object JGitUtil {
|
||||
} else {
|
||||
val oldIsImage = FileUtil.isImage(diff.getOldPath)
|
||||
val newIsImage = FileUtil.isImage(diff.getNewPath)
|
||||
val patch = if (oldIsImage || newIsImage) None else Some(makePatchFromDiffEntry(git, diff)) // TODO use DiffFormatter
|
||||
val tooLarge = patch.exists(_.count(_ == '\n') > 1000) // Don't show diff if the file has more than 1000 lines diff
|
||||
val patch =
|
||||
if (oldIsImage || newIsImage) None else Some(makePatchFromDiffEntry(git, diff)) // TODO use DiffFormatter
|
||||
val tooLarge =
|
||||
patch.exists(_.count(_ == '\n') > 1000) // Don't show diff if the file has more than 1000 lines diff
|
||||
val includeContent = tooLarge || !fetchContent || oldIsImage || newIsImage
|
||||
DiffInfo(
|
||||
changeType = diff.getChangeType,
|
||||
@@ -921,10 +920,9 @@ object JGitUtil {
|
||||
Some(if (revstr.isEmpty) repository.repository.defaultBranch else revstr),
|
||||
repository.branchList.headOption
|
||||
).flatMap {
|
||||
case Some(rev) => Some((git.getRepository.resolve(rev), rev))
|
||||
case None => None
|
||||
}
|
||||
.find(_._1 != null)
|
||||
case Some(rev) => Some((git.getRepository.resolve(rev), rev))
|
||||
case None => None
|
||||
}.find(_._1 != null)
|
||||
}
|
||||
|
||||
def createTag(git: Git, name: String, message: Option[String], commitId: String) = {
|
||||
@@ -1301,7 +1299,8 @@ object JGitUtil {
|
||||
c.getAuthorIdent.getWhen,
|
||||
Option(git.log.add(c).addPath(blame.getSourcePath(i)).setSkip(1).setMaxCount(2).call.iterator.next)
|
||||
.map(_.name),
|
||||
if (blame.getSourcePath(i) == path) { None } else { Some(blame.getSourcePath(i)) },
|
||||
if (blame.getSourcePath(i) == path) { None }
|
||||
else { Some(blame.getSourcePath(i)) },
|
||||
c.getCommitterIdent.getWhen,
|
||||
c.getShortMessage,
|
||||
Set.empty
|
||||
|
||||
@@ -128,13 +128,14 @@ object LDAPUtil {
|
||||
|
||||
val cachedInstance = provider.get()
|
||||
if (cachedInstance == null) {
|
||||
val cls = try {
|
||||
Class.forName("com.sun.net.ssl.internal.ssl.Provider")
|
||||
} catch {
|
||||
case e: ClassNotFoundException =>
|
||||
Class.forName("com.ibm.jsse.IBMJSSEProvider")
|
||||
case e: Throwable => throw e
|
||||
}
|
||||
val cls =
|
||||
try {
|
||||
Class.forName("com.sun.net.ssl.internal.ssl.Provider")
|
||||
} catch {
|
||||
case e: ClassNotFoundException =>
|
||||
Class.forName("com.ibm.jsse.IBMJSSEProvider")
|
||||
case e: Throwable => throw e
|
||||
}
|
||||
val newInstance = cls
|
||||
.getDeclaredConstructor()
|
||||
.newInstance()
|
||||
@@ -234,8 +235,8 @@ object LDAPUtil {
|
||||
case x => "(&(" + x + ")(" + userNameAttribute + "=" + userName + "))"
|
||||
}
|
||||
|
||||
getEntries(conn.search(baseDN, LDAPConnection.SCOPE_SUB, filterCond, null, false)).collectFirst {
|
||||
case x => x.getDN
|
||||
getEntries(conn.search(baseDN, LDAPConnection.SCOPE_SUB, filterCond, null, false)).collectFirst { case x =>
|
||||
x.getDN
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -62,9 +62,8 @@ class Mailer(settings: SystemSettings) {
|
||||
smtp.fromAddress
|
||||
.map(_ -> smtp.fromName.getOrElse(loginAccount.map(_.userName).getOrElse("GitBucket")))
|
||||
.orElse(Some("notifications@gitbucket.com" -> loginAccount.map(_.userName).getOrElse("GitBucket")))
|
||||
.foreach {
|
||||
case (address, name) =>
|
||||
email.setFrom(address, name)
|
||||
.foreach { case (address, name) =>
|
||||
email.setFrom(address, name)
|
||||
}
|
||||
email.setCharset("UTF-8")
|
||||
email.setSubject(subject)
|
||||
|
||||
@@ -9,7 +9,7 @@ object RepositoryName {
|
||||
def apply(fullName: String): RepositoryName = {
|
||||
fullName.split("/").toList match {
|
||||
case owner :: name :: Nil => RepositoryName(owner, name)
|
||||
case _ => throw new IllegalArgumentException(s"${fullName} is not repositoryName (only 'owner/name')")
|
||||
case _ => throw new IllegalArgumentException(s"${fullName} is not repositoryName (only 'owner/name')")
|
||||
}
|
||||
}
|
||||
def apply(repository: gitbucket.core.model.Repository): RepositoryName =
|
||||
|
||||
@@ -19,7 +19,9 @@ trait AvatarImageProvider { self: RequestCache =>
|
||||
// by user name
|
||||
getAccountByUserNameFromCache(userName).map { account =>
|
||||
if (account.image.isEmpty && context.settings.basicBehavior.gravatar) {
|
||||
s"""https://www.gravatar.com/avatar/${StringUtil.md5(account.mailAddress.toLowerCase)}?s=${size}&d=retro&r=g"""
|
||||
s"""https://www.gravatar.com/avatar/${StringUtil.md5(
|
||||
account.mailAddress.toLowerCase
|
||||
)}?s=${size}&d=retro&r=g"""
|
||||
} else {
|
||||
s"""${context.path}/${account.userName}/_avatar?${helpers.hashDate(account.updatedDate)}"""
|
||||
}
|
||||
@@ -30,7 +32,9 @@ trait AvatarImageProvider { self: RequestCache =>
|
||||
// by mail address
|
||||
getAccountByMailAddressFromCache(mailAddress).map { account =>
|
||||
if (account.image.isEmpty && context.settings.basicBehavior.gravatar) {
|
||||
s"""https://www.gravatar.com/avatar/${StringUtil.md5(account.mailAddress.toLowerCase)}?s=${size}&d=retro&r=g"""
|
||||
s"""https://www.gravatar.com/avatar/${StringUtil.md5(
|
||||
account.mailAddress.toLowerCase
|
||||
)}?s=${size}&d=retro&r=g"""
|
||||
} else {
|
||||
s"""${context.path}/${account.userName}/_avatar?${helpers.hashDate(account.updatedDate)}"""
|
||||
}
|
||||
@@ -45,13 +49,15 @@ trait AvatarImageProvider { self: RequestCache =>
|
||||
|
||||
if (tooltip) {
|
||||
Html(
|
||||
s"""<img src="${src}" class="${if (size > 20) { "avatar" } else { "avatar-mini" }}" style="width: ${size}px; height: ${size}px;"
|
||||
s"""<img src="${src}" class="${if (size > 20) { "avatar" }
|
||||
else { "avatar-mini" }}" style="width: ${size}px; height: ${size}px;"
|
||||
| alt="@${StringUtil.escapeHtml(userName)}"
|
||||
| data-toggle="tooltip" title="${StringUtil.escapeHtml(userName)}" />""".stripMargin
|
||||
)
|
||||
} else {
|
||||
Html(
|
||||
s"""<img src="${src}" class="${if (size > 20) { "avatar" } else { "avatar-mini" }}" style="width: ${size}px; height: ${size}px;"
|
||||
s"""<img src="${src}" class="${if (size > 20) { "avatar" }
|
||||
else { "avatar-mini" }}" style="width: ${size}px; height: ${size}px;"
|
||||
| alt="@${StringUtil.escapeHtml(userName)}" />""".stripMargin
|
||||
)
|
||||
}
|
||||
|
||||
@@ -10,13 +10,14 @@ trait LinkConverter { self: RequestCache =>
|
||||
/**
|
||||
* Creates a link to the issue or the pull request from the issue id.
|
||||
*/
|
||||
protected def createIssueLink(owner: String, repository: String, issueId: Int, title: String)(
|
||||
implicit context: Context
|
||||
protected def createIssueLink(owner: String, repository: String, issueId: Int, title: String)(implicit
|
||||
context: Context
|
||||
): String = {
|
||||
getIssueFromCache(owner, repository, issueId.toString) match {
|
||||
case Some(issue) =>
|
||||
s"""<a href="${context.path}/${owner}/${repository}/${if (issue.isPullRequest) "pull" else "issues"}/${issueId}"><strong>${StringUtil
|
||||
.escapeHtml(title)}</strong> #${issueId}</a>"""
|
||||
s"""<a href="${context.path}/${owner}/${repository}/${if (issue.isPullRequest) "pull"
|
||||
else "issues"}/${issueId}"><strong>${StringUtil
|
||||
.escapeHtml(title)}</strong> #${issueId}</a>"""
|
||||
case None =>
|
||||
s"Unknown #${issueId}"
|
||||
}
|
||||
@@ -25,13 +26,14 @@ trait LinkConverter { self: RequestCache =>
|
||||
/**
|
||||
* Creates a global link to the issue or the pull request from the issue id.
|
||||
*/
|
||||
protected def createGlobalIssueLink(owner: String, repository: String, issueId: Int, title: String)(
|
||||
implicit context: Context
|
||||
protected def createGlobalIssueLink(owner: String, repository: String, issueId: Int, title: String)(implicit
|
||||
context: Context
|
||||
): String = {
|
||||
getIssueFromCache(owner, repository, issueId.toString) match {
|
||||
case Some(issue) =>
|
||||
s"""<a href="${context.path}/${owner}/${repository}/${if (issue.isPullRequest) "pull" else "issues"}/${issueId}"><strong>${StringUtil
|
||||
.escapeHtml(title)}</strong> ${owner}/${repository}#${issueId}</a>"""
|
||||
s"""<a href="${context.path}/${owner}/${repository}/${if (issue.isPullRequest) "pull"
|
||||
else "issues"}/${issueId}"><strong>${StringUtil
|
||||
.escapeHtml(title)}</strong> ${owner}/${repository}#${issueId}</a>"""
|
||||
case None =>
|
||||
s"Unknown ${owner}/${repository}#${issueId}"
|
||||
}
|
||||
@@ -53,12 +55,12 @@ trait LinkConverter { self: RequestCache =>
|
||||
else text
|
||||
|
||||
escaped
|
||||
// convert username/project@SHA to link
|
||||
// convert username/project@SHA to link
|
||||
.replaceBy("(?<=(^|\\W))([a-zA-Z0-9\\-_]+)/([a-zA-Z0-9\\-_\\.]+)@([a-f0-9]{40})(?=(\\W|$))".r) { m =>
|
||||
getAccountByUserNameFromCache(m.group(2)).map { _ =>
|
||||
s"""<code><a href="${context.path}/${m.group(2)}/${m.group(3)}/commit/${m.group(4)}">${m.group(2)}/${m.group(
|
||||
3
|
||||
)}@${m.group(4).substring(0, 7)}</a></code>"""
|
||||
3
|
||||
)}@${m.group(4).substring(0, 7)}</a></code>"""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,13 +70,13 @@ trait LinkConverter { self: RequestCache =>
|
||||
getIssueFromCache(m.group(2), m.group(3), m.group(4)) match {
|
||||
case Some(pull) if (pull.isPullRequest) =>
|
||||
Some(s"""<a href="${context.path}/${m.group(2)}/${m.group(3)}/pull/${m
|
||||
.group(4)}" title="${pull.title}">${m.group(2)}/${m.group(
|
||||
3
|
||||
)}#${m.group(4)}</a>""")
|
||||
.group(4)}" title="${pull.title}">${m.group(2)}/${m.group(
|
||||
3
|
||||
)}#${m.group(4)}</a>""")
|
||||
case Some(issue) =>
|
||||
Some(s"""<a href="${context.path}/${m.group(2)}/${m.group(3)}/issues/${m
|
||||
.group(4)}" title="${issue.title}">${m.group(2)}/${m
|
||||
.group(3)}#${m.group(4)}</a>""")
|
||||
.group(4)}" title="${issue.title}">${m.group(2)}/${m
|
||||
.group(3)}#${m.group(4)}</a>""")
|
||||
case None =>
|
||||
Some(s"""${m.group(2)}/${m.group(3)}#${m.group(4)}""")
|
||||
}
|
||||
@@ -84,8 +86,8 @@ trait LinkConverter { self: RequestCache =>
|
||||
.replaceBy(("(?<=(^|\\W))([a-zA-Z0-9\\-_]+)@([a-f0-9]{40})(?=(\\W|$))").r) { m =>
|
||||
getAccountByUserNameFromCache(m.group(2)).map { _ =>
|
||||
s"""<code><a href="${context.path}/${m.group(2)}/${repository.name}/commit/${m.group(3)}">${m.group(2)}@${m
|
||||
.group(3)
|
||||
.substring(0, 7)}</a></code>"""
|
||||
.group(3)
|
||||
.substring(0, 7)}</a></code>"""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,10 +96,10 @@ trait LinkConverter { self: RequestCache =>
|
||||
getIssueFromCache(m.group(2), repository.name, m.group(3)) match {
|
||||
case Some(issue) if (issue.isPullRequest) =>
|
||||
Some(s"""<a href="${context.path}/${m.group(2)}/${repository.name}/pull/${m.group(3)}">${m.group(2)}#${m
|
||||
.group(3)}</a>""")
|
||||
.group(3)}</a>""")
|
||||
case Some(_) =>
|
||||
Some(s"""<a href="${context.path}/${m.group(2)}/${repository.name}/issues/${m.group(3)}">${m.group(2)}#${m
|
||||
.group(3)}</a>""")
|
||||
.group(3)}</a>""")
|
||||
case None =>
|
||||
Some(s"""${m.group(2)}#${m.group(3)}""")
|
||||
}
|
||||
@@ -109,12 +111,12 @@ trait LinkConverter { self: RequestCache =>
|
||||
getIssueFromCache(repository.owner, repository.name, m.group(3)) match {
|
||||
case Some(pull) if (pull.isPullRequest) =>
|
||||
Some(s"""<a href="${context.path}/${repository.owner}/${repository.name}/pull/${m
|
||||
.group(3)}" title="${pull.title}">${prefix}${m
|
||||
.group(3)}</a>""")
|
||||
.group(3)}" title="${pull.title}">${prefix}${m
|
||||
.group(3)}</a>""")
|
||||
case Some(issue) =>
|
||||
Some(s"""<a href="${context.path}/${repository.owner}/${repository.name}/issues/${m
|
||||
.group(3)}" title="${issue.title}">${prefix}${m
|
||||
.group(3)}</a>""")
|
||||
.group(3)}" title="${issue.title}">${prefix}${m
|
||||
.group(3)}</a>""")
|
||||
case None =>
|
||||
Some(s"""${m.group(2)}${m.group(3)}""")
|
||||
}
|
||||
@@ -130,7 +132,7 @@ trait LinkConverter { self: RequestCache =>
|
||||
// convert commit id to link
|
||||
.replaceBy("(?<=(^|[^\\w/@]))([a-f0-9]{40})(?=(\\W|$))".r) { m =>
|
||||
Some(s"""<code><a href="${context.path}/${repository.owner}/${repository.name}/commit/${m
|
||||
.group(2)}">${m.group(2).substring(0, 7)}</a></code>""")
|
||||
.group(2)}">${m.group(2).substring(0, 7)}</a></code>""")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,8 +160,8 @@ object helpers extends AvatarImageProvider with LinkConverter with RequestCache
|
||||
/**
|
||||
* Creates a link to the issue or the pull request from the issue id.
|
||||
*/
|
||||
def issueLink(owner: String, repository: String, issueId: Int, title: String)(
|
||||
implicit context: Context
|
||||
def issueLink(owner: String, repository: String, issueId: Int, title: String)(implicit
|
||||
context: Context
|
||||
): Html = {
|
||||
Html(createIssueLink(owner, repository, issueId, title))
|
||||
}
|
||||
@@ -169,8 +169,8 @@ object helpers extends AvatarImageProvider with LinkConverter with RequestCache
|
||||
/**
|
||||
* Creates a global link to the issue or the pull request from the issue id.
|
||||
*/
|
||||
def issueGlobalLink(owner: String, repository: String, issueId: Int, title: String)(
|
||||
implicit context: Context
|
||||
def issueGlobalLink(owner: String, repository: String, issueId: Int, title: String)(implicit
|
||||
context: Context
|
||||
): Html = {
|
||||
Html(createGlobalIssueLink(owner, repository, issueId, title))
|
||||
}
|
||||
@@ -179,8 +179,8 @@ object helpers extends AvatarImageProvider with LinkConverter with RequestCache
|
||||
* Returns <img> which displays the avatar icon for the given user name.
|
||||
* This method looks up Gravatar if avatar icon has not been configured in user settings.
|
||||
*/
|
||||
def avatar(userName: String, size: Int, tooltip: Boolean = false, mailAddress: String = "")(
|
||||
implicit context: Context
|
||||
def avatar(userName: String, size: Int, tooltip: Boolean = false, mailAddress: String = "")(implicit
|
||||
context: Context
|
||||
): Html =
|
||||
getAvatarImageHtml(userName, size, mailAddress, tooltip)
|
||||
|
||||
|
||||
@@ -257,7 +257,7 @@ class ApiIntegrationTest extends AnyFunSuite {
|
||||
assert(label1.getUrl == "http://localhost:19999/api/v3/repos/root/issue_label_test/labels/bug")
|
||||
}
|
||||
|
||||
// Replace labels (Cannot test because GHLabel.setLabels() doesn't use the replace endpoint)
|
||||
// Replace labels (Cannot test because GHLabel.setLabels() doesn't use the replace endpoint)
|
||||
// {
|
||||
// issue.setLabels("enhancement", "invalid", "question")
|
||||
//
|
||||
|
||||
@@ -297,7 +297,7 @@ object ApiSpecModels {
|
||||
committerEmailAddress = account.mailAddress,
|
||||
None,
|
||||
None
|
||||
)
|
||||
)
|
||||
|
||||
val apiCommitListItem = ApiCommitListItem(
|
||||
commit = commitInfo(sha1),
|
||||
@@ -443,7 +443,7 @@ object ApiSpecModels {
|
||||
|
||||
val apiPusher = ApiPusher(account)
|
||||
|
||||
//have both urls as https, as the expected samples are using https
|
||||
// have both urls as https, as the expected samples are using https
|
||||
val gitHubContext = JsonFormat.Context("https://api.github.com", Some("https://api.github.com"))
|
||||
|
||||
val apiRefHeadsMaster = ApiRef(
|
||||
@@ -797,7 +797,7 @@ object ApiSpecModels {
|
||||
|
||||
val jsonPusher = """{"name":"octocat","email":"octocat@example.com"}"""
|
||||
|
||||
//I checked all refs in gitbucket repo, and there appears to be only type "commit" and type "tag"
|
||||
// I checked all refs in gitbucket repo, and there appears to be only type "commit" and type "tag"
|
||||
val jsonRef = """{"ref":"refs/heads/featureA","object":{"sha":"6dcb09b5b57875f334f61aebed695e2e4193db5e"}}"""
|
||||
|
||||
val jsonRefHeadsMain =
|
||||
|
||||
@@ -28,9 +28,19 @@ import MergeServiceSpec._
|
||||
import org.json4s.JsonAST.{JArray, JString}
|
||||
|
||||
class MergeServiceSpec extends AnyFunSpec with ServiceSpecBase {
|
||||
val service = new MergeService with AccountService with ActivityService with IssuesService with LabelsService
|
||||
with MilestonesService with RepositoryService with PrioritiesService with PullRequestService with CommitsService
|
||||
with WebHookPullRequestService with WebHookPullRequestReviewCommentService with RequestCache {
|
||||
val service = new MergeService
|
||||
with AccountService
|
||||
with ActivityService
|
||||
with IssuesService
|
||||
with LabelsService
|
||||
with MilestonesService
|
||||
with RepositoryService
|
||||
with PrioritiesService
|
||||
with PullRequestService
|
||||
with CommitsService
|
||||
with WebHookPullRequestService
|
||||
with WebHookPullRequestReviewCommentService
|
||||
with RequestCache {
|
||||
override protected def getReceiveHooks(): Seq[ReceiveHook] = Nil
|
||||
}
|
||||
val branch = "master"
|
||||
|
||||
@@ -33,7 +33,11 @@ class PullRequestServiceSpec
|
||||
generateNewUserWithDBRepository("user1", "repo2")
|
||||
generateNewUserWithDBRepository("user2", "repo1")
|
||||
generateNewPullRequest("user1/repo1/master", "user1/repo1/head2", loginUser = "root") // not target branch
|
||||
generateNewPullRequest("user1/repo1/head1", "user1/repo1/master", loginUser = "root") // not target branch ( swap from, to )
|
||||
generateNewPullRequest(
|
||||
"user1/repo1/head1",
|
||||
"user1/repo1/master",
|
||||
loginUser = "root"
|
||||
) // not target branch ( swap from, to )
|
||||
generateNewPullRequest("user1/repo1/master", "user2/repo1/head1", loginUser = "root") // other user
|
||||
generateNewPullRequest("user1/repo1/master", "user1/repo2/head1", loginUser = "root") // other repository
|
||||
val r1 = swap(generateNewPullRequest("user1/repo1/master2", "user1/repo1/head1", loginUser = "root"))
|
||||
|
||||
@@ -108,10 +108,21 @@ trait ServiceSpecBase {
|
||||
|
||||
def user(name: String)(implicit s: Session): Account = AccountService.getAccountByUserName(name).get
|
||||
|
||||
lazy val dummyService = new RepositoryService with AccountService with ActivityService with IssuesService
|
||||
with MergeService with PullRequestService with CommitsService with CommitStatusService with LabelsService
|
||||
with MilestonesService with PrioritiesService with WebHookService with WebHookPullRequestService
|
||||
with WebHookPullRequestReviewCommentService with RequestCache {
|
||||
lazy val dummyService = new RepositoryService
|
||||
with AccountService
|
||||
with ActivityService
|
||||
with IssuesService
|
||||
with MergeService
|
||||
with PullRequestService
|
||||
with CommitsService
|
||||
with CommitStatusService
|
||||
with LabelsService
|
||||
with MilestonesService
|
||||
with PrioritiesService
|
||||
with WebHookService
|
||||
with WebHookPullRequestService
|
||||
with WebHookPullRequestReviewCommentService
|
||||
with RequestCache {
|
||||
override def fetchAsPullRequest(
|
||||
userName: String,
|
||||
repositoryName: String,
|
||||
@@ -133,8 +144,7 @@ trait ServiceSpecBase {
|
||||
ac
|
||||
}
|
||||
|
||||
def generateNewIssue(userName: String, repositoryName: String, loginUser: String = "root")(
|
||||
implicit
|
||||
def generateNewIssue(userName: String, repositoryName: String, loginUser: String = "root")(implicit
|
||||
s: Session
|
||||
): Int = {
|
||||
dummyService.insertIssue(
|
||||
@@ -149,8 +159,7 @@ trait ServiceSpecBase {
|
||||
)
|
||||
}
|
||||
|
||||
def generateNewPullRequest(base: String, request: String, loginUser: String)(
|
||||
implicit
|
||||
def generateNewPullRequest(base: String, request: String, loginUser: String)(implicit
|
||||
s: Session
|
||||
): (Issue, PullRequest) = {
|
||||
implicit val context = Context(createSystemSettings(), None, this.request)
|
||||
|
||||
@@ -5,9 +5,19 @@ import org.scalatest.funsuite.AnyFunSuite
|
||||
import gitbucket.core.model.WebHookContentType
|
||||
|
||||
class WebHookServiceSpec extends AnyFunSuite with ServiceSpecBase {
|
||||
lazy val service = new WebHookPullRequestService with AccountService with ActivityService with RepositoryService
|
||||
with MergeService with PullRequestService with IssuesService with CommitsService with LabelsService
|
||||
with MilestonesService with PrioritiesService with WebHookPullRequestReviewCommentService with RequestCache
|
||||
lazy val service = new WebHookPullRequestService
|
||||
with AccountService
|
||||
with ActivityService
|
||||
with RepositoryService
|
||||
with MergeService
|
||||
with PullRequestService
|
||||
with IssuesService
|
||||
with CommitsService
|
||||
with LabelsService
|
||||
with MilestonesService
|
||||
with PrioritiesService
|
||||
with WebHookPullRequestReviewCommentService
|
||||
with RequestCache
|
||||
|
||||
test("WebHookPullRequestService.getPullRequestsByRequestForWebhook") {
|
||||
withTestDB { implicit session =>
|
||||
|
||||
@@ -101,11 +101,12 @@ object GitSpecUtil {
|
||||
val merger = MergeStrategy.RECURSIVE.newMerger(repository, true)
|
||||
val mergeBaseTip = repository.resolve(into)
|
||||
val mergeTip = repository.resolve(branch)
|
||||
val conflicted = try {
|
||||
!merger.merge(mergeBaseTip, mergeTip)
|
||||
} catch {
|
||||
case e: NoMergeBaseException => true
|
||||
}
|
||||
val conflicted =
|
||||
try {
|
||||
!merger.merge(mergeBaseTip, mergeTip)
|
||||
} catch {
|
||||
case e: NoMergeBaseException => true
|
||||
}
|
||||
if (conflicted) {
|
||||
throw new RuntimeException("conflict!")
|
||||
}
|
||||
|
||||
@@ -88,41 +88,65 @@ class StringUtilSpec extends AnyFunSpec {
|
||||
it("should convert GitBucket repository url") {
|
||||
assert(
|
||||
StringUtil
|
||||
.getRepositoryViewerUrl("http://localhost:8080/git/root/gitbucket.git", baseUrl) == "http://localhost:8080/root/gitbucket"
|
||||
.getRepositoryViewerUrl(
|
||||
"http://localhost:8080/git/root/gitbucket.git",
|
||||
baseUrl
|
||||
) == "http://localhost:8080/root/gitbucket"
|
||||
)
|
||||
assert(
|
||||
StringUtil
|
||||
.getRepositoryViewerUrl("http://root@localhost:8080/git/root/gitbucket.git", baseUrl) == "http://localhost:8080/root/gitbucket"
|
||||
.getRepositoryViewerUrl(
|
||||
"http://root@localhost:8080/git/root/gitbucket.git",
|
||||
baseUrl
|
||||
) == "http://localhost:8080/root/gitbucket"
|
||||
)
|
||||
}
|
||||
it("should convert GitHub repository url") {
|
||||
assert(
|
||||
StringUtil
|
||||
.getRepositoryViewerUrl("https://github.com/root/gitbucket.git", baseUrl) == "https://github.com/root/gitbucket"
|
||||
.getRepositoryViewerUrl(
|
||||
"https://github.com/root/gitbucket.git",
|
||||
baseUrl
|
||||
) == "https://github.com/root/gitbucket"
|
||||
)
|
||||
assert(
|
||||
StringUtil
|
||||
.getRepositoryViewerUrl("https://root@github.com/root/gitbucket.git", baseUrl) == "https://github.com/root/gitbucket"
|
||||
.getRepositoryViewerUrl(
|
||||
"https://root@github.com/root/gitbucket.git",
|
||||
baseUrl
|
||||
) == "https://github.com/root/gitbucket"
|
||||
)
|
||||
}
|
||||
it("should convert BitBucket repository url") {
|
||||
assert(
|
||||
StringUtil
|
||||
.getRepositoryViewerUrl("https://bitbucket.org/root/gitbucket.git", baseUrl) == "https://bitbucket.org/root/gitbucket"
|
||||
.getRepositoryViewerUrl(
|
||||
"https://bitbucket.org/root/gitbucket.git",
|
||||
baseUrl
|
||||
) == "https://bitbucket.org/root/gitbucket"
|
||||
)
|
||||
assert(
|
||||
StringUtil
|
||||
.getRepositoryViewerUrl("https://root@bitbucket.org/root/gitbucket.git", baseUrl) == "https://bitbucket.org/root/gitbucket"
|
||||
.getRepositoryViewerUrl(
|
||||
"https://root@bitbucket.org/root/gitbucket.git",
|
||||
baseUrl
|
||||
) == "https://bitbucket.org/root/gitbucket"
|
||||
)
|
||||
}
|
||||
it("should convert GitLab repository url") {
|
||||
assert(
|
||||
StringUtil
|
||||
.getRepositoryViewerUrl("https://gitlab.com/root/gitbucket.git", baseUrl) == "https://gitlab.com/root/gitbucket"
|
||||
.getRepositoryViewerUrl(
|
||||
"https://gitlab.com/root/gitbucket.git",
|
||||
baseUrl
|
||||
) == "https://gitlab.com/root/gitbucket"
|
||||
)
|
||||
assert(
|
||||
StringUtil
|
||||
.getRepositoryViewerUrl("https://root@gitlab.com/root/gitbucket.git", baseUrl) == "https://gitlab.com/root/gitbucket"
|
||||
.getRepositoryViewerUrl(
|
||||
"https://root@gitlab.com/root/gitbucket.git",
|
||||
baseUrl
|
||||
) == "https://gitlab.com/root/gitbucket"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,8 +202,7 @@ class AvatarImageProviderSpec extends AnyFunSpec {
|
||||
*/
|
||||
class AvatarImageProviderImpl(account: Option[Account]) extends AvatarImageProvider with RequestCache {
|
||||
|
||||
def toHtml(userName: String, size: Int, mailAddress: String = "", tooltip: Boolean = false)(
|
||||
implicit
|
||||
def toHtml(userName: String, size: Int, mailAddress: String = "", tooltip: Boolean = false)(implicit
|
||||
context: Context
|
||||
): Html = getAvatarImageHtml(userName, size, mailAddress, tooltip)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user