mirror of
https://github.com/gitbucket/gitbucket.git
synced 2026-05-08 23:27:43 +02:00
Compare commits
101 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1a4961c3e1 | ||
|
|
561220237f | ||
|
|
f45b85aa71 | ||
|
|
83b3a7983e | ||
|
|
63d4c5054e | ||
|
|
c8f6017be9 | ||
|
|
f9fcb54861 | ||
|
|
3534b7172d | ||
|
|
42a7f974e9 | ||
|
|
b8e02d995a | ||
|
|
e0d038aa92 | ||
|
|
3d01df2bdc | ||
|
|
6f08f1fd23 | ||
|
|
3dd366b394 | ||
|
|
8cf4528959 | ||
|
|
5d77bc5d98 | ||
|
|
572c9ef558 | ||
|
|
7c736c526e | ||
|
|
696d354f3c | ||
|
|
501cbf54ab | ||
|
|
c15d69d566 | ||
|
|
83eb933230 | ||
|
|
43bec9b0df | ||
|
|
279305c202 | ||
|
|
ecbb86c006 | ||
|
|
921fb17ef0 | ||
|
|
0362de7d35 | ||
|
|
cf0d8ea2d0 | ||
|
|
0e9026447d | ||
|
|
cf4d9cb03c | ||
|
|
2a1edeaca3 | ||
|
|
eebabf9b08 | ||
|
|
d882fcad12 | ||
|
|
f976290282 | ||
|
|
f3f9d5dae2 | ||
|
|
71dffd1089 | ||
|
|
f411e98c9a | ||
|
|
1baa489bc7 | ||
|
|
f996b0fc4a | ||
|
|
eb6ba1c800 | ||
|
|
8fac1baa3c | ||
|
|
2d327543b9 | ||
|
|
8a080efe9d | ||
|
|
aaaf61e29e | ||
|
|
1294323df5 | ||
|
|
9ef4e75746 | ||
|
|
ded4ab702d | ||
|
|
f893d045c7 | ||
|
|
ef2e3adcfb | ||
|
|
a1908c5398 | ||
|
|
ec4f0d6531 | ||
|
|
9ef366237c | ||
|
|
9197ad2600 | ||
|
|
2cb7ecd851 | ||
|
|
7d1ad4ce66 | ||
|
|
c274acc8f4 | ||
|
|
7a0d48dd7a | ||
|
|
9c6f9048e1 | ||
|
|
4ff4acfd7e | ||
|
|
d8e9f07721 | ||
|
|
662c5638dd | ||
|
|
02b830d034 | ||
|
|
3734529e5c | ||
|
|
715ec24389 | ||
|
|
5615b23548 | ||
|
|
ca2eeb48cf | ||
|
|
b063c0a80c | ||
|
|
ee8b5692bd | ||
|
|
7a749dca67 | ||
|
|
0378f26ee6 | ||
|
|
4d281273c1 | ||
|
|
e23e11e1a8 | ||
|
|
772835dd22 | ||
|
|
bbf2e57548 | ||
|
|
aecda130b6 | ||
|
|
1d48030e7c | ||
|
|
929ba2fa19 | ||
|
|
6fefa947ca | ||
|
|
072cd2e846 | ||
|
|
5d20cd0365 | ||
|
|
03ec055f66 | ||
|
|
4b6a5e5d49 | ||
|
|
6d21e38159 | ||
|
|
a47c8249bf | ||
|
|
59d7a672b3 | ||
|
|
564e95d36e | ||
|
|
9aee99be74 | ||
|
|
aecd8b503d | ||
|
|
fa65eeea35 | ||
|
|
fe43584c3d | ||
|
|
c255b13dfc | ||
|
|
917b204e5b | ||
|
|
6225fd79fc | ||
|
|
cbec567ef4 | ||
|
|
84b62242d3 | ||
|
|
f17f74c30b | ||
|
|
63b04d5a27 | ||
|
|
f02073a24c | ||
|
|
cb87d126de | ||
|
|
941f8002e5 | ||
|
|
90f4f5cd89 |
39
.github/workflows/build.yml
vendored
Normal file
39
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
name: build
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
java: [8, 11]
|
||||||
|
steps:
|
||||||
|
- 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
|
||||||
|
uses: actions/setup-java@v1
|
||||||
|
with:
|
||||||
|
java-version: ${{ matrix.java }}
|
||||||
|
- name: Run tests
|
||||||
|
run: sbt scalafmtSbtCheck scalafmtCheck test:scalafmtCheck test
|
||||||
|
- name: Build executable
|
||||||
|
run: sbt executable
|
||||||
|
- name: Upload artifacts
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: gitbucket-java${{ matrix.java }}-${{ github.sha }}
|
||||||
|
path: ./target/executable/gitbucket.*
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -27,4 +27,5 @@ project/plugins/project/
|
|||||||
|
|
||||||
# Metals specific
|
# Metals specific
|
||||||
.metals
|
.metals
|
||||||
.bloop
|
.bloop
|
||||||
|
project/metals.sbt
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
version = "1.5.1"
|
||||||
project.git = true
|
project.git = true
|
||||||
|
|
||||||
maxColumn = 120
|
maxColumn = 120
|
||||||
|
|||||||
17
.travis.yml
17
.travis.yml
@@ -1,17 +0,0 @@
|
|||||||
language: scala
|
|
||||||
sudo: true
|
|
||||||
jdk:
|
|
||||||
- openjdk8
|
|
||||||
- openjdk11
|
|
||||||
script:
|
|
||||||
- sbt scalafmtSbtCheck scalafmtCheck test:scalafmtCheck test
|
|
||||||
before_script:
|
|
||||||
- sudo /etc/init.d/mysql stop
|
|
||||||
- sudo /etc/init.d/postgresql stop
|
|
||||||
- sudo chmod +x /usr/local/bin/sbt
|
|
||||||
cache:
|
|
||||||
directories:
|
|
||||||
- $HOME/.ivy2/cache
|
|
||||||
- $HOME/.sbt/boot
|
|
||||||
- $HOME/.sbt/launchers
|
|
||||||
- $HOME/.coursier
|
|
||||||
20
CHANGELOG.md
20
CHANGELOG.md
@@ -1,12 +1,28 @@
|
|||||||
# 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 environmental variables
|
- All CLI options are configurable by environment variables
|
||||||
- Folding pull request files
|
- Folding pull request files
|
||||||
- WebHook security options
|
- WebHook security options
|
||||||
- Add asignee and asignees properties to some Web APIs' response
|
- Add assignee and assignees properties to some Web APIs' response
|
||||||
|
|
||||||
### 4.32.0 - 7 Aug 2019
|
### 4.32.0 - 7 Aug 2019
|
||||||
|
|
||||||
|
|||||||
37
README.md
37
README.md
@@ -1,4 +1,4 @@
|
|||||||
GitBucket [](https://gitter.im/gitbucket/gitbucket) [](https://travis-ci.org/gitbucket/gitbucket) [](https://maven-badges.herokuapp.com/maven-central/io.github.gitbucket/gitbucket_2.13) [](https://github.com/gitbucket/gitbucket/blob/master/LICENSE)
|
GitBucket [](https://gitter.im/gitbucket/gitbucket) [](https://github.com/gitbucket/gitbucket/actions?query=workflow%3Abuild+branch%3Amaster) [](https://maven-badges.herokuapp.com/maven-central/io.github.gitbucket/gitbucket_2.13) [](https://github.com/gitbucket/gitbucket/blob/master/LICENSE)
|
||||||
=========
|
=========
|
||||||
|
|
||||||
GitBucket is a Git web platform powered by Scala offering:
|
GitBucket is a Git web platform powered by Scala offering:
|
||||||
@@ -31,20 +31,6 @@ GitBucket requires **Java8**. You have to install it, if it is not already insta
|
|||||||
1. Download the latest **gitbucket.war** from [the releases page](https://github.com/gitbucket/gitbucket/releases) and run it by `java -jar gitbucket.war`.
|
1. Download the latest **gitbucket.war** from [the releases page](https://github.com/gitbucket/gitbucket/releases) and run it by `java -jar gitbucket.war`.
|
||||||
2. Go to `http://[hostname]:8080/` and log in with ID: **root** / Pass: **root**.
|
2. Go to `http://[hostname]:8080/` and log in with ID: **root** / Pass: **root**.
|
||||||
|
|
||||||
You can specify following options:
|
|
||||||
|
|
||||||
- `--port=[NUMBER]`
|
|
||||||
- `--prefix=[CONTEXTPATH]`
|
|
||||||
- `--host=[HOSTNAME]`
|
|
||||||
- `--gitbucket.home=[DATA_DIR]`
|
|
||||||
- `--temp_dir=[TEMP_DIR]`
|
|
||||||
- `--max_file_size=[MAX_FILE_SIZE]`
|
|
||||||
- `--upload_timeout=[MAX_UPLOAD_TIMEOUT]`
|
|
||||||
|
|
||||||
`TEMP_DIR` is used as the [temporary directory for the jetty application context](https://www.eclipse.org/jetty/documentation/9.3.x/ref-temporary-directories.html). This is the directory into which the `gitbucket.war` file is unpacked, the source files are compiled, etc. If given this parameter **must** match the path of an existing directory or the application will quit reporting an error; if not given the path used will be a `tmp` directory inside the gitbucket home.
|
|
||||||
|
|
||||||
`MAX_FILE_SIZE` is the max file size in bytes for upload files *( default is 3 MB -> 3 x 1024 x 1024 )*.
|
|
||||||
|
|
||||||
You can also deploy `gitbucket.war` to a servlet container which supports Servlet 3.0 (like Jetty, Tomcat, JBoss, etc)
|
You can also deploy `gitbucket.war` to a servlet container which supports Servlet 3.0 (like Jetty, Tomcat, JBoss, etc)
|
||||||
|
|
||||||
For more information about installation on Mac or Windows Server (with IIS), or configuration of Apache or Nginx and also integration with other tools or services such as Jenkins or Slack, see [Wiki](https://github.com/gitbucket/gitbucket/wiki).
|
For more information about installation on Mac or Windows Server (with IIS), or configuration of Apache or Nginx and also integration with other tools or services such as Jenkins or Slack, see [Wiki](https://github.com/gitbucket/gitbucket/wiki).
|
||||||
@@ -69,13 +55,22 @@ Support
|
|||||||
- If you can't find same question and report, send it to [gitter room](https://gitter.im/gitbucket/gitbucket) before raising an issue.
|
- If you can't find same question and report, send it to [gitter room](https://gitter.im/gitbucket/gitbucket) before raising an issue.
|
||||||
- The highest priority of GitBucket is the ease of installation and API compatibility with GitHub, so your feature request might be rejected if they go against those principles.
|
- The highest priority of GitBucket is the ease of installation and API compatibility with GitHub, so your feature request might be rejected if they go against those principles.
|
||||||
|
|
||||||
What's New in 4.32.x
|
What's New in 4.33.x
|
||||||
-------------
|
-------------
|
||||||
### 4.33.0 - 31 Dec 2019
|
### 4.34.0 - 26 Jul 2020
|
||||||
|
|
||||||
- All CLI options are configurable by environmental variables
|
- Enhancement admin settings UI
|
||||||
- Folding pull request files
|
- File upload settings
|
||||||
- WebHook security options
|
- Restrict repository operations
|
||||||
- Add asignee and asignees properties to some Web APIs' response
|
- 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
|
||||||
|
|
||||||
See the [change log](CHANGELOG.md) for all of the updates.
|
See the [change log](CHANGELOG.md) for all of the updates.
|
||||||
|
|||||||
36
build.sbt
36
build.sbt
@@ -3,10 +3,10 @@ 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.33.0"
|
val GitBucketVersion = "4.34.0"
|
||||||
val ScalatraVersion = "2.7.0-RC1"
|
val ScalatraVersion = "2.7.0-RC1"
|
||||||
val JettyVersion = "9.4.25.v20191220"
|
val JettyVersion = "9.4.30.v20200611"
|
||||||
val JgitVersion = "5.6.0.201912101111-r"
|
val JgitVersion = "5.8.0.202006091008-r"
|
||||||
|
|
||||||
lazy val root = (project in file("."))
|
lazy val root = (project in file("."))
|
||||||
.enablePlugins(SbtTwirl, ScalatraPlugin)
|
.enablePlugins(SbtTwirl, ScalatraPlugin)
|
||||||
@@ -36,42 +36,40 @@ libraryDependencies ++= Seq(
|
|||||||
"org.scalatra" %% "scalatra" % ScalatraVersion,
|
"org.scalatra" %% "scalatra" % ScalatraVersion,
|
||||||
"org.scalatra" %% "scalatra-json" % ScalatraVersion,
|
"org.scalatra" %% "scalatra-json" % ScalatraVersion,
|
||||||
"org.scalatra" %% "scalatra-forms" % ScalatraVersion,
|
"org.scalatra" %% "scalatra-forms" % ScalatraVersion,
|
||||||
"org.json4s" %% "json4s-jackson" % "3.6.7",
|
"org.json4s" %% "json4s-jackson" % "3.6.9",
|
||||||
"commons-io" % "commons-io" % "2.6",
|
"commons-io" % "commons-io" % "2.7",
|
||||||
"io.github.gitbucket" % "solidbase" % "1.0.3",
|
"io.github.gitbucket" % "solidbase" % "1.0.3",
|
||||||
"io.github.gitbucket" % "markedj" % "1.0.16",
|
"io.github.gitbucket" % "markedj" % "1.0.16",
|
||||||
"org.apache.commons" % "commons-compress" % "1.19",
|
"org.apache.commons" % "commons-compress" % "1.20",
|
||||||
"org.apache.commons" % "commons-email" % "1.5",
|
"org.apache.commons" % "commons-email" % "1.5",
|
||||||
"commons-net" % "commons-net" % "3.6",
|
"commons-net" % "commons-net" % "3.6",
|
||||||
"org.apache.httpcomponents" % "httpclient" % "4.5.10",
|
"org.apache.httpcomponents" % "httpclient" % "4.5.12",
|
||||||
"org.apache.sshd" % "apache-sshd" % "2.1.0" exclude ("org.slf4j", "slf4j-jdk14") exclude ("org.apache.sshd", "sshd-mina") exclude ("org.apache.sshd", "sshd-netty"),
|
"org.apache.sshd" % "apache-sshd" % "2.1.0" exclude ("org.slf4j", "slf4j-jdk14") exclude ("org.apache.sshd", "sshd-mina") exclude ("org.apache.sshd", "sshd-netty"),
|
||||||
"org.apache.tika" % "tika-core" % "1.23",
|
"org.apache.tika" % "tika-core" % "1.24.1",
|
||||||
"com.github.takezoe" %% "blocking-slick-32" % "0.0.12",
|
"com.github.takezoe" %% "blocking-slick-32" % "0.0.12",
|
||||||
"com.novell.ldap" % "jldap" % "2009-10-07",
|
"com.novell.ldap" % "jldap" % "2009-10-07",
|
||||||
"com.h2database" % "h2" % "1.4.199",
|
"com.h2database" % "h2" % "1.4.199",
|
||||||
"org.mariadb.jdbc" % "mariadb-java-client" % "2.5.2",
|
"org.mariadb.jdbc" % "mariadb-java-client" % "2.6.0",
|
||||||
"org.postgresql" % "postgresql" % "42.2.6",
|
"org.postgresql" % "postgresql" % "42.2.6",
|
||||||
"ch.qos.logback" % "logback-classic" % "1.2.3",
|
"ch.qos.logback" % "logback-classic" % "1.2.3",
|
||||||
"com.zaxxer" % "HikariCP" % "3.4.1",
|
"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.8",
|
|
||||||
"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",
|
||||||
"org.eclipse.jetty" % "jetty-webapp" % JettyVersion % "provided",
|
"org.eclipse.jetty" % "jetty-webapp" % JettyVersion % "provided",
|
||||||
"javax.servlet" % "javax.servlet-api" % "3.1.0" % "provided",
|
"javax.servlet" % "javax.servlet-api" % "3.1.0" % "provided",
|
||||||
"junit" % "junit" % "4.12" % "test",
|
"junit" % "junit" % "4.13" % "test",
|
||||||
"org.scalatra" %% "scalatra-scalatest" % ScalatraVersion % "test",
|
"org.scalatra" %% "scalatra-scalatest" % ScalatraVersion % "test",
|
||||||
"org.mockito" % "mockito-core" % "3.2.4" % "test",
|
"org.mockito" % "mockito-core" % "3.3.3" % "test",
|
||||||
"com.dimafeng" %% "testcontainers-scala" % "0.34.2" % "test",
|
"com.dimafeng" %% "testcontainers-scala" % "0.37.0" % "test",
|
||||||
"org.testcontainers" % "mysql" % "1.12.4" % "test",
|
"org.testcontainers" % "mysql" % "1.14.3" % "test",
|
||||||
"org.testcontainers" % "postgresql" % "1.12.4" % "test",
|
"org.testcontainers" % "postgresql" % "1.14.3" % "test",
|
||||||
"net.i2p.crypto" % "eddsa" % "0.3.0",
|
"net.i2p.crypto" % "eddsa" % "0.3.0",
|
||||||
"is.tagomor.woothee" % "woothee-java" % "1.10.1",
|
"is.tagomor.woothee" % "woothee-java" % "1.11.0",
|
||||||
"org.ec4j.core" % "ec4j-core" % "0.0.3"
|
"org.ec4j.core" % "ec4j-core" % "0.0.3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
sbt.version=1.3.5
|
sbt.version=1.3.12
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ scalacOptions ++= Seq("-unchecked", "-deprecation", "-feature")
|
|||||||
|
|
||||||
addSbtPlugin("com.geirsson" % "sbt-scalafmt" % "1.5.1")
|
addSbtPlugin("com.geirsson" % "sbt-scalafmt" % "1.5.1")
|
||||||
addSbtPlugin("com.typesafe.sbt" % "sbt-twirl" % "1.5.0")
|
addSbtPlugin("com.typesafe.sbt" % "sbt-twirl" % "1.5.0")
|
||||||
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.10")
|
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.15.0")
|
||||||
addSbtPlugin("org.scalatra.sbt" % "sbt-scalatra" % "1.0.3")
|
addSbtPlugin("org.scalatra.sbt" % "sbt-scalatra" % "1.0.4")
|
||||||
addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.1.2")
|
addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.1.2")
|
||||||
addSbtPlugin("com.typesafe.sbt" % "sbt-license-report" % "1.2.0")
|
addSbtPlugin("com.typesafe.sbt" % "sbt-license-report" % "1.2.0")
|
||||||
addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.9.2")
|
addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.9.2")
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ import org.eclipse.jetty.server.Handler;
|
|||||||
import org.eclipse.jetty.server.HttpConnectionFactory;
|
import org.eclipse.jetty.server.HttpConnectionFactory;
|
||||||
import org.eclipse.jetty.server.Server;
|
import org.eclipse.jetty.server.Server;
|
||||||
import org.eclipse.jetty.server.handler.StatisticsHandler;
|
import org.eclipse.jetty.server.handler.StatisticsHandler;
|
||||||
|
import org.eclipse.jetty.server.session.DefaultSessionCache;
|
||||||
|
import org.eclipse.jetty.server.session.FileSessionDataStore;
|
||||||
|
import org.eclipse.jetty.server.session.SessionCache;
|
||||||
|
import org.eclipse.jetty.server.session.SessionHandler;
|
||||||
import org.eclipse.jetty.webapp.WebAppContext;
|
import org.eclipse.jetty.webapp.WebAppContext;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -21,6 +25,7 @@ public class JettyLauncher {
|
|||||||
String contextPath = "/";
|
String contextPath = "/";
|
||||||
String tmpDirPath="";
|
String tmpDirPath="";
|
||||||
boolean forceHttps = false;
|
boolean forceHttps = false;
|
||||||
|
boolean saveSessions = false;
|
||||||
|
|
||||||
host = getEnvironmentVariable("gitbucket.host");
|
host = getEnvironmentVariable("gitbucket.host");
|
||||||
port = getEnvironmentVariable("gitbucket.port");
|
port = getEnvironmentVariable("gitbucket.port");
|
||||||
@@ -28,6 +33,9 @@ public class JettyLauncher {
|
|||||||
tmpDirPath = getEnvironmentVariable("gitbucket.tempDir");
|
tmpDirPath = getEnvironmentVariable("gitbucket.tempDir");
|
||||||
|
|
||||||
for(String arg: args) {
|
for(String arg: args) {
|
||||||
|
if(arg.equals("--save_sessions")) {
|
||||||
|
saveSessions = true;
|
||||||
|
}
|
||||||
if(arg.startsWith("--") && arg.contains("=")) {
|
if(arg.startsWith("--") && arg.contains("=")) {
|
||||||
String[] dim = arg.split("=");
|
String[] dim = arg.split("=");
|
||||||
if(dim.length >= 2) {
|
if(dim.length >= 2) {
|
||||||
@@ -41,12 +49,6 @@ public class JettyLauncher {
|
|||||||
case "--prefix":
|
case "--prefix":
|
||||||
contextPath = dim[1];
|
contextPath = dim[1];
|
||||||
break;
|
break;
|
||||||
case "--max_file_size":
|
|
||||||
System.setProperty("gitbucket.maxFileSize", dim[1]);
|
|
||||||
break;
|
|
||||||
case "--upload_timeout":
|
|
||||||
System.setProperty("gitbucket.UploadTimeout", dim[1]);
|
|
||||||
break;
|
|
||||||
case "--gitbucket.home":
|
case "--gitbucket.home":
|
||||||
System.setProperty("gitbucket.home", dim[1]);
|
System.setProperty("gitbucket.home", dim[1]);
|
||||||
break;
|
break;
|
||||||
@@ -56,9 +58,6 @@ public class JettyLauncher {
|
|||||||
case "--plugin_dir":
|
case "--plugin_dir":
|
||||||
System.setProperty("gitbucket.pluginDir", dim[1]);
|
System.setProperty("gitbucket.pluginDir", dim[1]);
|
||||||
break;
|
break;
|
||||||
case "--validate_password":
|
|
||||||
System.setProperty("gitbucket.validate.password", dim[1]);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -96,6 +95,19 @@ public class JettyLauncher {
|
|||||||
|
|
||||||
WebAppContext context = new WebAppContext();
|
WebAppContext context = new WebAppContext();
|
||||||
|
|
||||||
|
if(saveSessions) {
|
||||||
|
File sessDir = new File(getGitBucketHome(), "sessions");
|
||||||
|
if(!sessDir.exists()){
|
||||||
|
sessDir.mkdirs();
|
||||||
|
}
|
||||||
|
SessionHandler sessions = context.getSessionHandler();
|
||||||
|
SessionCache cache = new DefaultSessionCache(sessions);
|
||||||
|
FileSessionDataStore fsds = new FileSessionDataStore();
|
||||||
|
fsds.setStoreDir(sessDir);
|
||||||
|
cache.setSessionDataStore(fsds);
|
||||||
|
sessions.setSessionCache(cache);
|
||||||
|
}
|
||||||
|
|
||||||
File tmpDir;
|
File tmpDir;
|
||||||
if(tmpDirPath == null || tmpDirPath.equals("")){
|
if(tmpDirPath == null || tmpDirPath.equals("")){
|
||||||
tmpDir = new File(getGitBucketHome(), "tmp");
|
tmpDir = new File(getGitBucketHome(), "tmp");
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
notifications:1.8.0
|
notifications:1.9.0
|
||||||
gist:4.18.0
|
gist:4.19.0
|
||||||
emoji:4.6.0
|
emoji:4.6.0
|
||||||
pages:1.8.0
|
pages:1.8.0
|
||||||
|
|||||||
@@ -60,13 +60,12 @@
|
|||||||
<!-- ACCESS_TOKEN -->
|
<!-- ACCESS_TOKEN -->
|
||||||
<!--================================================================================================-->
|
<!--================================================================================================-->
|
||||||
<createTable tableName="ACCESS_TOKEN">
|
<createTable tableName="ACCESS_TOKEN">
|
||||||
<column name="ACCESS_TOKEN_ID" type="int" nullable="false" autoIncrement="true" unique="true"/>
|
<column name="ACCESS_TOKEN_ID" type="int" nullable="false" autoIncrement="true" unique="true" primaryKeyName="IDX_ACCESS_TOKEN_PK" primaryKey="true" />
|
||||||
<column name="TOKEN_HASH" type="varchar(40)" nullable="false"/>
|
<column name="TOKEN_HASH" type="varchar(40)" nullable="false"/>
|
||||||
<column name="USER_NAME" type="varchar(100)" nullable="false"/>
|
<column name="USER_NAME" type="varchar(100)" nullable="false"/>
|
||||||
<column name="NOTE" type="text" nullable="false"/>
|
<column name="NOTE" type="text" nullable="false"/>
|
||||||
</createTable>
|
</createTable>
|
||||||
|
|
||||||
<addPrimaryKey constraintName="IDX_ACCESS_TOKEN_PK" tableName="ACCESS_TOKEN" columnNames="ACCESS_TOKEN_ID"/>
|
|
||||||
<addUniqueConstraint constraintName="IDX_ACCESS_TOKEN_TOKEN_HASH" tableName="ACCESS_TOKEN" columnNames="TOKEN_HASH"/>
|
<addUniqueConstraint constraintName="IDX_ACCESS_TOKEN_TOKEN_HASH" tableName="ACCESS_TOKEN" columnNames="TOKEN_HASH"/>
|
||||||
<addForeignKeyConstraint constraintName="IDX_ACCESS_TOKEN_FK0" baseTableName="ACCESS_TOKEN" baseColumnNames="USER_NAME" referencedTableName="ACCOUNT" referencedColumnNames="USER_NAME" onDelete="CASCADE" onUpdate="CASCADE"/>
|
<addForeignKeyConstraint constraintName="IDX_ACCESS_TOKEN_FK0" baseTableName="ACCESS_TOKEN" baseColumnNames="USER_NAME" referencedTableName="ACCOUNT" referencedColumnNames="USER_NAME" onDelete="CASCADE" onUpdate="CASCADE"/>
|
||||||
|
|
||||||
@@ -74,7 +73,7 @@
|
|||||||
<!-- ACTIVITY -->
|
<!-- ACTIVITY -->
|
||||||
<!--================================================================================================-->
|
<!--================================================================================================-->
|
||||||
<createTable tableName="ACTIVITY">
|
<createTable tableName="ACTIVITY">
|
||||||
<column name="ACTIVITY_ID" type="int" nullable="false" autoIncrement="true" unique="true"/>
|
<column name="ACTIVITY_ID" type="int" nullable="false" autoIncrement="true" unique="true" primaryKeyName="IDX_ACTIVITY_PK" primaryKey="true"/>
|
||||||
<column name="USER_NAME" type="varchar(100)" nullable="false"/>
|
<column name="USER_NAME" type="varchar(100)" nullable="false"/>
|
||||||
<column name="REPOSITORY_NAME" type="varchar(100)" nullable="false"/>
|
<column name="REPOSITORY_NAME" type="varchar(100)" nullable="false"/>
|
||||||
<column name="ACTIVITY_USER_NAME" type="varchar(100)" nullable="false"/>
|
<column name="ACTIVITY_USER_NAME" type="varchar(100)" nullable="false"/>
|
||||||
@@ -84,7 +83,6 @@
|
|||||||
<column name="ACTIVITY_DATE" type="datetime" nullable="false"/>
|
<column name="ACTIVITY_DATE" type="datetime" nullable="false"/>
|
||||||
</createTable>
|
</createTable>
|
||||||
|
|
||||||
<addPrimaryKey constraintName="IDX_ACTIVITY_PK" tableName="ACTIVITY" columnNames="ACTIVITY_ID"/>
|
|
||||||
<addForeignKeyConstraint constraintName="IDX_ACTIVITY_FK1" baseTableName="ACTIVITY" baseColumnNames="ACTIVITY_USER_NAME" referencedTableName="ACCOUNT" referencedColumnNames="USER_NAME"/>
|
<addForeignKeyConstraint constraintName="IDX_ACTIVITY_FK1" baseTableName="ACTIVITY" baseColumnNames="ACTIVITY_USER_NAME" referencedTableName="ACCOUNT" referencedColumnNames="USER_NAME"/>
|
||||||
<addForeignKeyConstraint constraintName="IDX_ACTIVITY_FK0" baseTableName="ACTIVITY" baseColumnNames="USER_NAME, REPOSITORY_NAME" referencedTableName="REPOSITORY" referencedColumnNames="USER_NAME, REPOSITORY_NAME"/>
|
<addForeignKeyConstraint constraintName="IDX_ACTIVITY_FK0" baseTableName="ACTIVITY" baseColumnNames="USER_NAME, REPOSITORY_NAME" referencedTableName="REPOSITORY" referencedColumnNames="USER_NAME, REPOSITORY_NAME"/>
|
||||||
|
|
||||||
@@ -108,7 +106,7 @@
|
|||||||
<column name="USER_NAME" type="varchar(100)" nullable="false"/>
|
<column name="USER_NAME" type="varchar(100)" nullable="false"/>
|
||||||
<column name="REPOSITORY_NAME" type="varchar(100)" nullable="false"/>
|
<column name="REPOSITORY_NAME" type="varchar(100)" nullable="false"/>
|
||||||
<column name="COMMIT_ID" type="varchar(100)" nullable="false"/>
|
<column name="COMMIT_ID" type="varchar(100)" nullable="false"/>
|
||||||
<column name="COMMENT_ID" type="int" nullable="false" autoIncrement="true" unique="true"/>
|
<column name="COMMENT_ID" type="int" nullable="false" autoIncrement="true" unique="true" primaryKeyName="IDX_COMMIT_COMMENT_PK" primaryKey="true" />
|
||||||
<column name="COMMENTED_USER_NAME" type="varchar(100)" nullable="false"/>
|
<column name="COMMENTED_USER_NAME" type="varchar(100)" nullable="false"/>
|
||||||
<column name="CONTENT" type="text" nullable="false"/>
|
<column name="CONTENT" type="text" nullable="false"/>
|
||||||
<column name="FILE_NAME" type="varchar(260)" nullable="true"/>
|
<column name="FILE_NAME" type="varchar(260)" nullable="true"/>
|
||||||
@@ -119,14 +117,13 @@
|
|||||||
<column name="ISSUE_ID" type="int" nullable="true"/>
|
<column name="ISSUE_ID" type="int" nullable="true"/>
|
||||||
</createTable>
|
</createTable>
|
||||||
|
|
||||||
<addPrimaryKey constraintName="IDX_COMMIT_COMMENT_PK" tableName="COMMIT_COMMENT" columnNames="COMMENT_ID"/>
|
|
||||||
<addForeignKeyConstraint constraintName="IDX_COMMIT_COMMENT_FK0" baseTableName="COMMIT_COMMENT" baseColumnNames="USER_NAME, REPOSITORY_NAME" referencedTableName="REPOSITORY" referencedColumnNames="USER_NAME, REPOSITORY_NAME"/>
|
<addForeignKeyConstraint constraintName="IDX_COMMIT_COMMENT_FK0" baseTableName="COMMIT_COMMENT" baseColumnNames="USER_NAME, REPOSITORY_NAME" referencedTableName="REPOSITORY" referencedColumnNames="USER_NAME, REPOSITORY_NAME"/>
|
||||||
|
|
||||||
<!--================================================================================================-->
|
<!--================================================================================================-->
|
||||||
<!-- COMMIT_STATUS -->
|
<!-- COMMIT_STATUS -->
|
||||||
<!--================================================================================================-->
|
<!--================================================================================================-->
|
||||||
<createTable tableName="COMMIT_STATUS">
|
<createTable tableName="COMMIT_STATUS">
|
||||||
<column name="COMMIT_STATUS_ID" type="int" nullable="false" autoIncrement="true" unique="true"/>
|
<column name="COMMIT_STATUS_ID" type="int" nullable="false" autoIncrement="true" unique="true" primaryKeyName="IDX_COMMIT_STATUS_PK" primaryKey="true" />
|
||||||
<column name="USER_NAME" type="varchar(100)" nullable="false"/>
|
<column name="USER_NAME" type="varchar(100)" nullable="false"/>
|
||||||
<column name="REPOSITORY_NAME" type="varchar(100)" nullable="false"/>
|
<column name="REPOSITORY_NAME" type="varchar(100)" nullable="false"/>
|
||||||
<column name="COMMIT_ID" type="varchar(40)" nullable="false"/>
|
<column name="COMMIT_ID" type="varchar(40)" nullable="false"/>
|
||||||
@@ -139,7 +136,6 @@
|
|||||||
<column name="UPDATED_DATE" type="datetime" nullable="false"/>
|
<column name="UPDATED_DATE" type="datetime" nullable="false"/>
|
||||||
</createTable>
|
</createTable>
|
||||||
|
|
||||||
<addPrimaryKey constraintName="IDX_COMMIT_STATUS_PK" tableName="COMMIT_STATUS" columnNames="COMMIT_STATUS_ID"/>
|
|
||||||
<addUniqueConstraint constraintName="IDX_COMMIT_STATUS_1" tableName="COMMIT_STATUS" columnNames="USER_NAME, REPOSITORY_NAME, COMMIT_ID, CONTEXT"/>
|
<addUniqueConstraint constraintName="IDX_COMMIT_STATUS_1" tableName="COMMIT_STATUS" columnNames="USER_NAME, REPOSITORY_NAME, COMMIT_ID, CONTEXT"/>
|
||||||
<addForeignKeyConstraint constraintName="IDX_COMMIT_STATUS_FK3" baseTableName="COMMIT_STATUS" baseColumnNames="CREATOR" referencedTableName="ACCOUNT" referencedColumnNames="USER_NAME" onDelete="CASCADE" onUpdate="CASCADE"/>
|
<addForeignKeyConstraint constraintName="IDX_COMMIT_STATUS_FK3" baseTableName="COMMIT_STATUS" baseColumnNames="CREATOR" referencedTableName="ACCOUNT" referencedColumnNames="USER_NAME" onDelete="CASCADE" onUpdate="CASCADE"/>
|
||||||
<addForeignKeyConstraint constraintName="IDX_COMMIT_STATUS_FK2" baseTableName="COMMIT_STATUS" baseColumnNames="USER_NAME" referencedTableName="ACCOUNT" referencedColumnNames="USER_NAME" onDelete="CASCADE" onUpdate="CASCADE"/>
|
<addForeignKeyConstraint constraintName="IDX_COMMIT_STATUS_FK2" baseTableName="COMMIT_STATUS" baseColumnNames="USER_NAME" referencedTableName="ACCOUNT" referencedColumnNames="USER_NAME" onDelete="CASCADE" onUpdate="CASCADE"/>
|
||||||
@@ -218,7 +214,7 @@
|
|||||||
<column name="USER_NAME" type="varchar(100)" nullable="false"/>
|
<column name="USER_NAME" type="varchar(100)" nullable="false"/>
|
||||||
<column name="REPOSITORY_NAME" type="varchar(100)" nullable="false"/>
|
<column name="REPOSITORY_NAME" type="varchar(100)" nullable="false"/>
|
||||||
<column name="ISSUE_ID" type="int" nullable="false"/>
|
<column name="ISSUE_ID" type="int" nullable="false"/>
|
||||||
<column name="COMMENT_ID" type="int" nullable="false" autoIncrement="true" unique="true"/>
|
<column name="COMMENT_ID" type="int" nullable="false" autoIncrement="true" unique="true" primaryKeyName="IDX_ISSUE_COMMENT_PK" primaryKey="true" />
|
||||||
<column name="ACTION" type="varchar(20)" nullable="false"/>
|
<column name="ACTION" type="varchar(20)" nullable="false"/>
|
||||||
<column name="COMMENTED_USER_NAME" type="varchar(100)" nullable="false"/>
|
<column name="COMMENTED_USER_NAME" type="varchar(100)" nullable="false"/>
|
||||||
<column name="CONTENT" type="text" nullable="false"/>
|
<column name="CONTENT" type="text" nullable="false"/>
|
||||||
@@ -226,7 +222,6 @@
|
|||||||
<column name="UPDATED_DATE" type="datetime" nullable="false"/>
|
<column name="UPDATED_DATE" type="datetime" nullable="false"/>
|
||||||
</createTable>
|
</createTable>
|
||||||
|
|
||||||
<addPrimaryKey constraintName="IDX_ISSUE_COMMENT_PK" tableName="ISSUE_COMMENT" columnNames="COMMENT_ID"/>
|
|
||||||
<addForeignKeyConstraint constraintName="IDX_ISSUE_COMMENT_FK0" baseTableName="ISSUE_COMMENT" baseColumnNames="USER_NAME, REPOSITORY_NAME, ISSUE_ID" referencedTableName="ISSUE" referencedColumnNames="USER_NAME, REPOSITORY_NAME, ISSUE_ID"/>
|
<addForeignKeyConstraint constraintName="IDX_ISSUE_COMMENT_FK0" baseTableName="ISSUE_COMMENT" baseColumnNames="USER_NAME, REPOSITORY_NAME, ISSUE_ID" referencedTableName="ISSUE" referencedColumnNames="USER_NAME, REPOSITORY_NAME, ISSUE_ID"/>
|
||||||
|
|
||||||
<!--================================================================================================-->
|
<!--================================================================================================-->
|
||||||
|
|||||||
4
src/main/resources/update/gitbucket-core_4.34.xml
Normal file
4
src/main/resources/update/gitbucket-core_4.34.xml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<changeSet>
|
||||||
|
<dropTable tableName="ACTIVITY" />
|
||||||
|
</changeSet>
|
||||||
@@ -16,7 +16,7 @@ class ScalatraBootstrap extends LifeCycle with SystemSettingsService {
|
|||||||
context.getSessionCookieConfig.setSecure(true)
|
context.getSessionCookieConfig.setSecure(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register TransactionFilter and BasicAuthenticationFilter at first
|
// Register TransactionFilter at first
|
||||||
context.addFilter("transactionFilter", new TransactionFilter)
|
context.addFilter("transactionFilter", new TransactionFilter)
|
||||||
context
|
context
|
||||||
.getFilterRegistration("transactionFilter")
|
.getFilterRegistration("transactionFilter")
|
||||||
|
|||||||
@@ -1,7 +1,22 @@
|
|||||||
package gitbucket.core
|
package gitbucket.core
|
||||||
|
|
||||||
import io.github.gitbucket.solidbase.migration.{SqlMigration, LiquibaseMigration}
|
import java.io.FileOutputStream
|
||||||
import io.github.gitbucket.solidbase.model.{Version, Module}
|
import java.nio.charset.StandardCharsets
|
||||||
|
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(
|
||||||
@@ -65,5 +80,38 @@ 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")
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ case class ApiPullRequest(
|
|||||||
body: String,
|
body: String,
|
||||||
user: ApiUser,
|
user: ApiUser,
|
||||||
labels: List[ApiLabel],
|
labels: List[ApiLabel],
|
||||||
assignee: Option[ApiUser]
|
assignee: Option[ApiUser],
|
||||||
|
draft: Option[Boolean]
|
||||||
) {
|
) {
|
||||||
val id = 0 // dummy id
|
val id = 0 // dummy id
|
||||||
val html_url = ApiPath(s"${base.repo.html_url.path}/pull/${number}")
|
val html_url = ApiPath(s"${base.repo.html_url.path}/pull/${number}")
|
||||||
@@ -62,7 +63,8 @@ object ApiPullRequest {
|
|||||||
body = issue.content.getOrElse(""),
|
body = issue.content.getOrElse(""),
|
||||||
user = user,
|
user = user,
|
||||||
labels = labels,
|
labels = labels,
|
||||||
assignee = assignee
|
assignee = assignee,
|
||||||
|
draft = Some(pullRequest.isDraft)
|
||||||
)
|
)
|
||||||
|
|
||||||
case class Commit(sha: String, ref: String, repo: ApiRepository)(baseOwner: String) {
|
case class Commit(sha: String, ref: String, repo: ApiRepository)(baseOwner: String) {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ case class ApiReleaseAsset(name: String, size: Long)(tag: String, fileName: Stri
|
|||||||
val label = name
|
val label = name
|
||||||
val file_id = fileName
|
val file_id = fileName
|
||||||
val browser_download_url = ApiPath(
|
val browser_download_url = ApiPath(
|
||||||
s"/api/v3/repos/${repositoryName.fullName}/releases/${tag}/assets/${fileName}"
|
s"/${repositoryName.fullName}/releases/${tag}/assets/${fileName}"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ case class CreateAPullRequest(
|
|||||||
head: String,
|
head: String,
|
||||||
base: String,
|
base: String,
|
||||||
body: Option[String],
|
body: Option[String],
|
||||||
maintainer_can_modify: Option[Boolean]
|
maintainer_can_modify: Option[Boolean],
|
||||||
|
draft: Option[Boolean]
|
||||||
)
|
)
|
||||||
|
|
||||||
case class CreateAPullRequestAlt(
|
case class CreateAPullRequestAlt(
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import gitbucket.core.util._
|
|||||||
import org.scalatra.i18n.Messages
|
import org.scalatra.i18n.Messages
|
||||||
import org.scalatra.BadRequest
|
import org.scalatra.BadRequest
|
||||||
import org.scalatra.forms._
|
import org.scalatra.forms._
|
||||||
|
import org.scalatra.Forbidden
|
||||||
|
|
||||||
class AccountController
|
class AccountController
|
||||||
extends AccountControllerBase
|
extends AccountControllerBase
|
||||||
@@ -34,6 +35,7 @@ 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
|
||||||
@@ -82,7 +84,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
|||||||
|
|
||||||
val newForm = mapping(
|
val newForm = mapping(
|
||||||
"userName" -> trim(label("User name", text(required, maxlength(100), identifier, uniqueUserName, reservedNames))),
|
"userName" -> trim(label("User name", text(required, maxlength(100), identifier, uniqueUserName, reservedNames))),
|
||||||
"password" -> trim(label("Password", text(required, maxlength(20), password))),
|
"password" -> trim(label("Password", text(required, maxlength(20)))),
|
||||||
"fullName" -> trim(label("Full Name", text(required, maxlength(100)))),
|
"fullName" -> trim(label("Full Name", text(required, maxlength(100)))),
|
||||||
"mailAddress" -> trim(label("Mail Address", text(required, maxlength(100), uniqueMailAddress()))),
|
"mailAddress" -> trim(label("Mail Address", text(required, maxlength(100), uniqueMailAddress()))),
|
||||||
"extraMailAddresses" -> list(
|
"extraMailAddresses" -> list(
|
||||||
@@ -94,7 +96,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
|||||||
)(AccountNewForm.apply)
|
)(AccountNewForm.apply)
|
||||||
|
|
||||||
val editForm = mapping(
|
val editForm = mapping(
|
||||||
"password" -> trim(label("Password", optional(text(maxlength(20), password)))),
|
"password" -> trim(label("Password", optional(text(maxlength(20))))),
|
||||||
"fullName" -> trim(label("Full Name", text(required, maxlength(100)))),
|
"fullName" -> trim(label("Full Name", text(required, maxlength(100)))),
|
||||||
"mailAddress" -> trim(label("Mail Address", text(required, maxlength(100), uniqueMailAddress("userName")))),
|
"mailAddress" -> trim(label("Mail Address", text(required, maxlength(100), uniqueMailAddress("userName")))),
|
||||||
"extraMailAddresses" -> list(
|
"extraMailAddresses" -> list(
|
||||||
@@ -691,27 +693,28 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
|||||||
* Create new repository.
|
* Create new repository.
|
||||||
*/
|
*/
|
||||||
post("/new", newRepositoryForm)(usersOnly { form =>
|
post("/new", newRepositoryForm)(usersOnly { form =>
|
||||||
LockUtil.lock(s"${form.owner}/${form.name}") {
|
if (context.settings.repositoryOperation.create || context.loginAccount.get.isAdmin) {
|
||||||
if (getRepository(form.owner, form.name).isEmpty) {
|
LockUtil.lock(s"${form.owner}/${form.name}") {
|
||||||
createRepository(
|
if (getRepository(form.owner, form.name).isEmpty) {
|
||||||
context.loginAccount.get,
|
createRepository(
|
||||||
form.owner,
|
context.loginAccount.get,
|
||||||
form.name,
|
form.owner,
|
||||||
form.description,
|
form.name,
|
||||||
form.isPrivate,
|
form.description,
|
||||||
form.initOption,
|
form.isPrivate,
|
||||||
form.sourceUrl
|
form.initOption,
|
||||||
)
|
form.sourceUrl
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
// redirect to the repository
|
||||||
|
redirect(s"/${form.owner}/${form.name}")
|
||||||
// redirect to the repository
|
} else Forbidden()
|
||||||
redirect(s"/${form.owner}/${form.name}")
|
|
||||||
})
|
})
|
||||||
|
|
||||||
get("/:owner/:repository/fork")(readableUsersOnly { repository =>
|
get("/:owner/:repository/fork")(readableUsersOnly { repository =>
|
||||||
if (repository.repository.options.allowFork) {
|
val loginAccount = context.loginAccount.get
|
||||||
val loginAccount = context.loginAccount.get
|
if (repository.repository.options.allowFork && (context.settings.repositoryOperation.fork || loginAccount.isAdmin)) {
|
||||||
val loginUserName = loginAccount.userName
|
val loginUserName = loginAccount.userName
|
||||||
val groups = getGroupsByUserName(loginUserName)
|
val groups = getGroupsByUserName(loginUserName)
|
||||||
groups match {
|
groups match {
|
||||||
@@ -735,8 +738,8 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
|||||||
})
|
})
|
||||||
|
|
||||||
post("/:owner/:repository/fork", accountForm)(readableUsersOnly { (form, repository) =>
|
post("/:owner/:repository/fork", accountForm)(readableUsersOnly { (form, repository) =>
|
||||||
if (repository.repository.options.allowFork) {
|
val loginAccount = context.loginAccount.get
|
||||||
val loginAccount = context.loginAccount.get
|
if (repository.repository.options.allowFork && (context.settings.repositoryOperation.fork || loginAccount.isAdmin)) {
|
||||||
val loginUserName = loginAccount.userName
|
val loginUserName = loginAccount.userName
|
||||||
val accountName = form.accountName
|
val accountName = form.accountName
|
||||||
|
|
||||||
@@ -750,7 +753,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
|||||||
// redirect to the repository
|
// redirect to the repository
|
||||||
redirect(s"/${accountName}/${repository.name}")
|
redirect(s"/${accountName}/${repository.name}")
|
||||||
}
|
}
|
||||||
} else BadRequest()
|
} else Forbidden()
|
||||||
})
|
})
|
||||||
|
|
||||||
private def existsAccount: Constraint = new Constraint() {
|
private def existsAccount: Constraint = new Constraint() {
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ 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,12 +22,18 @@ 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 =>
|
||||||
|
|
||||||
get("/dashboard/repos")(usersOnly {
|
get("/dashboard/repos")(usersOnly {
|
||||||
val repos = getVisibleRepositories(context.loginAccount, withoutPhysicalInfo = true)
|
val repos = getVisibleRepositories(
|
||||||
|
context.loginAccount,
|
||||||
|
None,
|
||||||
|
withoutPhysicalInfo = true,
|
||||||
|
limit = context.settings.limitVisibleRepositories
|
||||||
|
)
|
||||||
html.repos(getGroupNames(context.loginAccount.get.userName), repos, repos)
|
html.repos(getGroupNames(context.loginAccount.get.userName), repos, repos)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -93,7 +99,12 @@ trait DashboardControllerBase extends ControllerBase {
|
|||||||
},
|
},
|
||||||
filter,
|
filter,
|
||||||
getGroupNames(userName),
|
getGroupNames(userName),
|
||||||
getVisibleRepositories(context.loginAccount, withoutPhysicalInfo = true)
|
getVisibleRepositories(
|
||||||
|
context.loginAccount,
|
||||||
|
None,
|
||||||
|
withoutPhysicalInfo = true,
|
||||||
|
limit = context.settings.limitVisibleRepositories
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,7 +129,12 @@ trait DashboardControllerBase extends ControllerBase {
|
|||||||
},
|
},
|
||||||
filter,
|
filter,
|
||||||
getGroupNames(userName),
|
getGroupNames(userName),
|
||||||
getVisibleRepositories(context.loginAccount, withoutPhysicalInfo = true)
|
getVisibleRepositories(
|
||||||
|
context.loginAccount,
|
||||||
|
None,
|
||||||
|
withoutPhysicalInfo = true,
|
||||||
|
limit = context.settings.limitVisibleRepositories
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import org.scalatra.servlet.{FileItem, FileUploadSupport, MultipartConfig}
|
|||||||
import org.apache.commons.io.{FileUtils, IOUtils}
|
import org.apache.commons.io.{FileUtils, IOUtils}
|
||||||
|
|
||||||
import scala.util.Using
|
import scala.util.Using
|
||||||
|
import gitbucket.core.service.SystemSettingsService
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides Ajax based file upload functionality.
|
* Provides Ajax based file upload functionality.
|
||||||
@@ -28,11 +29,11 @@ class FileUploadController
|
|||||||
with FileUploadSupport
|
with FileUploadSupport
|
||||||
with RepositoryService
|
with RepositoryService
|
||||||
with AccountService
|
with AccountService
|
||||||
with ReleaseService {
|
with ReleaseService
|
||||||
|
with SystemSettingsService {
|
||||||
configureMultipartHandling(MultipartConfig(maxFileSize = Some(FileUtil.MaxFileSize)))
|
|
||||||
|
|
||||||
post("/image") {
|
post("/image") {
|
||||||
|
setMultipartConfig()
|
||||||
execute(
|
execute(
|
||||||
{ (file, fileId) =>
|
{ (file, fileId) =>
|
||||||
FileUtils
|
FileUtils
|
||||||
@@ -44,6 +45,7 @@ class FileUploadController
|
|||||||
}
|
}
|
||||||
|
|
||||||
post("/tmp") {
|
post("/tmp") {
|
||||||
|
setMultipartConfig()
|
||||||
execute(
|
execute(
|
||||||
{ (file, fileId) =>
|
{ (file, fileId) =>
|
||||||
FileUtils
|
FileUtils
|
||||||
@@ -55,6 +57,7 @@ class FileUploadController
|
|||||||
}
|
}
|
||||||
|
|
||||||
post("/file/:owner/:repository") {
|
post("/file/:owner/:repository") {
|
||||||
|
setMultipartConfig()
|
||||||
execute(
|
execute(
|
||||||
{ (file, fileId) =>
|
{ (file, fileId) =>
|
||||||
FileUtils.writeByteArrayToFile(
|
FileUtils.writeByteArrayToFile(
|
||||||
@@ -70,6 +73,7 @@ class FileUploadController
|
|||||||
}
|
}
|
||||||
|
|
||||||
post("/wiki/:owner/:repository") {
|
post("/wiki/:owner/:repository") {
|
||||||
|
setMultipartConfig()
|
||||||
// Don't accept not logged-in users
|
// Don't accept not logged-in users
|
||||||
session.get(Keys.Session.LoginAccount).collect {
|
session.get(Keys.Session.LoginAccount).collect {
|
||||||
case loginAccount: Account =>
|
case loginAccount: Account =>
|
||||||
@@ -128,6 +132,7 @@ class FileUploadController
|
|||||||
}
|
}
|
||||||
|
|
||||||
post("/release/:owner/:repository/:tag") {
|
post("/release/:owner/:repository/:tag") {
|
||||||
|
setMultipartConfigForLargeFile()
|
||||||
session
|
session
|
||||||
.get(Keys.Session.LoginAccount)
|
.get(Keys.Session.LoginAccount)
|
||||||
.collect {
|
.collect {
|
||||||
@@ -150,6 +155,7 @@ class FileUploadController
|
|||||||
|
|
||||||
post("/import") {
|
post("/import") {
|
||||||
import JDBCUtil._
|
import JDBCUtil._
|
||||||
|
setMultipartConfig()
|
||||||
session.get(Keys.Session.LoginAccount).collect {
|
session.get(Keys.Session.LoginAccount).collect {
|
||||||
case loginAccount: Account if loginAccount.isAdmin =>
|
case loginAccount: Account if loginAccount.isAdmin =>
|
||||||
execute({ (file, fileId) =>
|
execute({ (file, fileId) =>
|
||||||
@@ -159,6 +165,18 @@ class FileUploadController
|
|||||||
redirect("/admin/data")
|
redirect("/admin/data")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private def setMultipartConfig(): Unit = {
|
||||||
|
val settings = loadSystemSettings()
|
||||||
|
val config = MultipartConfig(maxFileSize = Some(settings.upload.maxFileSize))
|
||||||
|
config.apply(request.getServletContext())
|
||||||
|
}
|
||||||
|
|
||||||
|
private def setMultipartConfigForLargeFile(): Unit = {
|
||||||
|
val settings = loadSystemSettings()
|
||||||
|
val config = MultipartConfig(maxFileSize = Some(settings.upload.largeMaxFileSize))
|
||||||
|
config.apply(request.getServletContext())
|
||||||
|
}
|
||||||
|
|
||||||
private def onlyWikiEditable(owner: String, repository: String, loginAccount: Account)(action: => Any): Any = {
|
private def onlyWikiEditable(owner: String, repository: String, loginAccount: Account)(action: => Any): Any = {
|
||||||
implicit val session = Database.getSession(request)
|
implicit val session = Database.getSession(request)
|
||||||
getRepository(owner, repository) match {
|
getRepository(owner, repository) match {
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ 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
|
||||||
@@ -65,7 +66,12 @@ trait IndexControllerBase extends ControllerBase {
|
|||||||
val visibleOwnerSet: Set[String] = Set(account.userName) ++ getGroupsByUserName(account.userName)
|
val visibleOwnerSet: Set[String] = Set(account.userName) ++ getGroupsByUserName(account.userName)
|
||||||
gitbucket.core.html.index(
|
gitbucket.core.html.index(
|
||||||
getRecentActivitiesByOwners(visibleOwnerSet),
|
getRecentActivitiesByOwners(visibleOwnerSet),
|
||||||
getVisibleRepositories(Some(account), withoutPhysicalInfo = true),
|
getVisibleRepositories(
|
||||||
|
Some(account),
|
||||||
|
None,
|
||||||
|
withoutPhysicalInfo = true,
|
||||||
|
limit = context.settings.limitVisibleRepositories
|
||||||
|
),
|
||||||
showBannerToCreatePersonalAccessToken = hasAccountFederation(account.userName) && !hasAccessToken(
|
showBannerToCreatePersonalAccessToken = hasAccountFederation(account.userName) && !hasAccessToken(
|
||||||
account.userName
|
account.userName
|
||||||
)
|
)
|
||||||
@@ -73,7 +79,7 @@ trait IndexControllerBase extends ControllerBase {
|
|||||||
}
|
}
|
||||||
.getOrElse {
|
.getOrElse {
|
||||||
gitbucket.core.html.index(
|
gitbucket.core.html.index(
|
||||||
getRecentActivities(),
|
getRecentPublicActivities(),
|
||||||
getVisibleRepositories(None, withoutPhysicalInfo = true),
|
getVisibleRepositories(None, withoutPhysicalInfo = true),
|
||||||
showBannerToCreatePersonalAccessToken = false
|
showBannerToCreatePersonalAccessToken = false
|
||||||
)
|
)
|
||||||
@@ -156,7 +162,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(getRecentActivities())
|
xml.feed(getRecentPublicActivities())
|
||||||
}
|
}
|
||||||
|
|
||||||
post("/sidebar-collapse") {
|
post("/sidebar-collapse") {
|
||||||
@@ -279,11 +285,28 @@ trait IndexControllerBase extends ControllerBase {
|
|||||||
get("/search") {
|
get("/search") {
|
||||||
val query = params.getOrElse("query", "").trim.toLowerCase
|
val query = params.getOrElse("query", "").trim.toLowerCase
|
||||||
val visibleRepositories =
|
val visibleRepositories =
|
||||||
getVisibleRepositories(context.loginAccount, repositoryUserName = None, withoutPhysicalInfo = true)
|
getVisibleRepositories(
|
||||||
val repositories = visibleRepositories.filter { repository =>
|
context.loginAccount,
|
||||||
|
None,
|
||||||
|
withoutPhysicalInfo = true,
|
||||||
|
limit = context.settings.limitVisibleRepositories
|
||||||
|
)
|
||||||
|
|
||||||
|
val repositories = {
|
||||||
|
context.settings.limitVisibleRepositories match {
|
||||||
|
case true =>
|
||||||
|
getVisibleRepositories(
|
||||||
|
context.loginAccount,
|
||||||
|
None,
|
||||||
|
withoutPhysicalInfo = true,
|
||||||
|
limit = false
|
||||||
|
)
|
||||||
|
case false => visibleRepositories
|
||||||
|
}
|
||||||
|
}.filter { repository =>
|
||||||
repository.name.toLowerCase.indexOf(query) >= 0 || repository.owner.toLowerCase.indexOf(query) >= 0
|
repository.name.toLowerCase.indexOf(query) >= 0 || repository.owner.toLowerCase.indexOf(query) >= 0
|
||||||
}
|
}
|
||||||
|
|
||||||
gitbucket.core.search.html.repositories(query, repositories, visibleRepositories)
|
gitbucket.core.search.html.repositories(query, repositories, visibleRepositories)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ 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,6 +36,7 @@ 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,7 +2,14 @@ package gitbucket.core.controller
|
|||||||
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
import gitbucket.core.service.{AccountService, ActivityService, ReleaseService, RepositoryService}
|
import gitbucket.core.service.{
|
||||||
|
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._
|
||||||
@@ -10,6 +17,7 @@ import org.scalatra.forms._
|
|||||||
import gitbucket.core.releases.html
|
import gitbucket.core.releases.html
|
||||||
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 scala.util.Using
|
import scala.util.Using
|
||||||
|
|
||||||
class ReleaseController
|
class ReleaseController
|
||||||
@@ -21,6 +29,7 @@ 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
|
||||||
@@ -42,17 +51,14 @@ trait ReleaseControllerBase extends ControllerBase {
|
|||||||
)(ReleaseForm.apply)
|
)(ReleaseForm.apply)
|
||||||
|
|
||||||
get("/:owner/:repository/releases")(referrersOnly { repository =>
|
get("/:owner/:repository/releases")(referrersOnly { repository =>
|
||||||
val releases = getReleases(repository.owner, repository.name)
|
val page = PaginationHelper.page(params.get("page"))
|
||||||
val assets = getReleaseAssetsMap(repository.owner, repository.name)
|
|
||||||
|
|
||||||
html.list(
|
html.list(
|
||||||
repository,
|
repository,
|
||||||
repository.tags.reverse.map { tag =>
|
fetchReleases(repository, page),
|
||||||
(tag, releases.find(_.tag == tag.name).map { release =>
|
hasDeveloperRole(repository.owner, repository.name, context.loginAccount),
|
||||||
(release, assets(release))
|
page,
|
||||||
})
|
repository.tags.size
|
||||||
},
|
|
||||||
hasDeveloperRole(repository.owner, repository.name, context.loginAccount)
|
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -215,4 +221,21 @@ trait ReleaseControllerBase extends ControllerBase {
|
|||||||
redirect(s"/${repository.owner}/${repository.name}/releases")
|
redirect(s"/${repository.owner}/${repository.name}/releases")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
private def fetchReleases(repository: RepositoryService.RepositoryInfo, page: Int) = {
|
||||||
|
|
||||||
|
import gitbucket.core.service.ReleaseService._
|
||||||
|
|
||||||
|
val (offset, limit) = ((page - 1) * ReleaseLimit, ReleaseLimit)
|
||||||
|
val tagsToDisplay = repository.tags.reverse.slice(offset, offset + limit)
|
||||||
|
|
||||||
|
val releases = getReleases(repository.owner, repository.name, tagsToDisplay)
|
||||||
|
val assets = getReleaseAssetsMap(repository.owner, repository.name, releases)
|
||||||
|
|
||||||
|
val tagsWithReleases = tagsToDisplay.map { tag =>
|
||||||
|
(tag, releases.find(_.tag == tag.name).map { release =>
|
||||||
|
(release, assets(release))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
tagsWithReleases
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import org.eclipse.jgit.lib.Constants
|
|||||||
import org.eclipse.jgit.lib.ObjectId
|
import org.eclipse.jgit.lib.ObjectId
|
||||||
|
|
||||||
import scala.util.Using
|
import scala.util.Using
|
||||||
|
import org.scalatra.Forbidden
|
||||||
|
|
||||||
class RepositorySettingsController
|
class RepositorySettingsController
|
||||||
extends RepositorySettingsControllerBase
|
extends RepositorySettingsControllerBase
|
||||||
@@ -29,8 +30,10 @@ 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
|
||||||
@@ -39,12 +42,12 @@ 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 =>
|
||||||
|
|
||||||
// for repository options
|
// for repository options
|
||||||
case class OptionsForm(
|
case class OptionsForm(
|
||||||
repositoryName: String,
|
|
||||||
description: Option[String],
|
description: Option[String],
|
||||||
isPrivate: Boolean,
|
isPrivate: Boolean,
|
||||||
issuesOption: String,
|
issuesOption: String,
|
||||||
@@ -57,9 +60,6 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
|||||||
)
|
)
|
||||||
|
|
||||||
val optionsForm = mapping(
|
val optionsForm = mapping(
|
||||||
"repositoryName" -> trim(
|
|
||||||
label("Repository Name", text(required, maxlength(100), repository, renameRepositoryName))
|
|
||||||
),
|
|
||||||
"description" -> trim(label("Description", optional(text()))),
|
"description" -> trim(label("Description", optional(text()))),
|
||||||
"isPrivate" -> trim(label("Repository Type", boolean())),
|
"isPrivate" -> trim(label("Repository Type", boolean())),
|
||||||
"issuesOption" -> trim(label("Issues Option", text(required, featureOption))),
|
"issuesOption" -> trim(label("Issues Option", text(required, featureOption))),
|
||||||
@@ -100,9 +100,16 @@ 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
|
||||||
|
case class RenameRepositoryForm(repositoryName: String)
|
||||||
|
|
||||||
|
val renameForm = mapping(
|
||||||
|
"repositoryName" -> trim(
|
||||||
|
label("New repository name", text(required, maxlength(100), repository, renameRepositoryName))
|
||||||
)
|
)
|
||||||
|
)(RenameRepositoryForm.apply)
|
||||||
|
|
||||||
// for transfer ownership
|
// for transfer ownership
|
||||||
case class TransferOwnerShipForm(newOwner: String)
|
case class TransferOwnerShipForm(newOwner: String)
|
||||||
@@ -144,13 +151,8 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
|||||||
form.mergeOptions,
|
form.mergeOptions,
|
||||||
form.defaultMergeOption
|
form.defaultMergeOption
|
||||||
)
|
)
|
||||||
// Change repository name
|
|
||||||
if (repository.name != form.repositoryName) {
|
|
||||||
// Update database
|
|
||||||
renameRepository(repository.owner, repository.name, repository.owner, form.repositoryName)
|
|
||||||
}
|
|
||||||
flash.update("info", "Repository settings has been updated.")
|
flash.update("info", "Repository settings has been updated.")
|
||||||
redirect(s"/${repository.owner}/${form.repositoryName}/settings/options")
|
redirect(s"/${repository.owner}/${repository.name}/settings/options")
|
||||||
})
|
})
|
||||||
|
|
||||||
/** branch settings */
|
/** branch settings */
|
||||||
@@ -250,9 +252,10 @@ 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]] = h.map { h =>
|
def _headers(h: Array[org.apache.http.Header]): Array[Array[String]] =
|
||||||
Array(h.getName, h.getValue)
|
h.map { h =>
|
||||||
}
|
Array(h.getName, h.getValue)
|
||||||
|
}
|
||||||
|
|
||||||
Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) {
|
Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) {
|
||||||
git =>
|
git =>
|
||||||
@@ -364,24 +367,56 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
|||||||
html.danger(_, flash.get("info"))
|
html.danger(_, flash.get("info"))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rename repository.
|
||||||
|
*/
|
||||||
|
post("/:owner/:repository/settings/rename", renameForm)(ownerOnly { (form, repository) =>
|
||||||
|
if (context.settings.repositoryOperation.rename || context.loginAccount.get.isAdmin) {
|
||||||
|
if (repository.name != form.repositoryName) {
|
||||||
|
// Update database and move git repository
|
||||||
|
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}")
|
||||||
|
} else Forbidden()
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transfer repository ownership.
|
* Transfer repository ownership.
|
||||||
*/
|
*/
|
||||||
post("/:owner/:repository/settings/transfer", transferForm)(ownerOnly { (form, repository) =>
|
post("/:owner/:repository/settings/transfer", transferForm)(ownerOnly { (form, repository) =>
|
||||||
// Change repository owner
|
if (context.settings.repositoryOperation.transfer || context.loginAccount.get.isAdmin) {
|
||||||
if (repository.owner != form.newOwner) {
|
// Change repository owner
|
||||||
renameRepository(repository.owner, repository.name, form.newOwner, repository.name)
|
if (repository.owner != form.newOwner) {
|
||||||
}
|
// Update database and move git repository
|
||||||
redirect(s"/${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}")
|
||||||
|
} else Forbidden()
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete the repository.
|
* Delete the repository.
|
||||||
*/
|
*/
|
||||||
post("/:owner/:repository/settings/delete")(ownerOnly { repository =>
|
post("/:owner/:repository/settings/delete")(ownerOnly { repository =>
|
||||||
// Delete the repository and related files
|
if (context.settings.repositoryOperation.delete || context.loginAccount.get.isAdmin) {
|
||||||
deleteRepository(repository.repository)
|
// Delete the repository and related files
|
||||||
redirect(s"/${repository.owner}")
|
deleteRepository(repository.repository)
|
||||||
|
redirect(s"/${repository.owner}")
|
||||||
|
} else Forbidden()
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -418,32 +453,34 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
|||||||
/**
|
/**
|
||||||
* Provides duplication check for web hook url.
|
* Provides duplication check for web hook url.
|
||||||
*/
|
*/
|
||||||
private def webHook(needExists: Boolean): Constraint = new Constraint() {
|
private def webHook(needExists: Boolean): Constraint =
|
||||||
override def validate(name: String, value: String, messages: Messages): Option[String] =
|
new Constraint() {
|
||||||
if (getWebHook(params("owner"), params("repository"), value).isDefined != needExists) {
|
override def validate(name: String, value: String, messages: Messages): Option[String] =
|
||||||
Some(if (needExists) {
|
if (getWebHook(params("owner"), params("repository"), value).isDefined != needExists) {
|
||||||
"URL had not been registered yet."
|
Some(if (needExists) {
|
||||||
|
"URL had not been registered yet."
|
||||||
|
} else {
|
||||||
|
"URL had been registered already."
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
"URL had been registered already."
|
None
|
||||||
})
|
}
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private def webhookEvents = new ValueType[Set[WebHook.Event]] {
|
|
||||||
def convert(name: String, params: Map[String, Seq[String]], messages: Messages): Set[WebHook.Event] = {
|
|
||||||
WebHook.Event.values.flatMap { t =>
|
|
||||||
params.get(name + "." + t.name).map(_ => t)
|
|
||||||
}.toSet
|
|
||||||
}
|
}
|
||||||
def validate(name: String, params: Map[String, Seq[String]], messages: Messages): Seq[(String, String)] =
|
|
||||||
if (convert(name, params, messages).isEmpty) {
|
private def webhookEvents =
|
||||||
Seq(name -> messages("error.required").format(name))
|
new ValueType[Set[WebHook.Event]] {
|
||||||
} else {
|
def convert(name: String, params: Map[String, Seq[String]], messages: Messages): Set[WebHook.Event] = {
|
||||||
Nil
|
WebHook.Event.values.flatMap { t =>
|
||||||
|
params.get(name + "." + t.name).map(_ => t)
|
||||||
|
}.toSet
|
||||||
}
|
}
|
||||||
}
|
def validate(name: String, params: Map[String, Seq[String]], messages: Messages): Seq[(String, String)] =
|
||||||
|
if (convert(name, params, messages).isEmpty) {
|
||||||
|
Seq(name -> messages("error.required").format(name))
|
||||||
|
} else {
|
||||||
|
Nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// /**
|
// /**
|
||||||
// * Provides Constraint to validate the collaborator name.
|
// * Provides Constraint to validate the collaborator name.
|
||||||
@@ -463,70 +500,77 @@ trait RepositorySettingsControllerBase extends ControllerBase {
|
|||||||
/**
|
/**
|
||||||
* Duplicate check for the rename repository name.
|
* Duplicate check for the rename repository name.
|
||||||
*/
|
*/
|
||||||
private def renameRepositoryName: Constraint = new Constraint() {
|
private def renameRepositoryName: Constraint =
|
||||||
override def validate(
|
new Constraint() {
|
||||||
name: String,
|
override def validate(
|
||||||
value: String,
|
name: String,
|
||||||
params: Map[String, Seq[String]],
|
value: String,
|
||||||
messages: Messages
|
params: Map[String, Seq[String]],
|
||||||
): Option[String] = {
|
messages: Messages
|
||||||
for {
|
): Option[String] = {
|
||||||
repoName <- params.optionValue("repository") if repoName != value
|
for {
|
||||||
userName <- params.optionValue("owner")
|
repoName <- params.optionValue("repository") if repoName != value
|
||||||
_ <- getRepositoryNamesOfUser(userName).find(_ == value)
|
userName <- params.optionValue("owner")
|
||||||
} yield {
|
_ <- getRepositoryNamesOfUser(userName).find(_ == value)
|
||||||
"Repository already exists."
|
} yield {
|
||||||
|
"Repository already exists."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
private def featureOption: Constraint = new Constraint() {
|
private def featureOption: Constraint =
|
||||||
override def validate(
|
new Constraint() {
|
||||||
name: String,
|
override def validate(
|
||||||
value: String,
|
name: String,
|
||||||
params: Map[String, Seq[String]],
|
value: String,
|
||||||
messages: Messages
|
params: Map[String, Seq[String]],
|
||||||
): Option[String] =
|
messages: Messages
|
||||||
if (Seq("DISABLE", "PRIVATE", "PUBLIC", "ALL").contains(value)) None else Some("Option is invalid.")
|
): Option[String] =
|
||||||
}
|
if (Seq("DISABLE", "PRIVATE", "PUBLIC", "ALL").contains(value)) None else Some("Option is invalid.")
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides Constraint to validate the repository transfer user.
|
* Provides Constraint to validate the repository transfer user.
|
||||||
*/
|
*/
|
||||||
private def transferUser: Constraint = new Constraint() {
|
private def transferUser: Constraint =
|
||||||
override def validate(name: String, value: String, messages: Messages): Option[String] =
|
new Constraint() {
|
||||||
getAccountByUserName(value) match {
|
override def validate(name: String, value: String, messages: Messages): Option[String] =
|
||||||
case None => Some("User does not exist.")
|
getAccountByUserName(value) match {
|
||||||
case Some(x) =>
|
case None => Some("User does not exist.")
|
||||||
if (x.userName == params("owner")) {
|
case Some(x) =>
|
||||||
Some("This is current repository owner.")
|
if (x.userName == params("owner")) {
|
||||||
} else {
|
Some("This is current repository owner.")
|
||||||
params.get("repository").flatMap { repositoryName =>
|
} else {
|
||||||
getRepositoryNamesOfUser(x.userName).find(_ == repositoryName).map { _ =>
|
params.get("repository").flatMap { repositoryName =>
|
||||||
"User already has same repository."
|
getRepositoryNamesOfUser(x.userName).find(_ == repositoryName).map { _ =>
|
||||||
|
"User already has same repository."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private def mergeOptions = new ValueType[Seq[String]] {
|
private def mergeOptions =
|
||||||
override def convert(name: String, params: Map[String, Seq[String]], messages: Messages): Seq[String] = {
|
new ValueType[Seq[String]] {
|
||||||
params.getOrElse("mergeOptions", Nil)
|
override def convert(name: String, params: Map[String, Seq[String]], messages: Messages): Seq[String] = {
|
||||||
}
|
params.getOrElse("mergeOptions", Nil)
|
||||||
override def validate(name: String, params: Map[String, Seq[String]], messages: Messages): Seq[(String, String)] = {
|
}
|
||||||
val mergeOptions = params.getOrElse("mergeOptions", Nil)
|
override def validate(
|
||||||
if (mergeOptions.isEmpty) {
|
name: String,
|
||||||
Seq("mergeOptions" -> "At least one option must be enabled.")
|
params: Map[String, Seq[String]],
|
||||||
} else if (!mergeOptions.forall(x => Seq("merge-commit", "squash", "rebase").contains(x))) {
|
messages: Messages
|
||||||
Seq("mergeOptions" -> "mergeOptions are invalid.")
|
): Seq[(String, String)] = {
|
||||||
} else {
|
val mergeOptions = params.getOrElse("mergeOptions", Nil)
|
||||||
Nil
|
if (mergeOptions.isEmpty) {
|
||||||
|
Seq("mergeOptions" -> "At least one option must be enabled.")
|
||||||
|
} else if (!mergeOptions.forall(x => Seq("merge-commit", "squash", "rebase").contains(x))) {
|
||||||
|
Seq("mergeOptions" -> "mergeOptions are invalid.")
|
||||||
|
} else {
|
||||||
|
Nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ class RepositoryViewerController
|
|||||||
with WebHookPullRequestService
|
with WebHookPullRequestService
|
||||||
with WebHookPullRequestReviewCommentService
|
with WebHookPullRequestReviewCommentService
|
||||||
with ProtectedBranchService
|
with ProtectedBranchService
|
||||||
|
with RequestCache
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The repository viewer.
|
* The repository viewer.
|
||||||
@@ -928,8 +929,9 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
|||||||
defining(JGitUtil.getRevCommitFromId(git, objectId)) { revCommit =>
|
defining(JGitUtil.getRevCommitFromId(git, objectId)) { revCommit =>
|
||||||
val lastModifiedCommit =
|
val lastModifiedCommit =
|
||||||
if (path == ".") revCommit else JGitUtil.getLastModifiedCommit(git, revCommit, path)
|
if (path == ".") revCommit else JGitUtil.getLastModifiedCommit(git, revCommit, path)
|
||||||
|
val commitCount = JGitUtil.getCommitCount(git, lastModifiedCommit.getName)
|
||||||
// get files
|
// get files
|
||||||
val files = JGitUtil.getFileList(git, revision, path, context.settings.baseUrl)
|
val files = JGitUtil.getFileList(git, revision, path, context.settings.baseUrl, commitCount)
|
||||||
val parentPath = if (path == ".") Nil else path.split("/").toList
|
val parentPath = if (path == ".") Nil else path.split("/").toList
|
||||||
// process README.md or README.markdown
|
// process README.md or README.markdown
|
||||||
val readme = files
|
val readme = files
|
||||||
@@ -950,7 +952,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
|||||||
repository,
|
repository,
|
||||||
if (path == ".") Nil else path.split("/").toList, // current path
|
if (path == ".") Nil else path.split("/").toList, // current path
|
||||||
new JGitUtil.CommitInfo(lastModifiedCommit), // last modified commit
|
new JGitUtil.CommitInfo(lastModifiedCommit), // last modified commit
|
||||||
JGitUtil.getCommitCount(git, lastModifiedCommit.getName),
|
commitCount,
|
||||||
files,
|
files,
|
||||||
readme,
|
readme,
|
||||||
hasDeveloperRole(repository.owner, repository.name, context.loginAccount),
|
hasDeveloperRole(repository.owner, repository.name, context.loginAccount),
|
||||||
|
|||||||
@@ -38,14 +38,22 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
|||||||
"information" -> trim(label("Information", optional(text()))),
|
"information" -> trim(label("Information", optional(text()))),
|
||||||
"allowAccountRegistration" -> trim(label("Account registration", boolean())),
|
"allowAccountRegistration" -> trim(label("Account registration", boolean())),
|
||||||
"allowAnonymousAccess" -> trim(label("Anonymous access", boolean())),
|
"allowAnonymousAccess" -> trim(label("Anonymous access", boolean())),
|
||||||
"isCreateRepoOptionPublic" -> trim(label("Default option to create a new repository", boolean())),
|
"isCreateRepoOptionPublic" -> trim(label("Default visibility of new repository", boolean())),
|
||||||
|
"repositoryOperation" -> mapping(
|
||||||
|
"create" -> trim(label("Allow all users to create repository", boolean())),
|
||||||
|
"delete" -> trim(label("Allow all users to delete repository", boolean())),
|
||||||
|
"rename" -> trim(label("Allow all users to rename repository", boolean())),
|
||||||
|
"transfer" -> trim(label("Allow all users to transfer repository", boolean())),
|
||||||
|
"fork" -> trim(label("Allow all users to fork repository", boolean()))
|
||||||
|
)(RepositoryOperation.apply),
|
||||||
"gravatar" -> trim(label("Gravatar", boolean())),
|
"gravatar" -> trim(label("Gravatar", boolean())),
|
||||||
"notification" -> trim(label("Notification", boolean())),
|
"notification" -> trim(label("Notification", boolean())),
|
||||||
"activityLogLimit" -> trim(label("Limit of activity logs", optional(number()))),
|
"activityLogLimit" -> trim(label("Limit of activity logs", optional(number()))),
|
||||||
|
"limitVisibleRepositories" -> trim(label("limitVisibleRepositories", boolean())),
|
||||||
"ssh" -> mapping(
|
"ssh" -> mapping(
|
||||||
"enabled" -> trim(label("SSH access", boolean())),
|
"enabled" -> trim(label("SSH access", boolean())),
|
||||||
"host" -> trim(label("SSH host", optional(text()))),
|
"host" -> trim(label("SSH host", optional(text()))),
|
||||||
"port" -> trim(label("SSH port", optional(number()))),
|
"port" -> trim(label("SSH port", optional(number())))
|
||||||
)(Ssh.apply),
|
)(Ssh.apply),
|
||||||
"useSMTP" -> trim(label("SMTP", boolean())),
|
"useSMTP" -> trim(label("SMTP", boolean())),
|
||||||
"smtp" -> optionalIfNotChecked(
|
"smtp" -> optionalIfNotChecked(
|
||||||
@@ -90,11 +98,18 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
|||||||
)(OIDC.apply)
|
)(OIDC.apply)
|
||||||
),
|
),
|
||||||
"skinName" -> trim(label("AdminLTE skin name", text(required))),
|
"skinName" -> trim(label("AdminLTE skin name", text(required))),
|
||||||
|
"userDefinedCss" -> trim(label("User-defined CSS", optional(text()))),
|
||||||
"showMailAddress" -> trim(label("Show mail address", boolean())),
|
"showMailAddress" -> trim(label("Show mail address", boolean())),
|
||||||
"webhook" -> mapping(
|
"webhook" -> mapping(
|
||||||
"blockPrivateAddress" -> trim(label("Block private address", boolean())),
|
"blockPrivateAddress" -> trim(label("Block private address", boolean())),
|
||||||
"whitelist" -> trim(label("Whitelist", multiLineText()))
|
"whitelist" -> trim(label("Whitelist", multiLineText()))
|
||||||
)(WebHook.apply)
|
)(WebHook.apply),
|
||||||
|
"upload" -> mapping(
|
||||||
|
"maxFileSize" -> trim(label("Max file size", long(required))),
|
||||||
|
"timeout" -> trim(label("Timeout", long(required))),
|
||||||
|
"largeMaxFileSize" -> trim(label("Max file size for large file", long(required))),
|
||||||
|
"largeTimeout" -> trim(label("Timeout for large file", long(required)))
|
||||||
|
)(Upload.apply)
|
||||||
)(SystemSettings.apply).verifying { settings =>
|
)(SystemSettings.apply).verifying { settings =>
|
||||||
Vector(
|
Vector(
|
||||||
if (settings.ssh.enabled && settings.baseUrl.isEmpty) {
|
if (settings.ssh.enabled && settings.baseUrl.isEmpty) {
|
||||||
@@ -170,7 +185,7 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
|||||||
|
|
||||||
val newUserForm = mapping(
|
val newUserForm = mapping(
|
||||||
"userName" -> trim(label("Username", text(required, maxlength(100), identifier, uniqueUserName, reservedNames))),
|
"userName" -> trim(label("Username", text(required, maxlength(100), identifier, uniqueUserName, reservedNames))),
|
||||||
"password" -> trim(label("Password", text(required, maxlength(20), password))),
|
"password" -> trim(label("Password", text(required, maxlength(20)))),
|
||||||
"fullName" -> trim(label("Full Name", text(required, maxlength(100)))),
|
"fullName" -> trim(label("Full Name", text(required, maxlength(100)))),
|
||||||
"mailAddress" -> trim(label("Mail Address", text(required, maxlength(100), uniqueMailAddress()))),
|
"mailAddress" -> trim(label("Mail Address", text(required, maxlength(100), uniqueMailAddress()))),
|
||||||
"extraMailAddresses" -> list(
|
"extraMailAddresses" -> list(
|
||||||
@@ -184,7 +199,7 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
|||||||
|
|
||||||
val editUserForm = mapping(
|
val editUserForm = mapping(
|
||||||
"userName" -> trim(label("Username", text(required, maxlength(100), identifier))),
|
"userName" -> trim(label("Username", text(required, maxlength(100), identifier))),
|
||||||
"password" -> trim(label("Password", optional(text(maxlength(20), password)))),
|
"password" -> trim(label("Password", optional(text(maxlength(20))))),
|
||||||
"fullName" -> trim(label("Full Name", text(required, maxlength(100)))),
|
"fullName" -> trim(label("Full Name", text(required, maxlength(100)))),
|
||||||
"mailAddress" -> trim(label("Mail Address", text(required, maxlength(100), uniqueMailAddress("userName")))),
|
"mailAddress" -> trim(label("Mail Address", text(required, maxlength(100), uniqueMailAddress("userName")))),
|
||||||
"extraMailAddresses" -> list(
|
"extraMailAddresses" -> list(
|
||||||
@@ -529,24 +544,26 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private def members: Constraint = new Constraint() {
|
private def members: Constraint =
|
||||||
override def validate(name: String, value: String, messages: Messages): Option[String] = {
|
new Constraint() {
|
||||||
if (value.split(",").exists {
|
override def validate(name: String, value: String, messages: Messages): Option[String] = {
|
||||||
_.split(":") match { case Array(userName, isManager) => isManager.toBoolean }
|
if (value.split(",").exists {
|
||||||
}) None
|
_.split(":") match { case Array(userName, isManager) => isManager.toBoolean }
|
||||||
else Some("Must select one manager at least.")
|
}) None
|
||||||
}
|
else Some("Must select one manager at least.")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
protected def disableByNotYourself(paramName: String): Constraint = new Constraint() {
|
|
||||||
override def validate(name: String, value: String, messages: Messages): Option[String] = {
|
protected def disableByNotYourself(paramName: String): Constraint =
|
||||||
params.get(paramName).flatMap { userName =>
|
new Constraint() {
|
||||||
if (userName == context.loginAccount.get.userName && params.get("removed") == Some("true"))
|
override def validate(name: String, value: String, messages: Messages): Option[String] = {
|
||||||
Some("You can't disable your account yourself")
|
params.get(paramName).flatMap { userName =>
|
||||||
else
|
if (userName == context.loginAccount.get.userName && params.get("removed") == Some("true"))
|
||||||
None
|
Some("You can't disable your account yourself")
|
||||||
|
else
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ 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
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import gitbucket.core.util.Directory.getRepositoryDir
|
|||||||
import gitbucket.core.util.ReferrerAuthenticator
|
import gitbucket.core.util.ReferrerAuthenticator
|
||||||
import gitbucket.core.util.Implicits._
|
import gitbucket.core.util.Implicits._
|
||||||
import org.eclipse.jgit.api.Git
|
import org.eclipse.jgit.api.Git
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
|
||||||
import scala.jdk.CollectionConverters._
|
import scala.jdk.CollectionConverters._
|
||||||
import scala.util.Using
|
import scala.util.Using
|
||||||
@@ -12,11 +13,23 @@ import scala.util.Using
|
|||||||
trait ApiGitReferenceControllerBase extends ControllerBase {
|
trait ApiGitReferenceControllerBase extends ControllerBase {
|
||||||
self: ReferrerAuthenticator =>
|
self: ReferrerAuthenticator =>
|
||||||
|
|
||||||
|
private val logger = LoggerFactory.getLogger(classOf[ApiGitReferenceControllerBase])
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* i. Get a reference
|
* i. Get a reference
|
||||||
* https://developer.github.com/v3/git/refs/#get-a-reference
|
* https://developer.github.com/v3/git/refs/#get-a-reference
|
||||||
*/
|
*/
|
||||||
|
get("/api/v3/repos/:owner/:repository/git/ref/*")(referrersOnly { repository =>
|
||||||
|
getRef()
|
||||||
|
})
|
||||||
|
|
||||||
|
// Some versions of GHE support this path
|
||||||
get("/api/v3/repos/:owner/:repository/git/refs/*")(referrersOnly { repository =>
|
get("/api/v3/repos/:owner/:repository/git/refs/*")(referrersOnly { repository =>
|
||||||
|
logger.warn("git/refs/ endpoint may not be compatible with GitHub API v3. Consider using git/ref/ endpoint instead")
|
||||||
|
getRef()
|
||||||
|
})
|
||||||
|
|
||||||
|
private def getRef() = {
|
||||||
val revstr = multiParams("splat").head
|
val revstr = multiParams("splat").head
|
||||||
Using.resource(Git.open(getRepositoryDir(params("owner"), params("repository")))) { git =>
|
Using.resource(Git.open(getRepositoryDir(params("owner"), params("repository")))) { git =>
|
||||||
val ref = git.getRepository().findRef(revstr)
|
val ref = git.getRepository().findRef(revstr)
|
||||||
@@ -38,7 +51,8 @@ trait ApiGitReferenceControllerBase extends ControllerBase {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ii. Get all references
|
* ii. Get all references
|
||||||
* https://developer.github.com/v3/git/refs/#get-all-references
|
* https://developer.github.com/v3/git/refs/#get-all-references
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ trait ApiPullRequestControllerBase extends ControllerBase {
|
|||||||
requestBranch = reqBranch,
|
requestBranch = reqBranch,
|
||||||
commitIdFrom = commitIdFrom.getName,
|
commitIdFrom = commitIdFrom.getName,
|
||||||
commitIdTo = commitIdTo.getName,
|
commitIdTo = commitIdTo.getName,
|
||||||
isDraft = false,
|
isDraft = createPullReq.draft.getOrElse(false),
|
||||||
loginAccount = context.loginAccount.get,
|
loginAccount = context.loginAccount.get,
|
||||||
settings = context.settings
|
settings = context.settings
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import gitbucket.core.util.JGitUtil.CommitInfo
|
|||||||
import gitbucket.core.util.{JGitUtil, ReferrerAuthenticator, RepositoryName}
|
import gitbucket.core.util.{JGitUtil, ReferrerAuthenticator, RepositoryName}
|
||||||
import org.eclipse.jgit.api.Git
|
import org.eclipse.jgit.api.Git
|
||||||
import org.eclipse.jgit.revwalk.RevWalk
|
import org.eclipse.jgit.revwalk.RevWalk
|
||||||
|
import scala.jdk.CollectionConverters._
|
||||||
import scala.util.Using
|
import scala.util.Using
|
||||||
|
|
||||||
trait ApiRepositoryCommitControllerBase extends ControllerBase {
|
trait ApiRepositoryCommitControllerBase extends ControllerBase {
|
||||||
@@ -17,6 +18,33 @@ trait ApiRepositoryCommitControllerBase extends ControllerBase {
|
|||||||
* i. List commits on a repository
|
* i. List commits on a repository
|
||||||
* https://developer.github.com/v3/repos/commits/#list-commits-on-a-repository
|
* https://developer.github.com/v3/repos/commits/#list-commits-on-a-repository
|
||||||
*/
|
*/
|
||||||
|
get("/api/v3/repos/:owner/:repository/commits")(referrersOnly { repository =>
|
||||||
|
val owner = repository.owner
|
||||||
|
val name = repository.name
|
||||||
|
// TODO: The following parameters need to be implemented. [:path, :author, :since, :until]
|
||||||
|
val sha = if (request.body.nonEmpty) (parse(request.body) \ "sha").extract[String] else "refs/heads/master";
|
||||||
|
Using.resource(Git.open(getRepositoryDir(owner, name))) {
|
||||||
|
git =>
|
||||||
|
val repo = git.getRepository
|
||||||
|
Using.resource(new RevWalk(repo)) {
|
||||||
|
revWalk =>
|
||||||
|
val objectId = repo.resolve(sha)
|
||||||
|
revWalk.markStart(revWalk.parseCommit(objectId))
|
||||||
|
JsonFormat(revWalk.asScala.take(30).map {
|
||||||
|
commit =>
|
||||||
|
val commitInfo = new CommitInfo(commit)
|
||||||
|
ApiCommits(
|
||||||
|
repositoryName = RepositoryName(repository),
|
||||||
|
commitInfo = commitInfo,
|
||||||
|
diffs = JGitUtil.getDiffs(git, commitInfo.parents.headOption, commitInfo.id, false, true),
|
||||||
|
author = getAccount(commitInfo.authorName, commitInfo.authorEmailAddress),
|
||||||
|
committer = getAccount(commitInfo.committerName, commitInfo.committerEmailAddress),
|
||||||
|
commentCount = getCommitComment(repository.owner, repository.name, commitInfo.id.toString).size
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ii. Get a single commit
|
* ii. Get a single commit
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
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._
|
||||||
@@ -7,14 +11,7 @@ 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 {
|
||||||
val activityId = column[Int]("ACTIVITY_ID", O AutoInc)
|
def * = ???
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,5 +23,5 @@ case class Activity(
|
|||||||
message: String,
|
message: String,
|
||||||
additionalInfo: Option[String],
|
additionalInfo: Option[String],
|
||||||
activityDate: java.util.Date,
|
activityDate: java.util.Date,
|
||||||
activityId: Int = 0
|
activityId: String
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ trait CoreProfile
|
|||||||
with Profile
|
with Profile
|
||||||
with AccessTokenComponent
|
with AccessTokenComponent
|
||||||
with AccountComponent
|
with AccountComponent
|
||||||
with ActivityComponent
|
with ActivityComponent // ActivityComponent has been deprecated, but keep it for binary compatibility
|
||||||
with CollaboratorComponent
|
with CollaboratorComponent
|
||||||
with CommitCommentComponent
|
with CommitCommentComponent
|
||||||
with CommitStatusComponent
|
with CommitStatusComponent
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ 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 (settings.ldapAuthentication) {
|
val account = if (password.isEmpty) {
|
||||||
|
None
|
||||||
|
} else if (settings.ldapAuthentication) {
|
||||||
ldapAuthentication(settings, userName, password)
|
ldapAuthentication(settings, userName, password)
|
||||||
} else {
|
} else {
|
||||||
defaultAuthentication(userName, password)
|
defaultAuthentication(userName, password)
|
||||||
|
|||||||
@@ -3,65 +3,169 @@ 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.model.Profile.profile.blockingApi._
|
import gitbucket.core.util.Directory._
|
||||||
|
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 =>
|
||||||
|
|
||||||
def deleteOldActivities(limit: Int)(implicit s: Session): Int = {
|
private implicit val formats = Serialization.formats(NoTypeHints)
|
||||||
Activities.map(_.activityId).sortBy(_ desc).drop(limit).firstOption.map { id =>
|
|
||||||
Activities.filter(_.activityId <= id.bind).delete
|
private def writeLog(activity: Activity): Unit = {
|
||||||
} getOrElse 0
|
Using.resource(new FileOutputStream(ActivityLog, true)) { out =>
|
||||||
|
out.write((write(activity) + "\n").getBytes(StandardCharsets.UTF_8))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def getActivitiesByUser(activityUserName: String, isPublic: Boolean)(implicit s: Session): List[Activity] =
|
def getActivitiesByUser(activityUserName: String, isPublic: Boolean)(implicit context: Context): List[Activity] = {
|
||||||
Activities
|
if (!ActivityLog.exists()) {
|
||||||
.join(Repositories)
|
List.empty
|
||||||
.on((t1, t2) => t1.byRepository(t2.userName, t2.repositoryName))
|
} else {
|
||||||
.filter {
|
val list = new ListBuffer[Activity]
|
||||||
case (t1, t2) =>
|
Using.resource(new ReversedLinesFileReader(ActivityLog, StandardCharsets.UTF_8)) { reader =>
|
||||||
if (isPublic) {
|
var json: String = null
|
||||||
(t1.activityUserName === activityUserName.bind) && (t2.isPrivate === false.bind)
|
while (list.length < 50 && { json = reader.readLine(); json } != null) {
|
||||||
} else {
|
val activity = read[Activity](json)
|
||||||
(t1.activityUserName === activityUserName.bind)
|
if (activity.activityUserName == activityUserName) {
|
||||||
|
if (isPublic == false) {
|
||||||
|
list += activity
|
||||||
|
} else {
|
||||||
|
if (!getRepositoryInfoFromCache(activity.userName, activity.repositoryName)
|
||||||
|
.map(_.isPrivate)
|
||||||
|
.getOrElse(true)) {
|
||||||
|
list += activity
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.sortBy { case (t1, t2) => t1.activityId desc }
|
list.toList
|
||||||
.map { case (t1, t2) => t1 }
|
}
|
||||||
.take(30)
|
}
|
||||||
.list
|
|
||||||
|
|
||||||
def getRecentActivities()(implicit s: Session): List[Activity] =
|
def getRecentPublicActivities()(implicit context: Context): List[Activity] = {
|
||||||
Activities
|
if (!ActivityLog.exists()) {
|
||||||
.join(Repositories)
|
List.empty
|
||||||
.on((t1, t2) => t1.byRepository(t2.userName, t2.repositoryName))
|
} else {
|
||||||
.filter { case (t1, t2) => t2.isPrivate === false.bind }
|
val list = new ListBuffer[Activity]
|
||||||
.sortBy { case (t1, t2) => t1.activityId desc }
|
Using.resource(new ReversedLinesFileReader(ActivityLog, StandardCharsets.UTF_8)) { reader =>
|
||||||
.map { case (t1, t2) => t1 }
|
var json: String = null
|
||||||
.take(30)
|
while (list.length < 50 && { json = reader.readLine(); json } != null) {
|
||||||
.list
|
val activity = read[Activity](json)
|
||||||
|
if (!getRepositoryInfoFromCache(activity.userName, activity.repositoryName)
|
||||||
|
.map(_.isPrivate)
|
||||||
|
.getOrElse(true)) {
|
||||||
|
list += activity
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list.toList
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def getRecentActivitiesByOwners(owners: Set[String])(implicit s: Session): List[Activity] =
|
def getRecentActivitiesByOwners(owners: Set[String])(implicit context: Context): List[Activity] = {
|
||||||
Activities
|
if (!ActivityLog.exists()) {
|
||||||
.join(Repositories)
|
List.empty
|
||||||
.on((t1, t2) => t1.byRepository(t2.userName, t2.repositoryName))
|
} else {
|
||||||
.filter { case (t1, t2) => (t2.isPrivate === false.bind) || (t2.userName inSetBind owners) }
|
val list = new ListBuffer[Activity]
|
||||||
.sortBy { case (t1, t2) => t1.activityId desc }
|
Using.resource(new ReversedLinesFileReader(ActivityLog, StandardCharsets.UTF_8)) { reader =>
|
||||||
.map { case (t1, t2) => t1 }
|
var json: String = null
|
||||||
.take(30)
|
while (list.length < 50 && { json = reader.readLine(); json } != null) {
|
||||||
.list
|
val activity = read[Activity](json)
|
||||||
|
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)(
|
def recordCreateRepositoryActivity(userName: String, repositoryName: String, activityUserName: String): Unit = {
|
||||||
implicit s: Session
|
writeLog(
|
||||||
): Unit =
|
Activity(
|
||||||
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,
|
||||||
@@ -69,16 +173,20 @@ trait ActivityService {
|
|||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
issueId: Int,
|
issueId: Int,
|
||||||
title: String
|
title: String
|
||||||
)(implicit s: Session): Unit =
|
): Unit = {
|
||||||
Activities insert Activity(
|
writeLog(
|
||||||
userName,
|
Activity(
|
||||||
repositoryName,
|
userName,
|
||||||
activityUserName,
|
repositoryName,
|
||||||
"open_issue",
|
activityUserName,
|
||||||
s"[user:${activityUserName}] opened issue [issue:${userName}/${repositoryName}#${issueId}]",
|
"open_issue",
|
||||||
Some(title),
|
s"[user:${activityUserName}] opened issue [issue:${userName}/${repositoryName}#${issueId}]",
|
||||||
currentDate
|
Some(title),
|
||||||
|
currentDate,
|
||||||
|
UUID.randomUUID().toString
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
def recordCloseIssueActivity(
|
def recordCloseIssueActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
@@ -86,16 +194,20 @@ trait ActivityService {
|
|||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
issueId: Int,
|
issueId: Int,
|
||||||
title: String
|
title: String
|
||||||
)(implicit s: Session): Unit =
|
): Unit = {
|
||||||
Activities insert Activity(
|
writeLog(
|
||||||
userName,
|
Activity(
|
||||||
repositoryName,
|
userName,
|
||||||
activityUserName,
|
repositoryName,
|
||||||
"close_issue",
|
activityUserName,
|
||||||
s"[user:${activityUserName}] closed issue [issue:${userName}/${repositoryName}#${issueId}]",
|
"close_issue",
|
||||||
Some(title),
|
s"[user:${activityUserName}] closed issue [issue:${userName}/${repositoryName}#${issueId}]",
|
||||||
currentDate
|
Some(title),
|
||||||
|
currentDate,
|
||||||
|
UUID.randomUUID().toString
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
def recordClosePullRequestActivity(
|
def recordClosePullRequestActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
@@ -103,16 +215,20 @@ trait ActivityService {
|
|||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
issueId: Int,
|
issueId: Int,
|
||||||
title: String
|
title: String
|
||||||
)(implicit s: Session): Unit =
|
): Unit = {
|
||||||
Activities insert Activity(
|
writeLog(
|
||||||
userName,
|
Activity(
|
||||||
repositoryName,
|
userName,
|
||||||
activityUserName,
|
repositoryName,
|
||||||
"close_issue",
|
activityUserName,
|
||||||
s"[user:${activityUserName}] closed pull request [pullreq:${userName}/${repositoryName}#${issueId}]",
|
"close_issue",
|
||||||
Some(title),
|
s"[user:${activityUserName}] closed pull request [pullreq:${userName}/${repositoryName}#${issueId}]",
|
||||||
currentDate
|
Some(title),
|
||||||
|
currentDate,
|
||||||
|
UUID.randomUUID().toString
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
def recordReopenIssueActivity(
|
def recordReopenIssueActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
@@ -120,16 +236,41 @@ trait ActivityService {
|
|||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
issueId: Int,
|
issueId: Int,
|
||||||
title: String
|
title: String
|
||||||
)(implicit s: Session): Unit =
|
): Unit = {
|
||||||
Activities insert Activity(
|
writeLog(
|
||||||
userName,
|
Activity(
|
||||||
repositoryName,
|
userName,
|
||||||
activityUserName,
|
repositoryName,
|
||||||
"reopen_issue",
|
activityUserName,
|
||||||
s"[user:${activityUserName}] reopened issue [issue:${userName}/${repositoryName}#${issueId}]",
|
"reopen_issue",
|
||||||
Some(title),
|
s"[user:${activityUserName}] reopened issue [issue:${userName}/${repositoryName}#${issueId}]",
|
||||||
currentDate
|
Some(title),
|
||||||
|
currentDate,
|
||||||
|
UUID.randomUUID().toString
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
def recordReopenPullRequestActivity(
|
||||||
|
userName: String,
|
||||||
|
repositoryName: String,
|
||||||
|
activityUserName: String,
|
||||||
|
issueId: Int,
|
||||||
|
title: String
|
||||||
|
): Unit = {
|
||||||
|
writeLog(
|
||||||
|
Activity(
|
||||||
|
userName,
|
||||||
|
repositoryName,
|
||||||
|
activityUserName,
|
||||||
|
"reopen_issue",
|
||||||
|
s"[user:${activityUserName}] reopened pull request [issue:${userName}/${repositoryName}#${issueId}]",
|
||||||
|
Some(title),
|
||||||
|
currentDate,
|
||||||
|
UUID.randomUUID().toString
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
def recordCommentIssueActivity(
|
def recordCommentIssueActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
@@ -137,16 +278,20 @@ trait ActivityService {
|
|||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
issueId: Int,
|
issueId: Int,
|
||||||
comment: String
|
comment: String
|
||||||
)(implicit s: Session): Unit =
|
): Unit = {
|
||||||
Activities insert Activity(
|
writeLog(
|
||||||
userName,
|
Activity(
|
||||||
repositoryName,
|
userName,
|
||||||
activityUserName,
|
repositoryName,
|
||||||
"comment_issue",
|
activityUserName,
|
||||||
s"[user:${activityUserName}] commented on issue [issue:${userName}/${repositoryName}#${issueId}]",
|
"comment_issue",
|
||||||
Some(cut(comment, 200)),
|
s"[user:${activityUserName}] commented on issue [issue:${userName}/${repositoryName}#${issueId}]",
|
||||||
currentDate
|
Some(cut(comment, 200)),
|
||||||
|
currentDate,
|
||||||
|
UUID.randomUUID().toString
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
def recordCommentPullRequestActivity(
|
def recordCommentPullRequestActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
@@ -154,16 +299,20 @@ trait ActivityService {
|
|||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
issueId: Int,
|
issueId: Int,
|
||||||
comment: String
|
comment: String
|
||||||
)(implicit s: Session): Unit =
|
): Unit = {
|
||||||
Activities insert Activity(
|
writeLog(
|
||||||
userName,
|
Activity(
|
||||||
repositoryName,
|
userName,
|
||||||
activityUserName,
|
repositoryName,
|
||||||
"comment_issue",
|
activityUserName,
|
||||||
s"[user:${activityUserName}] commented on pull request [pullreq:${userName}/${repositoryName}#${issueId}]",
|
"comment_issue",
|
||||||
Some(cut(comment, 200)),
|
s"[user:${activityUserName}] commented on pull request [pullreq:${userName}/${repositoryName}#${issueId}]",
|
||||||
currentDate
|
Some(cut(comment, 200)),
|
||||||
|
currentDate,
|
||||||
|
UUID.randomUUID().toString
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
def recordCommentCommitActivity(
|
def recordCommentCommitActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
@@ -171,32 +320,40 @@ trait ActivityService {
|
|||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
commitId: String,
|
commitId: String,
|
||||||
comment: String
|
comment: String
|
||||||
)(implicit s: Session): Unit =
|
): Unit = {
|
||||||
Activities insert Activity(
|
writeLog(
|
||||||
userName,
|
Activity(
|
||||||
repositoryName,
|
userName,
|
||||||
activityUserName,
|
repositoryName,
|
||||||
"comment_commit",
|
activityUserName,
|
||||||
s"[user:${activityUserName}] commented on commit [commit:${userName}/${repositoryName}@${commitId}]",
|
"comment_commit",
|
||||||
Some(cut(comment, 200)),
|
s"[user:${activityUserName}] commented on commit [commit:${userName}/${repositoryName}@${commitId}]",
|
||||||
currentDate
|
Some(cut(comment, 200)),
|
||||||
|
currentDate,
|
||||||
|
UUID.randomUUID().toString
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
def recordCreateWikiPageActivity(
|
def recordCreateWikiPageActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
repositoryName: String,
|
repositoryName: String,
|
||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
pageName: String
|
pageName: String
|
||||||
)(implicit s: Session): Unit =
|
): Unit = {
|
||||||
Activities insert Activity(
|
writeLog(
|
||||||
userName,
|
Activity(
|
||||||
repositoryName,
|
userName,
|
||||||
activityUserName,
|
repositoryName,
|
||||||
"create_wiki",
|
activityUserName,
|
||||||
s"[user:${activityUserName}] created the [repo:${userName}/${repositoryName}] wiki",
|
"create_wiki",
|
||||||
Some(pageName),
|
s"[user:${activityUserName}] created the [repo:${userName}/${repositoryName}] wiki",
|
||||||
currentDate
|
Some(pageName),
|
||||||
|
currentDate,
|
||||||
|
UUID.randomUUID().toString
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
def recordEditWikiPageActivity(
|
def recordEditWikiPageActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
@@ -204,16 +361,20 @@ trait ActivityService {
|
|||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
pageName: String,
|
pageName: String,
|
||||||
commitId: String
|
commitId: String
|
||||||
)(implicit s: Session): Unit =
|
): Unit = {
|
||||||
Activities insert Activity(
|
writeLog(
|
||||||
userName,
|
Activity(
|
||||||
repositoryName,
|
userName,
|
||||||
activityUserName,
|
repositoryName,
|
||||||
"edit_wiki",
|
activityUserName,
|
||||||
s"[user:${activityUserName}] edited the [repo:${userName}/${repositoryName}] wiki",
|
"edit_wiki",
|
||||||
Some(pageName + ":" + commitId),
|
s"[user:${activityUserName}] edited the [repo:${userName}/${repositoryName}] wiki",
|
||||||
currentDate
|
Some(pageName + ":" + commitId),
|
||||||
|
currentDate,
|
||||||
|
UUID.randomUUID().toString
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
def recordPushActivity(
|
def recordPushActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
@@ -221,23 +382,27 @@ trait ActivityService {
|
|||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
branchName: String,
|
branchName: String,
|
||||||
commits: List[JGitUtil.CommitInfo]
|
commits: List[JGitUtil.CommitInfo]
|
||||||
)(implicit s: Session): Unit =
|
): Unit = {
|
||||||
Activities insert Activity(
|
writeLog(
|
||||||
userName,
|
Activity(
|
||||||
repositoryName,
|
userName,
|
||||||
activityUserName,
|
repositoryName,
|
||||||
"push",
|
activityUserName,
|
||||||
s"[user:${activityUserName}] pushed to [branch:${userName}/${repositoryName}#${branchName}] at [repo:${userName}/${repositoryName}]",
|
"push",
|
||||||
Some(
|
s"[user:${activityUserName}] pushed to [branch:${userName}/${repositoryName}#${branchName}] at [repo:${userName}/${repositoryName}]",
|
||||||
commits
|
Some(
|
||||||
.take(5)
|
commits
|
||||||
.map { commit =>
|
.take(5)
|
||||||
commit.id + ":" + commit.shortMessage
|
.map { commit =>
|
||||||
}
|
commit.id + ":" + commit.shortMessage
|
||||||
.mkString("\n")
|
}
|
||||||
),
|
.mkString("\n")
|
||||||
currentDate
|
),
|
||||||
|
currentDate,
|
||||||
|
UUID.randomUUID().toString
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
def recordCreateTagActivity(
|
def recordCreateTagActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
@@ -245,16 +410,20 @@ trait ActivityService {
|
|||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
tagName: String,
|
tagName: String,
|
||||||
commits: List[JGitUtil.CommitInfo]
|
commits: List[JGitUtil.CommitInfo]
|
||||||
)(implicit s: Session): Unit =
|
): Unit = {
|
||||||
Activities insert Activity(
|
writeLog(
|
||||||
userName,
|
Activity(
|
||||||
repositoryName,
|
userName,
|
||||||
activityUserName,
|
repositoryName,
|
||||||
"create_tag",
|
activityUserName,
|
||||||
s"[user:${activityUserName}] created tag [tag:${userName}/${repositoryName}#${tagName}] at [repo:${userName}/${repositoryName}]",
|
"create_tag",
|
||||||
None,
|
s"[user:${activityUserName}] created tag [tag:${userName}/${repositoryName}#${tagName}] at [repo:${userName}/${repositoryName}]",
|
||||||
currentDate
|
None,
|
||||||
|
currentDate,
|
||||||
|
UUID.randomUUID().toString
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
def recordDeleteTagActivity(
|
def recordDeleteTagActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
@@ -262,61 +431,80 @@ trait ActivityService {
|
|||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
tagName: String,
|
tagName: String,
|
||||||
commits: List[JGitUtil.CommitInfo]
|
commits: List[JGitUtil.CommitInfo]
|
||||||
)(implicit s: Session): Unit =
|
): Unit = {
|
||||||
Activities insert Activity(
|
writeLog(
|
||||||
userName,
|
Activity(
|
||||||
repositoryName,
|
userName,
|
||||||
activityUserName,
|
repositoryName,
|
||||||
"delete_tag",
|
activityUserName,
|
||||||
s"[user:${activityUserName}] deleted tag ${tagName} at [repo:${userName}/${repositoryName}]",
|
"delete_tag",
|
||||||
None,
|
s"[user:${activityUserName}] deleted tag ${tagName} at [repo:${userName}/${repositoryName}]",
|
||||||
currentDate
|
None,
|
||||||
|
currentDate,
|
||||||
|
UUID.randomUUID().toString
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
def recordCreateBranchActivity(
|
def recordCreateBranchActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
repositoryName: String,
|
repositoryName: String,
|
||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
branchName: String
|
branchName: String
|
||||||
)(implicit s: Session): Unit =
|
): Unit = {
|
||||||
Activities insert Activity(
|
writeLog(
|
||||||
userName,
|
Activity(
|
||||||
repositoryName,
|
userName,
|
||||||
activityUserName,
|
repositoryName,
|
||||||
"create_branch",
|
activityUserName,
|
||||||
s"[user:${activityUserName}] created branch [branch:${userName}/${repositoryName}#${branchName}] at [repo:${userName}/${repositoryName}]",
|
"create_branch",
|
||||||
None,
|
s"[user:${activityUserName}] created branch [branch:${userName}/${repositoryName}#${branchName}] at [repo:${userName}/${repositoryName}]",
|
||||||
currentDate
|
None,
|
||||||
|
currentDate,
|
||||||
|
UUID.randomUUID().toString
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
def recordDeleteBranchActivity(
|
def recordDeleteBranchActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
repositoryName: String,
|
repositoryName: String,
|
||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
branchName: String
|
branchName: String
|
||||||
)(implicit s: Session): Unit =
|
): Unit = {
|
||||||
Activities insert Activity(
|
writeLog(
|
||||||
userName,
|
Activity(
|
||||||
repositoryName,
|
userName,
|
||||||
activityUserName,
|
repositoryName,
|
||||||
"delete_branch",
|
activityUserName,
|
||||||
s"[user:${activityUserName}] deleted branch ${branchName} at [repo:${userName}/${repositoryName}]",
|
"delete_branch",
|
||||||
None,
|
s"[user:${activityUserName}] deleted branch ${branchName} at [repo:${userName}/${repositoryName}]",
|
||||||
currentDate
|
None,
|
||||||
|
currentDate,
|
||||||
|
UUID.randomUUID().toString
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
def recordForkActivity(userName: String, repositoryName: String, activityUserName: String, forkedUserName: String)(
|
def recordForkActivity(
|
||||||
implicit s: Session
|
userName: String,
|
||||||
): Unit =
|
repositoryName: String,
|
||||||
Activities insert Activity(
|
activityUserName: String,
|
||||||
userName,
|
forkedUserName: String
|
||||||
repositoryName,
|
): Unit = {
|
||||||
activityUserName,
|
writeLog(
|
||||||
"fork",
|
Activity(
|
||||||
s"[user:${activityUserName}] forked [repo:${userName}/${repositoryName}] to [repo:${forkedUserName}/${repositoryName}]",
|
userName,
|
||||||
None,
|
repositoryName,
|
||||||
currentDate
|
activityUserName,
|
||||||
|
"fork",
|
||||||
|
s"[user:${activityUserName}] forked [repo:${userName}/${repositoryName}] to [repo:${forkedUserName}/${repositoryName}]",
|
||||||
|
None,
|
||||||
|
currentDate,
|
||||||
|
UUID.randomUUID().toString
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
def recordPullRequestActivity(
|
def recordPullRequestActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
@@ -324,16 +512,20 @@ trait ActivityService {
|
|||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
issueId: Int,
|
issueId: Int,
|
||||||
title: String
|
title: String
|
||||||
)(implicit s: Session): Unit =
|
): Unit = {
|
||||||
Activities insert Activity(
|
writeLog(
|
||||||
userName,
|
Activity(
|
||||||
repositoryName,
|
userName,
|
||||||
activityUserName,
|
repositoryName,
|
||||||
"open_pullreq",
|
activityUserName,
|
||||||
s"[user:${activityUserName}] opened pull request [pullreq:${userName}/${repositoryName}#${issueId}]",
|
"open_pullreq",
|
||||||
Some(title),
|
s"[user:${activityUserName}] opened pull request [pullreq:${userName}/${repositoryName}#${issueId}]",
|
||||||
currentDate
|
Some(title),
|
||||||
|
currentDate,
|
||||||
|
UUID.randomUUID().toString
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
def recordMergeActivity(
|
def recordMergeActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
@@ -341,16 +533,20 @@ trait ActivityService {
|
|||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
issueId: Int,
|
issueId: Int,
|
||||||
message: String
|
message: String
|
||||||
)(implicit s: Session): Unit =
|
): Unit = {
|
||||||
Activities insert Activity(
|
writeLog(
|
||||||
userName,
|
Activity(
|
||||||
repositoryName,
|
userName,
|
||||||
activityUserName,
|
repositoryName,
|
||||||
"merge_pullreq",
|
activityUserName,
|
||||||
s"[user:${activityUserName}] merged pull request [pullreq:${userName}/${repositoryName}#${issueId}]",
|
"merge_pullreq",
|
||||||
Some(message),
|
s"[user:${activityUserName}] merged pull request [pullreq:${userName}/${repositoryName}#${issueId}]",
|
||||||
currentDate
|
Some(message),
|
||||||
|
currentDate,
|
||||||
|
UUID.randomUUID().toString
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
def recordReleaseActivity(
|
def recordReleaseActivity(
|
||||||
userName: String,
|
userName: String,
|
||||||
@@ -358,16 +554,20 @@ trait ActivityService {
|
|||||||
activityUserName: String,
|
activityUserName: String,
|
||||||
releaseName: String,
|
releaseName: String,
|
||||||
tagName: String
|
tagName: String
|
||||||
)(implicit s: Session): Unit =
|
): Unit = {
|
||||||
Activities insert Activity(
|
writeLog(
|
||||||
userName,
|
Activity(
|
||||||
repositoryName,
|
userName,
|
||||||
activityUserName,
|
repositoryName,
|
||||||
"release",
|
activityUserName,
|
||||||
s"[user:${activityUserName}] released [release:${userName}/${repositoryName}/${tagName}:${releaseName}] at [repo:${userName}/${repositoryName}]",
|
"release",
|
||||||
None,
|
s"[user:${activityUserName}] released [release:${userName}/${repositoryName}/${tagName}:${releaseName}] at [repo:${userName}/${repositoryName}]",
|
||||||
currentDate
|
None,
|
||||||
|
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
|
||||||
|
|||||||
@@ -39,7 +39,10 @@ trait HandleCommentService {
|
|||||||
))
|
))
|
||||||
case "reopen" if (issue.closed) =>
|
case "reopen" if (issue.closed) =>
|
||||||
false ->
|
false ->
|
||||||
(Some("reopen") -> Some(recordReopenIssueActivity _))
|
(Some("reopen") -> Some(
|
||||||
|
if (issue.isPullRequest) recordReopenPullRequestActivity _
|
||||||
|
else recordReopenIssueActivity _
|
||||||
|
))
|
||||||
}
|
}
|
||||||
.map {
|
.map {
|
||||||
case (closed, t) =>
|
case (closed, t) =>
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ trait IssuesService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the search result against issues.
|
* Returns the search result against issues.
|
||||||
*
|
*
|
||||||
* @param condition the search condition
|
* @param condition the search condition
|
||||||
* @param pullRequest if true then returns only pull requests, false then returns only issues.
|
* @param pullRequest if true then returns only pull requests, false then returns only issues.
|
||||||
@@ -910,13 +910,9 @@ object IssuesService {
|
|||||||
param(request, "groups").map(_.split(",").toSet).getOrElse(Set.empty)
|
param(request, "groups").map(_.split(",").toSet).getOrElse(Set.empty)
|
||||||
)
|
)
|
||||||
|
|
||||||
def page(request: HttpServletRequest) =
|
def page(request: HttpServletRequest) = {
|
||||||
try {
|
PaginationHelper.page(param(request, "page"))
|
||||||
val i = param(request, "page").getOrElse("1").toInt
|
}
|
||||||
if (i <= 0) 1 else i
|
|
||||||
} catch {
|
|
||||||
case e: NumberFormatException => 1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case class CommitStatusInfo(
|
case class CommitStatusInfo(
|
||||||
|
|||||||
15
src/main/scala/gitbucket/core/service/PaginationHelper.scala
Normal file
15
src/main/scala/gitbucket/core/service/PaginationHelper.scala
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package gitbucket.core.service
|
||||||
|
|
||||||
|
import scala.util.Try
|
||||||
|
|
||||||
|
object PaginationHelper {
|
||||||
|
|
||||||
|
def page(page: Option[String]) = {
|
||||||
|
|
||||||
|
page
|
||||||
|
.flatMap(pageStr => Try(pageStr.toInt).toOption)
|
||||||
|
.map(Math.max(1, _)) // remove negative pages
|
||||||
|
.getOrElse(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
package gitbucket.core.service
|
package gitbucket.core.service
|
||||||
|
|
||||||
import gitbucket.core.controller.Context
|
import gitbucket.core.controller.Context
|
||||||
import gitbucket.core.model.{Account, ReleaseTag, ReleaseAsset}
|
import gitbucket.core.model.{Account, ReleaseAsset, ReleaseTag}
|
||||||
import gitbucket.core.model.Profile.profile.blockingApi._
|
import gitbucket.core.model.Profile.profile.blockingApi._
|
||||||
import gitbucket.core.model.Profile._
|
import gitbucket.core.model.Profile._
|
||||||
import gitbucket.core.model.Profile.dateColumnType
|
import gitbucket.core.model.Profile.dateColumnType
|
||||||
|
import gitbucket.core.util.JGitUtil
|
||||||
|
|
||||||
trait ReleaseService {
|
trait ReleaseService {
|
||||||
self: AccountService with RepositoryService =>
|
self: AccountService with RepositoryService =>
|
||||||
@@ -35,10 +36,9 @@ trait ReleaseService {
|
|||||||
ReleaseAssets.filter(x => x.byTag(owner, repository, tag)).list
|
ReleaseAssets.filter(x => x.byTag(owner, repository, tag)).list
|
||||||
}
|
}
|
||||||
|
|
||||||
def getReleaseAssetsMap(owner: String, repository: String)(
|
def getReleaseAssetsMap(owner: String, repository: String, releases: Seq[ReleaseTag])(
|
||||||
implicit s: Session
|
implicit s: Session
|
||||||
): Map[ReleaseTag, Seq[ReleaseAsset]] = {
|
): Map[ReleaseTag, Seq[ReleaseAsset]] = {
|
||||||
val releases = getReleases(owner, repository)
|
|
||||||
releases.map(rel => (rel -> getReleaseAssets(owner, repository, rel.tag))).toMap
|
releases.map(rel => (rel -> getReleaseAssets(owner, repository, rel.tag))).toMap
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,20 +76,18 @@ trait ReleaseService {
|
|||||||
ReleaseTags.filter(x => x.byRepository(owner, repository)).sortBy(x => x.updatedDate).list
|
ReleaseTags.filter(x => x.byRepository(owner, repository)).sortBy(x => x.updatedDate).list
|
||||||
}
|
}
|
||||||
|
|
||||||
def getRelease(owner: String, repository: String, tag: String)(implicit s: Session): Option[ReleaseTag] = {
|
def getReleases(owner: String, repository: String, tags: Seq[JGitUtil.TagInfo])(
|
||||||
//Releases filter (_.byPrimaryKey(owner, repository, releaseId)) firstOption
|
implicit s: Session
|
||||||
ReleaseTags filter (_.byTag(owner, repository, tag)) firstOption
|
): Seq[ReleaseTag] = {
|
||||||
|
ReleaseTags
|
||||||
|
.filter(x => x.byRepository(owner, repository))
|
||||||
|
.filter(x => x.tag inSetBind tags.map(_.name))
|
||||||
|
.sortBy(x => x.updatedDate)
|
||||||
|
.list
|
||||||
|
}
|
||||||
|
def getRelease(owner: String, repository: String, tag: String)(implicit s: Session): Option[ReleaseTag] = {
|
||||||
|
ReleaseTags.filter(_.byTag(owner, repository, tag)).firstOption
|
||||||
}
|
}
|
||||||
|
|
||||||
// def getReleaseByTag(owner: String, repository: String, tag: String)(implicit s: Session): Option[Release] = {
|
|
||||||
// Releases filter (_.byTag(owner, repository, tag)) firstOption
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// def getRelease(owner: String, repository: String, releaseId: String)(implicit s: Session): Option[Release] = {
|
|
||||||
// if (isInteger(releaseId))
|
|
||||||
// getRelease(owner, repository, releaseId.toInt)
|
|
||||||
// else None
|
|
||||||
// }
|
|
||||||
|
|
||||||
def updateRelease(owner: String, repository: String, tag: String, title: String, content: Option[String])(
|
def updateRelease(owner: String, repository: String, tag: String, title: String, content: Option[String])(
|
||||||
implicit s: Session
|
implicit s: Session
|
||||||
@@ -107,3 +105,9 @@ trait ReleaseService {
|
|||||||
ReleaseTags filter (_.byPrimaryKey(owner, repository, tag)) delete
|
ReleaseTags filter (_.byPrimaryKey(owner, repository, tag)) delete
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object ReleaseService {
|
||||||
|
|
||||||
|
val ReleaseLimit = 10
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
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._
|
||||||
@@ -9,14 +8,11 @@ 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.{CommitInfo, FileInfo}
|
import gitbucket.core.util.JGitUtil.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 {
|
||||||
@@ -119,15 +115,6 @@ 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(
|
||||||
@@ -213,50 +200,6 @@ 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) {
|
||||||
@@ -304,7 +247,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
|
||||||
@@ -459,6 +402,7 @@ trait RepositoryService {
|
|||||||
/**
|
/**
|
||||||
* Returns the list of visible repositories for the specified user.
|
* Returns the list of visible repositories for the specified user.
|
||||||
* If repositoryUserName is given then filters results by repository owner.
|
* If repositoryUserName is given then filters results by repository owner.
|
||||||
|
* This function is for plugin compatibility.
|
||||||
*
|
*
|
||||||
* @param loginAccount the logged in account
|
* @param loginAccount the logged in account
|
||||||
* @param repositoryUserName the repository owner (if None then returns all repositories which are visible for logged in user)
|
* @param repositoryUserName the repository owner (if None then returns all repositories which are visible for logged in user)
|
||||||
@@ -470,23 +414,42 @@ trait RepositoryService {
|
|||||||
loginAccount: Option[Account],
|
loginAccount: Option[Account],
|
||||||
repositoryUserName: Option[String] = None,
|
repositoryUserName: Option[String] = None,
|
||||||
withoutPhysicalInfo: Boolean = false
|
withoutPhysicalInfo: Boolean = false
|
||||||
|
)(implicit s: Session): List[RepositoryInfo] =
|
||||||
|
getVisibleRepositories(loginAccount, repositoryUserName, withoutPhysicalInfo, false)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of visible repositories for the specified user.
|
||||||
|
* If repositoryUserName is given then filters results by repository owner.
|
||||||
|
*
|
||||||
|
* @param loginAccount the logged in account
|
||||||
|
* @param repositoryUserName the repository owner (if None then returns all repositories which are visible for logged in user)
|
||||||
|
* @param withoutPhysicalInfo if true then the result does not include physical repository information such as commit count,
|
||||||
|
* branches and tags
|
||||||
|
* @param limit if true then result will include only repositories associated with the login account.
|
||||||
|
* @return the repository information which is sorted in descending order of lastActivityDate.
|
||||||
|
*/
|
||||||
|
def getVisibleRepositories(
|
||||||
|
loginAccount: Option[Account],
|
||||||
|
repositoryUserName: Option[String],
|
||||||
|
withoutPhysicalInfo: Boolean,
|
||||||
|
limit: Boolean
|
||||||
)(implicit s: Session): List[RepositoryInfo] = {
|
)(implicit s: Session): List[RepositoryInfo] = {
|
||||||
(loginAccount match {
|
(loginAccount match {
|
||||||
// for Administrators
|
// for Administrators
|
||||||
case Some(x) if (x.isAdmin) =>
|
case Some(x) if (x.isAdmin && !limit) =>
|
||||||
Repositories
|
Repositories
|
||||||
.join(Accounts)
|
.join(Accounts)
|
||||||
.on(_.userName === _.userName)
|
.on(_.userName === _.userName)
|
||||||
.filter { case (t1, t2) => t2.removed === false.bind }
|
.filter { case (t1, t2) => t2.removed === false.bind }
|
||||||
.map { case (t1, t2) => t1 }
|
.map { case (t1, t2) => t1 }
|
||||||
// for Normal Users
|
// for Normal Users
|
||||||
case Some(x) if (!x.isAdmin) =>
|
case Some(x) if (!x.isAdmin || limit) =>
|
||||||
Repositories
|
Repositories
|
||||||
.join(Accounts)
|
.join(Accounts)
|
||||||
.on(_.userName === _.userName)
|
.on(_.userName === _.userName)
|
||||||
.filter {
|
.filter {
|
||||||
case (t1, t2) =>
|
case (t1, t2) =>
|
||||||
(t2.removed === false.bind) && ((t1.isPrivate === false.bind) || (t1.userName === x.userName) ||
|
(t2.removed === false.bind) && ((t1.isPrivate === false.bind && !limit.bind) || (t1.userName === x.userName) ||
|
||||||
(t1.userName in GroupMembers.filter(_.userName === x.userName.bind).map(_.groupName)) ||
|
(t1.userName in GroupMembers.filter(_.userName === x.userName.bind).map(_.groupName)) ||
|
||||||
(Collaborators.filter { t3 =>
|
(Collaborators.filter { t3 =>
|
||||||
t3.byRepository(t1.userName, t1.repositoryName) &&
|
t3.byRepository(t1.userName, t1.repositoryName) &&
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package gitbucket.core.service
|
package gitbucket.core.service
|
||||||
|
|
||||||
import gitbucket.core.model.{Session, Issue, Account}
|
import gitbucket.core.model.{Account, Issue, Repository, Session}
|
||||||
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.
|
||||||
@@ -23,21 +25,41 @@ 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 getIssue(userName: String, repositoryName: String, issueId: String)(implicit context: Context): Option[Issue] = {
|
def getIssueFromCache(userName: String, repositoryName: String, issueId: String)(
|
||||||
|
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 getAccountByUserName(userName: String)(implicit context: Context): Option[Account] = {
|
def getAccountByUserNameFromCache(userName: String)(implicit context: Context): Option[Account] = {
|
||||||
context.cache(s"account.${userName}") {
|
context.cache(s"account.${userName}") {
|
||||||
super.getAccountByUserName(userName)
|
super.getAccountByUserName(userName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def getAccountByMailAddress(mailAddress: String)(implicit context: Context): Option[Account] = {
|
def getAccountByMailAddressFromCache(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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,9 +21,15 @@ trait SystemSettingsService {
|
|||||||
props.setProperty(AllowAccountRegistration, settings.allowAccountRegistration.toString)
|
props.setProperty(AllowAccountRegistration, settings.allowAccountRegistration.toString)
|
||||||
props.setProperty(AllowAnonymousAccess, settings.allowAnonymousAccess.toString)
|
props.setProperty(AllowAnonymousAccess, settings.allowAnonymousAccess.toString)
|
||||||
props.setProperty(IsCreateRepoOptionPublic, settings.isCreateRepoOptionPublic.toString)
|
props.setProperty(IsCreateRepoOptionPublic, settings.isCreateRepoOptionPublic.toString)
|
||||||
|
props.setProperty(RepositoryOperationCreate, settings.repositoryOperation.create.toString)
|
||||||
|
props.setProperty(RepositoryOperationDelete, settings.repositoryOperation.delete.toString)
|
||||||
|
props.setProperty(RepositoryOperationRename, settings.repositoryOperation.rename.toString)
|
||||||
|
props.setProperty(RepositoryOperationTransfer, settings.repositoryOperation.transfer.toString)
|
||||||
|
props.setProperty(RepositoryOperationFork, settings.repositoryOperation.fork.toString)
|
||||||
props.setProperty(Gravatar, settings.gravatar.toString)
|
props.setProperty(Gravatar, settings.gravatar.toString)
|
||||||
props.setProperty(Notification, settings.notification.toString)
|
props.setProperty(Notification, settings.notification.toString)
|
||||||
settings.activityLogLimit.foreach(x => props.setProperty(ActivityLogLimit, x.toString))
|
settings.activityLogLimit.foreach(x => props.setProperty(ActivityLogLimit, x.toString))
|
||||||
|
props.setProperty(LimitVisibleRepositories, settings.limitVisibleRepositories.toString)
|
||||||
props.setProperty(SshEnabled, settings.ssh.enabled.toString)
|
props.setProperty(SshEnabled, settings.ssh.enabled.toString)
|
||||||
settings.ssh.sshHost.foreach(x => props.setProperty(SshHost, x.trim))
|
settings.ssh.sshHost.foreach(x => props.setProperty(SshHost, x.trim))
|
||||||
settings.ssh.sshPort.foreach(x => props.setProperty(SshPort, x.toString))
|
settings.ssh.sshPort.foreach(x => props.setProperty(SshPort, x.toString))
|
||||||
@@ -69,9 +75,14 @@ trait SystemSettingsService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
props.setProperty(SkinName, settings.skinName.toString)
|
props.setProperty(SkinName, settings.skinName.toString)
|
||||||
|
settings.userDefinedCss.foreach(x => props.setProperty(UserDefinedCss, x))
|
||||||
props.setProperty(ShowMailAddress, settings.showMailAddress.toString)
|
props.setProperty(ShowMailAddress, settings.showMailAddress.toString)
|
||||||
props.setProperty(WebHookBlockPrivateAddress, settings.webHook.blockPrivateAddress.toString)
|
props.setProperty(WebHookBlockPrivateAddress, settings.webHook.blockPrivateAddress.toString)
|
||||||
props.setProperty(WebHookWhitelist, settings.webHook.whitelist.mkString("\n"))
|
props.setProperty(WebHookWhitelist, settings.webHook.whitelist.mkString("\n"))
|
||||||
|
props.setProperty(UploadMaxFileSize, settings.upload.maxFileSize.toString)
|
||||||
|
props.setProperty(UploadTimeout, settings.upload.timeout.toString)
|
||||||
|
props.setProperty(UploadLargeMaxFileSize, settings.upload.largeMaxFileSize.toString)
|
||||||
|
props.setProperty(UploadLargeTimeout, settings.upload.largeTimeout.toString)
|
||||||
|
|
||||||
Using.resource(new java.io.FileOutputStream(GitBucketConf)) { out =>
|
Using.resource(new java.io.FileOutputStream(GitBucketConf)) { out =>
|
||||||
props.store(out, null)
|
props.store(out, null)
|
||||||
@@ -92,15 +103,27 @@ trait SystemSettingsService {
|
|||||||
getValue(props, AllowAccountRegistration, false),
|
getValue(props, AllowAccountRegistration, false),
|
||||||
getValue(props, AllowAnonymousAccess, true),
|
getValue(props, AllowAnonymousAccess, true),
|
||||||
getValue(props, IsCreateRepoOptionPublic, true),
|
getValue(props, IsCreateRepoOptionPublic, true),
|
||||||
|
RepositoryOperation(
|
||||||
|
create = getValue(props, RepositoryOperationCreate, true),
|
||||||
|
delete = getValue(props, RepositoryOperationDelete, true),
|
||||||
|
rename = getValue(props, RepositoryOperationRename, true),
|
||||||
|
transfer = getValue(props, RepositoryOperationTransfer, true),
|
||||||
|
fork = getValue(props, RepositoryOperationFork, true)
|
||||||
|
),
|
||||||
getValue(props, Gravatar, false),
|
getValue(props, Gravatar, false),
|
||||||
getValue(props, Notification, false),
|
getValue(props, Notification, false),
|
||||||
getOptionValue[Int](props, ActivityLogLimit, None),
|
getOptionValue[Int](props, ActivityLogLimit, None),
|
||||||
|
getValue(props, LimitVisibleRepositories, false),
|
||||||
Ssh(
|
Ssh(
|
||||||
getValue(props, SshEnabled, false),
|
getValue(props, SshEnabled, false),
|
||||||
getOptionValue[String](props, SshHost, None).map(_.trim),
|
getOptionValue[String](props, SshHost, None).map(_.trim),
|
||||||
getOptionValue(props, SshPort, Some(DefaultSshPort))
|
getOptionValue(props, SshPort, Some(DefaultSshPort))
|
||||||
),
|
),
|
||||||
getValue(props, UseSMTP, getValue(props, Notification, false)), // handle migration scenario from only notification to useSMTP
|
getValue(
|
||||||
|
props,
|
||||||
|
UseSMTP,
|
||||||
|
getValue(props, Notification, false)
|
||||||
|
), // handle migration scenario from only notification to useSMTP
|
||||||
if (getValue(props, UseSMTP, getValue(props, Notification, false))) {
|
if (getValue(props, UseSMTP, getValue(props, Notification, false))) {
|
||||||
Some(
|
Some(
|
||||||
Smtp(
|
Smtp(
|
||||||
@@ -148,8 +171,15 @@ trait SystemSettingsService {
|
|||||||
None
|
None
|
||||||
},
|
},
|
||||||
getValue(props, SkinName, "skin-blue"),
|
getValue(props, SkinName, "skin-blue"),
|
||||||
|
getOptionValue(props, UserDefinedCss, None),
|
||||||
getValue(props, ShowMailAddress, false),
|
getValue(props, ShowMailAddress, false),
|
||||||
WebHook(getValue(props, WebHookBlockPrivateAddress, false), getSeqValue(props, WebHookWhitelist, ""))
|
WebHook(getValue(props, WebHookBlockPrivateAddress, false), getSeqValue(props, WebHookWhitelist, "")),
|
||||||
|
Upload(
|
||||||
|
getValue(props, UploadMaxFileSize, 3 * 1024 * 1024),
|
||||||
|
getValue(props, UploadTimeout, 3 * 10000),
|
||||||
|
getValue(props, UploadLargeMaxFileSize, 3 * 1024 * 1024),
|
||||||
|
getValue(props, UploadLargeTimeout, 3 * 10000)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -167,9 +197,11 @@ object SystemSettingsService {
|
|||||||
allowAccountRegistration: Boolean,
|
allowAccountRegistration: Boolean,
|
||||||
allowAnonymousAccess: Boolean,
|
allowAnonymousAccess: Boolean,
|
||||||
isCreateRepoOptionPublic: Boolean,
|
isCreateRepoOptionPublic: Boolean,
|
||||||
|
repositoryOperation: RepositoryOperation,
|
||||||
gravatar: Boolean,
|
gravatar: Boolean,
|
||||||
notification: Boolean,
|
notification: Boolean,
|
||||||
activityLogLimit: Option[Int],
|
activityLogLimit: Option[Int],
|
||||||
|
limitVisibleRepositories: Boolean,
|
||||||
ssh: Ssh,
|
ssh: Ssh,
|
||||||
useSMTP: Boolean,
|
useSMTP: Boolean,
|
||||||
smtp: Option[Smtp],
|
smtp: Option[Smtp],
|
||||||
@@ -178,8 +210,10 @@ object SystemSettingsService {
|
|||||||
oidcAuthentication: Boolean,
|
oidcAuthentication: Boolean,
|
||||||
oidc: Option[OIDC],
|
oidc: Option[OIDC],
|
||||||
skinName: String,
|
skinName: String,
|
||||||
|
userDefinedCss: Option[String],
|
||||||
showMailAddress: Boolean,
|
showMailAddress: Boolean,
|
||||||
webHook: WebHook
|
webHook: WebHook,
|
||||||
|
upload: Upload
|
||||||
) {
|
) {
|
||||||
|
|
||||||
def baseUrl(request: HttpServletRequest): String =
|
def baseUrl(request: HttpServletRequest): String =
|
||||||
@@ -198,12 +232,21 @@ object SystemSettingsService {
|
|||||||
.fold(base)(_ + base.dropWhile(_ != ':'))
|
.fold(base)(_ + base.dropWhile(_ != ':'))
|
||||||
}
|
}
|
||||||
|
|
||||||
def sshAddress: Option[SshAddress] = ssh.sshHost.collect {
|
def sshAddress: Option[SshAddress] =
|
||||||
case host if ssh.enabled =>
|
ssh.sshHost.collect {
|
||||||
SshAddress(host, ssh.sshPort.getOrElse(DefaultSshPort), "git")
|
case host if ssh.enabled =>
|
||||||
}
|
SshAddress(host, ssh.sshPort.getOrElse(DefaultSshPort), "git")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case class RepositoryOperation(
|
||||||
|
create: Boolean,
|
||||||
|
delete: Boolean,
|
||||||
|
rename: Boolean,
|
||||||
|
transfer: Boolean,
|
||||||
|
fork: Boolean
|
||||||
|
)
|
||||||
|
|
||||||
case class Ssh(
|
case class Ssh(
|
||||||
enabled: Boolean,
|
enabled: Boolean,
|
||||||
sshHost: Option[String],
|
sshHost: Option[String],
|
||||||
@@ -251,13 +294,15 @@ object SystemSettingsService {
|
|||||||
host: String,
|
host: String,
|
||||||
port: Int,
|
port: Int,
|
||||||
user: Option[String],
|
user: Option[String],
|
||||||
password: Option[String],
|
password: Option[String]
|
||||||
)
|
)
|
||||||
|
|
||||||
case class SshAddress(host: String, port: Int, genericUser: String)
|
case class SshAddress(host: String, port: Int, genericUser: String)
|
||||||
|
|
||||||
case class WebHook(blockPrivateAddress: Boolean, whitelist: Seq[String])
|
case class WebHook(blockPrivateAddress: Boolean, whitelist: Seq[String])
|
||||||
|
|
||||||
|
case class Upload(maxFileSize: Long, timeout: Long, largeMaxFileSize: Long, largeTimeout: Long)
|
||||||
|
|
||||||
val DefaultSshPort = 29418
|
val DefaultSshPort = 29418
|
||||||
val DefaultSmtpPort = 25
|
val DefaultSmtpPort = 25
|
||||||
val DefaultLdapPort = 389
|
val DefaultLdapPort = 389
|
||||||
@@ -267,9 +312,15 @@ object SystemSettingsService {
|
|||||||
private val AllowAccountRegistration = "allow_account_registration"
|
private val AllowAccountRegistration = "allow_account_registration"
|
||||||
private val AllowAnonymousAccess = "allow_anonymous_access"
|
private val AllowAnonymousAccess = "allow_anonymous_access"
|
||||||
private val IsCreateRepoOptionPublic = "is_create_repository_option_public"
|
private val IsCreateRepoOptionPublic = "is_create_repository_option_public"
|
||||||
|
private val RepositoryOperationCreate = "repository_operation_create"
|
||||||
|
private val RepositoryOperationDelete = "repository_operation_delete"
|
||||||
|
private val RepositoryOperationRename = "repository_operation_rename"
|
||||||
|
private val RepositoryOperationTransfer = "repository_operation_transfer"
|
||||||
|
private val RepositoryOperationFork = "repository_operation_fork"
|
||||||
private val Gravatar = "gravatar"
|
private val Gravatar = "gravatar"
|
||||||
private val Notification = "notification"
|
private val Notification = "notification"
|
||||||
private val ActivityLogLimit = "activity_log_limit"
|
private val ActivityLogLimit = "activity_log_limit"
|
||||||
|
private val LimitVisibleRepositories = "limitVisibleRepositories"
|
||||||
private val SshEnabled = "ssh"
|
private val SshEnabled = "ssh"
|
||||||
private val SshHost = "ssh.host"
|
private val SshHost = "ssh.host"
|
||||||
private val SshPort = "ssh.port"
|
private val SshPort = "ssh.port"
|
||||||
@@ -301,14 +352,14 @@ object SystemSettingsService {
|
|||||||
private val OidcClientSecret = "oidc.client_secret"
|
private val OidcClientSecret = "oidc.client_secret"
|
||||||
private val OidcJwsAlgorithm = "oidc.jws_algorithm"
|
private val OidcJwsAlgorithm = "oidc.jws_algorithm"
|
||||||
private val SkinName = "skinName"
|
private val SkinName = "skinName"
|
||||||
|
private val UserDefinedCss = "userDefinedCss"
|
||||||
private val ShowMailAddress = "showMailAddress"
|
private val ShowMailAddress = "showMailAddress"
|
||||||
private val PluginNetworkInstall = "plugin.networkInstall"
|
|
||||||
private val PluginProxyHost = "plugin.proxy.host"
|
|
||||||
private val PluginProxyPort = "plugin.proxy.port"
|
|
||||||
private val PluginProxyUser = "plugin.proxy.user"
|
|
||||||
private val PluginProxyPassword = "plugin.proxy.password"
|
|
||||||
private val WebHookBlockPrivateAddress = "webhook.block_private_address"
|
private val WebHookBlockPrivateAddress = "webhook.block_private_address"
|
||||||
private val WebHookWhitelist = "webhook.whitelist"
|
private val WebHookWhitelist = "webhook.whitelist"
|
||||||
|
private val UploadMaxFileSize = "upload.maxFileSize"
|
||||||
|
private val UploadTimeout = "upload.timeout"
|
||||||
|
private val UploadLargeMaxFileSize = "upload.largeMaxFileSize"
|
||||||
|
private val UploadLargeTimeout = "upload.largeTimeout"
|
||||||
|
|
||||||
private def getValue[A: ClassTag](props: java.util.Properties, key: String, default: A): A = {
|
private def getValue[A: ClassTag](props: java.util.Properties, key: String, default: A): A = {
|
||||||
getConfigValue(key).getOrElse {
|
getConfigValue(key).getOrElse {
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class ApiAuthenticationFilter extends Filter with AccessTokenService with Accoun
|
|||||||
val response = res.asInstanceOf[HttpServletResponse]
|
val response = res.asInstanceOf[HttpServletResponse]
|
||||||
Option(request.getHeader("Authorization"))
|
Option(request.getHeader("Authorization"))
|
||||||
.map {
|
.map {
|
||||||
case auth if auth.startsWith("token ") =>
|
case auth if auth.toLowerCase().startsWith("token ") =>
|
||||||
AccessTokenService.getAccountByAccessToken(auth.substring(6).trim).toRight(())
|
AccessTokenService.getAccountByAccessToken(auth.substring(6).trim).toRight(())
|
||||||
case auth if auth.startsWith("Basic ") => doBasicAuth(auth, loadSystemSettings(), request).toRight(())
|
case auth if auth.startsWith("Basic ") => doBasicAuth(auth, loadSystemSettings(), request).toRight(())
|
||||||
case _ => Left(())
|
case _ => Left(())
|
||||||
|
|||||||
@@ -240,7 +240,8 @@ 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,11 +2,10 @@ 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.{ActivityService, SystemSettingsService}
|
import gitbucket.core.service.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._
|
||||||
@@ -21,8 +20,6 @@ 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
|
||||||
@@ -35,23 +32,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")
|
||||||
@@ -95,10 +92,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 = {
|
||||||
@@ -172,8 +169,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
|
||||||
@@ -181,21 +178,3 @@ 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")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import Directory._
|
|||||||
import ConfigUtil._
|
import ConfigUtil._
|
||||||
import com.github.takezoe.slick.blocking.{BlockingH2Driver, BlockingJdbcProfile, BlockingMySQLDriver}
|
import com.github.takezoe.slick.blocking.{BlockingH2Driver, BlockingJdbcProfile, BlockingMySQLDriver}
|
||||||
import liquibase.database.AbstractJdbcDatabase
|
import liquibase.database.AbstractJdbcDatabase
|
||||||
import liquibase.database.core.{H2Database, MySQLDatabase, PostgresDatabase}
|
import liquibase.database.core.{H2Database, MariaDBDatabase, MySQLDatabase, PostgresDatabase}
|
||||||
import org.apache.commons.io.FileUtils
|
import org.apache.commons.io.FileUtils
|
||||||
|
|
||||||
import scala.reflect.ClassTag
|
import scala.reflect.ClassTag
|
||||||
@@ -78,6 +78,8 @@ object DatabaseType {
|
|||||||
H2
|
H2
|
||||||
} else if (url.startsWith("jdbc:mysql:")) {
|
} else if (url.startsWith("jdbc:mysql:")) {
|
||||||
MySQL
|
MySQL
|
||||||
|
} else if (url.startsWith("jdbc:mariadb:")) {
|
||||||
|
MariaDb
|
||||||
} else if (url.startsWith("jdbc:postgresql:")) {
|
} else if (url.startsWith("jdbc:postgresql:")) {
|
||||||
PostgreSQL
|
PostgreSQL
|
||||||
} else {
|
} else {
|
||||||
@@ -97,6 +99,12 @@ object DatabaseType {
|
|||||||
val liquiDriver = new MySQLDatabase()
|
val liquiDriver = new MySQLDatabase()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object MariaDb extends DatabaseType {
|
||||||
|
val jdbcDriver = "org.mariadb.jdbc.Driver"
|
||||||
|
val slickDriver = BlockingMySQLDriver
|
||||||
|
val liquiDriver = new MariaDBDatabase()
|
||||||
|
}
|
||||||
|
|
||||||
object PostgreSQL extends DatabaseType {
|
object PostgreSQL extends DatabaseType {
|
||||||
val jdbcDriver = "org.postgresql.Driver2"
|
val jdbcDriver = "org.postgresql.Driver2"
|
||||||
val slickDriver = BlockingPostgresDriver
|
val slickDriver = BlockingPostgresDriver
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ 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"
|
||||||
@@ -62,7 +64,7 @@ object Directory {
|
|||||||
new File(getRepositoryFilesDir(owner, repository), "releases")
|
new File(getRepositoryFilesDir(owner, repository), "releases")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Directory for files which are attached to issue.
|
* Directory for Git LFS files.
|
||||||
*/
|
*/
|
||||||
def getLfsDir(owner: String, repository: String): File =
|
def getLfsDir(owner: String, repository: String): File =
|
||||||
new File(getRepositoryFilesDir(owner, repository), "lfs")
|
new File(getRepositoryFilesDir(owner, repository), "lfs")
|
||||||
|
|||||||
@@ -92,12 +92,4 @@ object FileUtil {
|
|||||||
name
|
name
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy val MaxFileSize: Long = {
|
|
||||||
ConfigUtil.getConfigValue[Long]("gitbucket.maxFileSize").getOrElse(3 * 1024 * 1024)
|
|
||||||
}
|
|
||||||
|
|
||||||
lazy val UploadTimeout: Long = {
|
|
||||||
ConfigUtil.getConfigValue[Long]("gitbucket.UploadTimeout").getOrElse(3 * 10000)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -290,6 +290,11 @@ object JGitUtil {
|
|||||||
.entryCapacity(10000)
|
.entryCapacity(10000)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
private val objectCommitCache = new Cache2kBuilder[ObjectId, RevCommit]() {}
|
||||||
|
.name("object-commit")
|
||||||
|
.entryCapacity(10000)
|
||||||
|
.build()
|
||||||
|
|
||||||
def removeCache(git: Git): Unit = {
|
def removeCache(git: Git): Unit = {
|
||||||
val dir = git.getRepository.getDirectory
|
val dir = git.getRepository.getDirectory
|
||||||
val keyPrefix = dir.getAbsolutePath + "@"
|
val keyPrefix = dir.getAbsolutePath + "@"
|
||||||
@@ -368,9 +373,16 @@ object JGitUtil {
|
|||||||
* @param revision the branch name or commit id
|
* @param revision the branch name or commit id
|
||||||
* @param path the directory path (optional)
|
* @param path the directory path (optional)
|
||||||
* @param baseUrl the base url of GitBucket instance. This parameter is used to generate links of submodules (optional)
|
* @param baseUrl the base url of GitBucket instance. This parameter is used to generate links of submodules (optional)
|
||||||
* @return HTML of the file list
|
* @param commitCount the number of commit of this repository (optional). If this number is greater than threshold, the commit info is cached in memory.
|
||||||
|
* @return The list of files in the specified directory. If the number of files are greater than threshold, the returned file list won't include the commit info.
|
||||||
*/
|
*/
|
||||||
def getFileList(git: Git, revision: String, path: String = ".", baseUrl: Option[String] = None): List[FileInfo] = {
|
def getFileList(
|
||||||
|
git: Git,
|
||||||
|
revision: String,
|
||||||
|
path: String = ".",
|
||||||
|
baseUrl: Option[String] = None,
|
||||||
|
commitCount: Int = 0
|
||||||
|
): List[FileInfo] = {
|
||||||
Using.resource(new RevWalk(git.getRepository)) { revWalk =>
|
Using.resource(new RevWalk(git.getRepository)) { revWalk =>
|
||||||
val objectId = git.getRepository.resolve(revision)
|
val objectId = git.getRepository.resolve(revision)
|
||||||
if (objectId == null) return Nil
|
if (objectId == null) return Nil
|
||||||
@@ -388,104 +400,85 @@ object JGitUtil {
|
|||||||
Using.resource(treeWalk)(f)
|
Using.resource(treeWalk)(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@tailrec
|
@tailrec
|
||||||
def simplifyPath(
|
def simplifyPath(
|
||||||
tuple: (ObjectId, FileMode, String, String, Option[String], RevCommit)
|
tuple: (ObjectId, FileMode, String, String, Option[String], Option[RevCommit])
|
||||||
): (ObjectId, FileMode, String, String, Option[String], RevCommit) = tuple match {
|
): (ObjectId, FileMode, String, String, Option[String], Option[RevCommit]) =
|
||||||
case (oid, FileMode.TREE, name, path, _, commit) =>
|
tuple match {
|
||||||
(Using.resource(new TreeWalk(git.getRepository)) { walk =>
|
case (oid, FileMode.TREE, name, path, _, commit) =>
|
||||||
walk.addTree(oid)
|
(Using.resource(new TreeWalk(git.getRepository)) { walk =>
|
||||||
// single tree child, or None
|
walk.addTree(oid)
|
||||||
if (walk.next() && walk.getFileMode(0) == FileMode.TREE) {
|
// single tree child, or None
|
||||||
Some(
|
if (walk.next() && walk.getFileMode(0) == FileMode.TREE) {
|
||||||
(
|
Some(
|
||||||
walk.getObjectId(0),
|
(
|
||||||
walk.getFileMode(0),
|
walk.getObjectId(0),
|
||||||
name + "/" + walk.getNameString,
|
walk.getFileMode(0),
|
||||||
path + "/" + walk.getNameString,
|
name + "/" + walk.getNameString,
|
||||||
None,
|
path + "/" + walk.getNameString,
|
||||||
commit
|
None,
|
||||||
)
|
commit
|
||||||
).filterNot(_ => walk.next())
|
)
|
||||||
} else {
|
).filterNot(_ => walk.next())
|
||||||
None
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}) match {
|
||||||
|
case Some(child) => simplifyPath(child)
|
||||||
|
case _ => tuple
|
||||||
}
|
}
|
||||||
}) match {
|
case _ => tuple
|
||||||
case Some(child) => simplifyPath(child)
|
}
|
||||||
case _ => tuple
|
|
||||||
}
|
|
||||||
case _ => tuple
|
|
||||||
}
|
|
||||||
|
|
||||||
def tupleAdd(tuple: (ObjectId, FileMode, String, String, Option[String]), rev: RevCommit) = tuple match {
|
def appendLastCommits(
|
||||||
case (oid, fmode, name, path, opt) => (oid, fmode, name, path, opt, rev)
|
fileList: List[(ObjectId, FileMode, String, String, Option[String])]
|
||||||
}
|
): List[(ObjectId, FileMode, String, String, Option[String], Option[RevCommit])] = {
|
||||||
|
fileList.map {
|
||||||
@tailrec
|
case (id, mode, name, path, opt) =>
|
||||||
def findLastCommits(
|
// Don't attempt to get the last commit if the number of files is very large.
|
||||||
result: List[(ObjectId, FileMode, String, String, Option[String], RevCommit)],
|
if (fileList.size >= 100) {
|
||||||
restList: List[((ObjectId, FileMode, String, String, Option[String]), Map[RevCommit, RevCommit])],
|
(id, mode, name, path, opt, None)
|
||||||
revIterator: java.util.Iterator[RevCommit]
|
} else if (commitCount < 10000) {
|
||||||
): List[(ObjectId, FileMode, String, String, Option[String], RevCommit)] = {
|
val i = git
|
||||||
if (restList.isEmpty) {
|
(id, mode, name, path, opt, Some(getCommit(path)))
|
||||||
result
|
} else {
|
||||||
} else if (!revIterator.hasNext) { // maybe, revCommit has only 1 log. other case, restList be empty
|
val cached = objectCommitCache.getEntry(id)
|
||||||
result ++ restList.map { case (tuple, map) => tupleAdd(tuple, map.values.headOption.getOrElse(revCommit)) }
|
if (cached == null) {
|
||||||
} else {
|
val commit = getCommit(path)
|
||||||
val newCommit = revIterator.next
|
objectCommitCache.put(id, commit)
|
||||||
val (thisTimeChecks, skips) = restList.partition {
|
(id, mode, name, path, opt, Some(commit))
|
||||||
case (tuple, parentsMap) => parentsMap.contains(newCommit)
|
} else {
|
||||||
}
|
(id, mode, name, path, opt, Some(cached.getValue))
|
||||||
if (thisTimeChecks.isEmpty) {
|
|
||||||
findLastCommits(result, restList, revIterator)
|
|
||||||
} else {
|
|
||||||
var nextRest = skips
|
|
||||||
var nextResult = result
|
|
||||||
// Map[(name, oid), (tuple, parentsMap)]
|
|
||||||
val rest = scala.collection.mutable.Map(thisTimeChecks.map { t =>
|
|
||||||
(t._1._3 -> t._1._1) -> t
|
|
||||||
}: _*)
|
|
||||||
lazy val newParentsMap = newCommit.getParents.map(_ -> newCommit).toMap
|
|
||||||
useTreeWalk(newCommit) { walk =>
|
|
||||||
while (walk.next) {
|
|
||||||
rest.remove(walk.getNameString -> walk.getObjectId(0)).foreach {
|
|
||||||
case (tuple, _) =>
|
|
||||||
if (newParentsMap.isEmpty) {
|
|
||||||
nextResult +:= tupleAdd(tuple, newCommit)
|
|
||||||
} else {
|
|
||||||
nextRest +:= tuple -> newParentsMap
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rest.values.foreach {
|
|
||||||
case (tuple, parentsMap) =>
|
|
||||||
val restParentsMap = parentsMap - newCommit
|
|
||||||
if (restParentsMap.isEmpty) {
|
|
||||||
nextResult +:= tupleAdd(tuple, parentsMap(newCommit))
|
|
||||||
} else {
|
|
||||||
nextRest +:= tuple -> restParentsMap
|
|
||||||
}
|
|
||||||
}
|
|
||||||
findLastCommits(nextResult, nextRest, revIterator)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def getCommit(path: String): RevCommit = {
|
||||||
|
git
|
||||||
|
.log()
|
||||||
|
.addPath(path)
|
||||||
|
.add(revCommit)
|
||||||
|
.setMaxCount(1)
|
||||||
|
.call()
|
||||||
|
.iterator()
|
||||||
|
.next()
|
||||||
|
}
|
||||||
|
|
||||||
var fileList: List[(ObjectId, FileMode, String, String, Option[String])] = Nil
|
var fileList: List[(ObjectId, FileMode, String, String, Option[String])] = Nil
|
||||||
useTreeWalk(revCommit) { treeWalk =>
|
useTreeWalk(revCommit) { treeWalk =>
|
||||||
while (treeWalk.next()) {
|
while (treeWalk.next()) {
|
||||||
val linkUrl = if (treeWalk.getFileMode(0) == FileMode.GITLINK) {
|
val linkUrl = if (treeWalk.getFileMode(0) == FileMode.GITLINK) {
|
||||||
getSubmodules(git, revCommit.getTree, baseUrl).find(_.path == treeWalk.getPathString).map(_.viewerUrl)
|
getSubmodules(git, revCommit.getTree, baseUrl).find(_.path == treeWalk.getPathString).map(_.viewerUrl)
|
||||||
} else None
|
} else None
|
||||||
fileList +:= (treeWalk.getObjectId(0), treeWalk.getFileMode(0), treeWalk.getNameString, treeWalk.getPathString, linkUrl)
|
fileList +:= (treeWalk.getObjectId(0), treeWalk.getFileMode(
|
||||||
|
0
|
||||||
|
), treeWalk.getNameString, treeWalk.getPathString, linkUrl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
revWalk.markStart(revCommit)
|
|
||||||
val it = revWalk.iterator
|
appendLastCommits(fileList)
|
||||||
val lastCommit = it.next
|
|
||||||
val nextParentsMap = Option(lastCommit).map(_.getParents.map(_ -> lastCommit).toMap).getOrElse(Map())
|
|
||||||
findLastCommits(List.empty, fileList.map(a => a -> nextParentsMap), it)
|
|
||||||
.map(simplifyPath)
|
.map(simplifyPath)
|
||||||
.map {
|
.map {
|
||||||
case (objectId, fileMode, name, path, linkUrl, commit) =>
|
case (objectId, fileMode, name, path, linkUrl, commit) =>
|
||||||
@@ -494,11 +487,14 @@ object JGitUtil {
|
|||||||
fileMode == FileMode.TREE || fileMode == FileMode.GITLINK,
|
fileMode == FileMode.TREE || fileMode == FileMode.GITLINK,
|
||||||
name,
|
name,
|
||||||
path,
|
path,
|
||||||
getSummaryMessage(commit.getFullMessage, commit.getShortMessage),
|
getSummaryMessage(
|
||||||
commit.getName,
|
commit.map(_.getFullMessage).getOrElse(""),
|
||||||
commit.getAuthorIdent.getWhen,
|
commit.map(_.getShortMessage).getOrElse("")
|
||||||
commit.getAuthorIdent.getName,
|
),
|
||||||
commit.getAuthorIdent.getEmailAddress,
|
commit.map(_.getName).getOrElse(""),
|
||||||
|
commit.map(_.getAuthorIdent.getWhen).orNull,
|
||||||
|
commit.map(_.getAuthorIdent.getName).getOrElse(""),
|
||||||
|
commit.map(_.getAuthorIdent.getEmailAddress).getOrElse(""),
|
||||||
linkUrl
|
linkUrl
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1004,11 +1000,12 @@ object JGitUtil {
|
|||||||
*/
|
*/
|
||||||
def getContentFromPath(git: Git, revTree: RevTree, path: String, fetchLargeFile: Boolean): Option[Array[Byte]] = {
|
def getContentFromPath(git: Git, revTree: RevTree, path: String, fetchLargeFile: Boolean): Option[Array[Byte]] = {
|
||||||
@scala.annotation.tailrec
|
@scala.annotation.tailrec
|
||||||
def getPathObjectId(path: String, walk: TreeWalk): Option[ObjectId] = walk.next match {
|
def getPathObjectId(path: String, walk: TreeWalk): Option[ObjectId] =
|
||||||
case true if (walk.getPathString == path) => Some(walk.getObjectId(0))
|
walk.next match {
|
||||||
case true => getPathObjectId(path, walk)
|
case true if (walk.getPathString == path) => Some(walk.getObjectId(0))
|
||||||
case false => None
|
case true => getPathObjectId(path, walk)
|
||||||
}
|
case false => None
|
||||||
|
}
|
||||||
|
|
||||||
Using.resource(new TreeWalk(git.getRepository)) { treeWalk =>
|
Using.resource(new TreeWalk(git.getRepository)) { treeWalk =>
|
||||||
treeWalk.addTree(revTree)
|
treeWalk.addTree(revTree)
|
||||||
|
|||||||
@@ -127,8 +127,14 @@ object LDAPUtil {
|
|||||||
private def getSslProvider(): Provider = {
|
private def getSslProvider(): Provider = {
|
||||||
val cachedInstance = provider.get()
|
val cachedInstance = provider.get()
|
||||||
if (cachedInstance == null) {
|
if (cachedInstance == null) {
|
||||||
val newInstance = Class
|
val cls = try {
|
||||||
.forName("com.sun.net.ssl.internal.ssl.Provider")
|
Class.forName("com.sun.net.ssl.internal.ssl.Provider")
|
||||||
|
} catch {
|
||||||
|
case e: ClassNotFoundException =>
|
||||||
|
Class.forName("com.ibm.jsse.IBMJSSEProvider")
|
||||||
|
case e: Throwable => throw e
|
||||||
|
}
|
||||||
|
val newInstance = cls
|
||||||
.getDeclaredConstructor()
|
.getDeclaredConstructor()
|
||||||
.newInstance()
|
.newInstance()
|
||||||
.asInstanceOf[Provider]
|
.asInstanceOf[Provider]
|
||||||
@@ -149,7 +155,7 @@ object LDAPUtil {
|
|||||||
keystore: String,
|
keystore: String,
|
||||||
error: String
|
error: String
|
||||||
)(f: LDAPConnection => Either[String, A]): Either[String, A] = {
|
)(f: LDAPConnection => Either[String, A]): Either[String, A] = {
|
||||||
if (tls) {
|
if (tls || ssl) {
|
||||||
// Dynamically set Sun as the security provider
|
// Dynamically set Sun as the security provider
|
||||||
Security.addProvider(getSslProvider())
|
Security.addProvider(getSslProvider())
|
||||||
|
|
||||||
|
|||||||
@@ -19,21 +19,6 @@ trait Validations {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Constraint for the password.
|
|
||||||
*/
|
|
||||||
val password: Constraint = new Constraint() {
|
|
||||||
lazy val validatePassword = ConfigUtil.getConfigValue[Boolean]("gitbucket.validate.password").getOrElse(true)
|
|
||||||
|
|
||||||
override def validate(name: String, value: String, messages: Messages): Option[String] = {
|
|
||||||
if (validatePassword == true && !value.matches("[a-zA-Z0-9\\-_.]+")) {
|
|
||||||
Some(s"${name} contains invalid character.")
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constraint for the repository identifier.
|
* Constraint for the repository identifier.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ trait AvatarImageProvider { self: RequestCache =>
|
|||||||
|
|
||||||
val src = if (mailAddress.isEmpty) {
|
val src = if (mailAddress.isEmpty) {
|
||||||
// by user name
|
// by user name
|
||||||
getAccountByUserName(userName).map { account =>
|
getAccountByUserNameFromCache(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
|
||||||
getAccountByMailAddress(mailAddress).map { account =>
|
getAccountByMailAddressFromCache(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
|
||||||
|
|
||||||
getIssue(userName, repositoryName, issueId.toString) match {
|
getIssueFromCache(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 =>
|
||||||
getAccountByUserName(m.group(2)).map { _ =>
|
getAccountByUserNameFromCache(m.group(2)).map { _ =>
|
||||||
s"""<code><a href="${context.path}/${m.group(2)}/${m.group(3)}/commit/${m.group(4)}">${m.group(2)}/${m.group(
|
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 =>
|
||||||
getIssue(m.group(2), m.group(3), m.group(4)) match {
|
getIssueFromCache(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 =>
|
||||||
getAccountByUserName(m.group(2)).map { _ =>
|
getAccountByUserNameFromCache(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 =>
|
||||||
getIssue(m.group(2), repository.name, m.group(3)) match {
|
getIssueFromCache(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)
|
||||||
getIssue(repository.owner, repository.name, m.group(3)) match {
|
getIssueFromCache(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 =>
|
||||||
getAccountByUserName(m.group(2)).map { _ =>
|
getAccountByUserNameFromCache(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,7 +3,6 @@ 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
|
||||||
@@ -196,7 +195,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("$", "\\$"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -204,50 +203,64 @@ 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(
|
.replaceAll("\\[issue:([^\\s]+?)/([^\\s]+?)#((\\d+))\\]"){ m =>
|
||||||
"\\[issue:([^\\s]+?)/([^\\s]+?)#((\\d+))\\]",
|
if (getRepositoryInfoFromCache(m.group(1), m.group(2)).isDefined) {
|
||||||
s"""<a href="${context.path}/$$1/$$2/issues/$$3">$$1/$$2#$$3</a>"""
|
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>"""
|
||||||
)
|
} else {
|
||||||
.replaceAll(
|
s"${m.group(1)}/${m.group(2)}#${m.group(3)}"
|
||||||
"\\[pullreq:([^\\s]+?)/([^\\s]+?)#((\\d+))\\]",
|
}
|
||||||
s"""<a href="${context.path}/$$1/$$2/pull/$$3">$$1/$$2#$$3</a>"""
|
}
|
||||||
)
|
.replaceAll("\\[pullreq:([^\\s]+?)/([^\\s]+?)#((\\d+))\\]"){ m =>
|
||||||
.replaceAll("\\[repo:([^\\s]+?)/([^\\s]+?)\\]", s"""<a href="${context.path}/$$1/$$2\">$$1/$$2</a>""")
|
if (getRepositoryInfoFromCache(m.group(1), m.group(2)).isDefined) {
|
||||||
.replaceAll(
|
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>"""
|
||||||
"\\[branch:([^\\s]+?)/([^\\s]+?)#([^\\s]+?)\\]",
|
} else {
|
||||||
(m: Match) =>
|
s"${m.group(1)}/${m.group(2)}#${m.group(3)}"
|
||||||
s"""<a href="${context.path}/${m.group(1)}/${m.group(2)}/tree/${encodeRefName(m.group(3))}">${StringUtil
|
}
|
||||||
.escapeHtml(
|
}
|
||||||
m.group(3)
|
.replaceAll("\\[repo:([^\\s]+?)/([^\\s]+?)\\]") { m =>
|
||||||
)}</a>"""
|
if (getRepositoryInfoFromCache(m.group(1), m.group(2)).isDefined) {
|
||||||
)
|
s"""<a href="${context.path}/${m.group(1)}/${m.group(2)}">${m.group(1)}/${m.group(2)}</a>"""
|
||||||
.replaceAll(
|
} else {
|
||||||
"\\[tag:([^\\s]+?)/([^\\s]+?)#([^\\s]+?)\\]",
|
s"${m.group(1)}/${m.group(2)}"
|
||||||
(m: Match) =>
|
}
|
||||||
s"""<a href="${context.path}/${m.group(1)}/${m.group(2)}/tree/${encodeRefName(m.group(3))}">${StringUtil
|
}
|
||||||
.escapeHtml(
|
.replaceAll("\\[branch:([^\\s]+?)/([^\\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)}/tree/${encodeRefName(m.group(3))}">${StringUtil.escapeHtml(m.group(3))}</a>"""
|
||||||
)
|
} else {
|
||||||
.replaceAll("\\[user:([^\\s]+?)\\]", (m: Match) => user(m.group(1)).body)
|
StringUtil.escapeHtml(m.group(3))
|
||||||
.replaceAll(
|
}
|
||||||
"\\[commit:([^\\s]+?)/([^\\s]+?)\\@([^\\s]+?)\\]",
|
}
|
||||||
(m: Match) =>
|
.replaceAll("\\[tag:([^\\s]+?)/([^\\s]+?)#([^\\s]+?)\\]") { m =>
|
||||||
s"""<a href="${context.path}/${m.group(1)}/${m.group(2)}/commit/${m.group(3)}">${m.group(1)}/${m
|
if (getRepositoryInfoFromCache(m.group(1), m.group(2)).isDefined) {
|
||||||
.group(2)}@${m.group(3).substring(0, 7)}</a>"""
|
s"""<a href="${context.path}/${m.group(1)}/${m.group(2)}/tree/${encodeRefName(m.group(3))}">${StringUtil.escapeHtml(m.group(3))}</a>"""
|
||||||
)
|
} else {
|
||||||
.replaceAll(
|
StringUtil.escapeHtml(m.group(3))
|
||||||
"\\[release:([^\\s]+?)/([^\\s]+?)/([^\\s]+?):(.+)\\]",
|
}
|
||||||
(m: Match) =>
|
}
|
||||||
s"""<a href="${context.path}/${m.group(1)}/${m.group(2)}/releases/${encodeRefName(m.group(3))}">${StringUtil
|
.replaceAll("\\[user:([^\\s]+?)\\]") { m =>
|
||||||
.escapeHtml(
|
user(m.group(1)).body
|
||||||
m.group(4)
|
}
|
||||||
)}</a>"""
|
.replaceAll("\\[commit:([^\\s]+?)/([^\\s]+?)\\@([^\\s]+?)\\]") { m =>
|
||||||
)
|
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.
|
||||||
@@ -333,9 +346,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) {
|
||||||
getAccountByUserName(userName)
|
getAccountByUserNameFromCache(userName)
|
||||||
} else {
|
} else {
|
||||||
getAccountByMailAddress(mailAddress)
|
getAccountByMailAddressFromCache(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
|
||||||
@@ -494,4 +507,8 @@ object helpers extends AvatarImageProvider with LinkConverter with RequestCache
|
|||||||
|
|
||||||
case class CommentDiffLine(newLine: Option[String], oldLine: Option[String], `type`: String, text: String)
|
case class CommentDiffLine(newLine: Option[String], oldLine: Option[String], `type`: String, text: String)
|
||||||
|
|
||||||
|
def appendQueryString(baseUrl: String, queryString: String): String = {
|
||||||
|
s"$baseUrl${if (baseUrl.contains("?")) "&" else "?"}$queryString"
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,12 +7,16 @@
|
|||||||
<form action="@context.path/admin/system" method="POST" validate="true" class="form-horizontal" autocomplete="off">
|
<form action="@context.path/admin/system" method="POST" validate="true" class="form-horizontal" autocomplete="off">
|
||||||
<ul class="nav nav-tabs fill-width" id="pullreq-tab">
|
<ul class="nav nav-tabs fill-width" id="pullreq-tab">
|
||||||
<li><a href="#system">System settings</a></li>
|
<li><a href="#system">System settings</a></li>
|
||||||
|
<li><a href="#integrations">Integrations</a></li>
|
||||||
<li><a href="#authentication">Authentication</a></li>
|
<li><a href="#authentication">Authentication</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="tab-content fill-width" style="padding-top: 20px;">
|
<div class="tab-content fill-width" style="padding-top: 20px;">
|
||||||
<div class="tab-pane" id="system">
|
<div class="tab-pane" id="system">
|
||||||
@settings_system(info)
|
@settings_system(info)
|
||||||
</div>
|
</div>
|
||||||
|
<div class="tab-pane" id="integrations">
|
||||||
|
@settings_integrations(info)
|
||||||
|
</div>
|
||||||
<div class="tab-pane" id="authentication">
|
<div class="tab-pane" id="authentication">
|
||||||
@settings_authentication(info)
|
@settings_authentication(info)
|
||||||
</div>
|
</div>
|
||||||
@@ -30,6 +34,9 @@ $(function(){
|
|||||||
if(location.hash == '#authentication'){
|
if(location.hash == '#authentication'){
|
||||||
$('li:has(a[href="#authentication"])').addClass('active');
|
$('li:has(a[href="#authentication"])').addClass('active');
|
||||||
$('div#authentication').addClass('active');
|
$('div#authentication').addClass('active');
|
||||||
|
} else if(location.hash == '#integrations'){
|
||||||
|
$('li:has(a[href="#integrations"])').addClass('active');
|
||||||
|
$('div#integrations').addClass('active');
|
||||||
} else {
|
} else {
|
||||||
$('li:has(a[href="#system"])').addClass('active');
|
$('li:has(a[href="#system"])').addClass('active');
|
||||||
$('div#system').addClass('active');
|
$('div#system').addClass('active');
|
||||||
|
|||||||
@@ -0,0 +1,196 @@
|
|||||||
|
@(info: Option[Any])(implicit context: gitbucket.core.controller.Context)
|
||||||
|
@import gitbucket.core.util.DatabaseConfig
|
||||||
|
<!--====================================================================-->
|
||||||
|
<!-- Services -->
|
||||||
|
<!--====================================================================-->
|
||||||
|
<label class="strong">Services</label>
|
||||||
|
<fieldset>
|
||||||
|
<label class="checkbox">
|
||||||
|
<input type="checkbox" name="gravatar"@if(context.settings.gravatar){ checked}/>
|
||||||
|
Use Gravatar for profile images
|
||||||
|
</label>
|
||||||
|
</fieldset>
|
||||||
|
<!--====================================================================-->
|
||||||
|
<!-- SSH access -->
|
||||||
|
<!--====================================================================-->
|
||||||
|
<hr>
|
||||||
|
<label class="strong">SSH access</label>
|
||||||
|
<fieldset>
|
||||||
|
<label class="checkbox">
|
||||||
|
<input type="checkbox" id="sshEnabled" name="ssh.enabled"@if(context.settings.ssh.enabled){ checked}/>
|
||||||
|
Enable SSH access to git repository
|
||||||
|
<span class="muted normal">(Both SSH host and Base URL are required if SSH access is enabled)</span>
|
||||||
|
</label>
|
||||||
|
</fieldset>
|
||||||
|
<div class="ssh">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-md-2" for="sshHost">SSH host</label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input type="text" id="sshHost" name="ssh.host" class="form-control" value="@context.settings.ssh.sshHost"/>
|
||||||
|
<span id="error-ssh_host" class="error"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-md-2" for="sshPort">SSH port</label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input type="text" id="sshPort" name="ssh.port" class="form-control" value="@context.settings.ssh.sshPort"/>
|
||||||
|
<span id="error-ssh_port" class="error"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!--====================================================================-->
|
||||||
|
<!-- Communication email -->
|
||||||
|
<!--====================================================================-->
|
||||||
|
<hr>
|
||||||
|
<label class="strong">Communication</label>
|
||||||
|
<fieldset>
|
||||||
|
<label class="checkbox">
|
||||||
|
<input type="checkbox" id="useSMTP" name="useSMTP" @if(context.settings.useSMTP){ checked}/>
|
||||||
|
SMTP
|
||||||
|
<span class="muted normal">(Enable notification as well as SMTP configuration if you want to send notification email too)</span>
|
||||||
|
</label>
|
||||||
|
</fieldset>
|
||||||
|
<div class="useSMTP">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-md-2" for="smtpHost">SMTP host</label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input type="text" id="smtpHost" name="smtp.host" class="form-control" value="@context.settings.smtp.map(_.host)"/>
|
||||||
|
<span id="error-smtp_host" class="error"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-md-2" for="smtpPort">SMTP port</label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input type="text" id="smtpPort" name="smtp.port" class="form-control input-mini" value="@context.settings.smtp.map(_.port)"/>
|
||||||
|
<span id="error-smtp_port" class="error"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-md-2" for="smtpUser">SMTP user</label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input type="text" id="smtpUser" name="smtp.user" class="form-control" value="@context.settings.smtp.map(_.user)"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-md-2" for="smtpPassword">SMTP password</label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input type="password" id="smtpPassword" name="smtp.password" class="form-control" value="@context.settings.smtp.map(_.password)"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-md-2" for="smtpSsl">Enable SSL</label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input type="checkbox" id="smtpSsl" name="smtp.ssl"@if(context.settings.smtp.flatMap(_.ssl).getOrElse(false)){ checked}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-md-2" for="smtpStarttls">Enable STARTTLS</label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input type="checkbox" id="smtpStarttls" name="smtp.starttls"@if(context.settings.smtp.flatMap(_.starttls).getOrElse(false)){ checked}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-md-2" for="fromAddress">FROM address</label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input type="text" id="fromAddress" name="smtp.fromAddress" class="form-control" value="@context.settings.smtp.map(_.fromAddress)"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-md-2" for="fromName">FROM name</label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input type="text" id="fromName" name="smtp.fromName" class="form-control" value="@context.settings.smtp.map(_.fromName)"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-right">
|
||||||
|
Send test mail to:
|
||||||
|
<input type="text" id="testAddress" size="30"/>
|
||||||
|
<input type="button" id="sendTestMail" value="Send"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!--====================================================================-->
|
||||||
|
<!-- Notification email -->
|
||||||
|
<!--====================================================================-->
|
||||||
|
<hr>
|
||||||
|
<label class="strong">Notifications</label>
|
||||||
|
<fieldset>
|
||||||
|
<label class="checkbox" for="notification">
|
||||||
|
<input type="checkbox" id="notification" name="notification"@if(context.settings.notification){ checked}/>
|
||||||
|
Send notifications
|
||||||
|
</label>
|
||||||
|
</fieldset>
|
||||||
|
<!--====================================================================-->
|
||||||
|
<!-- Web hook -->
|
||||||
|
<!--====================================================================-->
|
||||||
|
<hr>
|
||||||
|
<label class="strong">Web hook</label>
|
||||||
|
<fieldset>
|
||||||
|
<label class="checkbox" for="blockPrivateAddress">
|
||||||
|
<input type="checkbox" id="blockPrivateAddress" name="webhook.blockPrivateAddress"@if(context.settings.webHook.blockPrivateAddress){ checked}/>
|
||||||
|
Block sending to private addresses
|
||||||
|
</label>
|
||||||
|
</fieldset>
|
||||||
|
<div class="webhook">
|
||||||
|
<label><span class="strong">IP whitelist</span></label>
|
||||||
|
<fieldset>
|
||||||
|
<textarea name="webhook.whitelist" class="form-control" style="height: 100px;">@context.settings.webHook.whitelist.mkString("\n")</textarea>
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
$(function(){
|
||||||
|
$('#sendTestMail').click(function(){
|
||||||
|
var host = $('#smtpHost' ).val();
|
||||||
|
var port = $('#smtpPort' ).val();
|
||||||
|
var user = $('#smtpUser' ).val();
|
||||||
|
var password = $('#smtpPassword').val();
|
||||||
|
var ssl = $('#smtpSsl' ).prop('checked');
|
||||||
|
var starttls = $('#smtpStarttls').prop('checked');
|
||||||
|
var fromAddress = $('#fromAddress' ).val();
|
||||||
|
var fromName = $('#fromName' ).val();
|
||||||
|
var testAddress = $('#testAddress' ).val();
|
||||||
|
|
||||||
|
if(host == ''){
|
||||||
|
alert('SMTP Host is required.');
|
||||||
|
$('#smtpHost').focus();
|
||||||
|
} else if(testAddress == ''){
|
||||||
|
alert('Destination is required.');
|
||||||
|
$('#testAddress').focus();
|
||||||
|
} else {
|
||||||
|
$.post('@context.path/admin/system/sendmail', {
|
||||||
|
'smtp.host': host,
|
||||||
|
'smtp.port': port,
|
||||||
|
'smtp.user': user,
|
||||||
|
'smtp.password': password,
|
||||||
|
'smtp.ssl': ssl,
|
||||||
|
'smtp.starttls': starttls,
|
||||||
|
'smtp.fromAddress': fromAddress,
|
||||||
|
'smtp.fromName': fromName,
|
||||||
|
'testAddress': testAddress
|
||||||
|
}, function(data, status){
|
||||||
|
if(data != ''){
|
||||||
|
alert(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#sshEnabled').change(function(){
|
||||||
|
$('.ssh input').prop('disabled', !$(this).prop('checked'));
|
||||||
|
}).change();
|
||||||
|
|
||||||
|
$('#useSMTP').change(function(){
|
||||||
|
$('.useSMTP input').prop('disabled', !$(this).prop('checked'));
|
||||||
|
|
||||||
|
// With only SMTP in current version, notification cannot be enabled if no communication channel exists
|
||||||
|
$('#notification').prop('disabled', !$(this).prop('checked'));
|
||||||
|
|
||||||
|
if (!$(this).prop('checked')) {
|
||||||
|
// With only SMTP in current version, if SMTP is unchecked then we disable notification
|
||||||
|
$('#notification').prop('checked', false);
|
||||||
|
}
|
||||||
|
}).change();
|
||||||
|
|
||||||
|
$('#blockPrivateAddress').change(function(){
|
||||||
|
$('.webhook textarea').prop('disabled', !$(this).prop('checked'));
|
||||||
|
}).change();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@@ -94,6 +94,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!--====================================================================-->
|
<!--====================================================================-->
|
||||||
|
<!-- User-defined CSS -->
|
||||||
|
<!--====================================================================-->
|
||||||
|
<hr>
|
||||||
|
<label><span class="strong">User-defined CSS</span></label>
|
||||||
|
<fieldset>
|
||||||
|
<textarea name="userDefinedCss" class="form-control" style="height: 100px;">@context.settings.userDefinedCss</textarea>
|
||||||
|
</fieldset>
|
||||||
|
<!--====================================================================-->
|
||||||
<!-- Account registration -->
|
<!-- Account registration -->
|
||||||
<!--====================================================================-->
|
<!--====================================================================-->
|
||||||
<hr>
|
<hr>
|
||||||
@@ -108,8 +116,80 @@
|
|||||||
<span class="strong">Deny</span> <span class="normal">- Only administrators can create accounts.</span>
|
<span class="strong">Deny</span> <span class="normal">- Only administrators can create accounts.</span>
|
||||||
</label>
|
</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
<!--====================================================================-->
|
||||||
|
<!-- Repository operations -->
|
||||||
|
<!--====================================================================-->
|
||||||
<hr>
|
<hr>
|
||||||
<label class="strong">Default permissions when creating a new repository</label>
|
<label class="strong">Repository operation</label>
|
||||||
|
<fieldset>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-md-2">Create</label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<label class="radio">
|
||||||
|
<input type="radio" name="repositoryOperation.create" value="true"@if(context.settings.repositoryOperation.create){ checked}>
|
||||||
|
<span class="strong">All users</span> <span class="normal">- All users can create repository.</span>
|
||||||
|
</label>
|
||||||
|
<label class="radio">
|
||||||
|
<input type="radio" name="repositoryOperation.create" value="false"@if(!context.settings.repositoryOperation.create){ checked}>
|
||||||
|
<span class="strong">Admin only</span> <span class="normal">- Only administrators can create repository.</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-md-2">Delete</label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<label class="radio">
|
||||||
|
<input type="radio" name="repositoryOperation.delete" value="true"@if(context.settings.repositoryOperation.delete){ checked}>
|
||||||
|
<span class="strong">All users</span> <span class="normal">- All users can delete repository.</span>
|
||||||
|
</label>
|
||||||
|
<label class="radio">
|
||||||
|
<input type="radio" name="repositoryOperation.delete" value="false"@if(!context.settings.repositoryOperation.delete){ checked}>
|
||||||
|
<span class="strong">Admin only</span> <span class="normal">- Only administrators can delete repository.</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-md-2">Rename</label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<label class="radio">
|
||||||
|
<input type="radio" name="repositoryOperation.rename" value="true"@if(context.settings.repositoryOperation.rename){ checked}>
|
||||||
|
<span class="strong">All users</span> <span class="normal">- All users can rename repository.</span>
|
||||||
|
</label>
|
||||||
|
<label class="radio">
|
||||||
|
<input type="radio" name="repositoryOperation.rename" value="false"@if(!context.settings.repositoryOperation.rename){ checked}>
|
||||||
|
<span class="strong">Admin only</span> <span class="normal">- Only administrators can rename repository.</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-md-2">Transfer</label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<label class="radio">
|
||||||
|
<input type="radio" name="repositoryOperation.transfer" value="true"@if(context.settings.repositoryOperation.transfer){ checked}>
|
||||||
|
<span class="strong">All users</span> <span class="normal">- All users can transfer repository.</span>
|
||||||
|
</label>
|
||||||
|
<label class="radio">
|
||||||
|
<input type="radio" name="repositoryOperation.transfer" value="false"@if(!context.settings.repositoryOperation.transfer){ checked}>
|
||||||
|
<span class="strong">Admin only</span> <span class="normal">- Only administrators can transfer repository.</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-md-2">Fork</label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<label class="radio">
|
||||||
|
<input type="radio" name="repositoryOperation.fork" value="true"@if(context.settings.repositoryOperation.fork){ checked}>
|
||||||
|
<span class="strong">All users</span> <span class="normal">- All users can fork repository.</span>
|
||||||
|
</label>
|
||||||
|
<label class="radio">
|
||||||
|
<input type="radio" name="repositoryOperation.fork" value="false"@if(!context.settings.repositoryOperation.fork){ checked}>
|
||||||
|
<span class="strong">Admin only</span> <span class="normal">- Only administrators can fork repository.</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
<hr>
|
||||||
|
<label class="strong">Default visibility when creating a new repository</label>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<label class="radio">
|
<label class="radio">
|
||||||
<input type="radio" name="isCreateRepoOptionPublic" value="true"@if(context.settings.isCreateRepoOptionPublic){ checked}>
|
<input type="radio" name="isCreateRepoOptionPublic" value="true"@if(context.settings.isCreateRepoOptionPublic){ checked}>
|
||||||
@@ -151,6 +231,41 @@
|
|||||||
</label>
|
</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<!--====================================================================-->
|
<!--====================================================================-->
|
||||||
|
<!-- File upload -->
|
||||||
|
<!--====================================================================-->
|
||||||
|
<hr>
|
||||||
|
<label class="strong">File upload</label>
|
||||||
|
<fieldset>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-md-2" for="uploadMaxFileSize">Max size</label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input type="text" id="uploadMaxFileSize" name="upload.maxFileSize" class="form-control input-mini" value="@context.settings.upload.maxFileSize"/>
|
||||||
|
<span id="error-upload_maxFileSize" class="error"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-md-2" for="uploadTimeout">Timeout</label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input type="text" id="uploadTimeout" name="upload.timeout" class="form-control input-mini" value="@context.settings.upload.timeout"/>
|
||||||
|
<span id="error-upload_timeout" class="error"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-md-2" for="uploadLargeMaxFileSize">Max size for large files</label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input type="text" id="uploadLargeMaxFileSize" name="upload.largeMaxFileSize" class="form-control input-mini" value="@context.settings.upload.largeMaxFileSize"/>
|
||||||
|
<span id="error-upload_largeMaxFileSize" class="error"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-md-2" for="uploadLargeTimeout">Timeout for large files</label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<input type="text" id="uploadLargeTimeout" name="upload.largeTimeout" class="form-control input-mini" value="@context.settings.upload.largeTimeout"/>
|
||||||
|
<span id="error-upload_largeTimeout" class="error"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
<!--====================================================================-->
|
||||||
<!-- Activity -->
|
<!-- Activity -->
|
||||||
<!--====================================================================-->
|
<!--====================================================================-->
|
||||||
<hr>
|
<hr>
|
||||||
@@ -165,141 +280,20 @@
|
|||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<!--====================================================================-->
|
<!--====================================================================-->
|
||||||
<!-- Services -->
|
<!-- Sidebar -->
|
||||||
<!--====================================================================-->
|
<!--====================================================================-->
|
||||||
<hr>
|
<hr>
|
||||||
<label class="strong">Services</label>
|
<label><span class="strong">Show Repositories in Sidebar</span></label>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<label class="checkbox">
|
<label class="radio">
|
||||||
<input type="checkbox" name="gravatar"@if(context.settings.gravatar){ checked}/>
|
<input type="radio" name="limitVisibleRepositories" value="false"@if(!context.settings.limitVisibleRepositories){ checked}>
|
||||||
Use Gravatar for profile images
|
<span class="strong">All</span> <span class="normal">- Show all repositories in sidebar.</span>
|
||||||
|
</label>
|
||||||
|
<label class="radio">
|
||||||
|
<input type="radio" name="limitVisibleRepositories" value="true"@if(context.settings.limitVisibleRepositories){ checked}>
|
||||||
|
<span class="strong">Limited</span> <span class="normal">- Limit the visible repositories in sidebar.</span>
|
||||||
</label>
|
</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<!--====================================================================-->
|
|
||||||
<!-- SSH access -->
|
|
||||||
<!--====================================================================-->
|
|
||||||
<hr>
|
|
||||||
<label class="strong">SSH access</label>
|
|
||||||
<fieldset>
|
|
||||||
<label class="checkbox">
|
|
||||||
<input type="checkbox" id="sshEnabled" name="ssh.enabled"@if(context.settings.ssh.enabled){ checked}/>
|
|
||||||
Enable SSH access to git repository
|
|
||||||
<span class="muted normal">(Both SSH host and Base URL are required if SSH access is enabled)</span>
|
|
||||||
</label>
|
|
||||||
</fieldset>
|
|
||||||
<div class="ssh">
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="control-label col-md-2" for="sshHost">SSH host</label>
|
|
||||||
<div class="col-md-10">
|
|
||||||
<input type="text" id="sshHost" name="ssh.host" class="form-control" value="@context.settings.ssh.sshHost"/>
|
|
||||||
<span id="error-ssh_host" class="error"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="control-label col-md-2" for="sshPort">SSH port</label>
|
|
||||||
<div class="col-md-10">
|
|
||||||
<input type="text" id="sshPort" name="ssh.port" class="form-control" value="@context.settings.ssh.sshPort"/>
|
|
||||||
<span id="error-ssh_port" class="error"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!--====================================================================-->
|
|
||||||
<!-- Communication email -->
|
|
||||||
<!--====================================================================-->
|
|
||||||
<hr>
|
|
||||||
<label class="strong">Communication</label>
|
|
||||||
<fieldset>
|
|
||||||
<label class="checkbox">
|
|
||||||
<input type="checkbox" id="useSMTP" name="useSMTP" @if(context.settings.useSMTP){ checked}/>
|
|
||||||
SMTP
|
|
||||||
<span class="muted normal">(Enable notification as well as SMTP configuration if you want to send notification email too)</span>
|
|
||||||
</label>
|
|
||||||
</fieldset>
|
|
||||||
<div class="useSMTP">
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="control-label col-md-2" for="smtpHost">SMTP host</label>
|
|
||||||
<div class="col-md-10">
|
|
||||||
<input type="text" id="smtpHost" name="smtp.host" class="form-control" value="@context.settings.smtp.map(_.host)"/>
|
|
||||||
<span id="error-smtp_host" class="error"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="control-label col-md-2" for="smtpPort">SMTP port</label>
|
|
||||||
<div class="col-md-10">
|
|
||||||
<input type="text" id="smtpPort" name="smtp.port" class="form-control input-mini" value="@context.settings.smtp.map(_.port)"/>
|
|
||||||
<span id="error-smtp_port" class="error"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="control-label col-md-2" for="smtpUser">SMTP user</label>
|
|
||||||
<div class="col-md-10">
|
|
||||||
<input type="text" id="smtpUser" name="smtp.user" class="form-control" value="@context.settings.smtp.map(_.user)"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="control-label col-md-2" for="smtpPassword">SMTP password</label>
|
|
||||||
<div class="col-md-10">
|
|
||||||
<input type="password" id="smtpPassword" name="smtp.password" class="form-control" value="@context.settings.smtp.map(_.password)"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="control-label col-md-2" for="smtpSsl">Enable SSL</label>
|
|
||||||
<div class="col-md-10">
|
|
||||||
<input type="checkbox" id="smtpSsl" name="smtp.ssl"@if(context.settings.smtp.flatMap(_.ssl).getOrElse(false)){ checked}/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="control-label col-md-2" for="smtpStarttls">Enable STARTTLS</label>
|
|
||||||
<div class="col-md-10">
|
|
||||||
<input type="checkbox" id="smtpStarttls" name="smtp.starttls"@if(context.settings.smtp.flatMap(_.starttls).getOrElse(false)){ checked}/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="control-label col-md-2" for="fromAddress">FROM address</label>
|
|
||||||
<div class="col-md-10">
|
|
||||||
<input type="text" id="fromAddress" name="smtp.fromAddress" class="form-control" value="@context.settings.smtp.map(_.fromAddress)"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="control-label col-md-2" for="fromName">FROM name</label>
|
|
||||||
<div class="col-md-10">
|
|
||||||
<input type="text" id="fromName" name="smtp.fromName" class="form-control" value="@context.settings.smtp.map(_.fromName)"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="text-right">
|
|
||||||
Send test mail to:
|
|
||||||
<input type="text" id="testAddress" size="30"/>
|
|
||||||
<input type="button" id="sendTestMail" value="Send"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!--====================================================================-->
|
|
||||||
<!-- Notification email -->
|
|
||||||
<!--====================================================================-->
|
|
||||||
<hr>
|
|
||||||
<label class="strong">Notifications</label>
|
|
||||||
<fieldset>
|
|
||||||
<label class="checkbox" for="notification">
|
|
||||||
<input type="checkbox" id="notification" name="notification"@if(context.settings.notification){ checked}/>
|
|
||||||
Send notifications
|
|
||||||
</label>
|
|
||||||
</fieldset>
|
|
||||||
<!--====================================================================-->
|
|
||||||
<!-- Web hook -->
|
|
||||||
<!--====================================================================-->
|
|
||||||
<hr>
|
|
||||||
<label class="strong">Web hook</label>
|
|
||||||
<fieldset>
|
|
||||||
<label class="checkbox" for="blockPrivateAddress">
|
|
||||||
<input type="checkbox" id="blockPrivateAddress" name="webhook.blockPrivateAddress"@if(context.settings.webHook.blockPrivateAddress){ checked}/>
|
|
||||||
Block sending to private addresses
|
|
||||||
</label>
|
|
||||||
</fieldset>
|
|
||||||
<div class="webhook">
|
|
||||||
<label><span class="strong">IP whitelist</span></label>
|
|
||||||
<fieldset>
|
|
||||||
<textarea name="webhook.whitelist" class="form-control" style="height: 100px;">@context.settings.webHook.whitelist.mkString("\n")</textarea>
|
|
||||||
</fieldset>
|
|
||||||
</div>
|
|
||||||
<script>
|
<script>
|
||||||
$(function(){
|
$(function(){
|
||||||
$('#skinName').change(function(evt) {
|
$('#skinName').change(function(evt) {
|
||||||
@@ -309,61 +303,5 @@ $(function(){
|
|||||||
themeCss.attr('href', themeCss.attr('href').replace(oldVal, that.val()));
|
themeCss.attr('href', themeCss.attr('href').replace(oldVal, that.val()));
|
||||||
$(document.body).removeClass(oldVal).addClass(that.val());
|
$(document.body).removeClass(oldVal).addClass(that.val());
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#sendTestMail').click(function(){
|
|
||||||
var host = $('#smtpHost' ).val();
|
|
||||||
var port = $('#smtpPort' ).val();
|
|
||||||
var user = $('#smtpUser' ).val();
|
|
||||||
var password = $('#smtpPassword').val();
|
|
||||||
var ssl = $('#smtpSsl' ).prop('checked');
|
|
||||||
var starttls = $('#smtpStarttls').prop('checked');
|
|
||||||
var fromAddress = $('#fromAddress' ).val();
|
|
||||||
var fromName = $('#fromName' ).val();
|
|
||||||
var testAddress = $('#testAddress' ).val();
|
|
||||||
|
|
||||||
if(host == ''){
|
|
||||||
alert('SMTP Host is required.');
|
|
||||||
$('#smtpHost').focus();
|
|
||||||
} else if(testAddress == ''){
|
|
||||||
alert('Destination is required.');
|
|
||||||
$('#testAddress').focus();
|
|
||||||
} else {
|
|
||||||
$.post('@context.path/admin/system/sendmail', {
|
|
||||||
'smtp.host': host,
|
|
||||||
'smtp.port': port,
|
|
||||||
'smtp.user': user,
|
|
||||||
'smtp.password': password,
|
|
||||||
'smtp.ssl': ssl,
|
|
||||||
'smtp.starttls': starttls,
|
|
||||||
'smtp.fromAddress': fromAddress,
|
|
||||||
'smtp.fromName': fromName,
|
|
||||||
'testAddress': testAddress
|
|
||||||
}, function(data, status){
|
|
||||||
if(data != ''){
|
|
||||||
alert(data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#sshEnabled').change(function(){
|
|
||||||
$('.ssh input').prop('disabled', !$(this).prop('checked'));
|
|
||||||
}).change();
|
|
||||||
|
|
||||||
$('#useSMTP').change(function(){
|
|
||||||
$('.useSMTP input').prop('disabled', !$(this).prop('checked'));
|
|
||||||
|
|
||||||
// With only SMTP in current version, notification cannot be enabled if no communication channel exists
|
|
||||||
$('#notification').prop('disabled', !$(this).prop('checked'));
|
|
||||||
|
|
||||||
if (!$(this).prop('checked')) {
|
|
||||||
// With only SMTP in current version, if SMTP is unchecked then we disable notification
|
|
||||||
$('#notification').prop('checked', false);
|
|
||||||
}
|
|
||||||
}).change();
|
|
||||||
|
|
||||||
$('#blockPrivateAddress').change(function(){
|
|
||||||
$('.webhook textarea').prop('disabled', !$(this).prop('checked'));
|
|
||||||
}).change();
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -7,21 +7,24 @@
|
|||||||
@activities.map { activity =>
|
@activities.map { activity =>
|
||||||
<div class="block">
|
<div class="block">
|
||||||
@(activity.activityType match {
|
@(activity.activityType match {
|
||||||
case "open_issue" => detailActivity(activity, "issue-opened")
|
case "open_issue" => simpleActivity(activity)
|
||||||
case "comment_issue" => detailActivity(activity, "comment-discussion")
|
case "comment_issue" => simpleActivity(activity)
|
||||||
case "comment_commit" => detailActivity(activity, "comment-discussion")
|
case "comment_commit" => simpleActivity(activity)
|
||||||
case "close_issue" => detailActivity(activity, "issue-closed")
|
case "close_issue" => simpleActivity(activity)
|
||||||
case "reopen_issue" => detailActivity(activity, "issue-reopened")
|
case "reopen_issue" => simpleActivity(activity)
|
||||||
case "open_pullreq" => detailActivity(activity, "git-pull-request")
|
case "open_pullreq" => simpleActivity(activity)
|
||||||
case "merge_pullreq" => detailActivity(activity, "git-merge")
|
case "merge_pullreq" => simpleActivity(activity)
|
||||||
case "release" => detailActivity(activity, "package")
|
case "release" => simpleActivity(activity)
|
||||||
case "create_repository" => simpleActivity(activity, "repo")
|
case "create_repository" => simpleActivity(activity)
|
||||||
case "create_branch" => simpleActivity(activity, "git-branch")
|
case "delete_repository" => simpleActivity(activity)
|
||||||
case "delete_branch" => simpleActivity(activity, "circle-slash")
|
case "rename_repository" => simpleActivity(activity)
|
||||||
case "create_tag" => simpleActivity(activity, "tag")
|
case "transfer_repository" => simpleActivity(activity)
|
||||||
case "delete_tag" => simpleActivity(activity, "circle-slash")
|
case "create_branch" => simpleActivity(activity)
|
||||||
case "fork" => simpleActivity(activity, "repo-forked")
|
case "delete_branch" => simpleActivity(activity)
|
||||||
case "push" => customActivity(activity, "git-commit"){
|
case "create_tag" => simpleActivity(activity)
|
||||||
|
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){
|
||||||
@@ -37,12 +40,12 @@
|
|||||||
}}
|
}}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
case "create_wiki" => customActivity(activity, "book"){
|
case "create_wiki" => customActivity(activity){
|
||||||
<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, "book"){
|
case "edit_wiki" => customActivity(activity){
|
||||||
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">
|
||||||
@@ -60,26 +63,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@detailActivity(activity: gitbucket.core.model.Activity, image: String) = {
|
@customActivity(activity: gitbucket.core.model.Activity)(additionalInfo: Any) = {
|
||||||
@*
|
|
||||||
<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">
|
||||||
@@ -90,10 +74,7 @@
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
@simpleActivity(activity: gitbucket.core.model.Activity, image: String) = {
|
@simpleActivity(activity: gitbucket.core.model.Activity) = {
|
||||||
@*
|
|
||||||
<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>
|
||||||
|
|||||||
@@ -65,9 +65,8 @@ $(function(){
|
|||||||
}
|
}
|
||||||
@dropzone(clickable: Boolean, textareaId: Option[String]) = {
|
@dropzone(clickable: Boolean, textareaId: Option[String]) = {
|
||||||
url: '@context.path/upload/file/@repository.owner/@repository.name',
|
url: '@context.path/upload/file/@repository.owner/@repository.name',
|
||||||
maxFilesize: @{FileUtil.MaxFileSize / 1024 / 1024},
|
maxFilesize: @{context.settings.upload.maxFileSize / 1024 / 1024},
|
||||||
//timeout defaults to 30 secs
|
timeout: @{context.settings.upload.timeout},
|
||||||
timeout: @{FileUtil.UploadTimeout},
|
|
||||||
clickable: @clickable,
|
clickable: @clickable,
|
||||||
previewTemplate: "<div class=\"dz-preview\">\n <div class=\"dz-progress\"><span class=\"dz-upload\" data-dz-uploadprogress>Uploading your files...</span></div>\n <div class=\"dz-error-message\"><span data-dz-errormessage></span></div>\n</div>",
|
previewTemplate: "<div class=\"dz-preview\">\n <div class=\"dz-progress\"><span class=\"dz-upload\" data-dz-uploadprogress>Uploading your files...</span></div>\n <div class=\"dz-error-message\"><span data-dz-errormessage></span></div>\n</div>",
|
||||||
success: function(file, id) {
|
success: function(file, id) {
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
@(latestUpdatedDate: java.util.Date,
|
@(latestUpdatedDate: java.util.Date,
|
||||||
recentOnly: Boolean = true)
|
recentOnly: Boolean = true)
|
||||||
@import gitbucket.core.view.helpers
|
@import gitbucket.core.view.helpers
|
||||||
<span data-toggle="tooltip" title="@helpers.datetime(latestUpdatedDate)">
|
@if(latestUpdatedDate != null){
|
||||||
@if(recentOnly){
|
<span data-toggle="tooltip" title="@helpers.datetime(latestUpdatedDate)">
|
||||||
@helpers.datetimeAgoRecentOnly(latestUpdatedDate)
|
@if(recentOnly){
|
||||||
} else {
|
@helpers.datetimeAgoRecentOnly(latestUpdatedDate)
|
||||||
@helpers.datetimeAgo(latestUpdatedDate)
|
} else {
|
||||||
}
|
@helpers.datetimeAgo(latestUpdatedDate)
|
||||||
</span>
|
}
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
|||||||
@@ -104,8 +104,8 @@
|
|||||||
} else {
|
} else {
|
||||||
@if(diff.newContent != None || diff.oldContent != None){
|
@if(diff.newContent != None || diff.oldContent != None){
|
||||||
<div id="diffText-@i" class="diffText"></div>
|
<div id="diffText-@i" class="diffText"></div>
|
||||||
<input type="hidden" id="newText-@i" data-file-name="@diff.oldPath" value="@diff.newContent">
|
<input type="hidden" id="newText-@i" data-file-name="@diff.oldPath" data-val="@diff.newContent">
|
||||||
<input type="hidden" id="oldText-@i" data-file-name="@diff.newPath" value="@diff.oldContent">
|
<input type="hidden" id="oldText-@i" data-file-name="@diff.newPath" data-val="@diff.oldContent">
|
||||||
} else {
|
} else {
|
||||||
@if(diff.newIsImage || diff.oldIsImage){
|
@if(diff.newIsImage || diff.oldIsImage){
|
||||||
<div class="diff-image-render diff2up">
|
<div class="diff-image-render diff2up">
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
@(page: Int, count: Int, limit: Int, width: Int, baseURL: String)
|
@import gitbucket.core.view.helpers
|
||||||
|
@(page: Int, count: Int, limit: Int, width: Int, baseURL: String = "")
|
||||||
@defining(gitbucket.core.view.Pagination(page, count, limit, width)){ p =>
|
@defining(gitbucket.core.view.Pagination(page, count, limit, width)){ p =>
|
||||||
@if(p.count > p.limit){
|
@if(p.count > p.limit){
|
||||||
<div>
|
<div>
|
||||||
@@ -6,7 +7,7 @@
|
|||||||
@if(page == 1){
|
@if(page == 1){
|
||||||
<li class="disabled"><span>◀</span></li>
|
<li class="disabled"><span>◀</span></li>
|
||||||
} else {
|
} else {
|
||||||
<li><a href="@baseURL&page=@(page - 1)">◀</a></li>
|
<li><a href="@helpers.appendQueryString(baseURL, s"page=${page - 1 }")">◀</a></li>
|
||||||
}
|
}
|
||||||
@for(i <- 1 to p.max){
|
@for(i <- 1 to p.max){
|
||||||
@if(i == p.max && p.omitRight){
|
@if(i == p.max && p.omitRight){
|
||||||
@@ -16,7 +17,7 @@
|
|||||||
<li class="active"><span>@i</span></li>
|
<li class="active"><span>@i</span></li>
|
||||||
} else {
|
} else {
|
||||||
@if(p.visibleFor(i)){
|
@if(p.visibleFor(i)){
|
||||||
<li><a href="@baseURL&page=@i">@i</a></li>
|
<li><a href="@helpers.appendQueryString(baseURL, s"page=$i")">@i</a></li>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@if(i == 1 && p.omitLeft){
|
@if(i == 1 && p.omitLeft){
|
||||||
@@ -26,7 +27,7 @@
|
|||||||
@if(page == p.max){
|
@if(page == p.max){
|
||||||
<li class="disabled"><span>▶</span></li>
|
<li class="disabled"><span>▶</span></li>
|
||||||
} else {
|
} else {
|
||||||
<li><a href="@baseURL&page=@(page + 1)">▶</a></li>
|
<li><a href="@helpers.appendQueryString(baseURL, s"page=${page + 1}")">▶</a></li>
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -11,7 +11,9 @@
|
|||||||
repository: gitbucket.core.service.RepositoryService.RepositoryInfo,
|
repository: gitbucket.core.service.RepositoryService.RepositoryInfo,
|
||||||
isEditable: Boolean,
|
isEditable: Boolean,
|
||||||
isManageable: Boolean)(implicit context: gitbucket.core.controller.Context)
|
isManageable: Boolean)(implicit context: gitbucket.core.controller.Context)
|
||||||
|
|
||||||
@import gitbucket.core.view.helpers
|
@import gitbucket.core.view.helpers
|
||||||
|
|
||||||
@gitbucket.core.html.main((if(target == "issues") "Issues" else "Pull requests") + s" - ${repository.owner}/${repository.name}", Some(repository)){
|
@gitbucket.core.html.main((if(target == "issues") "Issues" else "Pull requests") + s" - ${repository.owner}/${repository.name}", Some(repository)){
|
||||||
@gitbucket.core.html.menu(target, repository){
|
@gitbucket.core.html.menu(target, repository){
|
||||||
<ul class="nav nav-pills pull-left" style="line-height: 14px; margin-bottom: 10px;">
|
<ul class="nav nav-pills pull-left" style="line-height: 14px; margin-bottom: 10px;">
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
<link href="@helpers.assets("/vendors/jquery-ui/jquery-ui.structure.min.css")" rel="stylesheet">
|
<link href="@helpers.assets("/vendors/jquery-ui/jquery-ui.structure.min.css")" rel="stylesheet">
|
||||||
<link href="@helpers.assets("/vendors/jquery-ui/jquery-ui.theme.min.css")" rel="stylesheet">
|
<link href="@helpers.assets("/vendors/jquery-ui/jquery-ui.theme.min.css")" rel="stylesheet">
|
||||||
<link href="@helpers.assets("/common/css/gitbucket.css")" rel="stylesheet">
|
<link href="@helpers.assets("/common/css/gitbucket.css")" rel="stylesheet">
|
||||||
<script src="@helpers.assets("/vendors/jquery/jquery-3.4.1.min.js")"></script>
|
<script src="@helpers.assets("/vendors/jquery/jquery-3.5.1.min.js")"></script>
|
||||||
<script src="@helpers.assets("/vendors/jquery-ui/jquery-ui.min.js")"></script>
|
<script src="@helpers.assets("/vendors/jquery-ui/jquery-ui.min.js")"></script>
|
||||||
<script src="@helpers.assets("/vendors/dropzone/dropzone.min.js")"></script>
|
<script src="@helpers.assets("/vendors/dropzone/dropzone.min.js")"></script>
|
||||||
<script src="@helpers.assets("/common/js/validation.js")"></script>
|
<script src="@helpers.assets("/common/js/validation.js")"></script>
|
||||||
@@ -55,6 +55,9 @@
|
|||||||
<meta name="go-import" content="@context.baseUrl.replaceFirst("^https?://", "")/@repository.owner/@repository.name git @repository.httpUrl" />
|
<meta name="go-import" content="@context.baseUrl.replaceFirst("^https?://", "")/@repository.owner/@repository.name git @repository.httpUrl" />
|
||||||
}
|
}
|
||||||
<script src="@helpers.assets("/vendors/AdminLTE-2.4.2/js/adminlte.min.js")" type="text/javascript"></script>
|
<script src="@helpers.assets("/vendors/AdminLTE-2.4.2/js/adminlte.min.js")" type="text/javascript"></script>
|
||||||
|
@context.settings.userDefinedCss.map { css =>
|
||||||
|
<style type="text/css">@css</style>
|
||||||
|
}
|
||||||
</head>
|
</head>
|
||||||
<body class="@context.settings.skinName page-load @if(body.toString.contains("menu-item-hover")){sidebar-mini} @if(context.sidebarCollapse){sidebar-collapse}">
|
<body class="@context.settings.skinName page-load @if(body.toString.contains("menu-item-hover")){sidebar-mini} @if(context.sidebarCollapse){sidebar-collapse}">
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
@@ -69,7 +72,7 @@
|
|||||||
<nav class="navbar navbar-static-top" role="navigation">
|
<nav class="navbar navbar-static-top" role="navigation">
|
||||||
<!-- Sidebar toggle button-->
|
<!-- Sidebar toggle button-->
|
||||||
@if(body.toString.contains("main-sidebar")){
|
@if(body.toString.contains("main-sidebar")){
|
||||||
<a href="#" class="sidebar-toggle" data-toggle="push-menu" role="button">
|
<a href="#" class="sidebar-toggle" data-toggle="push-menu" role="button" title="Toggle navigation">
|
||||||
<span class="sr-only">Toggle navigation</span>
|
<span class="sr-only">Toggle navigation</span>
|
||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
@@ -99,7 +102,9 @@
|
|||||||
<ul class="dropdown-menu pull-right" style="width: auto;">
|
<ul class="dropdown-menu pull-right" style="width: auto;">
|
||||||
<li>
|
<li>
|
||||||
<ul class="menu">
|
<ul class="menu">
|
||||||
<li><a href="@context.path/new">New repository</a></li>
|
@if(context.settings.repositoryOperation.create || context.loginAccount.get.isAdmin){
|
||||||
|
<li><a href="@context.path/new">New repository</a></li>
|
||||||
|
}
|
||||||
<li><a href="@context.path/groups/new">New group</a></li>
|
<li><a href="@context.path/groups/new">New group</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -75,7 +75,7 @@
|
|||||||
@gitbucket.core.plugin.PluginRegistry().getRepositoryHeaders.map { repositoryHeaderComponent =>
|
@gitbucket.core.plugin.PluginRegistry().getRepositoryHeaders.map { repositoryHeaderComponent =>
|
||||||
@repositoryHeaderComponent(repository, context)
|
@repositoryHeaderComponent(repository, context)
|
||||||
}
|
}
|
||||||
@if(repository.repository.options.allowFork) {
|
@if(repository.repository.options.allowFork && (context.settings.repositoryOperation.fork || context.loginAccount.map(_.isAdmin).getOrElse(false))) {
|
||||||
@if(context.loginAccount.isEmpty){
|
@if(context.loginAccount.isEmpty){
|
||||||
<a class="btn btn-default btn-sm" href="@context.path/signin?redirect=@helpers.urlEncode(s"${context.path}/${repository.owner}/${repository.name}")">
|
<a class="btn btn-default btn-sm" href="@context.path/signin?redirect=@helpers.urlEncode(s"${context.path}/${repository.owner}/${repository.name}")">
|
||||||
<span class="strong"><i class="octicon octicon-repo-forked"></i>Fork</span><span class="muted">: @repository.forkedCount</span>
|
<span class="strong"><i class="octicon octicon-repo-forked"></i>Fork</span><span class="muted">: @repository.forkedCount</span>
|
||||||
|
|||||||
@@ -71,10 +71,9 @@ $(function(){
|
|||||||
});
|
});
|
||||||
|
|
||||||
$("#drop").dropzone({
|
$("#drop").dropzone({
|
||||||
maxFilesize: @{gitbucket.core.util.FileUtil.MaxFileSize / 1024 / 1024},
|
|
||||||
url: '@context.path/upload/release/@repository.owner/@repository.name/@helpers.encodeRefName(tag.name)',
|
url: '@context.path/upload/release/@repository.owner/@repository.name/@helpers.encodeRefName(tag.name)',
|
||||||
//timeout defaults to 30 secs
|
maxFilesize: @{context.settings.upload.largeMaxFileSize / 1024 / 1024},
|
||||||
timeout: @{gitbucket.core.util.FileUtil.UploadTimeout},
|
timeout: @{context.settings.upload.largeTimeout},
|
||||||
previewTemplate: "<div class=\"dz-preview\">\n <div class=\"dz-progress\"><span class=\"dz-upload\" data-dz-uploadprogress>Uploading your files...</span></div>\n <div class=\"dz-error-message\"><span data-dz-errormessage></span></div>\n</div>",
|
previewTemplate: "<div class=\"dz-preview\">\n <div class=\"dz-progress\"><span class=\"dz-upload\" data-dz-uploadprogress>Uploading your files...</span></div>\n <div class=\"dz-error-message\"><span data-dz-errormessage></span></div>\n</div>",
|
||||||
success: function(file, id) {
|
success: function(file, id) {
|
||||||
var attach =
|
var attach =
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
@(repository: gitbucket.core.service.RepositoryService.RepositoryInfo,
|
@(repository: gitbucket.core.service.RepositoryService.RepositoryInfo,
|
||||||
releases: Seq[(gitbucket.core.util.JGitUtil.TagInfo, Option[(gitbucket.core.model.ReleaseTag, Seq[gitbucket.core.model.ReleaseAsset])])],
|
releases: Seq[(gitbucket.core.util.JGitUtil.TagInfo, Option[(gitbucket.core.model.ReleaseTag, Seq[gitbucket.core.model.ReleaseAsset])])],
|
||||||
hasWritePermission: Boolean)(implicit context: gitbucket.core.controller.Context)
|
hasWritePermission: Boolean,
|
||||||
|
page: Int, totalReleases: Int)(implicit context: gitbucket.core.controller.Context)
|
||||||
|
|
||||||
@import gitbucket.core.view.helpers
|
@import gitbucket.core.view.helpers
|
||||||
@gitbucket.core.html.main("Releases" + s" - ${repository.owner}/${repository.name}", Some(repository)){
|
@gitbucket.core.html.main("Releases" + s" - ${repository.owner}/${repository.name}", Some(repository)){
|
||||||
@gitbucket.core.html.menu("releases", repository){
|
@gitbucket.core.html.menu("releases", repository){
|
||||||
@@ -61,5 +63,9 @@
|
|||||||
}
|
}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
<div class="pull-right">
|
||||||
|
@gitbucket.core.helper.html.paginator(page, totalReleases, gitbucket.core.service.ReleaseService.ReleaseLimit, 10)
|
||||||
|
</div>
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -138,7 +138,6 @@ $(function(){
|
|||||||
$('#btn-code').click(function(){
|
$('#btn-code').click(function(){
|
||||||
$('#editor').show();
|
$('#editor').show();
|
||||||
$('#preview').hide();
|
$('#preview').hide();
|
||||||
$('#btn-code').appendClass('active');
|
|
||||||
$('#btn-preview').removeClass('active');
|
$('#btn-preview').removeClass('active');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -146,7 +145,6 @@ $(function(){
|
|||||||
$('#editor').hide();
|
$('#editor').hide();
|
||||||
$('#preview').show();
|
$('#preview').show();
|
||||||
$('#btn-code').removeClass('active');
|
$('#btn-code').removeClass('active');
|
||||||
$('#btn-preview').addClass('active');
|
|
||||||
|
|
||||||
@if(fileName.map(helpers.isRenderable _).getOrElse(false)) {
|
@if(fileName.map(helpers.isRenderable _).getOrElse(false)) {
|
||||||
// update preview
|
// update preview
|
||||||
|
|||||||
@@ -51,11 +51,12 @@
|
|||||||
$(function(){
|
$(function(){
|
||||||
$('#upload-area').dropzone({
|
$('#upload-area').dropzone({
|
||||||
url: '@context.path/upload/tmp',
|
url: '@context.path/upload/tmp',
|
||||||
maxFilesize: @{FileUtil.MaxFileSize / 1024 / 1024},
|
maxFilesize: @{context.settings.upload.maxFileSize / 1024 / 1024},
|
||||||
|
timeout: @{context.settings.upload.timeout},
|
||||||
clickable: true,
|
clickable: true,
|
||||||
previewTemplate: "<div class=\"dz-preview\">\n <div class=\"dz-progress\"><span class=\"dz-upload\" data-dz-uploadprogress>Uploading your files...</span></div>\n <div class=\"dz-error-message\"><span data-dz-errormessage></span></div>\n</div>",
|
previewTemplate: "<div class=\"dz-preview\">\n <div class=\"dz-progress\"><span class=\"dz-upload\" data-dz-uploadprogress>Uploading your files...</span></div>\n <div class=\"dz-error-message\"><span data-dz-errormessage></span></div>\n</div>",
|
||||||
success: function(file, id) {
|
success: function(file, id) {
|
||||||
file.previewElement.remove();
|
$(file.previewElement).remove();
|
||||||
$('#upload-files').append($('<li class="upload-file">')
|
$('#upload-files').append($('<li class="upload-file">')
|
||||||
.append($('<span>').data('id', id).text(file.name))
|
.append($('<span>').data('id', id).text(file.name))
|
||||||
.append($('<a class="delete" href="javascript:void(0);" style="margin-left: 4px;">(delete)</a>')));
|
.append($('<a class="delete" href="javascript:void(0);" style="margin-left: 4px;">(delete)</a>')));
|
||||||
|
|||||||
@@ -7,32 +7,8 @@
|
|||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading strong">Danger Zone</div>
|
<div class="panel-heading strong">Danger Zone</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<form id="transfer-form" method="post" action="@helpers.url(repository)/settings/transfer" validate="true" autocomplete="off">
|
|
||||||
<fieldset class="form-group">
|
|
||||||
<label class="strong">Transfer Ownership</label>
|
|
||||||
<div>
|
|
||||||
Transfer this repo to another user or to group.
|
|
||||||
<div class="pull-right">
|
|
||||||
@gitbucket.core.helper.html.account("newOwner", 200, true, true)
|
|
||||||
<input type="submit" class="btn btn-danger" value="Transfer"/>
|
|
||||||
<div>
|
|
||||||
<span id="error-newOwner" class="error"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
</form>
|
|
||||||
<form id="delete-form" method="post" action="@helpers.url(repository)/settings/delete">
|
|
||||||
<fieldset class="border-top form-group">
|
|
||||||
<label class="strong">Delete repository</label>
|
|
||||||
<div>
|
|
||||||
Once you delete a repository, there is no going back.
|
|
||||||
<input type="submit" class="btn btn-danger pull-right" value="Delete this repository"/>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
</form>
|
|
||||||
<form id="gc-form" method="post" action="@helpers.url(repository)/settings/gc">
|
<form id="gc-form" method="post" action="@helpers.url(repository)/settings/gc">
|
||||||
<fieldset class="border-top form-group">
|
<fieldset class="form-group">
|
||||||
<label class="strong">Garbage collection</label>
|
<label class="strong">Garbage collection</label>
|
||||||
<div>
|
<div>
|
||||||
Run garbage collection for this git repository immediately.
|
Run garbage collection for this git repository immediately.
|
||||||
@@ -40,6 +16,51 @@
|
|||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
|
@if(context.settings.repositoryOperation.rename || context.loginAccount.get.isAdmin){
|
||||||
|
<form id="rename-form" method="post" action="@helpers.url(repository)/settings/rename" validate="true" autocomplete="off">
|
||||||
|
<fieldset class="border-top form-group">
|
||||||
|
<label class="strong">Rename repository</label>
|
||||||
|
<div>
|
||||||
|
Rename this repository. The current URL will be unavailable.
|
||||||
|
<div class="pull-right">
|
||||||
|
<input type="text" name="repositoryName" id="repositoryName" class="form-control" style="width: 200px; display: inline; vertical-align: middle;" value="@repository.name"/>
|
||||||
|
<input type="submit" class="btn btn-danger" value="Rename"/>
|
||||||
|
<div>
|
||||||
|
<span id="error-repositoryName" class="error"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
}
|
||||||
|
@if(context.settings.repositoryOperation.transfer || context.loginAccount.get.isAdmin){
|
||||||
|
<form id="transfer-form" method="post" action="@helpers.url(repository)/settings/transfer" validate="true" autocomplete="off">
|
||||||
|
<fieldset class="border-top form-group">
|
||||||
|
<label class="strong">Transfer Ownership</label>
|
||||||
|
<div>
|
||||||
|
Transfer this repo to another user or to group.
|
||||||
|
<div class="pull-right">
|
||||||
|
@gitbucket.core.helper.html.account("newOwner", 200, true, true)
|
||||||
|
<input type="submit" class="btn btn-danger" value="Transfer"/>
|
||||||
|
<div>
|
||||||
|
<span id="error-newOwner" class="error"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
}
|
||||||
|
@if(context.settings.repositoryOperation.delete || context.loginAccount.get.isAdmin){
|
||||||
|
<form id="delete-form" method="post" action="@helpers.url(repository)/settings/delete">
|
||||||
|
<fieldset class="border-top form-group">
|
||||||
|
<label class="strong">Delete repository</label>
|
||||||
|
<div>
|
||||||
|
Once you delete a repository, there is no going back.
|
||||||
|
<input type="submit" class="btn btn-danger pull-right" value="Delete this repository"/>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@@ -50,6 +71,13 @@ $(function(){
|
|||||||
$('#delete-form').submit(function(){
|
$('#delete-form').submit(function(){
|
||||||
return confirm('Once you delete a repository, there is no going back.\nAre you sure?');
|
return confirm('Once you delete a repository, there is no going back.\nAre you sure?');
|
||||||
});
|
});
|
||||||
|
$('#rename-form').submit(function(){
|
||||||
|
if($('#rename-form').data('validated') === true){
|
||||||
|
return confirm('Rename this repository as you entered. The current URL will be unavailable.\nAre you sure?');
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
$('#transfer-form').submit(function(){
|
$('#transfer-form').submit(function(){
|
||||||
if($('#transfer-form').data('validated') === true){
|
if($('#transfer-form').data('validated') === true){
|
||||||
return confirm('Transfer to the repository owner you entered.\nAre you sure?');
|
return confirm('Transfer to the repository owner you entered.\nAre you sure?');
|
||||||
|
|||||||
@@ -9,11 +9,6 @@
|
|||||||
<div class="panel-heading strong">Settings</div>
|
<div class="panel-heading strong">Settings</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<fieldset class="form-group">
|
<fieldset class="form-group">
|
||||||
<label for="repositoryName" class="strong">Repository Name:</label>
|
|
||||||
<input type="text" name="repositoryName" id="repositoryName" class="form-control" value="@repository.name"/>
|
|
||||||
<span id="error-repositoryName" class="error"></span>
|
|
||||||
</fieldset>
|
|
||||||
<fieldset class="border-top form-group">
|
|
||||||
<label for="description" class="strong">Description:</label>
|
<label for="description" class="strong">Description:</label>
|
||||||
<input type="text" name="description" id="description" class="form-control" value="@repository.repository.description"/>
|
<input type="text" name="description" id="description" class="form-control" value="@repository.repository.description"/>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|||||||
@@ -5,11 +5,13 @@
|
|||||||
<div class="content-wrapper main-center">
|
<div class="content-wrapper main-center">
|
||||||
<div class="content body">
|
<div class="content body">
|
||||||
<div class="signin-form">
|
<div class="signin-form">
|
||||||
@context.settings.information.map { information =>
|
@if(context.settings.allowAnonymousAccess){
|
||||||
<div class="alert alert-info" style="background-color: white; color: #555; border-color: #4183c4; font-size: small; line-height: 120%;">
|
@context.settings.information.map { information =>
|
||||||
<button type="button" class="close" data-dismiss="alert">×</button>
|
<div class="alert alert-info" style="background-color: white; color: #555; border-color: #4183c4; font-size: small; line-height: 120%;">
|
||||||
@Html(information)
|
<button type="button" class="close" data-dismiss="alert">×</button>
|
||||||
</div>
|
@Html(information)
|
||||||
|
</div>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@gitbucket.core.helper.html.error(error)
|
@gitbucket.core.helper.html.error(error)
|
||||||
@gitbucket.core.html.signinform(context.settings, userName, password)
|
@gitbucket.core.html.signinform(context.settings, userName, password)
|
||||||
|
|||||||
@@ -48,7 +48,8 @@ $(function(){
|
|||||||
try {
|
try {
|
||||||
$('#content1').dropzone({
|
$('#content1').dropzone({
|
||||||
url: '@context.path/upload/wiki/@repository.owner/@repository.name',
|
url: '@context.path/upload/wiki/@repository.owner/@repository.name',
|
||||||
maxFilesize: @{FileUtil.MaxFileSize / 1024 / 1024},
|
maxFilesize: @{context.settings.upload.maxFileSize / 1024 / 1024},
|
||||||
|
timeout: @{context.settings.upload.timeout},
|
||||||
clickable: false,
|
clickable: false,
|
||||||
previewTemplate: "<div class=\"dz-preview\">\n <div class=\"dz-progress\"><span class=\"dz-upload\" data-dz-uploadprogress>Uploading your files...</span></div>\n <div class=\"dz-error-message\"><span data-dz-errormessage></span></div>\n</div>",
|
previewTemplate: "<div class=\"dz-preview\">\n <div class=\"dz-progress\"><span class=\"dz-upload\" data-dz-uploadprogress>Uploading your files...</span></div>\n <div class=\"dz-error-message\"><span data-dz-errormessage></span></div>\n</div>",
|
||||||
success: function(file, id) {
|
success: function(file, id) {
|
||||||
@@ -59,7 +60,8 @@ $(function(){
|
|||||||
});
|
});
|
||||||
$('.clickable').dropzone({
|
$('.clickable').dropzone({
|
||||||
url: '@context.path/upload/wiki/@repository.owner/@repository.name',
|
url: '@context.path/upload/wiki/@repository.owner/@repository.name',
|
||||||
maxFilesize: @{FileUtil.MaxFileSize / 1024 / 1024},
|
maxFilesize: @{context.settings.upload.maxFileSize / 1024 / 1024},
|
||||||
|
timeout: @{context.settings.upload.timeout},
|
||||||
previewTemplate: "<div class=\"dz-preview\">\n <div class=\"dz-progress\"><span class=\"dz-upload\" data-dz-uploadprogress>Uploading your files...</span></div>\n <div class=\"dz-error-message\"><span data-dz-errormessage></span></div>\n</div>",
|
previewTemplate: "<div class=\"dz-preview\">\n <div class=\"dz-progress\"><span class=\"dz-upload\" data-dz-uploadprogress>Uploading your files...</span></div>\n <div class=\"dz-error-message\"><span data-dz-errormessage></span></div>\n</div>",
|
||||||
success: function(file, id) {
|
success: function(file, id) {
|
||||||
var attachFile = (file.type.match(/image\/.*/) ? '\n![' + file.name.split('.')[0] : '\n[' + file.name) + '](' + file.name + ')';
|
var attachFile = (file.type.match(/image\/.*/) ? '\n![' + file.name.split('.')[0] : '\n[' + file.name) + '](' + file.name + ')';
|
||||||
|
|||||||
@@ -80,16 +80,6 @@
|
|||||||
</cookie-config>
|
</cookie-config>
|
||||||
</session-config>
|
</session-config>
|
||||||
|
|
||||||
<!-- ===================================================================== -->
|
|
||||||
<!-- Optional configurations -->
|
|
||||||
<!-- ===================================================================== -->
|
|
||||||
<!--
|
|
||||||
<context-param>
|
|
||||||
<param-name>gitbucket.home</param-name>
|
|
||||||
<param-value>PATH_TO_DATADIR</param-value>
|
|
||||||
</context-param>
|
|
||||||
-->
|
|
||||||
|
|
||||||
<mime-mapping>
|
<mime-mapping>
|
||||||
<extension>svg</extension>
|
<extension>svg</extension>
|
||||||
<mime-type>image/svg+xml</mime-type>
|
<mime-type>image/svg+xml</mime-type>
|
||||||
|
|||||||
@@ -76,12 +76,12 @@ function displayErrors(data, elem){
|
|||||||
* @param ignoreSpace {Number} 0: include, 1: ignore
|
* @param ignoreSpace {Number} 0: include, 1: ignore
|
||||||
*/
|
*/
|
||||||
function diffUsingJS(oldTextId, newTextId, outputId, viewType, ignoreSpace) {
|
function diffUsingJS(oldTextId, newTextId, outputId, viewType, ignoreSpace) {
|
||||||
var old = $('#'+oldTextId), head = $('#' + newTextId);
|
var old = $('#' + oldTextId), head = $('#' + newTextId);
|
||||||
var render = new JsDiffRender({
|
var render = new JsDiffRender({
|
||||||
oldText: old.val(),
|
oldText : old.data('val'),
|
||||||
oldTextName: old.attr('data-file-name'),
|
oldTextName: old.data('file-name'),
|
||||||
newText: head.val(),
|
newText : head.data('val'),
|
||||||
newTextName: head.attr('data-file-name'),
|
newTextName: head.data('file-name'),
|
||||||
ignoreSpace: ignoreSpace,
|
ignoreSpace: ignoreSpace,
|
||||||
contextSize: 4
|
contextSize: 4
|
||||||
});
|
});
|
||||||
|
|||||||
598
src/main/webapp/assets/vendors/dropzone/dropzone.js
vendored
598
src/main/webapp/assets/vendors/dropzone/dropzone.js
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
src/main/webapp/assets/vendors/jquery/jquery-3.5.1.min.js
vendored
Normal file
2
src/main/webapp/assets/vendors/jquery/jquery-3.5.1.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -110,7 +110,7 @@ table.diff ins{
|
|||||||
background-color: #a6f3a6;
|
background-color: #a6f3a6;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
table.diff del{
|
table.diff .body.delete del{
|
||||||
background-color: #f8cbcb;
|
background-color: #f8cbcb;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -520,6 +520,7 @@ object ApiSpecModels {
|
|||||||
|"user":$jsonUser,
|
|"user":$jsonUser,
|
||||||
|"labels":[$jsonLabel],
|
|"labels":[$jsonLabel],
|
||||||
|"assignee":$jsonUser,
|
|"assignee":$jsonUser,
|
||||||
|
|"draft":true,
|
||||||
|"id":0,
|
|"id":0,
|
||||||
|"html_url":"http://gitbucket.exmple.com/octocat/Hello-World/pull/1347",
|
|"html_url":"http://gitbucket.exmple.com/octocat/Hello-World/pull/1347",
|
||||||
|"url":"http://gitbucket.exmple.com/api/v3/repos/octocat/Hello-World/pulls/1347",
|
|"url":"http://gitbucket.exmple.com/api/v3/repos/octocat/Hello-World/pulls/1347",
|
||||||
@@ -706,7 +707,7 @@ object ApiSpecModels {
|
|||||||
|"size":100,
|
|"size":100,
|
||||||
|"label":"release.zip",
|
|"label":"release.zip",
|
||||||
|"file_id":"${assetFileName}",
|
|"file_id":"${assetFileName}",
|
||||||
|"browser_download_url":"http://gitbucket.exmple.com/api/v3/repos/octocat/Hello-World/releases/tag1/assets/${assetFileName}"
|
|"browser_download_url":"http://gitbucket.exmple.com/octocat/Hello-World/releases/tag1/assets/${assetFileName}"
|
||||||
|}""".stripMargin
|
|}""".stripMargin
|
||||||
|
|
||||||
val jsonRelease =
|
val jsonRelease =
|
||||||
|
|||||||
@@ -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 WebHookPullRequestService with WebHookPullRequestReviewCommentService with RequestCache {}
|
||||||
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,7 +18,8 @@ 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)
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import java.sql.DriverManager
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
import gitbucket.core.controller.Context
|
import gitbucket.core.controller.Context
|
||||||
import gitbucket.core.service.SystemSettingsService.{Ssh, SystemSettings}
|
import gitbucket.core.service.SystemSettingsService.{RepositoryOperation, Ssh, SystemSettings}
|
||||||
import javax.servlet.http.{HttpServletRequest, HttpSession}
|
import javax.servlet.http.{HttpServletRequest, HttpSession}
|
||||||
import org.scalatestplus.mockito.MockitoSugar
|
import org.scalatestplus.mockito.MockitoSugar
|
||||||
import org.mockito.Mockito._
|
import org.mockito.Mockito._
|
||||||
@@ -36,9 +36,17 @@ trait ServiceSpecBase extends MockitoSugar {
|
|||||||
allowAccountRegistration = false,
|
allowAccountRegistration = false,
|
||||||
allowAnonymousAccess = true,
|
allowAnonymousAccess = true,
|
||||||
isCreateRepoOptionPublic = true,
|
isCreateRepoOptionPublic = true,
|
||||||
|
repositoryOperation = RepositoryOperation(
|
||||||
|
create = true,
|
||||||
|
delete = true,
|
||||||
|
rename = true,
|
||||||
|
transfer = true,
|
||||||
|
fork = true
|
||||||
|
),
|
||||||
gravatar = false,
|
gravatar = false,
|
||||||
notification = false,
|
notification = false,
|
||||||
activityLogLimit = None,
|
activityLogLimit = None,
|
||||||
|
limitVisibleRepositories = false,
|
||||||
ssh = Ssh(
|
ssh = Ssh(
|
||||||
enabled = false,
|
enabled = false,
|
||||||
sshHost = None,
|
sshHost = None,
|
||||||
@@ -51,10 +59,17 @@ trait ServiceSpecBase extends MockitoSugar {
|
|||||||
oidcAuthentication = false,
|
oidcAuthentication = false,
|
||||||
oidc = None,
|
oidc = None,
|
||||||
skinName = "skin-blue",
|
skinName = "skin-blue",
|
||||||
|
userDefinedCss = None,
|
||||||
showMailAddress = false,
|
showMailAddress = false,
|
||||||
webHook = SystemSettingsService.WebHook(
|
webHook = SystemSettingsService.WebHook(
|
||||||
blockPrivateAddress = false,
|
blockPrivateAddress = false,
|
||||||
whitelist = Nil
|
whitelist = Nil
|
||||||
|
),
|
||||||
|
upload = SystemSettingsService.Upload(
|
||||||
|
maxFileSize = 3 * 1024 * 1024,
|
||||||
|
timeout = 30 * 10000,
|
||||||
|
largeMaxFileSize = 3 * 1024 * 1024,
|
||||||
|
largeTimeout = 30 * 10000
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -84,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 WebHookPullRequestReviewCommentService with RequestCache {
|
||||||
override def fetchAsPullRequest(
|
override def fetchAsPullRequest(
|
||||||
userName: String,
|
userName: String,
|
||||||
repositoryName: String,
|
repositoryName: String,
|
||||||
@@ -107,7 +122,8 @@ trait ServiceSpecBase extends MockitoSugar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def generateNewIssue(userName: String, repositoryName: String, loginUser: String = "root")(
|
def generateNewIssue(userName: String, repositoryName: String, loginUser: String = "root")(
|
||||||
implicit s: Session
|
implicit
|
||||||
|
s: Session
|
||||||
): Int = {
|
): Int = {
|
||||||
dummyService.insertIssue(
|
dummyService.insertIssue(
|
||||||
owner = userName,
|
owner = userName,
|
||||||
@@ -123,7 +139,8 @@ trait ServiceSpecBase extends MockitoSugar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def generateNewPullRequest(base: String, request: String, loginUser: String)(
|
def generateNewPullRequest(base: String, request: String, loginUser: String)(
|
||||||
implicit s: Session
|
implicit
|
||||||
|
s: Session
|
||||||
): (Issue, PullRequest) = {
|
): (Issue, PullRequest) = {
|
||||||
implicit val context = Context(createSystemSettings(), None, this.request)
|
implicit val context = Context(createSystemSettings(), None, this.request)
|
||||||
val Array(baseUserName, baseRepositoryName, baesBranch) = base.split("/")
|
val Array(baseUserName, baseRepositoryName, baesBranch) = base.split("/")
|
||||||
|
|||||||
@@ -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 MilestonesService with PrioritiesService with WebHookPullRequestReviewCommentService with RequestCache
|
||||||
|
|
||||||
test("WebHookPullRequestService.getPullRequestsByRequestForWebhook") {
|
test("WebHookPullRequestService.getPullRequestsByRequestForWebhook") {
|
||||||
withTestDB { implicit session =>
|
withTestDB { implicit session =>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import javax.servlet.http.{HttpServletRequest, HttpSession}
|
|||||||
import gitbucket.core.controller.Context
|
import gitbucket.core.controller.Context
|
||||||
import gitbucket.core.model.Account
|
import gitbucket.core.model.Account
|
||||||
import gitbucket.core.service.RequestCache
|
import gitbucket.core.service.RequestCache
|
||||||
import gitbucket.core.service.SystemSettingsService.{Ssh, SystemSettings, WebHook}
|
import gitbucket.core.service.SystemSettingsService.{RepositoryOperation, Ssh, SystemSettings, Upload, WebHook}
|
||||||
import org.mockito.Mockito._
|
import org.mockito.Mockito._
|
||||||
import org.scalatest.FunSpec
|
import org.scalatest.FunSpec
|
||||||
import org.scalatestplus.mockito.MockitoSugar
|
import org.scalatestplus.mockito.MockitoSugar
|
||||||
@@ -122,9 +122,17 @@ class AvatarImageProviderSpec extends FunSpec with MockitoSugar {
|
|||||||
allowAccountRegistration = false,
|
allowAccountRegistration = false,
|
||||||
allowAnonymousAccess = true,
|
allowAnonymousAccess = true,
|
||||||
isCreateRepoOptionPublic = true,
|
isCreateRepoOptionPublic = true,
|
||||||
|
repositoryOperation = RepositoryOperation(
|
||||||
|
create = true,
|
||||||
|
delete = true,
|
||||||
|
rename = true,
|
||||||
|
transfer = true,
|
||||||
|
fork = true
|
||||||
|
),
|
||||||
gravatar = useGravatar,
|
gravatar = useGravatar,
|
||||||
notification = false,
|
notification = false,
|
||||||
activityLogLimit = None,
|
activityLogLimit = None,
|
||||||
|
limitVisibleRepositories = false,
|
||||||
ssh = Ssh(
|
ssh = Ssh(
|
||||||
enabled = false,
|
enabled = false,
|
||||||
sshHost = None,
|
sshHost = None,
|
||||||
@@ -137,10 +145,17 @@ class AvatarImageProviderSpec extends FunSpec with MockitoSugar {
|
|||||||
oidcAuthentication = false,
|
oidcAuthentication = false,
|
||||||
oidc = None,
|
oidc = None,
|
||||||
skinName = "skin-blue",
|
skinName = "skin-blue",
|
||||||
|
userDefinedCss = None,
|
||||||
showMailAddress = false,
|
showMailAddress = false,
|
||||||
webHook = WebHook(
|
webHook = WebHook(
|
||||||
blockPrivateAddress = false,
|
blockPrivateAddress = false,
|
||||||
whitelist = Nil
|
whitelist = Nil
|
||||||
|
),
|
||||||
|
upload = Upload(
|
||||||
|
maxFileSize = 3 * 1024 * 1024,
|
||||||
|
timeout = 30 * 10000,
|
||||||
|
largeMaxFileSize = 3 * 1024 * 1024,
|
||||||
|
largeTimeout = 30 * 10000
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -150,11 +165,13 @@ class AvatarImageProviderSpec extends FunSpec with MockitoSugar {
|
|||||||
class AvatarImageProviderImpl(account: Option[Account]) extends AvatarImageProvider with RequestCache {
|
class AvatarImageProviderImpl(account: Option[Account]) extends AvatarImageProvider with RequestCache {
|
||||||
|
|
||||||
def toHtml(userName: String, size: Int, mailAddress: String = "", tooltip: Boolean = false)(
|
def toHtml(userName: String, size: Int, mailAddress: String = "", tooltip: Boolean = false)(
|
||||||
implicit context: Context
|
implicit
|
||||||
|
context: Context
|
||||||
): Html = getAvatarImageHtml(userName, size, mailAddress, tooltip)
|
): Html = getAvatarImageHtml(userName, size, mailAddress, tooltip)
|
||||||
|
|
||||||
override def getAccountByMailAddress(mailAddress: String)(implicit context: Context): Option[Account] = account
|
override def getAccountByMailAddressFromCache(mailAddress: String)(implicit context: Context): Option[Account] =
|
||||||
override def getAccountByUserName(userName: String)(implicit context: Context): Option[Account] = account
|
account
|
||||||
|
override def getAccountByUserNameFromCache(userName: String)(implicit context: Context): Option[Account] = account
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user