29 import de.uapcore.lightpit.HttpRequest |
29 import de.uapcore.lightpit.HttpRequest |
30 import de.uapcore.lightpit.boolValidator |
30 import de.uapcore.lightpit.boolValidator |
31 import de.uapcore.lightpit.dao.DataAccessObject |
31 import de.uapcore.lightpit.dao.DataAccessObject |
32 import de.uapcore.lightpit.dateOptValidator |
32 import de.uapcore.lightpit.dateOptValidator |
33 import de.uapcore.lightpit.entities.* |
33 import de.uapcore.lightpit.entities.* |
34 import de.uapcore.lightpit.types.IssueCategory |
34 import de.uapcore.lightpit.types.* |
35 import de.uapcore.lightpit.types.IssueStatus |
|
36 import de.uapcore.lightpit.types.VersionStatus |
|
37 import de.uapcore.lightpit.types.WebColor |
|
38 import de.uapcore.lightpit.viewmodel.* |
35 import de.uapcore.lightpit.viewmodel.* |
39 import jakarta.servlet.annotation.WebServlet |
36 import jakarta.servlet.annotation.WebServlet |
40 import java.sql.Date |
37 import java.sql.Date |
41 |
38 |
42 @WebServlet(urlPatterns = ["/projects/*"]) |
39 @WebServlet(urlPatterns = ["/projects/*"]) |
61 post("/%project/components/-/commit", this::componentCommit) |
58 post("/%project/components/-/commit", this::componentCommit) |
62 |
59 |
63 get("/%project/issues/%version/%component/%issue", this::issue) |
60 get("/%project/issues/%version/%component/%issue", this::issue) |
64 get("/%project/issues/%version/%component/%issue/edit", this::issueForm) |
61 get("/%project/issues/%version/%component/%issue/edit", this::issueForm) |
65 post("/%project/issues/%version/%component/%issue/comment", this::issueComment) |
62 post("/%project/issues/%version/%component/%issue/comment", this::issueComment) |
|
63 post("/%project/issues/%version/%component/%issue/relation", this::issueRelation) |
|
64 get("/%project/issues/%version/%component/%issue/removeRelation", this::issueRemoveRelation) |
66 get("/%project/issues/%version/%component/-/create", this::issueForm) |
65 get("/%project/issues/%version/%component/-/create", this::issueForm) |
67 post("/%project/issues/%version/%component/-/commit", this::issueCommit) |
66 post("/%project/issues/%version/%component/-/commit", this::issueCommit) |
68 } |
67 } |
69 |
68 |
70 private fun projects(http: HttpRequest, dao: DataAccessObject) { |
69 private fun projects(http: HttpRequest, dao: DataAccessObject) { |
438 |
437 |
439 http.renderCommit("projects/${project.node}/components/") |
438 http.renderCommit("projects/${project.node}/components/") |
440 } |
439 } |
441 |
440 |
442 private fun issue(http: HttpRequest, dao: DataAccessObject) { |
441 private fun issue(http: HttpRequest, dao: DataAccessObject) { |
|
442 val issue = http.pathParams["issue"]?.toIntOrNull()?.let(dao::findIssue) |
|
443 if (issue == null) { |
|
444 http.response.sendError(404) |
|
445 return |
|
446 } |
|
447 renderIssueView(http, dao, issue) |
|
448 } |
|
449 |
|
450 private fun renderIssueView( |
|
451 http: HttpRequest, |
|
452 dao: DataAccessObject, |
|
453 issue: Issue, |
|
454 relationError: String? = null |
|
455 ) { |
443 withPathInfo(http, dao)?.run { |
456 withPathInfo(http, dao)?.run { |
444 val issue = dao.findIssue(http.pathParams["issue"]?.toIntOrNull() ?: -1) |
|
445 if (issue == null) { |
|
446 http.response.sendError(404) |
|
447 return |
|
448 } |
|
449 |
|
450 val comments = dao.listComments(issue) |
457 val comments = dao.listComments(issue) |
451 |
458 |
452 with(http) { |
459 with(http) { |
453 pageTitle = "${projectInfo.project.name}: #${issue.id} ${issue.subject}" |
460 pageTitle = "${projectInfo.project.name}: #${issue.id} ${issue.subject}" |
454 view = IssueDetailView(issue, comments, project, version, component) |
461 view = IssueDetailView( |
|
462 issue, |
|
463 comments, |
|
464 project, |
|
465 version, |
|
466 component, |
|
467 dao.listIssues(project), |
|
468 dao.listIssueRelations(issue), |
|
469 relationError |
|
470 ) |
455 feedPath = feedPath(projectInfo.project) |
471 feedPath = feedPath(projectInfo.project) |
456 navigationMenu = activeProjectNavMenu( |
472 navigationMenu = activeProjectNavMenu( |
457 dao.listProjects(), |
473 dao.listProjects(), |
458 projectInfo, |
474 projectInfo, |
459 version, |
475 version, |
466 } |
482 } |
467 } |
483 } |
468 |
484 |
469 private fun issueForm(http: HttpRequest, dao: DataAccessObject) { |
485 private fun issueForm(http: HttpRequest, dao: DataAccessObject) { |
470 withPathInfo(http, dao)?.run { |
486 withPathInfo(http, dao)?.run { |
471 val issue = dao.findIssue(http.pathParams["issue"]?.toIntOrNull() ?: -1) ?: Issue( |
487 val issue = http.pathParams["issue"]?.toIntOrNull()?.let(dao::findIssue) ?: Issue( |
472 -1, |
488 -1, |
473 project, |
489 project, |
474 ) |
490 ) |
475 |
491 |
476 // for new issues set some defaults |
492 // for new issues set some defaults |
512 } |
528 } |
513 } |
529 } |
514 |
530 |
515 private fun issueComment(http: HttpRequest, dao: DataAccessObject) { |
531 private fun issueComment(http: HttpRequest, dao: DataAccessObject) { |
516 withPathInfo(http, dao)?.run { |
532 withPathInfo(http, dao)?.run { |
517 val issue = dao.findIssue(http.pathParams["issue"]?.toIntOrNull() ?: -1) |
533 val issue = http.pathParams["issue"]?.toIntOrNull()?.let(dao::findIssue) |
518 if (issue == null) { |
534 if (issue == null) { |
519 http.response.sendError(404) |
535 http.response.sendError(404) |
520 return |
536 return |
521 } |
537 } |
522 |
538 |
614 } else { |
630 } else { |
615 http.renderCommit("${issuesHref}${openId}") |
631 http.renderCommit("${issuesHref}${openId}") |
616 } |
632 } |
617 } |
633 } |
618 } |
634 } |
|
635 |
|
636 private fun issueRelation(http: HttpRequest, dao: DataAccessObject) { |
|
637 withPathInfo(http, dao)?.run { |
|
638 val issue = http.pathParams["issue"]?.toIntOrNull()?.let(dao::findIssue) |
|
639 if (issue == null) { |
|
640 http.response.sendError(404) |
|
641 return |
|
642 } |
|
643 |
|
644 // determine the relation type |
|
645 val type: Pair<RelationType, Boolean>? = http.param("type")?.let { |
|
646 try { |
|
647 if (it.startsWith("!")) { |
|
648 Pair(RelationType.valueOf(it.substring(1)), true) |
|
649 } else { |
|
650 Pair(RelationType.valueOf(it), false) |
|
651 } |
|
652 } catch (_: IllegalArgumentException) { |
|
653 null |
|
654 } |
|
655 } |
|
656 |
|
657 // if the relation type was invalid, send HTTP 500 |
|
658 if (type == null) { |
|
659 http.response.sendError(500) |
|
660 return |
|
661 } |
|
662 |
|
663 // determine the target issue |
|
664 val targetIssue: Issue? = http.param("issue")?.let { |
|
665 if (it.startsWith("#") && it.length > 1) { |
|
666 it.substring(1).split(" ", limit = 2)[0].toIntOrNull() |
|
667 ?.let(dao::findIssue) |
|
668 ?.takeIf { target -> target.project.id == issue.project.id } |
|
669 } else { |
|
670 null |
|
671 } |
|
672 } |
|
673 |
|
674 // check if the target issue is valid |
|
675 if (targetIssue == null) { |
|
676 renderIssueView(http, dao, issue, "issue.relations.target.invalid") |
|
677 return |
|
678 } |
|
679 |
|
680 // commit the result |
|
681 dao.insertIssueRelation(IssueRelation(issue, targetIssue, type.first, type.second)) |
|
682 http.renderCommit("${issuesHref}${issue.id}") |
|
683 } |
|
684 } |
|
685 |
|
686 private fun issueRemoveRelation(http: HttpRequest, dao: DataAccessObject) { |
|
687 withPathInfo(http, dao)?.run { |
|
688 val issue = http.pathParams["issue"]?.toIntOrNull()?.let(dao::findIssue) |
|
689 if (issue == null) { |
|
690 http.response.sendError(404) |
|
691 return |
|
692 } |
|
693 |
|
694 // determine relation |
|
695 val type = http.param("type")?.let { |
|
696 try {RelationType.valueOf(it)} |
|
697 catch (_:IllegalArgumentException) {null} |
|
698 } |
|
699 if (type == null) { |
|
700 http.response.sendError(500) |
|
701 return |
|
702 } |
|
703 val rel = http.param("to")?.toIntOrNull()?.let(dao::findIssue)?.let { |
|
704 IssueRelation( |
|
705 issue, |
|
706 it, |
|
707 type, |
|
708 http.param("reverse")?.toBoolean() ?: false |
|
709 ) |
|
710 } |
|
711 |
|
712 // execute removal, if there is something to remove |
|
713 rel?.run(dao::deleteIssueRelation) |
|
714 |
|
715 // always pretend that the operation was successful - if there was nothing to remove, it's okay |
|
716 http.renderCommit("${issuesHref}${issue.id}") |
|
717 } |
|
718 } |
619 } |
719 } |