From fdb8143b766c2b42482576c82778c63104af40af Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?=
Date: Tue, 11 Jun 2019 10:27:21 +0200
Subject: [PATCH] Validate new namespace and name on migration
---
.../sonia/scm/util/ValidationUtilTest.java | 7 +-
.../scm/update/MigrationWizardServlet.java | 133 ++++++++++++++++--
.../templates/repository-migration.mustache | 23 +--
3 files changed, 139 insertions(+), 24 deletions(-)
diff --git a/scm-core/src/test/java/sonia/scm/util/ValidationUtilTest.java b/scm-core/src/test/java/sonia/scm/util/ValidationUtilTest.java
index 972ed95a2d..51ff906b8f 100644
--- a/scm-core/src/test/java/sonia/scm/util/ValidationUtilTest.java
+++ b/scm-core/src/test/java/sonia/scm/util/ValidationUtilTest.java
@@ -147,6 +147,10 @@ public class ValidationUtilTest
public void testIsRepositoryNameValid() {
String[] validPaths = {
"scm",
+ "scm-",
+ "scm_",
+ "s_cm",
+ "s-cm",
"s",
"sc",
".hiddenrepo",
@@ -206,7 +210,8 @@ public class ValidationUtilTest
"a/..b",
"scm/main",
"scm/plugins/git-plugin",
- "scm/plugins/git-plugin"
+ "_scm",
+ "-scm"
};
for (String path : validPaths) {
diff --git a/scm-webapp/src/main/java/sonia/scm/update/MigrationWizardServlet.java b/scm-webapp/src/main/java/sonia/scm/update/MigrationWizardServlet.java
index 66c1006d4f..cd5f640c7b 100644
--- a/scm-webapp/src/main/java/sonia/scm/update/MigrationWizardServlet.java
+++ b/scm-webapp/src/main/java/sonia/scm/update/MigrationWizardServlet.java
@@ -10,6 +10,7 @@ import sonia.scm.event.ScmEventBus;
import sonia.scm.update.repository.MigrationStrategy;
import sonia.scm.update.repository.MigrationStrategyDao;
import sonia.scm.update.repository.XmlRepositoryV1UpdateStep;
+import sonia.scm.util.ValidationUtil;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -18,13 +19,13 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
-import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.stream.Collectors;
+
+import static java.util.Comparator.comparing;
@Singleton
class MigrationWizardServlet extends HttpServlet {
@@ -46,16 +47,20 @@ class MigrationWizardServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
- List repositoriesWithoutMigrationStrategies =
- new ArrayList<>(repositoryV1UpdateStep.getRepositoriesWithoutMigrationStrategies());
- repositoriesWithoutMigrationStrategies.sort(Comparator.comparing(XmlRepositoryV1UpdateStep.V1Repository::getPath));
+ List repositoryLineEntries = getRepositoryLineEntries();
+ doGet(req, resp, repositoryLineEntries);
+ }
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp, List repositoryLineEntries) {
HashMap model = new HashMap<>();
model.put("contextPath", req.getContextPath());
model.put("submitUrl", req.getRequestURI());
- model.put("repositories", repositoriesWithoutMigrationStrategies);
+ model.put("repositories", repositoryLineEntries);
model.put("strategies", getMigrationStrategies());
+ model.put("validationErrorsFound", repositoryLineEntries
+ .stream()
+ .anyMatch(entry -> entry.isNamespaceInvalid() || entry.isNameInvalid()));
MustacheFactory mf = new DefaultMustacheFactory();
Mustache template = mf.compile("templates/repository-migration.mustache");
@@ -64,16 +69,41 @@ class MigrationWizardServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
- resp.setStatus(200);
+ List repositoryLineEntries = getRepositoryLineEntries();
- Arrays.stream(req.getParameterValues("ids")).forEach(
- id -> {
- String strategy = req.getParameter("strategy-" + id);
- String namespace = req.getParameter("namespace-" + id);
- String name = req.getParameter("name-" + id);
- migrationStrategyDao.set(id, MigrationStrategy.valueOf(strategy), namespace, name);
+ boolean validationErrorFound = false;
+ for (RepositoryLineEntry repositoryLineEntry : repositoryLineEntries) {
+ String id = repositoryLineEntry.getId();
+ String namespace = req.getParameter("namespace-" + id);
+ String name = req.getParameter("name-" + id);
+ repositoryLineEntry.setNamespace(namespace);
+ repositoryLineEntry.setName(name);
+
+ if (!ValidationUtil.isRepositoryNameValid(namespace)) {
+ repositoryLineEntry.setNamespaceValid(false);
+ validationErrorFound = true;
}
- );
+ if (!ValidationUtil.isRepositoryNameValid(name)) {
+ repositoryLineEntry.setNameValid(false);
+ validationErrorFound = true;
+ }
+ }
+
+ if (validationErrorFound) {
+ doGet(req, resp, repositoryLineEntries);
+ return;
+ }
+
+ repositoryLineEntries.stream()
+ .map(RepositoryLineEntry::getId)
+ .forEach(
+ id -> {
+ String strategy = req.getParameter("strategy-" + id);
+ String namespace = req.getParameter("namespace-" + id);
+ String name = req.getParameter("name-" + id);
+ migrationStrategyDao.set(id, MigrationStrategy.valueOf(strategy), namespace, name);
+ }
+ );
MustacheFactory mf = new DefaultMustacheFactory();
Mustache template = mf.compile("templates/repository-migration-restart.mustache");
@@ -81,9 +111,20 @@ class MigrationWizardServlet extends HttpServlet {
respondWithTemplate(resp, model, template);
+ resp.setStatus(200);
+
ScmEventBus.getInstance().post(new RestartEvent(MigrationWizardServlet.class, "wrote migration data"));
}
+ private List getRepositoryLineEntries() {
+ List repositoriesWithoutMigrationStrategies =
+ repositoryV1UpdateStep.getRepositoriesWithoutMigrationStrategies();
+ return repositoriesWithoutMigrationStrategies.stream()
+ .map(RepositoryLineEntry::new)
+ .sorted(comparing(RepositoryLineEntry::getPath))
+ .collect(Collectors.toList());
+ }
+
private MigrationStrategy[] getMigrationStrategies() {
return MigrationStrategy.values();
}
@@ -101,4 +142,66 @@ class MigrationWizardServlet extends HttpServlet {
writer.flush();
resp.setStatus(200);
}
+
+ private static class RepositoryLineEntry {
+ private final String id;
+ private final String type;
+ private final String path;
+ private String namespace;
+ private String name;
+ private boolean namespaceValid = true;
+ private boolean nameValid = true;
+
+ public RepositoryLineEntry(XmlRepositoryV1UpdateStep.V1Repository repository) {
+ this.id = repository.getId();
+ this.type = repository.getType();
+ this.path = repository.getPath();
+ this.namespace = repository.getNewNamespace();
+ this.name = repository.getNewName();
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public String getNamespace() {
+ return namespace;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setNamespace(String namespace) {
+ this.namespace = namespace;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setNamespaceValid(boolean namespaceValid) {
+ this.namespaceValid = namespaceValid;
+ }
+
+ public void setNameValid(boolean nameValid) {
+ this.nameValid = nameValid;
+ }
+
+ public boolean isNamespaceInvalid() {
+ return !namespaceValid;
+ }
+
+ public boolean isNameInvalid() {
+ return !nameValid;
+ }
+ }
}
diff --git a/scm-webapp/src/main/resources/templates/repository-migration.mustache b/scm-webapp/src/main/resources/templates/repository-migration.mustache
index 5a9085fb4b..9d7e5e0a0b 100644
--- a/scm-webapp/src/main/resources/templates/repository-migration.mustache
+++ b/scm-webapp/src/main/resources/templates/repository-migration.mustache
@@ -41,14 +41,24 @@
+ {{#validationErrorsFound}}
+ Please correct the invalid namespaces or names below and try again.
+
+ {{/validationErrorsFound}}