Repository: syncope Updated Branches: refs/heads/2_0_X ade7e99a5 -> daa1d0d2f
[SYNCOPE-1009] USER form customization through json file, made minor (but necesary) bugfixes on wizard Project: http://git-wip-us.apache.org/repos/asf/syncope/repo Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/daa1d0d2 Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/daa1d0d2 Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/daa1d0d2 Branch: refs/heads/2_0_X Commit: daa1d0d2fe7f03cc98068ddc23afe2a3a0075a58 Parents: ade7e99 Author: Andrea Patricelli <andreapatrice...@apache.org> Authored: Thu Apr 6 08:55:44 2017 +0200 Committer: Andrea Patricelli <andreapatrice...@apache.org> Committed: Thu Apr 6 08:55:44 2017 +0200 ---------------------------------------------------------------------- .../enduser/model/CustomAttributesInfo.java | 62 ++++++++++++++ .../enduser/resources/SchemaResource.java | 90 ++++++++++++++++++-- .../resources/UserSelfCreateResource.java | 2 +- .../resources/UserSelfUpdateResource.java | 6 +- .../resources/app/configuration/customForm.json | 1 + .../resources/META-INF/resources/app/index.html | 1 + .../resources/META-INF/resources/app/js/app.js | 11 ++- .../app/js/controllers/UserController.js | 58 ++++++++++--- .../app/js/directives/dynamicPlainAttribute.js | 20 +++-- .../js/directives/dynamicVirtualAttribute.js | 35 ++++++-- .../app/js/services/configurationService.js | 41 +++++++++ .../app/js/services/saml2IdPService.js | 2 +- .../resources/app/js/services/schemaService.js | 38 +++++---- .../META-INF/resources/app/views/captcha.html | 4 +- .../app/views/dynamicPlainAttribute.html | 87 ++++++++++--------- .../app/views/dynamicVirtualAttribute.html | 2 +- 16 files changed, 361 insertions(+), 99 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/syncope/blob/daa1d0d2/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/CustomAttributesInfo.java ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/CustomAttributesInfo.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/CustomAttributesInfo.java new file mode 100644 index 0000000..61d08f1 --- /dev/null +++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/CustomAttributesInfo.java @@ -0,0 +1,62 @@ +/* + * 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.syncope.client.enduser.model; + +import java.io.Serializable; +import java.util.LinkedHashMap; +import java.util.Map; + +public class CustomAttributesInfo implements Serializable { + + private static final long serialVersionUID = 878444785696091916L; + + private Boolean show = Boolean.TRUE; + + private Map<String, ?> attributes = new LinkedHashMap<>(); + + public CustomAttributesInfo() { + } + + public Boolean getShow() { + return show; + } + + public void setShow(final Boolean show) { + this.show = show; + } + + public Map<String, ?> getAttributes() { + return attributes; + } + + public void setAttributes(final Map<String, ?> attributes) { + this.attributes = attributes; + } + + public CustomAttributesInfo show(final Boolean value) { + this.show = value; + return this; + } + + public CustomAttributesInfo attributes(final Map<String, ?> value) { + this.attributes = value; + return this; + } + +} http://git-wip-us.apache.org/repos/asf/syncope/blob/daa1d0d2/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SchemaResource.java ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SchemaResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SchemaResource.java index a68704d..169d1b4 100644 --- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SchemaResource.java +++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SchemaResource.java @@ -18,17 +18,27 @@ */ package org.apache.syncope.client.enduser.resources; +import static org.apache.syncope.client.enduser.resources.BaseResource.MAPPER; + +import com.fasterxml.jackson.core.type.TypeReference; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; import java.util.List; +import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.IterableUtils; import org.apache.commons.collections4.Predicate; +import org.apache.commons.lang3.StringUtils; import org.apache.syncope.client.enduser.SyncopeEnduserSession; import org.apache.syncope.client.enduser.annotations.Resource; +import org.apache.syncope.client.enduser.model.CustomAttributesInfo; import org.apache.syncope.client.enduser.model.SchemaResponse; import org.apache.syncope.common.lib.to.AbstractSchemaTO; import org.apache.syncope.common.lib.to.AnyTypeTO; @@ -49,6 +59,7 @@ public class SchemaResource extends BaseResource { private static final long serialVersionUID = 6453101466981543020L; + @SuppressWarnings("unchecked") @Override protected AbstractResource.ResourceResponse newResourceResponse(final IResource.Attributes attributes) { LOG.debug("Search all {} any type kind related schemas", AnyTypeKind.USER.name()); @@ -92,29 +103,51 @@ public class SchemaResource extends BaseResource { } } + Map<String, CustomAttributesInfo> customForm = MAPPER.readValue(request.getReader().readLine(), + new TypeReference<HashMap<String, CustomAttributesInfo>>() { + }); + SchemaService schemaService = SyncopeEnduserSession.get().getService(SchemaService.class); final List<AbstractSchemaTO> plainSchemas = classes.isEmpty() ? Collections.<AbstractSchemaTO>emptyList() - : schemaService.list( - new SchemaQuery.Builder().type(SchemaType.PLAIN).anyTypeClasses(classes).build()); + : customForm == null || customForm.isEmpty() || customForm.get(SchemaType.PLAIN.name()) == null + ? schemaService.list( + new SchemaQuery.Builder().type(SchemaType.PLAIN).anyTypeClasses(classes).build()) + : customForm.get(SchemaType.PLAIN.name()).getShow() + ? customizeSchemas(schemaService.list(new SchemaQuery.Builder().type(SchemaType.PLAIN). + anyTypeClasses(classes).build()), groupParam, customForm.get(SchemaType.PLAIN.name()). + getAttributes()) + : Collections.<AbstractSchemaTO>emptyList(); final List<AbstractSchemaTO> derSchemas = classes.isEmpty() ? Collections.<AbstractSchemaTO>emptyList() - : schemaService.list( - new SchemaQuery.Builder().type(SchemaType.DERIVED).anyTypeClasses(classes).build()); + : customForm == null || customForm.isEmpty() || customForm.get(SchemaType.DERIVED.name()) == null + ? schemaService.list( + new SchemaQuery.Builder().type(SchemaType.DERIVED).anyTypeClasses(classes).build()) + : customForm.get(SchemaType.DERIVED.name()).getShow() + ? customizeSchemas(schemaService.list(new SchemaQuery.Builder().type(SchemaType.DERIVED). + anyTypeClasses(classes).build()), groupParam, customForm.get(SchemaType.DERIVED.name()). + getAttributes()) + : Collections.<AbstractSchemaTO>emptyList(); final List<AbstractSchemaTO> virSchemas = classes.isEmpty() ? Collections.<AbstractSchemaTO>emptyList() - : schemaService.list( - new SchemaQuery.Builder().type(SchemaType.VIRTUAL).anyTypeClasses(classes).build()); + : customForm == null || customForm.isEmpty() || customForm.get(SchemaType.VIRTUAL.name()) == null + ? schemaService.list( + new SchemaQuery.Builder().type(SchemaType.VIRTUAL).anyTypeClasses(classes).build()) + : customForm.get(SchemaType.VIRTUAL.name()).getShow() + ? customizeSchemas(schemaService.list(new SchemaQuery.Builder().type(SchemaType.VIRTUAL). + anyTypeClasses(classes).build()), groupParam, customForm.get(SchemaType.VIRTUAL.name()). + getAttributes()) + : Collections.<AbstractSchemaTO>emptyList(); if (groupParam != null) { for (AbstractSchemaTO schema : plainSchemas) { - schema.setKey(groupParam + "#" + schema.getKey()); + schema.setKey(compositeSchemaKey(groupParam, schema.getKey())); } for (AbstractSchemaTO schema : derSchemas) { - schema.setKey(groupParam + "#" + schema.getKey()); + schema.setKey(compositeSchemaKey(groupParam, schema.getKey())); } for (AbstractSchemaTO schema : virSchemas) { - schema.setKey(groupParam + "#" + schema.getKey()); + schema.setKey(compositeSchemaKey(groupParam, schema.getKey())); } } @@ -142,4 +175,43 @@ public class SchemaResource extends BaseResource { return response; } + private List<AbstractSchemaTO> customizeSchemas(final List<AbstractSchemaTO> schemaTOs, final String groupParam, + final Map<String, ?> customForm) { + + if (customForm.isEmpty()) { + return schemaTOs; + } + final boolean isGroupBlank = StringUtils.isBlank(groupParam); + + CollectionUtils.filter(schemaTOs, new Predicate<AbstractSchemaTO>() { + + @Override + public boolean evaluate(final AbstractSchemaTO object) { + return customForm.containsKey(isGroupBlank + ? object.getKey() + : compositeSchemaKey(groupParam, object.getKey())); + } + }); + + Collections.sort(schemaTOs, new Comparator<AbstractSchemaTO>() { + + @Override + public int compare(final AbstractSchemaTO schemaTO1, final AbstractSchemaTO schemaTO2) { + List<String> order = new ArrayList<>(customForm.keySet()); + return order.indexOf(isGroupBlank + ? schemaTO1.getKey() + : compositeSchemaKey(groupParam, schemaTO1.getKey())) + - order.indexOf(isGroupBlank + ? schemaTO2.getKey() + : compositeSchemaKey(groupParam, schemaTO2.getKey())); + } + }); + + return schemaTOs; + } + + private String compositeSchemaKey(final String prefix, final String schemaKey) { + return prefix + "#" + schemaKey; + } + } http://git-wip-us.apache.org/repos/asf/syncope/blob/daa1d0d2/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfCreateResource.java ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfCreateResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfCreateResource.java index 2634640..c8baa53 100644 --- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfCreateResource.java +++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfCreateResource.java @@ -65,7 +65,7 @@ public class UserSelfCreateResource extends BaseResource { @Override protected ResourceResponse newResourceResponse(final Attributes attributes) { ResourceResponse response = new ResourceResponse(); - response.setContentType(MediaType.APPLICATION_JSON); + response.setContentType(MediaType.TEXT_PLAIN); try { HttpServletRequest request = (HttpServletRequest) attributes.getRequest().getContainerRequest(); http://git-wip-us.apache.org/repos/asf/syncope/blob/daa1d0d2/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfUpdateResource.java ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfUpdateResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfUpdateResource.java index 4a7e78c..2ee22db 100644 --- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfUpdateResource.java +++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfUpdateResource.java @@ -35,6 +35,7 @@ import org.apache.commons.lang3.time.FastDateFormat; import org.apache.syncope.client.enduser.SyncopeEnduserConstants; import org.apache.syncope.client.enduser.SyncopeEnduserSession; import org.apache.syncope.client.enduser.annotations.Resource; +import org.apache.syncope.common.lib.AnyOperations; import org.apache.syncope.common.lib.to.AttrTO; import org.apache.syncope.common.lib.to.MembershipTO; import org.apache.syncope.common.lib.to.PlainSchemaTO; @@ -164,9 +165,10 @@ public class UserSelfUpdateResource extends BaseResource { } userTO.getVirAttrs().removeAll(membAttrs); - // update user + // update user by patch Response res = SyncopeEnduserSession.get(). - getService(userTO.getETagValue(), UserSelfService.class).update(userTO); + getService(userTO.getETagValue(), UserSelfService.class).update(AnyOperations.diff(userTO, + SyncopeEnduserSession.get().getSelfTO(), true)); final String responseMessage = res.getStatusInfo().getFamily().equals(Response.Status.Family.SUCCESSFUL) ? new StringBuilder(). http://git-wip-us.apache.org/repos/asf/syncope/blob/daa1d0d2/client/enduser/src/main/resources/META-INF/resources/app/configuration/customForm.json ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/resources/META-INF/resources/app/configuration/customForm.json b/client/enduser/src/main/resources/META-INF/resources/app/configuration/customForm.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/client/enduser/src/main/resources/META-INF/resources/app/configuration/customForm.json @@ -0,0 +1 @@ +{} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/syncope/blob/daa1d0d2/client/enduser/src/main/resources/META-INF/resources/app/index.html ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/resources/META-INF/resources/app/index.html b/client/enduser/src/main/resources/META-INF/resources/app/index.html index 21a7984..7378236 100644 --- a/client/enduser/src/main/resources/META-INF/resources/app/index.html +++ b/client/enduser/src/main/resources/META-INF/resources/app/index.html @@ -99,6 +99,7 @@ under the License. <script src="js/services/groupService.js"></script> <script src="js/services/anyService.js"></script> <script src="js/services/saml2IdPService.js"></script> + <script src="js/services/configurationService.js"></script> <!--controllers--> <script src="js/controllers/HomeController.js"></script> <script src="js/controllers/LoginController.js"></script> http://git-wip-us.apache.org/repos/asf/syncope/blob/daa1d0d2/client/enduser/src/main/resources/META-INF/resources/app/js/app.js ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/app.js b/client/enduser/src/main/resources/META-INF/resources/app/js/app.js index d8ceeb4..64d535f 100644 --- a/client/enduser/src/main/resources/META-INF/resources/app/js/app.js +++ b/client/enduser/src/main/resources/META-INF/resources/app/js/app.js @@ -332,7 +332,8 @@ app.run(['$rootScope', '$location', '$state', 'AuthService', }; }]); app.controller('ApplicationController', ['$scope', '$rootScope', '$location', 'InfoService', 'SAML2IdPService', - function ($scope, $rootScope, $location, InfoService, SAML2IdPService) { + 'ConfigurationService', + function ($scope, $rootScope, $location, InfoService, SAML2IdPService, ConfigurationService) { $scope.initApplication = function () { /* * disable by default wizard buttons in self-registration @@ -405,6 +406,14 @@ app.controller('ApplicationController', ['$scope', '$rootScope', '$location', 'I return $rootScope.version; }; /* + * USER Attributes form customization + */ + ConfigurationService.get("customForm.json").then(function (response) { + $rootScope.customForm = response; + }, function (e) { + console.warn("Unable to retrieve form customization file provided, applying default configuration."); + }); + /* * USER Attributes sorting strategies */ $rootScope.attributesSorting = { http://git-wip-us.apache.org/repos/asf/syncope/blob/daa1d0d2/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js index 18ae153..ed9bc8f 100644 --- a/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js +++ b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js @@ -21,10 +21,10 @@ 'use strict'; -angular.module("self").controller("UserController", ['$scope', '$rootScope', '$location', '$compile', "$state", - 'AuthService', 'UserSelfService', 'SchemaService', 'RealmService', 'ResourceService', 'SecurityQuestionService', +angular.module("self").controller("UserController", ['$scope', '$rootScope', '$location', "$state", + 'UserSelfService', 'SchemaService', 'RealmService', 'ResourceService', 'SecurityQuestionService', 'GroupService', 'AnyService', 'UserUtil', 'GenericUtil', 'ValidationExecutor', '$translate', - function ($scope, $rootScope, $location, $compile, $state, AuthService, UserSelfService, SchemaService, RealmService, + function ($scope, $rootScope, $location, $state, UserSelfService, SchemaService, RealmService, ResourceService, SecurityQuestionService, GroupService, AnyService, UserUtil, GenericUtil, ValidationExecutor, $translate) { $scope.user = {}; @@ -41,6 +41,7 @@ angular.module("self").controller("UserController", ['$scope', '$rootScope', '$l $scope.captchaInput = { value: "" }; + $scope.customForm = {}; $scope.initUser = function () { $scope.dynamicForm = { @@ -64,14 +65,24 @@ angular.module("self").controller("UserController", ['$scope', '$rootScope', '$l // initialization is done here synchronously to have all schema fields populated correctly var schemaService; if (group) { - schemaService = SchemaService.getTypeExtSchemas(group, $rootScope.attributesSorting.ASC); + /* + * if you want to sort with custom JS function defined in put also a sorting function as last parameter + * e.g. $rootScope.attributesSorting.ASC + */ + schemaService = SchemaService.getTypeExtSchemas(group, $rootScope.customForm); } else { - schemaService = SchemaService.getUserSchemas(anyTypeClass, $rootScope.attributesSorting.ASC); + /* + * if you want to sort with custom JS function defined in put also a sorting function as last parameter + * e.g. $rootScope.attributesSorting.ASC + */ + schemaService = SchemaService.getUserSchemas(anyTypeClass, $rootScope.customForm); } schemaService.then(function (schemas) { if (group && (schemas.plainSchemas.length > 0 || schemas.derSchemas.length > 0 || schemas.virSchemas.length > 0)) $scope.dynamicForm.groupSchemas.push(group); - //initializing user schemas values + /* + * initializing user schemas values, i.e. USER attributes + */ initSchemaValues(schemas); }, function (response) { // parse error response and log @@ -90,19 +101,37 @@ angular.module("self").controller("UserController", ['$scope', '$rootScope', '$l // initialize plain attributes for (var i = 0; i < schemas.plainSchemas.length; i++) { var plainSchemaKey = schemas.plainSchemas[i].key; + var initialAttributeValues = $rootScope.customForm != null + && $rootScope.customForm["PLAIN"] != null + && $rootScope.customForm["PLAIN"]["attributes"] != null + && $rootScope.customForm["PLAIN"]["attributes"][plainSchemaKey] != null + && $rootScope.customForm["PLAIN"]["attributes"][plainSchemaKey].defaultValues + ? $rootScope.customForm["PLAIN"]["attributes"][plainSchemaKey].defaultValues + : []; if (!$scope.user.plainAttrs[plainSchemaKey]) { $scope.user.plainAttrs[plainSchemaKey] = { schema: plainSchemaKey, - values: [] + values: initialAttributeValues }; - // initialize multivalue schema and support table: create mode, only first value if (schemas.plainSchemas[i].multivalue) { - $scope.dynamicForm.attributeTable[schemas.plainSchemas[i].key] = { - fields: [schemas.plainSchemas[i].key + "_" + 0] - }; + // initialize multivalue schema and support table: create mode, default multivalues + if (initialAttributeValues.length > 0) { + // attribute create mode, init empty fields + $scope.dynamicForm.attributeTable[plainSchemaKey] = { + fields: [] + }; + for (var j = 0; j < initialAttributeValues.length; j++) { + $scope.dynamicForm.attributeTable[plainSchemaKey].fields.push(plainSchemaKey + "_" + j); + } + } else { + // initialize multivalue schema and support table: create mode, only first value + $scope.dynamicForm.attributeTable[schemas.plainSchemas[i].key] = { + fields: [schemas.plainSchemas[i].key + "_" + 0] + }; + } } } else if (schemas.plainSchemas[i].multivalue) { - // initialize multivalue schema and support table: update mode, all provided values + // initialize multivalue attribute and support table: update mode, all provided values $scope.dynamicForm.attributeTable[schemas.plainSchemas[i].key] = { fields: [schemas.plainSchemas[i].key + "_" + 0] }; @@ -133,12 +162,12 @@ angular.module("self").controller("UserController", ['$scope', '$rootScope', '$l schema: virSchemaKey, values: [] }; - // initialize multivalue schema and support table: create mode, only first value + // initialize multivalue attribute and support table: create mode, only first value $scope.dynamicForm.virtualAttributeTable[schemas.virSchemas[i].key] = { fields: [schemas.virSchemas[i].key + "_" + 0] }; } else { - // initialize multivalue schema and support table: update mode, all provided values + // initialize multivalue attribute and support table: update mode, all provided values $scope.dynamicForm.virtualAttributeTable[schemas.virSchemas[i].key] = { fields: [schemas.virSchemas[i].key + "_" + 0] }; @@ -271,6 +300,7 @@ angular.module("self").controller("UserController", ['$scope', '$rootScope', '$l if ($scope.user.mustChangePassword) { $location.path('/mustchangepassword'); } else { +// initConfiguration(); initProperties(); } }, function (e) { http://git-wip-us.apache.org/repos/asf/syncope/blob/daa1d0d2/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicPlainAttribute.js ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicPlainAttribute.js b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicPlainAttribute.js index c267087..f67b926 100644 --- a/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicPlainAttribute.js +++ b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicPlainAttribute.js @@ -19,7 +19,7 @@ 'use strict'; angular.module('self') - .directive('dynamicPlainAttribute', function ($filter) { + .directive('dynamicPlainAttribute', function () { return { restrict: 'E', templateUrl: 'views/dynamicPlainAttribute.html', @@ -50,10 +50,10 @@ angular.module('self') $scope.enumerationValues.push(enumerationValuesSplitted[i]); } //SYNCOPE-1024 enumeration keys mgmt - if ( schema.enumerationKeys ) { - var enumerationKeysSplitted = schema.enumerationKeys.toString().split( ";" ); - for ( var i = 0; i < enumerationKeysSplitted.length; i++ ) { - $scope.enumerationKeys.push( enumerationKeysSplitted[i] ); + if (schema.enumerationKeys) { + var enumerationKeysSplitted = schema.enumerationKeys.toString().split(";"); + for (var i = 0; i < enumerationKeysSplitted.length; i++) { + $scope.enumerationKeys.push(enumerationKeysSplitted[i]); } } $scope.user.plainAttrs[schema.key].values[index] = $scope.user.plainAttrs[schema.key].values[index] @@ -119,12 +119,20 @@ angular.module('self') case "Boolean": $scope.user.plainAttrs[schema.key].values[index] = - $scope.user.plainAttrs[schema.key].values[index] === "true" ? true : false; + $scope.user.plainAttrs[schema.key].values[index] === "true" ? "true" : "false"; break; } }; + $scope.customReadonly = function (schemaKey) { + return $rootScope.customForm != null + && $rootScope.customForm["PLAIN"] != null + && $rootScope.customForm["PLAIN"]["attributes"] != null + && $rootScope.customForm["PLAIN"]["attributes"][schemaKey] != null + && $rootScope.customForm["PLAIN"]["attributes"][schemaKey].readonly; + }; + $scope.$watch(function () { return $scope.user.plainAttrs[$scope.schema.key].values[$scope.index]; }, function (newValue, oldValue) { http://git-wip-us.apache.org/repos/asf/syncope/blob/daa1d0d2/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicVirtualAttribute.js ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicVirtualAttribute.js b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicVirtualAttribute.js index 6fc926b..85e2934 100644 --- a/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicVirtualAttribute.js +++ b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicVirtualAttribute.js @@ -28,16 +28,41 @@ angular.module('self') index: "=", user: "=" }, - controller: function ($scope) { + controller: function ($scope, $rootScope) { + var customValues = $rootScope.customForm != null + && $rootScope.customForm["VIRTUAL"] != null + && $rootScope.customForm["VIRTUAL"]["attributes"] != null + && $rootScope.customForm["VIRTUAL"]["attributes"][$scope.schema.key] != null + && $rootScope.customForm["VIRTUAL"]["attributes"][$scope.schema.key].defaultValues + ? $rootScope.customForm["VIRTUAL"]["attributes"][$scope.schema.key].defaultValues + : []; + $scope.$watch(function () { return $scope.user.virAttrs[$scope.schema.key].values[$scope.index]; }, function (newValue, oldValue) { - $scope.user.virAttrs[$scope.schema.key].values = $scope.user.virAttrs[$scope.schema.key].values - .filter(function (n) { - return (n !== undefined && n !== ""); - }); + if ($scope.user.virAttrs[$scope.schema.key].values + && $scope.user.virAttrs[$scope.schema.key].values.length > 0) { + $scope.user.virAttrs[$scope.schema.key].values = $scope.user.virAttrs[$scope.schema.key].values + .filter(function (n) { + return (n !== undefined && n !== ""); + }); + } else { + $scope.user.virAttrs[$scope.schema.key].values = customValues + .filter(function (n) { + return (n !== undefined && n !== ""); + }); + } }); + + $scope.customReadonly = function (schemaKey) { + return $rootScope.customForm != null + && $rootScope.customForm["VIRTUAL"] != null + && $rootScope.customForm["VIRTUAL"]["attributes"] != null + && $rootScope.customForm["VIRTUAL"]["attributes"][schemaKey] != null + && $rootScope.customForm["VIRTUAL"]["attributes"][schemaKey].readonly; + }; } //replace: true }; + }); http://git-wip-us.apache.org/repos/asf/syncope/blob/daa1d0d2/client/enduser/src/main/resources/META-INF/resources/app/js/services/configurationService.js ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/services/configurationService.js b/client/enduser/src/main/resources/META-INF/resources/app/js/services/configurationService.js new file mode 100644 index 0000000..25ee9f2 --- /dev/null +++ b/client/enduser/src/main/resources/META-INF/resources/app/js/services/configurationService.js @@ -0,0 +1,41 @@ +/* + * 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. + */ + +'use strict'; + +angular.module('self') + .factory('ConfigurationService', ['$q', '$http', + function ($q, $http) { + + var configuration = {}; + + configuration.get = function (filename) { + return $http.get("/syncope-enduser/app/configuration/" + filename, {cache: false}) + .then(function (response) { + return response.data; + }, function (response) { + console.error("Unable to retrieve " + filename); + return $q.reject(response.data); + }); + }; + + return configuration; + }]); + + http://git-wip-us.apache.org/repos/asf/syncope/blob/daa1d0d2/client/enduser/src/main/resources/META-INF/resources/app/js/services/saml2IdPService.js ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/services/saml2IdPService.js b/client/enduser/src/main/resources/META-INF/resources/app/js/services/saml2IdPService.js index e8faddd..7412da7 100644 --- a/client/enduser/src/main/resources/META-INF/resources/app/js/services/saml2IdPService.js +++ b/client/enduser/src/main/resources/META-INF/resources/app/js/services/saml2IdPService.js @@ -30,7 +30,7 @@ angular.module('self') .then(function (response) { return response.data; }, function (response) { - console.error("Something went wrong during realms retrieval, exit with status: ", response); + console.error("Something went wrong during saml2Idp extesion retrieval, exit with status: ", response); return $q.reject(response.data || response.statusText); }); }; http://git-wip-us.apache.org/repos/asf/syncope/blob/daa1d0d2/client/enduser/src/main/resources/META-INF/resources/app/js/services/schemaService.js ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/services/schemaService.js b/client/enduser/src/main/resources/META-INF/resources/app/js/services/schemaService.js index 90fdee9..1918bb3 100644 --- a/client/enduser/src/main/resources/META-INF/resources/app/js/services/schemaService.js +++ b/client/enduser/src/main/resources/META-INF/resources/app/js/services/schemaService.js @@ -19,32 +19,36 @@ 'use strict'; -angular.module( 'self' ) - .factory( 'SchemaService', [ '$q', '$http', - function ( $q, $http ) { +angular.module('self') + .factory('SchemaService', ['$q', '$http', + function ($q, $http) { - var schemaService = { }; + var schemaService = {}; - schemaService.getUserSchemas = function ( anyTypeClass, sortingFunction ) { - var classParam = anyTypeClass ? "?anyTypeClass=" + encodeURI( anyTypeClass ) : ""; + schemaService.getUserSchemas = function (anyTypeClass, customForm, sortingFunction) { + var classParam = anyTypeClass ? "?anyTypeClass=" + encodeURI(anyTypeClass) : ""; + var body = customForm ? customForm : {}; - return $http.get( "/syncope-enduser/api/schemas" + classParam ) - .then( function ( response ) { + return $http.post("/syncope-enduser/api/schemas" + classParam, body) + .then(function (response) { var schemas = response.data; - schemas.plainSchemas.sort( sortingFunction ); - schemas.derSchemas.sort( sortingFunction ); - schemas.virSchemas.sort( sortingFunction ); + if (sortingFunction) { + schemas.plainSchemas.sort(sortingFunction); + schemas.derSchemas.sort(sortingFunction); + schemas.virSchemas.sort(sortingFunction); + } return schemas; - }, function ( response ) { - console.error( "Something went wrong during schema retrieval, exit with status: ", response ); - return $q.reject( response.data || response.statusText ); - } ); + }, function (response) { + console.error("Something went wrong during schema retrieval, exit with status: ", response); + return $q.reject(response.data || response.statusText); + }); }; - schemaService.getTypeExtSchemas = function (group) { + schemaService.getTypeExtSchemas = function (group, customForm) { var param = group ? "?group=" + encodeURI(group) : ""; + var body = customForm ? customForm : {}; - return $http.get("/syncope-enduser/api/schemas" + param) + return $http.post("/syncope-enduser/api/schemas" + param, body) .then(function (response) { return response.data; }, function (response) { http://git-wip-us.apache.org/repos/asf/syncope/blob/daa1d0d2/client/enduser/src/main/resources/META-INF/resources/app/views/captcha.html ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/captcha.html b/client/enduser/src/main/resources/META-INF/resources/app/views/captcha.html index b0ea3ff..518ab35 100644 --- a/client/enduser/src/main/resources/META-INF/resources/app/views/captcha.html +++ b/client/enduser/src/main/resources/META-INF/resources/app/views/captcha.html @@ -24,8 +24,8 @@ under the License. <div id="captchaButtons" style="margin-top: 5%; margin-bottom: 10px"> <button id="refresh" type="button" class="btn btn-default btn-xs glyphicon glyphicon-refresh" ng-click="refreshCaptcha()" title="Refresh Captcha"></button> - <a id="refresh" class="btn btn-default btn-xs glyphicon glyphicon-question-sign" title="What is?" - href="https://it.wikipedia.org/wiki/CAPTCHA"/> + <a id="refresh" class="btn btn-default btn-xs glyphicon glyphicon-question-sign" title="What is?" + href="https://it.wikipedia.org/wiki/CAPTCHA" target="_blank"/> </div> <input class="form-control" style="margin:auto; max-width: 260px" type="text" ng-model="input.value"/> </div> http://git-wip-us.apache.org/repos/asf/syncope/blob/daa1d0d2/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicPlainAttribute.html ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicPlainAttribute.html b/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicPlainAttribute.html index 185f97f..b3b5822 100644 --- a/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicPlainAttribute.html +++ b/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicPlainAttribute.html @@ -16,15 +16,14 @@ KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> - <div ng-switch="schema.type" class="schema-type"> <input ng-switch-when="String" class="form-control" type="text" ng-model="user.plainAttrs[schema.key].values[index]" ng-required="{{schema.mandatoryCondition}}" validate="true" - ng-disabled="schema.readonly" ng-init="initAttribute(schema, index)" name="{{schema.key}}"/> + ng-disabled="schema.readonly || customReadonly(schema.key)" ng-init="initAttribute(schema, index)" name="{{schema.key}}"/> <div ng-switch-when="Encrypted" class="input-group input-group-sm"> - <span class="input-group-btn"> + <span class="input-group-btn" ng-disabled="schema.readonly || customReadonly(schema.key)"> <button type="button" class="btn btn-default btn-flat" confirm="{{'CONFIRM_REMOVE'| translate}}" onclick="var pwd = $(this).parent().next('input'); @@ -48,7 +47,7 @@ under the License. <input class="form-control" type="password" readonly="true" ng-model="user.plainAttrs[schema.key].values[index]" ng-required="{{schema.mandatoryCondition}}" validate="true" - ng-disabled="schema.readonly" ng-init="initAttribute(schema, index)" name="{{schema.key}}"/> + ng-disabled="schema.readonly || customReadonly(schema.key)" ng-init="initAttribute(schema, index)" name="{{schema.key}}"/> <span class="input-group-btn"> <button type="button" class="btn btn-default btn-flat" onmousedown="var pwd = $(this).parent().prev('input'); @@ -62,25 +61,29 @@ under the License. $(this).children().attr('class', 'fa fa-eye'); }" > - <i class="fa fa-eye"></i> - </button> - </span> - </div> + <i class="fa fa-eye"></i> +</button> +</span> +</div> - <div ng-switch-when="Boolean"> - <input type="checkbox" ng-model="user.plainAttrs[schema.key].values[index]" ng-required="{{schema.mandatoryCondition}}" +<div ng-switch-when="Boolean"> + <input type="checkbox" ng-model="user.plainAttrs[schema.key].values[index]" + ng-true-value="'true'" + ng-false-value="'false'" + ng-required="{{schema.mandatoryCondition}}" + ng-disabled="schema.readonly || customReadonly(schema.key)" ng-init="initAttribute(schema, index)" /> - </div> + </div> - <input ng-switch-when="Long" class="form-control" type="number" ng-model="user.plainAttrs[schema.key].values[index]" - ng-required="{{schema.mandatoryCondition}}" validate="true" - ng-init="initAttribute(schema, index)" name="{{schema.key}}"/> + <input ng-switch-when="Long" class="form-control" type="number" ng-model="user.plainAttrs[schema.key].values[index]" + ng-required="{{schema.mandatoryCondition}}" validate="true" + ng-init="initAttribute(schema, index)" name="{{schema.key}}"/> - <input ng-switch-when="Double" class="form-control" type="number" ng-model="user.plainAttrs[schema.key].values[index]" - ng-required="{{schema.mandatoryCondition}}" validate="true" - ng-init="initAttribute(schema, index)" name="{{schema.key}}"/> - - <div ng-switch-when="Date" id="date"> + <input ng-switch-when="Double" class="form-control" type="number" ng-model="user.plainAttrs[schema.key].values[index]" + ng-required="{{schema.mandatoryCondition}}" validate="true" + ng-init="initAttribute(schema, index)" name="{{schema.key}}"/> + + <div ng-switch-when="Date" id="date"> <input type="text" class="dateTimePicker" id="dateTimePicker" kendo-date-time-picker @@ -88,33 +91,37 @@ under the License. ng-required="{{schema.mandatoryCondition}}" close-text="Close" ng-init="initAttribute(schema, index)" ng-change="bindDateToModel(selectedDate, extendedDate)" + ng-disabled="schema.readonly || customReadonly(schema.key)" k-ng-model="selectedDate" data-k-format=languageFormat /> - </div> + </div> - <div ng-switch-when="Enum" ng-init="initAttribute(schema, index)"> - <select class="form-control" - ng-model="user.plainAttrs[schema.key].values[index]" - ng-required="{{schema.mandatoryCondition}}"> - <option ng-repeat="value in enumerationValues" value="{{value}}"> - {{enumerationKeys[$index] || value}} - </option> - </select> - </div> + <div ng-switch-when="Enum" ng-init="initAttribute(schema, index)"> + <select class="form-control" + ng-model="user.plainAttrs[schema.key].values[index]" + ng-required="{{schema.mandatoryCondition}}" + ng-disabled="schema.readonly || customReadonly(schema.key)"> + <option ng-repeat="value in enumerationValues" value="{{value}}"> + {{enumerationKeys[$index]|| value}} + </option> + </select> + </div> - <div ng-switch-when="Binary" ng-init="initAttribute(schema, index)"> - <input file-input type="file" id="fileInput" name="fileInput"/> - <button type="button" title="Download file" class="fileButton btn btn-default btn-sm" ng-click="download()"> - <i class="glyphicon glyphicon-download" ></i> - </button> - </div> + <div ng-switch-when="Binary" + ng-disabled="schema.readonly || customReadonly(schema.key)" + ng-init="initAttribute(schema, index)"> + <input file-input type="file" id="fileInput" name="fileInput"/> + <button type="button" title="Download file" class="fileButton btn btn-default btn-sm" ng-click="download()"> + <i class="glyphicon glyphicon-download" ></i> + </button> + </div> - <input ng-switch-default class="form-control" type="text" - ng-model="user.plainAttrs[schema.key].values[index]" - ng-required="{{schema.mandatoryCondition}}" - ng-disabled="schema.readonly" ng-init="initAttribute(schema, index)"/> -</div> + <input ng-switch-default class="form-control" type="text" + ng-model="user.plainAttrs[schema.key].values[index]" + ng-required="{{schema.mandatoryCondition}}" + ng-disabled="schema.readonly || customReadonly(schema.key)" ng-init="initAttribute(schema, index)"/> + </div> http://git-wip-us.apache.org/repos/asf/syncope/blob/daa1d0d2/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicVirtualAttribute.html ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicVirtualAttribute.html b/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicVirtualAttribute.html index a54a60c..ee84784 100644 --- a/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicVirtualAttribute.html +++ b/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicVirtualAttribute.html @@ -19,5 +19,5 @@ under the License. <p> <input class="form-control" type="text" ng-model="user.virAttrs[schema.key].values[index]" - ng-disabled="schema.readonly"/> + ng-disabled="schema.readonly || customReadonly(schema.key)"/> </p>