diff --git a/front/src/app/app-routing.module.ts b/front/src/app/app-routing.module.ts
index 1a6c609..02ad7fc 100644
--- a/front/src/app/app-routing.module.ts
+++ b/front/src/app/app-routing.module.ts
@@ -16,6 +16,7 @@ import {
SignOutScene,
SignUpScene,
HomeUnregisteredScene,
+ ManageAccountsScene,
} from './scene';
import { OnlyAdminGuard, OnlyUnregisteredGuardHome, OnlyUsersGuard, OnlyUsersGuardHome } from 'common/service/session';
import { ForbiddenScene, NotFound404Scene } from 'common/scene';
@@ -66,6 +67,11 @@ const routes: Routes = [
component: SettingsScene,
canActivate: [OnlyAdminGuard],
},
+ {
+ path: 'manage_accounts',
+ component: ManageAccountsScene,
+ canActivate: [OnlyAdminGuard],
+ },
{
path: '**',
component: NotFound404Scene,
diff --git a/front/src/app/app.component.ts b/front/src/app/app.component.ts
index e55bb0d..25cf9ab 100644
--- a/front/src/app/app.component.ts
+++ b/front/src/app/app.component.ts
@@ -102,9 +102,16 @@ export class AppComponent implements OnInit {
position: MenuPosition.LEFT,
hover: 'Admin configuration karso management',
icon: 'settings',
- title: 'Settings',
+ title: 'Admin Settings',
navigateTo: 'settings',
enable: this.sessionService.userAdmin === true,
+ }, { // TODO move this in the setting environment system ?
+ position: MenuPosition.LEFT,
+ hover: 'Admin of users',
+ icon: 'manage_accounts',
+ title: 'Manage Accounts',
+ navigateTo: 'manage_accounts',
+ enable: this.sessionService.userAdmin === true,
},
],
},
diff --git a/front/src/app/app.module.ts b/front/src/app/app.module.ts
index e63eeac..78f9f73 100644
--- a/front/src/app/app.module.ts
+++ b/front/src/app/app.module.ts
@@ -22,6 +22,7 @@ import {
ChangePasswordScene,
SettingsScene,
HomeUnregisteredScene,
+ ManageAccountsScene,
} from 'app/scene';
import {
BddService,
@@ -69,6 +70,7 @@ import { PasswordEntryComponent } from './component';
ForbiddenScene,
ChangePasswordScene,
HomeUnregisteredScene,
+ ManageAccountsScene,
],
imports: [
BrowserModule,
diff --git a/front/src/app/scene/index.ts b/front/src/app/scene/index.ts
index f8cf3cf..784a946 100644
--- a/front/src/app/scene/index.ts
+++ b/front/src/app/scene/index.ts
@@ -4,6 +4,7 @@ import { ForgotPasswordScene } from './forgot-password/forgot-password';
import { HelpScene } from './help/help';
import { HomeUnregisteredScene } from './home-unregistered/home-unregistered';
import { HomeScene } from './home/home';
+import { ManageAccountsScene } from './manage-accounts/manage-accounts';
import { SettingsScene } from './settings/settings';
import { SignInScene } from './sign-in/sign-in';
import { SignOutScene } from './sign-out/sign-out';
@@ -22,4 +23,5 @@ export {
ChangePasswordScene,
SettingsScene,
HomeUnregisteredScene,
+ ManageAccountsScene,
};
diff --git a/front/src/app/scene/manage-accounts/manage-accounts.html b/front/src/app/scene/manage-accounts/manage-accounts.html
new file mode 100644
index 0000000..90e2613
--- /dev/null
+++ b/front/src/app/scene/manage-accounts/manage-accounts.html
@@ -0,0 +1,100 @@
+
+
Manage User Accounts
+
+
+
+
Current users
+
List of all users
+
+
+
+
+ id |
+ login |
+ e-mail |
+ admin |
+ blocked |
+ avatar |
+ lastConnection |
+
+
+ {{user.id}} |
+ {{user.login}} |
+ {{user.email}} |
+ {{user.admin}} |
+ {{user.blocked}} |
+ {{user.avatar}} |
+ {{user.lastConnection}} |
+
+
+
+
+
+
+
+
+
+
+
+
Create new user
+
Add a new user on the server
+
+
+
+
+
+
+
+
diff --git a/front/src/app/scene/manage-accounts/manage-accounts.less b/front/src/app/scene/manage-accounts/manage-accounts.less
new file mode 100644
index 0000000..49e539a
--- /dev/null
+++ b/front/src/app/scene/manage-accounts/manage-accounts.less
@@ -0,0 +1,151 @@
+.settings-title {
+ width: 80%;
+ border: solid;
+ border-width: 1px;
+ margin: auto;
+ padding: 10px 20px;
+
+ border-color: black;
+ border-radius: 10px 10px 0px 0px;
+ background-color: gray;
+
+ .group-title {
+ font-size: 24px;
+ font-weight: bold;
+ line-height: 24px;
+ vertical-align: middle;
+ margin: 10px 0 10px 0;
+ text-align: Left;
+ }
+ .group-description {
+ font-size: 16px;
+ line-height: 16px;
+ vertical-align: middle;
+ margin: 10px 0 10px 0;
+ text-align: Left;
+ }
+}
+
+.settings-elements {
+ width: 80%;
+ border: solid;
+ border-width: 0px 1px;
+ margin: auto;
+ padding: 10px 20px;
+
+ border-color: black;
+ border-radius: 0px;
+ background-color: lightgray;
+ vertical-align: middle;
+ text-align: Left;
+
+ .elem-hr {
+ width: 100%;
+ border-color: black;
+ border: dashed;
+ border-width: 1px 0 0 0;
+ margin: 10px auto;
+ }
+ .elem-checkbox {
+ font-size: 18px;
+ font-weight: bold;
+ margin: 0 10px 0 10px;
+ }
+ .elem-title {
+ font-size: 18px;
+ font-weight: bold;
+ margin: 0 10px 0 36px;
+ }
+ .elem-description {
+ font-size: 14px;
+ margin: 0 20px 10px 50px;
+ font-style: italic;
+ }
+ .elem-input {
+ font-size: 14px;
+ margin: 0 20px 10px 36px;
+ input {
+ width: 100%;
+ }
+ }
+}
+
+.settings-validation {
+ width: 80%;
+ border: solid;
+ border-width: 1px;
+ margin: auto;
+ padding: 10px 20px;
+
+ border-color: black;
+ border-radius: 0px 0px 10px 10px;
+ background-color: gray;
+}
+
+.title {
+ //background-color: green;
+ font-size: 45px;
+ font-weight: bold;
+ line-height: 60px;
+ width: 100%;
+ text-align: center;
+ vertical-align: middle;
+ margin: 10px 0 10px 0;
+ text-shadow: 1px 1px 2px white, 0 0 1em white, 0 0 0.2em white;
+ text-transform: uppercase;
+ font-family: 'Roboto', 'Helvetica', 'Arial', sans-serif;
+}
+.item-home {
+ background-color: rgba(200, 200, 200, 0.5);
+ font-size: 20px;
+ height: 190px;
+ width: 200px;
+ margin: 5px;
+ padding: 0;
+ overflow: hidden;
+ // box-shadow: 0 1px 1.5px 0 rgba(0,0,0,.12),0 1px 1px 0 rgba(0,0,0,.24);
+ box-shadow: 0px 2px 4px 0 rgba(0, 0, 0, 0.6);
+ line-height: normal;
+ border: none;
+ font-family: 'Roboto', 'Helvetica', 'Arial', 'sans-serif';
+ font-weight: 500;
+ text-transform: uppercase;
+ letter-spacing: 0;
+ will-change: box-shadow;
+ outline: none;
+ cursor: pointer;
+ text-decoration: none;
+ text-align: center;
+ transition-duration: 0.4s;
+ float: left;
+ display: block;
+
+ h1 {
+ font-size: 24px;
+ }
+
+ &:hover {
+ background-color: rgba(200, 200, 200, 1);
+ //box-shadow: 0px 2px 4px 0 rgba(255, 0, 0, 0.6);
+ }
+
+ .material-icons {
+ vertical-align: middle;
+ }
+
+ .material-icons {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: ~'translate(-12px,-12px)';
+ line-height: 24px;
+ width: 24px;
+ }
+}
+
+@media all and (min-width: 1310px) {
+ .colomn_mutiple {
+ width: ~'calc(210px * 5)';
+ margin: auto;
+ }
+}
diff --git a/front/src/app/scene/manage-accounts/manage-accounts.ts b/front/src/app/scene/manage-accounts/manage-accounts.ts
new file mode 100644
index 0000000..ab4e9c6
--- /dev/null
+++ b/front/src/app/scene/manage-accounts/manage-accounts.ts
@@ -0,0 +1,285 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2018, Edouard DUPIN, all right reserved
+ * @license PROPRIETARY (see license file)
+ */
+
+import { Component, OnInit } from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
+import { AdminUserService, SettingsService } from 'app/service';
+import {
+ checkEmailValidity,
+ checkLoginValidity,
+ createPasswordState,
+ isArrayOf,
+ isBoolean,
+ isInArray,
+ isNullOrUndefined,
+ isNumber,
+ isObject,
+ isOptionalArrayOf,
+ isOptionalOf,
+ isString,
+ isUndefined,
+} from 'common/utils';
+export enum SettingType {
+ TITLE = 'TITLE',
+ GROUP = 'GROUP',
+ LINE = 'LINE',
+ BOOLEAN = 'BOOLEAN',
+ STRING = 'STRING',
+ PASSWORD = 'PASSWORD',
+}
+export function isSettingType(data: any): data is SettingType {
+ return isInArray(data, ['TITLE', 'GROUP', 'LINE', 'BOOLEAN', 'STRING', 'PASSWORD']);
+}
+
+export interface SettingsItem {
+ // Type of the menu Node
+ type: SettingType;
+ // Displayed Title
+ title?: string;
+ // Description of the parameter
+ description?: string;
+ // Image to dsplay that describe the parameter
+ image?: string;
+ // If true the parameter is applied directly to the backend
+ directApply?: boolean;
+ // Parameter key to SET/GET
+ key?: string;
+ // Parameter key to SET/GET or the sub-menu
+ value?: SettingsItem[] | boolean | string | Number;
+ // whendata is change the value is set here:
+ newValue?: boolean | string | Number;
+}
+
+export function isSettingsItem(data: any): data is SettingsItem {
+ if (isNullOrUndefined(data)) {
+ return false;
+ }
+ if (!isObject(data)) {
+ return false;
+ }
+ if (!isSettingType(data.type)) {
+ return false;
+ }
+ if (!isOptionalOf(data.title, isString)) {
+ return false;
+ }
+ if (!isOptionalOf(data.description, isString)) {
+ return false;
+ }
+ if (!isOptionalOf(data.image, isString)) {
+ return false;
+ }
+ if (!isOptionalOf(data.directApply, isBoolean)) {
+ return false;
+ }
+ if (!isOptionalOf(data.key, isString)) {
+ return false;
+ }
+ if (
+ !isOptionalOf(data.value, isBoolean) &&
+ !isOptionalOf(data.value, isString) &&
+ !isOptionalOf(data.value, isNumber) &&
+ !isOptionalArrayOf(data.value, isSettingsItem)
+ ) {
+ return false;
+ }
+ if (
+ !isOptionalOf(data.newValue, isBoolean) &&
+ !isOptionalOf(data.newValue, isString) &&
+ !isOptionalOf(data.newValue, isNumber)
+ ) {
+ return false;
+ }
+ return true;
+}
+
+@Component({
+ selector: 'app-settings',
+ templateUrl: './manage-accounts.html',
+ styleUrls: ['./manage-accounts.less'],
+})
+export class ManageAccountsScene implements OnInit {
+ users: any = [];
+
+ constructor(private adminUserService: AdminUserService) {
+ }
+ ngOnInit() {
+ let self = this;
+ this.adminUserService
+ .getUsers()
+ .then((response: any) => {
+ console.log(`??? get full response: ${JSON.stringify(response, null, 4)}`);
+ self.users = response;
+ })
+ .catch((error: any) => {
+ console.log(`??? get ERROR response: ${JSON.stringify(error, null, 4)}`);
+ });
+ }
+
+ public passwordState: boolean|string = false;
+ public password: string = '';
+ public validateButtonCreateUserDisabled: boolean = true;
+ /**
+ * update the state of the validation button. if all is OK, the button will became clickable
+ */
+ updateButtonVisibility(): void {
+ if (this.passwordState === true && this.loginOK === true && this.emailOK === true) {
+ this.validateButtonCreateUserDisabled = false;
+ } else {
+ this.validateButtonCreateUserDisabled = true;
+ }
+ }
+ /**
+ * Check if the current password is valid or not (update error message)
+ * @param newValue New password value.
+ */
+ checkPassword(newValue: string): void {
+ this.password = newValue;
+ this.passwordState = createPasswordState(this.password);
+ this.checkPassword(this.password);
+ this.updateButtonVisibility();
+ }
+ /**
+ * Request the creation of a new user.
+ */
+ onCreateUser(): void {
+
+ }
+
+
+
+ private signUpIconWrong: string = 'icon-right-not-validate';
+ private signUpIconWait: string = 'icon-right-load';
+ private signUpIconRight: string = 'icon-right-validate';
+
+
+ public login: string = '';
+ public loginOK: boolean = false;
+ public loginHelp: string = '';
+ public loginIcon: string = '';
+
+ public email: string = '';
+ public emailOK: boolean = false;
+ public emailHelp: string = '';
+ public emailIcon: string = '';
+
+
+ checkLogin(newValue: string): void {
+ // this.userService.loginSha("loooogin", "ekljkj", true);
+ this.login = newValue;
+ if (this.login === null || this.login.length === 0) {
+ this.loginOK = false;
+ this.loginIcon = '';
+ //this.loginIcon = this.signUpIconWrong;
+ this.loginHelp = '';
+ this.updateButtonVisibility();
+ return;
+ }
+ if (this.login.length < 6) {
+ this.loginOK = false;
+ this.loginHelp = 'Need 6 characters';
+ this.loginIcon = this.signUpIconWrong;
+ this.updateButtonVisibility();
+ return;
+ }
+ if (checkLoginValidity(this.login) === true) {
+ this.loginOK = false;
+ // this.loginHelp = "check in progress...";
+ this.loginIcon = this.signUpIconWait;
+ let self = this;
+ this.adminUserService
+ .checkLogin(this.login)
+ .then((isNotUsed: boolean) => {
+ // check if the answer is correct with the question
+ if (newValue !== self.login) {
+ return;
+ }
+ if (isNotUsed === false) {
+ // the login exist ... ==> it is found...
+ self.loginOK = false;
+ self.loginHelp = 'Login already used ...';
+ self.loginIcon = self.signUpIconWrong;
+ self.updateButtonVisibility();
+ } else {
+ self.loginOK = true;
+ self.loginHelp = '';
+ self.loginIcon = self.signUpIconRight;
+ self.updateButtonVisibility();
+ return;
+ }
+ })
+ .catch((error: number) => {
+ console.log(`Status ${error}`);
+ self.loginOK = false;
+ self.loginHelp = 'ErrorOccured in fetching data ...';
+ self.loginIcon = self.signUpIconWrong;
+ self.updateButtonVisibility();
+ });
+ } else {
+ this.loginOK = false;
+ this.loginHelp = 'Not valid: characters, numbers and "_-."';
+ }
+ this.updateButtonVisibility();
+ }
+
+ checkEmail(newValue: string): void {
+ this.email = newValue;
+ if (this.email === null || this.email.length === 0) {
+ this.emailOK = false;
+ this.updateButtonVisibility();
+ this.emailIcon = '';
+ this.emailHelp = '';
+ return;
+ }
+ if (this.email.length < 6) {
+ this.emailOK = false;
+ this.emailHelp = 'Need 6 characters';
+ this.updateButtonVisibility();
+ this.emailIcon = this.signUpIconWrong;
+ return;
+ }
+ if (checkEmailValidity(this.email) === true) {
+ this.emailOK = false;
+ this.emailHelp = '';
+ // this.loginHelp = "check in progress...";
+ this.emailIcon = this.signUpIconWait;
+ let self = this;
+ this.adminUserService.checkEMail(this.email).then(
+ (isNotUsed: boolean) => {
+ // check if the answer is correct with the question
+ if (newValue !== self.email) {
+ return;
+ }
+ if (isNotUsed === false) {
+ // the email exist ... ==> it is found...
+ self.emailOK = false;
+ self.emailHelp = 'email already used ...';
+ self.emailIcon = self.signUpIconWrong;
+ self.updateButtonVisibility();
+ } else {
+ self.emailOK = true;
+ self.emailHelp = '';
+ self.emailIcon = self.signUpIconRight;
+ self.updateButtonVisibility();
+ return;
+ }
+ },
+ (error: number) => {
+ console.log(`Status ${error}`);
+ self.emailOK = false;
+ self.emailHelp = 'ErrorOccured in fetching data ...';
+ self.emailIcon = self.signUpIconWrong;
+ self.updateButtonVisibility();
+ }
+ );
+ } else {
+ this.emailOK = false;
+ this.emailHelp = 'Not valid: characters, numbers, "_-." and email format: you@example.com';
+ }
+ this.updateButtonVisibility();
+ }
+
+}
diff --git a/front/src/app/service/admin-user.ts b/front/src/app/service/admin-user.ts
index bc02d0e..e380ae7 100644
--- a/front/src/app/service/admin-user.ts
+++ b/front/src/app/service/admin-user.ts
@@ -118,6 +118,24 @@ export class AdminUserService {
});
});
}
+ getUsers(): Promise {
+ return new Promise((resolve, reject) => {
+ this.http
+ .requestJson({
+ server: 'karso',
+ endPoint: 'users',
+ requestType: HTTPRequestModel.GET,
+ accept: HTTPMimeType.JSON,
+ contentType: HTTPMimeType.JSON
+ })
+ .then((response: ModelResponseHttp) => {
+ resolve(response.data);
+ })
+ .catch((error: any) => {
+ reject(`return ERROR ${JSON.stringify(error, null, 2)}`);
+ });
+ });
+ }
create(login: string, email: string, password: string) {
return this.createSha(login, email, sha512(password));