diff --git a/README.md b/README.md
index f4fef24..4a44fce 100644
--- a/README.md
+++ b/README.md
@@ -80,6 +80,16 @@
Release Notes
--------
+### 2.4.1 - 6 Oct 2014
+- Bug fix
+
+### 2.4 - 6 Oct 2014
+- New UI is applied to Issues and Pull requests
+- Side-by-side diff is available
+- Fix relative path problem in Markdown links and images
+- Plugin System is disabled in default
+- Some bug fix and improvements
+
### 2.3 - 1 Sep 2014
- Scala based plugin system
- Embedded Jetty war extraction directory moved to `GITBUCKET_HOME/tmp`
diff --git a/etc/icons.svg b/etc/icons.svg
index a1849e3..1d50b97 100644
--- a/etc/icons.svg
+++ b/etc/icons.svg
@@ -34,9 +34,9 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
- inkscape:zoom="0.7"
- inkscape:cx="482.58197"
- inkscape:cy="-83.92636"
+ inkscape:zoom="0.98994949"
+ inkscape:cx="174.78739"
+ inkscape:cy="-195.96338"
inkscape:document-units="px"
inkscape:current-layer="layer1-9"
showgrid="false"
@@ -1583,7 +1583,7 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/project/build.scala b/project/build.scala
index bbef2e5..8586d34 100644
--- a/project/build.scala
+++ b/project/build.scala
@@ -42,7 +42,7 @@
"org.apache.commons" % "commons-email" % "1.3.1",
"org.apache.httpcomponents" % "httpclient" % "4.3",
"org.apache.sshd" % "apache-sshd" % "0.11.0",
- "com.typesafe.slick" %% "slick" % "2.1.0-RC3",
+ "com.typesafe.slick" %% "slick" % "2.1.0",
"com.novell.ldap" % "jldap" % "2009-10-07",
"org.quartz-scheduler" % "quartz" % "2.2.1",
"com.h2database" % "h2" % "1.4.180",
diff --git a/src/main/scala/app/DashboardController.scala b/src/main/scala/app/DashboardController.scala
index d0a40f0..9ac588b 100644
--- a/src/main/scala/app/DashboardController.scala
+++ b/src/main/scala/app/DashboardController.scala
@@ -50,20 +50,20 @@
val userName = context.loginAccount.get.userName
val userRepos = getUserRepositories(userName, context.baseUrl, true).map(repo => repo.owner -> repo.name)
- val filterUser = Map(filter -> userName)
+ //val filterUser = Map(filter -> userName)
val page = IssueSearchCondition.page(request)
dashboard.html.issues(
- issues.html.listparts(
- searchIssue(condition, filterUser, false, (page - 1) * IssueLimit, IssueLimit, userRepos: _*),
+ dashboard.html.issueslist(
+ searchIssue(condition, false, (page - 1) * IssueLimit, IssueLimit, userRepos: _*),
page,
- countIssue(condition.copy(state = "open" ), filterUser, false, userRepos: _*),
- countIssue(condition.copy(state = "closed"), filterUser, false, userRepos: _*),
+ countIssue(condition.copy(state = "open" ), false, userRepos: _*),
+ countIssue(condition.copy(state = "closed"), false, userRepos: _*),
condition),
- countIssue(condition, Map.empty, false, userRepos: _*),
- countIssue(condition, Map("assigned" -> userName), false, userRepos: _*),
- countIssue(condition, Map("created_by" -> userName), false, userRepos: _*),
- countIssueGroupByRepository(condition, filterUser, false, userRepos: _*),
+ countIssue(condition.copy(assigned = None, author = None), false, userRepos: _*),
+ countIssue(condition.copy(assigned = Some(userName), author = None), false, userRepos: _*),
+ countIssue(condition.copy(assigned = None, author = Some(userName)), false, userRepos: _*),
+ countIssueGroupByRepository(condition, false, userRepos: _*),
condition,
filter)
@@ -80,24 +80,24 @@
}.copy(repo = repository))
val userName = context.loginAccount.get.userName
- val allRepos = getAllRepositories()
+ val allRepos = getAllRepositories(userName)
val userRepos = getUserRepositories(userName, context.baseUrl, true).map(repo => repo.owner -> repo.name)
val filterUser = Map(filter -> userName)
val page = IssueSearchCondition.page(request)
val counts = countIssueGroupByRepository(
- IssueSearchCondition().copy(state = condition.state), Map.empty, true, userRepos: _*)
+ IssueSearchCondition().copy(state = condition.state), true, userRepos: _*)
dashboard.html.pulls(
- pulls.html.listparts(
- searchIssue(condition, filterUser, true, (page - 1) * PullRequestLimit, PullRequestLimit, allRepos: _*),
+ dashboard.html.pullslist(
+ searchIssue(condition, true, (page - 1) * PullRequestLimit, PullRequestLimit, allRepos: _*),
page,
- countIssue(condition.copy(state = "open" ), filterUser, true, allRepos: _*),
- countIssue(condition.copy(state = "closed"), filterUser, true, allRepos: _*),
+ countIssue(condition.copy(state = "open" ), true, allRepos: _*),
+ countIssue(condition.copy(state = "closed"), true, allRepos: _*),
condition,
None,
false),
- getPullRequestCountGroupByUser(condition.state == "closed", None, None),
+ getAllPullRequestCountGroupByUser(condition.state == "closed", userName),
userRepos.map { case (userName, repoName) =>
(userName, repoName, counts.find { x => x._1 == userName && x._2 == repoName }.map(_._3).getOrElse(0))
}.sortBy(_._3).reverse,
diff --git a/src/main/scala/app/IssuesController.scala b/src/main/scala/app/IssuesController.scala
index 4fe478e..ef178ff 100644
--- a/src/main/scala/app/IssuesController.scala
+++ b/src/main/scala/app/IssuesController.scala
@@ -21,7 +21,6 @@
case class IssueCreateForm(title: String, content: Option[String],
assignedUserName: Option[String], milestoneId: Option[Int], labelNames: Option[String])
- case class IssueEditForm(title: String, content: Option[String])
case class CommentForm(issueId: Int, content: String)
case class IssueStateForm(issueId: Int, content: Option[String])
@@ -33,10 +32,12 @@
"labelNames" -> trim(optional(text()))
)(IssueCreateForm.apply)
+ val issueTitleEditForm = mapping(
+ "title" -> trim(label("Title", text(required)))
+ )(x => x)
val issueEditForm = mapping(
- "title" -> trim(label("Title", text(required))),
- "content" -> trim(optional(text()))
- )(IssueEditForm.apply)
+ "content" -> trim(optional(text()))
+ )(x => x)
val commentForm = mapping(
"issueId" -> label("Issue Id", number()),
@@ -48,16 +49,8 @@
"content" -> trim(optional(text()))
)(IssueStateForm.apply)
- get("/:owner/:repository/issues")(referrersOnly {
- searchIssues("all", _)
- })
-
- get("/:owner/:repository/issues/assigned/:userName")(referrersOnly {
- searchIssues("assigned", _)
- })
-
- get("/:owner/:repository/issues/created_by/:userName")(referrersOnly {
- searchIssues("created_by", _)
+ get("/:owner/:repository/issues")(referrersOnly { repository =>
+ searchIssues(repository)
})
get("/:owner/:repository/issues/:id")(referrersOnly { repository =>
@@ -126,14 +119,29 @@
}
})
- ajaxPost("/:owner/:repository/issues/edit/:id", issueEditForm)(readableUsersOnly { (form, repository) =>
+ ajaxPost("/:owner/:repository/issues/edit_title/:id", issueTitleEditForm)(readableUsersOnly { (title, repository) =>
defining(repository.owner, repository.name){ case (owner, name) =>
getIssue(owner, name, params("id")).map { issue =>
if(isEditable(owner, name, issue.openedUserName)){
// update issue
- updateIssue(owner, name, issue.issueId, form.title, form.content)
+ updateIssue(owner, name, issue.issueId, title, issue.content)
// extract references and create refer comment
- createReferComment(owner, name, issue, form.title + " " + form.content.getOrElse(""))
+ createReferComment(owner, name, issue.copy(title = title), title)
+
+ redirect(s"/${owner}/${name}/issues/_data/${issue.issueId}")
+ } else Unauthorized
+ } getOrElse NotFound
+ }
+ })
+
+ ajaxPost("/:owner/:repository/issues/edit/:id", issueEditForm)(readableUsersOnly { (content, repository) =>
+ defining(repository.owner, repository.name){ case (owner, name) =>
+ getIssue(owner, name, params("id")).map { issue =>
+ if(isEditable(owner, name, issue.openedUserName)){
+ // update issue
+ updateIssue(owner, name, issue.issueId, issue.title, content)
+ // extract references and create refer comment
+ createReferComment(owner, name, issue, content.getOrElse(""))
redirect(s"/${owner}/${name}/issues/_data/${issue.issueId}")
} else Unauthorized
@@ -181,7 +189,7 @@
if(isEditable(x.userName, x.repositoryName, x.openedUserName)){
params.get("dataType") collect {
case t if t == "html" => issues.html.editissue(
- x.title, x.content, x.issueId, x.userName, x.repositoryName)
+ x.content, x.issueId, x.userName, x.repositoryName)
} getOrElse {
contentType = formats("json")
org.json4s.jackson.Serialization.write(
@@ -235,15 +243,17 @@
milestoneId("milestoneId").map { milestoneId =>
getMilestonesWithIssueCount(repository.owner, repository.name)
.find(_._1.milestoneId == milestoneId).map { case (_, openCount, closeCount) =>
- issues.milestones.html.progress(openCount + closeCount, closeCount, false)
+ issues.milestones.html.progress(openCount + closeCount, closeCount)
} getOrElse NotFound
} getOrElse Ok()
})
post("/:owner/:repository/issues/batchedit/state")(collaboratorsOnly { repository =>
defining(params.get("value")){ action =>
- executeBatch(repository) {
- handleComment(_, None, repository)( _ => action)
+ action match {
+ case Some("open") => executeBatch(repository) { handleComment(_, None, repository)( _ => Some("reopen")) }
+ case Some("close") => executeBatch(repository) { handleComment(_, None, repository)( _ => Some("close")) }
+ case _ => // TODO BadRequest
}
}
})
@@ -293,7 +303,10 @@
private def executeBatch(repository: RepositoryService.RepositoryInfo)(execute: Int => Unit) = {
params("checked").split(',') map(_.toInt) foreach execute
- redirect(s"/${repository.owner}/${repository.name}/issues")
+ params("from") match {
+ case "issues" => redirect(s"/${repository.owner}/${repository.name}/issues")
+ case "pulls" => redirect(s"/${repository.owner}/${repository.name}/pulls")
+ }
}
private def createReferComment(owner: String, repository: String, fromIssue: Issue, message: String) = {
@@ -319,15 +332,15 @@
val (action, recordActivity) =
getAction(issue)
.collect {
- case "close" => true -> (Some("close") ->
- Some(if(issue.isPullRequest) recordClosePullRequestActivity _ else recordCloseIssueActivity _))
- case "reopen" => false -> (Some("reopen") ->
- Some(recordReopenIssueActivity _))
- }
+ case "close" if(!issue.closed) => true ->
+ (Some("close") -> Some(if(issue.isPullRequest) recordClosePullRequestActivity _ else recordCloseIssueActivity _))
+ case "reopen" if(issue.closed) => false ->
+ (Some("reopen") -> Some(recordReopenIssueActivity _))
+ }
.map { case (closed, t) =>
- updateClosed(owner, name, issueId, closed)
- t
- }
+ updateClosed(owner, name, issueId, closed)
+ t
+ }
.getOrElse(None -> None)
val commentId = content
@@ -337,7 +350,7 @@
case (content, action) => createComment(owner, name, userName, issueId, content, action)
}
- // record activity
+ // record comment activity if comment is entered
content foreach {
(if(issue.isPullRequest) recordCommentPullRequestActivity _ else recordCommentIssueActivity _)
(owner, name, userName, issueId, _)
@@ -370,9 +383,8 @@
}
}
- private def searchIssues(filter: String, repository: RepositoryService.RepositoryInfo) = {
+ private def searchIssues(repository: RepositoryService.RepositoryInfo) = {
defining(repository.owner, repository.name){ case (owner, repoName) =>
- val filterUser = Map(filter -> params.getOrElse("userName", ""))
val page = IssueSearchCondition.page(request)
val sessionKey = Keys.Session.Issues(owner, repoName)
@@ -383,19 +395,15 @@
)
issues.html.list(
- searchIssue(condition, filterUser, false, (page - 1) * IssueLimit, IssueLimit, owner -> repoName),
+ "issues",
+ searchIssue(condition, false, (page - 1) * IssueLimit, IssueLimit, owner -> repoName),
page,
(getCollaborators(owner, repoName) :+ owner).sorted,
getMilestones(owner, repoName),
getLabels(owner, repoName),
- countIssue(condition.copy(state = "open"), filterUser, false, owner -> repoName),
- countIssue(condition.copy(state = "closed"), filterUser, false, owner -> repoName),
- countIssue(condition, Map.empty, false, owner -> repoName),
- context.loginAccount.map(x => countIssue(condition, Map("assigned" -> x.userName), false, owner -> repoName)),
- context.loginAccount.map(x => countIssue(condition, Map("created_by" -> x.userName), false, owner -> repoName)),
- countIssueGroupByLabels(owner, repoName, condition, filterUser),
+ countIssue(condition.copy(state = "open" ), false, owner -> repoName),
+ countIssue(condition.copy(state = "closed"), false, owner -> repoName),
condition,
- filter,
repository,
hasWritePermission(owner, repoName, context.loginAccount))
}
diff --git a/src/main/scala/app/LabelsController.scala b/src/main/scala/app/LabelsController.scala
index 2ac47fc..f84012d 100644
--- a/src/main/scala/app/LabelsController.scala
+++ b/src/main/scala/app/LabelsController.scala
@@ -2,51 +2,67 @@
import jp.sf.amateras.scalatra.forms._
import service._
-import util.CollaboratorsAuthenticator
+import util.{ReferrerAuthenticator, CollaboratorsAuthenticator}
import util.Implicits._
import org.scalatra.i18n.Messages
+import org.scalatra.Ok
class LabelsController extends LabelsControllerBase
- with LabelsService with RepositoryService with AccountService with CollaboratorsAuthenticator
+ with LabelsService with IssuesService with RepositoryService with AccountService
+with ReferrerAuthenticator with CollaboratorsAuthenticator
trait LabelsControllerBase extends ControllerBase {
- self: LabelsService with RepositoryService with CollaboratorsAuthenticator =>
+ self: LabelsService with IssuesService with RepositoryService
+ with ReferrerAuthenticator with CollaboratorsAuthenticator =>
case class LabelForm(labelName: String, color: String)
- val newForm = mapping(
- "newLabelName" -> trim(label("Label name", text(required, labelName, maxlength(100)))),
- "newColor" -> trim(label("Color", text(required, color)))
+ val labelForm = mapping(
+ "labelName" -> trim(label("Label name", text(required, labelName, maxlength(100)))),
+ "labelColor" -> trim(label("Color", text(required, color)))
)(LabelForm.apply)
- val editForm = mapping(
- "editLabelName" -> trim(label("Label name", text(required, labelName, maxlength(100)))),
- "editColor" -> trim(label("Color", text(required, color)))
- )(LabelForm.apply)
-
- post("/:owner/:repository/issues/label/new", newForm)(collaboratorsOnly { (form, repository) =>
- createLabel(repository.owner, repository.name, form.labelName, form.color.substring(1))
- redirect(s"/${repository.owner}/${repository.name}/issues")
+ get("/:owner/:repository/issues/labels")(referrersOnly { repository =>
+ issues.labels.html.list(
+ getLabels(repository.owner, repository.name),
+ countIssueGroupByLabels(repository.owner, repository.name, IssuesService.IssueSearchCondition()),
+ repository,
+ hasWritePermission(repository.owner, repository.name, context.loginAccount))
})
- ajaxGet("/:owner/:repository/issues/label/edit")(collaboratorsOnly { repository =>
- issues.labels.html.editlist(getLabels(repository.owner, repository.name), repository)
+ ajaxGet("/:owner/:repository/issues/labels/new")(collaboratorsOnly { repository =>
+ issues.labels.html.edit(None, repository)
})
- ajaxGet("/:owner/:repository/issues/label/:labelId/edit")(collaboratorsOnly { repository =>
+ ajaxPost("/:owner/:repository/issues/labels/new", labelForm)(collaboratorsOnly { (form, repository) =>
+ val labelId = createLabel(repository.owner, repository.name, form.labelName, form.color.substring(1))
+ issues.labels.html.label(
+ getLabel(repository.owner, repository.name, labelId).get,
+ // TODO futility
+ countIssueGroupByLabels(repository.owner, repository.name, IssuesService.IssueSearchCondition()),
+ repository,
+ hasWritePermission(repository.owner, repository.name, context.loginAccount))
+ })
+
+ ajaxGet("/:owner/:repository/issues/labels/:labelId/edit")(collaboratorsOnly { repository =>
getLabel(repository.owner, repository.name, params("labelId").toInt).map { label =>
issues.labels.html.edit(Some(label), repository)
} getOrElse NotFound()
})
- ajaxPost("/:owner/:repository/issues/label/:labelId/edit", editForm)(collaboratorsOnly { (form, repository) =>
+ ajaxPost("/:owner/:repository/issues/labels/:labelId/edit", labelForm)(collaboratorsOnly { (form, repository) =>
updateLabel(repository.owner, repository.name, params("labelId").toInt, form.labelName, form.color.substring(1))
- issues.labels.html.editlist(getLabels(repository.owner, repository.name), repository)
+ issues.labels.html.label(
+ getLabel(repository.owner, repository.name, params("labelId").toInt).get,
+ // TODO futility
+ countIssueGroupByLabels(repository.owner, repository.name, IssuesService.IssueSearchCondition()),
+ repository,
+ hasWritePermission(repository.owner, repository.name, context.loginAccount))
})
- ajaxGet("/:owner/:repository/issues/label/:labelId/delete")(collaboratorsOnly { repository =>
+ ajaxPost("/:owner/:repository/issues/labels/:labelId/delete")(collaboratorsOnly { repository =>
deleteLabel(repository.owner, repository.name, params("labelId").toInt)
- issues.labels.html.editlist(getLabels(repository.owner, repository.name), repository)
+ Ok()
})
/**
diff --git a/src/main/scala/app/PullRequestsController.scala b/src/main/scala/app/PullRequestsController.scala
index 8fd4672..2f9aba5 100644
--- a/src/main/scala/app/PullRequestsController.scala
+++ b/src/main/scala/app/PullRequestsController.scala
@@ -62,10 +62,6 @@
searchPullRequests(None, repository)
})
- get("/:owner/:repository/pulls/:userName")(referrersOnly { repository =>
- searchPullRequests(Some(params("userName")), repository)
- })
-
get("/:owner/:repository/pull/:id")(referrersOnly { repository =>
params("id").toIntOpt.flatMap{ issueId =>
val owner = repository.owner
@@ -453,7 +449,6 @@
private def searchPullRequests(userName: Option[String], repository: RepositoryService.RepositoryInfo) =
defining(repository.owner, repository.name){ case (owner, repoName) =>
- val filterUser = userName.map { x => Map("created_by" -> x) } getOrElse Map("all" -> "")
val page = IssueSearchCondition.page(request)
val sessionKey = Keys.Session.Pulls(owner, repoName)
@@ -463,14 +458,15 @@
else session.getAs[IssueSearchCondition](sessionKey).getOrElse(IssueSearchCondition())
)
- pulls.html.list(
- searchIssue(condition, filterUser, true, (page - 1) * PullRequestLimit, PullRequestLimit, owner -> repoName),
- getPullRequestCountGroupByUser(condition.state == "closed", Some(owner), Some(repoName)),
- userName,
+ issues.html.list(
+ "pulls",
+ searchIssue(condition, true, (page - 1) * PullRequestLimit, PullRequestLimit, owner -> repoName),
page,
- countIssue(condition.copy(state = "open" ), filterUser, true, owner -> repoName),
- countIssue(condition.copy(state = "closed"), filterUser, true, owner -> repoName),
- countIssue(condition, Map.empty, true, owner -> repoName),
+ (getCollaborators(owner, repoName) :+ owner).sorted,
+ getMilestones(owner, repoName),
+ getLabels(owner, repoName),
+ countIssue(condition.copy(state = "open" ), true, owner -> repoName),
+ countIssue(condition.copy(state = "closed"), true, owner -> repoName),
condition,
repository,
hasWritePermission(owner, repoName, context.loginAccount))
diff --git a/src/main/scala/app/SystemSettingsController.scala b/src/main/scala/app/SystemSettingsController.scala
index c81e6d9..27b18fa 100644
--- a/src/main/scala/app/SystemSettingsController.scala
+++ b/src/main/scala/app/SystemSettingsController.scala
@@ -85,41 +85,55 @@
})
get("/admin/plugins")(adminOnly {
- val installedPlugins = plugin.PluginSystem.plugins
- val updatablePlugins = getAvailablePlugins(installedPlugins).filter(_.status == "updatable")
- admin.plugins.html.installed(installedPlugins, updatablePlugins)
+ if(enablePluginSystem){
+ val installedPlugins = plugin.PluginSystem.plugins
+ val updatablePlugins = getAvailablePlugins(installedPlugins).filter(_.status == "updatable")
+ admin.plugins.html.installed(installedPlugins, updatablePlugins)
+ } else NotFound
})
post("/admin/plugins/_update", pluginForm)(adminOnly { form =>
- deletePlugins(form.pluginIds)
- installPlugins(form.pluginIds)
- redirect("/admin/plugins")
+ if(enablePluginSystem){
+ deletePlugins(form.pluginIds)
+ installPlugins(form.pluginIds)
+ redirect("/admin/plugins")
+ } else NotFound
})
post("/admin/plugins/_delete", pluginForm)(adminOnly { form =>
- deletePlugins(form.pluginIds)
- redirect("/admin/plugins")
+ if(enablePluginSystem){
+ deletePlugins(form.pluginIds)
+ redirect("/admin/plugins")
+ } else NotFound
})
get("/admin/plugins/available")(adminOnly {
- val installedPlugins = plugin.PluginSystem.plugins
- val availablePlugins = getAvailablePlugins(installedPlugins).filter(_.status == "available")
- admin.plugins.html.available(availablePlugins)
+ if(enablePluginSystem){
+ val installedPlugins = plugin.PluginSystem.plugins
+ val availablePlugins = getAvailablePlugins(installedPlugins).filter(_.status == "available")
+ admin.plugins.html.available(availablePlugins)
+ } else NotFound
})
post("/admin/plugins/_install", pluginForm)(adminOnly { form =>
- installPlugins(form.pluginIds)
- redirect("/admin/plugins")
+ if(enablePluginSystem){
+ installPlugins(form.pluginIds)
+ redirect("/admin/plugins")
+ } else NotFound
})
get("/admin/plugins/console")(adminOnly {
- admin.plugins.html.console()
+ if(enablePluginSystem){
+ admin.plugins.html.console()
+ } else NotFound
})
post("/admin/plugins/console")(adminOnly {
- val script = request.getParameter("script")
- val result = plugin.ScalaPlugin.eval(script)
- Ok()
+ if(enablePluginSystem){
+ val script = request.getParameter("script")
+ val result = plugin.ScalaPlugin.eval(script)
+ Ok()
+ } else NotFound
})
// TODO Move these methods to PluginSystem or Service?
diff --git a/src/main/scala/model/Labels.scala b/src/main/scala/model/Labels.scala
index e36746a..47c6a2b 100644
--- a/src/main/scala/model/Labels.scala
+++ b/src/main/scala/model/Labels.scala
@@ -31,7 +31,7 @@
if(Integer.parseInt(r, 16) + Integer.parseInt(g, 16) + Integer.parseInt(b, 16) > 408){
"000000"
} else {
- "FFFFFF"
+ "ffffff"
}
}
}
diff --git a/src/main/scala/service/IssuesService.scala b/src/main/scala/service/IssuesService.scala
index 292b93a..9e7bfa6 100644
--- a/src/main/scala/service/IssuesService.scala
+++ b/src/main/scala/service/IssuesService.scala
@@ -43,14 +43,13 @@
* Returns the count of the search result against issues.
*
* @param condition the search condition
- * @param filterUser the filter user name (key is "all", "assigned" or "created_by", value is the user name)
* @param onlyPullRequest if true then counts only pull request, false then counts both of issue and pull request.
* @param repos Tuple of the repository owner and the repository name
* @return the count of the search result
*/
- def countIssue(condition: IssueSearchCondition, filterUser: Map[String, String], onlyPullRequest: Boolean,
- repos: (String, String)*)(implicit s: Session): Int =
- Query(searchIssueQuery(repos, condition, filterUser, onlyPullRequest).length).first
+ def countIssue(condition: IssueSearchCondition, onlyPullRequest: Boolean, repos: (String, String)*)
+ (implicit s: Session): Int =
+ Query(searchIssueQuery(repos, condition, onlyPullRequest).length).first
/**
* Returns the Map which contains issue count for each labels.
@@ -58,13 +57,12 @@
* @param owner the repository owner
* @param repository the repository name
* @param condition the search condition
- * @param filterUser the filter user name (key is "all", "assigned" or "created_by", value is the user name)
* @return the Map which contains issue count for each labels (key is label name, value is issue count)
*/
- def countIssueGroupByLabels(owner: String, repository: String, condition: IssueSearchCondition,
- filterUser: Map[String, String])(implicit s: Session): Map[String, Int] = {
+ def countIssueGroupByLabels(owner: String, repository: String,
+ condition: IssueSearchCondition)(implicit s: Session): Map[String, Int] = {
- searchIssueQuery(Seq(owner -> repository), condition.copy(labels = Set.empty), filterUser, false)
+ searchIssueQuery(Seq(owner -> repository), condition.copy(labels = Set.empty), false)
.innerJoin(IssueLabels).on { (t1, t2) =>
t1.byIssue(t2.userName, t2.repositoryName, t2.issueId)
}
@@ -84,15 +82,14 @@
* If the issue does not exist, its repository is not included in the result.
*
* @param condition the search condition
- * @param filterUser the filter user name (key is "all", "assigned" or "created_by", value is the user name)
* @param onlyPullRequest if true then returns only pull request, false then returns both of issue and pull request.
* @param repos Tuple of the repository owner and the repository name
* @return list which contains issue count for each repository
*/
def countIssueGroupByRepository(
- condition: IssueSearchCondition, filterUser: Map[String, String], onlyPullRequest: Boolean,
+ condition: IssueSearchCondition, onlyPullRequest: Boolean,
repos: (String, String)*)(implicit s: Session): List[(String, String, Int)] = {
- searchIssueQuery(repos, condition.copy(repo = None), filterUser, onlyPullRequest)
+ searchIssueQuery(repos, condition.copy(repo = None), onlyPullRequest)
.groupBy { t =>
t.userName -> t.repositoryName
}
@@ -107,19 +104,18 @@
* Returns the search result against issues.
*
* @param condition the search condition
- * @param filterUser the filter user name (key is "all", "assigned", "created_by" or "not_created_by", value is the user name)
- * @param onlyPullRequest if true then returns only pull request, false then returns both of issue and pull request.
+ * @param pullRequest if true then returns only pull requests, false then returns only issues.
* @param offset the offset for pagination
* @param limit the limit for pagination
* @param repos Tuple of the repository owner and the repository name
* @return the search result (list of tuples which contain issue, labels and comment count)
*/
- def searchIssue(condition: IssueSearchCondition, filterUser: Map[String, String], onlyPullRequest: Boolean,
+ def searchIssue(condition: IssueSearchCondition, pullRequest: Boolean,
offset: Int, limit: Int, repos: (String, String)*)
- (implicit s: Session): List[(Issue, List[Label], Int)] = {
+ (implicit s: Session): List[IssueInfo] = {
// get issues and comment count and labels
- searchIssueQuery(repos, condition, filterUser, onlyPullRequest)
+ searchIssueQuery(repos, condition, pullRequest)
.innerJoin(IssueOutline).on { (t1, t2) => t1.byIssue(t2.userName, t2.repositoryName, t2.issueId) }
.sortBy { case (t1, t2) =>
(condition.sort match {
@@ -136,21 +132,23 @@
.drop(offset).take(limit)
.leftJoin (IssueLabels) .on { case ((t1, t2), t3) => t1.byIssue(t3.userName, t3.repositoryName, t3.issueId) }
.leftJoin (Labels) .on { case (((t1, t2), t3), t4) => t3.byLabel(t4.userName, t4.repositoryName, t4.labelId) }
- .map { case (((t1, t2), t3), t4) =>
- (t1, t2.commentCount, t4.labelId.?, t4.labelName.?, t4.color.?)
+ .leftJoin (Milestones) .on { case ((((t1, t2), t3), t4), t5) => t1.byMilestone(t5.userName, t5.repositoryName, t5.milestoneId) }
+ .map { case ((((t1, t2), t3), t4), t5) =>
+ (t1, t2.commentCount, t4.labelId.?, t4.labelName.?, t4.color.?, t5.title.?)
}
.list
.splitWith { (c1, c2) =>
- c1._1.userName == c2._1.userName &&
+ c1._1.userName == c2._1.userName &&
c1._1.repositoryName == c2._1.repositoryName &&
- c1._1.issueId == c2._1.issueId
+ c1._1.issueId == c2._1.issueId
}
.map { issues => issues.head match {
- case (issue, commentCount, _,_,_) =>
- (issue,
+ case (issue, commentCount, _, _, _, milestone) =>
+ IssueInfo(issue,
issues.flatMap { t => t._3.map (
Label(issue.userName, issue.repositoryName, _, t._4.get, t._5.get)
)} toList,
+ milestone,
commentCount)
}} toList
}
@@ -159,7 +157,7 @@
* Assembles query for conditional issue searching.
*/
private def searchIssueQuery(repos: Seq[(String, String)], condition: IssueSearchCondition,
- filterUser: Map[String, String], onlyPullRequest: Boolean)(implicit s: Session) =
+ pullRequest: Boolean)(implicit s: Session) =
Issues filter { t1 =>
condition.repo
.map { _.split('/') match { case array => Seq(array(0) -> array(1)) } }
@@ -169,10 +167,9 @@
(t1.closed === (condition.state == "closed").bind) &&
(t1.milestoneId === condition.milestoneId.get.get.bind, condition.milestoneId.flatten.isDefined) &&
(t1.milestoneId.? isEmpty, condition.milestoneId == Some(None)) &&
- (t1.assignedUserName === filterUser("assigned").bind, filterUser.get("assigned").isDefined) &&
- (t1.openedUserName === filterUser("created_by").bind, filterUser.get("created_by").isDefined) &&
- (t1.openedUserName =!= filterUser("not_created_by").bind, filterUser.get("not_created_by").isDefined) &&
- (t1.pullRequest === true.bind, onlyPullRequest) &&
+ (t1.assignedUserName === condition.assigned.get.bind, condition.assigned.isDefined) &&
+ (t1.openedUserName === condition.author.get.bind, condition.author.isDefined) &&
+ (t1.pullRequest === pullRequest.bind) &&
(IssueLabels filter { t2 =>
(t2.byIssue(t1.userName, t1.repositoryName, t1.issueId)) &&
(t2.labelId in
@@ -337,11 +334,20 @@
case class IssueSearchCondition(
labels: Set[String] = Set.empty,
milestoneId: Option[Option[Int]] = None,
+ author: Option[String] = None,
+ assigned: Option[String] = None,
repo: Option[String] = None,
state: String = "open",
sort: String = "created",
direction: String = "desc"){
+ def isEmpty: Boolean = {
+ labels.isEmpty && milestoneId.isEmpty && author.isEmpty && assigned.isEmpty &&
+ state == "open" && sort == "created" && direction == "desc"
+ }
+
+ def nonEmpty: Boolean = !isEmpty
+
def toURL: String =
"?" + List(
if(labels.isEmpty) None else Some("labels=" + urlEncode(labels.mkString(","))),
@@ -349,6 +355,8 @@
case Some(x) => x.toString
case None => "none"
})},
+ author .map(x => "author=" + urlEncode(x)),
+ assigned.map(x => "assigned=" + urlEncode(x)),
repo.map("for=" + urlEncode(_)),
Some("state=" + urlEncode(state)),
Some("sort=" + urlEncode(sort)),
@@ -370,6 +378,8 @@
case "none" => None
case x => x.toIntOpt
},
+ param(request, "author"),
+ param(request, "assigned"),
param(request, "for"),
param(request, "state", Seq("open", "closed")).getOrElse("open"),
param(request, "sort", Seq("created", "comments", "updated")).getOrElse("created"),
@@ -383,4 +393,6 @@
}
}
+ case class IssueInfo(issue: Issue, labels: List[Label], milestone: Option[String], commentCount: Int)
+
}
diff --git a/src/main/scala/service/LabelsService.scala b/src/main/scala/service/LabelsService.scala
index 37c3d35..de1dcb8 100644
--- a/src/main/scala/service/LabelsService.scala
+++ b/src/main/scala/service/LabelsService.scala
@@ -12,8 +12,8 @@
def getLabel(owner: String, repository: String, labelId: Int)(implicit s: Session): Option[Label] =
Labels.filter(_.byPrimaryKey(owner, repository, labelId)).firstOption
- def createLabel(owner: String, repository: String, labelName: String, color: String)(implicit s: Session): Unit =
- Labels insert Label(
+ def createLabel(owner: String, repository: String, labelName: String, color: String)(implicit s: Session): Int =
+ Labels returning Labels.map(_.labelId) += Label(
userName = owner,
repositoryName = repository,
labelName = labelName,
diff --git a/src/main/scala/service/PullRequestService.scala b/src/main/scala/service/PullRequestService.scala
index 2129d07..d5bcb0b 100644
--- a/src/main/scala/service/PullRequestService.scala
+++ b/src/main/scala/service/PullRequestService.scala
@@ -36,6 +36,24 @@
.list
.map { x => PullRequestCount(x._1, x._2) }
+ def getAllPullRequestCountGroupByUser(closed: Boolean, userName: String)(implicit s: Session): List[PullRequestCount] =
+ PullRequests
+ .innerJoin(Issues).on { (t1, t2) => t1.byPrimaryKey(t2.userName, t2.repositoryName, t2.issueId) }
+ .innerJoin(Repositories).on { case ((t1, t2), t3) => t2.byRepository(t3.userName, t3.repositoryName) }
+ .filter { case ((t1, t2), t3) =>
+ (t2.closed === closed.bind) &&
+ (
+ (t3.isPrivate === false.bind) ||
+ (t3.userName === userName.bind) ||
+ (Collaborators.filter { t4 => t4.byRepository(t3.userName, t3.repositoryName) && (t4.collaboratorName === userName.bind)} exists)
+ )
+ }
+ .groupBy { case ((t1, t2), t3) => t2.openedUserName }
+ .map { case (userName, t) => userName -> t.length }
+ .sortBy(_._2 desc)
+ .list
+ .map { x => PullRequestCount(x._1, x._2) }
+
def createPullRequest(originUserName: String, originRepositoryName: String, issueId: Int,
originBranch: String, requestUserName: String, requestRepositoryName: String, requestBranch: String,
commitIdFrom: String, commitIdTo: String)(implicit s: Session): Unit =
diff --git a/src/main/scala/service/RepositoryService.scala b/src/main/scala/service/RepositoryService.scala
index 8e204a8..31e3637 100644
--- a/src/main/scala/service/RepositoryService.scala
+++ b/src/main/scala/service/RepositoryService.scala
@@ -166,8 +166,19 @@
}
}
- def getAllRepositories()(implicit s: Session): List[(String, String)] = {
- Repositories.sortBy(_.lastActivityDate desc).map{ t =>
+ /**
+ * Returns the repositories without private repository that user does not have access right.
+ * Include public repository, private own repository and private but collaborator repository.
+ *
+ * @param userName the user name of collaborator
+ * @return the repository infomation list
+ */
+ def getAllRepositories(userName: String)(implicit s: Session): List[(String, String)] = {
+ Repositories.filter { t1 =>
+ (t1.isPrivate === false.bind) ||
+ (t1.userName === userName.bind) ||
+ (Collaborators.filter { t2 => t2.byRepository(t1.userName, t1.repositoryName) && (t2.collaboratorName === userName.bind)} exists)
+ }.sortBy(_.lastActivityDate desc).map{ t =>
(t.userName, t.repositoryName)
}.list
}
diff --git a/src/main/scala/service/SystemSettingsService.scala b/src/main/scala/service/SystemSettingsService.scala
index 2d8f1d3..9fbd78f 100644
--- a/src/main/scala/service/SystemSettingsService.scala
+++ b/src/main/scala/service/SystemSettingsService.scala
@@ -191,4 +191,7 @@
else value
}
+ // TODO temporary flag
+ val enablePluginSystem = Option(System.getProperty("enable.plugin")).getOrElse("false").toBoolean
+
}
diff --git a/src/main/scala/servlet/AutoUpdateListener.scala b/src/main/scala/servlet/AutoUpdateListener.scala
index 2670181..aff3010 100644
--- a/src/main/scala/servlet/AutoUpdateListener.scala
+++ b/src/main/scala/servlet/AutoUpdateListener.scala
@@ -11,6 +11,7 @@
import org.eclipse.jgit.api.Git
import util.Directory
import plugin.PluginUpdateJob
+import service.SystemSettingsService
object AutoUpdate {
@@ -52,6 +53,7 @@
* The history of versions. A head of this sequence is the current BitBucket version.
*/
val versions = Seq(
+ new Version(2, 4),
new Version(2, 3) {
override def update(conn: Connection): Unit = {
super.update(conn)
@@ -168,18 +170,15 @@
*/
class AutoUpdateListener extends ServletContextListener {
import org.quartz.impl.StdSchedulerFactory
- import org.quartz.JobBuilder._
- import org.quartz.TriggerBuilder._
- import org.quartz.SimpleScheduleBuilder._
import AutoUpdate._
private val logger = LoggerFactory.getLogger(classOf[AutoUpdateListener])
private val scheduler = StdSchedulerFactory.getDefaultScheduler
override def contextInitialized(event: ServletContextEvent): Unit = {
- val datadir = event.getServletContext.getInitParameter("gitbucket.home")
- if(datadir != null){
- System.setProperty("gitbucket.home", datadir)
+ val dataDir = event.getServletContext.getInitParameter("gitbucket.home")
+ if(dataDir != null){
+ System.setProperty("gitbucket.home", dataDir)
}
org.h2.Driver.load()
@@ -210,21 +209,23 @@
logger.debug("End schema update")
}
- getDatabase(context).withSession { implicit session =>
- logger.debug("Starting plugin system...")
- try {
- plugin.PluginSystem.init()
+ if(SystemSettingsService.enablePluginSystem){
+ getDatabase(context).withSession { implicit session =>
+ logger.debug("Starting plugin system...")
+ try {
+ plugin.PluginSystem.init()
- scheduler.start()
- PluginUpdateJob.schedule(scheduler)
- logger.debug("PluginUpdateJob is started.")
+ scheduler.start()
+ PluginUpdateJob.schedule(scheduler)
+ logger.debug("PluginUpdateJob is started.")
- logger.debug("Plugin system is initialized.")
- } catch {
- case ex: Throwable => {
- logger.error("Failed to initialize plugin system", ex)
- ex.printStackTrace()
- throw ex
+ logger.debug("Plugin system is initialized.")
+ } catch {
+ case ex: Throwable => {
+ logger.error("Failed to initialize plugin system", ex)
+ ex.printStackTrace()
+ throw ex
+ }
}
}
}
diff --git a/src/main/scala/servlet/GitRepositoryServlet.scala b/src/main/scala/servlet/GitRepositoryServlet.scala
index 012c6ea..df55d46 100644
--- a/src/main/scala/servlet/GitRepositoryServlet.scala
+++ b/src/main/scala/servlet/GitRepositoryServlet.scala
@@ -134,8 +134,8 @@
// Retrieve all issue count in the repository
val issueCount =
- countIssue(IssueSearchCondition(state = "open"), Map.empty, false, owner -> repository) +
- countIssue(IssueSearchCondition(state = "closed"), Map.empty, false, owner -> repository)
+ countIssue(IssueSearchCondition(state = "open"), false, owner -> repository) +
+ countIssue(IssueSearchCondition(state = "closed"), false, owner -> repository)
// Extract new commit and apply issue comment
val defaultBranch = getRepository(owner, repository, baseUrl).get.repository.defaultBranch
diff --git a/src/main/scala/view/Markdown.scala b/src/main/scala/view/Markdown.scala
index d06dc1f..08c3dd4 100644
--- a/src/main/scala/view/Markdown.scala
+++ b/src/main/scala/view/Markdown.scala
@@ -97,9 +97,10 @@
Map[String, VerbatimSerializer](VerbatimSerializer.DEFAULT -> new GitBucketVerbatimSerializer).asJava
) with LinkConverter with RequestCache {
- override protected def printImageTag(imageNode: SuperNode, url: String): Unit =
- printer.print("")
- .print(" ")
+ override protected def printImageTag(imageNode: SuperNode, url: String): Unit = {
+ printer.print("")
+ .print(" ")
+ }
override protected def printLink(rendering: LinkRenderer.Rendering): Unit = {
printer.print('<').print('a')
@@ -110,15 +111,20 @@
printer.print('>').print(rendering.text).print("")
}
- private def fixUrl(url: String): String = {
- if(!enableWikiLink){
- if(url.startsWith("http://") || url.startsWith("https://") || url.startsWith("#") || url.startsWith("/") ||
- context.currentPath.contains("/blob/")){
- url
+ private def fixUrl(url: String, isImage: Boolean = false): String = {
+ if(url.startsWith("http://") || url.startsWith("https://") || url.startsWith("#") || url.startsWith("/")){
+ url
+ } else if(!enableWikiLink){
+ if(context.currentPath.contains("/blob/")){
+ url + (if(isImage) "?raw=true" else "")
+ } else if(context.currentPath.contains("/tree/")){
+ val paths = context.currentPath.split("/")
+ val branch = if(paths.length > 3) paths.drop(4).mkString("/") else repository.repository.defaultBranch
+ repository.httpUrl.replaceFirst("/git/", "/").stripSuffix(".git") + "/blob/" + branch + "/" + url + (if(isImage) "?raw=true" else "")
} else {
val paths = context.currentPath.split("/")
val branch = if(paths.length > 3) paths.last else repository.repository.defaultBranch
- repository.httpUrl.replaceFirst("/git/", "/").stripSuffix(".git") + "/blob/" + branch + "/" + url
+ repository.httpUrl.replaceFirst("/git/", "/").stripSuffix(".git") + "/blob/" + branch + "/" + url + (if(isImage) "?raw=true" else "")
}
} else {
repository.httpUrl.replaceFirst("/git/", "/").stripSuffix(".git") + "/wiki/_blob/" + url
diff --git a/src/main/twirl/admin/menu.scala.html b/src/main/twirl/admin/menu.scala.html
index 25cda19..1e48858 100644
--- a/src/main/twirl/admin/menu.scala.html
+++ b/src/main/twirl/admin/menu.scala.html
@@ -11,9 +11,11 @@
System Settings
-
- Plugins
-
+ @if(service.SystemSettingsService.enablePluginSystem){
+
+ Plugins
+
+ }
H2 Console
diff --git a/src/main/twirl/dashboard/issueslist.scala.html b/src/main/twirl/dashboard/issueslist.scala.html
new file mode 100644
index 0000000..4f27ea8
--- /dev/null
+++ b/src/main/twirl/dashboard/issueslist.scala.html
@@ -0,0 +1,184 @@
+@(issues: List[service.IssuesService.IssueInfo],
+ page: Int,
+ openCount: Int,
+ closedCount: Int,
+ condition: service.IssuesService.IssueSearchCondition,
+ collaborators: List[String] = Nil,
+ milestones: List[model.Milestone] = Nil,
+ labels: List[model.Label] = Nil,
+ repository: Option[service.RepositoryService.RepositoryInfo] = None,
+ hasWritePermission: Boolean = false)(implicit context: app.Context)
+@import context._
+@import view.helpers._
+@import service.IssuesService.IssueInfo
+
+ @if(condition.labels.nonEmpty || condition.milestoneId.isDefined){
+
+ Clear milestone and label filters
+
+ }
+ @if(condition.repo.isDefined){
+
+ Clear filter on @condition.repo
+
+ }
+
+ @helper.html.paginator(page, (if(condition.state == "open") openCount else closedCount), service.IssuesService.IssueLimit, 7, condition.toURL)
+
+
+ @helper.html.dropdown(
+ value = (condition.sort, condition.direction) match {
+ case ("created" , "desc") => "Newest"
+ case ("created" , "asc" ) => "Oldest"
+ case ("comments", "desc") => "Most commented"
+ case ("comments", "asc" ) => "Least commented"
+ case ("updated" , "desc") => "Recently updated"
+ case ("updated" , "asc" ) => "Least recently updated"
+ },
+ prefix = "Sort",
+ mini = false
+ ){
+
+
+ @helper.html.checkicon(condition.sort == "created" && condition.direction == "desc") Newest
+
+
+
+
+ @helper.html.checkicon(condition.sort == "created" && condition.direction == "asc") Oldest
+
+
+
+
+ @helper.html.checkicon(condition.sort == "comments" && condition.direction == "desc") Most commented
+
+
+
+
+ @helper.html.checkicon(condition.sort == "comments" && condition.direction == "asc") Least commented
+
+
+
+
+ @helper.html.checkicon(condition.sort == "updated" && condition.direction == "desc") Recently updated
+
+
+
+
+ @helper.html.checkicon(condition.sort == "updated" && condition.direction == "asc") Least recently updated
+
+
+ }
+
+
+ @helper.html.paginator(page, (if(condition.state == "open") openCount else closedCount), service.IssuesService.IssueLimit, 10, condition.toURL)
+
+
+
diff --git a/src/main/twirl/dashboard/pullslist.scala.html b/src/main/twirl/dashboard/pullslist.scala.html
new file mode 100644
index 0000000..46343b4
--- /dev/null
+++ b/src/main/twirl/dashboard/pullslist.scala.html
@@ -0,0 +1,101 @@
+@(issues: List[service.IssuesService.IssueInfo],
+ page: Int,
+ openCount: Int,
+ closedCount: Int,
+ condition: service.IssuesService.IssueSearchCondition,
+ repository: Option[service.RepositoryService.RepositoryInfo],
+ hasWritePermission: Boolean)(implicit context: app.Context)
+@import context._
+@import view.helpers._
+@import service.IssuesService.IssueInfo
+
+ @repository.map { repository =>
+ @if(hasWritePermission){
+
+ @helper.html.paginator(page, (if(condition.state == "open") openCount else closedCount), service.PullRequestService.PullRequestLimit, 7, condition.toURL)
+
New pull request
+
+ }
+ }
+
+ @helper.html.dropdown(
+ value = (condition.sort, condition.direction) match {
+ case ("created" , "desc") => "Newest"
+ case ("created" , "asc" ) => "Oldest"
+ case ("comments", "desc") => "Most commented"
+ case ("comments", "asc" ) => "Least commented"
+ case ("updated" , "desc") => "Recently updated"
+ case ("updated" , "asc" ) => "Least recently updated"
+ },
+ prefix = "Sort",
+ mini = false
+ ){
+
+
+ @helper.html.checkicon(condition.sort == "created" && condition.direction == "desc") Newest
+
+
+
+
+ @helper.html.checkicon(condition.sort == "created" && condition.direction == "asc") Oldest
+
+
+
+
+ @helper.html.checkicon(condition.sort == "comments" && condition.direction == "desc") Most commented
+
+
+
+
+ @helper.html.checkicon(condition.sort == "comments" && condition.direction == "asc") Least commented
+
+
+
+
+ @helper.html.checkicon(condition.sort == "updated" && condition.direction == "desc") Recently updated
+
+
+
+
+ @helper.html.checkicon(condition.sort == "updated" && condition.direction == "asc") Least recently updated
+
+
+ }
+
+ @if(issues.isEmpty){
+
+
+ No pull requests to show.
+
+
+ }
+ @issues.map { case IssueInfo(issue, labels, milestone, commentCount) =>
+
+
+
+ @issue.title
+ #@issue.issueId
+
+ @issue.content.map { content =>
+ @cut(content, 90)
+ }.getOrElse {
+ No description available
+ }
+
+
+ @avatarLink(issue.openedUserName, 20) by @user(issue.openedUserName, styleClass="username") @datetime(issue.registeredDate)
+ @if(commentCount > 0){
+
+ }
+
+
+
+ }
+
+
+ @helper.html.paginator(page, (if(condition.state == "open") openCount else closedCount), service.PullRequestService.PullRequestLimit, 10, condition.toURL)
+
+
\ No newline at end of file
diff --git a/src/main/twirl/helper/diff.scala.html b/src/main/twirl/helper/diff.scala.html
index 598841c..8d0cd88 100644
--- a/src/main/twirl/helper/diff.scala.html
+++ b/src/main/twirl/helper/diff.scala.html
@@ -41,7 +41,7 @@
-
-
+
@if(diff.newContent != None || diff.oldContent != None){
diff --git a/src/main/twirl/helper/dropdown.scala.html b/src/main/twirl/helper/dropdown.scala.html
index 70d1dce..20e2f4a 100644
--- a/src/main/twirl/helper/dropdown.scala.html
+++ b/src/main/twirl/helper/dropdown.scala.html
@@ -1,6 +1,13 @@
-@(value: String = "", prefix: String = "", mini: Boolean = true, style: String = "", right: Boolean = false)(body: Html)
-
-
+@(value : String = "",
+ prefix: String = "",
+ mini : Boolean = true,
+ style : String = "",
+ right : Boolean = false,
+ flat : Boolean = false)(body: Html)
+
+
@if(value.isEmpty){
} else {
diff --git a/src/main/twirl/issues/commentform.scala.html b/src/main/twirl/issues/commentform.scala.html
index edabb5d..04169c7 100644
--- a/src/main/twirl/issues/commentform.scala.html
+++ b/src/main/twirl/issues/commentform.scala.html
@@ -5,6 +5,7 @@
@import context._
@import view.helpers._
@if(loginAccount.isDefined){
+