mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-11-12 16:35:52 +01:00
Separate milestones from IssuesController / IssuesService.
This commit is contained in:
@@ -12,6 +12,7 @@ class ScalatraBootstrap extends LifeCycle {
|
|||||||
context.mount(new RepositoryViewerController, "/*")
|
context.mount(new RepositoryViewerController, "/*")
|
||||||
context.mount(new WikiController, "/*")
|
context.mount(new WikiController, "/*")
|
||||||
context.mount(new IssuesController, "/*")
|
context.mount(new IssuesController, "/*")
|
||||||
|
context.mount(new MilestonesController, "/*")
|
||||||
context.mount(new SettingsController, "/*")
|
context.mount(new SettingsController, "/*")
|
||||||
|
|
||||||
context.addListener(new ServletContextListener(){
|
context.addListener(new ServletContextListener(){
|
||||||
|
|||||||
@@ -73,101 +73,4 @@ trait IssuesControllerBase extends ControllerBase {
|
|||||||
redirect("/%s/%s/issues/%d".format(owner, repository, 1))
|
redirect("/%s/%s/issues/%d".format(owner, repository, 1))
|
||||||
})
|
})
|
||||||
|
|
||||||
get("/:owner/:repository/issues/milestones")(readableRepository {
|
|
||||||
val owner = params("owner")
|
|
||||||
val repository = params("repository")
|
|
||||||
val state = params.getOrElse("state", "open")
|
|
||||||
|
|
||||||
getRepository(owner, repository, baseUrl) match {
|
|
||||||
case None => NotFound()
|
|
||||||
case Some(r) => issues.html.milestones(state, getMilestones(owner, repository),
|
|
||||||
getMilestoneIssueCounts(owner, repository), r, isWritable(owner, repository, context.loginAccount))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
get("/:owner/:repository/issues/milestones/new")(writableRepository {
|
|
||||||
val owner = params("owner")
|
|
||||||
val repository = params("repository")
|
|
||||||
|
|
||||||
getRepository(owner, repository, baseUrl) match {
|
|
||||||
case None => NotFound()
|
|
||||||
case Some(r) => issues.html.milestoneedit(None, r)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
post("/:owner/:repository/issues/milestones/new", milestoneForm)(writableRepository { form =>
|
|
||||||
val owner = params("owner")
|
|
||||||
val repository = params("repository")
|
|
||||||
|
|
||||||
createMilestone(owner, repository, form.title, form.description, form.dueDate)
|
|
||||||
|
|
||||||
redirect("/%s/%s/issues/milestones".format(owner, repository))
|
|
||||||
})
|
|
||||||
|
|
||||||
get("/:owner/:repository/issues/milestones/:milestoneId/edit")(writableRepository {
|
|
||||||
val owner = params("owner")
|
|
||||||
val repository = params("repository")
|
|
||||||
val milestoneId = params("milestoneId").toInt
|
|
||||||
|
|
||||||
getRepository(owner, repository, baseUrl) match {
|
|
||||||
case None => NotFound()
|
|
||||||
case Some(r) => issues.html.milestoneedit(getMilestone(owner, repository, milestoneId), r)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
post("/:owner/:repository/issues/milestones/:milestoneId/edit", milestoneForm)(writableRepository { form =>
|
|
||||||
val owner = params("owner")
|
|
||||||
val repository = params("repository")
|
|
||||||
val milestoneId = params("milestoneId").toInt
|
|
||||||
|
|
||||||
getMilestone(owner, repository, milestoneId) match {
|
|
||||||
case None => NotFound()
|
|
||||||
case Some(m) => {
|
|
||||||
updateMilestone(m.copy(title = form.title, description = form.description, dueDate = form.dueDate))
|
|
||||||
redirect("/%s/%s/issues/milestones".format(owner, repository))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
get("/:owner/:repository/issues/milestones/:milestoneId/close")(writableRepository {
|
|
||||||
val owner = params("owner")
|
|
||||||
val repository = params("repository")
|
|
||||||
val milestoneId = params("milestoneId").toInt
|
|
||||||
|
|
||||||
getMilestone(owner, repository, milestoneId) match {
|
|
||||||
case None => NotFound()
|
|
||||||
case Some(m) => {
|
|
||||||
closeMilestone(m)
|
|
||||||
redirect("/%s/%s/issues/milestones".format(owner, repository))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
get("/:owner/:repository/issues/milestones/:milestoneId/open")(writableRepository {
|
|
||||||
val owner = params("owner")
|
|
||||||
val repository = params("repository")
|
|
||||||
val milestoneId = params("milestoneId").toInt
|
|
||||||
|
|
||||||
getMilestone(owner, repository, milestoneId) match {
|
|
||||||
case None => NotFound()
|
|
||||||
case Some(m) => {
|
|
||||||
openMilestone(m)
|
|
||||||
redirect("/%s/%s/issues/milestones".format(owner, repository))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
get("/:owner/:repository/issues/milestones/:milestoneId/delete")(writableRepository {
|
|
||||||
val owner = params("owner")
|
|
||||||
val repository = params("repository")
|
|
||||||
val milestoneId = params("milestoneId").toInt
|
|
||||||
|
|
||||||
getMilestone(owner, repository, milestoneId) match {
|
|
||||||
case None => NotFound()
|
|
||||||
case Some(m) => {
|
|
||||||
deleteMilestone(owner, repository, milestoneId)
|
|
||||||
redirect("/%s/%s/issues/milestones".format(owner, repository))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
122
src/main/scala/app/MilestonesController.scala
Normal file
122
src/main/scala/app/MilestonesController.scala
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
package app
|
||||||
|
|
||||||
|
import jp.sf.amateras.scalatra.forms._
|
||||||
|
|
||||||
|
import service._
|
||||||
|
import util.{WritableRepositoryAuthenticator, ReadableRepositoryAuthenticator, UsersOnlyAuthenticator}
|
||||||
|
|
||||||
|
class MilestonesController extends MilestonesControllerBase
|
||||||
|
with MilestonesService with RepositoryService with AccountService
|
||||||
|
with ReadableRepositoryAuthenticator with WritableRepositoryAuthenticator
|
||||||
|
|
||||||
|
trait MilestonesControllerBase extends ControllerBase {
|
||||||
|
self: MilestonesService with RepositoryService
|
||||||
|
with ReadableRepositoryAuthenticator with WritableRepositoryAuthenticator =>
|
||||||
|
|
||||||
|
case class MilestoneForm(title: String, description: Option[String], dueDate: Option[java.util.Date])
|
||||||
|
|
||||||
|
val milestoneForm = mapping(
|
||||||
|
"title" -> trim(label("Title", text(required, maxlength(100)))),
|
||||||
|
"description" -> trim(label("Description", optional(text()))),
|
||||||
|
"dueDate" -> trim(label("Due Date", optional(date())))
|
||||||
|
)(MilestoneForm.apply)
|
||||||
|
|
||||||
|
get("/:owner/:repository/issues/milestones")(readableRepository {
|
||||||
|
val owner = params("owner")
|
||||||
|
val repository = params("repository")
|
||||||
|
val state = params.getOrElse("state", "open")
|
||||||
|
|
||||||
|
getRepository(owner, repository, baseUrl) match {
|
||||||
|
case None => NotFound()
|
||||||
|
case Some(r) => issues.html.milestones(state, getMilestones(owner, repository),
|
||||||
|
getMilestoneIssueCounts(owner, repository), r, isWritable(owner, repository, context.loginAccount))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
get("/:owner/:repository/issues/milestones/new")(writableRepository {
|
||||||
|
val owner = params("owner")
|
||||||
|
val repository = params("repository")
|
||||||
|
|
||||||
|
getRepository(owner, repository, baseUrl) match {
|
||||||
|
case None => NotFound()
|
||||||
|
case Some(r) => issues.html.milestoneedit(None, r)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
post("/:owner/:repository/issues/milestones/new", milestoneForm)(writableRepository { form =>
|
||||||
|
val owner = params("owner")
|
||||||
|
val repository = params("repository")
|
||||||
|
|
||||||
|
createMilestone(owner, repository, form.title, form.description, form.dueDate)
|
||||||
|
|
||||||
|
redirect("/%s/%s/issues/milestones".format(owner, repository))
|
||||||
|
})
|
||||||
|
|
||||||
|
get("/:owner/:repository/issues/milestones/:milestoneId/edit")(writableRepository {
|
||||||
|
val owner = params("owner")
|
||||||
|
val repository = params("repository")
|
||||||
|
val milestoneId = params("milestoneId").toInt
|
||||||
|
|
||||||
|
getRepository(owner, repository, baseUrl) match {
|
||||||
|
case None => NotFound()
|
||||||
|
case Some(r) => issues.html.milestoneedit(getMilestone(owner, repository, milestoneId), r)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
post("/:owner/:repository/issues/milestones/:milestoneId/edit", milestoneForm)(writableRepository { form =>
|
||||||
|
val owner = params("owner")
|
||||||
|
val repository = params("repository")
|
||||||
|
val milestoneId = params("milestoneId").toInt
|
||||||
|
|
||||||
|
getMilestone(owner, repository, milestoneId) match {
|
||||||
|
case None => NotFound()
|
||||||
|
case Some(m) => {
|
||||||
|
updateMilestone(m.copy(title = form.title, description = form.description, dueDate = form.dueDate))
|
||||||
|
redirect("/%s/%s/issues/milestones".format(owner, repository))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
get("/:owner/:repository/issues/milestones/:milestoneId/close")(writableRepository {
|
||||||
|
val owner = params("owner")
|
||||||
|
val repository = params("repository")
|
||||||
|
val milestoneId = params("milestoneId").toInt
|
||||||
|
|
||||||
|
getMilestone(owner, repository, milestoneId) match {
|
||||||
|
case None => NotFound()
|
||||||
|
case Some(m) => {
|
||||||
|
closeMilestone(m)
|
||||||
|
redirect("/%s/%s/issues/milestones".format(owner, repository))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
get("/:owner/:repository/issues/milestones/:milestoneId/open")(writableRepository {
|
||||||
|
val owner = params("owner")
|
||||||
|
val repository = params("repository")
|
||||||
|
val milestoneId = params("milestoneId").toInt
|
||||||
|
|
||||||
|
getMilestone(owner, repository, milestoneId) match {
|
||||||
|
case None => NotFound()
|
||||||
|
case Some(m) => {
|
||||||
|
openMilestone(m)
|
||||||
|
redirect("/%s/%s/issues/milestones".format(owner, repository))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
get("/:owner/:repository/issues/milestones/:milestoneId/delete")(writableRepository {
|
||||||
|
val owner = params("owner")
|
||||||
|
val repository = params("repository")
|
||||||
|
val milestoneId = params("milestoneId").toInt
|
||||||
|
|
||||||
|
getMilestone(owner, repository, milestoneId) match {
|
||||||
|
case None => NotFound()
|
||||||
|
case Some(m) => {
|
||||||
|
deleteMilestone(owner, repository, milestoneId)
|
||||||
|
redirect("/%s/%s/issues/milestones".format(owner, repository))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
@@ -51,62 +51,4 @@ trait IssuesService {
|
|||||||
}.map(_.issueId).update(id) > 0
|
}.map(_.issueId).update(id) > 0
|
||||||
} get
|
} get
|
||||||
|
|
||||||
def createMilestone(owner: String, repository: String,
|
|
||||||
title: String, description: Option[String], dueDate: Option[java.util.Date]) =
|
|
||||||
Milestones.autoInc insert (owner, repository, title, description, dueDate, None)
|
|
||||||
|
|
||||||
def updateMilestone(milestone: Milestone): Unit =
|
|
||||||
Query(Milestones)
|
|
||||||
.filter { m => (m.userName is milestone.userName.bind) && (m.repositoryName is milestone.repositoryName.bind) && (m.milestoneId is milestone.milestoneId.bind)}
|
|
||||||
.map { m => m.title ~ m.description.? ~ m.dueDate.? ~ m.closedDate.? }
|
|
||||||
.update (
|
|
||||||
milestone.title,
|
|
||||||
milestone.description,
|
|
||||||
milestone.dueDate,
|
|
||||||
milestone.closedDate)
|
|
||||||
|
|
||||||
def openMilestone(milestone: Milestone): Unit = updateMilestone(milestone.copy(closedDate = None))
|
|
||||||
|
|
||||||
def closeMilestone(milestone: Milestone): Unit = updateMilestone(milestone.copy(closedDate = Some(currentDate)))
|
|
||||||
|
|
||||||
def deleteMilestone(owner: String, repository: String, milestoneId: Int): Unit = {
|
|
||||||
Query(Issues)
|
|
||||||
.filter { i => (i.userName is owner.bind) && (i.repositoryName is repository.bind) && (i.milestoneId is milestoneId.bind)}
|
|
||||||
.map { i => i.milestoneId.? }
|
|
||||||
.update(None)
|
|
||||||
|
|
||||||
Query(Milestones)
|
|
||||||
.filter { i => (i.userName is owner.bind) && (i.repositoryName is repository.bind) && (i.milestoneId is milestoneId.bind)}
|
|
||||||
.delete
|
|
||||||
}
|
|
||||||
|
|
||||||
def getMilestone(owner: String, repository: String, milestoneId: Int): Option[Milestone] =
|
|
||||||
Query(Milestones)
|
|
||||||
.filter(m => (m.userName is owner.bind) && (m.repositoryName is repository.bind) && (m.milestoneId is milestoneId.bind))
|
|
||||||
.sortBy(_.milestoneId desc)
|
|
||||||
.firstOption
|
|
||||||
|
|
||||||
def getMilestoneIssueCounts(owner: String, repository: String): Map[(Int, Boolean), Int] = {
|
|
||||||
import scala.slick.jdbc.GetResult
|
|
||||||
|
|
||||||
case class IssueCount(milestoneId: Int, closed: Boolean, count: Int)
|
|
||||||
implicit val getIssueCount = GetResult(r => IssueCount(r.<<, r.<<, r.<<))
|
|
||||||
|
|
||||||
sql"""
|
|
||||||
select MILESTONE_ID, CLOSED, COUNT(ISSUE_ID)
|
|
||||||
from ISSUE
|
|
||||||
where USER_NAME = $owner AND REPOSITORY_NAME = $repository AND MILESTONE_ID IS NOT NULL
|
|
||||||
group by USER_NAME, REPOSITORY_NAME, MILESTONE_ID, CLOSED"""
|
|
||||||
.as[IssueCount]
|
|
||||||
.list
|
|
||||||
.map { x => (x.milestoneId, x.closed) -> x.count }
|
|
||||||
.toMap
|
|
||||||
}
|
|
||||||
|
|
||||||
def getMilestones(owner: String, repository: String): List[Milestone] =
|
|
||||||
Query(Milestones)
|
|
||||||
.filter(m => (m.userName is owner.bind) && (m.repositoryName is repository.bind))
|
|
||||||
.sortBy(_.milestoneId desc)
|
|
||||||
.list
|
|
||||||
|
|
||||||
}
|
}
|
||||||
70
src/main/scala/service/MilestonesService.scala
Normal file
70
src/main/scala/service/MilestonesService.scala
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import scala.slick.driver.H2Driver.simple._
|
||||||
|
import Database.threadLocalSession
|
||||||
|
import scala.slick.jdbc.{StaticQuery => Q}
|
||||||
|
import Q.interpolation
|
||||||
|
|
||||||
|
import model._
|
||||||
|
import Milestones._
|
||||||
|
|
||||||
|
trait MilestonesService {
|
||||||
|
|
||||||
|
def createMilestone(owner: String, repository: String,
|
||||||
|
title: String, description: Option[String], dueDate: Option[java.util.Date]) =
|
||||||
|
Milestones.autoInc insert (owner, repository, title, description, dueDate, None)
|
||||||
|
|
||||||
|
def updateMilestone(milestone: Milestone): Unit =
|
||||||
|
Query(Milestones)
|
||||||
|
.filter { m => (m.userName is milestone.userName.bind) && (m.repositoryName is milestone.repositoryName.bind) && (m.milestoneId is milestone.milestoneId.bind)}
|
||||||
|
.map { m => m.title ~ m.description.? ~ m.dueDate.? ~ m.closedDate.? }
|
||||||
|
.update (
|
||||||
|
milestone.title,
|
||||||
|
milestone.description,
|
||||||
|
milestone.dueDate,
|
||||||
|
milestone.closedDate)
|
||||||
|
|
||||||
|
def openMilestone(milestone: Milestone): Unit = updateMilestone(milestone.copy(closedDate = None))
|
||||||
|
|
||||||
|
def closeMilestone(milestone: Milestone): Unit = updateMilestone(milestone.copy(closedDate = Some(currentDate)))
|
||||||
|
|
||||||
|
def deleteMilestone(owner: String, repository: String, milestoneId: Int): Unit = {
|
||||||
|
Query(Issues)
|
||||||
|
.filter { i => (i.userName is owner.bind) && (i.repositoryName is repository.bind) && (i.milestoneId is milestoneId.bind)}
|
||||||
|
.map { i => i.milestoneId.? }
|
||||||
|
.update(None)
|
||||||
|
|
||||||
|
Query(Milestones)
|
||||||
|
.filter { i => (i.userName is owner.bind) && (i.repositoryName is repository.bind) && (i.milestoneId is milestoneId.bind)}
|
||||||
|
.delete
|
||||||
|
}
|
||||||
|
|
||||||
|
def getMilestone(owner: String, repository: String, milestoneId: Int): Option[Milestone] =
|
||||||
|
Query(Milestones)
|
||||||
|
.filter(m => (m.userName is owner.bind) && (m.repositoryName is repository.bind) && (m.milestoneId is milestoneId.bind))
|
||||||
|
.sortBy(_.milestoneId desc)
|
||||||
|
.firstOption
|
||||||
|
|
||||||
|
def getMilestoneIssueCounts(owner: String, repository: String): Map[(Int, Boolean), Int] = {
|
||||||
|
import scala.slick.jdbc.GetResult
|
||||||
|
|
||||||
|
case class IssueCount(milestoneId: Int, closed: Boolean, count: Int)
|
||||||
|
implicit val getIssueCount = GetResult(r => IssueCount(r.<<, r.<<, r.<<))
|
||||||
|
|
||||||
|
sql"""
|
||||||
|
select MILESTONE_ID, CLOSED, COUNT(ISSUE_ID)
|
||||||
|
from ISSUE
|
||||||
|
where USER_NAME = $owner AND REPOSITORY_NAME = $repository AND MILESTONE_ID IS NOT NULL
|
||||||
|
group by USER_NAME, REPOSITORY_NAME, MILESTONE_ID, CLOSED"""
|
||||||
|
.as[IssueCount]
|
||||||
|
.list
|
||||||
|
.map { x => (x.milestoneId, x.closed) -> x.count }
|
||||||
|
.toMap
|
||||||
|
}
|
||||||
|
|
||||||
|
def getMilestones(owner: String, repository: String): List[Milestone] =
|
||||||
|
Query(Milestones)
|
||||||
|
.filter(m => (m.userName is owner.bind) && (m.repositoryName is repository.bind))
|
||||||
|
.sortBy(_.milestoneId desc)
|
||||||
|
.list
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user