[SYNCOPE-1019] Added dynamic templating feature to Enduser app
Project: http://git-wip-us.apache.org/repos/asf/syncope/repo Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/f9937e77 Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/f9937e77 Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/f9937e77 Branch: refs/heads/master Commit: f9937e77b78057f91a35d6caa46e9b1e3af832c7 Parents: e1972f8 Author: skylark17 <matteo.alessandr...@tirasa.net> Authored: Tue Aug 28 10:11:47 2018 +0200 Committer: skylark17 <matteo.alessandr...@tirasa.net> Committed: Mon Sep 10 17:47:30 2018 +0200 ---------------------------------------------------------------------- .gitignore | 1 + archetype/pom.xml | 7 +- .../archetype-resources/enduser/pom.xml | 6 +- .../syncope/client/console/pages/BasePage.html | 2 +- .../syncope/client/console/pages/Login.html | 2 +- .../console/pages/MustChangePassword.html | 2 +- client/enduser/pom.xml | 4 +- .../enduser/SyncopeEnduserApplication.java | 130 +++++-- .../enduser/adapters/PlatformInfoAdapter.java | 4 +- .../enduser/model/CustomAttributesInfo.java | 15 - .../client/enduser/model/CustomTemplate.java | 77 ++++ .../enduser/model/CustomTemplateInfo.java | 72 ++++ .../client/enduser/model/CustomTemplateUrl.java | 37 ++ .../enduser/model/CustomTemplateWizard.java | 49 +++ .../enduser/model/PlatformInfoRequest.java | 10 +- .../resources/DynamicTemplateResource.java | 79 ++++ .../resources/ExternalResourceResource.java | 14 +- .../client/enduser/resources/GroupResource.java | 43 ++- .../client/enduser/resources/InfoResource.java | 8 +- .../enduser/resources/SchemaResource.java | 45 ++- .../resources/UserSelfCreateResource.java | 3 +- .../enduser/resources/UserSelfReadResource.java | 15 +- .../resources/UserSelfUpdateResource.java | 7 +- .../enduser/util/UserRequestValidator.java | 29 +- .../META-INF/resources/app/css/app.css | 107 +++--- .../resources/app/css/customSpinner.css | 49 +++ .../META-INF/resources/app/css/editUser.css | 369 +++++++++++-------- .../META-INF/resources/app/css/login.css | 41 +-- .../META-INF/resources/app/css/notification.css | 28 ++ .../resources/app/css/passwordReset.css | 37 ++ .../app/css/templates/dark/editUser.css | 95 +++++ .../resources/app/css/templates/dark/login.css | 78 ++++ .../resources/META-INF/resources/app/index.html | 27 +- .../resources/META-INF/resources/app/js/app.js | 158 +++++--- .../app/js/controllers/LoginController.js | 11 +- .../app/js/controllers/OIDCClientController.js | 4 +- .../app/js/controllers/SAML2SPController.js | 4 +- .../app/js/controllers/UserController.js | 42 ++- .../app/js/directives/dynamicPlainAttribute.js | 10 +- .../app/js/directives/dynamicTemplateItem.js | 79 ++++ .../js/directives/dynamicVirtualAttribute.js | 22 +- .../js/directives/dynamicVirtualAttributes.js | 3 +- .../resources/app/js/directives/fileInput.js | 4 +- .../app/js/directives/navigationButtons.js | 71 ---- .../js/directives/navigationButtonsPartial.js | 71 ++++ .../app/js/services/dynamicTemplateService.js | 67 ++++ .../resources/app/js/util/assetsManager.js | 105 ++++++ .../META-INF/resources/app/views/captcha.html | 14 +- .../app/views/confirmpasswordreset.html | 28 +- .../app/views/dynamicDerivedAttributes.html | 19 +- .../app/views/dynamicPlainAttribute.html | 139 ++++--- .../app/views/dynamicPlainAttributes.html | 14 +- .../app/views/dynamicVirtualAttributes.html | 18 +- .../META-INF/resources/app/views/editUser.html | 31 +- .../resources/app/views/mustchangepassword.html | 22 +- .../resources/app/views/navigationButtons.html | 26 -- .../app/views/navigationButtonsPartial.html | 29 ++ .../resources/app/views/passwordreset.html | 55 +-- .../META-INF/resources/app/views/self.html | 60 +-- .../app/views/templates/editUserTemplate.html | 57 +++ .../onlyPlainAttrsDetails/editUserTemplate.html | 57 +++ .../views/templates/passwordresetTemplate.html | 79 ++++ .../app/views/templates/selfTemplate.html | 77 ++++ .../resources/app/views/user-credentials.html | 62 ++-- .../app/views/user-derived-schemas.html | 33 +- .../resources/app/views/user-form-finish.html | 29 +- .../resources/app/views/user-groups.html | 47 ++- .../resources/app/views/user-plain-schemas.html | 35 +- .../resources/app/views/user-resources.html | 37 +- .../app/views/user-virtual-schemas.html | 33 +- .../enduser/src/main/resources/customForm.json | 1 - .../main/resources/customFormAttributes.json | 1 + .../src/main/resources/customTemplate.json | 65 ++++ .../enduser/util/UserRequestValidatorTest.java | 40 +- .../enduser/src/test/resources/customForm.json | 50 --- .../test/resources/customFormAttributes.json | 44 +++ .../src/test/resources/customTemplate.json | 56 +++ deb/enduser/pom.xml | 3 +- deb/enduser/src/deb/control/conffiles | 3 +- fit/enduser-reference/pom.xml | 23 -- .../src/main/resources/customForm.json | 1 - .../main/resources/customFormAttributes.json | 1 + .../src/main/resources/customTemplate.json | 65 ++++ .../src/main/resources/package.json | 1 + .../src/test/resources/customForm.json | 1 - .../test/resources/customFormAttributes.json | 1 + .../src/test/resources/customTemplate.json | 65 ++++ .../src/test/resources/protractor-conf.js | 8 +- .../src/test/resources/tests/abstract.js | 11 +- .../src/test/resources/tests/edit.js | 5 + .../src/test/resources/tests/passwordreset.js | 1 + pom.xml | 48 +-- .../workingwithapachesyncope/customization.adoc | 207 ++++++++++- 93 files changed, 2770 insertions(+), 1075 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/syncope/blob/f9937e77/.gitignore ---------------------------------------------------------------------- diff --git a/.gitignore b/.gitignore index 3388d02..d479649 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ ide/eclipse/bundles/org.apache.syncope.ide.eclipse.plugin/lib/ ide/eclipse/bundles/org.apache.syncope.ide.eclipse.tests/bin/ ide/eclipse/bundles/org.apache.syncope.ide.eclipse.tests/screenshots/ *nb-configuration.xml +node_modules http://git-wip-us.apache.org/repos/asf/syncope/blob/f9937e77/archetype/pom.xml ---------------------------------------------------------------------- diff --git a/archetype/pom.xml b/archetype/pom.xml index 6561ed8..fa948d0 100644 --- a/archetype/pom.xml +++ b/archetype/pom.xml @@ -276,7 +276,8 @@ under the License. <targetPath>${project.build.outputDirectory}/archetype-resources/enduser/src/main/resources</targetPath> <includes> <include>enduser.properties</include> - <include>customForm.json</include> + <include>customFormAttributes.json</include> + <include>customTemplate.json</include> </includes> </resource> <resource> @@ -310,7 +311,7 @@ under the License. <includes> <include>enduser.properties</include> <include>saml2sp-agent.properties</include> - <include>customForm.json</include> + <include>customFormAttributes.json</include> </includes> </resource> <resource> @@ -319,7 +320,7 @@ under the License. <includes> <include>enduser.properties</include> <include>oidcclient-agent.properties</include> - <include>customForm.json</include> + <include>customFormAttributes.json</include> </includes> </resource> <resource> http://git-wip-us.apache.org/repos/asf/syncope/blob/f9937e77/archetype/src/main/resources/archetype-resources/enduser/pom.xml ---------------------------------------------------------------------- diff --git a/archetype/src/main/resources/archetype-resources/enduser/pom.xml b/archetype/src/main/resources/archetype-resources/enduser/pom.xml index 5f98d31..0c03dec 100644 --- a/archetype/src/main/resources/archetype-resources/enduser/pom.xml +++ b/archetype/src/main/resources/archetype-resources/enduser/pom.xml @@ -247,7 +247,11 @@ under the License. todir="${project.build.directory}/${project.build.finalName}/WEB-INF/classes" overwrite="true"/> - <copy file="${project.build.directory}/test-classes/customForm.json" + <copy file="${project.build.directory}/test-classes/customFormAttributes.json" + todir="${project.build.directory}/${project.build.finalName}/WEB-INF/classes" + overwrite="true"/> + + <copy file="${project.build.directory}/test-classes/customTemplate.json" todir="${project.build.directory}/${project.build.finalName}/WEB-INF/classes" overwrite="true"/> </target> http://git-wip-us.apache.org/repos/asf/syncope/blob/f9937e77/client/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage.html ---------------------------------------------------------------------- diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage.html b/client/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage.html index 169e2d6..d477213 100644 --- a/client/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage.html +++ b/client/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage.html @@ -26,7 +26,7 @@ under the License. <link rel="shortcut icon" href="img/favicon.png" type="image/png"/> - <link href="webjars/font-awesome/${font-awesome.version}/css/font-awesome.min.css" rel="stylesheet" type="text/css"/> + <link href="webjars/font-awesome/${font-awesome.version}/css/${font-awesome.filename}" rel="stylesheet" type="text/css"/> <link href="webjars/ionicons/${ionicons.version}/css/ionicons.min.css" rel="stylesheet" type="text/css"/> <link href="css/fonts.css" rel="stylesheet" type="text/css"/> http://git-wip-us.apache.org/repos/asf/syncope/blob/f9937e77/client/console/src/main/resources/org/apache/syncope/client/console/pages/Login.html ---------------------------------------------------------------------- diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/pages/Login.html b/client/console/src/main/resources/org/apache/syncope/client/console/pages/Login.html index bb5cd3a..0340b83 100644 --- a/client/console/src/main/resources/org/apache/syncope/client/console/pages/Login.html +++ b/client/console/src/main/resources/org/apache/syncope/client/console/pages/Login.html @@ -27,7 +27,7 @@ under the License. <link rel="shortcut icon" href="img/favicon.png" type="image/png"/> - <link href="webjars/font-awesome/${font-awesome.version}/css/font-awesome.min.css" rel="stylesheet" type="text/css" /> + <link href="webjars/font-awesome/${font-awesome.version}/css/${font-awesome.filename}" rel="stylesheet" type="text/css" /> <link href="webjars/ionicons/${ionicons.version}/css/ionicons.min.css" rel="stylesheet" type="text/css" /> <link href="css/fonts.css" rel="stylesheet" type="text/css"/> http://git-wip-us.apache.org/repos/asf/syncope/blob/f9937e77/client/console/src/main/resources/org/apache/syncope/client/console/pages/MustChangePassword.html ---------------------------------------------------------------------- diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/pages/MustChangePassword.html b/client/console/src/main/resources/org/apache/syncope/client/console/pages/MustChangePassword.html index 4aef153..037ea71 100644 --- a/client/console/src/main/resources/org/apache/syncope/client/console/pages/MustChangePassword.html +++ b/client/console/src/main/resources/org/apache/syncope/client/console/pages/MustChangePassword.html @@ -27,7 +27,7 @@ under the License. <link rel="shortcut icon" href="img/favicon.png" type="image/png"/> - <link href="webjars/font-awesome/${font-awesome.version}/css/font-awesome.min.css" rel="stylesheet" type="text/css" /> + <link href="webjars/font-awesome/${font-awesome.version}/css/${font-awesome.filename}" rel="stylesheet" type="text/css" /> <link href="webjars/ionicons/${ionicons.version}/css/ionicons.min.css" rel="stylesheet" type="text/css" /> <link href="css/fonts.css" rel="stylesheet" type="text/css"/> http://git-wip-us.apache.org/repos/asf/syncope/blob/f9937e77/client/enduser/pom.xml ---------------------------------------------------------------------- diff --git a/client/enduser/pom.xml b/client/enduser/pom.xml index 0acb899..bd5bf1a 100644 --- a/client/enduser/pom.xml +++ b/client/enduser/pom.xml @@ -137,8 +137,8 @@ under the License. <artifactId>ionicons</artifactId> </dependency> <dependency> - <groupId>org.webjars</groupId> - <artifactId>angular-ui-bootstrap</artifactId> + <groupId>org.webjars.npm</groupId> + <artifactId>ui-bootstrap4</artifactId> </dependency> <dependency> <groupId>org.webjars</groupId> http://git-wip-us.apache.org/repos/asf/syncope/blob/f9937e77/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserApplication.java ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserApplication.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserApplication.java index 98e723f..be67966 100644 --- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserApplication.java +++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserApplication.java @@ -39,6 +39,7 @@ import org.apache.syncope.client.enduser.annotations.Resource; import org.apache.syncope.client.enduser.init.ClassPathScanImplementationLookup; import org.apache.syncope.client.enduser.init.EnduserInitializer; import org.apache.syncope.client.enduser.model.CustomAttributesInfo; +import org.apache.syncope.client.enduser.model.CustomTemplateInfo; import org.apache.syncope.client.enduser.resources.CaptchaResource; import org.apache.syncope.client.lib.SyncopeClientFactoryBean; import org.apache.syncope.common.lib.PropertyUtils; @@ -64,7 +65,9 @@ public class SyncopeEnduserApplication extends WebApplication implements Seriali private static final String ENDUSER_PROPERTIES = "enduser.properties"; - private static final String CUSTOM_FORM_FILE = "customForm.json"; + private static final String CUSTOM_FORM_ATTRIBUTES_FILE = "customFormAttributes.json"; + + private static final String CUSTOM_TEMPLATE_FILE = "customTemplate.json"; public static SyncopeEnduserApplication get() { return (SyncopeEnduserApplication) WebApplication.get(); @@ -86,7 +89,9 @@ public class SyncopeEnduserApplication extends WebApplication implements Seriali private SyncopeClientFactoryBean clientFactory; - private Map<String, CustomAttributesInfo> customForm; + private Map<String, CustomAttributesInfo> customFormAttributes; + + private CustomTemplateInfo customTemplate; private static final ObjectMapper MAPPER = new ObjectMapper(); @@ -130,26 +135,29 @@ public class SyncopeEnduserApplication extends WebApplication implements Seriali setContentType(SyncopeClientFactoryBean.ContentType.JSON). setUseCompression(BooleanUtils.toBoolean(useGZIPCompression)); - // read customForm.json - try (InputStream is = getClass().getResourceAsStream("/" + CUSTOM_FORM_FILE)) { - customForm = MAPPER.readValue(is, + // read customFormAttributes.json + File enduserDir; + try (InputStream is = getClass().getResourceAsStream("/" + CUSTOM_FORM_ATTRIBUTES_FILE)) { + customFormAttributes = MAPPER.readValue(is, new TypeReference<HashMap<String, CustomAttributesInfo>>() { }); - File enduserDir = new File(props.getProperty("enduser.directory")); + enduserDir = new File(props.getProperty("enduser.directory")); boolean existsEnduserDir = enduserDir.exists() && enduserDir.canRead() && enduserDir.isDirectory(); if (existsEnduserDir) { - File customFormFile = FileUtils.getFile(enduserDir, CUSTOM_FORM_FILE); - if (customFormFile.exists() && customFormFile.canRead() && customFormFile.isFile()) { - customForm = MAPPER.readValue(FileUtils.openInputStream(customFormFile), + File customFormAttributesFile = FileUtils.getFile(enduserDir, CUSTOM_FORM_ATTRIBUTES_FILE); + if (customFormAttributesFile.exists() + && customFormAttributesFile.canRead() + && customFormAttributesFile.isFile()) { + customFormAttributes = MAPPER.readValue(FileUtils.openInputStream(customFormAttributesFile), new TypeReference<HashMap<String, CustomAttributesInfo>>() { }); } } FileAlterationObserver observer = existsEnduserDir ? new FileAlterationObserver(enduserDir, - pathname -> StringUtils.contains(pathname.getPath(), CUSTOM_FORM_FILE)) - : new FileAlterationObserver(getClass().getResource("/" + CUSTOM_FORM_FILE).getFile(), - pathname -> StringUtils.contains(pathname.getPath(), CUSTOM_FORM_FILE)); + pathname -> StringUtils.contains(pathname.getPath(), CUSTOM_FORM_ATTRIBUTES_FILE)) + : new FileAlterationObserver(getClass().getResource("/" + CUSTOM_FORM_ATTRIBUTES_FILE).getFile(), + pathname -> StringUtils.contains(pathname.getPath(), CUSTOM_FORM_ATTRIBUTES_FILE)); FileAlterationMonitor monitor = new FileAlterationMonitor(5000); @@ -158,8 +166,9 @@ public class SyncopeEnduserApplication extends WebApplication implements Seriali @Override public void onFileChange(final File file) { try { - LOG.trace("{} has changed. Reloading form customization configuration.", CUSTOM_FORM_FILE); - customForm = MAPPER.readValue(FileUtils.openInputStream(file), + LOG.trace("{} has changed. Reloading form attributes customization configuration.", + CUSTOM_FORM_ATTRIBUTES_FILE); + customFormAttributes = MAPPER.readValue(FileUtils.openInputStream(file), new TypeReference<HashMap<String, CustomAttributesInfo>>() { }); } catch (IOException e) { @@ -170,8 +179,9 @@ public class SyncopeEnduserApplication extends WebApplication implements Seriali @Override public void onFileCreate(final File file) { try { - LOG.trace("{} has been created. Loading form customization configuration.", CUSTOM_FORM_FILE); - customForm = MAPPER.readValue(FileUtils.openInputStream(file), + LOG.trace("{} has been created. Loading form attributes customization configuration.", + CUSTOM_FORM_ATTRIBUTES_FILE); + customFormAttributes = MAPPER.readValue(FileUtils.openInputStream(file), new TypeReference<HashMap<String, CustomAttributesInfo>>() { }); } catch (IOException e) { @@ -181,8 +191,72 @@ public class SyncopeEnduserApplication extends WebApplication implements Seriali @Override public void onFileDelete(final File file) { - LOG.trace("{} has been deleted. Resetting form customization configuration.", CUSTOM_FORM_FILE); - customForm = null; + LOG.trace("{} has been deleted. Resetting form attributes customization configuration.", + CUSTOM_FORM_ATTRIBUTES_FILE); + customFormAttributes = null; + } + }; + + observer.addListener(listener); + monitor.addObserver(observer); + monitor.start(); + } catch (Exception e) { + throw new WicketRuntimeException("Could not read " + CUSTOM_FORM_ATTRIBUTES_FILE, e); + } + + // read customTemplate.json + try (InputStream is = getClass().getResourceAsStream("/" + CUSTOM_TEMPLATE_FILE)) { + customTemplate = MAPPER.readValue(is, CustomTemplateInfo.class); + enduserDir = new File(props.getProperty("enduser.directory")); + boolean existsEnduserDir = enduserDir.exists() && enduserDir.canRead() && enduserDir.isDirectory(); + if (existsEnduserDir) { + File customTemplateFile = FileUtils.getFile(enduserDir, CUSTOM_TEMPLATE_FILE); + if (customTemplateFile.exists() + && customTemplateFile.canRead() + && customTemplateFile.isFile()) { + customTemplate = MAPPER.readValue(FileUtils.openInputStream(customTemplateFile), + CustomTemplateInfo.class); + } + } + FileAlterationObserver observer = existsEnduserDir + ? new FileAlterationObserver(enduserDir, + pathname -> StringUtils.contains(pathname.getPath(), CUSTOM_TEMPLATE_FILE)) + : new FileAlterationObserver(getClass().getResource("/" + CUSTOM_TEMPLATE_FILE).getFile(), + pathname -> StringUtils.contains(pathname.getPath(), CUSTOM_TEMPLATE_FILE)); + + FileAlterationMonitor monitor = new FileAlterationMonitor(5000); + + FileAlterationListener listener = new FileAlterationListenerAdaptor() { + + @Override + public void onFileChange(final File file) { + try { + LOG.trace("{} has changed. Reloading app customization configuration.", + CUSTOM_TEMPLATE_FILE); + customTemplate = MAPPER.readValue(FileUtils.openInputStream(file), + CustomTemplateInfo.class); + } catch (IOException e) { + e.printStackTrace(System.err); + } + } + + @Override + public void onFileCreate(final File file) { + try { + LOG.trace("{} has been created. Loading app customization configuration.", + CUSTOM_TEMPLATE_FILE); + customTemplate = MAPPER.readValue(FileUtils.openInputStream(file), + CustomTemplateInfo.class); + } catch (IOException e) { + e.printStackTrace(System.err); + } + } + + @Override + public void onFileDelete(final File file) { + LOG.trace("{} has been deleted. Resetting app customization configuration.", + CUSTOM_TEMPLATE_FILE); + customTemplate = null; } }; @@ -190,7 +264,7 @@ public class SyncopeEnduserApplication extends WebApplication implements Seriali monitor.addObserver(observer); monitor.start(); } catch (Exception e) { - throw new WicketRuntimeException("Could not read " + CUSTOM_FORM_FILE, e); + throw new WicketRuntimeException("Could not read " + CUSTOM_TEMPLATE_FILE, e); } // mount resources @@ -275,13 +349,21 @@ public class SyncopeEnduserApplication extends WebApplication implements Seriali return maxUploadFileSizeMB; } - public Map<String, CustomAttributesInfo> getCustomForm() { - return customForm; + public Map<String, CustomAttributesInfo> getCustomFormAttributes() { + return customFormAttributes; + } + + public void setCustomFormAttributes(final Map<String, CustomAttributesInfo> customFormAttributes) { + this.customFormAttributes.clear(); + this.customFormAttributes.putAll(customFormAttributes); + } + + public void setCustomTemplate(final CustomTemplateInfo customTemplate) { + this.customTemplate = customTemplate; } - public void setCustomForm(final Map<String, CustomAttributesInfo> customForm) { - this.customForm.clear(); - this.customForm.putAll(customForm); + public CustomTemplateInfo getCustomTemplate() { + return customTemplate; } } http://git-wip-us.apache.org/repos/asf/syncope/blob/f9937e77/client/enduser/src/main/java/org/apache/syncope/client/enduser/adapters/PlatformInfoAdapter.java ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/adapters/PlatformInfoAdapter.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/adapters/PlatformInfoAdapter.java index a9fcf3c..e194d6b 100644 --- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/adapters/PlatformInfoAdapter.java +++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/adapters/PlatformInfoAdapter.java @@ -27,7 +27,7 @@ import org.apache.syncope.common.lib.info.PlatformInfo; public final class PlatformInfoAdapter { public static PlatformInfoRequest toPlatformInfoRequest(final PlatformInfo platformInfo, - final Map<String, CustomAttributesInfo> customForm) { + final Map<String, CustomAttributesInfo> customFormAttributes) { PlatformInfoRequest request = new PlatformInfoRequest(); request.setPwdResetAllowed(platformInfo.isPwdResetAllowed()); request.setSelfRegAllowed(platformInfo.isSelfRegAllowed()); @@ -37,7 +37,7 @@ public final class PlatformInfoAdapter { if (SyncopeEnduserApplication.get().getMaxUploadFileSizeMB() != null) { request.setMaxUploadFileSizeMB(SyncopeEnduserApplication.get().getMaxUploadFileSizeMB()); } - request.setCustomForm(customForm); + request.setCustomFormAttributes(customFormAttributes); return request; } http://git-wip-us.apache.org/repos/asf/syncope/blob/f9937e77/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 index 63eaa0b..c49253c 100644 --- 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 @@ -26,21 +26,11 @@ public class CustomAttributesInfo implements Serializable { private static final long serialVersionUID = 878444785696091916L; - private Boolean show = Boolean.TRUE; - private Map<String, CustomAttribute> attributes = new LinkedHashMap<>(); public CustomAttributesInfo() { } - public Boolean isShow() { - return show; - } - - public void setShow(final Boolean show) { - this.show = show; - } - public Map<String, CustomAttribute> getAttributes() { return attributes; } @@ -49,11 +39,6 @@ public class CustomAttributesInfo implements Serializable { this.attributes = attributes; } - public CustomAttributesInfo show(final Boolean value) { - this.show = value; - return this; - } - public CustomAttributesInfo attributes(final Map<String, CustomAttribute> value) { this.attributes = value; return this; http://git-wip-us.apache.org/repos/asf/syncope/blob/f9937e77/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/CustomTemplate.java ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/CustomTemplate.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/CustomTemplate.java new file mode 100644 index 0000000..19d4a5b --- /dev/null +++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/CustomTemplate.java @@ -0,0 +1,77 @@ +/* + * 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.ArrayList; +import java.util.List; + +public class CustomTemplate implements Serializable { + + private static final long serialVersionUID = -3870675034923683299L; + + private String templateUrl; + + private List<String> css = new ArrayList<>(); + + private List<String> js = new ArrayList<>(); + + public CustomTemplate() { + } + + public String getTemplateUrl() { + return templateUrl; + } + + public void setTemplateUrl(final String templateUrl) { + this.templateUrl = templateUrl; + } + + public List<String> getCss() { + return css; + } + + public void setCss(final List<String> css) { + this.css = css; + } + + public List<String> getJs() { + return js; + } + + public void setJs(final List<String> js) { + this.js = js; + } + + public CustomTemplate templateUrl(final String value) { + this.templateUrl = value; + return this; + } + + public CustomTemplate css(final List<String> value) { + this.css = value; + return this; + } + + public CustomTemplate js(final List<String> value) { + this.js = value; + return this; + } + +} http://git-wip-us.apache.org/repos/asf/syncope/blob/f9937e77/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/CustomTemplateInfo.java ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/CustomTemplateInfo.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/CustomTemplateInfo.java new file mode 100644 index 0000000..d2fe9c1 --- /dev/null +++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/CustomTemplateInfo.java @@ -0,0 +1,72 @@ +/* + * 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.List; +import java.util.Map; + +public class CustomTemplateInfo implements Serializable { + + private static final long serialVersionUID = -3422125754029851539L; + + private Map<String, CustomTemplate> templates = new LinkedHashMap<>(); + + private CustomTemplateWizard wizard = new CustomTemplateWizard(); + + private Map<String, List<String>> generalAssets = new LinkedHashMap<>(); + + public CustomTemplateInfo() { + } + + public Map<String, CustomTemplate> getTemplates() { + return templates; + } + + public void setTemplates(final Map<String, CustomTemplate> templates) { + this.templates = templates; + } + + public CustomTemplateWizard getWizard() { + return wizard; + } + + public void setWizard(final CustomTemplateWizard wizard) { + this.wizard = wizard; + } + + public Map<String, List<String>> getGeneralAssets() { + return generalAssets; + } + + public void setGeneralAssets(final Map<String, List<String>> generalAssets) { + this.generalAssets = generalAssets; + } + + public CustomTemplateInfo templates(final Map<String, CustomTemplate> templates, + final CustomTemplateWizard wizard, final Map<String, List<String>> generalAssets) { + + this.templates = templates; + this.wizard = wizard; + this.generalAssets = generalAssets; + return this; + } + +} http://git-wip-us.apache.org/repos/asf/syncope/blob/f9937e77/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/CustomTemplateUrl.java ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/CustomTemplateUrl.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/CustomTemplateUrl.java new file mode 100644 index 0000000..40bde34 --- /dev/null +++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/CustomTemplateUrl.java @@ -0,0 +1,37 @@ +/* + * 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; + +public class CustomTemplateUrl implements Serializable { + + private static final long serialVersionUID = 3971593691907398343L; + + private String url; + + public String getUrl() { + return url; + } + + public void setUrl(final String url) { + this.url = url; + } + +} http://git-wip-us.apache.org/repos/asf/syncope/blob/f9937e77/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/CustomTemplateWizard.java ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/CustomTemplateWizard.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/CustomTemplateWizard.java new file mode 100644 index 0000000..3952f9b --- /dev/null +++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/CustomTemplateWizard.java @@ -0,0 +1,49 @@ +/* + * 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.HashMap; +import java.util.Map; + +public class CustomTemplateWizard implements Serializable { + + private static final long serialVersionUID = -4290154059045309105L; + + private String firstStep; + + private Map<String, CustomTemplateUrl> steps = new HashMap<>(); + + public String getFirstStep() { + return firstStep; + } + + public void setFirstStep(final String firstStep) { + this.firstStep = firstStep; + } + + public Map<String, CustomTemplateUrl> getSteps() { + return steps; + } + + public void setSteps(final Map<String, CustomTemplateUrl> steps) { + this.steps = steps; + } + +} http://git-wip-us.apache.org/repos/asf/syncope/blob/f9937e77/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/PlatformInfoRequest.java ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/PlatformInfoRequest.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/PlatformInfoRequest.java index c4daa44..bd80359 100644 --- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/PlatformInfoRequest.java +++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/model/PlatformInfoRequest.java @@ -37,7 +37,7 @@ public class PlatformInfoRequest implements Serializable { private int maxUploadFileSizeMB; - private Map<String, CustomAttributesInfo> customForm; + private Map<String, CustomAttributesInfo> customFormAttributes; public PlatformInfoRequest() { } @@ -90,12 +90,12 @@ public class PlatformInfoRequest implements Serializable { this.maxUploadFileSizeMB = maxUploadFileSizeMB; } - public Map<String, CustomAttributesInfo> getCustomForm() { - return customForm; + public Map<String, CustomAttributesInfo> getCustomFormAttributes() { + return customFormAttributes; } - public void setCustomForm(final Map<String, CustomAttributesInfo> customForm) { - this.customForm = customForm; + public void setCustomFormAttributes(final Map<String, CustomAttributesInfo> customFormAttributes) { + this.customFormAttributes = customFormAttributes; } } http://git-wip-us.apache.org/repos/asf/syncope/blob/f9937e77/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/DynamicTemplateResource.java ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/DynamicTemplateResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/DynamicTemplateResource.java new file mode 100644 index 0000000..86b19bd --- /dev/null +++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/DynamicTemplateResource.java @@ -0,0 +1,79 @@ +/* + * 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.resources; + +import static org.apache.syncope.client.enduser.resources.BaseResource.MAPPER; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import org.apache.commons.lang3.StringUtils; +import org.apache.syncope.client.enduser.SyncopeEnduserApplication; +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.client.enduser.model.CustomTemplateInfo; +import org.apache.syncope.client.enduser.util.SaltGenerator; +import org.apache.wicket.request.resource.IResource; +import org.apache.wicket.util.cookies.CookieUtils; + +@Resource(key = "info", path = "/api/dynamicTemplate") +public class DynamicTemplateResource extends BaseResource { + + private static final long serialVersionUID = 7181372091437530936L; + + @Override + protected ResourceResponse newResourceResponse(final IResource.Attributes attributes) { + ResourceResponse response = new ResourceResponse(); + response.setContentType(MediaType.APPLICATION_JSON); + + try { + final CookieUtils sessionCookieUtils = SyncopeEnduserSession.get().getCookieUtils(); + // set XSRF_TOKEN cookie + if (!SyncopeEnduserSession.get().isXsrfTokenGenerated() && (sessionCookieUtils.getCookie( + SyncopeEnduserConstants.XSRF_COOKIE) == null || StringUtils.isBlank( + sessionCookieUtils.getCookie(SyncopeEnduserConstants.XSRF_COOKIE).getValue()))) { + LOG.debug("Set XSRF-TOKEN cookie"); + SyncopeEnduserSession.get().setXsrfTokenGenerated(true); + sessionCookieUtils.save(SyncopeEnduserConstants.XSRF_COOKIE, + SaltGenerator.generate(SyncopeEnduserSession.get().getId())); + } + response.setTextEncoding(StandardCharsets.UTF_8.name()); + response.setWriteCallback(new WriteCallback() { + + @Override + public void writeData(final IResource.Attributes attributes) throws IOException { + CustomTemplateInfo customTemplate = SyncopeEnduserApplication.get().getCustomTemplate(); + attributes.getResponse().write(MAPPER.writeValueAsString(customTemplate)); + } + }); + response.setStatusCode(Response.Status.OK.getStatusCode()); + } catch (Exception e) { + LOG.error("Error retrieving syncope custom dynamic template", e); + response.setError(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), new StringBuilder() + .append("ErrorMessage{{ ") + .append(e.getMessage()) + .append(" }}") + .toString()); + } + + return response; + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/f9937e77/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/ExternalResourceResource.java ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/ExternalResourceResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/ExternalResourceResource.java index d354f56..2d7736c 100644 --- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/ExternalResourceResource.java +++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/ExternalResourceResource.java @@ -20,12 +20,15 @@ package org.apache.syncope.client.enduser.resources; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.Collections; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import org.apache.syncope.client.enduser.SyncopeEnduserApplication; import org.apache.syncope.client.enduser.SyncopeEnduserSession; import org.apache.syncope.client.enduser.annotations.Resource; +import org.apache.syncope.client.enduser.model.CustomTemplateInfo; import org.apache.syncope.common.rest.api.service.SyncopeService; import org.apache.wicket.request.resource.AbstractResource; import org.apache.wicket.request.resource.IResource; @@ -49,10 +52,13 @@ public class ExternalResourceResource extends BaseResource { return response; } - final List<String> resources = SyncopeEnduserSession.get(). - getService(SyncopeService.class).platform().getResources(); + CustomTemplateInfo customTemplate = + SyncopeEnduserApplication.get().getCustomTemplate(); + final List<String> resources = customTemplate.getWizard().getSteps().containsKey("groups") + ? SyncopeEnduserSession.get(). + getService(SyncopeService.class).platform().getResources() + : Collections.<String>emptyList(); - response.setTextEncoding(StandardCharsets.UTF_8.name()); response.setWriteCallback(new AbstractResource.WriteCallback() { @Override @@ -60,6 +66,8 @@ public class ExternalResourceResource extends BaseResource { attributes.getResponse().write(MAPPER.writeValueAsString(resources)); } }); + + response.setTextEncoding(StandardCharsets.UTF_8.name()); response.setStatusCode(Response.Status.OK.getStatusCode()); } catch (Exception e) { LOG.error("Error retrieving available resources", e); http://git-wip-us.apache.org/repos/asf/syncope/blob/f9937e77/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/GroupResource.java ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/GroupResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/GroupResource.java index 66ae312..14fb790 100644 --- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/GroupResource.java +++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/GroupResource.java @@ -22,14 +22,17 @@ import java.io.IOException; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import org.apache.syncope.client.enduser.SyncopeEnduserApplication; import org.apache.syncope.client.enduser.SyncopeEnduserSession; import org.apache.syncope.client.enduser.annotations.Resource; +import org.apache.syncope.client.enduser.model.CustomTemplateInfo; import org.apache.syncope.common.lib.SyncopeConstants; import org.apache.syncope.common.lib.to.GroupTO; import org.apache.syncope.common.rest.api.service.SyncopeService; @@ -55,24 +58,31 @@ public class GroupResource extends BaseResource { return response; } - String realm = URLDecoder.decode(attributes.getParameters().get("realm"). - toString(SyncopeConstants.ROOT_REALM), "UTF-8"); - StringValue term = attributes.getParameters().get("term"); - + CustomTemplateInfo customTemplate = + SyncopeEnduserApplication.get().getCustomTemplate(); final GroupResponse groupResponse = new GroupResponse(); - final int totGroups = SyncopeEnduserSession.get(). - getService(SyncopeService.class).numbers().getTotalGroups(); - final List<GroupTO> groupTOs = SyncopeEnduserSession.get(). - getService(SyncopeService.class).searchAssignableGroups( - realm, - term.isNull() || term.isEmpty() ? null : URLDecoder.decode(term.toString(), "UTF-8"), - 1, - 30).getResult(); - groupResponse.setTotGroups(totGroups); - groupResponse.setGroupTOs(groupTOs.stream().collect( - Collectors.toMap(GroupTO::getKey, GroupTO::getName))); + if (customTemplate.getWizard().getSteps().containsKey("groups")) { + String realm = URLDecoder.decode(attributes.getParameters().get("realm"). + toString(SyncopeConstants.ROOT_REALM), "UTF-8"); + StringValue term = attributes.getParameters().get("term"); + + final int totGroups = SyncopeEnduserSession.get(). + getService(SyncopeService.class).numbers().getTotalGroups(); + final List<GroupTO> groupTOs = SyncopeEnduserSession.get(). + getService(SyncopeService.class).searchAssignableGroups( + realm, + term.isNull() || term.isEmpty() ? null : URLDecoder.decode(term.toString(), "UTF-8"), + 1, + 30).getResult(); + groupResponse.setTotGroups(totGroups); + groupResponse.setGroupTOs(groupTOs.stream().collect( + Collectors.toMap(GroupTO::getKey, GroupTO::getName))); + } else { + groupResponse.setTotGroups(0); + Map<String, String> groups = new HashMap<>(); + groupResponse.setGroupTOs(groups); + } - response.setTextEncoding(StandardCharsets.UTF_8.name()); response.setWriteCallback(new AbstractResource.WriteCallback() { @Override @@ -80,6 +90,7 @@ public class GroupResource extends BaseResource { attributes.getResponse().write(MAPPER.writeValueAsString(groupResponse)); } }); + response.setTextEncoding(StandardCharsets.UTF_8.name()); response.setStatusCode(Response.Status.OK.getStatusCode()); } catch (Exception e) { LOG.error("Error retrieving available groups", e); http://git-wip-us.apache.org/repos/asf/syncope/blob/f9937e77/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/InfoResource.java ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/InfoResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/InfoResource.java index 58bd238..9b990a0 100644 --- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/InfoResource.java +++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/InfoResource.java @@ -57,18 +57,20 @@ public class InfoResource extends BaseResource { SaltGenerator.generate(SyncopeEnduserSession.get().getId())); } response.setTextEncoding(StandardCharsets.UTF_8.name()); + response.setWriteCallback(new WriteCallback() { @Override public void writeData(final IResource.Attributes attributes) throws IOException { - Map<String, CustomAttributesInfo> customForm = SyncopeEnduserApplication.get().getCustomForm(); + Map<String, CustomAttributesInfo> customFormAttributes = + SyncopeEnduserApplication.get().getCustomFormAttributes(); attributes.getResponse().write( MAPPER.writeValueAsString( PlatformInfoAdapter.toPlatformInfoRequest( SyncopeEnduserSession.get().getPlatformInfo(), - customForm == null + customFormAttributes == null ? new HashMap<>() - : customForm))); + : customFormAttributes))); } }); response.setStatusCode(Response.Status.OK.getStatusCode()); http://git-wip-us.apache.org/repos/asf/syncope/blob/f9937e77/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 3559bdb..b6c57e8 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 @@ -35,6 +35,7 @@ import org.apache.syncope.client.enduser.SyncopeEnduserSession; import org.apache.syncope.client.enduser.annotations.Resource; import org.apache.syncope.client.enduser.model.CustomAttribute; import org.apache.syncope.client.enduser.model.CustomAttributesInfo; +import org.apache.syncope.client.enduser.model.CustomTemplateInfo; import org.apache.syncope.client.enduser.model.SchemaResponse; import org.apache.syncope.common.lib.to.SchemaTO; import org.apache.syncope.common.lib.to.TypeExtensionTO; @@ -88,38 +89,47 @@ public class SchemaResource extends BaseResource { } // USER from customization, if empty or null ignore it, use it to filter attributes otherwise - Map<String, CustomAttributesInfo> customForm = SyncopeEnduserApplication.get().getCustomForm(); + Map<String, CustomAttributesInfo> customFormAttributes = + SyncopeEnduserApplication.get().getCustomFormAttributes(); + CustomTemplateInfo customTemplate = + SyncopeEnduserApplication.get().getCustomTemplate(); SchemaService schemaService = SyncopeEnduserSession.get().getService(SchemaService.class); final List<SchemaTO> plainSchemas = classes.isEmpty() ? Collections.<SchemaTO>emptyList() - : customForm == null || customForm.isEmpty() || customForm.get(SchemaType.PLAIN.name()) == null + : customFormAttributes == null + || customFormAttributes.isEmpty() + || customFormAttributes.get(SchemaType.PLAIN.name()) == null ? schemaService.search( new SchemaQuery.Builder().type(SchemaType.PLAIN).anyTypeClasses(classes).build()) - : customForm.get(SchemaType.PLAIN.name()).isShow() + : customTemplate.getWizard().getSteps().containsKey("plainSchemas") ? customizeSchemas(schemaService.search(new SchemaQuery.Builder().type(SchemaType.PLAIN). - anyTypeClasses(classes).build()), group, customForm.get(SchemaType.PLAIN.name()). - getAttributes()) + anyTypeClasses(classes).build()), group, + customFormAttributes.get(SchemaType.PLAIN.name()).getAttributes()) : Collections.<SchemaTO>emptyList(); final List<SchemaTO> derSchemas = classes.isEmpty() ? Collections.<SchemaTO>emptyList() - : customForm == null || customForm.isEmpty() || customForm.get(SchemaType.DERIVED.name()) == null + : customFormAttributes == null + || customFormAttributes.isEmpty() + || customFormAttributes.get(SchemaType.DERIVED.name()) == null ? schemaService.search( new SchemaQuery.Builder().type(SchemaType.DERIVED).anyTypeClasses(classes).build()) - : customForm.get(SchemaType.DERIVED.name()).isShow() + : customTemplate.getWizard().getSteps().containsKey("derivedSchemas") ? customizeSchemas(schemaService.search(new SchemaQuery.Builder().type(SchemaType.DERIVED). - anyTypeClasses(classes).build()), group, customForm.get(SchemaType.DERIVED.name()). - getAttributes()) + anyTypeClasses(classes).build()), group, + customFormAttributes.get(SchemaType.DERIVED.name()).getAttributes()) : Collections.<SchemaTO>emptyList(); final List<SchemaTO> virSchemas = classes.isEmpty() ? Collections.<SchemaTO>emptyList() - : customForm == null || customForm.isEmpty() || customForm.get(SchemaType.VIRTUAL.name()) == null + : customFormAttributes == null + || customFormAttributes.isEmpty() + || customFormAttributes.get(SchemaType.VIRTUAL.name()) == null ? schemaService.search( new SchemaQuery.Builder().type(SchemaType.VIRTUAL).anyTypeClasses(classes).build()) - : customForm.get(SchemaType.VIRTUAL.name()).isShow() + : customTemplate.getWizard().getSteps().containsKey("virtualSchemas") ? customizeSchemas(schemaService.search(new SchemaQuery.Builder().type(SchemaType.VIRTUAL). - anyTypeClasses(classes).build()), group, customForm.get(SchemaType.VIRTUAL.name()). - getAttributes()) + anyTypeClasses(classes).build()), group, + customFormAttributes.get(SchemaType.VIRTUAL.name()).getAttributes()) : Collections.<SchemaTO>emptyList(); if (group != null) { @@ -161,21 +171,20 @@ public class SchemaResource extends BaseResource { private List<SchemaTO> customizeSchemas( final List<SchemaTO> schemaTOs, final String groupParam, - final Map<String, CustomAttribute> customForm) { - - if (customForm.isEmpty()) { + final Map<String, CustomAttribute> customFormAttributes) { + if (customFormAttributes.isEmpty()) { return schemaTOs; } final boolean isGroupBlank = StringUtils.isBlank(groupParam); schemaTOs.removeAll(schemaTOs.stream(). - filter(schema -> !customForm.containsKey(isGroupBlank + filter(schema -> !customFormAttributes.containsKey(isGroupBlank ? schema.getKey() : compositeSchemaKey(groupParam, schema.getKey()))). collect(Collectors.toSet())); Collections.sort(schemaTOs, (schemaTO1, schemaTO2) -> { - List<String> order = new ArrayList<>(customForm.keySet()); + List<String> order = new ArrayList<>(customFormAttributes.keySet()); return order.indexOf(isGroupBlank ? schemaTO1.getKey() : compositeSchemaKey(groupParam, schemaTO1.getKey())) http://git-wip-us.apache.org/repos/asf/syncope/blob/f9937e77/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 9d8d7d5..e017d45 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 @@ -81,7 +81,8 @@ public class UserSelfCreateResource extends BaseUserSelfResource { LOG.trace("Request is [{}]", userTO); // check if request is compliant with customization form rules - if (UserRequestValidator.compliant(userTO, SyncopeEnduserApplication.get().getCustomForm(), true)) { + if (UserRequestValidator.compliant(userTO, + SyncopeEnduserApplication.get().getCustomFormAttributes(), true)) { // 1. membership attributes management Set<AttrTO> membAttrs = new HashSet<>(); http://git-wip-us.apache.org/repos/asf/syncope/blob/f9937e77/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfReadResource.java ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfReadResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfReadResource.java index 255449a..3e8e2ce 100644 --- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfReadResource.java +++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfReadResource.java @@ -97,7 +97,7 @@ public class UserSelfReadResource extends BaseUserSelfResource { membership.getVirAttrs().clear(); } // USER from customization, if empty or null ignore it, use it to filter attributes otherwise - applyFromCustomization(userTO, SyncopeEnduserApplication.get().getCustomForm()); + applyFromCustomization(userTO, SyncopeEnduserApplication.get().getCustomFormAttributes()); // 1.1 Date -> millis conversion for PLAIN attributes of USER for (PlainSchemaTO plainSchema : SyncopeEnduserSession.get().getDatePlainSchemas()) { @@ -127,26 +127,25 @@ public class UserSelfReadResource extends BaseUserSelfResource { return response; } - private void applyFromCustomization(final UserTO userTO, final Map<String, CustomAttributesInfo> customForm) { - if (customForm != null && !customForm.isEmpty()) { + private void applyFromCustomization(final UserTO userTO, + final Map<String, CustomAttributesInfo> customFormAttributes) { + if (customFormAttributes != null && !customFormAttributes.isEmpty()) { // filter PLAIN attributes - customizeAttrTOs(userTO.getPlainAttrs(), customForm.get(SchemaType.PLAIN.name())); + customizeAttrTOs(userTO.getPlainAttrs(), customFormAttributes.get(SchemaType.PLAIN.name())); // filter DERIVED attributes - customizeAttrTOs(userTO.getDerAttrs(), customForm.get(SchemaType.DERIVED.name())); + customizeAttrTOs(userTO.getDerAttrs(), customFormAttributes.get(SchemaType.DERIVED.name())); // filter VIRTUAL attributes - customizeAttrTOs(userTO.getVirAttrs(), customForm.get(SchemaType.VIRTUAL.name())); + customizeAttrTOs(userTO.getVirAttrs(), customFormAttributes.get(SchemaType.VIRTUAL.name())); } } private void customizeAttrTOs(final Set<AttrTO> attrs, final CustomAttributesInfo customAttributesInfo) { if (customAttributesInfo != null - && customAttributesInfo.isShow() && !customAttributesInfo.getAttributes().isEmpty()) { attrs.removeAll(attrs.stream(). filter(attr -> !customAttributesInfo.getAttributes().containsKey(attr.getSchema())). collect(Collectors.toList())); - } else if (customAttributesInfo != null && !customAttributesInfo.isShow()) { attrs.clear(); } } http://git-wip-us.apache.org/repos/asf/syncope/blob/f9937e77/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 26bad61..3cccb8f 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 @@ -66,10 +66,11 @@ public class UserSelfUpdateResource extends BaseUserSelfResource { } UserTO userTO = MAPPER.readValue(request.getReader().readLine(), UserTO.class); - Map<String, CustomAttributesInfo> customForm = SyncopeEnduserApplication.get().getCustomForm(); + Map<String, CustomAttributesInfo> customFormAttributes = + SyncopeEnduserApplication.get().getCustomFormAttributes(); // check if request is compliant with customization form rules - if (UserRequestValidator.compliant(userTO, customForm, false)) { + if (UserRequestValidator.compliant(userTO, customFormAttributes, false)) { // 1. membership attributes management Set<AttrTO> membAttrs = new HashSet<>(); userTO.getPlainAttrs().stream(). @@ -146,7 +147,7 @@ public class UserSelfUpdateResource extends BaseUserSelfResource { // get old user object from session UserTO selfTO = SyncopeEnduserSession.get().getSelfTO(); // align "userTO" and "selfTO" objects - if (customForm != null && !customForm.isEmpty()) { + if (customFormAttributes != null && !customFormAttributes.isEmpty()) { completeUserObject(userTO, selfTO); } // create diff patch http://git-wip-us.apache.org/repos/asf/syncope/blob/f9937e77/client/enduser/src/main/java/org/apache/syncope/client/enduser/util/UserRequestValidator.java ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/util/UserRequestValidator.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/util/UserRequestValidator.java index c5d348b..7772fcb 100644 --- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/util/UserRequestValidator.java +++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/util/UserRequestValidator.java @@ -19,8 +19,10 @@ package org.apache.syncope.client.enduser.util; import java.util.Map; +import org.apache.commons.lang3.StringUtils; import org.apache.syncope.client.enduser.model.CustomAttribute; import org.apache.syncope.client.enduser.model.CustomAttributesInfo; +import org.apache.syncope.client.enduser.model.CustomTemplateInfo; import org.apache.syncope.common.lib.EntityTOUtils; import org.apache.syncope.common.lib.to.AttrTO; import org.apache.syncope.common.lib.to.UserTO; @@ -35,26 +37,26 @@ public final class UserRequestValidator { private UserRequestValidator() { } - public static boolean compliant(final UserTO userTO, final Map<String, CustomAttributesInfo> customForm, + public static boolean compliant(final UserTO userTO, final Map<String, CustomAttributesInfo> customFormAttributes, final boolean checkDefaultValues) { - if (customForm == null || customForm.isEmpty()) { + if (customFormAttributes == null || customFormAttributes.isEmpty()) { return true; } return validateAttributes(EntityTOUtils.buildAttrMap(userTO.getPlainAttrs()), - customForm.get(SchemaType.PLAIN.name()), checkDefaultValues) + customFormAttributes.get(SchemaType.PLAIN.name()), checkDefaultValues) && validateAttributes(EntityTOUtils.buildAttrMap(userTO.getDerAttrs()), - customForm.get(SchemaType.DERIVED.name()), checkDefaultValues) + customFormAttributes.get(SchemaType.DERIVED.name()), checkDefaultValues) && validateAttributes(EntityTOUtils.buildAttrMap(userTO.getVirAttrs()), - customForm.get(SchemaType.VIRTUAL.name()), checkDefaultValues); + customFormAttributes.get(SchemaType.VIRTUAL.name()), checkDefaultValues); } private static boolean validateAttributes(final Map<String, AttrTO> attrMap, final CustomAttributesInfo customAttrInfo, final boolean checkDefaultValues) { return customAttrInfo == null - || (customAttrInfo.getAttributes().isEmpty() && customAttrInfo.isShow()) + || customAttrInfo.getAttributes().isEmpty() || attrMap.entrySet().stream().allMatch(entry -> { String schemaKey = entry.getKey(); AttrTO attrTO = entry.getValue(); @@ -69,6 +71,21 @@ public final class UserRequestValidator { } + public static boolean validateSteps(final CustomTemplateInfo customTemplateInfo) { + return customTemplateInfo != null + && StringUtils.isNotBlank(customTemplateInfo.getWizard().getFirstStep()) + && !customTemplateInfo.getWizard().getSteps().isEmpty(); + + } + + public static boolean validateStep(final String stepName, final CustomTemplateInfo customTemplateInfo) { + return customTemplateInfo != null + && !customTemplateInfo.getWizard().getSteps().isEmpty() + && customTemplateInfo.getWizard().getSteps().containsKey(stepName) + && StringUtils.isNotBlank(customTemplateInfo.getWizard().getSteps().get(stepName).getUrl()); + + } + private static boolean isValid(final AttrTO attrTO, final CustomAttribute customAttribute) { return customAttribute.isReadonly() ? attrTO.getValues().stream().allMatch(value -> customAttribute.getDefaultValues().contains(value)) http://git-wip-us.apache.org/repos/asf/syncope/blob/f9937e77/client/enduser/src/main/resources/META-INF/resources/app/css/app.css ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/resources/META-INF/resources/app/css/app.css b/client/enduser/src/main/resources/META-INF/resources/app/css/app.css index a91d764..494fb66 100644 --- a/client/enduser/src/main/resources/META-INF/resources/app/css/app.css +++ b/client/enduser/src/main/resources/META-INF/resources/app/css/app.css @@ -17,7 +17,8 @@ specific language governing permissions and limitations under the License. */ -/* app general css stylesheet */ +/* App general css stylesheet +============================================================================= */ .growl-container > .growl-item.ng-enter, .growl-container > .growl-item.ng-leave { @@ -27,73 +28,73 @@ under the License. transition:1s linear all; } -.k-notification-wrap{ - white-space: normal !important; - word-wrap: break-word !important; - font-size: 12px; - +.disable-link { + pointer-events: none; + cursor: default; } -.k-notification{ - width : 320px; - font-size: 12px; +.form-control:disabled, +.form-control[readonly] { + cursor: not-allowed; } -.suggestions{ - font-size: 10px; - display: inline-block; - margin-bottom: 5px; +.card-container.card { + width: 350px; + padding: 40px 40px 0px; } -#resetpassword{ - background: -moz-linear-gradient(top, #a9db80 0%, #96c56f 100%); /* FF3.6+ */ - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#a9db80), color-stop(100%,#96c56f)); /* Chrome,Safari4+ */ - background: -webkit-linear-gradient(top, #a9db80 0%,#96c56f 100%); /* Chrome10+,Safari5.1+ */ - background: -o-linear-gradient(top, #a9db80 0%,#96c56f 100%); /* Opera 11.10+ */ - background: -ms-linear-gradient(top, #a9db80 0%,#96c56f 100%); /* IE10+ */ - color: black; - margin-left: 5px; - /*width: 15%;*/ -} -#resetpassword:hover { - background: #658D5D; -} -#captchaImg{ - display: block; - margin: 0 auto; +.card { + background-color: #F7F7F7; + /* just in case there no content*/ + padding: 20px 25px 30px; + margin: 0 auto 25px; + margin-top: 50px; + /* shadows and rounded borders */ + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + border-radius: 2px; + -moz-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); + -webkit-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); + box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); } -.disable-link{ - pointer-events: none; - cursor: default; +.form-control { + display: block; + width: 100%; + height: 34px; + padding: 6px 12px; + font-size: 14px; + line-height: 1.42857; + color: #555; + background-color: #FFF; + /*background-image: none;*/ + border: 1px solid #CCC; + border-radius: 4px; + box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.075) inset; + transition: border-color 0.15s ease-in-out 0s, box-shadow 0.15s ease-in-out 0s; } -.treasure-overlay-spinner-container{ - z-index : 10001; +#captchaButtons { + margin-top: 5%; + margin-bottom: 10px; } -treasure-overlay-spinner .treasure-overlay-spinner-content { - height: 100%; -} -treasure-overlay-spinner { - height: 100%; - top: 0; - bottom: 0; - position: fixed; - right: 0; - left: 0; - overflow-y: auto; +/* <!-- Useless with Bootstrap > 3 */ +.p-0 { + padding-left: 0 !important; + padding-right: 0 !important; } -treasure-overlay-spinner .treasure-overlay-spinner { - position: fixed; +.float-left { + float: left !important; } - -treasure-overlay-spinner .treasure-overlay-spinner-container { - position: fixed; - background: rgba(0, 0, 0, 0.5490196078431373); +.float-right { + float: right !important; } -treasure-overlay-spinner.treasure-overlay-spinner-active-remove{ - transition: all 150ms ease-in 0s +.btn-default { + color: #333; + background-color: #fff; + border-color: #ccc; } +/* Useless with Bootstrap > 3 --> */ \ No newline at end of file http://git-wip-us.apache.org/repos/asf/syncope/blob/f9937e77/client/enduser/src/main/resources/META-INF/resources/app/css/customSpinner.css ---------------------------------------------------------------------- diff --git a/client/enduser/src/main/resources/META-INF/resources/app/css/customSpinner.css b/client/enduser/src/main/resources/META-INF/resources/app/css/customSpinner.css new file mode 100644 index 0000000..bbfe1de --- /dev/null +++ b/client/enduser/src/main/resources/META-INF/resources/app/css/customSpinner.css @@ -0,0 +1,49 @@ +/* +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. +*/ + +.treasure-overlay-spinner-container{ + z-index : 10001; +} + +treasure-overlay-spinner .treasure-overlay-spinner-content { + height: 100%; +} +treasure-overlay-spinner { + height: 100%; + top: 0; + bottom: 0; + position: fixed; + right: 0; + left: 0; + overflow-y: auto; +} + +treasure-overlay-spinner .treasure-overlay-spinner { + position: fixed; + pointer-events: none; +} + +treasure-overlay-spinner .treasure-overlay-spinner-container { + position: fixed; + background: rgba(0, 0, 0, 0.5490196078431373); +} + +treasure-overlay-spinner.treasure-overlay-spinner-active-remove { + transition: all 150ms ease-in 0s; +} \ No newline at end of file