diff --git a/src/main/scala/gitbucket/core/api/CreateAMilestone.scala b/src/main/scala/gitbucket/core/api/CreateAMilestone.scala new file mode 100644 index 0000000..39cdc60 --- /dev/null +++ b/src/main/scala/gitbucket/core/api/CreateAMilestone.scala @@ -0,0 +1,14 @@ +package gitbucket.core.api + +import java.util.Date + +case class CreateAMilestone( + title: String, + state: String = "open", + description: Option[String], + due_on: Option[Date] +) { + def isValid: Boolean = { + title.length <= 100 && title.matches("[a-zA-Z0-9\\-\\+_.]+") + } +} diff --git a/src/main/scala/gitbucket/core/controller/api/ApiIssueMilestoneControllerBase.scala b/src/main/scala/gitbucket/core/controller/api/ApiIssueMilestoneControllerBase.scala index 5b38a58..7de096b 100644 --- a/src/main/scala/gitbucket/core/controller/api/ApiIssueMilestoneControllerBase.scala +++ b/src/main/scala/gitbucket/core/controller/api/ApiIssueMilestoneControllerBase.scala @@ -1,7 +1,9 @@ package gitbucket.core.controller.api import gitbucket.core.api._ import gitbucket.core.controller.ControllerBase +import gitbucket.core.model.Repository import gitbucket.core.service.MilestonesService +import gitbucket.core.service.RepositoryService.RepositoryInfo import gitbucket.core.util.{ReferrerAuthenticator, WritableUsersAuthenticator} import gitbucket.core.util.Implicits._ import org.scalatra.NoContent @@ -41,6 +43,21 @@ * ii. Create a milestone * https://docs.github.com/en/rest/reference/issues#create-a-milestone */ + post("/api/v3/repos/:owner/:repository/milestones")(writableUsersOnly { repository => + (for { + data <- extractFromJsonBody[CreateAMilestone] if data.isValid + milestoneId = createMilestone( + repository.owner, + repository.name, + data.title, + data.description, + data.due_on + ) + apiMilestone <- getApiMilestone(repository, milestoneId) + } yield { + JsonFormat(apiMilestone) + }) getOrElse NotFound() + }) /* * iii. Get a milestone @@ -48,26 +65,34 @@ */ get("/api/v3/repos/:owner/:repository/milestones/:number")(referrersOnly { repository => val milestoneId = params("number").toInt // use milestoneId as number - getMilestonesWithIssueCount(repository.owner, repository.name) - .find(p => p._1.milestoneId == milestoneId) match { - case Some(milestoneWithIssue) => - JsonFormat( - ApiMilestone( - repository.repository, - milestoneWithIssue._1, - ApiUser(context.loginAccount.get), - milestoneWithIssue._2, - milestoneWithIssue._3 - ) - ) - case _ => NotFound() - } + (for (apiMilestone <- getApiMilestone(repository, milestoneId)) yield { + JsonFormat(apiMilestone) + }) getOrElse NotFound() }) /* * iv.Update a milestone * https://docs.github.com/en/rest/reference/issues#update-a-milestone */ + patch("/api/v3/repos/:owner/:repository/milestones/:number")(writableUsersOnly { repository => + val milestoneId = params("number").toInt + (for { + data <- extractFromJsonBody[CreateAMilestone] if data.isValid + milestone <- getMilestone(repository.owner, repository.name, milestoneId) + _ = (data.state, milestone.closedDate) match { + case ("open", Some(_)) => + openMilestone(milestone) + case ("closed", None) => + closeMilestone(milestone) + case _ => + } + milestone <- getMilestone(repository.owner, repository.name, milestoneId) + _ = updateMilestone(milestone.copy(title = data.title, description = data.description, dueDate = data.due_on)) + apiMilestone <- getApiMilestone(repository, milestoneId) + } yield { + JsonFormat(apiMilestone) + }) getOrElse NotFound() + }) /* * v. Delete a milestone @@ -78,4 +103,19 @@ deleteMilestone(repository.owner, repository.name, milestoneId) NoContent() }) + + private def getApiMilestone(repository: RepositoryInfo, milestoneId: Int): Option[ApiMilestone] = { + getMilestonesWithIssueCount(repository.owner, repository.name) + .find(p => p._1.milestoneId == milestoneId) + .map( + milestoneWithIssue => + ApiMilestone( + repository.repository, + milestoneWithIssue._1, + ApiUser(context.loginAccount.get), + milestoneWithIssue._2, + milestoneWithIssue._3 + ) + ) + } } diff --git a/src/main/scala/gitbucket/core/service/MilestonesService.scala b/src/main/scala/gitbucket/core/service/MilestonesService.scala index ae1ce1e..f5f9849 100644 --- a/src/main/scala/gitbucket/core/service/MilestonesService.scala +++ b/src/main/scala/gitbucket/core/service/MilestonesService.scala @@ -13,8 +13,8 @@ title: String, description: Option[String], dueDate: Option[java.util.Date] - )(implicit s: Session): Unit = - Milestones insert Milestone( + )(implicit s: Session): Int = { + Milestones returning Milestones.map(_.milestoneId) insert Milestone( userName = owner, repositoryName = repository, title = title, @@ -22,6 +22,7 @@ dueDate = dueDate, closedDate = None ) + } def updateMilestone(milestone: Milestone)(implicit s: Session): Unit = Milestones