You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by an...@apache.org on 2015/10/30 10:34:02 UTC
[2/4] syncope git commit: SYNCOPE-701 first working implementation
http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/img/ajax-loader.gif
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/img/ajax-loader.gif b/client/enduser/src/main/resources/META-INF/resources/app/img/ajax-loader.gif
new file mode 100644
index 0000000..766cf24
Binary files /dev/null and b/client/enduser/src/main/resources/META-INF/resources/app/img/ajax-loader.gif differ
http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/img/busy.gif
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/img/busy.gif b/client/enduser/src/main/resources/META-INF/resources/app/img/busy.gif
new file mode 100644
index 0000000..e77264f
Binary files /dev/null and b/client/enduser/src/main/resources/META-INF/resources/app/img/busy.gif differ
http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/img/favicon.png
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/img/favicon.png b/client/enduser/src/main/resources/META-INF/resources/app/img/favicon.png
new file mode 100644
index 0000000..aa2f3e2
Binary files /dev/null and b/client/enduser/src/main/resources/META-INF/resources/app/img/favicon.png differ
http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/img/logo-green.png
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/img/logo-green.png b/client/enduser/src/main/resources/META-INF/resources/app/img/logo-green.png
new file mode 100644
index 0000000..c57b86c
Binary files /dev/null and b/client/enduser/src/main/resources/META-INF/resources/app/img/logo-green.png differ
http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/img/logo.png
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/img/logo.png b/client/enduser/src/main/resources/META-INF/resources/app/img/logo.png
new file mode 100644
index 0000000..f05105e
Binary files /dev/null and b/client/enduser/src/main/resources/META-INF/resources/app/img/logo.png differ
http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/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
new file mode 100644
index 0000000..6cb7ae6
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/index.html
@@ -0,0 +1,116 @@
+<!--
+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.
+-->
+
+<!DOCTYPE html>
+<!--[if lt IE 7]> <html lang="en" ng-app="myApp" class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
+<!--[if IE 7]> <html lang="en" ng-app="myApp" class="no-js lt-ie9 lt-ie8"> <![endif]-->
+<!--[if IE 8]> <html lang="en" ng-app="myApp" class="no-js lt-ie9"> <![endif]-->
+<!--[if gt IE 8]><!--> <html lang="en" ng-app="SyncopeEnduserApp" class="no-js"> <!--<![endif]-->
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <title>SyncopeEnduserApp</title>
+ <meta name="description" content="">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <!--<link rel="stylesheet" href="bower_components/html5-boilerplate/dist/css/normalize.css">-->
+ <!--<link rel="stylesheet" href="bower_components/html5-boilerplate/dist/css/main.css">-->
+ <link rel="stylesheet" href="css/app.css">
+ <!--<script src="bower_components/html5-boilerplate/dist/js/vendor/modernizr-2.8.3.min.js"></script>-->
+ </head>
+ <body ng-cloak >
+ <!--<button ng-click=""-->
+
+ <!--[if lt IE 7]>
+ <p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
+ <![endif]-->
+
+ <!--<div ng-view ng-cloak ng-controller="ApplicationController"></div>-->
+ <div ui-view ng-cloak ng-controller="ApplicationController"></div>
+
+ <!-- <footer id="footer" class="hidden-print">
+ <ul class="nav pull-right">
+ <li>
+ Copyright © 2015, Apache Syncope
+ </li>
+ </ul>
+ </footer>-->
+
+ <!--default global growl message-->
+ <!--<div growl></div>-->
+
+ <!-- <div class="hidden-print" id="initialLoaderDiv">
+ <img src="img/ajax-loader.gif" class="ajax-loader"/>
+ </div>-->
+
+ <!-- In production use:
+ <script src="//ajax.googleapis.com/ajax/libs/angularjs/x.x.x/angular.min.js"></script>
+ -->
+ <script type="text/javascript" src="../webjars/jquery/${jquery.version}/jquery.js"></script>
+ <script src="../webjars/angular/${angular.version}/angular.js"></script>
+ <script src="../webjars/angular-ui-router/${angular-ui-router.version}/angular-ui-router.js"></script>
+ <script src="../webjars/angular-animate/${angular-animate.version}/angular-animate.js"></script>
+ <script src="../webjars/angular-resource/${angular-resource.version}/angular-resource.js"></script>
+ <script src="../webjars/angular-cookies/${angular-cookies.version}/angular-cookies.js"></script>
+ <script src="../webjars/angular-sanitize/${angular-sanitize.version}/angular-sanitize.js"></script>
+ <script src="../webjars/angular-ui-bootstrap/${angular-ui-bootstrap.version}/ui-bootstrap-tpls.js"></script>
+ <script src="../webjars/angular-ui-select/${angular-ui-select.version}/select.js"></script>
+ <script src="../webjars/angular-growl-2/${angular-growl-2.version}/angular-growl.js"></script>
+ <script type="text/javascript" src="../webjars/bootstrap-select/${bootstrap-select.version}/js/bootstrap-select.min.js"></script>
+ <script src="../webjars/FileSaver.js/${FileSaver.version}/FileSaver.js" type="text/javascript"></script>
+ <!--main angular application-->
+ <script src="js/app.js"></script>
+ <!--services-->
+ <script src="js/services/authService.js"></script>
+ <script src="js/services/userSelfService.js"></script>
+ <script src="js/services/schemaService.js"></script>
+ <script src="js/services/realmService.js"></script>
+ <script src="js/services/securityQuestionService.js"></script>
+ <!--controllers-->
+ <script src="js/controllers/HomeController.js"></script>
+ <script src="js/controllers/LoginController.js"></script>
+ <script src="js/controllers/LanguageController.js"></script>
+ <script src="js/controllers/UserController.js"></script>
+ <!--directives-->
+ <script src="js/directives/dynamicAttribute.js"></script>
+ <script src="js/directives/dynamicPlainAttributes.js"></script>
+ <script src="js/directives/dynamicDerivedAttributes.js"></script>
+ <script src="js/directives/dynamicVirtualAttributes.js"></script>
+ <script src="js/directives/navigationButtons.js"></script>
+ <script src="js/directives/loader.js"></script>
+ <script src="js/directives/equals.js"></script>
+ <!--filters-->
+ <script src="js/filters/propsFilter.js"></script>
+
+
+ <link rel="shortcut icon" href="img/favicon.png" type="image/png"/>
+ <link href="css/login.css" rel="stylesheet" type="text/css" />
+ <link href="../webjars/jquery-ui/${jquery-ui.version}/jquery-ui.css" rel="stylesheet" type="text/css" />
+ <link href="../webjars/bootstrap/${bootstrap.version}/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
+ <link href="../webjars/bootstrap-select/${bootstrap-select.version}/css/bootstrap-select.min.css" rel="stylesheet" type="text/css" />
+ <link href="../webjars/font-awesome/${font-awesome.version}/css/font-awesome.min.css" rel="stylesheet" type="text/css" />
+ <link href="../webjars/ionicons/${ionicons.version}/css/ionicons.min.css" rel="stylesheet" type="text/css" />
+ <link href="../webjars/angular-ui-select/${angular-ui-select.version}/select.css" rel="stylesheet" type="text/css"/>
+ <link href="../webjars/angular-growl-2/${angular-growl-2.version}/angular-growl.css" rel="stylesheet" type="text/css"/>
+ <link href="../webjars/select2/${select2.version}/select2.css" rel="stylesheet" type="text/css"/>
+ <link href="css/app.css" rel="stylesheet" type="text/css" />
+ <link href="css/login.css" rel="stylesheet" type="text/css" />
+ <link href="css/editUser.css" rel="stylesheet" type="text/css" />
+
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/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
new file mode 100644
index 0000000..1a53f00
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/app.js
@@ -0,0 +1,283 @@
+/**
+ 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('home', []);
+angular.module('login', []);
+angular.module('language', []);
+angular.module('self', []);
+
+// Declare app level module which depends on views, and components
+var app = angular.module('SyncopeEnduserApp', [
+ 'ui.router',
+ 'ui.bootstrap',
+ 'ui.select',
+ 'ngSanitize',
+ 'ngAnimate',
+ 'ngResource',
+ 'ngCookies',
+ 'angular-growl',
+ 'home',
+ 'login',
+ 'language',
+ 'self'
+]);
+
+app.config(['$stateProvider', '$urlRouterProvider', '$httpProvider', 'growlProvider',
+ function ($stateProvider, $urlRouterProvider, $httpProvider, growlProvider) {
+ // route configuration
+ $stateProvider
+ .state('home', {
+ url: '/',
+ templateUrl: 'views/self.html'
+ })
+ .state('self', {
+ url: '/self',
+ templateUrl: 'views/self.html'
+ })
+ .state('user-self-update', {
+ url: '/user-self-update',
+ templateUrl: 'views/home.html',
+ controller: 'HomeController',
+ resolve: {
+ 'authenticated': function (AuthenticationHelper) {
+ return AuthenticationHelper.authenticated();
+ }
+ }
+ })
+ .state('create', {
+ url: '/self/create',
+ templateUrl: 'views/editUser.html'
+ })
+ // nested states
+ // each of these sections will have their own view
+ // url will be nested (/self/create)
+ .state('create.credentials', {
+ url: '/credentials',
+ templateUrl: 'views/user-credentials.html'
+ })
+ .state('create.plainSchemas', {
+ url: '/plainSchemas',
+ templateUrl: 'views/user-plain-schemas.html'
+ })
+ .state('create.derivedSchemas', {
+ url: '/derivedSchemas',
+ templateUrl: 'views/user-derived-schemas.html'
+ })
+ .state('create.virtualSchemas', {
+ url: '/virtualSchemas',
+ templateUrl: 'views/user-virtual-schemas.html'
+ })
+ // url will be /self/create/schema
+ .state('create.groups', {
+ url: '/groups',
+ templateUrl: 'views/user-groups.html'
+ })
+ .state('create.resources', {
+ url: '/resources',
+ templateUrl: 'views/user-resources.html'
+ })
+ .state('update', {
+ url: '/self/update',
+ templateUrl: 'views/editUser.html',
+ resolve: {
+ 'authenticated': function (AuthenticationHelper) {
+ return AuthenticationHelper.authenticated();
+ }
+ }
+ })
+ // nested states
+ // each of these sections will have their own view
+ // url will be nested (/self/create)
+ .state('update.credentials', {
+ url: '/credentials',
+ templateUrl: 'views/user-credentials.html',
+ resolve: {
+ 'authenticated': function (AuthenticationHelper) {
+ return AuthenticationHelper.authenticated();
+ }
+ }
+ })
+ .state('update.plainSchemas', {
+ url: '/plainSchemas',
+ templateUrl: 'views/user-plain-schemas.html',
+ resolve: {
+ 'authenticated': function (AuthenticationHelper) {
+ return AuthenticationHelper.authenticated();
+ }
+ }
+ })
+ .state('update.derivedSchemas', {
+ url: '/derivedSchemas',
+ templateUrl: 'views/user-derived-schemas.html',
+ resolve: {
+ 'authenticated': function (AuthenticationHelper) {
+ return AuthenticationHelper.authenticated();
+ }
+ }
+ })
+ .state('update.virtualSchemas', {
+ url: '/virtualSchemas',
+ templateUrl: 'views/user-virtual-schemas.html',
+ resolve: {
+ 'authenticated': function (AuthenticationHelper) {
+ return AuthenticationHelper.authenticated();
+ }
+ }
+ })
+ // url will be /self/create/schema
+ .state('update.groups', {
+ url: '/groups',
+ templateUrl: 'views/user-groups.html',
+ resolve: {
+ 'authenticated': function (AuthenticationHelper) {
+ return AuthenticationHelper.authenticated();
+ }
+ }
+ })
+ .state('update.resources', {
+ url: '/resources',
+ templateUrl: 'views/user-resources.html',
+ resolve: {
+ 'authenticated': function (AuthenticationHelper) {
+ return AuthenticationHelper.authenticated();
+ }
+ }
+ });
+
+ // catch all other routes
+ // send users to the home page
+ $urlRouterProvider.otherwise('/');
+
+ // HTTP service configuration
+ $httpProvider.defaults.withCredentials = true;
+
+ $httpProvider.interceptors.push(function ($q, $rootScope, $location) {
+ var numLoadings = 0;
+ return {
+// 'request': function (config) {
+// numLoadings++;
+// // Show loader
+// if (config.url.indexOf("skipLoader=true") == -1) {
+// $rootScope.$broadcast("loader_show");
+// }
+// return config || $q.when(config);
+// },
+// 'response': function (response) {
+// if ((--numLoadings) === 0) {
+// // Hide loader
+// $rootScope.$broadcast("loader_hide");
+// }
+// return response || $q.when(response);
+// },
+ 'responseError': function (response) {
+ if (response.config.url.indexOf("acceptError=true") == -1) {
+ var status = response.status;
+ if (status == 401) {
+ console.log("ERROR " + status);
+// $location.path("/self");
+ }
+ if (status == 403) {
+ console.log("UNAUTHORIZED " + status);
+// $location.path("/self");
+ }
+ if (status == 400 || status == 404 || status == 412 || status == 500) {
+// if (response.data.validationErrors != undefined) {
+// for (var i in response.data.validationErrors) {
+// $rootScope.$broadcast('growlMessage', {text: response.data.validationErrors[i] || '', severity: 'error'});
+// }
+// } else if (response.data.message != undefined) {
+// $rootScope.$broadcast('growlMessage', {text: response.data.message || '', severity: 'error'})
+// }
+ console.log("GENERIC ERROR " + status);
+ }
+ }
+ return $q.reject(response);
+ }
+ };
+ });
+
+ growlProvider.globalTimeToLive(10000);
+ growlProvider.globalPosition('bottom-left');
+ growlProvider.globalInlineMessages(true);
+ growlProvider.globalDisableIcons(true);
+ //to enable html in growl
+// growlProvider.globalEnableHtml(true);
+ }]);
+
+app.run(['$rootScope', '$location', '$cookies', '$state',
+ function ($rootScope, $location, $cookies, $state) {
+ // main program
+ // keep user logged in after page refresh
+ // check if user is logged or not
+ $rootScope.currentUser = $cookies.get('currentUser') || null;
+//If the route change failed due to authentication error, redirect them out
+ $rootScope.$on('$routeChangeError', function (event, current, previous, rejection) {
+ if (rejection === 'Not Authenticated') {
+ $location.path('/self');
+ }
+ });
+
+// $rootScope.$on('success', function (event, args) {
+// console.log("IN CONFIG EVENTO: ", event);
+// $rootScope.$broadcast("error", "success");
+// });
+
+ $rootScope.$on('$stateChangeSuccess', function (event, toState) {
+ if (toState.name === 'create') {
+ $state.go('create.credentials');
+ } else if (toState.name === 'update') {
+ $state.go('update.credentials');
+ }
+ });
+// $rootScope.$on('$locationChangeStart', function (event, next, current) {
+// // redirect to login page if not logged in
+// if ($location.path() !== '/self' && !$rootScope.globals.currentUser) {
+// $location.path('/self');
+// }
+// });
+ }]);
+
+app.controller('ApplicationController', function ($scope) {
+// DO NOTHING
+// $scope.$on('success', function (event, args) {
+// console.log("IN CONFIG EVENTO: ", event)
+// $scope.$broadcast("error", "success");
+// });
+});
+
+app.factory('AuthenticationHelper', ['$q', '$rootScope',
+ function ($q, $rootScope) {
+ return {
+ authenticated: function () {
+
+ var currentUser = $rootScope.currentUser;
+
+ console.log("AuthenticationHelper, currentUser: ", currentUser);
+
+ if (angular.isDefined(currentUser) && currentUser) {
+ return true;
+ } else {
+ console.log("NOT AUTHENTICATED, REDIRECT TO LOGIN PAGE");
+ return $q.reject('Not Authenticated');
+ }
+ }
+ };
+ }]);
http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/HomeController.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/HomeController.js b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/HomeController.js
new file mode 100644
index 0000000..bf86413
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/HomeController.js
@@ -0,0 +1,39 @@
+/**
+ 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("home").controller("HomeController", ['$scope', '$http', '$location', function ($scope, $http, $location) {
+ $scope.title = 'Hello world!';
+ $scope.subtitle = 'Hello world SUBTITLE!';
+ $scope.name = "";
+
+// check if user is logged or not, check session variables: if user isn't logged redirect to login page
+
+ console.log("SONO IN HomeController");
+
+// var isLogged = false;
+// if (!isLogged) {
+// console.log("REDIRECT TO LOGIN PAGE");
+//// window.location = "./self.html";
+// $location.path("/self");
+// }
+
+
+ }]);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LanguageController.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LanguageController.js b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LanguageController.js
new file mode 100644
index 0000000..9e1fa6c
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LanguageController.js
@@ -0,0 +1,66 @@
+/*
+ * 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('language')
+ .controller('LanguageController', function ($scope) {
+
+ $scope.languages = {
+ availableLanguages: [
+ {id: '1', name: 'Italiano'},
+ {id: '2', name: 'English'},
+ {id: '3', name: 'Portugese'}
+ ],
+ selectedLanguage: {id: '2', name: 'English'}
+ };
+
+ $scope.init = function () {
+// MainService.settings().then(function (response) {
+// $scope.mainSettings = response;
+// });
+
+ console.log("Init language controller");
+ };
+
+ $scope.changeLanguage = function (language) {
+
+ console.log("Language changed to: ", language);
+
+ $scope.languages.selectedLanguage = language;
+
+// $translate.use(langKey);
+// LanguageService.switchLocale.query({language: langKey}, {}, function (response) {
+// $scope.selectedLanguage.locale = langKey;
+// });
+ };
+
+ this.retrieveLanguages = function () {
+// LanguageService.language.query({}, function (response) {
+// $scope.languages = response;
+// });
+ console.log("Retriebìving available languages");
+ };
+
+
+ this.retrieveLanguages();
+
+
+ });
+
http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LoginController.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LoginController.js b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LoginController.js
new file mode 100644
index 0000000..c962571
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LoginController.js
@@ -0,0 +1,93 @@
+/*
+ * 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("login").controller("LoginController", ['$scope', '$rootScope', '$http', '$location', '$cookies',
+ 'AuthService', 'growl', function ($scope, $rootScope, $http, $location, $cookies, AuthService, growl) {
+
+ $scope.credentials = {
+ username: '',
+ password: '',
+ errorMessage: ''
+ };
+
+ $scope.login = function (credentials) {
+
+ console.log("CREDENTIALS FROM PAGE: ", credentials);
+ console.log("AUTHSERVICE: ", AuthService);
+
+ AuthService.login($scope.credentials).then(function (user) {
+ console.log("LOGIN SUCCESS FOR: ", user);
+ console.log("DOPO AVER SETTATO CURRENT USER: ", $rootScope.currentUser);
+ console.log("COOKIE CURRENT USER: ", $cookies.get('currentUser'));
+ // reset error message
+ $scope.credentials.errorMessage = '';
+ // got to update page
+ $location.path("/self/update");
+ }, function (response) {
+ console.log("LOGIN FAILED: ", response);
+ $scope.credentials.errorMessage = "Login failed: " + response;
+ growl.error($scope.credentials.errorMessage, {referenceId: 1});
+ });
+ };
+
+ $scope.logout = function () {
+
+ console.log("PERFORMING LOGOUT");
+
+ AuthService.logout().then(function (response) {
+ console.log("LOGOUT SUCCESS: ", response);
+ }, function () {
+ console.log("LOGOUT FAILED");
+ });
+ };
+
+ $scope.isLogged = function () {
+ return angular.isDefined($rootScope.currentUser) && $rootScope.currentUser;
+ };
+
+ $scope.selfCreate = function () {
+ $location.path("/self/create");
+ };
+
+ $scope.passwordReset = function () {
+ // TODO
+ console.log("NOT YET IMPLEMENTED")
+ };
+
+ $scope.errorAPI = function () {
+ $http.get("/syncope-enduser/api/error").success(function (data) {
+ console.log("errorAPI response: ", data);
+ });
+ };
+
+ $scope.sampleAPI = function () {
+ $http.get("/syncope-enduser/api/user-self").success(function (data) {
+ console.log("sampleAPI response: ", data);
+ });
+ };
+
+ $scope.schemaAPI = function () {
+ $http.get("/syncope-enduser/api/schema").success(function (data) {
+ console.log("schemaAPI response: ", data);
+ });
+ };
+
+ }]);
http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/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
new file mode 100644
index 0000000..892de21
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js
@@ -0,0 +1,206 @@
+/*
+ * 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").controller("UserController", ['$scope', '$rootScope', '$location', 'AuthService',
+ 'UserSelfService', 'SchemaService', 'RealmService', 'SecurityQuestionService', 'growl', function ($scope, $rootScope,
+ $location, AuthService, UserSelfService, SchemaService, RealmService, SecurityQuestionService, growl) {
+
+ $scope.user = {};
+ $scope.confirmPassword = {
+ value: ''
+ };
+ $scope.userFormValid = false;
+ $scope.createMode = $location.path().indexOf("/self/create") > -1;
+
+ $scope.availableRealms = [];
+ $scope.availableSecurityQuestions = [];
+
+ $scope.initialSecurityQuestion = undefined;
+
+ $scope.initUser = function () {
+
+ $scope.dynamicForm = {
+ plainSchemas: [],
+ derSchemas: [],
+ virSchemas: [],
+ selectedDerSchemas: [],
+ selectedVirSchemas: [],
+ errorMessage: '',
+ attributeTable: {}
+ };
+
+
+ var initSchemas = function () {
+ // initialization is done here synchronously to have all schema fields populated correctly
+ SchemaService.getUserSchemas().then(function (schemas) {
+ $scope.dynamicForm.plainSchemas = schemas.plainSchemas;
+ $scope.dynamicForm.derSchemas = schemas.derSchemas;
+ $scope.dynamicForm.virSchemas = schemas.virSchemas;
+
+ // initialize plain attributes
+ for (var i = 0; i < schemas.plainSchemas.length; i++) {
+
+ var plainSchemaKey = schemas.plainSchemas[i].key;
+
+ if (!$scope.user.plainAttrs[plainSchemaKey]) {
+
+ $scope.user.plainAttrs[plainSchemaKey] = {
+ schema: plainSchemaKey,
+ values: [],
+ readonly: schemas.plainSchemas[i].readonly
+ };
+
+ // 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]
+ };
+ }
+ } else {
+ // initialize multivalue schema and support table: update mode, all provided values
+ if (schemas.plainSchemas[i].multivalue) {
+ $scope.dynamicForm.attributeTable[schemas.plainSchemas[i].key] = {
+ fields: [schemas.plainSchemas[i].key + "_" + 0]
+ };
+ // add other values
+ for (var j = 1; j < $scope.user.plainAttrs[plainSchemaKey].values.length; j++) {
+ $scope.dynamicForm.attributeTable[schemas.plainSchemas[i].key].fields.push(schemas.plainSchemas[i].key + "_" + j);
+ }
+ }
+ }
+ }
+
+ // initialize derived attributes
+ for (var i = 0; i < schemas.derSchemas.length; i++) {
+
+ var derSchemaKey = schemas.derSchemas[i].key;
+
+ if ($scope.user.derAttrs[derSchemaKey]) {
+ $scope.dynamicForm.selectedDerSchemas.push(schemas.derSchemas[i]);
+ }
+ }
+
+ // initialize virtual attributes
+ for (var i = 0; i < schemas.virSchemas.length; i++) {
+
+ var virSchemaKey = schemas.virSchemas[i].key;
+
+ if ($scope.user.virAttrs[virSchemaKey]) {
+ $scope.dynamicForm.selectedVirSchemas.push(schemas.virSchemas[i]);
+ }
+ }
+
+ }, function () {
+ console.log("Error retrieving user schemas");
+ });
+ console.log("USER WITH ATTRTO: ", $scope.user);
+
+ };
+
+ var initSecurityQuestions = function () {
+ SecurityQuestionService.getAvailableSecurityQuestions().then(function (response) {
+ $scope.availableSecurityQuestions = response;
+ }, function () {
+ console.log("Error");
+ });
+ };
+
+ var initRealms = function () {
+ $scope.availableRealms = RealmService.getAvailableRealmsStub();
+ };
+
+ var initUserRealm = function () {
+ $scope.user.realm = RealmService.getUserRealm();
+ };
+
+
+ var readUser = function () {
+ UserSelfService.read().then(function (response) {
+ $scope.user = response;
+ $scope.user.password = undefined;
+ $scope.initialSecurityQuestion = $scope.user.securityQuestion;
+ }, function () {
+ console.log("Error");
+ });
+ };
+
+ if ($scope.createMode) {
+
+ $scope.user = {
+ username: '',
+ password: '',
+ realm: '',
+ securityQuestion: undefined,
+ securityAnswer: '',
+ plainAttrs: {},
+ derAttrs: {},
+ virAttrs: {}
+ };
+
+ // retrieve user realm or all available realms
+ initUserRealm();
+
+ } else {
+
+ // read user from syncope core
+ readUser();
+ // read user security question
+
+ }
+
+ initRealms();
+ //retrieve security available questions
+ initSecurityQuestions();
+ // initialize user attributes starting from any object schemas
+ initSchemas();
+
+ };
+
+ $scope.saveUser = function (user) {
+ console.log("Save user: ", user);
+
+ if ($scope.createMode) {
+
+ UserSelfService.create(user).then(function (response) {
+ console.log("Created user: ", response);
+ growl.success("User " + $scope.user.username + " successfully created", {referenceId: 1});
+ $location.path('/self');
+ }, function (response) {
+ console.log("Error during user creation: ", response);
+ growl.error("Error: " + response, {referenceId: 2});
+ });
+
+ } else {
+
+ UserSelfService.update(user).then(function (response) {
+ console.log("Updated user: ", response);
+ growl.success("User " + $scope.user.username + " successfully updated", {referenceId: 1});
+ $location.path('/self');
+ }, function (response) {
+ console.log("Error during user update: ", response);
+ growl.error("Error: " + response, {referenceId: 2});
+ });
+ }
+ };
+
+
+
+ }]);
http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicAttribute.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicAttribute.js b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicAttribute.js
new file mode 100644
index 0000000..6a00507
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicAttribute.js
@@ -0,0 +1,190 @@
+/*
+ * 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')
+ .directive('dynamicAttribute', function ($filter) {
+ return {
+ restrict: 'E',
+ templateUrl: 'views/dynamicAttribute.html',
+ scope: {
+ schema: "=",
+ index: "=",
+ user: "="
+ },
+ controller: function ($scope, $element, $window) {
+ $scope.initAttribute = function (schema, index) {
+
+ switch (schema.type) {
+ case "Long":
+ case "Double":
+ $scope.user.plainAttrs[schema.key].values[index] = Number($scope.user.plainAttrs[schema.key].values[index])
+ || undefined;
+ break;
+ case "Enum":
+ $scope.enumerationValues = [];
+ var enumerationValuesSplitted = schema.enumerationValues.toString().split(";");
+ for (var i = 0; i < enumerationValuesSplitted.length; i++) {
+ $scope.enumerationValues.push(enumerationValuesSplitted[i]);
+ }
+ $scope.user.plainAttrs[schema.key].values[index] = $scope.user.plainAttrs[schema.key].values[index]
+ || $scope.enumerationValues[0];
+ break;
+ case "Binary":
+
+ $scope.userFile = $scope.userFile || '';
+ //for multivalue fields
+// $scope.fileInputId = "fileInputId_" + index;
+
+ $element.bind("change", function (changeEvent) {
+ $scope.$apply(function () {
+ var reader = new FileReader();
+ var file = changeEvent.target.files[0];
+ $scope.userFile = file.name;
+ reader.onload = function (readerEvt) {
+ var binaryString = readerEvt.target.result;
+ $scope.user.plainAttrs[schema.key].values[index] = btoa(binaryString);
+ };
+ reader.readAsBinaryString(file);
+ });
+ });
+
+ $scope.download = function () {
+ var byteString = atob($scope.user.plainAttrs[schema.key].values[index]);
+
+ var ab = new ArrayBuffer(byteString.length);
+ var ia = new Uint8Array(ab);
+ for (var i = 0; i < byteString.length; i++) {
+ ia[i] = byteString.charCodeAt(i);
+ }
+
+ var blob = new Blob([ia], {type: schema.mimeType});
+
+ saveAs(blob, schema.key);
+ };
+ $scope.remove = function () {
+ $scope.user.plainAttrs[schema.key].values.splice(index, 1);
+ $scope.userFile = '';
+ $("#fileInput").replaceWith($("#fileInput").clone(true));
+ };
+ break;
+ case "Date":
+
+ $scope.selectedDate = $scope.user.plainAttrs[schema.key].values[index];
+ $scope.format = $scope.schema.conversionPattern;
+ $scope.includeTimezone = false;
+ if ($scope.schema.conversionPattern.indexOf(".SSS") > -1) {
+ $scope.format = $scope.format.replace(".SSS", ".sss");
+ }
+ if ($scope.schema.conversionPattern.indexOf("Z") > -1) {
+ $scope.includeTimezone = true;
+ $scope.format = $scope.format.replace("Z", "");
+ }
+ if ($scope.schema.conversionPattern.indexOf("\'") > -1) {
+ $scope.format = $scope.format.replace(new RegExp("\'", "g"), "");
+ }
+
+ $scope.bindDateToModel = function (selectedDate, format) {
+ var newFormat = $scope.includeTimezone ? format.concat(" Z") : format;
+ if (selectedDate) {
+ selectedDate = $filter('date')(selectedDate, newFormat);
+ var dateGood = selectedDate.toString();
+ $scope.user.plainAttrs[schema.key].values[index] = dateGood;
+ } else {
+ $scope.user.plainAttrs[schema.key].values[index] = selectedDate;
+ }
+ };
+
+ $scope.clear = function () {
+ $scope.user.plainAttrs[schema.key].values[index] = null;
+ };
+
+ // Disable weekend selection
+ $scope.disabled = function (date, mode) {
+ // example if you want to disable weekends
+ // return (mode === 'day' && (date.getDay() === 0 || date.getDay() === 6));
+ return false;
+ };
+
+ $scope.toggleMin = function () {
+ $scope.minDate = $scope.minDate ? null : new Date();
+ };
+
+ $scope.maxDate = new Date(2050, 5, 22);
+
+ $scope.open = function ($event) {
+ $scope.status.opened = true;
+ };
+
+ $scope.setDate = function (year, month, day) {
+ $scope.user.plainAttrs[schema.key].values[index] = new Date(year, month, day);
+ };
+
+ $scope.dateOptions = {
+ startingDay: 1
+ };
+
+ $scope.status = {
+ opened: false
+ };
+
+ var tomorrow = new Date();
+ tomorrow.setDate(tomorrow.getDate() + 1);
+ var afterTomorrow = new Date();
+ afterTomorrow.setDate(tomorrow.getDate() + 2);
+ $scope.events =
+ [
+ {
+ date: tomorrow,
+ status: 'full'
+ },
+ {
+ date: afterTomorrow,
+ status: 'partially'
+ }
+ ];
+
+ $scope.getDayClass = function (date, mode) {
+ if (mode === 'day') {
+ var dayToCheck = new Date(date).setHours(0, 0, 0, 0);
+
+ for (var i = 0; i < $scope.events.length; i++) {
+ var currentDay = new Date($scope.events[i].date).setHours(0, 0, 0, 0);
+
+ if (dayToCheck === currentDay) {
+ return $scope.events[i].status;
+ }
+ }
+ }
+
+ };
+ break;
+
+ case "Boolean":
+ $scope.user.plainAttrs[schema.key].values[index] =
+ Boolean($scope.user.plainAttrs[schema.key].values[index]) || false;
+ break;
+
+ }
+ }
+ ;
+ },
+ replace: true
+ };
+ });
http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicDerivedAttributes.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicDerivedAttributes.js b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicDerivedAttributes.js
new file mode 100644
index 0000000..887b5c6
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicDerivedAttributes.js
@@ -0,0 +1,52 @@
+/*
+ * 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')
+ .directive('dynamicDerivedAttributes', function () {
+ return {
+ restrict: 'E',
+ templateUrl: 'views/dynamicDerivedAttributes.html',
+ scope: {
+ dynamicForm: "=form",
+ user: "="
+ },
+ controller: function ($scope) {
+
+ $scope.addDerivedAttribute = function (item, model) {
+ var derSchemaKey = item.key;
+ console.log("ADDING DERIVED item: ", derSchemaKey);
+ $scope.user.derAttrs[derSchemaKey] = {
+ schema: derSchemaKey,
+ values: [],
+ readonly: false
+ };
+
+ };
+
+ $scope.removeDerivedAttribute = function (item, model) {
+ var derSchemaKey = item.key;
+ console.log("REMOVING DERIVED item: ", derSchemaKey);
+ delete $scope.user.derAttrs[derSchemaKey];
+
+ };
+
+ }
+ };
+ });
http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicPlainAttributes.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicPlainAttributes.js b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicPlainAttributes.js
new file mode 100644
index 0000000..1a0a4c3
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicPlainAttributes.js
@@ -0,0 +1,45 @@
+/*
+ * 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')
+ .directive('dynamicPlainAttributes', function (SchemaService) {
+ return {
+ restrict: 'E',
+ templateUrl: 'views/dynamicPlainAttributes.html',
+ scope: {
+ dynamicForm: "=form",
+ user: "="
+ },
+ controller: function ($scope) {
+
+ $scope.addAttributeField = function (plainSchemaKey) {
+ console.log("ADDING: ", plainSchemaKey + "_" + ($scope.dynamicForm.attributeTable[plainSchemaKey].fields.length));
+ $scope.dynamicForm.attributeTable[plainSchemaKey].fields.push(plainSchemaKey + "_" + ($scope.dynamicForm.attributeTable[plainSchemaKey].fields.length));
+ };
+
+ $scope.removeAttributeField = function (plainSchemaKey, index) {
+ console.log("REMOVING FROM: " + plainSchemaKey + " ATTRIBUTE INDEX: " + index);
+ $scope.dynamicForm.attributeTable[plainSchemaKey].fields.splice(index, 1);
+ // clean user model
+ $scope.user.plainAttrs[plainSchemaKey].values.splice(index, 1);
+ };
+ }
+ };
+ });
http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicVirtualAttributes.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicVirtualAttributes.js b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicVirtualAttributes.js
new file mode 100644
index 0000000..62c1591
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicVirtualAttributes.js
@@ -0,0 +1,52 @@
+/*
+ * 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')
+ .directive('dynamicVirtualAttributes', function () {
+ return {
+ restrict: 'E',
+ templateUrl: 'views/dynamicVirtualAttributes.html',
+ scope: {
+ dynamicForm: "=form",
+ user: "="
+ },
+ controller: function ($scope) {
+
+ $scope.addVirtualAttribute = function (item, model) {
+ var virSchemaKey = item.key;
+ console.log("ADDING VIRTUAL item: ", virSchemaKey);
+ $scope.user.virAttrs[virSchemaKey] = {
+ schema: virSchemaKey,
+ values: [],
+ readonly: false
+ };
+
+ };
+
+ $scope.removeVirtualAttribute = function (item, model) {
+ var virSchemaKey = item.key;
+ console.log("REMOVING VIRTUAL item: ", virSchemaKey);
+ delete $scope.user.virAttrs[virSchemaKey];
+
+ };
+
+ }
+ };
+ });
http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/directives/equals.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/directives/equals.js b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/equals.js
new file mode 100644
index 0000000..54c2022
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/equals.js
@@ -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.
+ */
+
+angular.module('self')
+ .directive('equals', function () {
+ return {
+ restrict: 'A',
+ require: '?ngModel',
+ link: function (scope, elem, attrs, ngModel) {
+ if (!ngModel)
+ return; // do nothing if no ng-model
+
+ // watch own value and re-validate on change
+ scope.$watch(attrs.ngModel, function () {
+ validate();
+ });
+
+ // observe the other value and re-validate on change
+ attrs.$observe('equals', function (val) {
+ validate();
+ });
+
+ var validate = function () {
+ // values
+ var val1 = ngModel.$viewValue;
+ var val2 = attrs.equals;
+
+ // set validity
+ ngModel.$setValidity('equals', !val1 || !val2 || val1 === val2);
+ };
+ }
+ };
+ });
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/directives/loader.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/directives/loader.js b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/loader.js
new file mode 100644
index 0000000..603fb34
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/loader.js
@@ -0,0 +1,32 @@
+/*
+ * 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('SyncopeEnduserApp')
+ .directive("loader", function ($rootScope) {
+ return function ($scope, element, attrs) {
+ $scope.$on("loader_show", function () {
+ return element.show();
+ });
+ return $scope.$on("loader_hide", function () {
+ return element.hide();
+ });
+ };
+ });
http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/directives/navigationButtons.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/directives/navigationButtons.js b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/navigationButtons.js
new file mode 100644
index 0000000..ff3eebf
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/navigationButtons.js
@@ -0,0 +1,31 @@
+/*
+ * 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')
+ .directive('navigationButtons', function () {
+ return {
+ restrict: 'E',
+ templateUrl: 'views/navigationButtons.html',
+ scope: {
+ next: "@",
+ previous: "@"
+ }
+ };
+ });
http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/directives/passwordStrengthEstimator.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/directives/passwordStrengthEstimator.js b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/passwordStrengthEstimator.js
new file mode 100644
index 0000000..4bf52b2
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/passwordStrengthEstimator.js
@@ -0,0 +1,102 @@
+/*
+ * 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', [])
+ .directive('checkStrength', function () {
+ return {
+ replace: false,
+ restrict: 'EACM',
+ link: function (scope, iElement, iAttrs) {
+
+ var strength = {
+ colors: ['#F00', '#F90', '#FF0', '#9F0', '#0F0'],
+ mesureStrength: function (p) {
+
+ var _force = 0;
+ var _regex = /[$-/:-?{-~!"^_`\[\]]/g;
+
+ var _lowerLetters = /[a-z]+/.test(p);
+ var _upperLetters = /[A-Z]+/.test(p);
+ var _numbers = /[0-9]+/.test(p);
+ var _symbols = _regex.test(p);
+
+ var _flags = [_lowerLetters, _upperLetters, _numbers, _symbols];
+ var _passedMatches = $.grep(_flags, function (el) {
+ return el === true;
+ }).length;
+
+ _force += 2 * p.length + ((p.length >= 10) ? 1 : 0);
+ _force += _passedMatches * 10;
+
+ // penality (short password)
+ _force = (p.length <= 6) ? Math.min(_force, 10) : _force;
+
+ // penality (poor variety of characters)
+ _force = (_passedMatches == 1) ? Math.min(_force, 10) : _force;
+ _force = (_passedMatches == 2) ? Math.min(_force, 20) : _force;
+ _force = (_passedMatches == 3) ? Math.min(_force, 40) : _force;
+
+ return _force;
+
+ },
+ getColor: function (s) {
+
+ var idx = 0;
+ if (s <= 10) {
+ idx = 0;
+ }
+ else if (s <= 20) {
+ idx = 1;
+ }
+ else if (s <= 30) {
+ idx = 2;
+ }
+ else if (s <= 40) {
+ idx = 3;
+ }
+ else {
+ idx = 4;
+ }
+
+ return {idx: idx + 1, col: this.colors[idx]};
+
+ }
+ };
+
+ scope.$watch(iAttrs.checkStrength, function () {
+ if (scope.pw === '') {
+ iElement.css({"display": "none"});
+ } else {
+ var strength = strength.mesureStrength(scope.pw);
+ var c = strength.getColor(strength);
+ iElement.css({"display": "inline"});
+ iElement.children('li')
+ .css({"background": "#DDD"})
+ .slice(0, c.idx)
+ .css({"background": c.col});
+ }
+ });
+
+ },
+ template: ''
+ };
+ });
+
http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/filters/propsFilter.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/filters/propsFilter.js b/client/enduser/src/main/resources/META-INF/resources/app/js/filters/propsFilter.js
new file mode 100644
index 0000000..a092d0c
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/filters/propsFilter.js
@@ -0,0 +1,52 @@
+/*
+ * 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")
+ .filter('propsFilter', function () {
+ return function (items, props) {
+ var out = [];
+
+ if (angular.isArray(items)) {
+ items.forEach(function (item) {
+ var itemMatches = false;
+
+ var keys = Object.keys(props);
+ for (var i = 0; i < keys.length; i++) {
+ var prop = keys[i];
+ var text = props[prop].toLowerCase();
+ if (item[prop].toString().toLowerCase().indexOf(text) !== -1) {
+ itemMatches = true;
+ break;
+ }
+ }
+
+ if (itemMatches) {
+ out.push(item);
+ }
+ });
+ } else {
+ // Let the output be the input untouched
+ out = items;
+ }
+
+ return out;
+ };
+ });
http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/services/authService.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/services/authService.js b/client/enduser/src/main/resources/META-INF/resources/app/js/services/authService.js
new file mode 100644
index 0000000..3c3f7af
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/services/authService.js
@@ -0,0 +1,74 @@
+/*
+ * 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('login')
+ .factory('AuthService', ['$rootScope', '$resource', '$q', '$http', '$cookies',
+ function ($rootScope, $resource, $q, $http, $cookies) {
+
+ var authService = {};
+
+ var clearUserCookie = function () {
+ $rootScope.currentUser = null;
+ $cookies.remove('currentUser');
+ };
+
+ authService.login = function (credentials) {
+ return $http
+ .post('/syncope-enduser/api/login', credentials)
+ .then(function (response) {
+ var username = response.data;
+ $cookies.put('currentUser', username);
+ $rootScope.currentUser = username;
+ return username;
+ }, function (response) {
+ clearUserCookie();
+ console.log("Something went wrong during login, exit with status: ", response);
+ return $q.reject(response.data || response.statusText);
+ });
+ };
+
+ authService.logout = function () {
+ return $http
+ .get('/syncope-enduser/api/logout')
+ .then(function (response) {
+ clearUserCookie();
+ return response;
+ }, function (response) {
+ clearUserCookie();
+ console.log("Something went wrong during logout, exit with status: ", response);
+ });
+ };
+
+ return authService;
+// return {
+// login: $resource('/syncope-enduser/api/login', {}, {
+// do: {method: 'POST', params: {}, isArray: false}
+// })
+// };
+// return {
+// logout: $resource('/cradleDashboard/api/logout', {}, {
+// query: {method: 'GET', params: {}, isArray: false}
+// })
+// };
+
+ }]);
+
+
http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/services/realmService.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/services/realmService.js b/client/enduser/src/main/resources/META-INF/resources/app/js/services/realmService.js
new file mode 100644
index 0000000..356dc87
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/services/realmService.js
@@ -0,0 +1,47 @@
+/*
+ * 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('RealmService', ['$resource', '$q', '$http',
+ function ($resource, $q, $http) {
+
+ var realmService = {};
+
+ realmService.getAvailableRealmsStub = function () {
+ return ["/"];
+ };
+
+ realmService.getAvailableRealms = function () {
+ return $http.get("/syncope-enduser/api/realms")
+ .then(function (response) {
+ console.log("realms response: ", response);
+ return response.data;
+ }, function (response) {
+ console.log("Something went wrong during realms retrieval, exit with status: ", response);
+ return $q.reject(response.data || response.statusText);
+ });
+ };
+
+ realmService.getUserRealm = function () {
+ return "/";
+ };
+ return realmService;
+ }]);
http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/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
new file mode 100644
index 0000000..be9f510
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/services/schemaService.js
@@ -0,0 +1,42 @@
+/*
+ * 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('SchemaService', ['$resource', '$q', '$http',
+ function ($resource, $q, $http) {
+
+ var schemaService = {};
+
+ schemaService.getUserSchemas = function () {
+
+ return $http.get("/syncope-enduser/api/schemas")
+ .then(function (response) {
+ console.log("schemaAPI response: ", response);
+ return response.data;
+ }, function (response) {
+ console.log("Something went wrong during schema retrieval, exit with status: ", response);
+ return $q.reject(response.data || response.statusText);
+ });
+ };
+ return schemaService;
+ }]);
+
+
http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/services/securityQuestionService.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/services/securityQuestionService.js b/client/enduser/src/main/resources/META-INF/resources/app/js/services/securityQuestionService.js
new file mode 100644
index 0000000..ff91f18
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/services/securityQuestionService.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('SecurityQuestionService', ['$resource', '$q', '$http',
+ function ($resource, $q, $http) {
+
+ var securityQuestionService = {};
+
+ securityQuestionService.getAvailableSecurityQuestions = function () {
+ return $http.get("/syncope-enduser/api/securityQuestions")
+ .then(function (response) {
+ console.log("security questions response: ", response);
+ return response.data;
+ }, function (response) {
+ console.log("Something went wrong during security questions retrieval, exit with status: ",
+ response);
+ return $q.reject(response.data || response.statusText);
+ });
+ };
+
+ return securityQuestionService;
+ }]);
http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/js/services/userSelfService.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/services/userSelfService.js b/client/enduser/src/main/resources/META-INF/resources/app/js/services/userSelfService.js
new file mode 100644
index 0000000..3a99e7f
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/services/userSelfService.js
@@ -0,0 +1,69 @@
+/*
+ * 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('login')
+ .factory('UserSelfService', ['$resource', '$q', '$http',
+ function ($resource, $q, $http) {
+
+ var userSelfService = {};
+
+ userSelfService.read = function () {
+ return $http
+ .get('/syncope-enduser/api/self/read')
+ .then(function (response) {
+ console.log("response read: ", response.data);
+ return response.data;
+ }, function (response) {
+ console.log("Something went wrong during user self read, exit with status: ", response);
+ return $q.reject(response.data || response.statusText);
+ });
+ };
+
+ userSelfService.create = function (user) {
+ return $http
+ .post('/syncope-enduser/api/self/create', user)
+ .then(function (response) {
+ console.log("response save: ", response)
+ var username = response;
+ }, function (response) {
+ console.log("Something went wrong during user self creation, exit with status: ", response);
+ return $q.reject(response.data || response.statusText);
+ });
+ };
+
+ userSelfService.update = function (user) {
+ return $http
+ .post('/syncope-enduser/api/self/update', user)
+ .then(function (response) {
+ var username = response;
+ }, function (response) {
+ console.log("Something went wrong during user self update, exit with status: ", response);
+ return $q.reject(response.data || response.statusText);
+ });
+ };
+
+ userSelfService.passwordReset = function () {
+ };
+
+ return userSelfService;
+ }]);
+
+
http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicAttribute.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicAttribute.html b/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicAttribute.html
new file mode 100644
index 0000000..9c6b1d9
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicAttribute.html
@@ -0,0 +1,58 @@
+<div ng-switch="schema.type" >
+ <input ng-switch-when="String" 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)"/>
+ <input ng-switch-when="Encrypted" 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 ng-switch-when="Boolean">
+ <input type="checkbox" ng-model="user.plainAttrs[schema.key].values[index]" ng-required="schema.mandatoryCondition"
+ ng-init="initAttribute(schema, index)" />
+ </div>
+ <input ng-switch-when="Long" class="form-control" type="number" ng-model="user.plainAttrs[schema.key].values[index]" ng-required="schema.mandatoryCondition"
+ ng-init="initAttribute(schema, index)" />
+ <input ng-switch-when="Double" class="form-control" type="number" ng-model="user.plainAttrs[schema.key].values[index]" ng-required="schema.mandatoryCondition"
+ ng-init="initAttribute(schema, index)" />
+ <p ng-switch-when="Date" class="input-group" >
+ <input type="text" class="form-control"
+ uib-datepicker-popup="{{format}}"
+ ng-model="selectedDate"
+ ng-change="bindDateToModel(selectedDate, format)"
+ min-date="minDate" max-date="maxDate"
+ is-open="status.opened" datepicker-options="dateOptions"
+ ng-required="schema.mandatoryCondition" close-text="Close" ng-init="initAttribute(schema, index)"/>
+ <span class="input-group-btn">
+ <button type="button" class="btn btn-default" ng-click="open($event)"><i class="glyphicon glyphicon-calendar"></i></button>
+ </span>
+ </p>
+
+ <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}}">{{schema.enumerationKeys[$index] || value}}</option>
+ </select>
+ </div>
+
+ <div ng-switch-when="Binary" ng-init="initAttribute(schema, index)">
+ <div enctype="multipart/form-data" accept-charset="UTF-8">
+ <input id="fileInput" type="file" ng-required="schema.mandatoryCondition"/>
+ <button type="button" title="Download file" class="fileButton btn btn-default btn-sm" ng-click="download()">
+ <i class="glyphicon glyphicon-download" ></i>
+ </button>
+ <button type="button" class="fileButton btn btn-default btn-sm" title="Remove file" ng-click="remove()">
+ <i class="glyphicon glyphicon-remove-sign" ></i>
+ </button>
+ <h4><span class="label label-primary" ng-model="userFile">{{userFile}}</span></h4>
+ </div>
+
+ </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>
http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicDerivedAttributes.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicDerivedAttributes.html b/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicDerivedAttributes.html
new file mode 100644
index 0000000..9400877
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicDerivedAttributes.html
@@ -0,0 +1,21 @@
+<ui-select on-select="addDerivedAttribute($item, $model)" on-remove="removeDerivedAttribute($item, $model)" multiple
+ ng-model="dynamicForm.selectedDerSchemas" theme="select2" class="attribute-ui-select">
+ <ui-select-match placeholder="Select derived attribute...">{{$item.key}}</ui-select-match>
+ <ui-select-choices repeat="derSchema in dynamicForm.derSchemas | propsFilter: {key: $select.search}">
+ <div ng-bind-html="derSchema.key | highlight: $select.search"></div>
+ <small>
+ name: {{derSchema.key}}
+ expression: {{derSchema.expression}}
+ </small>
+ </ui-select-choices>
+</ui-select>
+
+<ul class="attribute-virtual-value-container">
+ <li class="attribute-virtual-value-field" ng-repeat="selectedDerSchema in dynamicForm.selectedDerSchemas| filter:q as results">
+ {{selectedDerSchema.key}}
+ <input style="font-weight: normal" class="form-control" type="text" ng-disabled="true" ng-model="user.derAttrs[selectedDerSchema.key].values[0]"/>
+ </li>
+ <li class="attribute-virtual-value-field" ng-if="results.length == 0">
+ <strong>No derived attributes selected...</strong>
+ </li>
+</ul>
http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicPlainAttributes.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicPlainAttributes.html b/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicPlainAttributes.html
new file mode 100644
index 0000000..074abbd
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicPlainAttributes.html
@@ -0,0 +1,22 @@
+<div id="attribute" class="form-group" ng-repeat="plainSchema in dynamicForm.plainSchemas">
+ <label for="plainSchema.key">{{plainSchema.key}} <span ng-if="Boolean(plainSchema.mandatoryCondition)">*</span></label>
+ <div ng-if="!plainSchema.multivalue">
+ <dynamic-attribute schema="plainSchema" user="user" index="0"></dynamic-attribute>
+ </div>
+
+ <div ng-if="plainSchema.multivalue">
+ <div ng-repeat="field in dynamicForm.attributeTable[plainSchema.key].fields track by $index" ng-model='dynamicForm.attributeTable[plainSchema.key].fields[$index]'>
+ <dynamic-attribute schema="plainSchema" user="user" index="$index"></dynamic-attribute>
+ <span>
+ <button class="btn btn-default btn-sm minus" ng-if="$index > 0" type="button" ng-click="removeAttributeField(plainSchema.key, $index)">
+ <i class="glyphicon glyphicon-minus" title="Remove value"></i>
+ </button>
+ </span>
+ </div>
+ <span>
+ <button class="btn btn-default btn-sm" type="button" ng-click="addAttributeField(plainSchema.key)">
+ <i class="glyphicon glyphicon-plus" title="Add value"></i>
+ </button>
+ </span>
+ </div>
+</div>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/syncope/blob/223a64e2/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicVirtualAttributes.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicVirtualAttributes.html b/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicVirtualAttributes.html
new file mode 100644
index 0000000..897eb2c
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/dynamicVirtualAttributes.html
@@ -0,0 +1,18 @@
+<ui-select on-select="addVirtualAttribute($item, $model)" on-remove="removeVirtualAttribute($item, $model)" multiple
+ ng-model="dynamicForm.selectedVirSchemas" theme="select2" ng-disabled="false" class="attribute-ui-select">
+ <ui-select-match placeholder="Select virtual attribute...">{{$item.key}}</ui-select-match>
+ <ui-select-choices repeat="virSchema in dynamicForm.virSchemas | propsFilter: {key: $select.search}">
+ <div ng-bind-html="virSchema.key | highlight: $select.search"></div>
+ </ui-select-choices>
+</ui-select>
+
+<ul class="attribute-virtual-value-container">
+ <li class="attribute-virtual-value-field" ng-repeat="selectedVirSchema in dynamicForm.selectedVirSchemas| filter:q as results">
+ {{selectedVirSchema.key}}
+ <input style="font-weight: normal" class="form-control" type="text" ng-disabled="selectedVirSchema.readonly"
+ ng-model="user.virAttrs[selectedVirSchema.key].values[0]"/>
+ </li>
+ <li class="attribute-virtual-value-field" ng-if="results.length == 0">
+ <strong>No virtual attributes selected...</strong>
+ </li>
+</ul>
\ No newline at end of file