Merge remote-tracking branch 'upstream/master' into anon-access

Conflicts:
	src/main/scala/app/SystemSettingsController.scala
	src/main/scala/service/SystemSettingsService.scala
	src/test/scala/view/AvatarImageProviderSpec.scala
This commit is contained in:
Mark LaCroix
2015-01-21 15:49:42 -05:00
27 changed files with 170 additions and 155 deletions

View File

@@ -291,7 +291,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
* 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)
})
/**

View File

@@ -248,10 +248,10 @@ trait RepositoryViewerControllerBase extends ControllerBase {
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 @@ trait RepositoryViewerControllerBase extends ControllerBase {
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 @@ trait RepositoryViewerControllerBase extends ControllerBase {
}
}
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 @@ trait RepositoryViewerControllerBase extends ControllerBase {
}
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
}
}

View File

@@ -17,6 +17,7 @@ trait SystemSettingsControllerBase extends ControllerBase {
"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 @@ trait SystemSettingsControllerBase extends ControllerBase {
"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 =>

View File

@@ -189,7 +189,7 @@ trait RepositoryService { self: AccountService =>
new RepositoryInfo(
JGitUtil.getRepositoryInfo(repository.userName, repository.repositoryName, baseUrl),
repository,
issues.size,
issues.count(_ == false),
issues.count(_ == true),
getForkedCount(
repository.originUserName.getOrElse(repository.userName),

View File

@@ -15,6 +15,7 @@ trait SystemSettingsService {
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 @@ trait SystemSettingsService {
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 @@ trait SystemSettingsService {
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 @@ trait SystemSettingsService {
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 @@ object SystemSettingsService {
information: Option[String],
allowAccountRegistration: Boolean,
allowAnonymousAccess: Boolean,
isCreateRepoOptionPublic: Boolean,
gravatar: Boolean,
notification: Boolean,
ssh: Boolean,
@@ -137,6 +142,7 @@ object SystemSettingsService {
fullNameAttribute: Option[String],
mailAttribute: Option[String],
tls: Option[Boolean],
ssl: Option[Boolean],
keystore: Option[String])
case class Smtp(
@@ -156,6 +162,7 @@ object SystemSettingsService {
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 @@ object SystemSettingsService {
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 =

View File

@@ -52,6 +52,7 @@ object AutoUpdate {
* 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)

View File

@@ -48,6 +48,7 @@ object LDAPUtil {
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 @@ object LDAPUtil {
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 @@ object LDAPUtil {
}).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 @@ object LDAPUtil {
}
}
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)

View File

@@ -18,9 +18,14 @@ object Markdown {
/**
* 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 @@ object Markdown {
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 @@ class GitBucketLinkRender(context: app.Context, repository: service.RepositorySe
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 @@ class GitBucketHtmlSerializer(
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 {

View File

@@ -86,9 +86,14 @@ object helpers extends AvatarImageProvider with LinkConverter with RequestCache
/**
* 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,