src/main/kotlin/de/uapcore/lightpit/servlet/ProjectServlet.kt

changeset 263
aa22103809cd
parent 254
55ca6cafc3dd
child 265
6a21bb926e02
     1.1 --- a/src/main/kotlin/de/uapcore/lightpit/servlet/ProjectServlet.kt	Fri Dec 30 13:21:09 2022 +0100
     1.2 +++ b/src/main/kotlin/de/uapcore/lightpit/servlet/ProjectServlet.kt	Fri Dec 30 19:04:34 2022 +0100
     1.3 @@ -31,10 +31,7 @@
     1.4  import de.uapcore.lightpit.dao.DataAccessObject
     1.5  import de.uapcore.lightpit.dateOptValidator
     1.6  import de.uapcore.lightpit.entities.*
     1.7 -import de.uapcore.lightpit.types.IssueCategory
     1.8 -import de.uapcore.lightpit.types.IssueStatus
     1.9 -import de.uapcore.lightpit.types.VersionStatus
    1.10 -import de.uapcore.lightpit.types.WebColor
    1.11 +import de.uapcore.lightpit.types.*
    1.12  import de.uapcore.lightpit.viewmodel.*
    1.13  import jakarta.servlet.annotation.WebServlet
    1.14  import java.sql.Date
    1.15 @@ -63,6 +60,8 @@
    1.16          get("/%project/issues/%version/%component/%issue", this::issue)
    1.17          get("/%project/issues/%version/%component/%issue/edit", this::issueForm)
    1.18          post("/%project/issues/%version/%component/%issue/comment", this::issueComment)
    1.19 +        post("/%project/issues/%version/%component/%issue/relation", this::issueRelation)
    1.20 +        get("/%project/issues/%version/%component/%issue/removeRelation", this::issueRemoveRelation)
    1.21          get("/%project/issues/%version/%component/-/create", this::issueForm)
    1.22          post("/%project/issues/%version/%component/-/commit", this::issueCommit)
    1.23      }
    1.24 @@ -440,18 +439,35 @@
    1.25      }
    1.26  
    1.27      private fun issue(http: HttpRequest, dao: DataAccessObject) {
    1.28 +        val issue = http.pathParams["issue"]?.toIntOrNull()?.let(dao::findIssue)
    1.29 +        if (issue == null) {
    1.30 +            http.response.sendError(404)
    1.31 +            return
    1.32 +        }
    1.33 +        renderIssueView(http, dao, issue)
    1.34 +    }
    1.35 +
    1.36 +    private fun renderIssueView(
    1.37 +        http: HttpRequest,
    1.38 +        dao: DataAccessObject,
    1.39 +        issue: Issue,
    1.40 +        relationError: String? = null
    1.41 +    ) {
    1.42          withPathInfo(http, dao)?.run {
    1.43 -            val issue = dao.findIssue(http.pathParams["issue"]?.toIntOrNull() ?: -1)
    1.44 -            if (issue == null) {
    1.45 -                http.response.sendError(404)
    1.46 -                return
    1.47 -            }
    1.48 -
    1.49              val comments = dao.listComments(issue)
    1.50  
    1.51              with(http) {
    1.52                  pageTitle = "${projectInfo.project.name}: #${issue.id} ${issue.subject}"
    1.53 -                view = IssueDetailView(issue, comments, project, version, component)
    1.54 +                view = IssueDetailView(
    1.55 +                    issue,
    1.56 +                    comments,
    1.57 +                    project,
    1.58 +                    version,
    1.59 +                    component,
    1.60 +                    dao.listIssues(project),
    1.61 +                    dao.listIssueRelations(issue),
    1.62 +                    relationError
    1.63 +                )
    1.64                  feedPath = feedPath(projectInfo.project)
    1.65                  navigationMenu = activeProjectNavMenu(
    1.66                      dao.listProjects(),
    1.67 @@ -468,7 +484,7 @@
    1.68  
    1.69      private fun issueForm(http: HttpRequest, dao: DataAccessObject) {
    1.70          withPathInfo(http, dao)?.run {
    1.71 -            val issue = dao.findIssue(http.pathParams["issue"]?.toIntOrNull() ?: -1) ?: Issue(
    1.72 +            val issue = http.pathParams["issue"]?.toIntOrNull()?.let(dao::findIssue) ?: Issue(
    1.73                  -1,
    1.74                  project,
    1.75              )
    1.76 @@ -514,7 +530,7 @@
    1.77  
    1.78      private fun issueComment(http: HttpRequest, dao: DataAccessObject) {
    1.79          withPathInfo(http, dao)?.run {
    1.80 -            val issue = dao.findIssue(http.pathParams["issue"]?.toIntOrNull() ?: -1)
    1.81 +            val issue = http.pathParams["issue"]?.toIntOrNull()?.let(dao::findIssue)
    1.82              if (issue == null) {
    1.83                  http.response.sendError(404)
    1.84                  return
    1.85 @@ -616,4 +632,88 @@
    1.86              }
    1.87          }
    1.88      }
    1.89 +
    1.90 +    private fun issueRelation(http: HttpRequest, dao: DataAccessObject) {
    1.91 +        withPathInfo(http, dao)?.run {
    1.92 +            val issue = http.pathParams["issue"]?.toIntOrNull()?.let(dao::findIssue)
    1.93 +            if (issue == null) {
    1.94 +                http.response.sendError(404)
    1.95 +                return
    1.96 +            }
    1.97 +            
    1.98 +            // determine the relation type
    1.99 +            val type: Pair<RelationType, Boolean>? = http.param("type")?.let {
   1.100 +                try {
   1.101 +                    if (it.startsWith("!")) {
   1.102 +                        Pair(RelationType.valueOf(it.substring(1)), true)
   1.103 +                    } else {
   1.104 +                        Pair(RelationType.valueOf(it), false)
   1.105 +                    }
   1.106 +                } catch (_: IllegalArgumentException) {
   1.107 +                    null
   1.108 +                }
   1.109 +            }
   1.110 +            
   1.111 +            // if the relation type was invalid, send HTTP 500
   1.112 +            if (type == null) {
   1.113 +                http.response.sendError(500)
   1.114 +                return
   1.115 +            }
   1.116 +            
   1.117 +            // determine the target issue
   1.118 +            val targetIssue: Issue? = http.param("issue")?.let {
   1.119 +                if (it.startsWith("#") && it.length > 1) {
   1.120 +                    it.substring(1).split(" ", limit = 2)[0].toIntOrNull()
   1.121 +                        ?.let(dao::findIssue)
   1.122 +                        ?.takeIf { target -> target.project.id == issue.project.id }
   1.123 +                } else {
   1.124 +                    null
   1.125 +                }
   1.126 +            }
   1.127 +
   1.128 +            // check if the target issue is valid
   1.129 +            if (targetIssue == null) {
   1.130 +                renderIssueView(http, dao, issue, "issue.relations.target.invalid")
   1.131 +                return
   1.132 +            }
   1.133 +            
   1.134 +            // commit the result
   1.135 +            dao.insertIssueRelation(IssueRelation(issue, targetIssue, type.first, type.second))
   1.136 +            http.renderCommit("${issuesHref}${issue.id}")
   1.137 +        }
   1.138 +    }
   1.139 +
   1.140 +    private fun issueRemoveRelation(http: HttpRequest, dao: DataAccessObject) {
   1.141 +        withPathInfo(http, dao)?.run {
   1.142 +            val issue = http.pathParams["issue"]?.toIntOrNull()?.let(dao::findIssue)
   1.143 +            if (issue == null) {
   1.144 +                http.response.sendError(404)
   1.145 +                return
   1.146 +            }
   1.147 +
   1.148 +            // determine relation
   1.149 +            val type = http.param("type")?.let {
   1.150 +                try {RelationType.valueOf(it)}
   1.151 +                catch (_:IllegalArgumentException) {null}
   1.152 +            }
   1.153 +            if (type == null) {
   1.154 +                http.response.sendError(500)
   1.155 +                return
   1.156 +            }
   1.157 +            val rel = http.param("to")?.toIntOrNull()?.let(dao::findIssue)?.let {
   1.158 +                IssueRelation(
   1.159 +                    issue,
   1.160 +                    it,
   1.161 +                    type,
   1.162 +                    http.param("reverse")?.toBoolean() ?: false
   1.163 +                )
   1.164 +            }
   1.165 +
   1.166 +            // execute removal, if there is something to remove
   1.167 +            rel?.run(dao::deleteIssueRelation)
   1.168 +
   1.169 +            // always pretend that the operation was successful - if there was nothing to remove, it's okay
   1.170 +            http.renderCommit("${issuesHref}${issue.id}")
   1.171 +        }
   1.172 +    }
   1.173  }
   1.174 \ No newline at end of file

mercurial