mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-15 17:56:17 +01:00
Merge with 2.0.0-m3
This commit is contained in:
8
pom.xml
8
pom.xml
@@ -439,6 +439,13 @@
|
|||||||
<artifactId>smp-maven-plugin</artifactId>
|
<artifactId>smp-maven-plugin</artifactId>
|
||||||
<version>1.0.0-alpha-6</version>
|
<version>1.0.0-alpha-6</version>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
<version>2.8.2</version>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
</plugins>
|
</plugins>
|
||||||
</pluginManagement>
|
</pluginManagement>
|
||||||
|
|
||||||
@@ -633,7 +640,6 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-deploy-plugin</artifactId>
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
<version>2.7</version>
|
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
<plugin>
|
<plugin>
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package sonia.scm;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
public class IllegalIdentifierChangeException extends BadRequestException {
|
||||||
|
|
||||||
|
private static final String CODE = "thbsUFokjk";
|
||||||
|
|
||||||
|
public IllegalIdentifierChangeException(ContextEntry.ContextBuilder context, String message) {
|
||||||
|
super(context.build(), message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IllegalIdentifierChangeException(String message) {
|
||||||
|
super(Collections.emptyList(), message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCode() {
|
||||||
|
return CODE;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -184,17 +184,19 @@ public class ModifyCommandBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("UnstableApiUsage") // Files only used internal
|
||||||
private File loadData(ByteSource data) throws IOException {
|
private File loadData(ByteSource data) throws IOException {
|
||||||
File file = createTemporaryFile();
|
File file = createTemporaryFile();
|
||||||
data.copyTo(Files.asByteSink(file));
|
data.copyTo(Files.asByteSink(file));
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("UnstableApiUsage") // Files and ByteStreams only used internal
|
||||||
private File loadData(InputStream data) throws IOException {
|
private File loadData(InputStream data) throws IOException {
|
||||||
File file = createTemporaryFile();
|
File file = createTemporaryFile();
|
||||||
OutputStream out = Files.asByteSink(file).openBufferedStream();
|
try (OutputStream out = Files.asByteSink(file).openBufferedStream()) {
|
||||||
ByteStreams.copy(data, out);
|
ByteStreams.copy(data, out);
|
||||||
out.close();
|
}
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
//@flow
|
//@flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import {Redirect, Route, Switch, withRouter} from "react-router-dom";
|
import { Redirect, Route, Switch, withRouter } from "react-router-dom";
|
||||||
import type {Links} from "@scm-manager/ui-types";
|
import type { Links } from "@scm-manager/ui-types";
|
||||||
|
|
||||||
import Overview from "../repos/containers/Overview";
|
import Overview from "../repos/containers/Overview";
|
||||||
import Users from "../users/containers/Users";
|
import Users from "../users/containers/Users";
|
||||||
import Login from "../containers/Login";
|
import Login from "../containers/Login";
|
||||||
import Logout from "../containers/Logout";
|
import Logout from "../containers/Logout";
|
||||||
|
|
||||||
import {ProtectedRoute} from "@scm-manager/ui-components";
|
import { ProtectedRoute } from "@scm-manager/ui-components";
|
||||||
import {binder, ExtensionPoint} from "@scm-manager/ui-extensions";
|
import { binder, ExtensionPoint } from "@scm-manager/ui-extensions";
|
||||||
|
|
||||||
import CreateUser from "../users/containers/CreateUser";
|
import CreateUser from "../users/containers/CreateUser";
|
||||||
import SingleUser from "../users/containers/SingleUser";
|
import SingleUser from "../users/containers/SingleUser";
|
||||||
@@ -34,7 +34,7 @@ class Main extends React.Component<Props> {
|
|||||||
render() {
|
render() {
|
||||||
const { authenticated, links } = this.props;
|
const { authenticated, links } = this.props;
|
||||||
const redirectUrlFactory = binder.getExtension("main.redirect", this.props);
|
const redirectUrlFactory = binder.getExtension("main.redirect", this.props);
|
||||||
let url = "/repos";
|
let url = "/repos/";
|
||||||
if (redirectUrlFactory) {
|
if (redirectUrlFactory) {
|
||||||
url = redirectUrlFactory(this.props);
|
url = redirectUrlFactory(this.props);
|
||||||
}
|
}
|
||||||
@@ -44,9 +44,10 @@ class Main extends React.Component<Props> {
|
|||||||
<Redirect exact from="/" to={url} />
|
<Redirect exact from="/" to={url} />
|
||||||
<Route exact path="/login" component={Login} />
|
<Route exact path="/login" component={Login} />
|
||||||
<Route path="/logout" component={Logout} />
|
<Route path="/logout" component={Logout} />
|
||||||
|
<Redirect exact strict from="/repos" to="/repos/" />
|
||||||
<ProtectedRoute
|
<ProtectedRoute
|
||||||
exact
|
exact
|
||||||
path="/repos"
|
path="/repos/"
|
||||||
component={Overview}
|
component={Overview}
|
||||||
authenticated={authenticated}
|
authenticated={authenticated}
|
||||||
/>
|
/>
|
||||||
@@ -67,9 +68,10 @@ class Main extends React.Component<Props> {
|
|||||||
component={RepositoryRoot}
|
component={RepositoryRoot}
|
||||||
authenticated={authenticated}
|
authenticated={authenticated}
|
||||||
/>
|
/>
|
||||||
|
<Redirect exact strict from="/users" to="/users/" />
|
||||||
<ProtectedRoute
|
<ProtectedRoute
|
||||||
exact
|
exact
|
||||||
path="/users"
|
path="/users/"
|
||||||
component={Users}
|
component={Users}
|
||||||
authenticated={authenticated}
|
authenticated={authenticated}
|
||||||
/>
|
/>
|
||||||
@@ -89,10 +91,10 @@ class Main extends React.Component<Props> {
|
|||||||
path="/user/:name"
|
path="/user/:name"
|
||||||
component={SingleUser}
|
component={SingleUser}
|
||||||
/>
|
/>
|
||||||
|
<Redirect exact strict from="/groups" to="/groups/" />
|
||||||
<ProtectedRoute
|
<ProtectedRoute
|
||||||
exact
|
exact
|
||||||
path="/groups"
|
path="/groups/"
|
||||||
component={Groups}
|
component={Groups}
|
||||||
authenticated={authenticated}
|
authenticated={authenticated}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package sonia.scm.api.v2.resources;
|
|||||||
|
|
||||||
import de.otto.edison.hal.HalRepresentation;
|
import de.otto.edison.hal.HalRepresentation;
|
||||||
import sonia.scm.ConcurrentModificationException;
|
import sonia.scm.ConcurrentModificationException;
|
||||||
|
import sonia.scm.IllegalIdentifierChangeException;
|
||||||
import sonia.scm.Manager;
|
import sonia.scm.Manager;
|
||||||
import sonia.scm.ModelObject;
|
import sonia.scm.ModelObject;
|
||||||
import sonia.scm.NotFoundException;
|
import sonia.scm.NotFoundException;
|
||||||
@@ -11,8 +12,6 @@ import java.util.function.Function;
|
|||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adapter from resource http endpoints to managers, for Single resources (e.g. {@code /user/name}).
|
* Adapter from resource http endpoints to managers, for Single resources (e.g. {@code /user/name}).
|
||||||
*
|
*
|
||||||
@@ -55,7 +54,7 @@ class SingleResourceManagerAdapter<MODEL_OBJECT extends ModelObject,
|
|||||||
MODEL_OBJECT existingModelObject = reader.get();
|
MODEL_OBJECT existingModelObject = reader.get();
|
||||||
MODEL_OBJECT changedModelObject = applyChanges.apply(existingModelObject);
|
MODEL_OBJECT changedModelObject = applyChanges.apply(existingModelObject);
|
||||||
if (!hasSameKey.test(changedModelObject)) {
|
if (!hasSameKey.test(changedModelObject)) {
|
||||||
return Response.status(BAD_REQUEST).entity("illegal change of id").build();
|
throw new IllegalIdentifierChangeException("illegal change of id");
|
||||||
}
|
}
|
||||||
else if (modelObjectWasModifiedConcurrently(existingModelObject, changedModelObject)) {
|
else if (modelObjectWasModifiedConcurrently(existingModelObject, changedModelObject)) {
|
||||||
throw new ConcurrentModificationException(type, keyExtractor.apply(existingModelObject));
|
throw new ConcurrentModificationException(type, keyExtractor.apply(existingModelObject));
|
||||||
|
|||||||
@@ -59,6 +59,9 @@ import java.util.ArrayList;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
import static java.util.stream.Collectors.toList;
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
//~--- JDK imports ------------------------------------------------------------
|
||||||
|
|
||||||
@@ -68,6 +71,7 @@ import java.util.Set;
|
|||||||
*
|
*
|
||||||
* TODO don't mix nio and io
|
* TODO don't mix nio and io
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("squid:S3725") // performance is not critical, for this type of checks
|
||||||
public final class PluginProcessor
|
public final class PluginProcessor
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -171,7 +175,11 @@ public final class PluginProcessor
|
|||||||
|
|
||||||
extract(archives);
|
extract(archives);
|
||||||
|
|
||||||
List<Path> dirs = collectPluginDirectories(pluginDirectory);
|
List<Path> dirs =
|
||||||
|
collectPluginDirectories(pluginDirectory)
|
||||||
|
.stream()
|
||||||
|
.filter(isPluginDirectory())
|
||||||
|
.collect(toList());
|
||||||
|
|
||||||
logger.debug("process {} directories: {}", dirs.size(), dirs);
|
logger.debug("process {} directories: {}", dirs.size(), dirs);
|
||||||
|
|
||||||
@@ -194,6 +202,10 @@ public final class PluginProcessor
|
|||||||
return ImmutableSet.copyOf(wrappers);
|
return ImmutableSet.copyOf(wrappers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Predicate<Path> isPluginDirectory() {
|
||||||
|
return dir -> Files.exists(dir.resolve(DIRECTORY_METAINF).resolve("scm").resolve("plugin.xml"));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method description
|
* Method description
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -167,6 +167,10 @@
|
|||||||
"CHRM7IQzo1": {
|
"CHRM7IQzo1": {
|
||||||
"displayName": "Änderung fehlgeschlagen",
|
"displayName": "Änderung fehlgeschlagen",
|
||||||
"description": "Die Änderung ist fehlgeschlagen. Bitte wenden Sie sich an ihren Administrator für weitere Hinweise."
|
"description": "Die Änderung ist fehlgeschlagen. Bitte wenden Sie sich an ihren Administrator für weitere Hinweise."
|
||||||
|
},
|
||||||
|
"thbsUFokjk": {
|
||||||
|
"displayName": "Unerlaubte Änderung eines Schlüsselwerts",
|
||||||
|
"description": "Ein Schlüsselwert wurde unerlaubterweise geändert."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"namespaceStrategies": {
|
"namespaceStrategies": {
|
||||||
|
|||||||
@@ -167,6 +167,10 @@
|
|||||||
"CHRM7IQzo1": {
|
"CHRM7IQzo1": {
|
||||||
"displayName": "Change failed",
|
"displayName": "Change failed",
|
||||||
"description": "The change failed. Please contact your administrator for further assistance."
|
"description": "The change failed. Please contact your administrator for further assistance."
|
||||||
|
},
|
||||||
|
"thbsUFokjk": {
|
||||||
|
"displayName": "Illegal change of an identifier",
|
||||||
|
"description": "A identifier value has been changed in the entity. This is not allowed."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"namespaceStrategies": {
|
"namespaceStrategies": {
|
||||||
|
|||||||
@@ -134,6 +134,16 @@ public class PluginProcessorTest
|
|||||||
assertThat(plugin.getId(), is(PLUGIN_A.id));
|
assertThat(plugin.getId(), is(PLUGIN_A.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldCollectPluginsAndDoNotFailOnNonPluginDirectories() throws IOException {
|
||||||
|
new File(pluginDirectory, "some-directory").mkdirs();
|
||||||
|
|
||||||
|
copySmp(PLUGIN_A);
|
||||||
|
InstalledPlugin plugin = collectAndGetFirst();
|
||||||
|
|
||||||
|
assertThat(plugin.getId(), is(PLUGIN_A.id));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method description
|
* Method description
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user