mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-11-08 14:35:52 +01:00
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:
@@ -8,6 +8,6 @@ Common scripts are in this directory.
|
||||
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`
|
||||
|
||||
1
src/main/resources/update/2_8.sql
Normal file
1
src/main/resources/update/2_8.sql
Normal file
@@ -0,0 +1 @@
|
||||
ALTER TABLE COMMIT_COMMENT ALTER COLUMN FILE_NAME NVARCHAR(260);
|
||||
@@ -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)
|
||||
})
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 =>
|
||||
|
||||
contentType = "application/octet-stream"
|
||||
response.setHeader("Content-Disposition", s"attachment; filename=${filename}")
|
||||
response.setBufferSize(1024 * 1024);
|
||||
|
||||
git.archive
|
||||
.setFormat(suffix.tail)
|
||||
.setTree(revCommit.getTree)
|
||||
.setOutputStream(out)
|
||||
.setOutputStream(response.getOutputStream)
|
||||
.call()
|
||||
}
|
||||
contentType = "application/octet-stream"
|
||||
response.setHeader("Content-Disposition", s"attachment; filename=${file.getName}")
|
||||
file
|
||||
|
||||
Unit
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 =>
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 @@
|
||||
</fieldset>
|
||||
<fieldset class="margin">
|
||||
<label class="radio">
|
||||
<input type="radio" name="isPrivate" value="false" checked>
|
||||
<input type="radio" name="isPrivate" value="false" @if(isCreateRepoOptionPublic){checked}>
|
||||
<span class="strong"><img src="@assets/common/images/repo_public.png"/> </i> Public</span><br>
|
||||
<div>
|
||||
<span>All users and guests can read this repository.</span>
|
||||
@@ -38,7 +39,7 @@
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<label class="radio">
|
||||
<input type="radio" name="isPrivate" value="true">
|
||||
<input type="radio" name="isPrivate" value="true" @if(!isCreateRepoOptionPublic){checked}>
|
||||
<span class="strong"><img src="@assets/common/images/repo_private.png"/> </i> Private</span><br>
|
||||
<div>
|
||||
<span>Only collaborators can read this repository.</span>
|
||||
|
||||
@@ -53,6 +53,18 @@
|
||||
<span class="strong">Deny</span> - Only administrators can create accounts.
|
||||
</label>
|
||||
</fieldset>
|
||||
<hr>
|
||||
<label class="strong">Default option to create a new repository</label>
|
||||
<fieldset>
|
||||
<label class="radio">
|
||||
<input type="radio" name="isCreateRepoOptionPublic" value="true"@if(settings.isCreateRepoOptionPublic){ checked}>
|
||||
<span class="strong">Public</span> - All users and guests can read that repository.
|
||||
</label>
|
||||
<label class="radio">
|
||||
<input type="radio" name="isCreateRepoOptionPublic" value="false"@if(!settings.isCreateRepoOptionPublic){ checked}>
|
||||
<span class="strong">Private</span> - Only collaborators can read that repository.
|
||||
</label>
|
||||
</fieldset>
|
||||
<!--====================================================================-->
|
||||
<!-- Anonymous access -->
|
||||
<!--====================================================================-->
|
||||
@@ -184,6 +196,13 @@
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="ldap.ssl"@if(settings.ldap.flatMap(_.ssl).getOrElse(false)){ checked}/> Enable SSL
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="ldapBindDN">Keystore</label>
|
||||
<div class="controls">
|
||||
|
||||
@@ -8,13 +8,6 @@
|
||||
@import context._
|
||||
@import view.helpers._
|
||||
@import service.IssuesService.IssueInfo
|
||||
@*
|
||||
<ul class="nav nav-pills-group pull-left fill-width">
|
||||
<li class="@if(filter == "created_by"){active} first"><a href="@path/dashboard/issues/created_by@condition.toURL">Created</a></li>
|
||||
<li class="@if(filter == "assigned"){active}"><a href="@path/dashboard/issues/assigned@condition.toURL">Assigned</a></li>
|
||||
<li class="@if(filter == "mentioned"){active} last"><a href="@path/dashboard/issues/mentioned@condition.toURL">Mentioned</a></li>
|
||||
</ul>
|
||||
*@
|
||||
<table class="table table-bordered table-hover table-issues">
|
||||
<tr>
|
||||
<th style="background-color: #eee;">
|
||||
@@ -29,7 +22,7 @@
|
||||
} else {
|
||||
<img src="@assets/common/images/issue-@(if(issue.closed) "closed" else "open").png"/>
|
||||
}
|
||||
<a href="@path/@issue.userName/@issue.repositoryName">@issue.repositoryName</a> ・
|
||||
<a href="@path/@issue.userName/@issue.repositoryName">@issue.userName/@issue.repositoryName</a> ・
|
||||
@if(issue.isPullRequest){
|
||||
<a href="@path/@issue.userName/@issue.repositoryName/pull/@issue.issueId" class="issue-title">@issue.title</a>
|
||||
} else {
|
||||
|
||||
@@ -11,6 +11,6 @@
|
||||
@dashboard.html.tab("pulls")
|
||||
<div class="container">
|
||||
@issuesnavi(filter, "pulls", condition)
|
||||
@pullslist(issues, page, openCount, closedCount, condition, filter, groups)
|
||||
@issueslist(issues, page, openCount, closedCount, condition, filter, groups)
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
@(issues: List[service.IssuesService.IssueInfo],
|
||||
page: Int,
|
||||
openCount: Int,
|
||||
closedCount: Int,
|
||||
condition: service.IssuesService.IssueSearchCondition,
|
||||
filter: String,
|
||||
groups: List[String])(implicit context: app.Context)
|
||||
@import context._
|
||||
@import view.helpers._
|
||||
@import service.IssuesService.IssueInfo
|
||||
@*
|
||||
<ul class="nav nav-pills-group pull-left fill-width">
|
||||
<li class="@if(filter == "created_by"){active} first"><a href="@path/dashboard/pulls/created_by@condition.toURL">Created</a></li>
|
||||
<li class="@if(filter == "assigned"){active}"><a href="@path/dashboard/pulls/assigned@condition.toURL">Assigned</a></li>
|
||||
<li class="@if(filter == "mentioned"){active} last"><a href="@path/dashboard/pulls/mentioned@condition.toURL">Mentioned</a></li>
|
||||
<li class="pull-right">
|
||||
<div class="input-prepend" style="margin-bottom: 0px;">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn dropdown-toggle" data-toggle="dropdown" style="height: 34px;">
|
||||
Filter
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="?q=is:open">Open issues and pull requests</a></li>
|
||||
<li><a href="?q=is:open+is:issue+author:@urlEncode(loginAccount.get.userName)">Your issues</a></li>
|
||||
<li><a href="?q=is:open+is:pr+author:@urlEncode(loginAccount.get.userName)">Your pull requests</a></li>
|
||||
<li><a href="?q=is:open+assignee:@urlEncode(loginAccount.get.userName)">Everything assigned to you</a></li>
|
||||
<li><a href="?q=is:open+mentions:@urlEncode(loginAccount.get.userName)">Everything mentioning you</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<input type="text" id="search-filter-box" class="input-xlarge" name="q" style="height: 24px;" value="is:@{if(active == "issues") "issue" else "pr"} @condition.toFilterString"/>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
*@
|
||||
<table class="table table-bordered table-hover table-issues">
|
||||
<tr>
|
||||
<th style="background-color: #eee;">
|
||||
@dashboard.html.header(openCount, closedCount, condition, groups)
|
||||
</th>
|
||||
</tr>
|
||||
@issues.map { case IssueInfo(issue, labels, milestone, commentCount) =>
|
||||
<tr>
|
||||
<td>
|
||||
<img src="@assets/common/images/pullreq-@(if(issue.closed) "closed" else "open").png"/>
|
||||
<a href="@path/@issue.userName/@issue.repositoryName/pull/@issue.issueId" class="issue-title">@issue.title</a>
|
||||
<span class="pull-right muted">#@issue.issueId</span>
|
||||
<div style="margin-left: 20px;">
|
||||
@issue.content.map { content =>
|
||||
@cut(content, 90)
|
||||
}.getOrElse {
|
||||
<span class="muted">No description available</span>
|
||||
}
|
||||
</div>
|
||||
<div class="small muted" style="margin-left: 20px;">
|
||||
@avatarLink(issue.openedUserName, 20) by @user(issue.openedUserName, styleClass="username") @datetime(issue.registeredDate)
|
||||
@if(commentCount > 0){
|
||||
<i class="icon-comment"></i><a href="@path/@issue.userName/@issue.repositoryName/issues/@issue.issueId" class="issue-comment-count">@commentCount @plural(commentCount, "comment")</a>
|
||||
}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</table>
|
||||
<div class="pull-right">
|
||||
@helper.html.paginator(page, (if(condition.state == "open") openCount else closedCount), service.PullRequestService.PullRequestLimit, 10, condition.toURL)
|
||||
</div>
|
||||
@@ -120,6 +120,13 @@ $(function(){
|
||||
renderDiffs(0);
|
||||
});
|
||||
|
||||
$('.toggle-notes').change(function() {
|
||||
if (!$(this).prop('checked')) {
|
||||
$(this).closest('table').find('.not-diff.inline-comment-form').remove();
|
||||
}
|
||||
$(this).closest('table').find('.not-diff').toggle();
|
||||
});
|
||||
|
||||
function renderDiffs(viewType){
|
||||
window.viewType = viewType;
|
||||
@diffs.zipWithIndex.map { case (diff, i) =>
|
||||
@@ -146,33 +153,31 @@ $(function(){
|
||||
if (typeof $('#show-notes')[0] !== 'undefined' && !$('#show-notes')[0].checked) {
|
||||
$(this).hide();
|
||||
}
|
||||
if (typeof oldline !== 'undefined') {
|
||||
var tmp;
|
||||
var diff;
|
||||
if (typeof oldline !== 'undefined') {
|
||||
if (typeof newline !== 'undefined') {
|
||||
tmp = getInlineContainer();
|
||||
} else {
|
||||
tmp = getInlineContainer('old');
|
||||
}
|
||||
tmp.children('td:first').html($(this).clone().show());
|
||||
$('table[filename="' + filename + '"]').find('table.diff').find('.oldline').filter(function() {
|
||||
return new RegExp('^' + oldline + '[\\+]*$').test($(this).text());
|
||||
}).parent().nextAll(':not(.not-diff):first').before(tmp);
|
||||
diff = $('table[filename="' + filename + '"]');
|
||||
diff.find('table.diff').find('.oldline[line-number=' + oldline + ']')
|
||||
.parent().nextAll(':not(.not-diff):first').before(tmp);
|
||||
} else {
|
||||
var tmp = getInlineContainer('new');
|
||||
tmp = getInlineContainer('new');
|
||||
tmp.children('td:last').html($(this).clone().show());
|
||||
$('table[filename="' + filename + '"]').find('table.diff').find('.newline').filter(function() {
|
||||
return new RegExp('^' + newline + '\\+$').test($(this).text());
|
||||
}).parent().nextAll(':not(.not-diff):first').before(tmp);
|
||||
diff = $('table[filename="' + filename + '"]');
|
||||
diff.find('table.diff').find('.newline[line-number=' + newline + ']')
|
||||
.parent().nextAll(':not(.not-diff):first').before(tmp);
|
||||
}
|
||||
});
|
||||
$('.toggle-notes').change(function() {
|
||||
if (!$(this).prop('checked')) {
|
||||
$(this).closest('table').find('.not-diff.inline-comment-form').remove();
|
||||
if (!diff.find('.toggle-notes').prop('checked')) {
|
||||
tmp.hide();
|
||||
}
|
||||
$(this).closest('table').find('.not-diff').toggle();
|
||||
});
|
||||
@if(hasWritePermission) {
|
||||
$('table.diff th').hover(
|
||||
$('table.diff td').hover(
|
||||
function() {
|
||||
$(this).find('b').css('display', 'inline-block');
|
||||
},
|
||||
@@ -180,12 +185,12 @@ $(function(){
|
||||
$(this).find('b').css('display', 'none');
|
||||
}
|
||||
);
|
||||
$('table.diff td').hover(
|
||||
$('table.diff th').hover(
|
||||
function() {
|
||||
$(this).prev('th').find('b').css('display', 'inline-block');
|
||||
$(this).nextAll().find('b').first().css('display', 'inline-block');
|
||||
},
|
||||
function() {
|
||||
$(this).prev('th').find('b').css('display', 'none');
|
||||
$(this).nextAll().find('b').first().css('display', 'none');
|
||||
}
|
||||
);
|
||||
$('.add-comment').click(function() {
|
||||
@@ -198,12 +203,14 @@ $(function(){
|
||||
if (!$tr.nextAll(':not(.not-diff):first').prev().hasClass('inline-comment-form')) {
|
||||
var commitId = $this.closest('.table-bordered').attr('commitId'),
|
||||
fileName = $this.closest('.table-bordered').attr('fileName'),
|
||||
oldLineNumber, newLineNumber = $this.closest('.newline').clone().children().remove().end().text(),
|
||||
url = '@url(repository)/commit/' + commitId + '/comment/_form?fileName=' + fileName @if(issueId.isDefined){+ '&issueId=@issueId.get'};
|
||||
oldLineNumber, newLineNumber,
|
||||
url = '@url(repository)/commit/' + commitId + '/comment/_form?fileName=' + fileName@issueId.map { id => + '&issueId=@id' };
|
||||
if (viewType == 0) {
|
||||
oldLineNumber = $this.closest('.oldline').clone().children().remove().end().text();
|
||||
oldLineNumber = $this.parent().prev('.oldline').attr('line-number');
|
||||
newLineNumber = $this.parent().prev('.newline').attr('line-number');
|
||||
} else {
|
||||
oldLineNumber = $this.closest('tr').find('.oldline').text();
|
||||
oldLineNumber = $this.parent().prevAll('.oldline').attr('line-number');
|
||||
newLineNumber = $this.parent().prevAll('.newline').attr('line-number');
|
||||
}
|
||||
if (!isNaN(oldLineNumber) && oldLineNumber) {
|
||||
url += ('&oldLineNumber=' + oldLineNumber)
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="brand" href="@path/">
|
||||
<img src="@assets/common/images/gitbucket.png"/>GitBucket
|
||||
<img src="@assets/common/images/gitbucket.png" style="width: 24px; height: 24px;"/>GitBucket
|
||||
@defining(servlet.AutoUpdate.getCurrentVersion){ version =>
|
||||
<span class="header-version">@version.majorVersion.@version.minorVersion</span>
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
<p>
|
||||
<span class="strong">Step 3:</span> Merge the changes and update the server
|
||||
</p>
|
||||
@defining(s"git checkout master\ngit merge ${pullreq.requestUserName}-${pullreq.requestBranch}\ngit push origin ${pullreq.branch}"){ command =>
|
||||
@defining(s"git checkout ${pullreq.branch}\ngit merge ${pullreq.requestUserName}-${pullreq.requestBranch}\ngit push origin ${pullreq.branch}"){ command =>
|
||||
@helper.html.copy("merge-command-copy-3", command){
|
||||
<pre style="width: 500px; float: left;">@command</pre>
|
||||
}
|
||||
|
||||
@@ -29,10 +29,10 @@
|
||||
<input type="submit" class="btn btn-success" formaction="@url(repository)/commit/@commitId/comment/new" value="Comment on this commit"/>
|
||||
</div>
|
||||
}
|
||||
@if(issueId.isDefined){<input type="hidden" name="issueId" value="@issueId.get">}
|
||||
@if(fileName.isDefined){<input type="hidden" name="fileName" value="@fileName.get">}
|
||||
@if(oldLineNumber.isDefined){<input type="hidden" name="oldLineNumber" value="@oldLineNumber.get">}
|
||||
@if(newLineNumber.isDefined){<input type="hidden" name="newLineNumber" value="@newLineNumber.get">}
|
||||
@issueId.map { issueId => <input type="hidden" name="issueId" value="@issueId"> }
|
||||
@fileName.map { fileName => <input type="hidden" name="fileName" value="@fileName"> }
|
||||
@oldLineNumber.map { oldLineNumber => <input type="hidden" name="oldLineNumber" value="@oldLineNumber"> }
|
||||
@newLineNumber.map { newLineNumber => <input type="hidden" name="newLineNumber" value="@newLineNumber"> }
|
||||
</form>
|
||||
<script>
|
||||
$('.btn-inline-comment').click(function(e) {
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
@import context._
|
||||
@main("Sign in"){
|
||||
<div class="signin-form">
|
||||
@settings.information.map { information =>
|
||||
<div class="alert alert-info" style="background-color: white; color: #555; border-color: #4183c4; font-size: small; line-height: 120%;">
|
||||
<button type="button" class="close" data-dismiss="alert">×</button>
|
||||
@Html(information)
|
||||
</div>
|
||||
}
|
||||
@signinform(settings)
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
</div>
|
||||
<div style="width: 650px;" class="pull-left">
|
||||
<div class="markdown-body">
|
||||
@markdown(page.content, repository, true, false)
|
||||
@markdown(page.content, repository, true, false, false, false, pages)
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -975,15 +975,16 @@ table.diff .add-comment {
|
||||
position: absolute;
|
||||
background: blue;
|
||||
top: 0;
|
||||
left: -7px;
|
||||
color: white;
|
||||
padding: 2px;
|
||||
padding: 2px 4px;
|
||||
border: solid 1px blue;
|
||||
border-radius: 3px;
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
table.diff .add-comment:hover {
|
||||
padding: 4px;
|
||||
padding: 4px 6px;
|
||||
top: -1px;
|
||||
}
|
||||
|
||||
@@ -1009,6 +1010,14 @@ table.diff tbody tr.not-diff:hover td{
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.diff .oldline:before, .diff .newline:before {
|
||||
content: attr(line-number);
|
||||
}
|
||||
|
||||
.diff .skipline:before {
|
||||
content: "..."
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/* Repository Settings */
|
||||
/****************************************************************************/
|
||||
@@ -1088,6 +1097,8 @@ div.markdown-body pre {
|
||||
div.markdown-body code {
|
||||
font-size: 12px;
|
||||
padding: 0 5px;
|
||||
background-color: rgba(0,0,0,0.04);
|
||||
rgb(51, 51, 51);
|
||||
}
|
||||
|
||||
div.markdown-body table {
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 484 B After Width: | Height: | Size: 6.8 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 675 B After Width: | Height: | Size: 7.6 KiB |
@@ -84,7 +84,7 @@ diffview = {
|
||||
b.appendChild(document.createTextNode("+"));
|
||||
b.style.display = "none";
|
||||
b.className = "add-comment";
|
||||
e.appendChild(b);
|
||||
e.insertBefore(b, e.firstChild);
|
||||
e.style.position = "relative";
|
||||
return e;
|
||||
}
|
||||
@@ -117,9 +117,12 @@ diffview = {
|
||||
* to the given row.
|
||||
*/
|
||||
function addCells (row, tidx, tend, textLines, change, thclass) {
|
||||
var tmp;
|
||||
if (tidx < tend) {
|
||||
row.appendChild(addButton(ctelt("th", thclass, (tidx + 1).toString())));
|
||||
row.appendChild(ctelt("td", change, textLines[tidx].replace(/\t/g, "\u00a0\u00a0\u00a0\u00a0")));
|
||||
tmp = ctelt("th", thclass, "");
|
||||
tmp.setAttribute("line-number", (tidx + 1).toString());
|
||||
row.appendChild(tmp);
|
||||
row.appendChild(addButton(ctelt("td", change, textLines[tidx].replace(/\t/g, "\u00a0\u00a0\u00a0\u00a0"))));
|
||||
return tidx + 1;
|
||||
} else {
|
||||
row.appendChild(document.createElement("th"));
|
||||
@@ -129,9 +132,13 @@ diffview = {
|
||||
}
|
||||
|
||||
function addCellsInline (row, tidx, tidx2, textLines, change) {
|
||||
row.appendChild(ctelt("th", "oldline", tidx == null ? "" : (tidx + 1).toString()));
|
||||
row.appendChild(addButton(ctelt("th", "newline", tidx2 == null ? "" : (tidx2 + 1).toString())));
|
||||
row.appendChild(ctelt("td", change, textLines[tidx != null ? tidx : tidx2].replace(/\t/g, "\u00a0\u00a0\u00a0\u00a0")));
|
||||
var tmp = ctelt("th", "oldline", "");
|
||||
tmp.setAttribute("line-number", tidx == null ? "" : (tidx + 1).toString());
|
||||
row.appendChild(tmp);
|
||||
tmp = ctelt("th", "newline", "");
|
||||
tmp.setAttribute("line-number", tidx2 == null ? "" : (tidx2 + 1).toString());
|
||||
row.appendChild(tmp);
|
||||
row.appendChild(addButton(ctelt("td", change, textLines[tidx != null ? tidx : tidx2].replace(/\t/g, "\u00a0\u00a0\u00a0\u00a0"))));
|
||||
}
|
||||
|
||||
for (var idx = 0; idx < opcodes.length; idx++) {
|
||||
@@ -154,9 +161,9 @@ diffview = {
|
||||
b += jump;
|
||||
n += jump;
|
||||
i += jump - 1;
|
||||
node.appendChild(telt("th", "..."));
|
||||
node.appendChild(ctelt("th", "skipline", ""));
|
||||
if (!inline) node.appendChild(ctelt("td", "skip", ""));
|
||||
node.appendChild(telt("th", "..."));
|
||||
node.appendChild(ctelt("th", "skipline", ""));
|
||||
node.appendChild(ctelt("td", "skip", ""));
|
||||
|
||||
// skip last lines if they're all equal
|
||||
|
||||
@@ -96,6 +96,7 @@ class AvatarImageProviderSpec extends Specification with Mockito {
|
||||
information = None,
|
||||
allowAccountRegistration = false,
|
||||
allowAnonymousAccess = true,
|
||||
isCreateRepoOptionPublic = true,
|
||||
gravatar = useGravatar,
|
||||
notification = false,
|
||||
ssh = false,
|
||||
|
||||
Reference in New Issue
Block a user