mirror of
https://github.com/scm-manager/scm-manager.git
synced 2026-01-28 02:09:09 +01:00
merge
This commit is contained in:
@@ -5,8 +5,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## Unreleased
|
||||
### Added
|
||||
- Permissions can be specified for namespaces ([#1335](https://github.com/scm-manager/scm-manager/pull/1335))
|
||||
### Fixed
|
||||
- Missing synchronization during repository creation ([#1328](https://github.com/scm-manager/scm-manager/pull/1328))
|
||||
- Missing BranchCreatedEvent for mercurial ([#1334](https://github.com/scm-manager/scm-manager/pull/1334))
|
||||
- Branch not found right after creation ([#1334](https://github.com/scm-manager/scm-manager/pull/1334))
|
||||
|
||||
## [2.5.0] - 2020-09-10
|
||||
### Added
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 199 KiB After Width: | Height: | Size: 187 KiB |
@@ -26,6 +26,8 @@ Icon | Beschreibung
|
||||
 | Öffnet die Sources-Übersicht für das Repository
|
||||
 | Öffnet die Einstellungen für das Repository
|
||||
|
||||
Zusätzlich können über das Icon rechts neben den Überschriften für die Namespaces weitere Einstellungen auf Namespace-Ebene vorgenommen werden.
|
||||
|
||||
### Repository erstellen
|
||||
Im SCM-Manager können neue Git, Mercurial & Subersion (SVN) Repositories über ein Formular angelegt werden. Dieses kann über den Button "Repository erstellen" aufgerufen werden. Dabei muss ein gültiger Name eingetragen und der Repository-Typ bestimmt werden.
|
||||
|
||||
|
||||
@@ -12,10 +12,12 @@ Innerhalb der Gefahrenzone unten auf der Seite gibt es mit entsprechenden Rechte
|
||||

|
||||
|
||||
### Berechtigungen
|
||||
Dank des fein granularen Berechtigungskonzepts des SCM-Managers können Nutzern und Gruppen, basierend auf definierbaren Rollen oder auf individuellen Einstellungen, Rechte zugewiesen werden. Berechtigungen können global und auf Repository-Ebene vergeben werden. Globale Berechtigungen werden in der Administrations-Oberfläche des SCM-Managers vergeben. Unter diesem Eintrag handelt es sich um Repository-bezogene Berechtigungen.
|
||||
Dank des fein granularen Berechtigungskonzepts des SCM-Managers können Nutzern und Gruppen, basierend auf definierbaren Rollen oder auf individuellen Einstellungen, Rechte zugewiesen werden. Berechtigungen können global, auf Namespace-Ebene und auf Repository-Ebene vergeben werden. Globale Berechtigungen werden in der Administrations-Oberfläche des SCM-Managers vergeben. Unter diesem Eintrag handelt es sich um Repository-bezogene Berechtigungen.
|
||||
|
||||
Die Berechtigungen können jeweils für Gruppen und für Benutzer vergeben werden. Dabei gibt es die Möglichkeiten die Berechtigungen über Berechtigungsrollen zu definieren oder jede Berechtigung einzeln zu vergeben. Die Berechtigungsrollen können in der Administrations-Oberfläche definiert werden.
|
||||
|
||||
Berechtigungen auf Namespace-Ebene können über die Einstellungen für Namespaces bearbeitet werden. Diese sind über das Einstellungs-Symbol neben den Namespace-Überschriften auf der Repository-Übersicht erreichbar.
|
||||
|
||||

|
||||
|
||||
Für individuelle Berechtigungen kann man über "Erweitert" einen Dialog öffnen, um jede Berechtigung einzeln zu vergeben.
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 199 KiB After Width: | Height: | Size: 187 KiB |
@@ -24,6 +24,8 @@ Icon | Description
|
||||
 | Opens the sources overview for the repository
|
||||
 | Opens the settings for the repository
|
||||
|
||||
Clicking the icon on the right-hand side of each namespace caption, you can change additional settings for this namespace.
|
||||
|
||||
### Create a Repository
|
||||
In SCM-Manager new Git, Mercurial & Subversion (SVN) repositories can be created via a form that can be accessed via the "Create Repository" button. A valid name and the repository type are mandatory.
|
||||
|
||||
|
||||
@@ -12,10 +12,12 @@ In the danger zone at the bottom you may rename the repository or delete it. If
|
||||

|
||||
|
||||
### Permissions
|
||||
Thanks to the finely granular permission concept of SCM-Manager, users and groups can be authorized based on definable roles or individual settings. Permissions can be granted globally or repository-specific. Global permissions are managed in the administration area of SCM-Manager. The following image shows repository-specific permissions.
|
||||
Thanks to the finely granular permission concept of SCM-Manager, users and groups can be authorized based on definable roles or individual settings. Permissions can be granted globally, namespace-wide, or repository-specific. Global permissions are managed in the administration area of SCM-Manager. The following image shows repository-specific permissions.
|
||||
|
||||
Permissions can be granted to groups or users. It is possible to manage each permission individually or to create roles that contain several permissions. Roles can be defined in the administration area.
|
||||
|
||||
Namespace-wide permissions can be configured in the namespace settings. These can be accessed via the settings icon on the right-hand side of the namespace heading in the repository overview.
|
||||
|
||||

|
||||
|
||||
To manage permissions individually, an "Advanced" dialog can be opened to manage every single permission.
|
||||
|
||||
2
pom.xml
2
pom.xml
@@ -903,7 +903,7 @@
|
||||
|
||||
<properties>
|
||||
<!-- test libraries -->
|
||||
<mockito.version>3.5.6</mockito.version>
|
||||
<mockito.version>3.5.7</mockito.version>
|
||||
<hamcrest.version>2.1</hamcrest.version>
|
||||
<junit.version>5.6.2</junit.version>
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.repository;
|
||||
|
||||
|
||||
import sonia.scm.HandlerEventType;
|
||||
import sonia.scm.event.AbstractHandlerEvent;
|
||||
import sonia.scm.event.Event;
|
||||
|
||||
/**
|
||||
* The NamespaceEvent is fired if a {@link Namespace} object changes.
|
||||
*
|
||||
* @since 2.6.0
|
||||
*/
|
||||
@Event
|
||||
public class NamespaceEvent extends AbstractHandlerEvent<Namespace> {
|
||||
|
||||
public NamespaceEvent(HandlerEventType eventType, Namespace namespace) {
|
||||
super(eventType, namespace);
|
||||
}
|
||||
|
||||
public NamespaceEvent(HandlerEventType eventType, Namespace namespace, Namespace oldNamespace) {
|
||||
super(eventType, namespace, oldNamespace);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.repository;
|
||||
|
||||
import sonia.scm.HandlerEventType;
|
||||
import sonia.scm.ModificationHandlerEvent;
|
||||
import sonia.scm.event.Event;
|
||||
|
||||
/**
|
||||
* Event which is fired whenever a namespace is modified.
|
||||
*
|
||||
* @since 2.6.0
|
||||
*/
|
||||
@Event
|
||||
public final class NamespaceModificationEvent extends NamespaceEvent implements ModificationHandlerEvent<Namespace> {
|
||||
|
||||
private final Namespace itemBeforeModification;
|
||||
|
||||
public NamespaceModificationEvent(HandlerEventType eventType, Namespace item, Namespace itemBeforeModification) {
|
||||
super(eventType, item, itemBeforeModification);
|
||||
this.itemBeforeModification = itemBeforeModification;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Namespace getItemBeforeModification() {
|
||||
return itemBeforeModification;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,13 +21,14 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.repository;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.base.Objects;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import sonia.scm.security.PermissionObject;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
@@ -118,8 +119,7 @@ public class RepositoryPermission implements PermissionObject, Serializable
|
||||
final RepositoryPermission other = (RepositoryPermission) obj;
|
||||
|
||||
return Objects.equal(name, other.name)
|
||||
&& verbs.size() == other.verbs.size()
|
||||
&& verbs.containsAll(other.verbs)
|
||||
&& (verbs == null && other.verbs == null || verbs != null && other.verbs != null && CollectionUtils.isEqualCollection(verbs, other.verbs))
|
||||
&& Objects.equal(role, other.role)
|
||||
&& Objects.equal(groupPermission, other.groupPermission);
|
||||
}
|
||||
|
||||
@@ -21,21 +21,51 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.repository.api;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.event.ScmEventBus;
|
||||
import sonia.scm.repository.Branch;
|
||||
import sonia.scm.repository.BranchCreatedEvent;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.spi.BranchCommand;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @since 2.0
|
||||
*/
|
||||
public final class BranchCommandBuilder {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(BranchCommandBuilder.class);
|
||||
|
||||
private final Repository repository;
|
||||
private final BranchCommand command;
|
||||
private final ScmEventBus eventBus;
|
||||
private final BranchRequest request = new BranchRequest();
|
||||
|
||||
public BranchCommandBuilder(Repository repository, BranchCommand command) {
|
||||
this(repository, command, ScmEventBus.getInstance());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link BranchCommandBuilder}.
|
||||
*
|
||||
* @param command type specific command implementation
|
||||
*
|
||||
* @deprecated use {@link #BranchCommandBuilder(Repository, BranchCommand)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public BranchCommandBuilder(BranchCommand command) {
|
||||
this(null, command, ScmEventBus.getInstance());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
BranchCommandBuilder(Repository repository, BranchCommand command, ScmEventBus eventBus) {
|
||||
this.repository = repository;
|
||||
this.command = command;
|
||||
this.eventBus = eventBus;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,17 +83,23 @@ public final class BranchCommandBuilder {
|
||||
* Execute the command and create a new branch with the given name.
|
||||
* @param name The name of the new branch.
|
||||
* @return The created branch.
|
||||
* @throws IOException
|
||||
*/
|
||||
public Branch branch(String name) {
|
||||
request.setNewBranch(name);
|
||||
return command.branch(request);
|
||||
Branch branch = command.branch(request);
|
||||
fireCreatedEvent(branch);
|
||||
return branch;
|
||||
}
|
||||
|
||||
private void fireCreatedEvent(Branch branch) {
|
||||
if (repository != null) {
|
||||
eventBus.post(new BranchCreatedEvent(repository, branch.getName()));
|
||||
} else {
|
||||
LOG.warn("the branch command was created without a repository, so we are not able to fire a BranchCreatedEvent");
|
||||
}
|
||||
}
|
||||
|
||||
public void delete(String branchName) {
|
||||
command.deleteOrClose(branchName);
|
||||
}
|
||||
|
||||
private BranchCommand command;
|
||||
private BranchRequest request = new BranchRequest();
|
||||
}
|
||||
|
||||
@@ -177,7 +177,7 @@ public final class RepositoryService implements Closeable {
|
||||
LOG.debug("create branch command for repository {}",
|
||||
repository.getNamespaceAndName());
|
||||
|
||||
return new BranchCommandBuilder(provider.getBranchCommand());
|
||||
return new BranchCommandBuilder(repository, provider.getBranchCommand());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -298,10 +298,12 @@ public final class RepositoryServiceFactory {
|
||||
|
||||
/**
|
||||
* Clear caches on repository push.
|
||||
* We do this synchronously, because there are often workflows which are creating branches and fetch them straight
|
||||
* after the creation.
|
||||
*
|
||||
* @param event hook event
|
||||
*/
|
||||
@Subscribe(referenceType = ReferenceType.STRONG)
|
||||
@Subscribe(async = false, referenceType = ReferenceType.STRONG)
|
||||
public void onEvent(PostReceiveRepositoryHookEvent event) {
|
||||
Repository repository = event.getRepository();
|
||||
|
||||
@@ -324,13 +326,6 @@ public final class RepositoryServiceFactory {
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe(async = false)
|
||||
@SuppressWarnings({"unchecked", "java:S3740", "rawtypes"})
|
||||
public void onEvent(BranchCreatedEvent event) {
|
||||
RepositoryCacheKeyPredicate predicate = new RepositoryCacheKeyPredicate(event.getRepository().getId());
|
||||
cacheManager.getCache(BranchesCommandBuilder.CACHE_NAME).removeAll(predicate);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onEvent(PublicKeyDeletedEvent event) {
|
||||
cacheManager.getCache(LogCommandBuilder.CACHE_NAME).clear();
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.repository.api;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import sonia.scm.event.ScmEventBus;
|
||||
import sonia.scm.repository.Branch;
|
||||
import sonia.scm.repository.BranchCreatedEvent;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.spi.BranchCommand;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class BranchCommandBuilderTest {
|
||||
|
||||
@Mock
|
||||
private BranchCommand command;
|
||||
|
||||
@Mock
|
||||
private ScmEventBus eventBus;
|
||||
|
||||
private final Repository repository = new Repository("42", "git", "spaceships", "heart-of-gold");
|
||||
|
||||
private final String branchName = "feature/infinite_improbability_drive";
|
||||
private final Branch branch = Branch.normalBranch(branchName, "42");
|
||||
|
||||
@Nested
|
||||
class Creation {
|
||||
|
||||
@BeforeEach
|
||||
void configureMocks() {
|
||||
when(command.branch(any())).thenReturn(branch);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDelegateCreationToCommand() {
|
||||
BranchCommandBuilder builder = new BranchCommandBuilder(repository, command, eventBus);
|
||||
Branch returnedBranch = builder.branch(branchName);
|
||||
assertThat(branch).isSameAs(returnedBranch);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSendBranchCreatedEvent() {
|
||||
BranchCommandBuilder builder = new BranchCommandBuilder(repository, command, eventBus);
|
||||
builder.branch(branchName);
|
||||
|
||||
ArgumentCaptor<BranchCreatedEvent> captor = ArgumentCaptor.forClass(BranchCreatedEvent.class);
|
||||
verify(eventBus).post(captor.capture());
|
||||
BranchCreatedEvent event = captor.getValue();
|
||||
assertThat(event.getBranchName()).isEqualTo("feature/infinite_improbability_drive");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotSendEventWithoutRepository() {
|
||||
BranchCommandBuilder builder = new BranchCommandBuilder(null, command, eventBus);
|
||||
builder.branch(branchName);
|
||||
|
||||
verify(eventBus, never()).post(any());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Nested
|
||||
class Deletion {
|
||||
|
||||
@Test
|
||||
void shouldDelegateDeletionToCommand() {
|
||||
BranchCommandBuilder builder = new BranchCommandBuilder(repository, command, eventBus);
|
||||
builder.delete(branchName);
|
||||
verify(command).deleteOrClose(branchName);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -30,7 +30,6 @@ import org.eclipse.jgit.api.errors.GitAPIException;
|
||||
import org.eclipse.jgit.lib.Ref;
|
||||
import sonia.scm.event.ScmEventBus;
|
||||
import sonia.scm.repository.Branch;
|
||||
import sonia.scm.repository.BranchCreatedEvent;
|
||||
import sonia.scm.repository.GitUtil;
|
||||
import sonia.scm.repository.InternalRepositoryException;
|
||||
import sonia.scm.repository.PostReceiveRepositoryHookEvent;
|
||||
@@ -48,9 +47,7 @@ import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Collections.singleton;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static java.util.Collections.*;
|
||||
import static sonia.scm.ContextEntry.ContextBuilder.entity;
|
||||
|
||||
public class GitBranchCommand extends AbstractGitCommand implements BranchCommand {
|
||||
@@ -72,8 +69,6 @@ public class GitBranchCommand extends AbstractGitCommand implements BranchComman
|
||||
eventBus.post(new PreReceiveRepositoryHookEvent(hookEvent));
|
||||
Ref ref = git.branchCreate().setStartPoint(request.getParentBranch()).setName(request.getNewBranch()).call();
|
||||
eventBus.post(new PostReceiveRepositoryHookEvent(hookEvent));
|
||||
// Clear cache synchronously to avoid branch not found in invalid cache
|
||||
eventBus.post(new BranchCreatedEvent(repository, request.getNewBranch()));
|
||||
return Branch.normalBranch(request.getNewBranch(), GitUtil.getId(ref.getObjectId()));
|
||||
} catch (GitAPIException | IOException ex) {
|
||||
throw new InternalRepositoryException(repository, "could not create branch " + request.getNewBranch(), ex);
|
||||
|
||||
@@ -104,7 +104,8 @@ public class GitBranchCommandTest extends AbstractGitCommandTestBase {
|
||||
@Test
|
||||
public void shouldThrowExceptionWhenDeletingDefaultBranch() {
|
||||
String branchToBeDeleted = "master";
|
||||
assertThrows(CannotDeleteDefaultBranchException.class, () -> createCommand().deleteOrClose(branchToBeDeleted));
|
||||
GitBranchCommand command = createCommand();
|
||||
assertThrows(CannotDeleteDefaultBranchException.class, () -> command.deleteOrClose(branchToBeDeleted));
|
||||
}
|
||||
|
||||
private GitBranchCommand createCommand() {
|
||||
@@ -130,7 +131,6 @@ public class GitBranchCommandTest extends AbstractGitCommandTestBase {
|
||||
List<Object> events = captor.getAllValues();
|
||||
assertThat(events.get(0)).isInstanceOf(PreReceiveRepositoryHookEvent.class);
|
||||
assertThat(events.get(1)).isInstanceOf(PostReceiveRepositoryHookEvent.class);
|
||||
assertThat(events.get(2)).isInstanceOf(BranchCreatedEvent.class);
|
||||
|
||||
PreReceiveRepositoryHookEvent event = (PreReceiveRepositoryHookEvent) events.get(0);
|
||||
assertThat(event.getContext().getBranchProvider().getCreatedOrModified()).containsExactly("new_branch");
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"babel-loader": "^8.0.6",
|
||||
"css-loader": "^3.2.0",
|
||||
"file-loader": "^4.2.0",
|
||||
"mini-css-extract-plugin": "^0.10.0",
|
||||
"mini-css-extract-plugin": "^0.11.0",
|
||||
"mustache": "^3.1.0",
|
||||
"optimize-css-assets-webpack-plugin": "^5.0.3",
|
||||
"react-refresh": "^0.8.0",
|
||||
|
||||
9
scm-ui/ui-webapp/public/locales/de/namespaces.json
Normal file
9
scm-ui/ui-webapp/public/locales/de/namespaces.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"namespaceRoot": {
|
||||
"menu": {
|
||||
"navigationLabel": "Namespace",
|
||||
"settingsNavLink": "Einstellungen",
|
||||
"permissionsNavLink": "Berechtigungen"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -218,7 +218,8 @@
|
||||
"renameRepo": {
|
||||
"button": "Repository umbenennen",
|
||||
"subtitle": "Benennt dieses Repository um",
|
||||
"description": "Es werden keine Weiterleitung auf den neuen Namen eingerichtet.",
|
||||
"description1": "Es werden keine Weiterleitung auf den neuen Namen eingerichtet.",
|
||||
"description2": "Berechtigungen aus dem Namespace werden bei einem Wechsel nicht übernommen.",
|
||||
"modal": {
|
||||
"title": "Repository umbenennen",
|
||||
"label": {
|
||||
|
||||
@@ -218,7 +218,8 @@
|
||||
"renameRepo": {
|
||||
"button": "Rename Repository",
|
||||
"subtitle": "Renames this repository",
|
||||
"description": "There will be no redirects to the renamed repository.",
|
||||
"description1": "There will be no redirects to the renamed repository.",
|
||||
"description2": "Permissions from the namespace will not be adapted when the namespace is changed.",
|
||||
"modal": {
|
||||
"title": "Rename repository",
|
||||
"label": {
|
||||
|
||||
@@ -73,21 +73,29 @@ it("should group the repositories by their namespace", () => {
|
||||
hitchhikerHeartOfGold,
|
||||
hitchhikerPuzzle42
|
||||
];
|
||||
const namespaces = {
|
||||
_embedded: {
|
||||
namespaces: [{ namespace: "hitchhiker" }, { namespace: "slarti" }, { namespace: "zaphod" }]
|
||||
}
|
||||
};
|
||||
|
||||
const expected = [
|
||||
{
|
||||
name: "hitchhiker",
|
||||
namespace: { namespace: "hitchhiker" },
|
||||
repositories: [hitchhikerHeartOfGold, hitchhikerPuzzle42, hitchhikerRestand]
|
||||
},
|
||||
{
|
||||
name: "slarti",
|
||||
namespace: { namespace: "slarti" },
|
||||
repositories: [slartiFjords, slartiBlueprintsFjords]
|
||||
},
|
||||
{
|
||||
name: "zaphod",
|
||||
namespace: { namespace: "zaphod" },
|
||||
repositories: [zaphodMarvinFirmware]
|
||||
}
|
||||
];
|
||||
|
||||
expect(groupByNamespace(repositories)).toEqual(expected);
|
||||
expect(groupByNamespace(repositories, namespaces)).toEqual(expected);
|
||||
});
|
||||
|
||||
@@ -76,7 +76,7 @@ const DangerZone: FC<Props> = ({ repository, indexLinks }) => {
|
||||
<>
|
||||
<hr />
|
||||
<Subtitle subtitle={t("repositoryForm.dangerZone")} />
|
||||
<DangerZoneContainer>{dangerZone.map(entry => entry)}</DangerZoneContainer>
|
||||
<DangerZoneContainer>{dangerZone}</DangerZoneContainer>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -159,7 +159,9 @@ const RenameRepository: FC<Props> = ({ repository, indexLinks }) => {
|
||||
<p>
|
||||
<strong>{t("renameRepo.subtitle")}</strong>
|
||||
<br />
|
||||
{t("renameRepo.description")}
|
||||
{t("renameRepo.description1")}
|
||||
<br />
|
||||
{t("renameRepo.description2")}
|
||||
</p>
|
||||
}
|
||||
right={
|
||||
|
||||
@@ -123,7 +123,6 @@ class NamespaceRoot extends React.Component<Props> {
|
||||
</Page>
|
||||
</StateMenuContextProvider>
|
||||
);
|
||||
// return <h1>{`HALLO ${this.props.namespace}`}</h1>;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import sonia.scm.NotFoundException;
|
||||
import sonia.scm.repository.Namespace;
|
||||
import sonia.scm.repository.NamespaceManager;
|
||||
import sonia.scm.repository.NamespacePermissions;
|
||||
import sonia.scm.repository.RepositoryPermission;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
@@ -50,7 +49,6 @@ import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.net.URI;
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@@ -120,7 +118,6 @@ public class NamespacePermissionResource {
|
||||
public Response create(@PathParam("namespace") String namespaceName, @Valid RepositoryPermissionDto permission) {
|
||||
log.info("try to add new permission: {}", permission);
|
||||
Namespace namespace = load(namespaceName);
|
||||
NamespacePermissions.permissionWrite().check();
|
||||
checkPermissionAlreadyExists(permission, namespace);
|
||||
namespace.addPermission(dtoToModelMapper.map(permission));
|
||||
manager.modify(namespace);
|
||||
@@ -164,7 +161,6 @@ public class NamespacePermissionResource {
|
||||
)
|
||||
public RepositoryPermissionDto get(@PathParam("namespace") String namespaceName, @PathParam("permission-name") String permissionName) {
|
||||
Namespace namespace = load(namespaceName);
|
||||
NamespacePermissions.permissionRead().check();
|
||||
return
|
||||
namespace.getPermissions()
|
||||
.stream()
|
||||
@@ -210,7 +206,6 @@ public class NamespacePermissionResource {
|
||||
)
|
||||
public HalRepresentation getAll(@PathParam("namespace") String namespaceMame) {
|
||||
Namespace namespace = load(namespaceMame);
|
||||
NamespacePermissions.permissionRead().check();
|
||||
return repositoryPermissionCollectionToDtoMapper.map(namespace);
|
||||
}
|
||||
|
||||
@@ -241,7 +236,6 @@ public class NamespacePermissionResource {
|
||||
@Valid RepositoryPermissionDto permission) {
|
||||
log.info("try to update the permission with name: {}. the modified permission is: {}", permissionName, permission);
|
||||
Namespace namespace = load(namespaceName);
|
||||
NamespacePermissions.permissionWrite().check();
|
||||
String extractedPermissionName = getPermissionName(permissionName);
|
||||
if (!isPermissionExist(new RepositoryPermissionDto(extractedPermissionName, isGroupPermission(permissionName)), namespace)) {
|
||||
throw notFound(entity(RepositoryPermission.class, permissionName).in(Namespace.class, namespaceName));
|
||||
@@ -289,7 +283,6 @@ public class NamespacePermissionResource {
|
||||
@PathParam("permission-name") String permissionName) {
|
||||
log.info("try to delete the permission with name: {}.", permissionName);
|
||||
Namespace namespace = load(namespaceName);
|
||||
NamespacePermissions.permissionWrite().check();
|
||||
namespace.getPermissions()
|
||||
.stream()
|
||||
.filter(filterPermission(permissionName))
|
||||
|
||||
@@ -24,6 +24,10 @@
|
||||
|
||||
package sonia.scm.repository;
|
||||
|
||||
import com.github.legman.Subscribe;
|
||||
import sonia.scm.HandlerEventType;
|
||||
import sonia.scm.event.ScmEventBus;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
@@ -36,11 +40,13 @@ public class DefaultNamespaceManager implements NamespaceManager {
|
||||
|
||||
private final RepositoryManager repositoryManager;
|
||||
private final NamespaceDao dao;
|
||||
private final ScmEventBus eventBus;
|
||||
|
||||
@Inject
|
||||
public DefaultNamespaceManager(RepositoryManager repositoryManager, NamespaceDao dao) {
|
||||
public DefaultNamespaceManager(RepositoryManager repositoryManager, NamespaceDao dao, ScmEventBus eventBus) {
|
||||
this.repositoryManager = repositoryManager;
|
||||
this.dao = dao;
|
||||
this.eventBus = eventBus;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -64,15 +70,45 @@ public class DefaultNamespaceManager implements NamespaceManager {
|
||||
|
||||
@Override
|
||||
public void modify(Namespace namespace) {
|
||||
if (!get(namespace.getNamespace()).isPresent()) {
|
||||
throw notFound(entity("Namespace", namespace.getNamespace()));
|
||||
}
|
||||
NamespacePermissions.permissionWrite().check();
|
||||
Namespace oldNamespace = get(namespace.getNamespace())
|
||||
.orElseThrow(() -> notFound(entity(Namespace.class, namespace.getNamespace())));
|
||||
fireEvent(HandlerEventType.BEFORE_MODIFY, namespace, oldNamespace);
|
||||
dao.add(namespace);
|
||||
fireEvent(HandlerEventType.MODIFY, namespace, oldNamespace);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void cleanupDeletedNamespaces(RepositoryEvent repositoryEvent) {
|
||||
HandlerEventType eventType = repositoryEvent.getEventType();
|
||||
if (eventType == HandlerEventType.DELETE || eventType == HandlerEventType.MODIFY && !repositoryEvent.getItem().getNamespace().equals(repositoryEvent.getOldItem().getNamespace())) {
|
||||
Collection<String> allNamespaces = repositoryManager.getAllNamespaces();
|
||||
String oldNamespace = getOldNamespace(repositoryEvent);
|
||||
if (!allNamespaces.contains(oldNamespace)) {
|
||||
dao.delete(oldNamespace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getOldNamespace(RepositoryEvent repositoryEvent) {
|
||||
if (repositoryEvent.getEventType() == HandlerEventType.DELETE) {
|
||||
return repositoryEvent.getItem().getNamespace();
|
||||
} else {
|
||||
return repositoryEvent.getOldItem().getNamespace();
|
||||
}
|
||||
}
|
||||
|
||||
private Namespace createNamespaceForName(String namespace) {
|
||||
return dao.get(namespace)
|
||||
.map(Namespace::clone)
|
||||
.orElse(new Namespace(namespace));
|
||||
if (NamespacePermissions.permissionRead().isPermitted()) {
|
||||
return dao.get(namespace)
|
||||
.map(Namespace::clone)
|
||||
.orElse(new Namespace(namespace));
|
||||
} else {
|
||||
return new Namespace(namespace);
|
||||
}
|
||||
}
|
||||
|
||||
protected void fireEvent(HandlerEventType event, Namespace namespace, Namespace oldNamespace) {
|
||||
eventBus.post(new NamespaceModificationEvent(event, namespace, oldNamespace));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,4 +46,8 @@ public class NamespaceDao {
|
||||
public void add(Namespace namespace) {
|
||||
store.put(namespace.getNamespace(), namespace);
|
||||
}
|
||||
|
||||
public void delete(String namespace) {
|
||||
store.remove(namespace);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.security;
|
||||
|
||||
import com.github.legman.Subscribe;
|
||||
@@ -35,14 +35,19 @@ import sonia.scm.event.ScmEventBus;
|
||||
import sonia.scm.group.Group;
|
||||
import sonia.scm.group.GroupEvent;
|
||||
import sonia.scm.group.GroupModificationEvent;
|
||||
import sonia.scm.repository.Namespace;
|
||||
import sonia.scm.repository.NamespaceEvent;
|
||||
import sonia.scm.repository.NamespaceModificationEvent;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryEvent;
|
||||
import sonia.scm.repository.RepositoryModificationEvent;
|
||||
import sonia.scm.repository.RepositoryPermission;
|
||||
import sonia.scm.user.User;
|
||||
import sonia.scm.user.UserEvent;
|
||||
import sonia.scm.user.UserModificationEvent;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Receives all kinds of events, which affects authorization relevant data and fires an
|
||||
@@ -146,23 +151,45 @@ public class AuthorizationChangedEventProducer {
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onEvent(NamespaceEvent event) {
|
||||
if (event.getEventType().isPost() && isModificationEvent(event)) {
|
||||
handleNamespaceModificationEvent((NamespaceModificationEvent) event);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleRepositoryModificationEvent(RepositoryModificationEvent event) {
|
||||
Repository repository = event.getItem();
|
||||
if (isAuthorizationDataModified(repository, event.getItemBeforeModification())) {
|
||||
if (isAuthorizationDataModified(repository.getPermissions(), event.getItemBeforeModification().getPermissions())) {
|
||||
logger.debug(
|
||||
"fire authorization changed event, because a relevant field of repository {} has changed", repository.getName()
|
||||
"fire authorization changed event, because a relevant field of repository {}/{} has changed", repository.getNamespace(), repository.getName()
|
||||
);
|
||||
fireEventForEveryUser();
|
||||
} else {
|
||||
logger.debug(
|
||||
"authorization changed event is not fired, because non relevant field of repository {} has changed",
|
||||
repository.getName()
|
||||
"authorization changed event is not fired, because non relevant field of repository {}/{} has changed",
|
||||
repository.getNamespace(), repository.getName()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAuthorizationDataModified(Repository repository, Repository beforeModification) {
|
||||
return !(repository.getPermissions().containsAll(beforeModification.getPermissions()) && beforeModification.getPermissions().containsAll(repository.getPermissions()));
|
||||
private void handleNamespaceModificationEvent(NamespaceModificationEvent event) {
|
||||
Namespace namespace = event.getItem();
|
||||
if (isAuthorizationDataModified(namespace.getPermissions(), event.getItemBeforeModification().getPermissions())) {
|
||||
logger.debug(
|
||||
"fire authorization changed event, because a relevant field of namespace {} has changed", namespace.getNamespace()
|
||||
);
|
||||
fireEventForEveryUser();
|
||||
} else {
|
||||
logger.debug(
|
||||
"authorization changed event is not fired, because non relevant field of namespace {} has changed",
|
||||
namespace.getNamespace()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAuthorizationDataModified(Collection<RepositoryPermission> newPermissions, Collection<RepositoryPermission> permissionsBeforeModification) {
|
||||
return !(newPermissions.containsAll(permissionsBeforeModification) && permissionsBeforeModification.containsAll(newPermissions));
|
||||
}
|
||||
|
||||
private void fireEventForEveryUser() {
|
||||
|
||||
@@ -44,6 +44,12 @@
|
||||
<permission>
|
||||
<value>repository:create</value>
|
||||
</permission>
|
||||
<permission>
|
||||
<value>namespace:permissionRead</value>
|
||||
</permission>
|
||||
<permission>
|
||||
<value>namespace:permissionWrite</value>
|
||||
</permission>
|
||||
<permission>
|
||||
<value>user:*</value>
|
||||
</permission>
|
||||
|
||||
@@ -24,11 +24,14 @@
|
||||
|
||||
package sonia.scm.repository;
|
||||
|
||||
import com.github.legman.EventBus;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import sonia.scm.HandlerEventType;
|
||||
import sonia.scm.event.ScmEventBus;
|
||||
import sonia.scm.store.InMemoryDataStore;
|
||||
import sonia.scm.store.InMemoryDataStoreFactory;
|
||||
|
||||
@@ -37,7 +40,11 @@ import java.util.Optional;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static sonia.scm.HandlerEventType.DELETE;
|
||||
import static sonia.scm.HandlerEventType.MODIFY;
|
||||
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@@ -45,6 +52,8 @@ class DefaultNamespaceManagerTest {
|
||||
|
||||
@Mock
|
||||
RepositoryManager repositoryManager;
|
||||
@Mock
|
||||
ScmEventBus eventBus;
|
||||
|
||||
Namespace life;
|
||||
|
||||
@@ -56,7 +65,7 @@ class DefaultNamespaceManagerTest {
|
||||
@BeforeEach
|
||||
void mockExistingNamespaces() {
|
||||
dao = new NamespaceDao(new InMemoryDataStoreFactory(new InMemoryDataStore()));
|
||||
manager = new DefaultNamespaceManager(repositoryManager, dao);
|
||||
manager = new DefaultNamespaceManager(repositoryManager, dao, eventBus);
|
||||
|
||||
when(repositoryManager.getAllNamespaces()).thenReturn(asList("life", "universe", "rest"));
|
||||
|
||||
@@ -115,5 +124,29 @@ class DefaultNamespaceManagerTest {
|
||||
Namespace newLife = manager.get("life").get();
|
||||
|
||||
assertThat(newLife).isEqualTo(modifiedNamespace);
|
||||
verify(eventBus).post(argThat(event -> ((NamespaceModificationEvent)event).getEventType() == HandlerEventType.BEFORE_MODIFY));
|
||||
verify(eventBus).post(argThat(event -> ((NamespaceModificationEvent)event).getEventType() == HandlerEventType.MODIFY));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldCleanUpPermissionWhenLastRepositoryOfNamespaceWasDeleted() {
|
||||
when(repositoryManager.getAllNamespaces()).thenReturn(asList("universe", "rest"));
|
||||
|
||||
manager.cleanupDeletedNamespaces(new RepositoryEvent(DELETE, new Repository("1", "git", "life", "earth")));
|
||||
|
||||
assertThat(dao.get("life")).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldCleanUpPermissionWhenLastRepositoryOfNamespaceWasRenamed() {
|
||||
when(repositoryManager.getAllNamespaces()).thenReturn(asList("universe", "rest", "highway"));
|
||||
|
||||
manager.cleanupDeletedNamespaces(
|
||||
new RepositoryModificationEvent(
|
||||
MODIFY,
|
||||
new Repository("1", "git", "highway", "earth"),
|
||||
new Repository("1", "git", "life", "earth")));
|
||||
|
||||
assertThat(dao.get("life")).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.security;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
@@ -31,6 +31,8 @@ import sonia.scm.HandlerEventType;
|
||||
import sonia.scm.group.Group;
|
||||
import sonia.scm.group.GroupEvent;
|
||||
import sonia.scm.group.GroupModificationEvent;
|
||||
import sonia.scm.repository.Namespace;
|
||||
import sonia.scm.repository.NamespaceModificationEvent;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryEvent;
|
||||
import sonia.scm.repository.RepositoryModificationEvent;
|
||||
@@ -251,6 +253,55 @@ public class AuthorizationChangedEventProducerTest {
|
||||
assertUserEventIsFired("trillian");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnNamespaceModificationEvent()
|
||||
{
|
||||
Namespace namespaceModified = new Namespace("hitchhiker");
|
||||
namespaceModified.setPermissions(Lists.newArrayList(new RepositoryPermission("test", singletonList("read"), false)));
|
||||
|
||||
Namespace namespace = new Namespace("hitchhiker");
|
||||
namespace.setPermissions(Lists.newArrayList(new RepositoryPermission("test", singletonList("read"), false)));
|
||||
|
||||
producer.onEvent(new NamespaceModificationEvent(HandlerEventType.BEFORE_CREATE, namespaceModified, namespace));
|
||||
assertEventIsNotFired();
|
||||
|
||||
producer.onEvent(new NamespaceModificationEvent(HandlerEventType.CREATE, namespaceModified, namespace));
|
||||
assertEventIsNotFired();
|
||||
|
||||
namespaceModified.setPermissions(Lists.newArrayList(new RepositoryPermission("test", singletonList("read"), false)));
|
||||
producer.onEvent(new NamespaceModificationEvent(HandlerEventType.CREATE, namespaceModified, namespace));
|
||||
assertEventIsNotFired();
|
||||
|
||||
namespaceModified.setPermissions(Lists.newArrayList(new RepositoryPermission("test123", singletonList("read"), false)));
|
||||
producer.onEvent(new NamespaceModificationEvent(HandlerEventType.CREATE, namespaceModified, namespace));
|
||||
assertGlobalEventIsFired();
|
||||
|
||||
resetStoredEvent();
|
||||
|
||||
namespaceModified.setPermissions(
|
||||
Lists.newArrayList(new RepositoryPermission("test", singletonList("read"), true))
|
||||
);
|
||||
producer.onEvent(new NamespaceModificationEvent(HandlerEventType.CREATE, namespaceModified, namespace));
|
||||
assertGlobalEventIsFired();
|
||||
|
||||
resetStoredEvent();
|
||||
|
||||
namespaceModified.setPermissions(
|
||||
Lists.newArrayList(new RepositoryPermission("test", asList("read", "write"), false))
|
||||
);
|
||||
producer.onEvent(new NamespaceModificationEvent(HandlerEventType.CREATE, namespaceModified, namespace));
|
||||
assertGlobalEventIsFired();
|
||||
|
||||
resetStoredEvent();
|
||||
namespace.setPermissions(Lists.newArrayList(new RepositoryPermission("test", asList("read", "write"), false)));
|
||||
|
||||
namespaceModified.setPermissions(
|
||||
Lists.newArrayList(new RepositoryPermission("test", asList("write", "read"), false))
|
||||
);
|
||||
producer.onEvent(new NamespaceModificationEvent(HandlerEventType.CREATE, namespaceModified, namespace));
|
||||
assertEventIsNotFired();
|
||||
}
|
||||
|
||||
private static class StoringAuthorizationChangedEventProducer extends AuthorizationChangedEventProducer {
|
||||
|
||||
private AuthorizationChangedEvent event;
|
||||
|
||||
Reference in New Issue
Block a user