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