fixes #882 - wrong redirect after version/component/variant form

Thu, 11 Jun 2026 16:01:47 +0200

author
Mike Becker <universe@uap-core.de>
date
Thu, 11 Jun 2026 16:01:47 +0200
changeset 428
89ec560a97cb
parent 427
4124102c2f37
child 429
349c03df471f

fixes #882 - wrong redirect after version/component/variant form

src/main/kotlin/de/uapcore/lightpit/servlet/ProjectServlet.kt file | annotate | diff | comparison | revisions
src/main/webapp/WEB-INF/changelogs/changelog-de.jspf file | annotate | diff | comparison | revisions
src/main/webapp/WEB-INF/changelogs/changelog.jspf file | annotate | diff | comparison | revisions
--- a/src/main/kotlin/de/uapcore/lightpit/servlet/ProjectServlet.kt	Thu Jun 11 14:54:23 2026 +0200
+++ b/src/main/kotlin/de/uapcore/lightpit/servlet/ProjectServlet.kt	Thu Jun 11 16:01:47 2026 +0200
@@ -190,6 +190,48 @@
         }
     }
 
+    private fun obtainIdAndProject(http: HttpRequest, dao: DataAccessObject): Pair<Int, Project>? {
+        val id = http.param("id")?.toIntOrNull()
+        val projectid = http.param("projectid")?.toIntOrNull() ?: -1
+        val project = dao.findProject(projectid)
+        return if (id == null || project == null) {
+            http.response.sendError(400)
+            null
+        } else {
+            Pair(id, project)
+        }
+    }
+
+    private fun sanitizeReturnLink(
+        http: HttpRequest, project: Project,
+        version: Version? = null, component: Component? = null, variant: Variant? = null
+    ): String {
+        val entity = if (version != null) "versions" else if (component != null) "components" else "variants"
+        val defaultPath = http.baseHref + "projects/${project.node}/${entity}/"
+
+        // referer is bad, redirect to default path
+        val returnPath = http.sanitizeReferer(http.param("returnLink"))
+            ?.substring(http.baseHref.length) ?: return defaultPath
+
+        // check if referer is a link to the project overview
+        if (PathPattern("projects/%project").matches(returnPath)) return http.baseHref + "projects/${project.node}"
+
+        // check if referer is an issue list for a project and reconstruct the path with possibly updated nodes
+        val pattern = PathPattern("projects/%project/issues/%version/%component/%variant/")
+        if (!pattern.matches(returnPath)) return defaultPath
+
+        val pathParams = pattern.obtainPathParameters(returnPath)
+        val project = project.node
+        val version = version?.node ?: pathParams["version"]
+        val component = component?.node ?: pathParams["component"]
+        val variant = variant?.node ?: pathParams["variant"]
+
+        // probably unnecessary safeguard - this should never happen
+        if (version == null || component == null || variant == null) return defaultPath
+
+        return http.baseHref + "projects/$project/issues/$version/$component/$variant/"
+    }
+
     private fun versions(http: HttpRequest, dao: DataAccessObject) {
         withPathInfo(http, dao)?.let { path ->
             with(http) {
@@ -210,8 +252,7 @@
             val version = if (path.versionInfo is OptionalPathInfo.Specific)
                 path.versionInfo.elem else Version(-1, path.project.id)
 
-            val returnLink = http.baseHref + if (http.referer?.endsWith("/versions/") ?: true)
-                "projects/${path.project.node}/versions/" else path.issuesHref
+            val returnLink = http.referer ?: "projects/${path.project.node}/versions/"
 
             with(http) {
                 view = VersionEditView(path.projectInfo, version, returnLink)
@@ -221,18 +262,6 @@
         }
     }
 
-    private fun obtainIdAndProject(http: HttpRequest, dao: DataAccessObject): Pair<Int, Project>? {
-        val id = http.param("id")?.toIntOrNull()
-        val projectid = http.param("projectid")?.toIntOrNull() ?: -1
-        val project = dao.findProject(projectid)
-        return if (id == null || project == null) {
-            http.response.sendError(400)
-            null
-        } else {
-            Pair(id, project)
-        }
-    }
-
     private fun versionCommit(http: HttpRequest, dao: DataAccessObject) {
         val idParams = obtainIdAndProject(http, dao) ?: return
         val (id, project) = idParams
@@ -264,7 +293,7 @@
             dao.updateVersion(version)
         }
 
-        http.renderCommit(http.sanitizeReferer(http.param("returnLink")) ?: "projects/${project.node}/versions/")
+        http.renderCommit(sanitizeReturnLink(http, project, version = version))
     }
 
     private fun versionPlanning(http: HttpRequest, dao: DataAccessObject) {
@@ -332,8 +361,7 @@
             val component = if (path.componentInfo is OptionalPathInfo.Specific)
                 path.componentInfo.elem else Component(-1, path.project.id)
 
-            val returnLink = http.baseHref + if (http.referer?.endsWith("/components/") ?: true)
-                "projects/${path.project.node}/components/" else path.issuesHref
+            val returnLink = http.referer ?: "projects/${path.project.node}/components/"
 
             with(http) {
                 view = ComponentEditView(path.projectInfo, component, dao.listUsers(), returnLink)
@@ -370,7 +398,7 @@
             dao.updateComponent(component)
         }
 
-        http.renderCommit(http.sanitizeReferer(http.param("returnLink")) ?: "projects/${project.node}/components/")
+        http.renderCommit(sanitizeReturnLink(http, project, component = component))
     }
 
     private fun variants(http: HttpRequest, dao: DataAccessObject) {
@@ -393,8 +421,7 @@
             val variant = if (path.variantInfo is OptionalPathInfo.Specific)
                 path.variantInfo.elem else Variant(-1, path.project.id)
 
-            val returnLink = http.baseHref + if (http.referer?.endsWith("/variants/") ?: true)
-                "projects/${path.project.node}/variants/" else path.issuesHref
+            val returnLink = http.referer ?: "projects/${path.project.node}/variants/"
 
             with(http) {
                 view = VariantEditView(path.projectInfo, variant, returnLink)
@@ -427,7 +454,7 @@
             dao.updateVariant(variant)
         }
 
-        http.renderCommit(http.sanitizeReferer(http.param("returnLink")) ?: "projects/${project.node}/variants/")
+        http.renderCommit(sanitizeReturnLink(http, project, variant = variant))
     }
 
     private fun issue(http: HttpRequest, dao: DataAccessObject) {
--- a/src/main/webapp/WEB-INF/changelogs/changelog-de.jspf	Thu Jun 11 14:54:23 2026 +0200
+++ b/src/main/webapp/WEB-INF/changelogs/changelog-de.jspf	Thu Jun 11 16:01:47 2026 +0200
@@ -29,6 +29,8 @@
 <ul>
     <li>RSS Einträge für Kommentare enthalten nun die Kommentar-ID in der GUID.</li>
     <li>Regression bei der Darstellung von Markdown-Überschriften behoben.</li>
+    <li>Regression beim Speichern von Versionen, Komponenten und Varianten behoben, die eine fehlerhafte Weiterleitung zur Folge hat, wenn der Pfadname geändert wird.</li>
+    <li>Fehler behoben, bei dem die Formulare für Versionen, Komponenten und Varianten die Pfadinformationen über die Teile, die nicht zum Formular gehören, verloren haben.</li>
 </ul>
 
 <h3>Version 1.6.1</h3>
--- a/src/main/webapp/WEB-INF/changelogs/changelog.jspf	Thu Jun 11 14:54:23 2026 +0200
+++ b/src/main/webapp/WEB-INF/changelogs/changelog.jspf	Thu Jun 11 16:01:47 2026 +0200
@@ -29,6 +29,8 @@
 <ul>
     <li>Add the comment ID to the GUID of RSS entries for comments.</li>
     <li>Fix regression with rendering Markdown headings.</li>
+    <li>Fix regression that caused a wrong redirect when changing the node name of a version/component/variant.</li>
+    <li>Fix that redirecting from a version/component/variant only retains the path info for what was edited in the form.</li>
 </ul>
 
 <h3>Version 1.6.1</h3>

mercurial