| {this.createFileIcon(file)} |
- {this.createFileName(file)} |
+ {this.createFileName(file)} |
{fileSize} |
From 7e2184ef61ddeb5370e6dc47fad9f7f00d25c4ba Mon Sep 17 00:00:00 2001
From: Philipp Czora
Date: Thu, 13 Dec 2018 15:21:13 +0100
Subject: [PATCH 10/35] Fixed typo
---
.../java/sonia/scm/user/ChangePasswordNotAllowedException.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scm-core/src/main/java/sonia/scm/user/ChangePasswordNotAllowedException.java b/scm-core/src/main/java/sonia/scm/user/ChangePasswordNotAllowedException.java
index 486d392b0b..b0f8117e82 100644
--- a/scm-core/src/main/java/sonia/scm/user/ChangePasswordNotAllowedException.java
+++ b/scm-core/src/main/java/sonia/scm/user/ChangePasswordNotAllowedException.java
@@ -7,7 +7,7 @@ import sonia.scm.ContextEntry;
public class ChangePasswordNotAllowedException extends BadRequestException {
private static final String CODE = "9BR7qpDAe1";
- public static final String WRONG_USER_TYPE = "User of type %s are not allowed to change password";
+ public static final String WRONG_USER_TYPE = "Users of type %s are not allowed to change password";
public ChangePasswordNotAllowedException(ContextEntry.ContextBuilder context, String type) {
super(context.build(), String.format(WRONG_USER_TYPE, type));
From 0af5d3901cd7a02c75130117c7cabc2b39a916aa Mon Sep 17 00:00:00 2001
From: Philipp Czora
Date: Thu, 13 Dec 2018 15:31:00 +0100
Subject: [PATCH 11/35] Renamed NotSupportedFeatureException
---
...reException.java => FeatureNotSupportedException.java} | 4 ++--
.../sonia/scm/repository/AbstractRepositoryHandler.java | 6 +++---
.../main/java/sonia/scm/repository/RepositoryHandler.java | 6 +++---
.../java/sonia/scm/repository/api/DiffCommandBuilder.java | 4 ++--
.../java/sonia/scm/repository/api/LogCommandBuilder.java | 4 ++--
.../scm/api/rest/resources/RepositoryImportResource.java | 8 ++++----
6 files changed, 16 insertions(+), 16 deletions(-)
rename scm-core/src/main/java/sonia/scm/{NotSupportedFeatureException.java => FeatureNotSupportedException.java} (95%)
diff --git a/scm-core/src/main/java/sonia/scm/NotSupportedFeatureException.java b/scm-core/src/main/java/sonia/scm/FeatureNotSupportedException.java
similarity index 95%
rename from scm-core/src/main/java/sonia/scm/NotSupportedFeatureException.java
rename to scm-core/src/main/java/sonia/scm/FeatureNotSupportedException.java
index 3b389a7dc4..2d64af4318 100644
--- a/scm-core/src/main/java/sonia/scm/NotSupportedFeatureException.java
+++ b/scm-core/src/main/java/sonia/scm/FeatureNotSupportedException.java
@@ -41,13 +41,13 @@ import java.util.Collections;
* @version 1.6
*/
@SuppressWarnings("squid:MaximumInheritanceDepth") // exceptions have a deep inheritance depth themselves; therefore we accept this here
-public class NotSupportedFeatureException extends BadRequestException {
+public class FeatureNotSupportedException extends BadRequestException {
private static final long serialVersionUID = 256498734456613496L;
private static final String CODE = "9SR8G0kmU1";
- public NotSupportedFeatureException(String feature)
+ public FeatureNotSupportedException(String feature)
{
super(Collections.emptyList(),createMessage(feature));
}
diff --git a/scm-core/src/main/java/sonia/scm/repository/AbstractRepositoryHandler.java b/scm-core/src/main/java/sonia/scm/repository/AbstractRepositoryHandler.java
index a3e8a1da73..1e9cc3d374 100644
--- a/scm-core/src/main/java/sonia/scm/repository/AbstractRepositoryHandler.java
+++ b/scm-core/src/main/java/sonia/scm/repository/AbstractRepositoryHandler.java
@@ -38,7 +38,7 @@ package sonia.scm.repository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import sonia.scm.NotSupportedFeatureException;
+import sonia.scm.FeatureNotSupportedException;
import sonia.scm.SCMContextProvider;
import sonia.scm.event.ScmEventBus;
@@ -167,12 +167,12 @@ public abstract class AbstractRepositoryHandler
*
* @return
*
- * @throws NotSupportedFeatureException
+ * @throws FeatureNotSupportedException
*/
@Override
public ImportHandler getImportHandler()
{
- throw new NotSupportedFeatureException("import");
+ throw new FeatureNotSupportedException("import");
}
/**
diff --git a/scm-core/src/main/java/sonia/scm/repository/RepositoryHandler.java b/scm-core/src/main/java/sonia/scm/repository/RepositoryHandler.java
index cb19cb7f5e..aaa090827a 100644
--- a/scm-core/src/main/java/sonia/scm/repository/RepositoryHandler.java
+++ b/scm-core/src/main/java/sonia/scm/repository/RepositoryHandler.java
@@ -36,7 +36,7 @@ package sonia.scm.repository;
//~--- non-JDK imports --------------------------------------------------------
import sonia.scm.Handler;
-import sonia.scm.NotSupportedFeatureException;
+import sonia.scm.FeatureNotSupportedException;
import sonia.scm.plugin.ExtensionPoint;
/**
@@ -59,9 +59,9 @@ public interface RepositoryHandler
* @return {@link ImportHandler} for the repository type of this handler
* @since 1.12
*
- * @throws NotSupportedFeatureException
+ * @throws FeatureNotSupportedException
*/
- public ImportHandler getImportHandler() throws NotSupportedFeatureException;
+ public ImportHandler getImportHandler() throws FeatureNotSupportedException;
/**
* Returns informations about the version of the RepositoryHandler.
diff --git a/scm-core/src/main/java/sonia/scm/repository/api/DiffCommandBuilder.java b/scm-core/src/main/java/sonia/scm/repository/api/DiffCommandBuilder.java
index 32b633a67c..9e7094d5bf 100644
--- a/scm-core/src/main/java/sonia/scm/repository/api/DiffCommandBuilder.java
+++ b/scm-core/src/main/java/sonia/scm/repository/api/DiffCommandBuilder.java
@@ -38,7 +38,7 @@ package sonia.scm.repository.api;
import com.google.common.base.Preconditions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import sonia.scm.NotSupportedFeatureException;
+import sonia.scm.FeatureNotSupportedException;
import sonia.scm.repository.Feature;
import sonia.scm.repository.spi.DiffCommand;
import sonia.scm.repository.spi.DiffCommandRequest;
@@ -203,7 +203,7 @@ public final class DiffCommandBuilder
public DiffCommandBuilder setAncestorChangeset(String revision)
{
if (!supportedFeatures.contains(Feature.INCOMING_REVISION)) {
- throw new NotSupportedFeatureException(Feature.INCOMING_REVISION.name());
+ throw new FeatureNotSupportedException(Feature.INCOMING_REVISION.name());
}
request.setAncestorChangeset(revision);
diff --git a/scm-core/src/main/java/sonia/scm/repository/api/LogCommandBuilder.java b/scm-core/src/main/java/sonia/scm/repository/api/LogCommandBuilder.java
index 7b8e172661..917b81391f 100644
--- a/scm-core/src/main/java/sonia/scm/repository/api/LogCommandBuilder.java
+++ b/scm-core/src/main/java/sonia/scm/repository/api/LogCommandBuilder.java
@@ -39,7 +39,7 @@ import com.google.common.base.Objects;
import com.google.common.collect.ImmutableList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import sonia.scm.NotSupportedFeatureException;
+import sonia.scm.FeatureNotSupportedException;
import sonia.scm.cache.Cache;
import sonia.scm.cache.CacheManager;
import sonia.scm.repository.Changeset;
@@ -410,7 +410,7 @@ public final class LogCommandBuilder
*/
public LogCommandBuilder setAncestorChangeset(String ancestorChangeset) {
if (!supportedFeatures.contains(Feature.INCOMING_REVISION)) {
- throw new NotSupportedFeatureException(Feature.INCOMING_REVISION.name());
+ throw new FeatureNotSupportedException(Feature.INCOMING_REVISION.name());
}
request.setAncestorChangeset(ancestorChangeset);
return this;
diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryImportResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryImportResource.java
index 6bf6c8e803..64b20fc10c 100644
--- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryImportResource.java
+++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryImportResource.java
@@ -46,7 +46,7 @@ import org.apache.shiro.SecurityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.NotFoundException;
-import sonia.scm.NotSupportedFeatureException;
+import sonia.scm.FeatureNotSupportedException;
import sonia.scm.Type;
import sonia.scm.api.rest.RestActionUploadResult;
import sonia.scm.api.v2.resources.RepositoryResource;
@@ -394,7 +394,7 @@ public class RepositoryImportResource
response = Response.ok(result).build();
}
- catch (NotSupportedFeatureException ex)
+ catch (FeatureNotSupportedException ex)
{
logger
.warn(
@@ -609,7 +609,7 @@ public class RepositoryImportResource
types.add(t);
}
}
- catch (NotSupportedFeatureException ex)
+ catch (FeatureNotSupportedException ex)
{
if (logger.isTraceEnabled())
{
@@ -711,7 +711,7 @@ public class RepositoryImportResource
}
}
}
- catch (NotSupportedFeatureException ex)
+ catch (FeatureNotSupportedException ex)
{
throw new WebApplicationException(ex, Response.Status.BAD_REQUEST);
}
From d6efec8fe3f67bd8932ff1e5c0f92ada19bcf5b9 Mon Sep 17 00:00:00 2001
From: Sebastian Sdorra
Date: Fri, 14 Dec 2018 08:28:28 +0100
Subject: [PATCH 12/35] use url safe base64 encoding
---
.../main/java/sonia/scm/security/DefaultCipherHandler.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/scm-core/src/main/java/sonia/scm/security/DefaultCipherHandler.java b/scm-core/src/main/java/sonia/scm/security/DefaultCipherHandler.java
index b4f0d81cd3..9c1fa590cc 100644
--- a/scm-core/src/main/java/sonia/scm/security/DefaultCipherHandler.java
+++ b/scm-core/src/main/java/sonia/scm/security/DefaultCipherHandler.java
@@ -164,7 +164,7 @@ public class DefaultCipherHandler implements CipherHandler {
String result = null;
try {
- byte[] encodedInput = Base64.getDecoder().decode(value);
+ byte[] encodedInput = Base64.getUrlDecoder().decode(value);
byte[] salt = new byte[SALT_LENGTH];
byte[] encoded = new byte[encodedInput.length - SALT_LENGTH];
@@ -221,7 +221,7 @@ public class DefaultCipherHandler implements CipherHandler {
System.arraycopy(salt, 0, result, 0, SALT_LENGTH);
System.arraycopy(encodedInput, 0, result, SALT_LENGTH,
result.length - SALT_LENGTH);
- res = new String(Base64.getEncoder().encode(result), ENCODING);
+ res = new String(Base64.getUrlEncoder().encode(result), ENCODING);
} catch (IOException | GeneralSecurityException ex) {
throw new CipherException("could not encode string", ex);
}
From 306482094d4181bf8ede9d9e8048e858a9042026 Mon Sep 17 00:00:00 2001
From: Sebastian Sdorra
Date: Fri, 14 Dec 2018 08:29:30 +0100
Subject: [PATCH 13/35] move AccessTokenCookieIssue from scm-webapp to scm-core
---
.../scm/security/AccessTokenCookieIssuer.java | 30 +++++++++++++++++++
.../main/java/sonia/scm/ScmServletModule.java | 5 ++--
...va => DefaultAccessTokenCookieIssuer.java} | 8 ++---
...> DefaultAccessTokenCookieIssuerTest.java} | 6 ++--
4 files changed, 40 insertions(+), 9 deletions(-)
create mode 100644 scm-core/src/main/java/sonia/scm/security/AccessTokenCookieIssuer.java
rename scm-webapp/src/main/java/sonia/scm/security/{AccessTokenCookieIssuer.java => DefaultAccessTokenCookieIssuer.java} (93%)
rename scm-webapp/src/test/java/sonia/scm/security/{AccessTokenCookieIssuerTest.java => DefaultAccessTokenCookieIssuerTest.java} (93%)
diff --git a/scm-core/src/main/java/sonia/scm/security/AccessTokenCookieIssuer.java b/scm-core/src/main/java/sonia/scm/security/AccessTokenCookieIssuer.java
new file mode 100644
index 0000000000..999c693b8f
--- /dev/null
+++ b/scm-core/src/main/java/sonia/scm/security/AccessTokenCookieIssuer.java
@@ -0,0 +1,30 @@
+package sonia.scm.security;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Generates cookies and invalidates access token cookies.
+ *
+ * @author Sebastian Sdorra
+ * @since 2.0.0
+ */
+public interface AccessTokenCookieIssuer {
+
+ /**
+ * Creates a cookie for token authentication and attaches it to the response.
+ *
+ * @param request http servlet request
+ * @param response http servlet response
+ * @param accessToken access token
+ */
+ void authenticate(HttpServletRequest request, HttpServletResponse response, AccessToken accessToken);
+ /**
+ * Invalidates the authentication cookie.
+ *
+ * @param request http servlet request
+ * @param response http servlet response
+ */
+ void invalidate(HttpServletRequest request, HttpServletResponse response);
+
+}
diff --git a/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java b/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java
index 9555ad66b5..d7846dbac5 100644
--- a/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java
+++ b/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java
@@ -79,14 +79,14 @@ import sonia.scm.repository.spi.HookEventFacade;
import sonia.scm.repository.xml.XmlRepositoryDAO;
import sonia.scm.schedule.QuartzScheduler;
import sonia.scm.schedule.Scheduler;
+import sonia.scm.security.AccessTokenCookieIssuer;
import sonia.scm.security.AuthorizationChangedEventProducer;
import sonia.scm.security.CipherHandler;
import sonia.scm.security.CipherUtil;
import sonia.scm.security.ConfigurableLoginAttemptHandler;
-import sonia.scm.security.DefaultJwtAccessTokenRefreshStrategy;
+import sonia.scm.security.DefaultAccessTokenCookieIssuer;
import sonia.scm.security.DefaultKeyGenerator;
import sonia.scm.security.DefaultSecuritySystem;
-import sonia.scm.security.JwtAccessTokenRefreshStrategy;
import sonia.scm.security.KeyGenerator;
import sonia.scm.security.LoginAttemptHandler;
import sonia.scm.security.SecuritySystem;
@@ -320,6 +320,7 @@ public class ScmServletModule extends ServletModule
// bind events
// bind(LastModifiedUpdateListener.class);
+ bind(AccessTokenCookieIssuer.class).to(DefaultAccessTokenCookieIssuer.class);
bind(PushStateDispatcher.class).toProvider(PushStateDispatcherProvider.class);
}
diff --git a/scm-webapp/src/main/java/sonia/scm/security/AccessTokenCookieIssuer.java b/scm-webapp/src/main/java/sonia/scm/security/DefaultAccessTokenCookieIssuer.java
similarity index 93%
rename from scm-webapp/src/main/java/sonia/scm/security/AccessTokenCookieIssuer.java
rename to scm-webapp/src/main/java/sonia/scm/security/DefaultAccessTokenCookieIssuer.java
index bb1473dca6..fd3f0e0d6f 100644
--- a/scm-webapp/src/main/java/sonia/scm/security/AccessTokenCookieIssuer.java
+++ b/scm-webapp/src/main/java/sonia/scm/security/DefaultAccessTokenCookieIssuer.java
@@ -51,12 +51,12 @@ import java.util.concurrent.TimeUnit;
* @author Sebastian Sdorra
* @since 2.0.0
*/
-public final class AccessTokenCookieIssuer {
+public final class DefaultAccessTokenCookieIssuer implements AccessTokenCookieIssuer {
/**
- * the logger for AccessTokenCookieIssuer
+ * the logger for DefaultAccessTokenCookieIssuer
*/
- private static final Logger LOG = LoggerFactory.getLogger(AccessTokenCookieIssuer.class);
+ private static final Logger LOG = LoggerFactory.getLogger(DefaultAccessTokenCookieIssuer.class);
private final ScmConfiguration configuration;
@@ -66,7 +66,7 @@ public final class AccessTokenCookieIssuer {
* @param configuration scm main configuration
*/
@Inject
- public AccessTokenCookieIssuer(ScmConfiguration configuration) {
+ public DefaultAccessTokenCookieIssuer(ScmConfiguration configuration) {
this.configuration = configuration;
}
diff --git a/scm-webapp/src/test/java/sonia/scm/security/AccessTokenCookieIssuerTest.java b/scm-webapp/src/test/java/sonia/scm/security/DefaultAccessTokenCookieIssuerTest.java
similarity index 93%
rename from scm-webapp/src/test/java/sonia/scm/security/AccessTokenCookieIssuerTest.java
rename to scm-webapp/src/test/java/sonia/scm/security/DefaultAccessTokenCookieIssuerTest.java
index 03cf174226..9c80cfc67b 100644
--- a/scm-webapp/src/test/java/sonia/scm/security/AccessTokenCookieIssuerTest.java
+++ b/scm-webapp/src/test/java/sonia/scm/security/DefaultAccessTokenCookieIssuerTest.java
@@ -20,11 +20,11 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
-public class AccessTokenCookieIssuerTest {
+public class DefaultAccessTokenCookieIssuerTest {
private ScmConfiguration configuration;
- private AccessTokenCookieIssuer issuer;
+ private DefaultAccessTokenCookieIssuer issuer;
@Mock
private HttpServletRequest request;
@@ -41,7 +41,7 @@ public class AccessTokenCookieIssuerTest {
@Before
public void setUp() {
configuration = new ScmConfiguration();
- issuer = new AccessTokenCookieIssuer(configuration);
+ issuer = new DefaultAccessTokenCookieIssuer(configuration);
}
@Test
From 6f29aed9df95c1a27f4a5d3a6941d2438cbacc9f Mon Sep 17 00:00:00 2001
From: Sebastian Sdorra
Date: Fri, 14 Dec 2018 08:33:45 +0100
Subject: [PATCH 14/35] fixed broken AuthenticationResourceTest
---
.../sonia/scm/api/v2/resources/AuthenticationResourceTest.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AuthenticationResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AuthenticationResourceTest.java
index 42428f9f77..1123dc94ce 100644
--- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AuthenticationResourceTest.java
+++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/AuthenticationResourceTest.java
@@ -18,6 +18,7 @@ import sonia.scm.security.AccessToken;
import sonia.scm.security.AccessTokenBuilder;
import sonia.scm.security.AccessTokenBuilderFactory;
import sonia.scm.security.AccessTokenCookieIssuer;
+import sonia.scm.security.DefaultAccessTokenCookieIssuer;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -46,7 +47,7 @@ public class AuthenticationResourceTest {
@Mock
private AccessTokenBuilder accessTokenBuilder;
- private AccessTokenCookieIssuer cookieIssuer = new AccessTokenCookieIssuer(mock(ScmConfiguration.class));
+ private AccessTokenCookieIssuer cookieIssuer = new DefaultAccessTokenCookieIssuer(mock(ScmConfiguration.class));
private static final String AUTH_JSON_TRILLIAN = "{\n" +
"\t\"cookie\": true,\n" +
From de2c594fafc670edc208ad59223038aca0cf0e6c Mon Sep 17 00:00:00 2001
From: Philipp Czora
Date: Fri, 14 Dec 2018 08:09:50 +0000
Subject: [PATCH 15/35] Close branch feature/bad_request
From 044a60c7c94a2bfd965ddc50df9bd4046f44d89c Mon Sep 17 00:00:00 2001
From: Florian Scholdei
Date: Fri, 14 Dec 2018 10:42:20 +0100
Subject: [PATCH 16/35] implemented word-break for column
---
scm-ui/src/repos/sources/components/FileTreeLeaf.js | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/scm-ui/src/repos/sources/components/FileTreeLeaf.js b/scm-ui/src/repos/sources/components/FileTreeLeaf.js
index 36bd734d11..f7f9feb52e 100644
--- a/scm-ui/src/repos/sources/components/FileTreeLeaf.js
+++ b/scm-ui/src/repos/sources/components/FileTreeLeaf.js
@@ -11,12 +11,13 @@ const styles = {
iconColumn: {
width: "16px"
},
- wordBreakTable: {
+ wordBreakColumn: {
WebkitHyphens: "auto",
MozHyphens: "auto",
MsHyphens: "auto",
hyphens: "auto",
- wordBreak: "auto"
+ wordBreak: "break-all",
+ minWidth: "10em"
}
};
@@ -78,12 +79,12 @@ class FileTreeLeaf extends React.Component {
return (
| {this.createFileIcon(file)} |
- {this.createFileName(file)} |
+ {this.createFileName(file)} |
{fileSize} |
|
- {file.description} |
+ {file.description} |
);
}
From d02cb60b47db99903fc380c7cb111492dbcdb2a4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?=
Date: Fri, 14 Dec 2018 14:50:14 +0100
Subject: [PATCH 17/35] Add getters with Optional to stores
---
.../sonia/scm/store/ConfigurationStore.java | 18 ++++++++++++++++--
.../java/sonia/scm/store/MultiEntryStore.java | 16 ++++++++++++++++
2 files changed, 32 insertions(+), 2 deletions(-)
diff --git a/scm-core/src/main/java/sonia/scm/store/ConfigurationStore.java b/scm-core/src/main/java/sonia/scm/store/ConfigurationStore.java
index a7f21dd304..bcdc0443ca 100644
--- a/scm-core/src/main/java/sonia/scm/store/ConfigurationStore.java
+++ b/scm-core/src/main/java/sonia/scm/store/ConfigurationStore.java
@@ -33,6 +33,10 @@
package sonia.scm.store;
+import java.util.Optional;
+
+import static java.util.Optional.ofNullable;
+
/**
* ConfigurationStore for configuration objects. Note: the default
* implementation use JAXB to marshall the configuration objects.
@@ -50,7 +54,17 @@ public interface ConfigurationStore
*
* @return configuration object from store
*/
- public T get();
+ T get();
+
+ /**
+ * Returns the configuration object from store.
+ *
+ *
+ * @return configuration object from store
+ */
+ default Optional getOptional() {
+ return ofNullable(get());
+ }
//~--- set methods ----------------------------------------------------------
@@ -60,5 +74,5 @@ public interface ConfigurationStore
*
* @param obejct configuration object to store
*/
- public void set(T obejct);
+ void set(T object);
}
diff --git a/scm-core/src/main/java/sonia/scm/store/MultiEntryStore.java b/scm-core/src/main/java/sonia/scm/store/MultiEntryStore.java
index 9a35cee0e0..c1a8863758 100644
--- a/scm-core/src/main/java/sonia/scm/store/MultiEntryStore.java
+++ b/scm-core/src/main/java/sonia/scm/store/MultiEntryStore.java
@@ -32,6 +32,10 @@
package sonia.scm.store;
+import java.util.Optional;
+
+import static java.util.Optional.ofNullable;
+
/**
* Base class for {@link BlobStore} and {@link DataStore}.
*
@@ -67,4 +71,16 @@ public interface MultiEntryStore {
* @return item with the given id
*/
public T get(String id);
+
+ /**
+ * Returns the item with the given id from the store.
+ *
+ *
+ * @param id id of the item to return
+ *
+ * @return item with the given id
+ */
+ default Optional getOptional(String id) {
+ return ofNullable(get(id));
+ }
}
From 3edd3cbb456b90fd6683a6c81a4cf27d96193401 Mon Sep 17 00:00:00 2001
From: Florian Scholdei
Date: Fri, 14 Dec 2018 15:03:59 +0100
Subject: [PATCH 18/35] implemented work-break for media and table
---
scm-ui/src/repos/sources/containers/Content.js | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/scm-ui/src/repos/sources/containers/Content.js b/scm-ui/src/repos/sources/containers/Content.js
index 34d024b2a2..cbd83f9d6f 100644
--- a/scm-ui/src/repos/sources/containers/Content.js
+++ b/scm-ui/src/repos/sources/containers/Content.js
@@ -41,6 +41,14 @@ const styles = {
isVerticalCenter: {
display: "flex",
alignItems: "center"
+ },
+ wordBreakColumn: {
+ WebkitHyphens: "auto",
+ MozHyphens: "auto",
+ MsHyphens: "auto",
+ hypens: "auto",
+ wordBreak: "break-all",
+ minWidth: "10em"
}
};
@@ -93,7 +101,7 @@ class Content extends React.Component {
classes.marginInHeader
)}
/>
- {file.name}
+ {file.name}
{selector}
@@ -125,7 +133,7 @@ class Content extends React.Component {
| {t("sources.content.path")} |
- {file.path} |
+ {file.path} |
| {t("sources.content.branch")} |
@@ -141,7 +149,7 @@ class Content extends React.Component {
| {t("sources.content.description")} |
- {description} |
+ {description} |
From ae28b513584b81ed1d5a7a99dc564a12d06c412a Mon Sep 17 00:00:00 2001
From: Florian Scholdei
Date: Fri, 14 Dec 2018 16:28:06 +0100
Subject: [PATCH 19/35] added css-class to branch column and renamed it
---
scm-ui/src/repos/sources/containers/Content.js | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/scm-ui/src/repos/sources/containers/Content.js b/scm-ui/src/repos/sources/containers/Content.js
index cbd83f9d6f..33bfc7a8ca 100644
--- a/scm-ui/src/repos/sources/containers/Content.js
+++ b/scm-ui/src/repos/sources/containers/Content.js
@@ -42,13 +42,12 @@ const styles = {
display: "flex",
alignItems: "center"
},
- wordBreakColumn: {
+ wordBreak: {
WebkitHyphens: "auto",
MozHyphens: "auto",
MsHyphens: "auto",
hypens: "auto",
wordBreak: "break-all",
- minWidth: "10em"
}
};
@@ -101,7 +100,7 @@ class Content extends React.Component {
classes.marginInHeader
)}
/>
- {file.name}
+ {file.name}
{selector}
@@ -129,15 +128,15 @@ class Content extends React.Component {
if (!collapsed) {
return (
-
+
| {t("sources.content.path")} |
- {file.path} |
+ {file.path} |
| {t("sources.content.branch")} |
- {revision} |
+ {revision} |
| {t("sources.content.size")} |
@@ -149,7 +148,7 @@ class Content extends React.Component {
| {t("sources.content.description")} |
- {description} |
+ {description} |
From 30fdce545530ba6df9bfb99af2f078350ee492aa Mon Sep 17 00:00:00 2001
From: Florian Scholdei
Date: Fri, 14 Dec 2018 16:30:19 +0100
Subject: [PATCH 20/35] corrected wrong approach
---
scm-ui/src/repos/sources/containers/Content.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scm-ui/src/repos/sources/containers/Content.js b/scm-ui/src/repos/sources/containers/Content.js
index 33bfc7a8ca..4565746999 100644
--- a/scm-ui/src/repos/sources/containers/Content.js
+++ b/scm-ui/src/repos/sources/containers/Content.js
@@ -128,7 +128,7 @@ class Content extends React.Component {
if (!collapsed) {
return (
-
+
| {t("sources.content.path")} |
From cef43b8b914eca55a136ed649c302dae42338ed8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?=
Date: Fri, 14 Dec 2018 16:38:14 +0100
Subject: [PATCH 21/35] Add abstract base class to enrich repository json
responses
---
.../web/AbstractRepositoryJsonEnricher.java | 40 +++++++++++++++++++
1 file changed, 40 insertions(+)
create mode 100644 scm-core/src/main/java/sonia/scm/web/AbstractRepositoryJsonEnricher.java
diff --git a/scm-core/src/main/java/sonia/scm/web/AbstractRepositoryJsonEnricher.java b/scm-core/src/main/java/sonia/scm/web/AbstractRepositoryJsonEnricher.java
new file mode 100644
index 0000000000..38f353e24b
--- /dev/null
+++ b/scm-core/src/main/java/sonia/scm/web/AbstractRepositoryJsonEnricher.java
@@ -0,0 +1,40 @@
+package sonia.scm.web;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import static java.util.Collections.singletonMap;
+import static sonia.scm.web.VndMediaType.REPOSITORY;
+import static sonia.scm.web.VndMediaType.REPOSITORY_COLLECTION;
+
+public abstract class AbstractRepositoryJsonEnricher extends JsonEnricherBase {
+
+ public AbstractRepositoryJsonEnricher(ObjectMapper objectMapper) {
+ super(objectMapper);
+ }
+
+ @Override
+ public void enrich(JsonEnricherContext context) {
+ if (resultHasMediaType(REPOSITORY, context)) {
+ JsonNode repositoryNode = context.getResponseEntity();
+ enrichRepositoryNode(repositoryNode);
+ } else if (resultHasMediaType(REPOSITORY_COLLECTION, context)) {
+ JsonNode repositoryCollectionNode = context.getResponseEntity().get("_embedded").withArray("repositories");
+ repositoryCollectionNode.elements().forEachRemaining(this::enrichRepositoryNode);
+ }
+ }
+
+ private void enrichRepositoryNode(JsonNode repositoryNode) {
+ String namespace = repositoryNode.get("namespace").asText();
+ String name = repositoryNode.get("name").asText();
+
+ enrichRepositoryNode(repositoryNode, namespace, name);
+ }
+
+ protected abstract void enrichRepositoryNode(JsonNode repositoryNode, String namespace, String name);
+
+ protected void addLink(JsonNode repositoryNode, String linkName, String link) {
+ JsonNode newPullRequestNode = createObject(singletonMap("href", value(link)));
+ addPropertyNode(repositoryNode.get("_links"), linkName, newPullRequestNode);
+ }
+}
From c0ba6984e9fa37b91266d4729cc5c7ceb0901951 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?=
Date: Fri, 14 Dec 2018 16:51:40 +0100
Subject: [PATCH 22/35] Add unit test
---
.../AbstractRepositoryJsonEnricherTest.java | 107 ++++++++++++++++++
.../sonia/scm/repository/repository-001.json | 42 +++++++
.../repository/repository-collection-001.json | 106 +++++++++++++++++
3 files changed, 255 insertions(+)
create mode 100644 scm-core/src/test/java/sonia/scm/web/AbstractRepositoryJsonEnricherTest.java
create mode 100644 scm-core/src/test/resources/sonia/scm/repository/repository-001.json
create mode 100644 scm-core/src/test/resources/sonia/scm/repository/repository-collection-001.json
diff --git a/scm-core/src/test/java/sonia/scm/web/AbstractRepositoryJsonEnricherTest.java b/scm-core/src/test/java/sonia/scm/web/AbstractRepositoryJsonEnricherTest.java
new file mode 100644
index 0000000000..2c8ef76464
--- /dev/null
+++ b/scm-core/src/test/java/sonia/scm/web/AbstractRepositoryJsonEnricherTest.java
@@ -0,0 +1,107 @@
+package sonia.scm.web;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.io.Resources;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.junit.jupiter.MockitoExtension;
+import sonia.scm.api.v2.resources.ScmPathInfoStore;
+
+import javax.ws.rs.core.MediaType;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URL;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@ExtendWith(MockitoExtension.class)
+class AbstractRepositoryJsonEnricherTest {
+
+ private final ObjectMapper objectMapper = new ObjectMapper();
+ private AbstractRepositoryJsonEnricher linkEnricher;
+ private JsonNode rootNode;
+
+ @BeforeEach
+ void globalSetUp() {
+ ScmPathInfoStore pathInfoStore = new ScmPathInfoStore();
+ pathInfoStore.set(() -> URI.create("/"));
+
+ linkEnricher = new AbstractRepositoryJsonEnricher(objectMapper) {
+ @Override
+ protected void enrichRepositoryNode(JsonNode repositoryNode, String namespace, String name) {
+ addLink(repositoryNode, "new-link", "/somewhere");
+ }
+ };
+ }
+
+ @Test
+ void shouldEnrichRepositories() throws IOException {
+ URL resource = Resources.getResource("sonia/scm/repository/repository-001.json");
+ rootNode = objectMapper.readTree(resource);
+
+ JsonEnricherContext context = new JsonEnricherContext(
+ URI.create("/"),
+ MediaType.valueOf(VndMediaType.REPOSITORY),
+ rootNode
+ );
+
+ linkEnricher.enrich(context);
+
+ String configLink = context.getResponseEntity()
+ .get("_links")
+ .get("new-link")
+ .get("href")
+ .asText();
+
+ assertThat(configLink).isEqualTo("/somewhere");
+ }
+
+ @Test
+ void shouldEnrichAllRepositories() throws IOException {
+ URL resource = Resources.getResource("sonia/scm/repository/repository-collection-001.json");
+ rootNode = objectMapper.readTree(resource);
+
+ JsonEnricherContext context = new JsonEnricherContext(
+ URI.create("/"),
+ MediaType.valueOf(VndMediaType.REPOSITORY_COLLECTION),
+ rootNode
+ );
+
+ linkEnricher.enrich(context);
+
+ context.getResponseEntity()
+ .get("_embedded")
+ .withArray("repositories")
+ .elements()
+ .forEachRemaining(node -> {
+ String configLink = node
+ .get("_links")
+ .get("new-link")
+ .get("href")
+ .asText();
+
+ assertThat(configLink).isEqualTo("/somewhere");
+ });
+ }
+
+ @Test
+ void shouldNotModifyObjectsWithUnsupportedMediaType() throws IOException {
+ URL resource = Resources.getResource("sonia/scm/repository/repository-001.json");
+ rootNode = objectMapper.readTree(resource);
+ JsonEnricherContext context = new JsonEnricherContext(
+ URI.create("/"),
+ MediaType.valueOf(VndMediaType.USER),
+ rootNode
+ );
+
+ linkEnricher.enrich(context);
+
+ boolean hasNewPullRequestLink = context.getResponseEntity()
+ .get("_links")
+ .has("new-link");
+
+ assertThat(hasNewPullRequestLink).isFalse();
+ }
+}
diff --git a/scm-core/src/test/resources/sonia/scm/repository/repository-001.json b/scm-core/src/test/resources/sonia/scm/repository/repository-001.json
new file mode 100644
index 0000000000..43ea136942
--- /dev/null
+++ b/scm-core/src/test/resources/sonia/scm/repository/repository-001.json
@@ -0,0 +1,42 @@
+{
+ "creationDate": "2018-11-09T09:48:32.732Z",
+ "description": "Handling static webresources made easy",
+ "healthCheckFailures": [],
+ "lastModified": "2018-11-09T09:49:20.973Z",
+ "namespace": "scmadmin",
+ "name": "web-resources",
+ "archived": false,
+ "type": "git",
+ "_links": {
+ "self": {
+ "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources"
+ },
+ "delete": {
+ "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources"
+ },
+ "update": {
+ "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources"
+ },
+ "permissions": {
+ "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources/permissions/"
+ },
+ "protocol": [
+ {
+ "href": "http://localhost:8081/scm/repo/scmadmin/web-resources",
+ "name": "http"
+ }
+ ],
+ "tags": {
+ "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources/tags/"
+ },
+ "branches": {
+ "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources/branches/"
+ },
+ "changesets": {
+ "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources/changesets/"
+ },
+ "sources": {
+ "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources/sources/"
+ }
+ }
+}
diff --git a/scm-core/src/test/resources/sonia/scm/repository/repository-collection-001.json b/scm-core/src/test/resources/sonia/scm/repository/repository-collection-001.json
new file mode 100644
index 0000000000..f4eeb24bbc
--- /dev/null
+++ b/scm-core/src/test/resources/sonia/scm/repository/repository-collection-001.json
@@ -0,0 +1,106 @@
+{
+ "page": 0,
+ "pageTotal": 1,
+ "_links": {
+ "self": {
+ "href": "http://localhost:8081/scm/api/v2/repositories/?page=0&pageSize=10"
+ },
+ "first": {
+ "href": "http://localhost:8081/scm/api/v2/repositories/?page=0&pageSize=10"
+ },
+ "last": {
+ "href": "http://localhost:8081/scm/api/v2/repositories/?page=0&pageSize=10"
+ },
+ "create": {
+ "href": "http://localhost:8081/scm/api/v2/repositories/"
+ }
+ },
+ "_embedded": {
+ "repositories": [
+ {
+ "creationDate": "2018-11-09T09:48:32.732Z",
+ "description": "Handling static webresources made easy",
+ "healthCheckFailures": [],
+ "lastModified": "2018-11-09T09:49:20.973Z",
+ "namespace": "scmadmin",
+ "name": "web-resources",
+ "archived": false,
+ "type": "git",
+ "_links": {
+ "self": {
+ "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources"
+ },
+ "delete": {
+ "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources"
+ },
+ "update": {
+ "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources"
+ },
+ "permissions": {
+ "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources/permissions/"
+ },
+ "protocol": [
+ {
+ "href": "http://localhost:8081/scm/repo/scmadmin/web-resources",
+ "name": "http"
+ }
+ ],
+ "tags": {
+ "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources/tags/"
+ },
+ "branches": {
+ "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources/branches/"
+ },
+ "changesets": {
+ "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources/changesets/"
+ },
+ "sources": {
+ "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources/sources/"
+ }
+ }
+ },
+ {
+ "creationDate": "2018-11-09T09:48:32.732Z",
+ "description": "Handling static webresources made easy",
+ "healthCheckFailures": [],
+ "lastModified": "2018-11-09T09:49:20.973Z",
+ "namespace": "scmadmin",
+ "name": "web-resources",
+ "archived": false,
+ "type": "git",
+ "_links": {
+ "self": {
+ "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources"
+ },
+ "delete": {
+ "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources"
+ },
+ "update": {
+ "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources"
+ },
+ "permissions": {
+ "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources/permissions/"
+ },
+ "protocol": [
+ {
+ "href": "http://localhost:8081/scm/repo/scmadmin/web-resources",
+ "name": "http"
+ }
+ ],
+ "tags": {
+ "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources/tags/"
+ },
+ "branches": {
+ "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources/branches/"
+ },
+ "changesets": {
+ "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources/changesets/"
+ },
+ "sources": {
+ "href": "http://localhost:8081/scm/api/v2/repositories/scmadmin/web-resources/sources/"
+ }
+ }
+ }
+ ]
+ }
+}
From 84e27b60d4e9b1b6edc3ab9c64159803d8da3f62 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?=
Date: Fri, 14 Dec 2018 17:20:22 +0100
Subject: [PATCH 23/35] Give attribute proper name
---
.../java/sonia/scm/web/AbstractRepositoryJsonEnricher.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/scm-core/src/main/java/sonia/scm/web/AbstractRepositoryJsonEnricher.java b/scm-core/src/main/java/sonia/scm/web/AbstractRepositoryJsonEnricher.java
index 38f353e24b..2cb4674d24 100644
--- a/scm-core/src/main/java/sonia/scm/web/AbstractRepositoryJsonEnricher.java
+++ b/scm-core/src/main/java/sonia/scm/web/AbstractRepositoryJsonEnricher.java
@@ -34,7 +34,7 @@ public abstract class AbstractRepositoryJsonEnricher extends JsonEnricherBase {
protected abstract void enrichRepositoryNode(JsonNode repositoryNode, String namespace, String name);
protected void addLink(JsonNode repositoryNode, String linkName, String link) {
- JsonNode newPullRequestNode = createObject(singletonMap("href", value(link)));
- addPropertyNode(repositoryNode.get("_links"), linkName, newPullRequestNode);
+ JsonNode hrefNode = createObject(singletonMap("href", value(link)));
+ addPropertyNode(repositoryNode.get("_links"), linkName, hrefNode);
}
}
From 01eb287bb0b2def04832733f34bc0a790cde20d9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?=
Date: Fri, 14 Dec 2018 16:21:36 +0000
Subject: [PATCH 24/35] Close branch feature/abstract_repository_enricher
From af7e776fddf742b47ddfe581347ecedf32b849e9 Mon Sep 17 00:00:00 2001
From: Sebastian Sdorra
Date: Mon, 17 Dec 2018 13:06:11 +0100
Subject: [PATCH 25/35] added getParentKey() to AccessToken interface
---
.../main/java/sonia/scm/security/AccessToken.java | 12 ++++++++++++
.../main/java/sonia/scm/security/JwtAccessToken.java | 1 +
2 files changed, 13 insertions(+)
diff --git a/scm-core/src/main/java/sonia/scm/security/AccessToken.java b/scm-core/src/main/java/sonia/scm/security/AccessToken.java
index c2a5f4b747..ac7700b030 100644
--- a/scm-core/src/main/java/sonia/scm/security/AccessToken.java
+++ b/scm-core/src/main/java/sonia/scm/security/AccessToken.java
@@ -80,8 +80,20 @@ public interface AccessToken {
*/
Date getExpiration();
+ /**
+ * Returns refresh expiration of token.
+ *
+ * @return refresh expiration
+ */
Optional getRefreshExpiration();
+ /**
+ * Returns id of the parent key.
+ *
+ * @return parent key id
+ */
+ Optional getParentKey();
+
/**
* Returns the scope of the token. The scope is able to reduce the permissions of the subject in the context of this
* token. For example we could issue a token which can only be used to read a single repository. for more informations
diff --git a/scm-webapp/src/main/java/sonia/scm/security/JwtAccessToken.java b/scm-webapp/src/main/java/sonia/scm/security/JwtAccessToken.java
index 8fb5929188..4418cb40a8 100644
--- a/scm-webapp/src/main/java/sonia/scm/security/JwtAccessToken.java
+++ b/scm-webapp/src/main/java/sonia/scm/security/JwtAccessToken.java
@@ -87,6 +87,7 @@ public final class JwtAccessToken implements AccessToken {
return ofNullable(claims.get(REFRESHABLE_UNTIL_CLAIM_KEY, Date.class));
}
+ @Override
public Optional getParentKey() {
return ofNullable(claims.get(PARENT_TOKEN_ID_CLAIM_KEY).toString());
}
From f041d63887d0f58fce1a95ee863f100b95c9f142 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?=
Date: Mon, 17 Dec 2018 14:01:15 +0100
Subject: [PATCH 26/35] Read link from repository for repository config
---
.../packages/ui-components/src/config/ConfigurationBinder.js | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/scm-ui-components/packages/ui-components/src/config/ConfigurationBinder.js b/scm-ui-components/packages/ui-components/src/config/ConfigurationBinder.js
index 960fe7db21..1b2b37bb19 100644
--- a/scm-ui-components/packages/ui-components/src/config/ConfigurationBinder.js
+++ b/scm-ui-components/packages/ui-components/src/config/ConfigurationBinder.js
@@ -63,8 +63,9 @@ class ConfigurationBinder {
// route for global configuration, passes the current repository to component
- const RepoRoute = ({ url, repository }) => {
- return this.route(url + to, );
+ const RepoRoute = ({url, repository}) => {
+ const link = repository._links[linkName].href
+ return this.route(url + to, );
};
// bind config route to extension point
From 3daf4f76747153c8888f8eee8cc727b44756653f Mon Sep 17 00:00:00 2001
From: Sebastian Sdorra
Date: Mon, 17 Dec 2018 14:58:51 +0100
Subject: [PATCH 27/35] implemented in-memory version of DataStore for testing
---
.../sonia/scm/store/InMemoryDataStore.java | 53 +++++++++++++++++++
.../scm/store/InMemoryDataStoreFactory.java | 26 +++++++++
2 files changed, 79 insertions(+)
create mode 100644 scm-test/src/main/java/sonia/scm/store/InMemoryDataStore.java
create mode 100644 scm-test/src/main/java/sonia/scm/store/InMemoryDataStoreFactory.java
diff --git a/scm-test/src/main/java/sonia/scm/store/InMemoryDataStore.java b/scm-test/src/main/java/sonia/scm/store/InMemoryDataStore.java
new file mode 100644
index 0000000000..06198d89bf
--- /dev/null
+++ b/scm-test/src/main/java/sonia/scm/store/InMemoryDataStore.java
@@ -0,0 +1,53 @@
+package sonia.scm.store;
+
+import sonia.scm.security.KeyGenerator;
+import sonia.scm.security.UUIDKeyGenerator;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * In memory store implementation of {@link DataStore}.
+ *
+ * @author Sebastian Sdorra
+ *
+ * @param type of stored object
+ */
+public class InMemoryDataStore implements DataStore {
+
+ private final Map store = new HashMap<>();
+ private KeyGenerator generator = new UUIDKeyGenerator();
+
+ @Override
+ public String put(T item) {
+ String key = generator.createKey();
+ store.put(key, item);
+ return key;
+ }
+
+ @Override
+ public void put(String id, T item) {
+ store.put(id, item);
+ }
+
+ @Override
+ public Map getAll() {
+ return Collections.unmodifiableMap(store);
+ }
+
+ @Override
+ public void clear() {
+ store.clear();
+ }
+
+ @Override
+ public void remove(String id) {
+ store.remove(id);
+ }
+
+ @Override
+ public T get(String id) {
+ return store.get(id);
+ }
+}
diff --git a/scm-test/src/main/java/sonia/scm/store/InMemoryDataStoreFactory.java b/scm-test/src/main/java/sonia/scm/store/InMemoryDataStoreFactory.java
new file mode 100644
index 0000000000..b0e95e9f9c
--- /dev/null
+++ b/scm-test/src/main/java/sonia/scm/store/InMemoryDataStoreFactory.java
@@ -0,0 +1,26 @@
+package sonia.scm.store;
+
+/**
+ * In memory configuration store factory for testing purposes.
+ *
+ * @author Sebastian Sdorra
+ */
+public class InMemoryDataStoreFactory implements DataStoreFactory {
+
+ private InMemoryDataStore store;
+
+ public InMemoryDataStoreFactory() {
+ }
+
+ public InMemoryDataStoreFactory(InMemoryDataStore store) {
+ this.store = store;
+ }
+
+ @Override
+ public DataStore getStore(TypedStoreParameters storeParameters) {
+ if (store != null) {
+ return store;
+ }
+ return new InMemoryDataStore<>();
+ }
+}
From 480801d3b00953d1f9e3006e0a23ebbc6b2de0c0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?=
Date: Mon, 17 Dec 2018 15:23:25 +0100
Subject: [PATCH 28/35] Do not keep directory for stores
---
.../scm/store/FileBasedStoreFactory.java | 21 ++++++++-----------
1 file changed, 9 insertions(+), 12 deletions(-)
diff --git a/scm-dao-xml/src/main/java/sonia/scm/store/FileBasedStoreFactory.java b/scm-dao-xml/src/main/java/sonia/scm/store/FileBasedStoreFactory.java
index 099ab53baa..d37a150723 100644
--- a/scm-dao-xml/src/main/java/sonia/scm/store/FileBasedStoreFactory.java
+++ b/scm-dao-xml/src/main/java/sonia/scm/store/FileBasedStoreFactory.java
@@ -58,8 +58,6 @@ public abstract class FileBasedStoreFactory {
private RepositoryLocationResolver repositoryLocationResolver;
private Store store;
- private File storeDirectory;
-
protected FileBasedStoreFactory(SCMContextProvider contextProvider , RepositoryLocationResolver repositoryLocationResolver, Store store) {
this.contextProvider = contextProvider;
this.repositoryLocationResolver = repositoryLocationResolver;
@@ -75,17 +73,16 @@ public abstract class FileBasedStoreFactory {
}
protected File getStoreLocation(String name, Class type, Repository repository) {
- if (storeDirectory == null) {
- if (repository != null) {
- LOG.debug("create store with type: {}, name: {} and repository: {}", type, name, repository.getNamespaceAndName());
- storeDirectory = this.getStoreDirectory(store, repository);
- } else {
- LOG.debug("create store with type: {} and name: {} ", type, name);
- storeDirectory = this.getStoreDirectory(store);
- }
- IOUtil.mkdirs(storeDirectory);
+ File storeDirectory;
+ if (repository != null) {
+ LOG.debug("create store with type: {}, name: {} and repository: {}", type, name, repository.getNamespaceAndName());
+ storeDirectory = this.getStoreDirectory(store, repository);
+ } else {
+ LOG.debug("create store with type: {} and name: {} ", type, name);
+ storeDirectory = this.getStoreDirectory(store);
}
- return new File(this.storeDirectory, name);
+ IOUtil.mkdirs(storeDirectory);
+ return new File(storeDirectory, name);
}
/**
From 4c0f99329326cb3711d115624a524fc7c53aefb7 Mon Sep 17 00:00:00 2001
From: Sebastian Sdorra
Date: Tue, 18 Dec 2018 09:26:51 +0100
Subject: [PATCH 29/35] added jaxb adapter for instant objects
---
.../java/sonia/scm/xml/XmlInstantAdapter.java | 25 ++++++++++
.../sonia/scm/xml/XmlInstantAdapterTest.java | 47 +++++++++++++++++++
2 files changed, 72 insertions(+)
create mode 100644 scm-core/src/main/java/sonia/scm/xml/XmlInstantAdapter.java
create mode 100644 scm-core/src/test/java/sonia/scm/xml/XmlInstantAdapterTest.java
diff --git a/scm-core/src/main/java/sonia/scm/xml/XmlInstantAdapter.java b/scm-core/src/main/java/sonia/scm/xml/XmlInstantAdapter.java
new file mode 100644
index 0000000000..9b8d718851
--- /dev/null
+++ b/scm-core/src/main/java/sonia/scm/xml/XmlInstantAdapter.java
@@ -0,0 +1,25 @@
+package sonia.scm.xml;
+
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+import java.time.Instant;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.TemporalAccessor;
+
+/**
+ * JAXB adapter for {@link Instant} objects.
+ *
+ * @since 2.0.0
+ */
+public class XmlInstantAdapter extends XmlAdapter {
+
+ @Override
+ public String marshal(Instant instant) {
+ return DateTimeFormatter.ISO_INSTANT.format(instant);
+ }
+
+ @Override
+ public Instant unmarshal(String text) {
+ TemporalAccessor parsed = DateTimeFormatter.ISO_INSTANT.parse(text);
+ return Instant.from(parsed);
+ }
+}
diff --git a/scm-core/src/test/java/sonia/scm/xml/XmlInstantAdapterTest.java b/scm-core/src/test/java/sonia/scm/xml/XmlInstantAdapterTest.java
new file mode 100644
index 0000000000..eb1ea86aee
--- /dev/null
+++ b/scm-core/src/test/java/sonia/scm/xml/XmlInstantAdapterTest.java
@@ -0,0 +1,47 @@
+package sonia.scm.xml;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junitpioneer.jupiter.TempDirectory;
+
+import javax.xml.bind.JAXB;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+import java.nio.file.Path;
+import java.time.Instant;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@ExtendWith(TempDirectory.class)
+class XmlInstantAdapterTest {
+
+ @Test
+ void shouldMarshalAndUnmarshalInstant(@TempDirectory.TempDir Path tempDirectory) {
+ Path path = tempDirectory.resolve("instant.xml");
+
+ Instant instant = Instant.now();
+ InstantObject object = new InstantObject(instant);
+ JAXB.marshal(object, path.toFile());
+
+ InstantObject unmarshaled = JAXB.unmarshal(path.toFile(), InstantObject.class);
+ assertEquals(instant, unmarshaled.instant);
+ }
+
+ @XmlRootElement(name = "instant-object")
+ @XmlAccessorType(XmlAccessType.FIELD)
+ public static class InstantObject {
+
+ @XmlJavaTypeAdapter(XmlInstantAdapter.class)
+ private Instant instant;
+
+ public InstantObject() {
+ }
+
+ InstantObject(Instant instant) {
+ this.instant = instant;
+ }
+ }
+
+}
From 13e3d54100b2d8aa1bba3b843355a84073cfbbb1 Mon Sep 17 00:00:00 2001
From: Sebastian Sdorra
Date: Tue, 18 Dec 2018 14:55:38 +0100
Subject: [PATCH 30/35] added constructor with predefined store
---
.../scm/store/InMemoryConfigurationStoreFactory.java | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/scm-test/src/main/java/sonia/scm/store/InMemoryConfigurationStoreFactory.java b/scm-test/src/main/java/sonia/scm/store/InMemoryConfigurationStoreFactory.java
index 2c5641bfd1..2180afdca2 100644
--- a/scm-test/src/main/java/sonia/scm/store/InMemoryConfigurationStoreFactory.java
+++ b/scm-test/src/main/java/sonia/scm/store/InMemoryConfigurationStoreFactory.java
@@ -42,8 +42,20 @@ package sonia.scm.store;
*/
public class InMemoryConfigurationStoreFactory implements ConfigurationStoreFactory {
+ private ConfigurationStore store;
+
+ public InMemoryConfigurationStoreFactory() {
+ }
+
+ public InMemoryConfigurationStoreFactory(ConfigurationStore store) {
+ this.store = store;
+ }
+
@Override
public ConfigurationStore getStore(TypedStoreParameters storeParameters) {
+ if (store != null) {
+ return store;
+ }
return new InMemoryConfigurationStore<>();
}
}
From 3bb85463885bda502f5426e1ea747ca7e796983e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?=
Date: Tue, 18 Dec 2018 14:57:00 +0000
Subject: [PATCH 31/35] Close branch feature/changes-for-cas-plugin
From 30c9b87cd3d7be614bd8188fc0d5734a0ead09e5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Maren=20S=C3=BCwer?=
Date: Wed, 19 Dec 2018 08:40:04 +0100
Subject: [PATCH 32/35] added is-clipped class, and show description not at
mobile view
---
scm-ui/src/repos/containers/RepositoryRoot.js | 2 +-
scm-ui/src/repos/sources/components/FileTree.js | 4 +++-
scm-ui/src/repos/sources/components/FileTreeLeaf.js | 5 ++++-
3 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/scm-ui/src/repos/containers/RepositoryRoot.js b/scm-ui/src/repos/containers/RepositoryRoot.js
index 81de0296fc..a3f69fe70b 100644
--- a/scm-ui/src/repos/containers/RepositoryRoot.js
+++ b/scm-ui/src/repos/containers/RepositoryRoot.js
@@ -114,7 +114,7 @@ class RepositoryRoot extends React.Component {
return (
-
+
{
|
{t("sources.file-tree.lastModified")}
|
- {t("sources.file-tree.description")} |
+
+ {t("sources.file-tree.description")}
+ |
diff --git a/scm-ui/src/repos/sources/components/FileTreeLeaf.js b/scm-ui/src/repos/sources/components/FileTreeLeaf.js
index f7f9feb52e..724a80e742 100644
--- a/scm-ui/src/repos/sources/components/FileTreeLeaf.js
+++ b/scm-ui/src/repos/sources/components/FileTreeLeaf.js
@@ -6,6 +6,7 @@ import FileSize from "./FileSize";
import FileIcon from "./FileIcon";
import { Link } from "react-router-dom";
import type { File } from "@scm-manager/ui-types";
+import classNames from "classnames";
const styles = {
iconColumn: {
@@ -84,7 +85,9 @@ class FileTreeLeaf extends React.Component {
|
- {file.description} |
+
+ {file.description}
+ |
);
}
From ee90707fcc82d792a0780e08adb1075697b6f286 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Maren=20S=C3=BCwer?=
Date: Wed, 19 Dec 2018 07:50:48 +0000
Subject: [PATCH 33/35] Close branch bug/single_source_overflow
From 0d8e0fef8e6fdf7d2afb7555729f52b1482ee151 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Maren=20S=C3=BCwer?=
Date: Wed, 19 Dec 2018 08:26:50 +0000
Subject: [PATCH 34/35] Close branch bug/table_navi_overflow
From d8c5349994bde1ed7cfde64debaf3806a33189b4 Mon Sep 17 00:00:00 2001
From: Florian Scholdei
Date: Wed, 19 Dec 2018 09:47:44 +0100
Subject: [PATCH 35/35] outsourced and refactored is-word-break class
---
scm-ui/src/repos/sources/components/FileTreeLeaf.js | 11 +++--------
scm-ui/styles/scm.scss | 8 ++++++++
2 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/scm-ui/src/repos/sources/components/FileTreeLeaf.js b/scm-ui/src/repos/sources/components/FileTreeLeaf.js
index 724a80e742..20905a8354 100644
--- a/scm-ui/src/repos/sources/components/FileTreeLeaf.js
+++ b/scm-ui/src/repos/sources/components/FileTreeLeaf.js
@@ -12,12 +12,7 @@ const styles = {
iconColumn: {
width: "16px"
},
- wordBreakColumn: {
- WebkitHyphens: "auto",
- MozHyphens: "auto",
- MsHyphens: "auto",
- hyphens: "auto",
- wordBreak: "break-all",
+ wordBreakMinWidth: {
minWidth: "10em"
}
};
@@ -80,12 +75,12 @@ class FileTreeLeaf extends React.Component {
return (
| {this.createFileIcon(file)} |
- {this.createFileName(file)} |
+ {this.createFileName(file)} |
{fileSize} |
|
-
+ |
{file.description}
|
diff --git a/scm-ui/styles/scm.scss b/scm-ui/styles/scm.scss
index 4d306df6ad..8937ae3068 100644
--- a/scm-ui/styles/scm.scss
+++ b/scm-ui/styles/scm.scss
@@ -27,6 +27,14 @@ $blue: #33B2E8;
padding: 0 0 0 3.8em !important;
}
+.is-word-break {
+ -webkit-hyphens: auto;
+ -moz-hyphens: auto;
+ -ms-hyphens: auto;
+ hyphens: auto;
+ word-break: break-all;
+}
+
.main {
min-height: calc(100vh - 260px);
}
|