mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-11-01 02:56:08 +01:00
Compare commits
1 Commits
4.34.0
...
disable-gi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f16f395539 |
10
.github/workflows/build.yml
vendored
10
.github/workflows/build.yml
vendored
@@ -14,16 +14,6 @@ jobs:
|
|||||||
java: [8, 11]
|
java: [8, 11]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Cache
|
|
||||||
uses: actions/cache@v2
|
|
||||||
env:
|
|
||||||
cache-name: cache-sbt-libs
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
~/.ivy2/cache
|
|
||||||
~/.sbt
|
|
||||||
~/.cache/coursier/v1
|
|
||||||
key: build-${{ env.cache-name }}-${{ hashFiles('build.sbt') }}
|
|
||||||
- name: Set up JDK
|
- name: Set up JDK
|
||||||
uses: actions/setup-java@v1
|
uses: actions/setup-java@v1
|
||||||
with:
|
with:
|
||||||
|
|||||||
16
CHANGELOG.md
16
CHANGELOG.md
@@ -1,22 +1,6 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
All changes to the project will be documented in this file.
|
All changes to the project will be documented in this file.
|
||||||
|
|
||||||
### 4.34.0 - 26 Jul 2020
|
|
||||||
|
|
||||||
- Enhancement admin settings UI
|
|
||||||
- File upload settings
|
|
||||||
- Restrict repository operations
|
|
||||||
- User-defined CSS
|
|
||||||
- Limit the repository list in the sidebar
|
|
||||||
- Improve MariaDB support
|
|
||||||
- Improve activity logging
|
|
||||||
- CLI option to persist session on disk in the standalone mode
|
|
||||||
- Web API updates
|
|
||||||
- Add [list commits API](https://developer.github.com/v3/repos/commits/#list-commits)
|
|
||||||
- Bundled plugins updates
|
|
||||||
- [gitbucket-gist-plugin](https://github.com/gitbucket/gitbucket-gist-plugin) 4.18.0 -> 4.19.0
|
|
||||||
- [gitbucket-notifications-plugin](https://github.com/gitbucket/gitbucket-notifications-plugin) 1.8.0 -> 1.9.0
|
|
||||||
|
|
||||||
### 4.33.0 - 31 Dec 2019
|
### 4.33.0 - 31 Dec 2019
|
||||||
|
|
||||||
- All CLI options are configurable by environment variables
|
- All CLI options are configurable by environment variables
|
||||||
|
|||||||
19
README.md
19
README.md
@@ -57,20 +57,11 @@ Support
|
|||||||
|
|
||||||
What's New in 4.33.x
|
What's New in 4.33.x
|
||||||
-------------
|
-------------
|
||||||
### 4.34.0 - 26 Jul 2020
|
### 4.33.0 - 31 Dec 2019
|
||||||
|
|
||||||
- Enhancement admin settings UI
|
- All CLI options are configurable by environment variables
|
||||||
- File upload settings
|
- Folding pull request files
|
||||||
- Restrict repository operations
|
- WebHook security options
|
||||||
- User-defined CSS
|
- Add assignee and assignees properties to some Web APIs' response
|
||||||
- Limit the repository list in the sidebar
|
|
||||||
- Improve MariaDB support
|
|
||||||
- Improve activity logging
|
|
||||||
- CLI option to persist session on disk in the standalone mode
|
|
||||||
- Web API updates
|
|
||||||
- Add [list commits API](https://developer.github.com/v3/repos/commits/#list-commits)
|
|
||||||
- Bundled plugins updates
|
|
||||||
- [gitbucket-gist-plugin](https://github.com/gitbucket/gitbucket-gist-plugin) 4.18.0 -> 4.19.0
|
|
||||||
- [gitbucket-notifications-plugin](https://github.com/gitbucket/gitbucket-notifications-plugin) 1.8.0 -> 1.9.0
|
|
||||||
|
|
||||||
See the [change log](CHANGELOG.md) for all of the updates.
|
See the [change log](CHANGELOG.md) for all of the updates.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import com.typesafe.sbt.pgp.PgpKeys._
|
|||||||
|
|
||||||
val Organization = "io.github.gitbucket"
|
val Organization = "io.github.gitbucket"
|
||||||
val Name = "gitbucket"
|
val Name = "gitbucket"
|
||||||
val GitBucketVersion = "4.34.0"
|
val GitBucketVersion = "4.33.0"
|
||||||
val ScalatraVersion = "2.7.0-RC1"
|
val ScalatraVersion = "2.7.0-RC1"
|
||||||
val JettyVersion = "9.4.30.v20200611"
|
val JettyVersion = "9.4.30.v20200611"
|
||||||
val JgitVersion = "5.8.0.202006091008-r"
|
val JgitVersion = "5.8.0.202006091008-r"
|
||||||
@@ -54,9 +54,11 @@ libraryDependencies ++= Seq(
|
|||||||
"ch.qos.logback" % "logback-classic" % "1.2.3",
|
"ch.qos.logback" % "logback-classic" % "1.2.3",
|
||||||
"com.zaxxer" % "HikariCP" % "3.4.5",
|
"com.zaxxer" % "HikariCP" % "3.4.5",
|
||||||
"com.typesafe" % "config" % "1.4.0",
|
"com.typesafe" % "config" % "1.4.0",
|
||||||
|
"com.typesafe.akka" %% "akka-actor" % "2.5.27",
|
||||||
"fr.brouillard.oss.security.xhub" % "xhub4j-core" % "1.1.0",
|
"fr.brouillard.oss.security.xhub" % "xhub4j-core" % "1.1.0",
|
||||||
"com.github.bkromhout" % "java-diff-utils" % "2.1.1",
|
"com.github.bkromhout" % "java-diff-utils" % "2.1.1",
|
||||||
"org.cache2k" % "cache2k-all" % "1.2.4.Final",
|
"org.cache2k" % "cache2k-all" % "1.2.4.Final",
|
||||||
|
"com.enragedginger" %% "akka-quartz-scheduler" % "1.8.1-akka-2.5.x" exclude ("com.mchange", "c3p0") exclude ("com.zaxxer", "HikariCP-java6"),
|
||||||
"net.coobird" % "thumbnailator" % "0.4.11",
|
"net.coobird" % "thumbnailator" % "0.4.11",
|
||||||
"com.github.zafarkhaja" % "java-semver" % "0.9.0",
|
"com.github.zafarkhaja" % "java-semver" % "0.9.0",
|
||||||
"com.nimbusds" % "oauth2-oidc-sdk" % "5.64.4",
|
"com.nimbusds" % "oauth2-oidc-sdk" % "5.64.4",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
notifications:1.9.0
|
notifications:1.8.0
|
||||||
gist:4.19.0
|
gist:4.18.0
|
||||||
emoji:4.6.0
|
emoji:4.6.0
|
||||||
pages:1.8.0
|
pages:1.8.0
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<changeSet>
|
|
||||||
<dropTable tableName="ACTIVITY" />
|
|
||||||
</changeSet>
|
|
||||||
@@ -1,22 +1,7 @@
|
|||||||
package gitbucket.core
|
package gitbucket.core
|
||||||
|
|
||||||
import java.io.FileOutputStream
|
import io.github.gitbucket.solidbase.migration.{SqlMigration, LiquibaseMigration}
|
||||||
import java.nio.charset.StandardCharsets
|
import io.github.gitbucket.solidbase.model.{Version, Module}
|
||||||
import java.sql.Connection
|
|
||||||
import java.util
|
|
||||||
import java.util.UUID
|
|
||||||
|
|
||||||
import gitbucket.core.model.Activity
|
|
||||||
import gitbucket.core.util.Directory.ActivityLog
|
|
||||||
import gitbucket.core.util.JDBCUtil
|
|
||||||
import io.github.gitbucket.solidbase.Solidbase
|
|
||||||
import io.github.gitbucket.solidbase.migration.{LiquibaseMigration, Migration, SqlMigration}
|
|
||||||
import io.github.gitbucket.solidbase.model.{Module, Version}
|
|
||||||
import org.json4s.NoTypeHints
|
|
||||||
import org.json4s.jackson.Serialization
|
|
||||||
import org.json4s.jackson.Serialization.write
|
|
||||||
|
|
||||||
import scala.util.Using
|
|
||||||
|
|
||||||
object GitBucketCoreModule
|
object GitBucketCoreModule
|
||||||
extends Module(
|
extends Module(
|
||||||
@@ -80,38 +65,5 @@ object GitBucketCoreModule
|
|||||||
new Version("4.31.1"),
|
new Version("4.31.1"),
|
||||||
new Version("4.31.2"),
|
new Version("4.31.2"),
|
||||||
new Version("4.32.0", new LiquibaseMigration("update/gitbucket-core_4.32.xml")),
|
new Version("4.32.0", new LiquibaseMigration("update/gitbucket-core_4.32.xml")),
|
||||||
new Version("4.33.0"),
|
new Version("4.33.0")
|
||||||
new Version(
|
|
||||||
"4.34.0",
|
|
||||||
new Migration() {
|
|
||||||
override def migrate(moduleId: String, version: String, context: util.Map[String, AnyRef]): Unit = {
|
|
||||||
implicit val formats = Serialization.formats(NoTypeHints)
|
|
||||||
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")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Using.resource(new FileOutputStream(ActivityLog, true)) { out =>
|
|
||||||
list.foreach { activity =>
|
|
||||||
out.write((write(activity) + "\n").getBytes(StandardCharsets.UTF_8))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
new LiquibaseMigration("update/gitbucket-core_4.34.xml")
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ class AccountController
|
|||||||
with WebHookService
|
with WebHookService
|
||||||
with PrioritiesService
|
with PrioritiesService
|
||||||
with RepositoryCreationService
|
with RepositoryCreationService
|
||||||
with RequestCache
|
|
||||||
|
|
||||||
trait AccountControllerBase extends AccountManagementControllerBase {
|
trait AccountControllerBase extends AccountManagementControllerBase {
|
||||||
self: AccountService
|
self: AccountService
|
||||||
|
|||||||
@@ -52,7 +52,6 @@ class ApiController
|
|||||||
with ReferrerAuthenticator
|
with ReferrerAuthenticator
|
||||||
with ReadableUsersAuthenticator
|
with ReadableUsersAuthenticator
|
||||||
with WritableUsersAuthenticator
|
with WritableUsersAuthenticator
|
||||||
with RequestCache
|
|
||||||
|
|
||||||
trait ApiControllerBase extends ControllerBase {
|
trait ApiControllerBase extends ControllerBase {
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ class DashboardController
|
|||||||
with WebHookPullRequestReviewCommentService
|
with WebHookPullRequestReviewCommentService
|
||||||
with MilestonesService
|
with MilestonesService
|
||||||
with UsersAuthenticator
|
with UsersAuthenticator
|
||||||
with RequestCache
|
|
||||||
|
|
||||||
trait DashboardControllerBase extends ControllerBase {
|
trait DashboardControllerBase extends ControllerBase {
|
||||||
self: IssuesService with PullRequestService with RepositoryService with AccountService with UsersAuthenticator =>
|
self: IssuesService with PullRequestService with RepositoryService with AccountService with UsersAuthenticator =>
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ class IndexController
|
|||||||
with AccessTokenService
|
with AccessTokenService
|
||||||
with AccountFederationService
|
with AccountFederationService
|
||||||
with OpenIDConnectService
|
with OpenIDConnectService
|
||||||
with RequestCache
|
|
||||||
|
|
||||||
trait IndexControllerBase extends ControllerBase {
|
trait IndexControllerBase extends ControllerBase {
|
||||||
self: RepositoryService
|
self: RepositoryService
|
||||||
@@ -79,7 +78,7 @@ trait IndexControllerBase extends ControllerBase {
|
|||||||
}
|
}
|
||||||
.getOrElse {
|
.getOrElse {
|
||||||
gitbucket.core.html.index(
|
gitbucket.core.html.index(
|
||||||
getRecentPublicActivities(),
|
getRecentActivities(),
|
||||||
getVisibleRepositories(None, withoutPhysicalInfo = true),
|
getVisibleRepositories(None, withoutPhysicalInfo = true),
|
||||||
showBannerToCreatePersonalAccessToken = false
|
showBannerToCreatePersonalAccessToken = false
|
||||||
)
|
)
|
||||||
@@ -162,7 +161,7 @@ trait IndexControllerBase extends ControllerBase {
|
|||||||
|
|
||||||
get("/activities.atom") {
|
get("/activities.atom") {
|
||||||
contentType = "application/atom+xml; type=feed"
|
contentType = "application/atom+xml; type=feed"
|
||||||
xml.feed(getRecentPublicActivities())
|
xml.feed(getRecentActivities())
|
||||||
}
|
}
|
||||||
|
|
||||||
post("/sidebar-collapse") {
|
post("/sidebar-collapse") {
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ class IssuesController
|
|||||||
with WebHookPullRequestReviewCommentService
|
with WebHookPullRequestReviewCommentService
|
||||||
with CommitsService
|
with CommitsService
|
||||||
with PrioritiesService
|
with PrioritiesService
|
||||||
with RequestCache
|
|
||||||
|
|
||||||
trait IssuesControllerBase extends ControllerBase {
|
trait IssuesControllerBase extends ControllerBase {
|
||||||
self: IssuesService
|
self: IssuesService
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ class PullRequestsController
|
|||||||
with MergeService
|
with MergeService
|
||||||
with ProtectedBranchService
|
with ProtectedBranchService
|
||||||
with PrioritiesService
|
with PrioritiesService
|
||||||
with RequestCache
|
|
||||||
|
|
||||||
trait PullRequestsControllerBase extends ControllerBase {
|
trait PullRequestsControllerBase extends ControllerBase {
|
||||||
self: RepositoryService
|
self: RepositoryService
|
||||||
|
|||||||
@@ -2,14 +2,7 @@ package gitbucket.core.controller
|
|||||||
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
import gitbucket.core.service.{
|
import gitbucket.core.service.{AccountService, ActivityService, PaginationHelper, ReleaseService, RepositoryService}
|
||||||
AccountService,
|
|
||||||
ActivityService,
|
|
||||||
PaginationHelper,
|
|
||||||
ReleaseService,
|
|
||||||
RepositoryService,
|
|
||||||
RequestCache
|
|
||||||
}
|
|
||||||
import gitbucket.core.util._
|
import gitbucket.core.util._
|
||||||
import gitbucket.core.util.Directory._
|
import gitbucket.core.util.Directory._
|
||||||
import gitbucket.core.util.Implicits._
|
import gitbucket.core.util.Implicits._
|
||||||
@@ -29,7 +22,6 @@ class ReleaseController
|
|||||||
with ReadableUsersAuthenticator
|
with ReadableUsersAuthenticator
|
||||||
with ReferrerAuthenticator
|
with ReferrerAuthenticator
|
||||||
with WritableUsersAuthenticator
|
with WritableUsersAuthenticator
|
||||||
with RequestCache
|
|
||||||
|
|
||||||
trait ReleaseControllerBase extends ControllerBase {
|
trait ReleaseControllerBase extends ControllerBase {
|
||||||
self: RepositoryService
|
self: RepositoryService
|
||||||
|
|||||||
@@ -30,10 +30,8 @@ class RepositorySettingsController
|
|||||||
with ProtectedBranchService
|
with ProtectedBranchService
|
||||||
with CommitStatusService
|
with CommitStatusService
|
||||||
with DeployKeyService
|
with DeployKeyService
|
||||||
with ActivityService
|
|
||||||
with OwnerAuthenticator
|
with OwnerAuthenticator
|
||||||
with UsersAuthenticator
|
with UsersAuthenticator
|
||||||
with RequestCache
|
|
||||||
|
|
||||||
trait RepositorySettingsControllerBase extends ControllerBase {
|
trait RepositorySettingsControllerBase extends ControllerBase {
|
||||||
self: RepositoryService
|
self: RepositoryService
|
||||||
@@ -42,7 +40,6 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
|||||||
with ProtectedBranchService
|
with ProtectedBranchService
|
||||||
with CommitStatusService
|
with CommitStatusService
|
||||||
with DeployKeyService
|
with DeployKeyService
|
||||||
with ActivityService
|
|
||||||
with OwnerAuthenticator
|
with OwnerAuthenticator
|
||||||
with UsersAuthenticator =>
|
with UsersAuthenticator =>
|
||||||
|
|
||||||
@@ -100,7 +97,9 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
|||||||
"events" -> webhookEvents,
|
"events" -> webhookEvents,
|
||||||
"ctype" -> label("ctype", text()),
|
"ctype" -> label("ctype", text()),
|
||||||
"token" -> optional(trim(label("token", text(maxlength(100)))))
|
"token" -> optional(trim(label("token", text(maxlength(100)))))
|
||||||
)((url, events, ctype, token) => WebHookForm(url, events, WebHookContentType.valueOf(ctype), token))
|
)(
|
||||||
|
(url, events, ctype, token) => WebHookForm(url, events, WebHookContentType.valueOf(ctype), token)
|
||||||
|
)
|
||||||
|
|
||||||
// for rename repository
|
// for rename repository
|
||||||
case class RenameRepositoryForm(repositoryName: String)
|
case class RenameRepositoryForm(repositoryName: String)
|
||||||
@@ -252,8 +251,7 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
|||||||
* Send the test request to registered web hook URLs.
|
* Send the test request to registered web hook URLs.
|
||||||
*/
|
*/
|
||||||
ajaxPost("/:owner/:repository/settings/hooks/test")(ownerOnly { repository =>
|
ajaxPost("/:owner/:repository/settings/hooks/test")(ownerOnly { repository =>
|
||||||
def _headers(h: Array[org.apache.http.Header]): Array[Array[String]] =
|
def _headers(h: Array[org.apache.http.Header]): Array[Array[String]] = h.map { h =>
|
||||||
h.map { h =>
|
|
||||||
Array(h.getName, h.getValue)
|
Array(h.getName, h.getValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,15 +371,7 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
|||||||
post("/:owner/:repository/settings/rename", renameForm)(ownerOnly { (form, repository) =>
|
post("/:owner/:repository/settings/rename", renameForm)(ownerOnly { (form, repository) =>
|
||||||
if (context.settings.repositoryOperation.rename || context.loginAccount.get.isAdmin) {
|
if (context.settings.repositoryOperation.rename || context.loginAccount.get.isAdmin) {
|
||||||
if (repository.name != form.repositoryName) {
|
if (repository.name != form.repositoryName) {
|
||||||
// Update database and move git repository
|
|
||||||
renameRepository(repository.owner, repository.name, repository.owner, form.repositoryName)
|
renameRepository(repository.owner, repository.name, repository.owner, form.repositoryName)
|
||||||
// Record activity log
|
|
||||||
recordRenameRepositoryActivity(
|
|
||||||
repository.owner,
|
|
||||||
form.repositoryName,
|
|
||||||
repository.name,
|
|
||||||
context.loginAccount.get.userName
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
redirect(s"/${repository.owner}/${form.repositoryName}")
|
redirect(s"/${repository.owner}/${form.repositoryName}")
|
||||||
} else Forbidden()
|
} else Forbidden()
|
||||||
@@ -394,15 +384,7 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
|||||||
if (context.settings.repositoryOperation.transfer || context.loginAccount.get.isAdmin) {
|
if (context.settings.repositoryOperation.transfer || context.loginAccount.get.isAdmin) {
|
||||||
// Change repository owner
|
// Change repository owner
|
||||||
if (repository.owner != form.newOwner) {
|
if (repository.owner != form.newOwner) {
|
||||||
// Update database and move git repository
|
|
||||||
renameRepository(repository.owner, repository.name, form.newOwner, repository.name)
|
renameRepository(repository.owner, repository.name, form.newOwner, repository.name)
|
||||||
// Record activity log
|
|
||||||
recordRenameRepositoryActivity(
|
|
||||||
form.newOwner,
|
|
||||||
repository.name,
|
|
||||||
repository.owner,
|
|
||||||
context.loginAccount.get.userName
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
redirect(s"/${form.newOwner}/${repository.name}")
|
redirect(s"/${form.newOwner}/${repository.name}")
|
||||||
} else Forbidden()
|
} else Forbidden()
|
||||||
@@ -453,8 +435,7 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
|||||||
/**
|
/**
|
||||||
* Provides duplication check for web hook url.
|
* Provides duplication check for web hook url.
|
||||||
*/
|
*/
|
||||||
private def webHook(needExists: Boolean): Constraint =
|
private def webHook(needExists: Boolean): Constraint = new Constraint() {
|
||||||
new Constraint() {
|
|
||||||
override def validate(name: String, value: String, messages: Messages): Option[String] =
|
override def validate(name: String, value: String, messages: Messages): Option[String] =
|
||||||
if (getWebHook(params("owner"), params("repository"), value).isDefined != needExists) {
|
if (getWebHook(params("owner"), params("repository"), value).isDefined != needExists) {
|
||||||
Some(if (needExists) {
|
Some(if (needExists) {
|
||||||
@@ -467,8 +448,7 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private def webhookEvents =
|
private def webhookEvents = new ValueType[Set[WebHook.Event]] {
|
||||||
new ValueType[Set[WebHook.Event]] {
|
|
||||||
def convert(name: String, params: Map[String, Seq[String]], messages: Messages): Set[WebHook.Event] = {
|
def convert(name: String, params: Map[String, Seq[String]], messages: Messages): Set[WebHook.Event] = {
|
||||||
WebHook.Event.values.flatMap { t =>
|
WebHook.Event.values.flatMap { t =>
|
||||||
params.get(name + "." + t.name).map(_ => t)
|
params.get(name + "." + t.name).map(_ => t)
|
||||||
@@ -500,8 +480,7 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
|||||||
/**
|
/**
|
||||||
* Duplicate check for the rename repository name.
|
* Duplicate check for the rename repository name.
|
||||||
*/
|
*/
|
||||||
private def renameRepositoryName: Constraint =
|
private def renameRepositoryName: Constraint = new Constraint() {
|
||||||
new Constraint() {
|
|
||||||
override def validate(
|
override def validate(
|
||||||
name: String,
|
name: String,
|
||||||
value: String,
|
value: String,
|
||||||
@@ -519,9 +498,9 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
private def featureOption: Constraint =
|
private def featureOption: Constraint = new Constraint() {
|
||||||
new Constraint() {
|
|
||||||
override def validate(
|
override def validate(
|
||||||
name: String,
|
name: String,
|
||||||
value: String,
|
value: String,
|
||||||
@@ -534,8 +513,7 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
|||||||
/**
|
/**
|
||||||
* Provides Constraint to validate the repository transfer user.
|
* Provides Constraint to validate the repository transfer user.
|
||||||
*/
|
*/
|
||||||
private def transferUser: Constraint =
|
private def transferUser: Constraint = new Constraint() {
|
||||||
new Constraint() {
|
|
||||||
override def validate(name: String, value: String, messages: Messages): Option[String] =
|
override def validate(name: String, value: String, messages: Messages): Option[String] =
|
||||||
getAccountByUserName(value) match {
|
getAccountByUserName(value) match {
|
||||||
case None => Some("User does not exist.")
|
case None => Some("User does not exist.")
|
||||||
@@ -552,16 +530,11 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private def mergeOptions =
|
private def mergeOptions = new ValueType[Seq[String]] {
|
||||||
new ValueType[Seq[String]] {
|
|
||||||
override def convert(name: String, params: Map[String, Seq[String]], messages: Messages): Seq[String] = {
|
override def convert(name: String, params: Map[String, Seq[String]], messages: Messages): Seq[String] = {
|
||||||
params.getOrElse("mergeOptions", Nil)
|
params.getOrElse("mergeOptions", Nil)
|
||||||
}
|
}
|
||||||
override def validate(
|
override def validate(name: String, params: Map[String, Seq[String]], messages: Messages): Seq[(String, String)] = {
|
||||||
name: String,
|
|
||||||
params: Map[String, Seq[String]],
|
|
||||||
messages: Messages
|
|
||||||
): Seq[(String, String)] = {
|
|
||||||
val mergeOptions = params.getOrElse("mergeOptions", Nil)
|
val mergeOptions = params.getOrElse("mergeOptions", Nil)
|
||||||
if (mergeOptions.isEmpty) {
|
if (mergeOptions.isEmpty) {
|
||||||
Seq("mergeOptions" -> "At least one option must be enabled.")
|
Seq("mergeOptions" -> "At least one option must be enabled.")
|
||||||
|
|||||||
@@ -60,7 +60,6 @@ class RepositoryViewerController
|
|||||||
with WebHookPullRequestService
|
with WebHookPullRequestService
|
||||||
with WebHookPullRequestReviewCommentService
|
with WebHookPullRequestReviewCommentService
|
||||||
with ProtectedBranchService
|
with ProtectedBranchService
|
||||||
with RequestCache
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The repository viewer.
|
* The repository viewer.
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ class WikiController
|
|||||||
with WebHookService
|
with WebHookService
|
||||||
with ReadableUsersAuthenticator
|
with ReadableUsersAuthenticator
|
||||||
with ReferrerAuthenticator
|
with ReferrerAuthenticator
|
||||||
with RequestCache
|
|
||||||
|
|
||||||
trait WikiControllerBase extends ControllerBase {
|
trait WikiControllerBase extends ControllerBase {
|
||||||
self: WikiService
|
self: WikiService
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
package gitbucket.core.model
|
package gitbucket.core.model
|
||||||
|
|
||||||
/**
|
|
||||||
* ActivityComponent has been deprecated, but keep it for binary compatibility.
|
|
||||||
*/
|
|
||||||
@deprecated("ActivityComponent has been deprecated, but keep it for binary compatibility.", "4.34.0")
|
|
||||||
trait ActivityComponent extends TemplateComponent { self: Profile =>
|
trait ActivityComponent extends TemplateComponent { self: Profile =>
|
||||||
import profile.api._
|
import profile.api._
|
||||||
import self._
|
import self._
|
||||||
@@ -11,7 +7,14 @@ trait ActivityComponent extends TemplateComponent { self: Profile =>
|
|||||||
lazy val Activities = TableQuery[Activities]
|
lazy val Activities = TableQuery[Activities]
|
||||||
|
|
||||||
class Activities(tag: Tag) extends Table[Activity](tag, "ACTIVITY") with BasicTemplate {
|
class Activities(tag: Tag) extends Table[Activity](tag, "ACTIVITY") with BasicTemplate {
|
||||||
def * = ???
|
val activityId = column[Int]("ACTIVITY_ID", O AutoInc)
|
||||||
|
val activityUserName = column[String]("ACTIVITY_USER_NAME")
|
||||||
|
val activityType = column[String]("ACTIVITY_TYPE")
|
||||||
|
val message = column[String]("MESSAGE")
|
||||||
|
val additionalInfo = column[String]("ADDITIONAL_INFO")
|
||||||
|
val activityDate = column[java.util.Date]("ACTIVITY_DATE")
|
||||||
|
def * =
|
||||||
|
(userName, repositoryName, activityUserName, activityType, message, additionalInfo.?, activityDate, activityId) <> (Activity.tupled, Activity.unapply)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,5 +26,5 @@ case class Activity(
|
|||||||
message: String,
|
message: String,
|
||||||
additionalInfo: Option[String],
|
additionalInfo: Option[String],
|
||||||
activityDate: java.util.Date,
|
activityDate: java.util.Date,
|
||||||
activityId: String
|
activityId: Int = 0
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ trait CoreProfile
|
|||||||
with Profile
|
with Profile
|
||||||
with AccessTokenComponent
|
with AccessTokenComponent
|
||||||
with AccountComponent
|
with AccountComponent
|
||||||
with ActivityComponent // ActivityComponent has been deprecated, but keep it for binary compatibility
|
with ActivityComponent
|
||||||
with CollaboratorComponent
|
with CollaboratorComponent
|
||||||
with CommitCommentComponent
|
with CommitCommentComponent
|
||||||
with CommitStatusComponent
|
with CommitStatusComponent
|
||||||
|
|||||||
@@ -17,9 +17,7 @@ trait AccountService {
|
|||||||
def authenticate(settings: SystemSettings, userName: String, password: String)(
|
def authenticate(settings: SystemSettings, userName: String, password: String)(
|
||||||
implicit s: Session
|
implicit s: Session
|
||||||
): Option[Account] = {
|
): Option[Account] = {
|
||||||
val account = if (password.isEmpty) {
|
val account = if (settings.ldapAuthentication) {
|
||||||
None
|
|
||||||
} else if (settings.ldapAuthentication) {
|
|
||||||
ldapAuthentication(settings, userName, password)
|
ldapAuthentication(settings, userName, password)
|
||||||
} else {
|
} else {
|
||||||
defaultAuthentication(userName, password)
|
defaultAuthentication(userName, password)
|
||||||
|
|||||||
@@ -3,169 +3,65 @@ package gitbucket.core.service
|
|||||||
import gitbucket.core.model.Activity
|
import gitbucket.core.model.Activity
|
||||||
import gitbucket.core.util.JGitUtil
|
import gitbucket.core.util.JGitUtil
|
||||||
import gitbucket.core.model.Profile._
|
import gitbucket.core.model.Profile._
|
||||||
import gitbucket.core.util.Directory._
|
import gitbucket.core.model.Profile.profile.blockingApi._
|
||||||
import org.json4s._
|
|
||||||
import org.json4s.jackson.Serialization
|
|
||||||
import org.json4s.jackson.Serialization.{read, write}
|
|
||||||
|
|
||||||
import scala.util.Using
|
|
||||||
import java.io.FileOutputStream
|
|
||||||
import java.nio.charset.StandardCharsets
|
|
||||||
import java.util.UUID
|
|
||||||
|
|
||||||
import gitbucket.core.controller.Context
|
|
||||||
import org.apache.commons.io.input.ReversedLinesFileReader
|
|
||||||
|
|
||||||
import scala.collection.mutable.ListBuffer
|
|
||||||
|
|
||||||
trait ActivityService {
|
trait ActivityService {
|
||||||
self: RequestCache =>
|
|
||||||
|
|
||||||
private implicit val formats = Serialization.formats(NoTypeHints)
|
def deleteOldActivities(limit: Int)(implicit s: Session): Int = {
|
||||||
|
Activities.map(_.activityId).sortBy(_ desc).drop(limit).firstOption.map { id =>
|
||||||
private def writeLog(activity: Activity): Unit = {
|
Activities.filter(_.activityId <= id.bind).delete
|
||||||
Using.resource(new FileOutputStream(ActivityLog, true)) { out =>
|
} getOrElse 0
|
||||||
out.write((write(activity) + "\n").getBytes(StandardCharsets.UTF_8))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def getActivitiesByUser(activityUserName: String, isPublic: Boolean)(implicit context: Context): List[Activity] = {
|
def getActivitiesByUser(activityUserName: String, isPublic: Boolean)(implicit s: Session): List[Activity] =
|
||||||
if (!ActivityLog.exists()) {
|
Activities
|
||||||
List.empty
|
.join(Repositories)
|
||||||
|
.on((t1, t2) => t1.byRepository(t2.userName, t2.repositoryName))
|
||||||
|
.filter {
|
||||||
|
case (t1, t2) =>
|
||||||
|
if (isPublic) {
|
||||||
|
(t1.activityUserName === activityUserName.bind) && (t2.isPrivate === false.bind)
|
||||||
} else {
|
} else {
|
||||||
val list = new ListBuffer[Activity]
|
(t1.activityUserName === activityUserName.bind)
|
||||||
Using.resource(new ReversedLinesFileReader(ActivityLog, StandardCharsets.UTF_8)) { reader =>
|
|
||||||
var json: String = null
|
|
||||||
while (list.length < 50 && { json = reader.readLine(); json } != null) {
|
|
||||||
val activity = read[Activity](json)
|
|
||||||
if (activity.activityUserName == activityUserName) {
|
|
||||||
if (isPublic == false) {
|
|
||||||
list += activity
|
|
||||||
} else {
|
|
||||||
if (!getRepositoryInfoFromCache(activity.userName, activity.repositoryName)
|
|
||||||
.map(_.isPrivate)
|
|
||||||
.getOrElse(true)) {
|
|
||||||
list += activity
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
list.toList
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.sortBy { case (t1, t2) => t1.activityId desc }
|
||||||
|
.map { case (t1, t2) => t1 }
|
||||||
|
.take(30)
|
||||||
|
.list
|
||||||
|
|
||||||
def getRecentPublicActivities()(implicit context: Context): List[Activity] = {
|
def getRecentActivities()(implicit s: Session): List[Activity] =
|
||||||
if (!ActivityLog.exists()) {
|
Activities
|
||||||
List.empty
|
.join(Repositories)
|
||||||
} else {
|
.on((t1, t2) => t1.byRepository(t2.userName, t2.repositoryName))
|
||||||
val list = new ListBuffer[Activity]
|
.filter { case (t1, t2) => t2.isPrivate === false.bind }
|
||||||
Using.resource(new ReversedLinesFileReader(ActivityLog, StandardCharsets.UTF_8)) { reader =>
|
.sortBy { case (t1, t2) => t1.activityId desc }
|
||||||
var json: String = null
|
.map { case (t1, t2) => t1 }
|
||||||
while (list.length < 50 && { json = reader.readLine(); json } != null) {
|
.take(30)
|
||||||
val activity = read[Activity](json)
|
.list
|
||||||
if (!getRepositoryInfoFromCache(activity.userName, activity.repositoryName)
|
|
||||||
.map(_.isPrivate)
|
|
||||||
.getOrElse(true)) {
|
|
||||||
list += activity
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
list.toList
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def getRecentActivitiesByOwners(owners: Set[String])(implicit context: Context): List[Activity] = {
|
def getRecentActivitiesByOwners(owners: Set[String])(implicit s: Session): List[Activity] =
|
||||||
if (!ActivityLog.exists()) {
|
Activities
|
||||||
List.empty
|
.join(Repositories)
|
||||||
} else {
|
.on((t1, t2) => t1.byRepository(t2.userName, t2.repositoryName))
|
||||||
val list = new ListBuffer[Activity]
|
.filter { case (t1, t2) => (t2.isPrivate === false.bind) || (t2.userName inSetBind owners) }
|
||||||
Using.resource(new ReversedLinesFileReader(ActivityLog, StandardCharsets.UTF_8)) { reader =>
|
.sortBy { case (t1, t2) => t1.activityId desc }
|
||||||
var json: String = null
|
.map { case (t1, t2) => t1 }
|
||||||
while (list.length < 50 && { json = reader.readLine(); json } != null) {
|
.take(30)
|
||||||
val activity = read[Activity](json)
|
.list
|
||||||
if (owners.contains(activity.userName)) {
|
|
||||||
list += activity
|
|
||||||
} else if (!getRepositoryInfoFromCache(activity.userName, activity.repositoryName)
|
|
||||||
.map(_.isPrivate)
|
|
||||||
.getOrElse(true)) {
|
|
||||||
list += activity
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
list.toList
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def recordCreateRepositoryActivity(userName: String, repositoryName: String, activityUserName: String): Unit = {
|
def recordCreateRepositoryActivity(userName: String, repositoryName: String, activityUserName: String)(
|
||||||
writeLog(
|
implicit s: Session
|
||||||
Activity(
|
): Unit =
|
||||||
|
Activities insert Activity(
|
||||||
userName,
|
userName,
|
||||||
repositoryName,
|
repositoryName,
|
||||||
activityUserName,
|
activityUserName,
|
||||||
"create_repository",
|
"create_repository",
|
||||||
s"[user:${activityUserName}] created [repo:${userName}/${repositoryName}]",
|
s"[user:${activityUserName}] created [repo:${userName}/${repositoryName}]",
|
||||||
None,
|
None,
|
||||||
currentDate,
|
currentDate
|
||||||
UUID.randomUUID().toString
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
def recordDeleteRepositoryActivity(userName: String, repositoryName: String, activityUserName: String): Unit = {
|
|
||||||
writeLog(
|
|
||||||
Activity(
|
|
||||||
userName,
|
|
||||||
repositoryName,
|
|
||||||
activityUserName,
|
|
||||||
"delete_repository",
|
|
||||||
s"[user:${activityUserName}] deleted [repo:${userName}/${repositoryName}]",
|
|
||||||
None,
|
|
||||||
currentDate,
|
|
||||||
UUID.randomUUID().toString
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
def recordTransferRepositoryActivity(
|
|
||||||
userName: String,
|
|
||||||
repositoryName: String,
|
|
||||||
oldUserName: String,
|
|
||||||
activityUserName: String
|
|
||||||
): Unit = {
|
|
||||||
writeLog(
|
|
||||||
Activity(
|
|
||||||
userName,
|
|
||||||
repositoryName,
|
|
||||||
activityUserName,
|
|
||||||
"transfer_repository",
|
|
||||||
s"[user:${activityUserName}] transfered [repo:${oldUserName}/${repositoryName}] to [repo:${userName}/${repositoryName}]",
|
|
||||||
None,
|
|
||||||
currentDate,
|
|
||||||
UUID.randomUUID().toString
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
def recordRenameRepositoryActivity(
|
|
||||||
userName: String,
|
|
||||||
repositoryName: String,
|
|
||||||
oldRepositoryName: String,
|
|
||||||
activityUserName: String
|
|
||||||
): Unit = {
|
|
||||||
writeLog(
|
|
||||||
Activity(
|
|
||||||
userName,
|
|
||||||
repositoryName,
|
|
||||||
activityUserName,
|
|
||||||
"rename_repository",
|
|
||||||
s"[user:${activityUserName}] renamed [repo:${userName}/${oldRepositoryName}] at [repo:${userName}/${repositoryName}]",
|
|
||||||
None,
|
|
||||||
currentDate,
|
|
||||||
UUID.randomUUID().toString
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
def recordCreateIssueActivity(
|
def recordCreateIssueActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
@@ -173,20 +69,16 @@ trait ActivityService {
|
|||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
issueId: Int,
|
issueId: Int,
|
||||||
title: String
|
title: String
|
||||||
): Unit = {
|
)(implicit s: Session): Unit =
|
||||||
writeLog(
|
Activities insert Activity(
|
||||||
Activity(
|
|
||||||
userName,
|
userName,
|
||||||
repositoryName,
|
repositoryName,
|
||||||
activityUserName,
|
activityUserName,
|
||||||
"open_issue",
|
"open_issue",
|
||||||
s"[user:${activityUserName}] opened issue [issue:${userName}/${repositoryName}#${issueId}]",
|
s"[user:${activityUserName}] opened issue [issue:${userName}/${repositoryName}#${issueId}]",
|
||||||
Some(title),
|
Some(title),
|
||||||
currentDate,
|
currentDate
|
||||||
UUID.randomUUID().toString
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
def recordCloseIssueActivity(
|
def recordCloseIssueActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
@@ -194,20 +86,16 @@ trait ActivityService {
|
|||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
issueId: Int,
|
issueId: Int,
|
||||||
title: String
|
title: String
|
||||||
): Unit = {
|
)(implicit s: Session): Unit =
|
||||||
writeLog(
|
Activities insert Activity(
|
||||||
Activity(
|
|
||||||
userName,
|
userName,
|
||||||
repositoryName,
|
repositoryName,
|
||||||
activityUserName,
|
activityUserName,
|
||||||
"close_issue",
|
"close_issue",
|
||||||
s"[user:${activityUserName}] closed issue [issue:${userName}/${repositoryName}#${issueId}]",
|
s"[user:${activityUserName}] closed issue [issue:${userName}/${repositoryName}#${issueId}]",
|
||||||
Some(title),
|
Some(title),
|
||||||
currentDate,
|
currentDate
|
||||||
UUID.randomUUID().toString
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
def recordClosePullRequestActivity(
|
def recordClosePullRequestActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
@@ -215,20 +103,16 @@ trait ActivityService {
|
|||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
issueId: Int,
|
issueId: Int,
|
||||||
title: String
|
title: String
|
||||||
): Unit = {
|
)(implicit s: Session): Unit =
|
||||||
writeLog(
|
Activities insert Activity(
|
||||||
Activity(
|
|
||||||
userName,
|
userName,
|
||||||
repositoryName,
|
repositoryName,
|
||||||
activityUserName,
|
activityUserName,
|
||||||
"close_issue",
|
"close_issue",
|
||||||
s"[user:${activityUserName}] closed pull request [pullreq:${userName}/${repositoryName}#${issueId}]",
|
s"[user:${activityUserName}] closed pull request [pullreq:${userName}/${repositoryName}#${issueId}]",
|
||||||
Some(title),
|
Some(title),
|
||||||
currentDate,
|
currentDate
|
||||||
UUID.randomUUID().toString
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
def recordReopenIssueActivity(
|
def recordReopenIssueActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
@@ -236,20 +120,16 @@ trait ActivityService {
|
|||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
issueId: Int,
|
issueId: Int,
|
||||||
title: String
|
title: String
|
||||||
): Unit = {
|
)(implicit s: Session): Unit =
|
||||||
writeLog(
|
Activities insert Activity(
|
||||||
Activity(
|
|
||||||
userName,
|
userName,
|
||||||
repositoryName,
|
repositoryName,
|
||||||
activityUserName,
|
activityUserName,
|
||||||
"reopen_issue",
|
"reopen_issue",
|
||||||
s"[user:${activityUserName}] reopened issue [issue:${userName}/${repositoryName}#${issueId}]",
|
s"[user:${activityUserName}] reopened issue [issue:${userName}/${repositoryName}#${issueId}]",
|
||||||
Some(title),
|
Some(title),
|
||||||
currentDate,
|
currentDate
|
||||||
UUID.randomUUID().toString
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
def recordReopenPullRequestActivity(
|
def recordReopenPullRequestActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
@@ -257,20 +137,16 @@ trait ActivityService {
|
|||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
issueId: Int,
|
issueId: Int,
|
||||||
title: String
|
title: String
|
||||||
): Unit = {
|
)(implicit s: Session): Unit =
|
||||||
writeLog(
|
Activities insert Activity(
|
||||||
Activity(
|
|
||||||
userName,
|
userName,
|
||||||
repositoryName,
|
repositoryName,
|
||||||
activityUserName,
|
activityUserName,
|
||||||
"reopen_issue",
|
"reopen_issue",
|
||||||
s"[user:${activityUserName}] reopened pull request [issue:${userName}/${repositoryName}#${issueId}]",
|
s"[user:${activityUserName}] reopened pull request [issue:${userName}/${repositoryName}#${issueId}]",
|
||||||
Some(title),
|
Some(title),
|
||||||
currentDate,
|
currentDate
|
||||||
UUID.randomUUID().toString
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
def recordCommentIssueActivity(
|
def recordCommentIssueActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
@@ -278,20 +154,16 @@ trait ActivityService {
|
|||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
issueId: Int,
|
issueId: Int,
|
||||||
comment: String
|
comment: String
|
||||||
): Unit = {
|
)(implicit s: Session): Unit =
|
||||||
writeLog(
|
Activities insert Activity(
|
||||||
Activity(
|
|
||||||
userName,
|
userName,
|
||||||
repositoryName,
|
repositoryName,
|
||||||
activityUserName,
|
activityUserName,
|
||||||
"comment_issue",
|
"comment_issue",
|
||||||
s"[user:${activityUserName}] commented on issue [issue:${userName}/${repositoryName}#${issueId}]",
|
s"[user:${activityUserName}] commented on issue [issue:${userName}/${repositoryName}#${issueId}]",
|
||||||
Some(cut(comment, 200)),
|
Some(cut(comment, 200)),
|
||||||
currentDate,
|
currentDate
|
||||||
UUID.randomUUID().toString
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
def recordCommentPullRequestActivity(
|
def recordCommentPullRequestActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
@@ -299,20 +171,16 @@ trait ActivityService {
|
|||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
issueId: Int,
|
issueId: Int,
|
||||||
comment: String
|
comment: String
|
||||||
): Unit = {
|
)(implicit s: Session): Unit =
|
||||||
writeLog(
|
Activities insert Activity(
|
||||||
Activity(
|
|
||||||
userName,
|
userName,
|
||||||
repositoryName,
|
repositoryName,
|
||||||
activityUserName,
|
activityUserName,
|
||||||
"comment_issue",
|
"comment_issue",
|
||||||
s"[user:${activityUserName}] commented on pull request [pullreq:${userName}/${repositoryName}#${issueId}]",
|
s"[user:${activityUserName}] commented on pull request [pullreq:${userName}/${repositoryName}#${issueId}]",
|
||||||
Some(cut(comment, 200)),
|
Some(cut(comment, 200)),
|
||||||
currentDate,
|
currentDate
|
||||||
UUID.randomUUID().toString
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
def recordCommentCommitActivity(
|
def recordCommentCommitActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
@@ -320,40 +188,32 @@ trait ActivityService {
|
|||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
commitId: String,
|
commitId: String,
|
||||||
comment: String
|
comment: String
|
||||||
): Unit = {
|
)(implicit s: Session): Unit =
|
||||||
writeLog(
|
Activities insert Activity(
|
||||||
Activity(
|
|
||||||
userName,
|
userName,
|
||||||
repositoryName,
|
repositoryName,
|
||||||
activityUserName,
|
activityUserName,
|
||||||
"comment_commit",
|
"comment_commit",
|
||||||
s"[user:${activityUserName}] commented on commit [commit:${userName}/${repositoryName}@${commitId}]",
|
s"[user:${activityUserName}] commented on commit [commit:${userName}/${repositoryName}@${commitId}]",
|
||||||
Some(cut(comment, 200)),
|
Some(cut(comment, 200)),
|
||||||
currentDate,
|
currentDate
|
||||||
UUID.randomUUID().toString
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
def recordCreateWikiPageActivity(
|
def recordCreateWikiPageActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
repositoryName: String,
|
repositoryName: String,
|
||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
pageName: String
|
pageName: String
|
||||||
): Unit = {
|
)(implicit s: Session): Unit =
|
||||||
writeLog(
|
Activities insert Activity(
|
||||||
Activity(
|
|
||||||
userName,
|
userName,
|
||||||
repositoryName,
|
repositoryName,
|
||||||
activityUserName,
|
activityUserName,
|
||||||
"create_wiki",
|
"create_wiki",
|
||||||
s"[user:${activityUserName}] created the [repo:${userName}/${repositoryName}] wiki",
|
s"[user:${activityUserName}] created the [repo:${userName}/${repositoryName}] wiki",
|
||||||
Some(pageName),
|
Some(pageName),
|
||||||
currentDate,
|
currentDate
|
||||||
UUID.randomUUID().toString
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
def recordEditWikiPageActivity(
|
def recordEditWikiPageActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
@@ -361,20 +221,16 @@ trait ActivityService {
|
|||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
pageName: String,
|
pageName: String,
|
||||||
commitId: String
|
commitId: String
|
||||||
): Unit = {
|
)(implicit s: Session): Unit =
|
||||||
writeLog(
|
Activities insert Activity(
|
||||||
Activity(
|
|
||||||
userName,
|
userName,
|
||||||
repositoryName,
|
repositoryName,
|
||||||
activityUserName,
|
activityUserName,
|
||||||
"edit_wiki",
|
"edit_wiki",
|
||||||
s"[user:${activityUserName}] edited the [repo:${userName}/${repositoryName}] wiki",
|
s"[user:${activityUserName}] edited the [repo:${userName}/${repositoryName}] wiki",
|
||||||
Some(pageName + ":" + commitId),
|
Some(pageName + ":" + commitId),
|
||||||
currentDate,
|
currentDate
|
||||||
UUID.randomUUID().toString
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
def recordPushActivity(
|
def recordPushActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
@@ -382,9 +238,8 @@ trait ActivityService {
|
|||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
branchName: String,
|
branchName: String,
|
||||||
commits: List[JGitUtil.CommitInfo]
|
commits: List[JGitUtil.CommitInfo]
|
||||||
): Unit = {
|
)(implicit s: Session): Unit =
|
||||||
writeLog(
|
Activities insert Activity(
|
||||||
Activity(
|
|
||||||
userName,
|
userName,
|
||||||
repositoryName,
|
repositoryName,
|
||||||
activityUserName,
|
activityUserName,
|
||||||
@@ -398,11 +253,8 @@ trait ActivityService {
|
|||||||
}
|
}
|
||||||
.mkString("\n")
|
.mkString("\n")
|
||||||
),
|
),
|
||||||
currentDate,
|
currentDate
|
||||||
UUID.randomUUID().toString
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
def recordCreateTagActivity(
|
def recordCreateTagActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
@@ -410,20 +262,16 @@ trait ActivityService {
|
|||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
tagName: String,
|
tagName: String,
|
||||||
commits: List[JGitUtil.CommitInfo]
|
commits: List[JGitUtil.CommitInfo]
|
||||||
): Unit = {
|
)(implicit s: Session): Unit =
|
||||||
writeLog(
|
Activities insert Activity(
|
||||||
Activity(
|
|
||||||
userName,
|
userName,
|
||||||
repositoryName,
|
repositoryName,
|
||||||
activityUserName,
|
activityUserName,
|
||||||
"create_tag",
|
"create_tag",
|
||||||
s"[user:${activityUserName}] created tag [tag:${userName}/${repositoryName}#${tagName}] at [repo:${userName}/${repositoryName}]",
|
s"[user:${activityUserName}] created tag [tag:${userName}/${repositoryName}#${tagName}] at [repo:${userName}/${repositoryName}]",
|
||||||
None,
|
None,
|
||||||
currentDate,
|
currentDate
|
||||||
UUID.randomUUID().toString
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
def recordDeleteTagActivity(
|
def recordDeleteTagActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
@@ -431,80 +279,61 @@ trait ActivityService {
|
|||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
tagName: String,
|
tagName: String,
|
||||||
commits: List[JGitUtil.CommitInfo]
|
commits: List[JGitUtil.CommitInfo]
|
||||||
): Unit = {
|
)(implicit s: Session): Unit =
|
||||||
writeLog(
|
Activities insert Activity(
|
||||||
Activity(
|
|
||||||
userName,
|
userName,
|
||||||
repositoryName,
|
repositoryName,
|
||||||
activityUserName,
|
activityUserName,
|
||||||
"delete_tag",
|
"delete_tag",
|
||||||
s"[user:${activityUserName}] deleted tag ${tagName} at [repo:${userName}/${repositoryName}]",
|
s"[user:${activityUserName}] deleted tag ${tagName} at [repo:${userName}/${repositoryName}]",
|
||||||
None,
|
None,
|
||||||
currentDate,
|
currentDate
|
||||||
UUID.randomUUID().toString
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
def recordCreateBranchActivity(
|
def recordCreateBranchActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
repositoryName: String,
|
repositoryName: String,
|
||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
branchName: String
|
branchName: String
|
||||||
): Unit = {
|
)(implicit s: Session): Unit =
|
||||||
writeLog(
|
Activities insert Activity(
|
||||||
Activity(
|
|
||||||
userName,
|
userName,
|
||||||
repositoryName,
|
repositoryName,
|
||||||
activityUserName,
|
activityUserName,
|
||||||
"create_branch",
|
"create_branch",
|
||||||
s"[user:${activityUserName}] created branch [branch:${userName}/${repositoryName}#${branchName}] at [repo:${userName}/${repositoryName}]",
|
s"[user:${activityUserName}] created branch [branch:${userName}/${repositoryName}#${branchName}] at [repo:${userName}/${repositoryName}]",
|
||||||
None,
|
None,
|
||||||
currentDate,
|
currentDate
|
||||||
UUID.randomUUID().toString
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
def recordDeleteBranchActivity(
|
def recordDeleteBranchActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
repositoryName: String,
|
repositoryName: String,
|
||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
branchName: String
|
branchName: String
|
||||||
): Unit = {
|
)(implicit s: Session): Unit =
|
||||||
writeLog(
|
Activities insert Activity(
|
||||||
Activity(
|
|
||||||
userName,
|
userName,
|
||||||
repositoryName,
|
repositoryName,
|
||||||
activityUserName,
|
activityUserName,
|
||||||
"delete_branch",
|
"delete_branch",
|
||||||
s"[user:${activityUserName}] deleted branch ${branchName} at [repo:${userName}/${repositoryName}]",
|
s"[user:${activityUserName}] deleted branch ${branchName} at [repo:${userName}/${repositoryName}]",
|
||||||
None,
|
None,
|
||||||
currentDate,
|
currentDate
|
||||||
UUID.randomUUID().toString
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
def recordForkActivity(
|
def recordForkActivity(userName: String, repositoryName: String, activityUserName: String, forkedUserName: String)(
|
||||||
userName: String,
|
implicit s: Session
|
||||||
repositoryName: String,
|
): Unit =
|
||||||
activityUserName: String,
|
Activities insert Activity(
|
||||||
forkedUserName: String
|
|
||||||
): Unit = {
|
|
||||||
writeLog(
|
|
||||||
Activity(
|
|
||||||
userName,
|
userName,
|
||||||
repositoryName,
|
repositoryName,
|
||||||
activityUserName,
|
activityUserName,
|
||||||
"fork",
|
"fork",
|
||||||
s"[user:${activityUserName}] forked [repo:${userName}/${repositoryName}] to [repo:${forkedUserName}/${repositoryName}]",
|
s"[user:${activityUserName}] forked [repo:${userName}/${repositoryName}] to [repo:${forkedUserName}/${repositoryName}]",
|
||||||
None,
|
None,
|
||||||
currentDate,
|
currentDate
|
||||||
UUID.randomUUID().toString
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
def recordPullRequestActivity(
|
def recordPullRequestActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
@@ -512,20 +341,16 @@ trait ActivityService {
|
|||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
issueId: Int,
|
issueId: Int,
|
||||||
title: String
|
title: String
|
||||||
): Unit = {
|
)(implicit s: Session): Unit =
|
||||||
writeLog(
|
Activities insert Activity(
|
||||||
Activity(
|
|
||||||
userName,
|
userName,
|
||||||
repositoryName,
|
repositoryName,
|
||||||
activityUserName,
|
activityUserName,
|
||||||
"open_pullreq",
|
"open_pullreq",
|
||||||
s"[user:${activityUserName}] opened pull request [pullreq:${userName}/${repositoryName}#${issueId}]",
|
s"[user:${activityUserName}] opened pull request [pullreq:${userName}/${repositoryName}#${issueId}]",
|
||||||
Some(title),
|
Some(title),
|
||||||
currentDate,
|
currentDate
|
||||||
UUID.randomUUID().toString
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
def recordMergeActivity(
|
def recordMergeActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
@@ -533,20 +358,16 @@ trait ActivityService {
|
|||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
issueId: Int,
|
issueId: Int,
|
||||||
message: String
|
message: String
|
||||||
): Unit = {
|
)(implicit s: Session): Unit =
|
||||||
writeLog(
|
Activities insert Activity(
|
||||||
Activity(
|
|
||||||
userName,
|
userName,
|
||||||
repositoryName,
|
repositoryName,
|
||||||
activityUserName,
|
activityUserName,
|
||||||
"merge_pullreq",
|
"merge_pullreq",
|
||||||
s"[user:${activityUserName}] merged pull request [pullreq:${userName}/${repositoryName}#${issueId}]",
|
s"[user:${activityUserName}] merged pull request [pullreq:${userName}/${repositoryName}#${issueId}]",
|
||||||
Some(message),
|
Some(message),
|
||||||
currentDate,
|
currentDate
|
||||||
UUID.randomUUID().toString
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
def recordReleaseActivity(
|
def recordReleaseActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
@@ -554,20 +375,16 @@ trait ActivityService {
|
|||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
releaseName: String,
|
releaseName: String,
|
||||||
tagName: String
|
tagName: String
|
||||||
): Unit = {
|
)(implicit s: Session): Unit =
|
||||||
writeLog(
|
Activities insert Activity(
|
||||||
Activity(
|
|
||||||
userName,
|
userName,
|
||||||
repositoryName,
|
repositoryName,
|
||||||
activityUserName,
|
activityUserName,
|
||||||
"release",
|
"release",
|
||||||
s"[user:${activityUserName}] released [release:${userName}/${repositoryName}/${tagName}:${releaseName}] at [repo:${userName}/${repositoryName}]",
|
s"[user:${activityUserName}] released [release:${userName}/${repositoryName}/${tagName}:${releaseName}] at [repo:${userName}/${repositoryName}]",
|
||||||
None,
|
None,
|
||||||
currentDate,
|
currentDate
|
||||||
UUID.randomUUID().toString
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private def cut(value: String, length: Int): String =
|
private def cut(value: String, length: Int): String =
|
||||||
if (value.length > length) value.substring(0, length) + "..." else value
|
if (value.length > length) value.substring(0, length) + "..." else value
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package gitbucket.core.service
|
package gitbucket.core.service
|
||||||
|
|
||||||
|
import gitbucket.core.api.JsonFormat
|
||||||
import gitbucket.core.controller.Context
|
import gitbucket.core.controller.Context
|
||||||
import gitbucket.core.util._
|
import gitbucket.core.util._
|
||||||
import gitbucket.core.util.SyntaxSugars._
|
import gitbucket.core.util.SyntaxSugars._
|
||||||
@@ -8,11 +9,14 @@ import gitbucket.core.model.Profile._
|
|||||||
import gitbucket.core.model.Profile.profile.blockingApi._
|
import gitbucket.core.model.Profile.profile.blockingApi._
|
||||||
import gitbucket.core.model.Profile.dateColumnType
|
import gitbucket.core.model.Profile.dateColumnType
|
||||||
import gitbucket.core.plugin.PluginRegistry
|
import gitbucket.core.plugin.PluginRegistry
|
||||||
|
import gitbucket.core.service.WebHookService.WebHookPushPayload
|
||||||
import gitbucket.core.util.Directory.{getRepositoryDir, getRepositoryFilesDir, getTemporaryDir, getWikiRepositoryDir}
|
import gitbucket.core.util.Directory.{getRepositoryDir, getRepositoryFilesDir, getTemporaryDir, getWikiRepositoryDir}
|
||||||
import gitbucket.core.util.JGitUtil.FileInfo
|
import gitbucket.core.util.JGitUtil.{CommitInfo, FileInfo}
|
||||||
import org.apache.commons.io.FileUtils
|
import org.apache.commons.io.FileUtils
|
||||||
import org.eclipse.jgit.api.Git
|
import org.eclipse.jgit.api.Git
|
||||||
|
import org.eclipse.jgit.dircache.{DirCache, DirCacheBuilder}
|
||||||
import org.eclipse.jgit.lib.{Repository => _, _}
|
import org.eclipse.jgit.lib.{Repository => _, _}
|
||||||
|
import org.eclipse.jgit.transport.{ReceiveCommand, ReceivePack}
|
||||||
import scala.util.Using
|
import scala.util.Using
|
||||||
|
|
||||||
trait RepositoryService {
|
trait RepositoryService {
|
||||||
@@ -115,6 +119,15 @@ trait RepositoryService {
|
|||||||
}
|
}
|
||||||
.update(newUserName, newRepositoryName)
|
.update(newUserName, newRepositoryName)
|
||||||
|
|
||||||
|
// Updates activity fk before deleting repository because activity is sorted by activityId
|
||||||
|
// and it can't be changed by deleting-and-inserting record.
|
||||||
|
Activities.filter(_.byRepository(oldUserName, oldRepositoryName)).list.foreach { activity =>
|
||||||
|
Activities
|
||||||
|
.filter(_.activityId === activity.activityId.bind)
|
||||||
|
.map(x => (x.userName, x.repositoryName))
|
||||||
|
.update(newUserName, newRepositoryName)
|
||||||
|
}
|
||||||
|
|
||||||
deleteRepositoryOnModel(oldUserName, oldRepositoryName)
|
deleteRepositoryOnModel(oldUserName, oldRepositoryName)
|
||||||
|
|
||||||
RepositoryWebHooks.insertAll(
|
RepositoryWebHooks.insertAll(
|
||||||
@@ -200,6 +213,50 @@ trait RepositoryService {
|
|||||||
collaborators.map(_.copy(userName = newUserName, repositoryName = newRepositoryName)): _*
|
collaborators.map(_.copy(userName = newUserName, repositoryName = newRepositoryName)): _*
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Update activity messages
|
||||||
|
Activities
|
||||||
|
.filter { t =>
|
||||||
|
(t.message like s"%:${oldUserName}/${oldRepositoryName}]%") ||
|
||||||
|
(t.message like s"%:${oldUserName}/${oldRepositoryName}#%") ||
|
||||||
|
(t.message like s"%:${oldUserName}/${oldRepositoryName}@%")
|
||||||
|
}
|
||||||
|
.map { t =>
|
||||||
|
t.activityId -> t.message
|
||||||
|
}
|
||||||
|
.list
|
||||||
|
.foreach {
|
||||||
|
case (activityId, message) =>
|
||||||
|
Activities
|
||||||
|
.filter(_.activityId === activityId.bind)
|
||||||
|
.map(_.message)
|
||||||
|
.update(
|
||||||
|
message
|
||||||
|
.replace(
|
||||||
|
s"[repo:${oldUserName}/${oldRepositoryName}]",
|
||||||
|
s"[repo:${newUserName}/${newRepositoryName}]"
|
||||||
|
)
|
||||||
|
.replace(
|
||||||
|
s"[branch:${oldUserName}/${oldRepositoryName}#",
|
||||||
|
s"[branch:${newUserName}/${newRepositoryName}#"
|
||||||
|
)
|
||||||
|
.replace(
|
||||||
|
s"[tag:${oldUserName}/${oldRepositoryName}#",
|
||||||
|
s"[tag:${newUserName}/${newRepositoryName}#"
|
||||||
|
)
|
||||||
|
.replace(
|
||||||
|
s"[pullreq:${oldUserName}/${oldRepositoryName}#",
|
||||||
|
s"[pullreq:${newUserName}/${newRepositoryName}#"
|
||||||
|
)
|
||||||
|
.replace(
|
||||||
|
s"[issue:${oldUserName}/${oldRepositoryName}#",
|
||||||
|
s"[issue:${newUserName}/${newRepositoryName}#"
|
||||||
|
)
|
||||||
|
.replace(
|
||||||
|
s"[commit:${oldUserName}/${oldRepositoryName}@",
|
||||||
|
s"[commit:${newUserName}/${newRepositoryName}@"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
// Move git repository
|
// Move git repository
|
||||||
defining(getRepositoryDir(oldUserName, oldRepositoryName)) { dir =>
|
defining(getRepositoryDir(oldUserName, oldRepositoryName)) { dir =>
|
||||||
if (dir.isDirectory) {
|
if (dir.isDirectory) {
|
||||||
@@ -247,7 +304,7 @@ trait RepositoryService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private def deleteRepositoryOnModel(userName: String, repositoryName: String)(implicit s: Session): Unit = {
|
private def deleteRepositoryOnModel(userName: String, repositoryName: String)(implicit s: Session): Unit = {
|
||||||
// Activities.filter(_.byRepository(userName, repositoryName)).delete
|
Activities.filter(_.byRepository(userName, repositoryName)).delete
|
||||||
Collaborators.filter(_.byRepository(userName, repositoryName)).delete
|
Collaborators.filter(_.byRepository(userName, repositoryName)).delete
|
||||||
CommitComments.filter(_.byRepository(userName, repositoryName)).delete
|
CommitComments.filter(_.byRepository(userName, repositoryName)).delete
|
||||||
IssueLabels.filter(_.byRepository(userName, repositoryName)).delete
|
IssueLabels.filter(_.byRepository(userName, repositoryName)).delete
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
package gitbucket.core.service
|
package gitbucket.core.service
|
||||||
|
|
||||||
import gitbucket.core.model.{Account, Issue, Repository, Session}
|
import gitbucket.core.model.{Session, Issue, Account}
|
||||||
import gitbucket.core.util.Implicits
|
import gitbucket.core.util.Implicits
|
||||||
import gitbucket.core.controller.Context
|
import gitbucket.core.controller.Context
|
||||||
import Implicits.request2Session
|
import Implicits.request2Session
|
||||||
import gitbucket.core.model.Profile.{Accounts, Repositories}
|
|
||||||
import gitbucket.core.model.Profile.profile.blockingApi._
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This service is used for a view helper mainly.
|
* This service is used for a view helper mainly.
|
||||||
@@ -25,41 +23,21 @@ trait RequestCache
|
|||||||
private implicit def context2Session(implicit context: Context): Session =
|
private implicit def context2Session(implicit context: Context): Session =
|
||||||
request2Session(context.request)
|
request2Session(context.request)
|
||||||
|
|
||||||
def getIssueFromCache(userName: String, repositoryName: String, issueId: String)(
|
def getIssue(userName: String, repositoryName: String, issueId: String)(implicit context: Context): Option[Issue] = {
|
||||||
implicit context: Context
|
|
||||||
): Option[Issue] = {
|
|
||||||
context.cache(s"issue.${userName}/${repositoryName}#${issueId}") {
|
context.cache(s"issue.${userName}/${repositoryName}#${issueId}") {
|
||||||
super.getIssue(userName, repositoryName, issueId)
|
super.getIssue(userName, repositoryName, issueId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def getAccountByUserNameFromCache(userName: String)(implicit context: Context): Option[Account] = {
|
def getAccountByUserName(userName: String)(implicit context: Context): Option[Account] = {
|
||||||
context.cache(s"account.${userName}") {
|
context.cache(s"account.${userName}") {
|
||||||
super.getAccountByUserName(userName)
|
super.getAccountByUserName(userName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def getAccountByMailAddressFromCache(mailAddress: String)(implicit context: Context): Option[Account] = {
|
def getAccountByMailAddress(mailAddress: String)(implicit context: Context): Option[Account] = {
|
||||||
context.cache(s"account.${mailAddress}") {
|
context.cache(s"account.${mailAddress}") {
|
||||||
super.getAccountByMailAddress(mailAddress)
|
super.getAccountByMailAddress(mailAddress)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
.map {
|
|
||||||
case (t1, t2) => t1
|
|
||||||
}
|
|
||||||
.firstOption
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -240,8 +240,7 @@ class CommitLogHook(owner: String, repository: String, pusher: String, baseUrl:
|
|||||||
with WebHookPullRequestService
|
with WebHookPullRequestService
|
||||||
with WebHookPullRequestReviewCommentService
|
with WebHookPullRequestReviewCommentService
|
||||||
with CommitsService
|
with CommitsService
|
||||||
with SystemSettingsService
|
with SystemSettingsService {
|
||||||
with RequestCache {
|
|
||||||
|
|
||||||
private val logger = LoggerFactory.getLogger(classOf[CommitLogHook])
|
private val logger = LoggerFactory.getLogger(classOf[CommitLogHook])
|
||||||
private var existIds: Seq[String] = Nil
|
private var existIds: Seq[String] = Nil
|
||||||
|
|||||||
@@ -2,10 +2,11 @@ package gitbucket.core.servlet
|
|||||||
|
|
||||||
import java.io.{File, FileOutputStream}
|
import java.io.{File, FileOutputStream}
|
||||||
|
|
||||||
|
import akka.event.Logging
|
||||||
import com.typesafe.config.ConfigFactory
|
import com.typesafe.config.ConfigFactory
|
||||||
import gitbucket.core.GitBucketCoreModule
|
import gitbucket.core.GitBucketCoreModule
|
||||||
import gitbucket.core.plugin.PluginRegistry
|
import gitbucket.core.plugin.PluginRegistry
|
||||||
import gitbucket.core.service.SystemSettingsService
|
import gitbucket.core.service.{ActivityService, SystemSettingsService}
|
||||||
import gitbucket.core.util.DatabaseConfig
|
import gitbucket.core.util.DatabaseConfig
|
||||||
import gitbucket.core.util.Directory._
|
import gitbucket.core.util.Directory._
|
||||||
import gitbucket.core.util.JDBCUtil._
|
import gitbucket.core.util.JDBCUtil._
|
||||||
@@ -20,6 +21,8 @@ import javax.servlet.{ServletContextEvent, ServletContextListener}
|
|||||||
|
|
||||||
import org.apache.commons.io.{FileUtils, IOUtils}
|
import org.apache.commons.io.{FileUtils, IOUtils}
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
import akka.actor.{Actor, ActorSystem, Props}
|
||||||
|
import com.typesafe.akka.extension.quartz.QuartzSchedulerExtension
|
||||||
|
|
||||||
import scala.jdk.CollectionConverters._
|
import scala.jdk.CollectionConverters._
|
||||||
import scala.util.Using
|
import scala.util.Using
|
||||||
@@ -32,23 +35,23 @@ class InitializeListener extends ServletContextListener with SystemSettingsServi
|
|||||||
|
|
||||||
private val logger = LoggerFactory.getLogger(classOf[InitializeListener])
|
private val logger = LoggerFactory.getLogger(classOf[InitializeListener])
|
||||||
|
|
||||||
// // ActorSystem for Quartz scheduler
|
// ActorSystem for Quartz scheduler
|
||||||
// private val system = ActorSystem(
|
private val system = ActorSystem(
|
||||||
// "job",
|
"job",
|
||||||
// ConfigFactory.parseString("""
|
ConfigFactory.parseString("""
|
||||||
// |akka {
|
|akka {
|
||||||
// | daemonic = on
|
| daemonic = on
|
||||||
// | coordinated-shutdown.run-by-jvm-shutdown-hook = off
|
| coordinated-shutdown.run-by-jvm-shutdown-hook = off
|
||||||
// | quartz {
|
| quartz {
|
||||||
// | schedules {
|
| schedules {
|
||||||
// | Daily {
|
| Daily {
|
||||||
// | expression = "0 0 0 * * ?"
|
| expression = "0 0 0 * * ?"
|
||||||
// | }
|
| }
|
||||||
// | }
|
| }
|
||||||
// | }
|
| }
|
||||||
// |}
|
|}
|
||||||
// """.stripMargin)
|
""".stripMargin)
|
||||||
// )
|
)
|
||||||
|
|
||||||
override def contextInitialized(event: ServletContextEvent): Unit = {
|
override def contextInitialized(event: ServletContextEvent): Unit = {
|
||||||
val dataDir = event.getServletContext.getInitParameter("gitbucket.home")
|
val dataDir = event.getServletContext.getInitParameter("gitbucket.home")
|
||||||
@@ -92,10 +95,10 @@ class InitializeListener extends ServletContextListener with SystemSettingsServi
|
|||||||
PluginRegistry.initialize(event.getServletContext, loadSystemSettings(), conn)
|
PluginRegistry.initialize(event.getServletContext, loadSystemSettings(), conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
// // Start Quartz scheduler
|
// Start Quartz scheduler
|
||||||
// val scheduler = QuartzSchedulerExtension(system)
|
val scheduler = QuartzSchedulerExtension(system)
|
||||||
//
|
|
||||||
// scheduler.schedule("Daily", system.actorOf(Props[DeleteOldActivityActor]), "DeleteOldActivity")
|
scheduler.schedule("Daily", system.actorOf(Props[DeleteOldActivityActor]), "DeleteOldActivity")
|
||||||
}
|
}
|
||||||
|
|
||||||
private def checkVersion(manager: JDBCVersionManager, conn: java.sql.Connection): Unit = {
|
private def checkVersion(manager: JDBCVersionManager, conn: java.sql.Connection): Unit = {
|
||||||
@@ -169,8 +172,8 @@ class InitializeListener extends ServletContextListener with SystemSettingsServi
|
|||||||
}
|
}
|
||||||
|
|
||||||
override def contextDestroyed(event: ServletContextEvent): Unit = {
|
override def contextDestroyed(event: ServletContextEvent): Unit = {
|
||||||
// // Shutdown Quartz scheduler
|
// Shutdown Quartz scheduler
|
||||||
// system.terminate()
|
system.terminate()
|
||||||
// Shutdown plugins
|
// Shutdown plugins
|
||||||
PluginRegistry.shutdown(event.getServletContext, loadSystemSettings())
|
PluginRegistry.shutdown(event.getServletContext, loadSystemSettings())
|
||||||
// Close datasource
|
// Close datasource
|
||||||
@@ -178,3 +181,21 @@ class InitializeListener extends ServletContextListener with SystemSettingsServi
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DeleteOldActivityActor extends Actor with SystemSettingsService with ActivityService {
|
||||||
|
|
||||||
|
private val logger = Logging(context.system, this)
|
||||||
|
|
||||||
|
def receive = {
|
||||||
|
case s: String => {
|
||||||
|
loadSystemSettings().activityLogLimit.foreach { limit =>
|
||||||
|
if (limit > 0) {
|
||||||
|
Database() withTransaction { implicit session =>
|
||||||
|
val rows = deleteOldActivities(limit)
|
||||||
|
logger.info(s"Deleted ${rows} activity logs")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -29,8 +29,6 @@ object Directory {
|
|||||||
|
|
||||||
val GitBucketConf = new File(GitBucketHome, "gitbucket.conf")
|
val GitBucketConf = new File(GitBucketHome, "gitbucket.conf")
|
||||||
|
|
||||||
val ActivityLog = new File(GitBucketHome, "activity.log")
|
|
||||||
|
|
||||||
val RepositoryHome = s"${GitBucketHome}/repositories"
|
val RepositoryHome = s"${GitBucketHome}/repositories"
|
||||||
|
|
||||||
val DatabaseHome = s"${GitBucketHome}/data"
|
val DatabaseHome = s"${GitBucketHome}/data"
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ trait AvatarImageProvider { self: RequestCache =>
|
|||||||
|
|
||||||
val src = if (mailAddress.isEmpty) {
|
val src = if (mailAddress.isEmpty) {
|
||||||
// by user name
|
// by user name
|
||||||
getAccountByUserNameFromCache(userName).map { account =>
|
getAccountByUserName(userName).map { account =>
|
||||||
if (account.image.isEmpty && context.settings.gravatar) {
|
if (account.image.isEmpty && context.settings.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 {
|
} else {
|
||||||
@@ -28,7 +28,7 @@ trait AvatarImageProvider { self: RequestCache =>
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// by mail address
|
// by mail address
|
||||||
getAccountByMailAddressFromCache(mailAddress).map { account =>
|
getAccountByMailAddress(mailAddress).map { account =>
|
||||||
if (account.image.isEmpty && context.settings.gravatar) {
|
if (account.image.isEmpty && context.settings.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 {
|
} else {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ trait LinkConverter { self: RequestCache =>
|
|||||||
val userName = repository.repository.userName
|
val userName = repository.repository.userName
|
||||||
val repositoryName = repository.repository.repositoryName
|
val repositoryName = repository.repository.repositoryName
|
||||||
|
|
||||||
getIssueFromCache(userName, repositoryName, issueId.toString) match {
|
getIssue(userName, repositoryName, issueId.toString) match {
|
||||||
case Some(issue) =>
|
case Some(issue) =>
|
||||||
s"""<a href="${context.path}/${userName}/${repositoryName}/${if (issue.isPullRequest) "pull" else "issues"}/${issueId}"><strong>${StringUtil
|
s"""<a href="${context.path}/${userName}/${repositoryName}/${if (issue.isPullRequest) "pull" else "issues"}/${issueId}"><strong>${StringUtil
|
||||||
.escapeHtml(title)}</strong> #${issueId}</a>"""
|
.escapeHtml(title)}</strong> #${issueId}</a>"""
|
||||||
@@ -43,7 +43,7 @@ trait LinkConverter { self: RequestCache =>
|
|||||||
escaped
|
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 =>
|
.replaceBy("(?<=(^|\\W))([a-zA-Z0-9\\-_]+)/([a-zA-Z0-9\\-_\\.]+)@([a-f0-9]{40})(?=(\\W|$))".r) { m =>
|
||||||
getAccountByUserNameFromCache(m.group(2)).map { _ =>
|
getAccountByUserName(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(
|
s"""<code><a href="${context.path}/${m.group(2)}/${m.group(3)}/commit/${m.group(4)}">${m.group(2)}/${m.group(
|
||||||
3
|
3
|
||||||
)}@${m.group(4).substring(0, 7)}</a></code>"""
|
)}@${m.group(4).substring(0, 7)}</a></code>"""
|
||||||
@@ -53,7 +53,7 @@ trait LinkConverter { self: RequestCache =>
|
|||||||
// convert username/project#Num to link
|
// convert username/project#Num to link
|
||||||
.replaceBy(("(?<=(^|\\W))([a-zA-Z0-9\\-_]+)/([a-zA-Z0-9\\-_\\.]+)" + issueIdPrefix + "([0-9]+)(?=(\\W|$))").r) {
|
.replaceBy(("(?<=(^|\\W))([a-zA-Z0-9\\-_]+)/([a-zA-Z0-9\\-_\\.]+)" + issueIdPrefix + "([0-9]+)(?=(\\W|$))").r) {
|
||||||
m =>
|
m =>
|
||||||
getIssueFromCache(m.group(2), m.group(3), m.group(4)) match {
|
getIssue(m.group(2), m.group(3), m.group(4)) match {
|
||||||
case Some(issue) if (issue.isPullRequest) =>
|
case Some(issue) if (issue.isPullRequest) =>
|
||||||
Some(s"""<a href="${context.path}/${m.group(2)}/${m.group(3)}/pull/${m.group(4)}">${m.group(2)}/${m.group(
|
Some(s"""<a href="${context.path}/${m.group(2)}/${m.group(3)}/pull/${m.group(4)}">${m.group(2)}/${m.group(
|
||||||
3
|
3
|
||||||
@@ -68,7 +68,7 @@ trait LinkConverter { self: RequestCache =>
|
|||||||
|
|
||||||
// convert username@SHA to link
|
// convert username@SHA to link
|
||||||
.replaceBy(("(?<=(^|\\W))([a-zA-Z0-9\\-_]+)@([a-f0-9]{40})(?=(\\W|$))").r) { m =>
|
.replaceBy(("(?<=(^|\\W))([a-zA-Z0-9\\-_]+)@([a-f0-9]{40})(?=(\\W|$))").r) { m =>
|
||||||
getAccountByUserNameFromCache(m.group(2)).map { _ =>
|
getAccountByUserName(m.group(2)).map { _ =>
|
||||||
s"""<code><a href="${context.path}/${m.group(2)}/${repository.name}/commit/${m.group(3)}">${m.group(2)}@${m
|
s"""<code><a href="${context.path}/${m.group(2)}/${repository.name}/commit/${m.group(3)}">${m.group(2)}@${m
|
||||||
.group(3)
|
.group(3)
|
||||||
.substring(0, 7)}</a></code>"""
|
.substring(0, 7)}</a></code>"""
|
||||||
@@ -77,7 +77,7 @@ trait LinkConverter { self: RequestCache =>
|
|||||||
|
|
||||||
// convert username#Num to link
|
// convert username#Num to link
|
||||||
.replaceBy(("(?<=(^|\\W))([a-zA-Z0-9\\-_]+)" + issueIdPrefix + "([0-9]+)(?=(\\W|$))").r) { m =>
|
.replaceBy(("(?<=(^|\\W))([a-zA-Z0-9\\-_]+)" + issueIdPrefix + "([0-9]+)(?=(\\W|$))").r) { m =>
|
||||||
getIssueFromCache(m.group(2), repository.name, m.group(3)) match {
|
getIssue(m.group(2), repository.name, m.group(3)) match {
|
||||||
case Some(issue) if (issue.isPullRequest) =>
|
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
|
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>""")
|
||||||
@@ -92,7 +92,7 @@ trait LinkConverter { self: RequestCache =>
|
|||||||
// convert issue id to link
|
// convert issue id to link
|
||||||
.replaceBy(("(?<=(^|\\W))(GH-|(?<!&)" + issueIdPrefix + ")([0-9]+)(?=(\\W|$))").r) { m =>
|
.replaceBy(("(?<=(^|\\W))(GH-|(?<!&)" + issueIdPrefix + ")([0-9]+)(?=(\\W|$))").r) { m =>
|
||||||
val prefix = if (m.group(2) == "issue:") "#" else m.group(2)
|
val prefix = if (m.group(2) == "issue:") "#" else m.group(2)
|
||||||
getIssueFromCache(repository.owner, repository.name, m.group(3)) match {
|
getIssue(repository.owner, repository.name, m.group(3)) match {
|
||||||
case Some(issue) if (issue.isPullRequest) =>
|
case Some(issue) if (issue.isPullRequest) =>
|
||||||
Some(s"""<a href="${context.path}/${repository.owner}/${repository.name}/pull/${m.group(3)}">${prefix}${m
|
Some(s"""<a href="${context.path}/${repository.owner}/${repository.name}/pull/${m.group(3)}">${prefix}${m
|
||||||
.group(3)}</a>""")
|
.group(3)}</a>""")
|
||||||
@@ -106,7 +106,7 @@ trait LinkConverter { self: RequestCache =>
|
|||||||
|
|
||||||
// convert @username to link
|
// convert @username to link
|
||||||
.replaceBy("(?<=(^|\\W))@([a-zA-Z0-9\\-_\\.]+)(?=(\\W|$))".r) { m =>
|
.replaceBy("(?<=(^|\\W))@([a-zA-Z0-9\\-_\\.]+)(?=(\\W|$))".r) { m =>
|
||||||
getAccountByUserNameFromCache(m.group(2)).map { _ =>
|
getAccountByUserName(m.group(2)).map { _ =>
|
||||||
s"""<a href="${context.path}/${m.group(2)}">@${m.group(2)}</a>"""
|
s"""<a href="${context.path}/${m.group(2)}">@${m.group(2)}</a>"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package gitbucket.core.view
|
|||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.{Date, Locale, TimeZone}
|
import java.util.{Date, Locale, TimeZone}
|
||||||
|
|
||||||
|
import com.nimbusds.jose.util.JSONObjectUtils
|
||||||
import gitbucket.core.controller.Context
|
import gitbucket.core.controller.Context
|
||||||
import gitbucket.core.model.CommitState
|
import gitbucket.core.model.CommitState
|
||||||
import gitbucket.core.model.PullRequest
|
import gitbucket.core.model.PullRequest
|
||||||
@@ -195,7 +196,7 @@ object helpers extends AvatarImageProvider with LinkConverter with RequestCache
|
|||||||
|
|
||||||
import scala.util.matching.Regex._
|
import scala.util.matching.Regex._
|
||||||
implicit class RegexReplaceString(private val s: String) extends AnyVal {
|
implicit class RegexReplaceString(private val s: String) extends AnyVal {
|
||||||
def replaceAll(pattern: String)(replacer: Match => String): String = {
|
def replaceAll(pattern: String, replacer: (Match) => String): String = {
|
||||||
pattern.r.replaceAllIn(s, (m: Match) => replacer(m).replace("$", "\\$"))
|
pattern.r.replaceAllIn(s, (m: Match) => replacer(m).replace("$", "\\$"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -203,64 +204,50 @@ object helpers extends AvatarImageProvider with LinkConverter with RequestCache
|
|||||||
/**
|
/**
|
||||||
* Convert link notations in the activity message.
|
* Convert link notations in the activity message.
|
||||||
*/
|
*/
|
||||||
// format: off
|
|
||||||
def activityMessage(message: String)(implicit context: Context): Html =
|
def activityMessage(message: String)(implicit context: Context): Html =
|
||||||
Html(
|
Html(
|
||||||
message
|
message
|
||||||
.replaceAll("\\[issue:([^\\s]+?)/([^\\s]+?)#((\\d+))\\]"){ m =>
|
.replaceAll(
|
||||||
if (getRepositoryInfoFromCache(m.group(1), m.group(2)).isDefined) {
|
"\\[issue:([^\\s]+?)/([^\\s]+?)#((\\d+))\\]",
|
||||||
s"""<a href="${context.path}/${m.group(1)}/${m.group(2)}/issues/${m.group(3)}">${m.group(1)}/${m.group(2)}#${m.group(3)}</a>"""
|
s"""<a href="${context.path}/$$1/$$2/issues/$$3">$$1/$$2#$$3</a>"""
|
||||||
} else {
|
)
|
||||||
s"${m.group(1)}/${m.group(2)}#${m.group(3)}"
|
.replaceAll(
|
||||||
}
|
"\\[pullreq:([^\\s]+?)/([^\\s]+?)#((\\d+))\\]",
|
||||||
}
|
s"""<a href="${context.path}/$$1/$$2/pull/$$3">$$1/$$2#$$3</a>"""
|
||||||
.replaceAll("\\[pullreq:([^\\s]+?)/([^\\s]+?)#((\\d+))\\]"){ m =>
|
)
|
||||||
if (getRepositoryInfoFromCache(m.group(1), m.group(2)).isDefined) {
|
.replaceAll("\\[repo:([^\\s]+?)/([^\\s]+?)\\]", s"""<a href="${context.path}/$$1/$$2\">$$1/$$2</a>""")
|
||||||
s"""<a href="${context.path}/${m.group(1)}/${m.group(2)}/pull/${m.group(3)}">${m.group(1)}/${m.group(2)}#${m.group(3)}</a>"""
|
.replaceAll(
|
||||||
} else {
|
"\\[branch:([^\\s]+?)/([^\\s]+?)#([^\\s]+?)\\]",
|
||||||
s"${m.group(1)}/${m.group(2)}#${m.group(3)}"
|
(m: Match) =>
|
||||||
}
|
s"""<a href="${context.path}/${m.group(1)}/${m.group(2)}/tree/${encodeRefName(m.group(3))}">${StringUtil
|
||||||
}
|
.escapeHtml(
|
||||||
.replaceAll("\\[repo:([^\\s]+?)/([^\\s]+?)\\]") { m =>
|
m.group(3)
|
||||||
if (getRepositoryInfoFromCache(m.group(1), m.group(2)).isDefined) {
|
)}</a>"""
|
||||||
s"""<a href="${context.path}/${m.group(1)}/${m.group(2)}">${m.group(1)}/${m.group(2)}</a>"""
|
)
|
||||||
} else {
|
.replaceAll(
|
||||||
s"${m.group(1)}/${m.group(2)}"
|
"\\[tag:([^\\s]+?)/([^\\s]+?)#([^\\s]+?)\\]",
|
||||||
}
|
(m: Match) =>
|
||||||
}
|
s"""<a href="${context.path}/${m.group(1)}/${m.group(2)}/tree/${encodeRefName(m.group(3))}">${StringUtil
|
||||||
.replaceAll("\\[branch:([^\\s]+?)/([^\\s]+?)#([^\\s]+?)\\]") { m =>
|
.escapeHtml(
|
||||||
if (getRepositoryInfoFromCache(m.group(1), m.group(2)).isDefined) {
|
m.group(3)
|
||||||
s"""<a href="${context.path}/${m.group(1)}/${m.group(2)}/tree/${encodeRefName(m.group(3))}">${StringUtil.escapeHtml(m.group(3))}</a>"""
|
)}</a>"""
|
||||||
} else {
|
)
|
||||||
StringUtil.escapeHtml(m.group(3))
|
.replaceAll("\\[user:([^\\s]+?)\\]", (m: Match) => user(m.group(1)).body)
|
||||||
}
|
.replaceAll(
|
||||||
}
|
"\\[commit:([^\\s]+?)/([^\\s]+?)\\@([^\\s]+?)\\]",
|
||||||
.replaceAll("\\[tag:([^\\s]+?)/([^\\s]+?)#([^\\s]+?)\\]") { m =>
|
(m: Match) =>
|
||||||
if (getRepositoryInfoFromCache(m.group(1), m.group(2)).isDefined) {
|
s"""<a href="${context.path}/${m.group(1)}/${m.group(2)}/commit/${m.group(3)}">${m.group(1)}/${m
|
||||||
s"""<a href="${context.path}/${m.group(1)}/${m.group(2)}/tree/${encodeRefName(m.group(3))}">${StringUtil.escapeHtml(m.group(3))}</a>"""
|
.group(2)}@${m.group(3).substring(0, 7)}</a>"""
|
||||||
} else {
|
)
|
||||||
StringUtil.escapeHtml(m.group(3))
|
.replaceAll(
|
||||||
}
|
"\\[release:([^\\s]+?)/([^\\s]+?)/([^\\s]+?):(.+)\\]",
|
||||||
}
|
(m: Match) =>
|
||||||
.replaceAll("\\[user:([^\\s]+?)\\]") { m =>
|
s"""<a href="${context.path}/${m.group(1)}/${m.group(2)}/releases/${encodeRefName(m.group(3))}">${StringUtil
|
||||||
user(m.group(1)).body
|
.escapeHtml(
|
||||||
}
|
m.group(4)
|
||||||
.replaceAll("\\[commit:([^\\s]+?)/([^\\s]+?)\\@([^\\s]+?)\\]") { m =>
|
)}</a>"""
|
||||||
if (getRepositoryInfoFromCache(m.group(1), m.group(2)).isDefined) {
|
)
|
||||||
s"""<a href="${context.path}/${m.group(1)}/${m.group(2)}/commit/${m.group(3)}">${m.group(1)}/${m.group(2)}@${m.group(3).substring(0, 7)}</a>"""
|
|
||||||
} else {
|
|
||||||
s"${m.group(1)}/${m.group(2)}@${m.group(3).substring(0, 7)}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.replaceAll("\\[release:([^\\s]+?)/([^\\s]+?)/([^\\s]+?):(.+)\\]") { m =>
|
|
||||||
if (getRepositoryInfoFromCache(m.group(1), m.group(2)).isDefined) {
|
|
||||||
s"""<a href="${context.path}/${m.group(1)}/${m.group(2)}/releases/${encodeRefName(m.group(3))}">${StringUtil.escapeHtml(m.group(4))}</a>"""
|
|
||||||
} else {
|
|
||||||
StringUtil.escapeHtml(m.group(4))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
// format: off
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove html tags from the given Html instance.
|
* Remove html tags from the given Html instance.
|
||||||
@@ -346,9 +333,9 @@ object helpers extends AvatarImageProvider with LinkConverter with RequestCache
|
|||||||
content: Html
|
content: Html
|
||||||
)(implicit context: Context): Html =
|
)(implicit context: Context): Html =
|
||||||
(if (mailAddress.isEmpty) {
|
(if (mailAddress.isEmpty) {
|
||||||
getAccountByUserNameFromCache(userName)
|
getAccountByUserName(userName)
|
||||||
} else {
|
} else {
|
||||||
getAccountByMailAddressFromCache(mailAddress)
|
getAccountByMailAddress(mailAddress)
|
||||||
}).map { account =>
|
}).map { account =>
|
||||||
Html(s"""<a href="${url(account.userName)}" class="${styleClass}">${content}</a>""")
|
Html(s"""<a href="${url(account.userName)}" class="${styleClass}">${content}</a>""")
|
||||||
} getOrElse content
|
} getOrElse content
|
||||||
|
|||||||
@@ -7,24 +7,21 @@
|
|||||||
@activities.map { activity =>
|
@activities.map { activity =>
|
||||||
<div class="block">
|
<div class="block">
|
||||||
@(activity.activityType match {
|
@(activity.activityType match {
|
||||||
case "open_issue" => simpleActivity(activity)
|
case "open_issue" => detailActivity(activity, "issue-opened")
|
||||||
case "comment_issue" => simpleActivity(activity)
|
case "comment_issue" => detailActivity(activity, "comment-discussion")
|
||||||
case "comment_commit" => simpleActivity(activity)
|
case "comment_commit" => detailActivity(activity, "comment-discussion")
|
||||||
case "close_issue" => simpleActivity(activity)
|
case "close_issue" => detailActivity(activity, "issue-closed")
|
||||||
case "reopen_issue" => simpleActivity(activity)
|
case "reopen_issue" => detailActivity(activity, "issue-reopened")
|
||||||
case "open_pullreq" => simpleActivity(activity)
|
case "open_pullreq" => detailActivity(activity, "git-pull-request")
|
||||||
case "merge_pullreq" => simpleActivity(activity)
|
case "merge_pullreq" => detailActivity(activity, "git-merge")
|
||||||
case "release" => simpleActivity(activity)
|
case "release" => detailActivity(activity, "package")
|
||||||
case "create_repository" => simpleActivity(activity)
|
case "create_repository" => simpleActivity(activity, "repo")
|
||||||
case "delete_repository" => simpleActivity(activity)
|
case "create_branch" => simpleActivity(activity, "git-branch")
|
||||||
case "rename_repository" => simpleActivity(activity)
|
case "delete_branch" => simpleActivity(activity, "circle-slash")
|
||||||
case "transfer_repository" => simpleActivity(activity)
|
case "create_tag" => simpleActivity(activity, "tag")
|
||||||
case "create_branch" => simpleActivity(activity)
|
case "delete_tag" => simpleActivity(activity, "circle-slash")
|
||||||
case "delete_branch" => simpleActivity(activity)
|
case "fork" => simpleActivity(activity, "repo-forked")
|
||||||
case "create_tag" => simpleActivity(activity)
|
case "push" => customActivity(activity, "git-commit"){
|
||||||
case "delete_tag" => simpleActivity(activity)
|
|
||||||
case "fork" => simpleActivity(activity)
|
|
||||||
case "push" => customActivity(activity){
|
|
||||||
<div class="small activity-message">
|
<div class="small activity-message">
|
||||||
{activity.additionalInfo.get.split("\n").reverse.take(4).zipWithIndex.map{ case (commit, i) =>
|
{activity.additionalInfo.get.split("\n").reverse.take(4).zipWithIndex.map{ case (commit, i) =>
|
||||||
if(i == 3){
|
if(i == 3){
|
||||||
@@ -40,12 +37,12 @@
|
|||||||
}}
|
}}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
case "create_wiki" => customActivity(activity){
|
case "create_wiki" => customActivity(activity, "book"){
|
||||||
<div class="small activity-message">
|
<div class="small activity-message">
|
||||||
Created <a href={s"${context.path}/${activity.userName}/${activity.repositoryName}/wiki/${activity.additionalInfo.get}"}>{activity.additionalInfo.get}</a>.
|
Created <a href={s"${context.path}/${activity.userName}/${activity.repositoryName}/wiki/${activity.additionalInfo.get}"}>{activity.additionalInfo.get}</a>.
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
case "edit_wiki" => customActivity(activity){
|
case "edit_wiki" => customActivity(activity, "book"){
|
||||||
activity.additionalInfo.get.split(":") match {
|
activity.additionalInfo.get.split(":") match {
|
||||||
case Array(pageName, commitId) =>
|
case Array(pageName, commitId) =>
|
||||||
<div class="small activity-message">
|
<div class="small activity-message">
|
||||||
@@ -63,7 +60,26 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@customActivity(activity: gitbucket.core.model.Activity)(additionalInfo: Any) = {
|
@detailActivity(activity: gitbucket.core.model.Activity, image: String) = {
|
||||||
|
@*
|
||||||
|
<div class="activity-icon-large"><i class="mega-octicon octicon-@image"></i></div>
|
||||||
|
*@
|
||||||
|
<div>
|
||||||
|
<div class="muted small">@gitbucket.core.helper.html.datetimeago(activity.activityDate)</div>
|
||||||
|
<div class="strong">
|
||||||
|
@helpers.avatarLink(activity.activityUserName, 16)
|
||||||
|
@helpers.activityMessage(activity.message)
|
||||||
|
</div>
|
||||||
|
@activity.additionalInfo.map { additionalInfo =>
|
||||||
|
<div class=" activity-message">@additionalInfo</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@customActivity(activity: gitbucket.core.model.Activity, image: String)(additionalInfo: Any) = {
|
||||||
|
@*
|
||||||
|
<div class="activity-icon-large"><i class="mega-octicon octicon-@image"></i></div>
|
||||||
|
*@
|
||||||
<div>
|
<div>
|
||||||
<div class="muted small">@gitbucket.core.helper.html.datetimeago(activity.activityDate)</div>
|
<div class="muted small">@gitbucket.core.helper.html.datetimeago(activity.activityDate)</div>
|
||||||
<div class="strong">
|
<div class="strong">
|
||||||
@@ -74,7 +90,10 @@
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
@simpleActivity(activity: gitbucket.core.model.Activity) = {
|
@simpleActivity(activity: gitbucket.core.model.Activity, image: String) = {
|
||||||
|
@*
|
||||||
|
<div class="activity-icon-small"><i class="octicon octicon-@image"></i></div>
|
||||||
|
*@
|
||||||
<div>
|
<div>
|
||||||
<span class="muted small">@gitbucket.core.helper.html.datetimeago(activity.activityDate)</span>
|
<span class="muted small">@gitbucket.core.helper.html.datetimeago(activity.activityDate)</span>
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import scala.util.Using
|
|||||||
class MergeServiceSpec extends FunSpec {
|
class MergeServiceSpec extends FunSpec {
|
||||||
val service = new MergeService with AccountService with ActivityService with IssuesService with LabelsService
|
val service = new MergeService with AccountService with ActivityService with IssuesService with LabelsService
|
||||||
with MilestonesService with RepositoryService with PrioritiesService with PullRequestService with CommitsService
|
with MilestonesService with RepositoryService with PrioritiesService with PullRequestService with CommitsService
|
||||||
with WebHookPullRequestService with WebHookPullRequestReviewCommentService with RequestCache {}
|
with WebHookPullRequestService with WebHookPullRequestReviewCommentService {}
|
||||||
val branch = "master"
|
val branch = "master"
|
||||||
val issueId = 10
|
val issueId = 10
|
||||||
def initRepository(owner: String, name: String): File = {
|
def initRepository(owner: String, name: String): File = {
|
||||||
|
|||||||
@@ -18,8 +18,7 @@ class PullRequestServiceSpec
|
|||||||
with PrioritiesService
|
with PrioritiesService
|
||||||
with WebHookService
|
with WebHookService
|
||||||
with WebHookPullRequestService
|
with WebHookPullRequestService
|
||||||
with WebHookPullRequestReviewCommentService
|
with WebHookPullRequestReviewCommentService {
|
||||||
with RequestCache {
|
|
||||||
|
|
||||||
def swap(r: (Issue, PullRequest)) = (r._2 -> r._1)
|
def swap(r: (Issue, PullRequest)) = (r._2 -> r._1)
|
||||||
|
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ trait ServiceSpecBase extends MockitoSugar {
|
|||||||
lazy val dummyService = new RepositoryService with AccountService with ActivityService with IssuesService
|
lazy val dummyService = new RepositoryService with AccountService with ActivityService with IssuesService
|
||||||
with MergeService with PullRequestService with CommitsService with CommitStatusService with LabelsService
|
with MergeService with PullRequestService with CommitsService with CommitStatusService with LabelsService
|
||||||
with MilestonesService with PrioritiesService with WebHookService with WebHookPullRequestService
|
with MilestonesService with PrioritiesService with WebHookService with WebHookPullRequestService
|
||||||
with WebHookPullRequestReviewCommentService with RequestCache {
|
with WebHookPullRequestReviewCommentService {
|
||||||
override def fetchAsPullRequest(
|
override def fetchAsPullRequest(
|
||||||
userName: String,
|
userName: String,
|
||||||
repositoryName: String,
|
repositoryName: String,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import gitbucket.core.model.WebHookContentType
|
|||||||
class WebHookServiceSpec extends FunSuite with ServiceSpecBase {
|
class WebHookServiceSpec extends FunSuite with ServiceSpecBase {
|
||||||
lazy val service = new WebHookPullRequestService with AccountService with ActivityService with RepositoryService
|
lazy val service = new WebHookPullRequestService with AccountService with ActivityService with RepositoryService
|
||||||
with MergeService with PullRequestService with IssuesService with CommitsService with LabelsService
|
with MergeService with PullRequestService with IssuesService with CommitsService with LabelsService
|
||||||
with MilestonesService with PrioritiesService with WebHookPullRequestReviewCommentService with RequestCache
|
with MilestonesService with PrioritiesService with WebHookPullRequestReviewCommentService
|
||||||
|
|
||||||
test("WebHookPullRequestService.getPullRequestsByRequestForWebhook") {
|
test("WebHookPullRequestService.getPullRequestsByRequestForWebhook") {
|
||||||
withTestDB { implicit session =>
|
withTestDB { implicit session =>
|
||||||
|
|||||||
@@ -169,9 +169,8 @@ class AvatarImageProviderSpec extends FunSpec with MockitoSugar {
|
|||||||
context: Context
|
context: Context
|
||||||
): Html = getAvatarImageHtml(userName, size, mailAddress, tooltip)
|
): Html = getAvatarImageHtml(userName, size, mailAddress, tooltip)
|
||||||
|
|
||||||
override def getAccountByMailAddressFromCache(mailAddress: String)(implicit context: Context): Option[Account] =
|
override def getAccountByMailAddress(mailAddress: String)(implicit context: Context): Option[Account] = account
|
||||||
account
|
override def getAccountByUserName(userName: String)(implicit context: Context): Option[Account] = account
|
||||||
override def getAccountByUserNameFromCache(userName: String)(implicit context: Context): Option[Account] = account
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user