diff --git a/contrib/README.md b/contrib/README.md index 1121a22..716ef77 100644 --- a/contrib/README.md +++ b/contrib/README.md @@ -8,6 +8,6 @@ This version of scripts has so far only been tested on Ubuntu and Mac. Someone else will have to test on RedHat. To run: -1. Edit `gitbucket.conf` to suit. -2. Type: `install` + 1. Edit `gitbucket.conf` to suit. + 2. Type: `install` diff --git a/src/main/resources/update/2_8.sql b/src/main/resources/update/2_8.sql new file mode 100644 index 0000000..38c95d3 --- /dev/null +++ b/src/main/resources/update/2_8.sql @@ -0,0 +1 @@ +ALTER TABLE COMMIT_COMMENT ALTER COLUMN FILE_NAME NVARCHAR(260); diff --git a/src/main/scala/app/AccountController.scala b/src/main/scala/app/AccountController.scala index 4628a36..732e18d 100644 --- a/src/main/scala/app/AccountController.scala +++ b/src/main/scala/app/AccountController.scala @@ -291,7 +291,7 @@ * Show the new repository form. */ get("/new")(usersOnly { - account.html.newrepo(getGroupsByUserName(context.loginAccount.get.userName)) + account.html.newrepo(getGroupsByUserName(context.loginAccount.get.userName), context.settings.isCreateRepoOptionPublic) }) /** diff --git a/src/main/scala/app/RepositoryViewerController.scala b/src/main/scala/app/RepositoryViewerController.scala index 69e02ea..00f6755 100644 --- a/src/main/scala/app/RepositoryViewerController.scala +++ b/src/main/scala/app/RepositoryViewerController.scala @@ -248,10 +248,10 @@ val id = params("id") createCommitComment(repository.owner, repository.name, id, context.loginAccount.get.userName, form.content, form.fileName, form.oldLineNumber, form.newLineNumber, form.issueId.isDefined) - if (form.issueId.isDefined) - recordCommentPullRequestActivity(repository.owner, repository.name, context.loginAccount.get.userName, form.issueId.get, form.content) - else - recordCommentCommitActivity(repository.owner, repository.name, context.loginAccount.get.userName, id, form.content) + form.issueId match { + case Some(issueId) => recordCommentPullRequestActivity(repository.owner, repository.name, context.loginAccount.get.userName, issueId, form.content) + case None => recordCommentCommitActivity(repository.owner, repository.name, context.loginAccount.get.userName, id, form.content) + } redirect(s"/${repository.owner}/${repository.name}/commit/${id}") }) @@ -273,10 +273,10 @@ val id = params("id") val commentId = createCommitComment(repository.owner, repository.name, id, context.loginAccount.get.userName, form.content, form.fileName, form.oldLineNumber, form.newLineNumber, form.issueId.isDefined) - if (form.issueId.isDefined) - recordCommentPullRequestActivity(repository.owner, repository.name, context.loginAccount.get.userName, form.issueId.get, form.content) - else - recordCommentCommitActivity(repository.owner, repository.name, context.loginAccount.get.userName, id, form.content) + form.issueId match { + case Some(issueId) => recordCommentPullRequestActivity(repository.owner, repository.name, context.loginAccount.get.userName, issueId, form.content) + case None => recordCommentCommitActivity(repository.owner, repository.name, context.loginAccount.get.userName, id, form.content) + } helper.html.commitcomment(getCommitComment(repository.owner, repository.name, commentId.toString).get, hasWritePermission(repository.owner, repository.name, context.loginAccount), repository) }) @@ -532,7 +532,7 @@ } } - private def archiveRepository(name: String, suffix: String, repository: RepositoryService.RepositoryInfo): File = { + private def archiveRepository(name: String, suffix: String, repository: RepositoryService.RepositoryInfo): Unit = { val revision = name.stripSuffix(suffix) val workDir = getDownloadWorkDir(repository.owner, repository.name, session.getId) if(workDir.exists) { @@ -540,21 +540,23 @@ } workDir.mkdirs - val file = new File(workDir, repository.name + "-" + - (if(revision.length == 40) revision.substring(0, 10) else revision).replace('/', '_') + suffix) + val filename = repository.name + "-" + + (if(revision.length == 40) revision.substring(0, 10) else revision).replace('/', '_') + suffix using(Git.open(getRepositoryDir(repository.owner, repository.name))){ git => val revCommit = JGitUtil.getRevCommitFromId(git, git.getRepository.resolve(revision)) - using(new java.io.FileOutputStream(file)) { out => - git.archive - .setFormat(suffix.tail) - .setTree(revCommit.getTree) - .setOutputStream(out) - .call() - } + contentType = "application/octet-stream" - response.setHeader("Content-Disposition", s"attachment; filename=${file.getName}") - file + response.setHeader("Content-Disposition", s"attachment; filename=${filename}") + response.setBufferSize(1024 * 1024); + + git.archive + .setFormat(suffix.tail) + .setTree(revCommit.getTree) + .setOutputStream(response.getOutputStream) + .call() + + Unit } } diff --git a/src/main/scala/app/SystemSettingsController.scala b/src/main/scala/app/SystemSettingsController.scala index af1e2c9..e278433 100644 --- a/src/main/scala/app/SystemSettingsController.scala +++ b/src/main/scala/app/SystemSettingsController.scala @@ -17,6 +17,7 @@ "information" -> trim(label("Information", optional(text()))), "allowAccountRegistration" -> trim(label("Account registration", boolean())), "allowAnonymousAccess" -> trim(label("Anonymous access", boolean())), + "isCreateRepoOptionPublic" -> trim(label("Default option to create a new repository", boolean())), "gravatar" -> trim(label("Gravatar", boolean())), "notification" -> trim(label("Notification", boolean())), "ssh" -> trim(label("SSH access", boolean())), @@ -42,6 +43,7 @@ "fullNameAttribute" -> trim(label("Full name attribute", optional(text()))), "mailAttribute" -> trim(label("Mail address attribute", optional(text()))), "tls" -> trim(label("Enable TLS", optional(boolean()))), + "ssl" -> trim(label("Enable SSL", optional(boolean()))), "keystore" -> trim(label("Keystore", optional(text()))) )(Ldap.apply)) )(SystemSettings.apply).verifying { settings => diff --git a/src/main/scala/service/RepositoryService.scala b/src/main/scala/service/RepositoryService.scala index b74ccb4..6894125 100644 --- a/src/main/scala/service/RepositoryService.scala +++ b/src/main/scala/service/RepositoryService.scala @@ -189,7 +189,7 @@ new RepositoryInfo( JGitUtil.getRepositoryInfo(repository.userName, repository.repositoryName, baseUrl), repository, - issues.size, + issues.count(_ == false), issues.count(_ == true), getForkedCount( repository.originUserName.getOrElse(repository.userName), diff --git a/src/main/scala/service/SystemSettingsService.scala b/src/main/scala/service/SystemSettingsService.scala index d234b9c..156a23b 100644 --- a/src/main/scala/service/SystemSettingsService.scala +++ b/src/main/scala/service/SystemSettingsService.scala @@ -15,6 +15,7 @@ settings.information.foreach(x => props.setProperty(Information, x)) props.setProperty(AllowAccountRegistration, settings.allowAccountRegistration.toString) props.setProperty(AllowAnonymousAccess, settings.allowAnonymousAccess.toString) + props.setProperty(IsCreateRepoOptionPublic, settings.isCreateRepoOptionPublic.toString) props.setProperty(Gravatar, settings.gravatar.toString) props.setProperty(Notification, settings.notification.toString) props.setProperty(Ssh, settings.ssh.toString) @@ -43,6 +44,7 @@ ldap.fullNameAttribute.foreach(x => props.setProperty(LdapFullNameAttribute, x)) ldap.mailAttribute.foreach(x => props.setProperty(LdapMailAddressAttribute, x)) ldap.tls.foreach(x => props.setProperty(LdapTls, x.toString)) + ldap.ssl.foreach(x => props.setProperty(LdapSsl, x.toString)) ldap.keystore.foreach(x => props.setProperty(LdapKeystore, x)) } } @@ -65,6 +67,7 @@ getOptionValue[String](props, Information, None), getValue(props, AllowAccountRegistration, false), getValue(props, AllowAnonymousAccess, true), + getValue(props, IsCreateRepoOptionPublic, true), getValue(props, Gravatar, true), getValue(props, Notification, false), getValue(props, Ssh, false), @@ -94,6 +97,7 @@ getOptionValue(props, LdapFullNameAttribute, None), getOptionValue(props, LdapMailAddressAttribute, None), getOptionValue[Boolean](props, LdapTls, None), + getOptionValue[Boolean](props, LdapSsl, None), getOptionValue(props, LdapKeystore, None))) } else { None @@ -112,6 +116,7 @@ information: Option[String], allowAccountRegistration: Boolean, allowAnonymousAccess: Boolean, + isCreateRepoOptionPublic: Boolean, gravatar: Boolean, notification: Boolean, ssh: Boolean, @@ -137,6 +142,7 @@ fullNameAttribute: Option[String], mailAttribute: Option[String], tls: Option[Boolean], + ssl: Option[Boolean], keystore: Option[String]) case class Smtp( @@ -156,6 +162,7 @@ private val Information = "information" private val AllowAccountRegistration = "allow_account_registration" private val AllowAnonymousAccess = "allow_anonymous_access" + private val IsCreateRepoOptionPublic = "is_create_repository_option_public" private val Gravatar = "gravatar" private val Notification = "notification" private val Ssh = "ssh" @@ -178,6 +185,7 @@ private val LdapFullNameAttribute = "ldap.fullname_attribute" private val LdapMailAddressAttribute = "ldap.mail_attribute" private val LdapTls = "ldap.tls" + private val LdapSsl = "ldap.ssl" private val LdapKeystore = "ldap.keystore" private def getValue[A: ClassTag](props: java.util.Properties, key: String, default: A): A = diff --git a/src/main/scala/servlet/AutoUpdateListener.scala b/src/main/scala/servlet/AutoUpdateListener.scala index 3fbcce0..6020a0f 100644 --- a/src/main/scala/servlet/AutoUpdateListener.scala +++ b/src/main/scala/servlet/AutoUpdateListener.scala @@ -52,6 +52,7 @@ * The history of versions. A head of this sequence is the current BitBucket version. */ val versions = Seq( + new Version(2, 8), new Version(2, 7) { override def update(conn: Connection): Unit = { super.update(conn) diff --git a/src/main/scala/util/LDAPUtil.scala b/src/main/scala/util/LDAPUtil.scala index ae578bd..c8d741f 100644 --- a/src/main/scala/util/LDAPUtil.scala +++ b/src/main/scala/util/LDAPUtil.scala @@ -48,6 +48,7 @@ dn = ldapSettings.bindDN.getOrElse(""), password = ldapSettings.bindPassword.getOrElse(""), tls = ldapSettings.tls.getOrElse(false), + ssl = ldapSettings.ssl.getOrElse(false), keystore = ldapSettings.keystore.getOrElse(""), error = "System LDAP authentication failed." ){ conn => @@ -65,6 +66,7 @@ dn = userDN, password = password, tls = ldapSettings.tls.getOrElse(false), + ssl = ldapSettings.ssl.getOrElse(false), keystore = ldapSettings.keystore.getOrElse(""), error = "User LDAP Authentication Failed." ){ conn => @@ -96,7 +98,7 @@ }).replaceAll("[^a-zA-Z0-9\\-_.]", "").replaceAll("^[_\\-]", "") } - private def bind[A](host: String, port: Int, dn: String, password: String, tls: Boolean, keystore: String, error: String) + private def bind[A](host: String, port: Int, dn: String, password: String, tls: Boolean, ssl: Boolean, keystore: String, error: String) (f: LDAPConnection => Either[String, A]): Either[String, A] = { if (tls) { // Dynamically set Sun as the security provider @@ -109,7 +111,13 @@ } } - val conn: LDAPConnection = new LDAPConnection(new LDAPJSSEStartTLSFactory()) + val conn: LDAPConnection = + if(ssl) { + new LDAPConnection(new LDAPJSSESecureSocketFactory()) + }else { + new LDAPConnection(new LDAPJSSEStartTLSFactory()) + } + try { // Connect to the server conn.connect(host, port) diff --git a/src/main/scala/view/Markdown.scala b/src/main/scala/view/Markdown.scala index 71a7ef8..87719b4 100644 --- a/src/main/scala/view/Markdown.scala +++ b/src/main/scala/view/Markdown.scala @@ -18,9 +18,14 @@ /** * Converts Markdown of Wiki pages to HTML. */ - def toHtml(markdown: String, repository: service.RepositoryService.RepositoryInfo, - enableWikiLink: Boolean, enableRefsLink: Boolean, - enableTaskList: Boolean = false, hasWritePermission: Boolean = false)(implicit context: app.Context): String = { + def toHtml(markdown: String, + repository: service.RepositoryService.RepositoryInfo, + enableWikiLink: Boolean, + enableRefsLink: Boolean, + enableTaskList: Boolean = false, + hasWritePermission: Boolean = false, + pages: List[String] = Nil)(implicit context: app.Context): String = { + // escape issue id val s = if(enableRefsLink){ markdown.replaceAll("(?<=(\\W|^))#(\\d+)(?=(\\W|$))", "issue:$2") @@ -35,12 +40,16 @@ Extensions.AUTOLINKS | Extensions.WIKILINKS | Extensions.FENCED_CODE_BLOCKS | Extensions.TABLES | Extensions.HARDWRAPS | Extensions.SUPPRESS_ALL_HTML ).parseMarkdown(source.toCharArray) - new GitBucketHtmlSerializer(markdown, repository, enableWikiLink, enableRefsLink, enableTaskList, hasWritePermission).toHtml(rootNode) + new GitBucketHtmlSerializer(markdown, repository, enableWikiLink, enableRefsLink, enableTaskList, hasWritePermission, pages).toHtml(rootNode) } } -class GitBucketLinkRender(context: app.Context, repository: service.RepositoryService.RepositoryInfo, - enableWikiLink: Boolean) extends LinkRenderer with WikiService { +class GitBucketLinkRender( + context: app.Context, + repository: service.RepositoryService.RepositoryInfo, + enableWikiLink: Boolean, + pages: List[String]) extends LinkRenderer with WikiService { + override def render(node: WikiLinkNode): Rendering = { if(enableWikiLink){ try { @@ -54,7 +63,7 @@ val url = repository.httpUrl.replaceFirst("/git/", "/").stripSuffix(".git") + "/wiki/" + StringUtil.urlEncode(page) - if(getWikiPage(repository.owner, repository.name, page).isDefined){ + if(pages.contains(page)){ new Rendering(url, label) } else { new Rendering(url, label).withAttribute("class", "absent") @@ -91,9 +100,10 @@ enableWikiLink: Boolean, enableRefsLink: Boolean, enableTaskList: Boolean, - hasWritePermission: Boolean + hasWritePermission: Boolean, + pages: List[String] )(implicit val context: app.Context) extends ToHtmlSerializer( - new GitBucketLinkRender(context, repository, enableWikiLink), + new GitBucketLinkRender(context, repository, enableWikiLink, pages), Map[String, VerbatimSerializer](VerbatimSerializer.DEFAULT -> new GitBucketVerbatimSerializer).asJava ) with LinkConverter with RequestCache { diff --git a/src/main/scala/view/helpers.scala b/src/main/scala/view/helpers.scala index c84f7c9..caea648 100644 --- a/src/main/scala/view/helpers.scala +++ b/src/main/scala/view/helpers.scala @@ -86,9 +86,14 @@ /** * Converts Markdown of Wiki pages to HTML. */ - def markdown(value: String, repository: service.RepositoryService.RepositoryInfo, - enableWikiLink: Boolean, enableRefsLink: Boolean, enableTaskList: Boolean = false, hasWritePermission: Boolean = false)(implicit context: app.Context): Html = - Html(Markdown.toHtml(value, repository, enableWikiLink, enableRefsLink, enableTaskList, hasWritePermission)) + def markdown(value: String, + repository: service.RepositoryService.RepositoryInfo, + enableWikiLink: Boolean, + enableRefsLink: Boolean, + enableTaskList: Boolean = false, + hasWritePermission: Boolean = false, + pages: List[String] = Nil)(implicit context: app.Context): Html = + Html(Markdown.toHtml(value, repository, enableWikiLink, enableRefsLink, enableTaskList, hasWritePermission, pages)) def renderMarkup(filePath: List[String], fileContent: String, branch: String, repository: service.RepositoryService.RepositoryInfo, diff --git a/src/main/twirl/account/newrepo.scala.html b/src/main/twirl/account/newrepo.scala.html index b5f6c6a..da9b068 100644 --- a/src/main/twirl/account/newrepo.scala.html +++ b/src/main/twirl/account/newrepo.scala.html @@ -1,4 +1,5 @@ -@(groupNames: List[String])(implicit context: app.Context) +@(groupNames: List[String], +isCreateRepoOptionPublic: Boolean)(implicit context: app.Context) @import context._ @import view.helpers._ @html.main("Create a New Repository"){ @@ -29,7 +30,7 @@