~wegtam/smederee
Showing details for patch a847d84e7fdd3ea2d6695cfc2ec9512fef7f7628.
diff -rN -u old-smederee/modules/hub/src/main/scala/de/smederee/tickets/TicketRoutes.scala new-smederee/modules/hub/src/main/scala/de/smederee/tickets/TicketRoutes.scala --- old-smederee/modules/hub/src/main/scala/de/smederee/tickets/TicketRoutes.scala 2025-01-22 01:20:12.987672948 +0000 +++ new-smederee/modules/hub/src/main/scala/de/smederee/tickets/TicketRoutes.scala 2025-01-22 01:20:12.991672953 +0000 @@ -232,99 +232,107 @@ case ar @ POST -> Root / UsernamePathParameter(projectOwnerName) / ProjectNamePathParameter( projectName ) / "tickets" as user => - ar.req.decodeStrict[F, UrlForm] { urlForm => - val response = - for { - csrf <- Sync[F].delay(ar.req.getCsrfToken) - language <- Sync[F].delay(user.language.getOrElse(LanguageCode("en"))) - projectAndId <- loadProject(user.some)(projectOwnerName, projectName) - resp <- projectAndId match { - case Some((project, projectId)) => - for { - _ <- Sync[F].raiseUnless(project.owner.uid === ProjectOwnerId.fromUserId(user.uid))( - new Error("Only maintainers may add tickets!") - ) - labels <- labelRepo.allLabels(projectId).compile.toList - milestones <- milestoneRepo.allMilestones(projectId).compile.toList - formData <- Sync[F].delay(urlForm.values) - form <- Sync[F].delay(TicketForm.validate(formData)) - projectBaseUri <- Sync[F].delay( - linkConfig.createFullUri( - Uri(path = - Uri.Path( - Vector( - Uri.Path.Segment(s"~$projectOwnerName"), - Uri.Path.Segment(projectName.toString) + ar.req.decodeStrict[F, UrlForm] { + urlForm => + val response = + for { + csrf <- Sync[F].delay(ar.req.getCsrfToken) + language <- Sync[F].delay(user.language.getOrElse(LanguageCode("en"))) + projectAndId <- loadProject(user.some)(projectOwnerName, projectName) + resp <- projectAndId match { + case Some((project, projectId)) => + for { + _ <- Sync[F].raiseUnless( + project.owner.uid === ProjectOwnerId.fromUserId(user.uid) + )( + new Error("Only maintainers may add tickets!") + ) + labels <- labelRepo.allLabels(projectId).compile.toList + milestones <- milestoneRepo.allMilestones(projectId).compile.toList + formData <- Sync[F].delay(urlForm.values) + form <- Sync[F].delay(TicketForm.validate(formData)) + projectBaseUri <- Sync[F].delay( + linkConfig.createFullUri( + Uri(path = + Uri.Path( + Vector( + Uri.Path.Segment(s"~$projectOwnerName"), + Uri.Path.Segment(projectName.toString) + ) ) ) ) ) - ) - pageTitle = genPageTitleBase(projectOwnerName)( - projectName.some - ) |+| " Create a new ticket." - resp <- form match { - case Validated.Invalid(errors) => - BadRequest( - views.html.createTicket(lang = language)( - projectBaseUri.addSegment("tickets"), - csrf, - linkToHubService, - labels, - milestones, - projectBaseUri, - pageTitle.some, - user.some, - project - )(formData.withDefaultValue(Chain.empty), FormErrors.fromNec(errors)) - ) - case Validated.Valid(ticketData) => - for { - timestamp <- Sync[F].delay(OffsetDateTime.now(ZoneOffset.UTC)) - ticketLabels <- ticketData.labels.traverse(name => - labelRepo.findLabel(projectId)(name) - ) - ticketMilestones <- ticketData.milestones.traverse(title => - milestoneRepo.findMilestone(projectId)(title) - ) - number <- projectRepo.incrementNextTicketNumber(projectId) - ticket <- Sync[F].delay( - Ticket( - number = number, - title = ticketData.title, - content = ticketData.content, - status = ticketData.status, - resolution = ticketData.resolution, - submitter = Submitter( - SubmitterId(user.uid.toUUID), - SubmitterName(user.name.toString) - ).some, - createdAt = timestamp, - updatedAt = timestamp + pageTitle = genPageTitleBase(projectOwnerName)( + projectName.some + ) |+| " Create a new ticket." + resp <- form match { + case Validated.Invalid(errors) => + BadRequest( + views.html.createTicket(lang = language)( + projectBaseUri.addSegment("tickets"), + csrf, + linkToHubService, + labels, + milestones, + projectBaseUri, + pageTitle.some, + user.some, + project + )( + formData.withDefaultValue(Chain.empty), + FormErrors.fromNec(errors) ) ) - _ <- ticketRepo.createTicket(projectId)(ticket) - _ <- ticketLabels.flatten.traverse( - ticketRepo.addLabel(projectId)(number) - ) - _ <- ticketMilestones.flatten.traverse( - ticketRepo.addMilestone(projectId)(number) - ) - resp <- SeeOther(Location(projectBaseUri.addSegment("tickets"))) - } yield resp - } - } yield resp - case _ => NotFound() - } + case Validated.Valid(ticketData) => + for { + timestamp <- Sync[F].delay(OffsetDateTime.now(ZoneOffset.UTC)) + ticketLabels <- ticketData.labels.traverse(name => + labelRepo.findLabel(projectId)(name) + ) + ticketMilestones <- ticketData.milestones.traverse(title => + milestoneRepo.findMilestone(projectId)(title) + ) + number <- projectRepo.incrementNextTicketNumber(projectId) + ticket <- Sync[F].delay( + Ticket( + number = number, + title = ticketData.title, + content = ticketData.content, + status = ticketData.status, + resolution = ticketData.resolution, + submitter = Submitter( + SubmitterId(user.uid.toUUID), + SubmitterName(user.name.toString) + ).some, + createdAt = timestamp, + updatedAt = timestamp + ) + ) + _ <- ticketRepo.createTicket(projectId)(ticket) + _ <- ticketLabels.flatten.traverse( + ticketRepo.addLabel(projectId)(number) + ) + _ <- ticketMilestones.flatten.traverse( + ticketRepo.addMilestone(projectId)(number) + ) + resp <- SeeOther(Location(projectBaseUri.addSegment("tickets"))) + } yield resp + } + } yield resp + case _ => NotFound() + } + } yield resp + response.recoverWith { error => + log.error("Internal Server Error", error) + for { + csrf <- Sync[F].delay(ar.req.getCsrfToken) + language <- Sync[F].delay(user.language.getOrElse(LanguageCode("en"))) + resp <- InternalServerError( + views.html.errors.internalServerError(lang = language)(csrf, user.some) + ) } yield resp - response.recoverWith { error => - log.error("Internal Server Error", error) - for { - csrf <- Sync[F].delay(ar.req.getCsrfToken) - language <- Sync[F].delay(user.language.getOrElse(LanguageCode("en"))) - resp <- InternalServerError(views.html.errors.internalServerError(lang = language)(csrf, user.some)) - } yield resp - } + } } } @@ -332,111 +340,119 @@ case ar @ POST -> Root / UsernamePathParameter(projectOwnerName) / ProjectNamePathParameter( projectName ) / "tickets" / TicketNumberPathParameter(ticketNumber) as user => - ar.req.decodeStrict[F, UrlForm] { urlForm => - val response = - for { - csrf <- Sync[F].delay(ar.req.getCsrfToken) - language <- Sync[F].delay(user.language.getOrElse(LanguageCode("en"))) - projectAndId <- loadProject(user.some)(projectOwnerName, projectName) - ticket <- projectAndId.traverse(tuple => ticketRepo.findTicket(tuple._2)(ticketNumber)) - resp <- (projectAndId, ticket.getOrElse(None)) match { - case (Some((project, projectId)), Some(ticket)) => - for { - _ <- Sync[F].raiseUnless(project.owner.uid === ProjectOwnerId.fromUserId(user.uid))( - new Error("Only maintainers may edit tickets!") - ) - labels <- labelRepo.allLabels(projectId).compile.toList - milestones <- milestoneRepo.allMilestones(projectId).compile.toList - formData <- Sync[F].delay(urlForm.values) - form <- Sync[F].delay(TicketForm.validate(formData)) - projectBaseUri <- Sync[F].delay( - linkConfig.createFullUri( - Uri(path = - Uri.Path( - Vector( - Uri.Path.Segment(s"~$projectOwnerName"), - Uri.Path.Segment(projectName.toString) + ar.req.decodeStrict[F, UrlForm] { + urlForm => + val response = + for { + csrf <- Sync[F].delay(ar.req.getCsrfToken) + language <- Sync[F].delay(user.language.getOrElse(LanguageCode("en"))) + projectAndId <- loadProject(user.some)(projectOwnerName, projectName) + ticket <- projectAndId.traverse(tuple => ticketRepo.findTicket(tuple._2)(ticketNumber)) + resp <- (projectAndId, ticket.getOrElse(None)) match { + case (Some((project, projectId)), Some(ticket)) => + for { + _ <- Sync[F].raiseUnless( + project.owner.uid === ProjectOwnerId.fromUserId(user.uid) + )( + new Error("Only maintainers may edit tickets!") + ) + labels <- labelRepo.allLabels(projectId).compile.toList + milestones <- milestoneRepo.allMilestones(projectId).compile.toList + formData <- Sync[F].delay(urlForm.values) + form <- Sync[F].delay(TicketForm.validate(formData)) + projectBaseUri <- Sync[F].delay( + linkConfig.createFullUri( + Uri(path = + Uri.Path( + Vector( + Uri.Path.Segment(s"~$projectOwnerName"), + Uri.Path.Segment(projectName.toString) + ) ) ) ) ) - ) - pageTitle = genPageTitleBase(projectOwnerName)( - projectName.some - ) |+| " Create a new ticket." - resp <- form match { - case Validated.Invalid(errors) => - BadRequest( - views.html.createTicket(lang = language)( - projectBaseUri.addSegment("tickets"), - csrf, - linkToHubService, - labels, - milestones, - projectBaseUri, - pageTitle.some, - user.some, - project - )(formData.withDefaultValue(Chain.empty), FormErrors.fromNec(errors)) - ) - case Validated.Valid(ticketData) => - for { - timestamp <- Sync[F].delay(OffsetDateTime.now(ZoneOffset.UTC)) - oldLabels <- ticketRepo - .loadLabels(projectId)(ticket.number) - .compile - .toList - oldMilestones <- ticketRepo - .loadMilestones(projectId)(ticket.number) - .compile - .toList - ticketLabels <- ticketData.labels.traverse(name => - labelRepo.findLabel(projectId)(name) - ) - ticketMilestones <- ticketData.milestones.traverse(title => - milestoneRepo.findMilestone(projectId)(title) - ) - labelsToCreate = ticketLabels.flatten.diff(oldLabels) - labelsToRemove = oldLabels.diff(ticketLabels.flatten) - milestonesToCreate = ticketMilestones.flatten.diff(oldMilestones) - milestonesToRemove = oldMilestones.diff(ticketMilestones.flatten) - updatedTicket = - ticket.copy( - title = ticketData.title, - content = ticketData.content, - status = ticketData.status, - resolution = ticketData.resolution, - createdAt = ticket.createdAt, - updatedAt = timestamp - ) - _ <- ticketRepo.updateTicket(projectId)(updatedTicket) - _ <- labelsToRemove.traverse( - ticketRepo.removeLabel(projectId)(updatedTicket) - ) - _ <- milestonesToRemove.traverse( - ticketRepo.removeMilestone(projectId)(updatedTicket) - ) - _ <- labelsToCreate.traverse( - ticketRepo.addLabel(projectId)(ticket.number) - ) - _ <- milestonesToCreate.traverse( - ticketRepo.addMilestone(projectId)(ticket.number) + pageTitle = genPageTitleBase(projectOwnerName)( + projectName.some + ) |+| " Create a new ticket." + resp <- form match { + case Validated.Invalid(errors) => + BadRequest( + views.html.createTicket(lang = language)( + projectBaseUri.addSegment("tickets"), + csrf, + linkToHubService, + labels, + milestones, + projectBaseUri, + pageTitle.some, + user.some, + project + )( + formData.withDefaultValue(Chain.empty), + FormErrors.fromNec(errors) + ) ) - resp <- SeeOther(Location(projectBaseUri.addSegment("tickets"))) - } yield resp - } - } yield resp - case _ => NotFound() - } + case Validated.Valid(ticketData) => + for { + timestamp <- Sync[F].delay(OffsetDateTime.now(ZoneOffset.UTC)) + oldLabels <- ticketRepo + .loadLabels(projectId)(ticket.number) + .compile + .toList + oldMilestones <- ticketRepo + .loadMilestones(projectId)(ticket.number) + .compile + .toList + ticketLabels <- ticketData.labels.traverse(name => + labelRepo.findLabel(projectId)(name) + ) + ticketMilestones <- ticketData.milestones.traverse(title => + milestoneRepo.findMilestone(projectId)(title) + ) + labelsToCreate = ticketLabels.flatten.diff(oldLabels) + labelsToRemove = oldLabels.diff(ticketLabels.flatten) + milestonesToCreate = ticketMilestones.flatten.diff(oldMilestones) + milestonesToRemove = oldMilestones.diff(ticketMilestones.flatten) + updatedTicket = + ticket.copy( + title = ticketData.title, + content = ticketData.content, + status = ticketData.status, + resolution = ticketData.resolution, + createdAt = ticket.createdAt, + updatedAt = timestamp + ) + _ <- ticketRepo.updateTicket(projectId)(updatedTicket) + _ <- labelsToRemove.traverse( + ticketRepo.removeLabel(projectId)(updatedTicket) + ) + _ <- milestonesToRemove.traverse( + ticketRepo.removeMilestone(projectId)(updatedTicket) + ) + _ <- labelsToCreate.traverse( + ticketRepo.addLabel(projectId)(ticket.number) + ) + _ <- milestonesToCreate.traverse( + ticketRepo.addMilestone(projectId)(ticket.number) + ) + resp <- SeeOther(Location(projectBaseUri.addSegment("tickets"))) + } yield resp + } + } yield resp + case _ => NotFound() + } + } yield resp + response.recoverWith { error => + log.error("Internal Server Error", error) + for { + csrf <- Sync[F].delay(ar.req.getCsrfToken) + language <- Sync[F].delay(user.language.getOrElse(LanguageCode("en"))) + resp <- InternalServerError( + views.html.errors.internalServerError(lang = language)(csrf, user.some) + ) } yield resp - response.recoverWith { error => - log.error("Internal Server Error", error) - for { - csrf <- Sync[F].delay(ar.req.getCsrfToken) - language <- Sync[F].delay(user.language.getOrElse(LanguageCode("en"))) - resp <- InternalServerError(views.html.errors.internalServerError(lang = language)(csrf, user.some)) - } yield resp - } + } } } diff -rN -u old-smederee/modules/hub/src/test/scala/de/smederee/hub/DoobieVcsMetadataRepositoryTest.scala new-smederee/modules/hub/src/test/scala/de/smederee/hub/DoobieVcsMetadataRepositoryTest.scala --- old-smederee/modules/hub/src/test/scala/de/smederee/hub/DoobieVcsMetadataRepositoryTest.scala 2025-01-22 01:20:12.987672948 +0000 +++ new-smederee/modules/hub/src/test/scala/de/smederee/hub/DoobieVcsMetadataRepositoryTest.scala 2025-01-22 01:20:12.991672953 +0000 @@ -197,17 +197,18 @@ } test("findVcsRepositoryBranches must return all branches".tag(NeedsDatabase)) { - PropF.forAllF { (accounts: NonEmptyList[Account], repositories: NonEmptyList[VcsRepository]) => - val vcsRepositories = accounts.zip(repositories).map { tuple => - val (account, repo) = tuple - repo.copy(owner = account.toVcsRepositoryOwner) - } - val numberOfForks = - if ((vcsRepositories.tail.size / 2) > 5) { - 5 - } else { - vcsRepositories.tail.size / 2 - } + PropF.forAllF { + (accounts: NonEmptyList[Account], repositories: NonEmptyList[VcsRepository]) => + val vcsRepositories = accounts.zip(repositories).map { tuple => + val (account, repo) = tuple + repo.copy(owner = account.toVcsRepositoryOwner) + } + val numberOfForks = + if ((vcsRepositories.tail.size / 2) > 5) { + 5 + } else { + vcsRepositories.tail.size / 2 + } val dbConfig = configuration.database val tx = Transactor.fromDriverManager[IO]( driver = dbConfig.driver, @@ -311,17 +312,18 @@ } test("findVcsRepositoryParentFork must return the parent repository if it exists".tag(NeedsDatabase)) { - PropF.forAllF { (accounts: NonEmptyList[Account], repositories: NonEmptyList[VcsRepository]) => - val vcsRepositories = accounts.zip(repositories).map { tuple => - val (account, repo) = tuple - repo.copy(owner = account.toVcsRepositoryOwner) - } - val numberOfForks = - if ((vcsRepositories.tail.size / 2) > 5) { - 5 - } else { - vcsRepositories.tail.size / 2 - } + PropF.forAllF { + (accounts: NonEmptyList[Account], repositories: NonEmptyList[VcsRepository]) => + val vcsRepositories = accounts.zip(repositories).map { tuple => + val (account, repo) = tuple + repo.copy(owner = account.toVcsRepositoryOwner) + } + val numberOfForks = + if ((vcsRepositories.tail.size / 2) > 5) { + 5 + } else { + vcsRepositories.tail.size / 2 + } val dbConfig = configuration.database val tx = Transactor.fromDriverManager[IO]( driver = dbConfig.driver, diff -rN -u old-smederee/.scalafmt.conf new-smederee/.scalafmt.conf --- old-smederee/.scalafmt.conf 2025-01-22 01:20:12.987672948 +0000 +++ new-smederee/.scalafmt.conf 2025-01-22 01:20:12.987672948 +0000 @@ -1,4 +1,4 @@ -version = "3.8.3" +version = "3.8.4" runner.dialect = scala3 style = "defaultWithAlign" # Other options...