You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2022/01/13 12:15:40 UTC
[isis] branch master updated: ISIS-2905: adds role/permission model export (yaml)
This is an automated email from the ASF dual-hosted git repository.
ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git
The following commit(s) were added to refs/heads/master by this push:
new a2ded16 ISIS-2905: adds role/permission model export (yaml)
a2ded16 is described below
commit a2ded162a2002eff00fddc4109688c97c3f6ab17
Author: Andi Huber <ah...@apache.org>
AuthorDate: Thu Jan 13 13:15:28 2022 +0100
ISIS-2905: adds role/permission model export (yaml)
---
.../isis/applib/value/NamedWithMimeType.java | 9 +-
.../isis/commons/internal/resources/_Yaml.java | 40 +++++--
.../demo/domain/src/main/resources/application.yml | 4 +-
.../secman/applib/IsisModuleExtSecmanApplib.java | 2 +
...va => ApplicationRoleManager_exportAsYaml.java} | 39 ++++---
.../man/mixins/ApplicationRoleManager_newRole.java | 2 +-
.../secman/applib/util/ApplicationSecurityDto.java | 123 +++++++++++++++++++++
7 files changed, 191 insertions(+), 28 deletions(-)
diff --git a/api/applib/src/main/java/org/apache/isis/applib/value/NamedWithMimeType.java b/api/applib/src/main/java/org/apache/isis/applib/value/NamedWithMimeType.java
index cada0a7..9c199c5 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/value/NamedWithMimeType.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/value/NamedWithMimeType.java
@@ -107,6 +107,7 @@ public interface NamedWithMimeType extends Serializable {
XML("application/xml"), /*alias*/ XSD("application/xml"),
XUL("application/vnd.mozilla.xul+xml"),
+ YAML("text/vnd.yaml", "yml"),
ZIP("application/zip"),
_7Z("application/x-7z-compressed"),
@@ -149,10 +150,12 @@ public interface NamedWithMimeType extends Serializable {
;
- private CommonMimeType(final String primaryType, final String ... additionalProposedFileExtension) {
+ private CommonMimeType(final String primaryType, final String ... proposedFileExtensions) {
this.mimeType = newMimeType(primaryType);
- this.proposedFileExtensions = Can.ofSingleton(name().toLowerCase())
- .addAll(Can.ofArray(additionalProposedFileExtension));
+ this.proposedFileExtensions =
+ proposedFileExtensions.length>0
+ ? Can.ofArray(proposedFileExtensions)
+ : Can.ofSingleton(name().toLowerCase()); // default
}
@Getter final MimeType mimeType;
diff --git a/commons/src/main/java/org/apache/isis/commons/internal/resources/_Yaml.java b/commons/src/main/java/org/apache/isis/commons/internal/resources/_Yaml.java
index 5fae924..3d6b770 100644
--- a/commons/src/main/java/org/apache/isis/commons/internal/resources/_Yaml.java
+++ b/commons/src/main/java/org/apache/isis/commons/internal/resources/_Yaml.java
@@ -24,12 +24,16 @@ import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
+import java.io.StringWriter;
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.DumperOptions.LineBreak;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;
import org.apache.isis.commons.functional.Result;
+import lombok.SneakyThrows;
import lombok.val;
/**
@@ -47,7 +51,7 @@ public class _Yaml {
// -- FROM INPUT STREAM
- private static <T> T _readYaml(final Class<T> clazz, InputStream content) {
+ private static <T> T _readYaml(final Class<T> clazz, final InputStream content) {
val yaml = new Yaml(new Constructor(clazz));
return yaml.load(content);
}
@@ -59,13 +63,13 @@ public class _Yaml {
* @param clazz
* @param content
*/
- public static <T> Result<T> readYaml(final Class<T> clazz, InputStream content) {
+ public static <T> Result<T> readYaml(final Class<T> clazz, final InputStream content) {
return Result.of(()->_readYaml(clazz, content));
}
// -- FROM STRING
- private static <T> T _readYaml(final Class<T> clazz, String content) {
+ private static <T> T _readYaml(final Class<T> clazz, final String content) {
val yaml = new Yaml(new Constructor(clazz));
return yaml.load(content);
}
@@ -77,13 +81,13 @@ public class _Yaml {
* @param clazz
* @param content
*/
- public static <T> Result<T> readYaml(final Class<T> clazz, String content) {
+ public static <T> Result<T> readYaml(final Class<T> clazz, final String content) {
return Result.of(()->_readYaml(clazz, content));
}
// -- FROM FILE
- private static <T> T _readYaml(final Class<T> clazz, File content) throws FileNotFoundException, IOException {
+ private static <T> T _readYaml(final Class<T> clazz, final File content) throws FileNotFoundException, IOException {
try(val fis = new FileInputStream(content)) {
val yaml = new Yaml(new Constructor(clazz));
return yaml.load(fis);
@@ -97,13 +101,13 @@ public class _Yaml {
* @param clazz
* @param content
*/
- public static <T> Result<T> readYaml(final Class<T> clazz, File content) {
+ public static <T> Result<T> readYaml(final Class<T> clazz, final File content) {
return Result.of(()->_readYaml(clazz, content));
}
// -- FROM BYTE ARRAY
- private static <T> T _readYaml(final Class<T> clazz, byte[] content) throws IOException {
+ private static <T> T _readYaml(final Class<T> clazz, final byte[] content) throws IOException {
try(val bais = new ByteArrayInputStream(content)) {
val yaml = new Yaml(new Constructor(clazz));
return yaml.load(bais);
@@ -117,8 +121,28 @@ public class _Yaml {
* @param clazz
* @param content
*/
- public static <T> Result<T> readYaml(final Class<T> clazz, byte[] content) {
+ public static <T> Result<T> readYaml(final Class<T> clazz, final byte[] content) {
return Result.of(()->_readYaml(clazz, content));
}
+ // -- WRITING
+
+ @SneakyThrows
+ private static String _toString(final Object pojo) {
+ try(val writer = new StringWriter()){
+ val options = new DumperOptions();
+ options.setIndent(2);
+ options.setLineBreak(LineBreak.UNIX); // fixated for consistency
+ //options.setPrettyFlow(true);
+ //options.setDefaultFlowStyle(FlowStyle.BLOCK);
+ val yaml = new Yaml(options);
+ yaml.dump(pojo, writer);
+ return writer.toString();
+ }
+ }
+
+ public static Result<String> toString(final Object pojo) {
+ return Result.of(()->_toString(pojo));
+ }
+
}
diff --git a/examples/demo/domain/src/main/resources/application.yml b/examples/demo/domain/src/main/resources/application.yml
index dabd72f..84aaa68 100644
--- a/examples/demo/domain/src/main/resources/application.yml
+++ b/examples/demo/domain/src/main/resources/application.yml
@@ -34,7 +34,9 @@ isis:
delete.*:fa-trash,
find.*:fa-search,
list.*:fa-list,
- all.*:fa-list
+ all.*:fa-list,
+ export.*:fa-file-export,
+ import.*:fa-file-import
css-class:
patterns:
delete.*:btn-danger
diff --git a/extensions/security/secman/applib/src/main/java/org/apache/isis/extensions/secman/applib/IsisModuleExtSecmanApplib.java b/extensions/security/secman/applib/src/main/java/org/apache/isis/extensions/secman/applib/IsisModuleExtSecmanApplib.java
index e9fa913..50e2426 100644
--- a/extensions/security/secman/applib/src/main/java/org/apache/isis/extensions/secman/applib/IsisModuleExtSecmanApplib.java
+++ b/extensions/security/secman/applib/src/main/java/org/apache/isis/extensions/secman/applib/IsisModuleExtSecmanApplib.java
@@ -41,6 +41,7 @@ import org.apache.isis.extensions.secman.applib.role.dom.mixins.ApplicationRole_
import org.apache.isis.extensions.secman.applib.role.dom.mixins.ApplicationRole_updateDescription;
import org.apache.isis.extensions.secman.applib.role.dom.mixins.ApplicationRole_updateName;
import org.apache.isis.extensions.secman.applib.role.man.mixins.ApplicationRoleManager_allRoles;
+import org.apache.isis.extensions.secman.applib.role.man.mixins.ApplicationRoleManager_exportAsYaml;
import org.apache.isis.extensions.secman.applib.role.man.mixins.ApplicationRoleManager_newRole;
import org.apache.isis.extensions.secman.applib.role.menu.ApplicationRoleMenu;
import org.apache.isis.extensions.secman.applib.seed.SeedSecurityModuleService;
@@ -173,6 +174,7 @@ import org.apache.isis.testing.fixtures.applib.IsisModuleTestingFixturesApplib;
// ApplicationRoleManager
ApplicationRoleManager_allRoles.class,
ApplicationRoleManager_newRole.class,
+ ApplicationRoleManager_exportAsYaml.class,
// other @Services
SeedSecurityModuleService.class,
diff --git a/extensions/security/secman/applib/src/main/java/org/apache/isis/extensions/secman/applib/role/man/mixins/ApplicationRoleManager_newRole.java b/extensions/security/secman/applib/src/main/java/org/apache/isis/extensions/secman/applib/role/man/mixins/ApplicationRoleManager_exportAsYaml.java
similarity index 68%
copy from extensions/security/secman/applib/src/main/java/org/apache/isis/extensions/secman/applib/role/man/mixins/ApplicationRoleManager_newRole.java
copy to extensions/security/secman/applib/src/main/java/org/apache/isis/extensions/secman/applib/role/man/mixins/ApplicationRoleManager_exportAsYaml.java
index 5c47fce..6384c58 100644
--- a/extensions/security/secman/applib/src/main/java/org/apache/isis/extensions/secman/applib/role/man/mixins/ApplicationRoleManager_newRole.java
+++ b/extensions/security/secman/applib/src/main/java/org/apache/isis/extensions/secman/applib/role/man/mixins/ApplicationRoleManager_exportAsYaml.java
@@ -23,17 +23,19 @@ import javax.inject.Inject;
import org.apache.isis.applib.annotation.Action;
import org.apache.isis.applib.annotation.ActionLayout;
import org.apache.isis.applib.annotation.MemberSupport;
-import org.apache.isis.applib.annotation.Optionality;
import org.apache.isis.applib.annotation.Parameter;
-import org.apache.isis.applib.annotation.ParameterLayout;
import org.apache.isis.applib.annotation.SemanticsOf;
+import org.apache.isis.applib.value.Clob;
+import org.apache.isis.applib.value.NamedWithMimeType.CommonMimeType;
import org.apache.isis.extensions.secman.applib.IsisModuleExtSecmanApplib;
-import org.apache.isis.extensions.secman.applib.role.dom.ApplicationRole;
import org.apache.isis.extensions.secman.applib.role.dom.ApplicationRoleRepository;
import org.apache.isis.extensions.secman.applib.role.man.ApplicationRoleManager;
+import org.apache.isis.extensions.secman.applib.user.dom.ApplicationUserRepository;
import org.apache.isis.extensions.secman.applib.user.man.mixins.ApplicationUserManager_newLocalUser.DomainEvent;
+import org.apache.isis.extensions.secman.applib.util.ApplicationSecurityDto;
import lombok.RequiredArgsConstructor;
+import lombok.val;
@Action(
domainEvent = DomainEvent.class,
@@ -41,27 +43,34 @@ import lombok.RequiredArgsConstructor;
)
@ActionLayout(
associateWith = "allRoles",
- sequence = "1"
+ sequence = "1.1"
)
@RequiredArgsConstructor
-public class ApplicationRoleManager_newRole {
+public class ApplicationRoleManager_exportAsYaml {
public static class DomainEvent
- extends IsisModuleExtSecmanApplib.ActionDomainEvent<ApplicationRoleManager_newRole> {}
+ extends IsisModuleExtSecmanApplib.ActionDomainEvent<ApplicationRoleManager_exportAsYaml> {}
@Inject private ApplicationRoleRepository applicationRoleRepository;
+ @Inject private ApplicationUserRepository applicationUserRepository;
+ @SuppressWarnings("unused")
private final ApplicationRoleManager target;
- @MemberSupport public ApplicationRoleManager act (
- @Parameter(maxLength = ApplicationRole.Name.MAX_LENGTH)
- @ParameterLayout(named="Name", typicalLength= ApplicationRole.Name.TYPICAL_LENGTH)
- final String name,
- @Parameter(maxLength = ApplicationRole.Description.MAX_LENGTH, optionality = Optionality.OPTIONAL)
- @ParameterLayout(named="Description", typicalLength= ApplicationRole.Description.TYPICAL_LENGTH)
- final String description) {
- applicationRoleRepository.newRole(name, description);
- return target;
+ @MemberSupport public Clob act(
+ @Parameter
+ final String fileName) {
+
+ val yaml = ApplicationSecurityDto.create(
+ applicationRoleRepository,
+ applicationUserRepository)
+ .toYaml();
+
+ return Clob.of(fileName, CommonMimeType.YAML, yaml);
+ }
+
+ @MemberSupport public String defaultFileName() {
+ return "secman-roles.yml";
}
}
diff --git a/extensions/security/secman/applib/src/main/java/org/apache/isis/extensions/secman/applib/role/man/mixins/ApplicationRoleManager_newRole.java b/extensions/security/secman/applib/src/main/java/org/apache/isis/extensions/secman/applib/role/man/mixins/ApplicationRoleManager_newRole.java
index 5c47fce..c1ef648 100644
--- a/extensions/security/secman/applib/src/main/java/org/apache/isis/extensions/secman/applib/role/man/mixins/ApplicationRoleManager_newRole.java
+++ b/extensions/security/secman/applib/src/main/java/org/apache/isis/extensions/secman/applib/role/man/mixins/ApplicationRoleManager_newRole.java
@@ -41,7 +41,7 @@ import lombok.RequiredArgsConstructor;
)
@ActionLayout(
associateWith = "allRoles",
- sequence = "1"
+ sequence = "2"
)
@RequiredArgsConstructor
public class ApplicationRoleManager_newRole {
diff --git a/extensions/security/secman/applib/src/main/java/org/apache/isis/extensions/secman/applib/util/ApplicationSecurityDto.java b/extensions/security/secman/applib/src/main/java/org/apache/isis/extensions/secman/applib/util/ApplicationSecurityDto.java
new file mode 100644
index 0000000..7956f0b
--- /dev/null
+++ b/extensions/security/secman/applib/src/main/java/org/apache/isis/extensions/secman/applib/util/ApplicationSecurityDto.java
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.isis.extensions.secman.applib.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.isis.applib.services.appfeat.ApplicationFeatureSort;
+import org.apache.isis.commons.internal.resources._Yaml;
+import org.apache.isis.extensions.secman.applib.permission.dom.ApplicationPermission;
+import org.apache.isis.extensions.secman.applib.permission.dom.ApplicationPermissionMode;
+import org.apache.isis.extensions.secman.applib.permission.dom.ApplicationPermissionRule;
+import org.apache.isis.extensions.secman.applib.role.dom.ApplicationRole;
+import org.apache.isis.extensions.secman.applib.role.dom.ApplicationRoleRepository;
+import org.apache.isis.extensions.secman.applib.user.dom.ApplicationUser;
+import org.apache.isis.extensions.secman.applib.user.dom.ApplicationUserRepository;
+
+import lombok.Data;
+import lombok.NonNull;
+import lombok.val;
+
+/**
+ * In-memory model of users, roles and permissions.
+ *
+ * @since 2.0 {index}
+ */
+@Data
+public class ApplicationSecurityDto {
+
+ @Data
+ public static class PermissionDto {
+
+ static PermissionDto from(final ApplicationPermission permission) {
+ val permissionDto = new PermissionDto();
+ permissionDto.setFeatureFqn(permission.getFeatureFqn());
+ permissionDto.setFeatureSort(permission.getFeatureSort());
+ permissionDto.setMode(permission.getMode());
+ permissionDto.setRule(permission.getRule());
+ return permissionDto;
+ }
+
+ String featureFqn;
+ ApplicationFeatureSort featureSort;
+ ApplicationPermissionMode mode;
+ ApplicationPermissionRule rule;
+ }
+
+ @Data
+ public static class RoleDto {
+
+ static RoleDto from(final ApplicationRole role) {
+ val roleDto = new RoleDto();
+ roleDto.set__name(role.getName());
+ roleDto.setDescription(role.getDescription());
+ role.getPermissions().stream()
+ .map(PermissionDto::from)
+ .forEach(roleDto.getPermissions()::add);
+ return roleDto;
+ }
+
+ String __name; // secondary key - ensure earliest alphabetic order
+ String description;
+ List<PermissionDto> permissions = new ArrayList<>();
+ }
+
+ @Data
+ public static class UserDto {
+
+ static UserDto from(final ApplicationUser user) {
+ val userDto = new UserDto();
+ userDto.set__username(user.getUsername());
+
+ user.getRoles().stream()
+ .map(ApplicationRole::getName)
+ .forEach(userDto.getRoleNames()::add);
+
+ return userDto;
+ }
+
+ String __username; // secondary key - ensure earliest alphabetic order
+ List<String> roleNames = new ArrayList<>();
+ }
+
+ public static ApplicationSecurityDto create(
+ final @NonNull ApplicationRoleRepository applicationRoleRepository,
+ final @NonNull ApplicationUserRepository applicationUserRepository) {
+ val model = new ApplicationSecurityDto();
+
+ applicationRoleRepository.allRoles().stream()
+ .map(RoleDto::from)
+ .forEach(model.getRoles()::add);
+
+ applicationUserRepository.allUsers().stream()
+ .map(UserDto::from)
+ .forEach(model.getUsers()::add);
+
+ return model;
+ }
+
+ private List<RoleDto> roles = new ArrayList<>();
+ private List<UserDto> users = new ArrayList<>();
+
+ public String toYaml() {
+ return _Yaml.toString(this).presentElseFail();
+ }
+
+}