mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-15 09:46:16 +01:00
Validate new namespace and name on migration
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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<XmlRepositoryV1UpdateStep.V1Repository> repositoriesWithoutMigrationStrategies =
|
||||
new ArrayList<>(repositoryV1UpdateStep.getRepositoriesWithoutMigrationStrategies());
|
||||
repositoriesWithoutMigrationStrategies.sort(Comparator.comparing(XmlRepositoryV1UpdateStep.V1Repository::getPath));
|
||||
List<RepositoryLineEntry> repositoryLineEntries = getRepositoryLineEntries();
|
||||
doGet(req, resp, repositoryLineEntries);
|
||||
}
|
||||
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp, List<RepositoryLineEntry> repositoryLineEntries) {
|
||||
HashMap<String, Object> 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<RepositoryLineEntry> 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<RepositoryLineEntry> getRepositoryLineEntries() {
|
||||
List<XmlRepositoryV1UpdateStep.V1Repository> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,14 +41,24 @@
|
||||
</p>
|
||||
</div>
|
||||
<hr>
|
||||
{{#validationErrorsFound}}
|
||||
<div class="notification is-danger">Please correct the invalid namespaces or names below and try again.</div>
|
||||
<hr>
|
||||
{{/validationErrorsFound}}
|
||||
<form action="{{submitUrl}}" method="post">
|
||||
<table class="card-table table is-hoverable is-fullwidth">
|
||||
<tr>
|
||||
<th>Original name</th>
|
||||
<th>Type</th>
|
||||
<th>New namespace</th>
|
||||
<th>New name</th>
|
||||
<th>Strategy</th>
|
||||
<th>New namespace
|
||||
<span class="tooltip is-tooltip-right is-tooltip-multiline t-tooltip-0-1-38" data-tooltip="The namespace of the repository. This will be part op the url. The new namespace must consist of letters, digits, dots, dashes and underscores (it must not start with a dash or a underscore)."><i class="fa fa-question-circle has-text-info t-textinfo-0-1-10"></i></span>
|
||||
</th>
|
||||
<th>New name
|
||||
<span class="tooltip is-tooltip-right is-tooltip-multiline t-tooltip-0-1-38" data-tooltip="The name of the repository. This will be part op the url. The new name must consist of letters, digits, dots, dashes and underscores (it must not start with a dash or a underscore)."><i class="fa fa-question-circle has-text-info t-textinfo-0-1-10"></i></span>
|
||||
</th>
|
||||
<th>Strategy
|
||||
<span class="tooltip is-tooltip-right is-tooltip-multiline t-tooltip-0-1-38" data-tooltip="The strategy used to migrate the data directory of the repository. See above for the means of the different strategies."><i class="fa fa-question-circle has-text-info t-textinfo-0-1-10"></i></span>
|
||||
</th>
|
||||
</tr>
|
||||
{{#repositories}}
|
||||
<tr>
|
||||
@@ -59,10 +69,10 @@
|
||||
{{type}}
|
||||
</td>
|
||||
<td>
|
||||
<input class="input" type="text" name="namespace-{{id}}" value="{{newNamespace}}">
|
||||
<input class="input {{#namespaceInvalid}}is-danger{{/namespaceInvalid}}" type="text" name="namespace-{{id}}" value="{{namespace}}">
|
||||
</td>
|
||||
<td>
|
||||
<input class="input" type="text" name="name-{{id}}" value="{{newName}}">
|
||||
<input class="input {{#nameInvalid}}is-danger{{/nameInvalid}}" type="text" name="name-{{id}}" value="{{name}}">
|
||||
</td>
|
||||
<td>
|
||||
<div class="field">
|
||||
@@ -78,9 +88,6 @@
|
||||
</tr>
|
||||
{{/repositories}}
|
||||
</table>
|
||||
{{#repositories}}
|
||||
<input type="hidden" name="ids" value="{{id}}">
|
||||
{{/repositories}}
|
||||
<button class="button is-primary" type="submit">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user