diff --git a/src/main/resources/update/gitbucket-core_4.6.xml b/src/main/resources/update/gitbucket-core_4.6.xml new file mode 100644 index 0000000..6bf4acf --- /dev/null +++ b/src/main/resources/update/gitbucket-core_4.6.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/main/scala/gitbucket/core/GitBucketCoreModule.scala b/src/main/scala/gitbucket/core/GitBucketCoreModule.scala index a404be3..6830d2d 100644 --- a/src/main/scala/gitbucket/core/GitBucketCoreModule.scala +++ b/src/main/scala/gitbucket/core/GitBucketCoreModule.scala @@ -15,5 +15,8 @@ new Version("4.2.1"), new Version("4.3.0"), new Version("4.4.0"), - new Version("4.5.0") + new Version("4.5.0"), + new Version("4.6.0", + new LiquibaseMigration("update/gitbucket-core_4.6.xml") + ) ) diff --git a/src/main/scala/gitbucket/core/controller/AccountController.scala b/src/main/scala/gitbucket/core/controller/AccountController.scala index c0f0212..0308a4a 100644 --- a/src/main/scala/gitbucket/core/controller/AccountController.scala +++ b/src/main/scala/gitbucket/core/controller/AccountController.scala @@ -14,6 +14,7 @@ import io.github.gitbucket.scalatra.forms._ import org.apache.commons.io.FileUtils import org.scalatra.i18n.Messages +import org.scalatra.BadRequest class AccountController extends AccountControllerBase @@ -355,76 +356,80 @@ }) get("/:owner/:repository/fork")(readableUsersOnly { repository => - val loginAccount = context.loginAccount.get - val loginUserName = loginAccount.userName - val groups = getGroupsByUserName(loginUserName) - groups match { - case _: List[String] => - val managerPermissions = groups.map { group => - val members = getGroupMembers(group) - context.loginAccount.exists(x => members.exists { member => member.userName == x.userName && member.isManager }) - } - helper.html.forkrepository( - repository, - (groups zip managerPermissions).toMap - ) - case _ => redirect(s"/${loginUserName}") - } + if(repository.repository.options.allowFork){ + val loginAccount = context.loginAccount.get + val loginUserName = loginAccount.userName + val groups = getGroupsByUserName(loginUserName) + groups match { + case _: List[String] => + val managerPermissions = groups.map { group => + val members = getGroupMembers(group) + context.loginAccount.exists(x => members.exists { member => member.userName == x.userName && member.isManager }) + } + helper.html.forkrepository( + repository, + (groups zip managerPermissions).toMap + ) + case _ => redirect(s"/${loginUserName}") + } + } else BadRequest }) post("/:owner/:repository/fork", accountForm)(readableUsersOnly { (form, repository) => - val loginAccount = context.loginAccount.get - val loginUserName = loginAccount.userName - val accountName = form.accountName + if(repository.repository.options.allowFork){ + val loginAccount = context.loginAccount.get + val loginUserName = loginAccount.userName + val accountName = form.accountName - LockUtil.lock(s"${accountName}/${repository.name}"){ - if(getRepository(accountName, repository.name).isDefined || - (accountName != loginUserName && !getGroupsByUserName(loginUserName).contains(accountName))){ - // redirect to the repository if repository already exists - redirect(s"/${accountName}/${repository.name}") - } else { - // Insert to the database at first - val originUserName = repository.repository.originUserName.getOrElse(repository.owner) - val originRepositoryName = repository.repository.originRepositoryName.getOrElse(repository.name) + LockUtil.lock(s"${accountName}/${repository.name}"){ + if(getRepository(accountName, repository.name).isDefined || + (accountName != loginUserName && !getGroupsByUserName(loginUserName).contains(accountName))){ + // redirect to the repository if repository already exists + redirect(s"/${accountName}/${repository.name}") + } else { + // Insert to the database at first + val originUserName = repository.repository.originUserName.getOrElse(repository.owner) + val originRepositoryName = repository.repository.originRepositoryName.getOrElse(repository.name) - insertRepository( - repositoryName = repository.name, - userName = accountName, - description = repository.repository.description, - isPrivate = repository.repository.isPrivate, - originRepositoryName = Some(originRepositoryName), - originUserName = Some(originUserName), - parentRepositoryName = Some(repository.name), - parentUserName = Some(repository.owner) - ) + insertRepository( + repositoryName = repository.name, + userName = accountName, + description = repository.repository.description, + isPrivate = repository.repository.isPrivate, + originRepositoryName = Some(originRepositoryName), + originUserName = Some(originUserName), + parentRepositoryName = Some(repository.name), + parentUserName = Some(repository.owner) + ) - // Add collaborators for group repository - val ownerAccount = getAccountByUserName(accountName).get - if(ownerAccount.isGroupAccount){ - getGroupMembers(accountName).foreach { member => - addCollaborator(accountName, repository.name, member.userName) + // Add collaborators for group repository + val ownerAccount = getAccountByUserName(accountName).get + if(ownerAccount.isGroupAccount){ + getGroupMembers(accountName).foreach { member => + addCollaborator(accountName, repository.name, member.userName) + } } + + // Insert default labels + insertDefaultLabels(accountName, repository.name) + + // clone repository actually + JGitUtil.cloneRepository( + getRepositoryDir(repository.owner, repository.name), + getRepositoryDir(accountName, repository.name)) + + // Create Wiki repository + JGitUtil.cloneRepository( + getWikiRepositoryDir(repository.owner, repository.name), + getWikiRepositoryDir(accountName, repository.name)) + + // Record activity + recordForkActivity(repository.owner, repository.name, loginUserName, accountName) + // redirect to the repository + redirect(s"/${accountName}/${repository.name}") } - - // Insert default labels - insertDefaultLabels(accountName, repository.name) - - // clone repository actually - JGitUtil.cloneRepository( - getRepositoryDir(repository.owner, repository.name), - getRepositoryDir(accountName, repository.name)) - - // Create Wiki repository - JGitUtil.cloneRepository( - getWikiRepositoryDir(repository.owner, repository.name), - getWikiRepositoryDir(accountName, repository.name)) - - // Record activity - recordForkActivity(repository.owner, repository.name, loginUserName, accountName) - // redirect to the repository - redirect(s"/${accountName}/${repository.name}") } - } + } else BadRequest }) private def existsAccount: Constraint = new Constraint(){ diff --git a/src/main/scala/gitbucket/core/controller/RepositorySettingsController.scala b/src/main/scala/gitbucket/core/controller/RepositorySettingsController.scala index b60ae5d..6d7c981 100644 --- a/src/main/scala/gitbucket/core/controller/RepositorySettingsController.scala +++ b/src/main/scala/gitbucket/core/controller/RepositorySettingsController.scala @@ -35,7 +35,8 @@ externalIssuesUrl: Option[String], enableWiki: Boolean, allowWikiEditing: Boolean, - externalWikiUrl: Option[String] + externalWikiUrl: Option[String], + allowFork: Boolean ) val optionsForm = mapping( @@ -46,7 +47,8 @@ "externalIssuesUrl" -> trim(label("External Issues URL", optional(text(maxlength(200))))), "enableWiki" -> trim(label("Enable Wiki" , boolean())), "allowWikiEditing" -> trim(label("Allow Wiki Editing" , boolean())), - "externalWikiUrl" -> trim(label("External Wiki URL" , optional(text(maxlength(200))))) + "externalWikiUrl" -> trim(label("External Wiki URL" , optional(text(maxlength(200))))), + "allowFork" -> trim(label("Allow Forking" , boolean())) )(OptionsForm.apply) // for default branch @@ -111,7 +113,8 @@ form.externalIssuesUrl, form.enableWiki, form.allowWikiEditing, - form.externalWikiUrl + form.externalWikiUrl, + form.allowFork ) // Change repository name if(repository.name != form.repositoryName){ diff --git a/src/main/scala/gitbucket/core/controller/RepositoryViewerController.scala b/src/main/scala/gitbucket/core/controller/RepositoryViewerController.scala index cee8f4f..4307fbb 100644 --- a/src/main/scala/gitbucket/core/controller/RepositoryViewerController.scala +++ b/src/main/scala/gitbucket/core/controller/RepositoryViewerController.scala @@ -494,18 +494,20 @@ }) get("/:owner/:repository/network/members")(referrersOnly { repository => - html.forked( - getRepository( - repository.repository.originUserName.getOrElse(repository.owner), - repository.repository.originRepositoryName.getOrElse(repository.name)), - getForkedRepositories( - repository.repository.originUserName.getOrElse(repository.owner), - repository.repository.originRepositoryName.getOrElse(repository.name)), - context.loginAccount match { - case None => List() - case account: Option[Account] => getGroupsByUserName(account.get.userName) - }, // groups of current user - repository) + if(repository.repository.options.allowFork) { + html.forked( + getRepository( + repository.repository.originUserName.getOrElse(repository.owner), + repository.repository.originRepositoryName.getOrElse(repository.name)), + getForkedRepositories( + repository.repository.originUserName.getOrElse(repository.owner), + repository.repository.originRepositoryName.getOrElse(repository.name)), + context.loginAccount match { + case None => List() + case account: Option[Account] => getGroupsByUserName(account.get.userName) + }, // groups of current user + repository) + } else BadRequest() }) /** diff --git a/src/main/scala/gitbucket/core/controller/WikiController.scala b/src/main/scala/gitbucket/core/controller/WikiController.scala index ad98cee..847c421 100644 --- a/src/main/scala/gitbucket/core/controller/WikiController.scala +++ b/src/main/scala/gitbucket/core/controller/WikiController.scala @@ -241,7 +241,7 @@ private def targetWikiPage = getWikiPage(params("owner"), params("repository"), params("pageName")) private def isEditable(repository: RepositoryInfo)(implicit context: Context): Boolean = - repository.repository.allowWikiEditing || ( + repository.repository.options.allowWikiEditing || ( hasWritePermission(repository.owner, repository.name, context.loginAccount) ) diff --git a/src/main/scala/gitbucket/core/model/Repository.scala b/src/main/scala/gitbucket/core/model/Repository.scala index ebdfb3a..c5c61bb 100644 --- a/src/main/scala/gitbucket/core/model/Repository.scala +++ b/src/main/scala/gitbucket/core/model/Repository.scala @@ -7,24 +7,62 @@ lazy val Repositories = TableQuery[Repositories] class Repositories(tag: Tag) extends Table[Repository](tag, "REPOSITORY") with BasicTemplate { - val isPrivate = column[Boolean]("PRIVATE") - val description = column[String]("DESCRIPTION") - val defaultBranch = column[String]("DEFAULT_BRANCH") - val registeredDate = column[java.util.Date]("REGISTERED_DATE") - val updatedDate = column[java.util.Date]("UPDATED_DATE") - val lastActivityDate = column[java.util.Date]("LAST_ACTIVITY_DATE") - val originUserName = column[String]("ORIGIN_USER_NAME") + val isPrivate = column[Boolean]("PRIVATE") + val description = column[String]("DESCRIPTION") + val defaultBranch = column[String]("DEFAULT_BRANCH") + val registeredDate = column[java.util.Date]("REGISTERED_DATE") + val updatedDate = column[java.util.Date]("UPDATED_DATE") + val lastActivityDate = column[java.util.Date]("LAST_ACTIVITY_DATE") + val originUserName = column[String]("ORIGIN_USER_NAME") val originRepositoryName = column[String]("ORIGIN_REPOSITORY_NAME") - val parentUserName = column[String]("PARENT_USER_NAME") + val parentUserName = column[String]("PARENT_USER_NAME") val parentRepositoryName = column[String]("PARENT_REPOSITORY_NAME") - val enableIssues = column[Boolean]("ENABLE_ISSUES") - val externalIssuesUrl = column[String]("EXTERNAL_ISSUES_URL") - val enableWiki = column[Boolean]("ENABLE_WIKI") - val allowWikiEditing = column[Boolean]("ALLOW_WIKI_EDITING") - val externalWikiUrl = column[String]("EXTERNAL_WIKI_URL") - def * = (userName, repositoryName, isPrivate, description.?, defaultBranch, - registeredDate, updatedDate, lastActivityDate, originUserName.?, originRepositoryName.?, parentUserName.?, parentRepositoryName.?, - enableIssues, externalIssuesUrl.?, enableWiki, allowWikiEditing, externalWikiUrl.?) <> (Repository.tupled, Repository.unapply) + val enableIssues = column[Boolean]("ENABLE_ISSUES") + val externalIssuesUrl = column[String]("EXTERNAL_ISSUES_URL") + val enableWiki = column[Boolean]("ENABLE_WIKI") + val allowWikiEditing = column[Boolean]("ALLOW_WIKI_EDITING") + val externalWikiUrl = column[String]("EXTERNAL_WIKI_URL") + val allowFork = column[Boolean]("ALLOW_FORK") + + def * = ( + (userName, repositoryName, isPrivate, description.?, defaultBranch, + registeredDate, updatedDate, lastActivityDate, originUserName.?, originRepositoryName.?, parentUserName.?, parentRepositoryName.?), + (enableIssues, externalIssuesUrl.?, enableWiki, allowWikiEditing, externalWikiUrl.?, allowFork) + ).shaped <> ( + { case (repository, options) => + Repository( + repository._1, + repository._2, + repository._3, + repository._4, + repository._5, + repository._6, + repository._7, + repository._8, + repository._9, + repository._10, + repository._11, + repository._12, + RepositoryOptions.tupled.apply(options) + ) + }, { (r: Repository) => + Some((( + r.userName, + r.repositoryName, + r.isPrivate, + r.description, + r.defaultBranch, + r.registeredDate, + r.updatedDate, + r.lastActivityDate, + r.originUserName, + r.originRepositoryName, + r.parentUserName, + r.parentRepositoryName + ),( + RepositoryOptions.unapply(r.options).get + ))) + }) def byPrimaryKey(owner: String, repository: String) = byRepository(owner, repository) } @@ -43,9 +81,14 @@ originRepositoryName: Option[String], parentUserName: Option[String], parentRepositoryName: Option[String], + options: RepositoryOptions +) + +case class RepositoryOptions( enableIssues: Boolean, externalIssuesUrl: Option[String], enableWiki: Boolean, allowWikiEditing: Boolean, - externalWikiUrl: Option[String] + externalWikiUrl: Option[String], + allowFork: Boolean ) diff --git a/src/main/scala/gitbucket/core/service/RepositoryService.scala b/src/main/scala/gitbucket/core/service/RepositoryService.scala index 959e735..3541c07 100644 --- a/src/main/scala/gitbucket/core/service/RepositoryService.scala +++ b/src/main/scala/gitbucket/core/service/RepositoryService.scala @@ -1,7 +1,7 @@ package gitbucket.core.service import gitbucket.core.controller.Context -import gitbucket.core.model.{Collaborator, Repository, Account} +import gitbucket.core.model.{Collaborator, Repository, RepositoryOptions, Account} import gitbucket.core.model.Profile._ import gitbucket.core.util.JGitUtil import profile.simple._ @@ -37,11 +37,14 @@ originRepositoryName = originRepositoryName, parentUserName = parentUserName, parentRepositoryName = parentRepositoryName, - enableIssues = true, - externalIssuesUrl = None, - enableWiki = true, - allowWikiEditing = true, - externalWikiUrl = None + options = RepositoryOptions( + enableIssues = true, + externalIssuesUrl = None, + enableWiki = true, + allowWikiEditing = true, + externalWikiUrl = None, + allowFork = true + ) ) IssueId insert (userName, repositoryName, 0) @@ -321,10 +324,11 @@ def saveRepositoryOptions(userName: String, repositoryName: String, description: Option[String], isPrivate: Boolean, enableIssues: Boolean, externalIssuesUrl: Option[String], - enableWiki: Boolean, allowWikiEditing: Boolean, externalWikiUrl: Option[String])(implicit s: Session): Unit = + enableWiki: Boolean, allowWikiEditing: Boolean, externalWikiUrl: Option[String], + allowFork: Boolean)(implicit s: Session): Unit = Repositories.filter(_.byRepository(userName, repositoryName)) - .map { r => (r.description.?, r.isPrivate, r.enableIssues, r.externalIssuesUrl.?, r.enableWiki, r.allowWikiEditing, r.externalWikiUrl.?, r.updatedDate) } - .update (description, isPrivate, enableIssues, externalIssuesUrl, enableWiki, allowWikiEditing, externalWikiUrl, currentDate) + .map { r => (r.description.?, r.isPrivate, r.enableIssues, r.externalIssuesUrl.?, r.enableWiki, r.allowWikiEditing, r.externalWikiUrl.?, r.allowFork, r.updatedDate) } + .update (description, isPrivate, enableIssues, externalIssuesUrl, enableWiki, allowWikiEditing, externalWikiUrl, allowFork, currentDate) def saveRepositoryDefaultBranch(userName: String, repositoryName: String, defaultBranch: String)(implicit s: Session): Unit = diff --git a/src/main/twirl/gitbucket/core/menu.scala.html b/src/main/twirl/gitbucket/core/menu.scala.html index 061fa02..cefd82c 100644 --- a/src/main/twirl/gitbucket/core/menu.scala.html +++ b/src/main/twirl/gitbucket/core/menu.scala.html @@ -27,24 +27,26 @@ @menuitem("/branches", "branches", "Branches", "git-branch", repository.branchList.length) @menuitem("/tags", "tags", "Tags", "tag", repository.tags.length) } - @if(repository.repository.enableIssues) { + @if(repository.repository.options.enableIssues) { @menuitem("/issues", "issues", "Issues", "issue-opened", repository.issueCount) @menuitem("/pulls", "pulls", "Pull Requests", "git-pull-request", repository.pullCount) @menuitem("/issues/labels", "labels", "Labels", "tag") @menuitem("/issues/milestones", "milestones", "Milestones", "milestone") } else { - @repository.repository.externalIssuesUrl.map { externalIssuesUrl => + @repository.repository.options.externalIssuesUrl.map { externalIssuesUrl => @menuitem(externalIssuesUrl, "issues", "Issues", "issue-opened") } } - @if(repository.repository.enableWiki) { + @if(repository.repository.options.enableWiki) { @menuitem("/wiki", "wiki", "Wiki", "book") } else { - @repository.repository.externalWikiUrl.map { externalWikiUrl => + @repository.repository.options.externalWikiUrl.map { externalWikiUrl => @menuitem(externalWikiUrl, "wiki", "Wiki", "book") } } - @menuitem("/network/members", "fork", "Forks", "repo-forked", repository.forkedCount) + @if(repository.repository.options.allowFork) { + @menuitem("/network/members", "fork", "Forks", "repo-forked", repository.forkedCount) + } @if(context.loginAccount.isDefined && (context.loginAccount.get.isAdmin || repository.managers.contains(context.loginAccount.get.userName))){ @menuitem("/settings", "settings", "Settings", "tools") } diff --git a/src/main/twirl/gitbucket/core/settings/options.scala.html b/src/main/twirl/gitbucket/core/settings/options.scala.html index 490da70..7b26310 100644 --- a/src/main/twirl/gitbucket/core/settings/options.scala.html +++ b/src/main/twirl/gitbucket/core/settings/options.scala.html @@ -46,7 +46,7 @@
-
+
- + +
+
+