Compare commits

...

12 Commits
1.0 ... 1.1

Author SHA1 Message Date
takezoe
bdd83a84fd (refs #20)Upgrade to JGit 3.0.0. 2013-07-05 11:10:44 +09:00
takezoe
ef38855b4b Selected label style is changed to bold. 2013-07-05 04:20:41 +09:00
takezoe
9bc8db5a15 Disable GET Ajax cache. 2013-07-05 02:35:23 +09:00
takezoe
c53f3843b8 (refs #19)Add unique checking for mail address. 2013-07-05 01:37:29 +09:00
takezoe
56f1f5d47f Remove all error messages before validation. 2013-07-04 22:53:50 +09:00
takezoe
d74ef599d3 Fix redirect path. 2013-07-04 22:45:03 +09:00
takezoe
398c77e277 Fix form action of the account register form. 2013-07-04 22:43:16 +09:00
takezoe
99e562e9e6 Fix redirect path after milestone updating. 2013-07-04 22:42:31 +09:00
takezoe
47bdb8da23 (refs #18)Add schema update to fix constraints for COLLABORATOR. 2013-07-04 18:46:01 +09:00
takezoe
869930165c (refs #17)Fix wiki link. 2013-07-04 17:26:32 +09:00
takezoe
d0f052e056 Hide comment count for no comment issues. 2013-07-04 16:45:47 +09:00
takezoe
afd2325678 (refs #16)Fixed foreign key constraint problem in repository deletion. 2013-07-04 16:06:55 +09:00
16 changed files with 76 additions and 32 deletions

View File

@@ -22,7 +22,7 @@ object MyBuild extends Build {
scalaVersion := ScalaVersion,
resolvers += Classpaths.typesafeReleases,
libraryDependencies ++= Seq(
"org.eclipse.jgit" % "org.eclipse.jgit.http.server" % "2.3.1.201302201838-r",
"org.eclipse.jgit" % "org.eclipse.jgit.http.server" % "3.0.0.201306101825-r",
"org.apache.commons" % "commons-io" % "1.3.2",
"org.scalatra" %% "scalatra" % ScalatraVersion,
"org.scalatra" %% "scalatra-specs2" % ScalatraVersion % "test",

View File

@@ -0,0 +1,8 @@
-- Fix COLLABORATOR constraints
ALTER TABLE COLLABORATOR DROP CONSTRAINT IDX_COLLABORATOR_FK1 IF EXISTS;
ALTER TABLE COLLABORATOR DROP CONSTRAINT IDX_COLLABORATOR_FK0 IF EXISTS;
ALTER TABLE COLLABORATOR DROP CONSTRAINT IDX_COLLABORATOR_PK IF EXISTS;
ALTER TABLE COLLABORATOR ADD CONSTRAINT IDX_COLLABORATOR_PK PRIMARY KEY (USER_NAME, REPOSITORY_NAME, COLLABORATOR_NAME);
ALTER TABLE COLLABORATOR ADD CONSTRAINT IDX_COLLABORATOR_FK0 FOREIGN KEY (USER_NAME, REPOSITORY_NAME) REFERENCES REPOSITORY (USER_NAME, REPOSITORY_NAME);
ALTER TABLE COLLABORATOR ADD CONSTRAINT IDX_COLLABORATOR_FK1 FOREIGN KEY (COLLABORATOR_NAME) REFERENCES ACCOUNT (USER_NAME);

View File

@@ -16,15 +16,15 @@ trait AccountControllerBase extends ControllerBase {
case class AccountEditForm(password: Option[String], mailAddress: String, url: Option[String])
val newForm = mapping(
"userName" -> trim(label("User name" , text(required, maxlength(100), identifier, unique))),
"userName" -> trim(label("User name" , text(required, maxlength(100), identifier, uniqueUserName))),
"password" -> trim(label("Password" , text(required, maxlength(20)))),
"mailAddress" -> trim(label("Mail Address" , text(required, maxlength(100)))),
"mailAddress" -> trim(label("Mail Address" , text(required, maxlength(100), uniqueMailAddress()))),
"url" -> trim(label("URL" , optional(text(maxlength(200)))))
)(AccountNewForm.apply)
val editForm = mapping(
"password" -> trim(label("Password" , optional(text(maxlength(20))))),
"mailAddress" -> trim(label("Mail Address" , text(required, maxlength(100)))),
"mailAddress" -> trim(label("Mail Address" , text(required, maxlength(100), uniqueMailAddress("userName")))),
"url" -> trim(label("URL" , optional(text(maxlength(200)))))
)(AccountEditForm.apply)
@@ -67,9 +67,18 @@ trait AccountControllerBase extends ControllerBase {
} else NotFound
}
private def unique: Constraint = new Constraint(){
// TODO Merge with UserManagementController
private def uniqueUserName: Constraint = new Constraint(){
def validate(name: String, value: String): Option[String] =
getAccountByUserName(value).map { _ => "User already exists." }
}
// TODO Merge with UserManagementController
private def uniqueMailAddress(paramName: String = ""): Constraint = new Constraint(){
def validate(name: String, value: String): Option[String] =
getAccountByMailAddress(value)
.filter { x => if(paramName.isEmpty) true else Some(x.userName) != params.get(paramName) }
.map { _ => "Mail address is already registered." }
}
}

View File

@@ -45,7 +45,7 @@ trait MilestonesControllerBase extends ControllerBase {
post("/:owner/:repository/issues/milestones/:milestoneId/edit", milestoneForm)(collaboratorsOnly { (form, repository) =>
getMilestone(repository.owner, repository.name, params("milestoneId").toInt).map { milestone =>
updateMilestone(milestone.copy(title = form.title, description = form.description, dueDate = form.dueDate))
redirect("/%s/%s/issues/milestones".format(repository.owner, repository.repository))
redirect("/%s/%s/issues/milestones".format(repository.owner, repository.name))
} getOrElse NotFound
})

View File

@@ -45,7 +45,7 @@ trait SettingsControllerBase extends ControllerBase {
*/
post("/:owner/:repository/settings/options", optionsForm)(ownerOnly { (form, repository) =>
saveRepositoryOptions(repository.owner, repository.name, form.description, form.defaultBranch, form.isPrivate)
redirect("%s/%s/settings/options".format(repository.owner, repository.name))
redirect("/%s/%s/settings/options".format(repository.owner, repository.name))
})
/**

View File

@@ -13,9 +13,9 @@ trait UserManagementControllerBase extends ControllerBase { self: AccountService
case class UserEditForm(userName: String, password: Option[String], mailAddress: String, isAdmin: Boolean, url: Option[String])
val newForm = mapping(
"userName" -> trim(label("Username" , text(required, maxlength(100), identifier, unique))),
"userName" -> trim(label("Username" , text(required, maxlength(100), identifier, uniqueUserName))),
"password" -> trim(label("Password" , text(required, maxlength(20)))),
"mailAddress" -> trim(label("Mail Address" , text(required, maxlength(100)))),
"mailAddress" -> trim(label("Mail Address" , text(required, maxlength(100), uniqueMailAddress()))),
"isAdmin" -> trim(label("User Type" , boolean())),
"url" -> trim(label("URL" , optional(text(maxlength(200)))))
)(UserNewForm.apply)
@@ -23,7 +23,7 @@ trait UserManagementControllerBase extends ControllerBase { self: AccountService
val editForm = mapping(
"userName" -> trim(label("Username" , text(required, maxlength(100), identifier))),
"password" -> trim(label("Password" , optional(text(maxlength(20))))),
"mailAddress" -> trim(label("Mail Address" , text(required, maxlength(100)))),
"mailAddress" -> trim(label("Mail Address" , text(required, maxlength(100), uniqueMailAddress("userName")))),
"isAdmin" -> trim(label("User Type" , boolean())),
"url" -> trim(label("URL" , optional(text(maxlength(200)))))
)(UserEditForm.apply)
@@ -59,9 +59,18 @@ trait UserManagementControllerBase extends ControllerBase { self: AccountService
} getOrElse NotFound
})
private def unique: Constraint = new Constraint(){
// TODO Merge with AccountController?
private def uniqueUserName: Constraint = new Constraint(){
def validate(name: String, value: String): Option[String] =
getAccountByUserName(value).map { _ => "User already exists." }
}
}
// TODO Merge with AccountController?
private def uniqueMailAddress(paramName: String = ""): Constraint = new Constraint(){
def validate(name: String, value: String): Option[String] =
getAccountByMailAddress(value)
.filter { x => if(paramName.isEmpty) true else Some(x.userName) != params.get(paramName) }
.map { _ => "Mail address is already registered." }
}
}

View File

@@ -9,7 +9,10 @@ trait AccountService {
def getAccountByUserName(userName: String): Option[Account] =
Query(Accounts) filter(_.userName is userName.bind) firstOption
def getAccountByMailAddress(mailAddress: String): Option[Account] =
Query(Accounts) filter(_.mailAddress is mailAddress.bind) firstOption
def getAllUsers(): List[Account] = Query(Accounts) sortBy(_.userName) list
def createAccount(userName: String, password: String, mailAddress: String, isAdmin: Boolean, url: Option[String]): Unit =

View File

@@ -36,8 +36,12 @@ trait RepositoryService { self: AccountService =>
def deleteRepository(userName: String, repositoryName: String): Unit = {
Collaborators .filter(_.byRepository(userName, repositoryName)).delete
IssueId .filter(_.byRepository(userName, repositoryName)).delete
IssueLabels .filter(_.byRepository(userName, repositoryName)).delete
Labels .filter(_.byRepository(userName, repositoryName)).delete
IssueComments .filter(_.byRepository(userName, repositoryName)).delete
Issues .filter(_.byRepository(userName, repositoryName)).delete
IssueId .filter(_.byRepository(userName, repositoryName)).delete
Milestones .filter(_.byRepository(userName, repositoryName)).delete
Repositories .filter(_.byRepository(userName, repositoryName)).delete
}

View File

@@ -14,7 +14,7 @@ object AutoUpdate {
* Version of GitBucket
*
* @param majorVersion the major version
* @param minorVersion the minor version
* @param minorVersion the minor version
*/
case class Version(majorVersion: Int, minorVersion: Int){
@@ -22,7 +22,7 @@ object AutoUpdate {
/**
* Execute update/MAJOR_MINOR.sql to update schema to this version.
* If corresponding SQL file does not exist, this method do nothing.
* If corresponding SQL file does not exist, this method do nothing.
*/
def update(conn: Connection): Unit = {
val sqlPath = "update/%d_%d.sql".format(majorVersion, minorVersion)
@@ -40,7 +40,7 @@ object AutoUpdate {
}
/**
* MAJOR.MINOR
* MAJOR.MINOR
*/
val versionString = "%d.%d".format(majorVersion, minorVersion)
}
@@ -49,6 +49,7 @@ object AutoUpdate {
* The history of versions. A head of this sequence is the current BitBucket version.
*/
val versions = Seq(
Version(1, 1),
Version(1, 0)
)
@@ -84,7 +85,7 @@ object AutoUpdate {
}
/**
* Start H2 database and update schema automatically.
* Start H2 database and update schema automatically.
*/
class AutoUpdateListener extends org.h2.server.web.DbStarter {
import AutoUpdate._

View File

@@ -25,8 +25,6 @@ class GitBucketLinkRender(context: app.Context, repository: service.RepositorySe
enableWikiLink: Boolean) extends LinkRenderer {
override def render(node: WikiLinkNode): Rendering = {
if(enableWikiLink){
super.render(node)
} else {
try {
val text = node.getText
val (label, page) = if(text.contains('|')){
@@ -35,12 +33,14 @@ class GitBucketLinkRender(context: app.Context, repository: service.RepositorySe
} else {
(text, text)
}
val url = "%s/%s/%s/wiki/%s".format(context.path, repository.owner, repository.name,
java.net.URLEncoder.encode(page.replace(' ', '-'), "UTF-8"))
val url = repository.url.replaceFirst("/git/", "/").replaceFirst("\\.git$", "") +
"/wiki/" + java.net.URLEncoder.encode(page.replace(' ', '-'), "UTF-8")
new Rendering(url, label)
} catch {
case e: java.io.UnsupportedEncodingException => throw new IllegalStateException();
}
} else {
super.render(node)
}
}
}
@@ -96,8 +96,11 @@ class GitBucketHtmlSerializer(
}
private def fixUrl(url: String): String = {
if(!enableWikiLink || url.startsWith("http://") || url.startsWith("https://")) url
else repository.url.replaceFirst("/git/", "/").replaceFirst("\\.git$", "") + "/wiki/_blob/" + url
if(!enableWikiLink || url.startsWith("http://") || url.startsWith("https://")){
url
} else {
repository.url.replaceFirst("/git/", "/").replaceFirst("\\.git$", "") + "/wiki/_blob/" + url
}
}
private def printAttribute(name: String, value: String) {

View File

@@ -7,7 +7,7 @@
} else {
<h3>Create your account</h3>
}
<form action="@if(account.isDefined){@url(account.get.userName)/_edit}else{/register}" method="POST" validate="true">
<form action="@if(account.isDefined){@url(account.get.userName)/_edit}else{@path/register}" method="POST" validate="true">
@if(account.isEmpty){
<fieldset>
<label for="userName"><strong>User name</strong></label>

View File

@@ -105,13 +105,15 @@ $(function(){
if($(this).data('selected') == true){
$(this).css({
'background-color': 'white',
'color' : 'black'
'color' : 'black',
'font-weight' : 'normal'
});
$(this).data('selected', false);
} else {
$(this).css({
'background-color': '#' + $(this).data('bgcolor'),
'color' : '#' + $(this).data('fgcolor')
'color' : '#' + $(this).data('fgcolor'),
'font-weight' : 'bold'
});
$(this).data('selected', true);
}

View File

@@ -176,7 +176,9 @@
<span class="pull-right muted">#@issue.issueId</span>
<div class="small muted">
Opened by <a href="@url(issue.openedUserName)" class="username">@issue.openedUserName</a> @datetime(issue.registeredDate)&nbsp;
<i class="icon-comment"></i><a href="@url(repository)/issues/@issue.issueId" class="issue-comment-count">@commentCount @plural(commentCount, "comment")</a>
@if(commentCount > 0){
<i class="icon-comment"></i><a href="@url(repository)/issues/@issue.issueId" class="issue-comment-count">@commentCount @plural(commentCount, "comment")</a>
}
</div>
</td>
</tr>

View File

@@ -57,7 +57,4 @@
@body
</div>
</body>
<script>
$(function(){ prettyPrint(); });
</script>
</html>

View File

@@ -1,5 +1,11 @@
$(function(){
$.ajaxSetup({
cache: false
});
$('#repository-url').click(function(){
this.select(0, this.value.length);
});
prettyPrint();
});

View File

@@ -13,7 +13,7 @@ function validate(e){
$.post(form.attr('action') + '/validate', $(e.target).serialize(), function(data){
// clear all error messages
$('.error-message').text('');
$('.error').text('');
if($.isEmptyObject(data)){
form.data('validated', true);