[DEV] many update and corect securityu fail n set parameters

This commit is contained in:
Edouard DUPIN 2023-02-12 23:59:43 +01:00
parent e1bb3a3ab9
commit dd936c2e94
20 changed files with 492 additions and 319 deletions

View File

@ -27,7 +27,7 @@
<dependency> <dependency>
<groupId>kangaroo-and-rabbit</groupId> <groupId>kangaroo-and-rabbit</groupId>
<artifactId>archidata</artifactId> <artifactId>archidata</artifactId>
<version>0.3.1</version> <version>0.3.2</version>
</dependency> </dependency>
<!-- testing --> <!-- testing -->
<dependency> <dependency>

View File

@ -11,8 +11,8 @@ public class WebLauncherLocal {
// for local test: // for local test:
ConfigBaseVariable.apiAdress = "http://0.0.0.0:15080/karso/api/"; ConfigBaseVariable.apiAdress = "http://0.0.0.0:15080/karso/api/";
ConfigBaseVariable.dbPort = "3306"; ConfigBaseVariable.dbPort = "3306";
ConfigBaseVariable.dbType = "sqlite"; //ConfigBaseVariable.dbType = "sqlite";
ConfigBaseVariable.dbHost = "./bdd_base.sqlite"; //ConfigBaseVariable.dbHost = "./bdd_base.sqlite";
} }
WebLauncher.main(args); WebLauncher.main(args);

View File

@ -72,7 +72,7 @@ public class SystemConfigResource {
} }
@PUT @PUT
@Path("key/{key}") @Path("key/{key}")
@RolesAllowed(value= {"USER", "ADMIN"}) @RolesAllowed(value= {"ADMIN"})
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Response setKey(@Context SecurityContext sc, @PathParam("key") String key, String jsonRequest) throws Exception { public Response setKey(@Context SecurityContext sc, @PathParam("key") String key, String jsonRequest) throws Exception {
Settings res = null; Settings res = null;
@ -90,7 +90,7 @@ public class SystemConfigResource {
JsonNode value = root.findPath("value"); JsonNode value = root.findPath("value");
res.value = value.asText(); res.value = value.asText();
System.out.println(" update valu : " + res.value);
SqlWrapper.update(res, res.id, List.of("value")); SqlWrapper.update(res, res.id, List.of("value"));
return Response.status(201).entity("{ \"value\":\"" + res.value + "\"}").build(); return Response.status(201).entity("{ \"value\":\"" + res.value + "\"}").build();
} }

View File

@ -42,7 +42,7 @@ import {
UserService, UserService,
} from 'common/service'; } from 'common/service';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { ErrorComponent, PopInComponent, SpinerComponent, TopMenuComponent, UploadFileComponent, PasswordEntryComponent, EntryComponent, AsyncActionStatusComponent, ErrorMessageStateComponent, CheckboxComponent, BurgerPropertyComponent, EntryValidatorComponent, RenderSettingsComponent, RenderFormComponent } from 'common/component'; import { ErrorComponent, PopInComponent, SpinerComponent, TopMenuComponent, UploadFileComponent, PasswordEntryComponent, EntryComponent, AsyncActionStatusComponent, ErrorMessageStateComponent, CheckboxComponent, BurgerPropertyComponent, EntryValidatorComponent, RenderSettingsComponent, RenderFormComponent, EntryNumberComponent } from 'common/component';
import { ForbiddenScene } from 'common/scene'; import { ForbiddenScene } from 'common/scene';
import { AdminUserService, ApplicationService, ApplicationTokenService, SettingsService } from 'app/service'; import { AdminUserService, ApplicationService, ApplicationTokenService, SettingsService } from 'app/service';
import { PopInUploadProgress, PopInDeleteConfirm } from 'common/popin'; import { PopInUploadProgress, PopInDeleteConfirm } from 'common/popin';
@ -63,6 +63,7 @@ import { PopInUploadProgress, PopInDeleteConfirm } from 'common/popin';
BurgerPropertyComponent, BurgerPropertyComponent,
RenderSettingsComponent, RenderSettingsComponent,
RenderFormComponent, RenderFormComponent,
EntryNumberComponent,
PopInComponent, PopInComponent,
PopInUploadProgress, PopInUploadProgress,

View File

@ -5,72 +5,19 @@
<name>Application properties</name> <name>Application properties</name>
<description>Update property of the application:</description> <description>Update property of the application:</description>
<body> <body>
<table width="100%"> <spiner *ngIf="editApplicationMenu===undefined"></spiner>
<tr> <app-render-form
<td width="25%"><b>id:</b></td> *ngIf="editApplicationMenu!==undefined"
<td width="75%">{{application?.id}}</td> [values]="editApplicationMenu"
</tr> (deltaValues)="onEditValues($event)"
<tr> (changeState)="onEditState($event)"
<td><b>Name:</b></td> ></app-render-form>
<td>
<app-entry
[value]="application?.name"
placeholder="Enter application name"
[hasError]="nameState !== true"
(changeValue)="checkName($event)"></app-entry>
<app-error-message-state [value]="nameState"></app-error-message-state>
</td>
</tr>
<tr>
<td><b>Description:</b></td>
<td>
<app-entry
[value]="application?.description"
(changeValue)="updateDescription($event)"></app-entry>
</td>
</tr>
<tr>
<td><b>Redirect (http://):</b></td>
<td>
<app-entry
[value]="application?.redirect"
placeholder="Enter http redirect adresses "
[hasError]="redirectState !== true"
(changeValue)="checkRedirect($event)"></app-entry>
<app-error-message-state [value]="redirectState"></app-error-message-state>
</td>
</tr>
<tr>
<td><b>Redirect development (http://):</b></td>
<td>
<app-entry
[value]="application?.redirectDev"
(changeValue)="updateRedirectDev($event)"></app-entry>
</td>
</tr>
<tr>
<td><b>Notification address (http://):</b></td>
<td>
<app-entry
[value]="application?.notification"
(changeValue)="updateNotification($event)"></app-entry>
</td>
</tr>
<tr>
<td><b>TTL (seconds before expiration):</b></td>
<td>
<app-entry
[value]="application?.ttl"
(changeValue)="updateTTL($event)"></app-entry>
</td>
</tr>
</table>
</body> </body>
<footer> <footer>
<button <button
class="button login color-button-validate color-shadow-black" class="button login color-button-validate color-shadow-black"
id="create-button" id="create-button"
[disabled]="validateButtonCreateApplicationDisabled" [disabled]="updateButtonDisabled !== 0"
(click)="onUpdateApplication()" (click)="onUpdateApplication()"
type="submit"> type="submit">
Update Update
@ -108,41 +55,28 @@
</tr> </tr>
</table> </table>
</body> </body>
</burger-property>
</div>
<div class="clear"><br/></div>
<div style="padding-top:15px;">
<burger-property>
<name>Add Token</name>
<body>
<app-render-form
[values]="createTokenMenu"
(deltaValues)="onCreateValueDeltaValues($event)"
(changeState)="onCreateValueState($event)"
></app-render-form>
</body>
<footer> <footer>
<table> <button
<tr> class="button login color-button-validate color-shadow-black"
<td width="25%">Name/Descriptiion token:</td> id="create-button"
<td> (click)="createToken()"
<app-entry-validator [disabled]="createTokenDisabled !== 0"
[value]="tokenName" type="submit">
placeholder="Enter the token name / decription" + Create new Token
(checker)="checkTokenName($event)" </button>
(changeValue)="newTokenName($event)"></app-entry-validator>
</td>
</tr>
<tr>
<td>Validity time (in day)</td>
<td>
<app-entry-validator
[value]="tokenTTL"
placeholder="Enter the Time To Lead (in day)"
(checker)="checkTokenTTL($event)"
(changeValue)="newTokenTTL($event)"></app-entry-validator>
</td>
</tr>
<tr>
<td></td>
<td>
<button
class="button login color-button-validate color-shadow-black"
id="create-button"
(click)="createToken()"
type="submit">
+ Create new Token
</button>
</td>
</tr>
</table>
</footer> </footer>
</burger-property> </burger-property>
</div> </div>

View File

@ -9,9 +9,9 @@ import { ActivatedRoute } from '@angular/router';
import { ApplicationService, ApplicationModel, ApplicationTokenService } from 'app/service'; import { ApplicationService, ApplicationModel, ApplicationTokenService } from 'app/service';
import { ApplicationTokenModel } from 'app/service/application-token'; import { ApplicationTokenModel } from 'app/service/application-token';
import { AsyncActionState } from 'common/component'; import { AsyncActionState } from 'common/component';
import { CheckerParameter } from 'common/component/entry-validator/entry-validator'; import { CheckerParameterType, SettingsItem, SettingType } from 'common/component/render-settings/render-settings';
import { NotificationService, PopInService } from 'common/service'; import { NotificationService, PopInService } from 'common/service';
import { isNumeric } from 'common/utils'; import { isNumber, isNumeric, isString } from 'common/utils';
@Component({ @Component({
selector: 'application-setting-edit', selector: 'application-setting-edit',
@ -42,9 +42,9 @@ export class ApplicationEditScene implements OnInit {
.then((response: ApplicationModel) => { .then((response: ApplicationModel) => {
console.log(`??? get full response: ${JSON.stringify(response, null, 4)}`); console.log(`??? get full response: ${JSON.stringify(response, null, 4)}`);
self.application = response; self.application = response;
self.applicationRef = { ...response };
self.checkName(self.application.name); self.checkName(self.application.name);
self.checkRedirect(self.application.redirect); //self.checkRedirect(self.application.redirect);
this.configureEditInput();
}) })
.catch((error: any) => { .catch((error: any) => {
console.log(`??? get ERROR response: ${JSON.stringify(error, null, 4)}`); console.log(`??? get ERROR response: ${JSON.stringify(error, null, 4)}`);
@ -58,133 +58,143 @@ export class ApplicationEditScene implements OnInit {
.catch((error: any) => { .catch((error: any) => {
console.log(`??? get ERROR response: ${JSON.stringify(error, null, 4)}`); console.log(`??? get ERROR response: ${JSON.stringify(error, null, 4)}`);
}); });
this.configureInput();
} }
formatTimestamp(unix_timestamp: number) { formatTimestamp(unix_timestamp: number) {
return new Date(unix_timestamp).toISOString().replace("T", " ").replace("Z", " GMT").replace(".000", ""); return new Date(unix_timestamp).toISOString().replace("T", " ").replace("Z", " GMT").replace(".000", "");
} }
updateDescription(newValue: string): void { editApplicationMenu: SettingsItem[] = undefined;
this.application.description = newValue;
this.updateButtonVisibility(); // this permit to clear the input menu...
} configureEditInput() {
updateRedirectDev(newValue: string): void { this.editApplicationMenu = [
this.application.redirectDev = newValue; {
this.updateButtonVisibility(); type: SettingType.VALUE,
} title: 'ID:',
updateNotification(newValue: string): void { value: this.application?.id,
this.application.notification = newValue; },
this.updateButtonVisibility(); {
} type: SettingType.STRING,
updateTTL(newValue: string): void { title: 'Name:',
if (isNumeric(newValue)) { placeholder: 'Enter application name',
this.application.ttl = Number(newValue); key: 'name',
} value: this.application?.name,
this.updateButtonVisibility(); checker: (value) => { return this.checkName(value)},
} require: true,
},
{
type: SettingType.STRING,
title: 'Description:',
public nameState: boolean|string = false; key: 'description',
public redirectState: boolean|string = false; value: this.application?.description,
public validateButtonCreateApplicationDisabled: boolean = true; },
/** {
* update the state of the validation button. if all is OK, the button will became clickable type: SettingType.STRING,
*/ title: 'Redirect:',
updateButtonVisibility(): void { description:"Redirect when login (http://):",
if ( ! (this.nameState === true && this.redirectState === true ) ) { placeholder: 'Enter http redirect adresses',
this.validateButtonCreateApplicationDisabled = true; key: 'redirect',
return; value: this.application?.redirect,
} checker: (value: CheckerParameterType) => { return this.checkRedirect(value)},
if (this.application.name !== this.applicationRef.name) { require: true,
this.validateButtonCreateApplicationDisabled = false; },
return; {
} type: SettingType.STRING,
if (this.application.description !== this.applicationRef.description) { title: 'Redirect (dev):',
this.validateButtonCreateApplicationDisabled = false; description:"Redirect development (http://):",
return; placeholder: 'Enter http redirect adresses',
} key: 'redirectDev',
if (this.application.redirect !== this.applicationRef.redirect) { value: this.application?.redirectDev,
this.validateButtonCreateApplicationDisabled = false; },
return; {
} type: SettingType.STRING,
if (this.application.redirectDev !== this.applicationRef.redirectDev) { title: 'Notification:',
this.validateButtonCreateApplicationDisabled = false; description:"Redirect development (http://):",
return; placeholder:"http://xxx/sso-event",
} key: 'notification',
if (this.application.notification !== this.applicationRef.notification) { value: this.application?.notification,
this.validateButtonCreateApplicationDisabled = false; },
return; {
} type: SettingType.NUMBER,
if (this.application.ttl !== this.applicationRef.ttl) { title: 'TTL:',
this.validateButtonCreateApplicationDisabled = false; description: 'Time in seconds of the validity of the token',
return; placeholder: "888",
} key: 'ttl',
this.validateButtonCreateApplicationDisabled = true; value: this.application?.ttl,
} checker: (value: CheckerParameterType) => { return this.checkTTL(value)},
require: true,
/** },
* Check the login writing rules ];
*/ this.updateButtonDisabled = undefined;
checkName(newValue: string): void { this.dataUpdate = {};
this.application.name = newValue;
if (this.application?.name?.length < 6) {
this.nameState = "This name is too small >=6.";
}
this.nameState = true;
this.updateButtonVisibility();
} }
/** /**
* Check the login writing rules * Check the redirection have a good form
*/ */
checkRedirect(newValue: string): void { checkRedirect(value: CheckerParameterType): string | undefined {
this.application.redirect = newValue; if (!isString(value)) {
this.redirectState = true; return "must be a string";
if (this.application?.redirect?.length <= 5) {
this.redirectState = "This redirect is too small.";
} }
this.updateButtonVisibility(); if (value.length <= 5) {
return "This redirect is too small.";
}
return undefined;
}
updateButtonDisabled: number | undefined = undefined;
dataUpdate: object = {}
onEditState(value: number) {
console.log(`changeState : ${JSON.stringify(value, null, 2)}`);
this.updateButtonDisabled = value;
// we do not change the main ref ==> notify angular that something have change and need to be re-render???
this.cdr.detectChanges();
}
onEditValues(value: any) {
console.log(`onDeltaValues : ${JSON.stringify(value, null, 2)}`);
this.dataUpdate = value;
// we do not change the main ref ==> notify angular that something have change and need to be re-render???
this.cdr.detectChanges();
} }
createState: string | boolean = undefined;
updateState: string | boolean = undefined;
/** /**
* Request the creation of a new application. * Request the creation of a new application.
*/ */
onUpdateApplication(): void { onUpdateApplication(): void {
console.log(`create user:`); this.updateState = AsyncActionState.LOADING;
this.createState = AsyncActionState.LOADING;
let self = this; let self = this;
/* this.applicationService.update(this.id, this.dataUpdate)
this.applicationService.create(this.name, this.redirect)
.then( .then(
(data: ApplicationModel) => { (data: ApplicationModel) => {
self.createState = AsyncActionState.DONE; self.updateState = AsyncActionState.DONE;
console.log(`Get new user: ${JSON.stringify(data, null, 2)}`); console.log(`Get new application data: ${JSON.stringify(data, null, 2)}`);
////////self.applications.push(data); self.application = data;
self.cdr.detectChanges(); self.configureEditInput()
self.name = null;
self.redirect = null;
setTimeout(() => { setTimeout(() => {
this.createState = undefined; this.updateState = undefined;
}, 3000); }, 3000);
} }
).catch( ).catch(
(error: any) => { (error: any) => {
self.createState = AsyncActionState.FAIL; self.updateState = AsyncActionState.FAIL;
setTimeout(() => { setTimeout(() => {
self.createState = undefined; self.updateState = undefined;
}, 3000); }, 3000);
} }
); );
*/
} }
createToken(): void { createToken(): void {
let self = this; let self = this;
this.applicationTokenService this.applicationTokenService
.create(this.id, this.tokenName, this.tokenTTL) .create(this.id, this.dataCreateApplication["name"], this.dataCreateApplication["ttl"])
.then((response: ApplicationTokenModel) => { .then((response: ApplicationTokenModel) => {
console.log(`??? get fullllllll response: ${JSON.stringify(response, null, 4)}`); //console.log(`??? get fullllllll response: ${JSON.stringify(response, null, 4)}`);
self.tokens.push(response); self.tokens.push(response);
response.token = `"${response.id}:${response.token}"` response.token = `"${response.id}:${response.token}"`
self.cdr.detectChanges(); self.cdr.detectChanges();
@ -228,64 +238,75 @@ export class ApplicationEditScene implements OnInit {
} }
} }
createFrom = [
{
title: "Name/Description token",
placeholder: "Enter the token name / decription",
value: "",
type: "INPUT",
checker: this.checkTokenName,
},
{
title: "Validity time (in day)",
placeholder: "Enter the Time To Lead (in day)",
value: "",
checker: this.checkTokenName,
},
]; createTokenMenu: SettingsItem[] = []
tokenName: string = undefined;
tokenTTL: number = undefined;
tokenCreateErrorCount: number = 2;
newTokenName(newValue: string) {
this.tokenName = newValue;
}
checkTokenName(chekParam: CheckerParameter): void {
if (chekParam.value.length < 3) {
chekParam.result("Must have 3 chars");
return;
}
chekParam.result(true);
}
newTokenTTL(newValue: string) { // this permit to clear the input menu...
if (isNumeric(newValue)) { configureInput() {
this.tokenTTL = Number(newValue); this.createTokenMenu = [
} {
type: SettingType.STRING,
title: 'Token name:',
placeholder: 'Enter the token name / decription',
key: 'name',
value: '',
checker: (value: CheckerParameterType) => { return this.checkName(value)},
require: true,
},
{
type: SettingType.NUMBER,
title: 'Token TTL:',
placeholder: 'Enter the Time To Lead (in day)',
key: 'ttl',
value: '',
checker: (value: CheckerParameterType) => { return this.checkTTL(value)},
require: true,
},
];
} }
checkTokenTTL(chekParam: CheckerParameter): void { public createTokenDisabled: number = undefined;
if (!isNumeric(chekParam.value)) { public dataCreateApplication: object = {};
chekParam.result("Must be a number");
return; /**
* Check the application name is available
*/
checkName(value: CheckerParameterType): string | undefined {
if (!isString(value)) {
return "Must be a String";
} }
if (chekParam.value.length<1) { if (value.length < 3) {
chekParam.result("Minimum one day"); return "This name is too small >=3.";
return;
} }
let value = Number(chekParam.value); return undefined;
if (value<0) {
chekParam.result("Value must be > 0");
return;
}
if (value===0) {
chekParam.result("This have no need to create token");
return;
}
chekParam.result(true);
} }
/**
* Check the redirection have a good form
*/
checkTTL(value: CheckerParameterType): string | undefined {
if (!isNumber(value)) {
return "Must be a number";
}
const tokenTTL = Number(value);
if (tokenTTL < 1) {
return "Minimum one day";
}
return undefined;
}
onCreateValueState(value: number) {
console.log(`changeState : ${JSON.stringify(value, null, 2)}`);
this.createTokenDisabled = value;
// we do not change the main ref ==> notify angular that something have change and need to be re-render???
this.cdr.detectChanges();
}
onCreateValueDeltaValues(value: any) {
console.log(`onDeltaValues : ${JSON.stringify(value, null, 2)}`);
this.dataCreateApplication = value;
// we do not change the main ref ==> notify angular that something have change and need to be re-render???
this.cdr.detectChanges();
}
} }

View File

@ -11,7 +11,7 @@
<th>name</th> <th>name</th>
<th>Description</th> <th>Description</th>
<th>redirect</th> <th>redirect</th>
<th>TTL</th> <th>TTL (min)</th>
<th>Notification</th> <th>Notification</th>
<th>Actions</th> <th>Actions</th>
</tr> </tr>

View File

@ -8,8 +8,9 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { ApplicationService, ApplicationModel } from 'app/service'; import { ApplicationService, ApplicationModel } from 'app/service';
import { AsyncActionState } from 'common/component'; import { AsyncActionState } from 'common/component';
import { SettingsItem, SettingType } from 'common/component/render-settings/render-settings'; import { CheckerParameterType, SettingsItem, SettingType } from 'common/component/render-settings/render-settings';
import { NotificationService, PopInService } from 'common/service'; import { NotificationService, PopInService } from 'common/service';
import { isString } from 'common/utils';
@Component({ @Component({
selector: 'application-setting', selector: 'application-setting',
@ -113,7 +114,10 @@ export class ApplicationsScene implements OnInit {
/** /**
* Check the application name is available * Check the application name is available
*/ */
checkName(value: string): string | undefined { checkName(value: CheckerParameterType): string | undefined {
if (!isString(value)) {
return "must be a string";
}
console.log(`input value : ${value}`) console.log(`input value : ${value}`)
if (value.length < 6) { if (value.length < 6) {
return "This name is too small >=6."; return "This name is too small >=6.";
@ -130,7 +134,10 @@ export class ApplicationsScene implements OnInit {
/** /**
* Check the redirection have a good form * Check the redirection have a good form
*/ */
checkRedirect(value: string): string | undefined { checkRedirect(value: CheckerParameterType): string | undefined {
if (!isString(value)) {
return "must be a string";
}
if (value.length <= 5) { if (value.length <= 5) {
return "This redirect is too small."; return "This redirect is too small.";
} }

View File

@ -5,7 +5,9 @@
<name>{{data.title}}</name> <name>{{data.title}}</name>
<description>{{data.description}}</description> <description>{{data.description}}</description>
<body> <body>
<spiner *ngIf="data.values===undefined"></spiner>
<app-render-settings <app-render-settings
*ngIf="data.values!==undefined"
[values]="data.values" [values]="data.values"
(deltaValues)="onDeltaValues($event, data)" (deltaValues)="onDeltaValues($event, data)"
(changeState)="onState($event, data)" (changeState)="onState($event, data)"

View File

@ -9,16 +9,11 @@ import { ActivatedRoute } from '@angular/router';
import { SettingsService } from 'app/service'; import { SettingsService } from 'app/service';
import { isSettingsItem, SettingsItem, SettingType } from 'common/component/render-settings/render-settings'; import { isSettingsItem, SettingsItem, SettingType } from 'common/component/render-settings/render-settings';
import { import {
isArrayOf,
isBoolean,
isInArray,
isNullOrUndefined, isNullOrUndefined,
isNumber,
isObject, isObject,
isOptionalArrayOf, isOptionalArrayOf,
isOptionalOf, isOptionalOf,
isString, isString,
isUndefined,
} from 'common/utils'; } from 'common/utils';
@ -35,6 +30,8 @@ export interface SettingsItem222 {
newValues?: object; newValues?: object;
// local state: if undefined => no change, otherwise the number of wrong values. // local state: if undefined => no change, otherwise the number of wrong values.
state?: number; state?: number;
// values get from the server.
serverValues?: object;
} }
export function isSettingsItem222(data: any): data is SettingsItem222 { export function isSettingsItem222(data: any): data is SettingsItem222 {
@ -75,47 +72,58 @@ export class SettingsScene implements OnInit {
{ {
title: 'Authentication:', title: 'Authentication:',
description: 'Manage the right of access to the web-services', description: 'Manage the right of access to the web-services',
values: [ values: undefined,
{
type: SettingType.BOOLEAN,
title: 'Enable Sign-in',
description: 'Enable User to sign-in (only authorize administrators).',
key: 'SIGN_IN_ENABLE',
value: true,
},
{
type: SettingType.LINE,
},
{
type: SettingType.BOOLEAN,
title: 'Enable Sign-up',
description: 'Enable unregister user to sign-up (register) on this web-site.',
key: 'SIGN_UP_ENABLE',
value: false,
},
{
type: SettingType.STRING,
title: 'Sign-up e-mail filter',
description: 'Specify the e-mail filtering to sign-up (regex).',
key: 'SIGN_UP_FILTER',
value: '^.*$',
},
{
type: SettingType.BOOLEAN,
title: 'e-mail validation required',
description: 'Force-user to validate his e-mail to access on service.',
key: 'EMAIL_VALIDATION_REQUIRED',
value: false,
},
],
}, },
]; ];
// this permit to clear the input menu...
configureEditInput() {
const root = this.menu[0];
root.values = [
{
type: SettingType.BOOLEAN,
title: 'Enable Sign-in',
description: 'Enable User to sign-in (only authorize administrators).',
key: 'SIGN_IN_ENABLE',
value: root.serverValues["SIGN_IN_ENABLE"],
},
{
type: SettingType.LINE,
},
{
type: SettingType.BOOLEAN,
title: 'Enable Sign-up',
description: 'Enable unregister user to sign-up (register) on this web-site.',
key: 'SIGN_UP_ENABLE',
value: root.serverValues["SIGN_UP_ENABLE"],
},
{
type: SettingType.STRING,
title: 'Sign-up e-mail filter',
description: 'Specify the e-mail filtering to sign-up (regex).',
key: 'SIGN_UP_FILTER',
value: root.serverValues["SIGN_UP_FILTER"],
},
{
type: SettingType.BOOLEAN,
title: 'e-mail validation required',
description: 'Force-user to validate his e-mail to access on service.',
key: 'EMAIL_VALIDATION_REQUIRED',
value: root.serverValues["EMAIL_VALIDATION_REQUIRED"],
},
],
this.menu[0].state = undefined;
this.menu[0].newValues = {};
}
ngOnInit() { ngOnInit() {
this.settingService this.settingService
.gets(['SIGN_IN_ENABLE', 'SIGN_UP_ENABLE', 'SIGN_UP_FILTER', 'EMAIL_VALIDATION_REQUIRED']) .gets(['SIGN_IN_ENABLE', 'SIGN_UP_ENABLE', 'SIGN_UP_FILTER', 'EMAIL_VALIDATION_REQUIRED'])
.then((response: object) => { .then((response: object) => {
console.log(`??? get full response: ${JSON.stringify(response, null, 4)}`); console.log(`??? get full response: ${JSON.stringify(response, null, 4)}`);
this.menu[0].serverValues = response;
this.configureEditInput();
}) })
.catch((error: any) => { .catch((error: any) => {
console.log(`??? get ERROR response: ${JSON.stringify(error, null, 4)}`); console.log(`??? get ERROR response: ${JSON.stringify(error, null, 4)}`);
@ -165,6 +173,7 @@ export class SettingsScene implements OnInit {
onUpdate(elem: SettingsItem222) { onUpdate(elem: SettingsItem222) {
this.settingService.sets(elem.newValues) this.settingService.sets(elem.newValues)
.then((result: object) => { .then((result: object) => {
// TODO ...
//multipleResponse.add(key, result); //multipleResponse.add(key, result);
}) })
.catch((error: any) => { .catch((error: any) => {

View File

@ -173,6 +173,26 @@ export class ApplicationService {
}); });
}); });
} }
update(id: number, updateState: object): Promise<ApplicationModel> {
return new Promise((resolve, reject) => {
this.http
.requestJson({
server: 'karso',
endPoint: `application/${id}`,
requestType: HTTPRequestModel.PUT,
accept: HTTPMimeType.JSON,
contentType: HTTPMimeType.JSON,
body:updateState,
})
.then((response: ModelResponseHttp) => {
// TODO: check type ...
resolve(response.data);
})
.catch((error: any) => {
reject(`return ERROR ${JSON.stringify(error, null, 2)}`);
});
});
}
create(name: string, redirect: string): Promise<ApplicationModel> { create(name: string, redirect: string): Promise<ApplicationModel> {
let body = { let body = {

View File

@ -0,0 +1,15 @@
<div class="top">
<input
type="text"
[placeholder]="placeholder===undefined?'':placeholder"
required=""
[style.border]="hasError||notANumber? '2px dashed red' : ''"
[(ngModel)]="value"
(input)="onChangeValue($event.target.value)" />
<button class="eye-button-2 unselectable" tabindex="-1" (click)="onDecrement()" type="submit">
<i class="material-icons">arrow_back_ios</i>
</button>
<button class="eye-button unselectable" tabindex="-1" (click)="onIncrement()" type="submit">
<i class="material-icons">arrow_forward_ios</i>
</button>
</div>

View File

@ -0,0 +1,39 @@
input {
width: 100%;
padding: 12px 20px;
margin: 8px 0;
display: inline-block;
border: 1px solid #ccc;
box-sizing: border-box;
z-index: 5;
}
.eye-button {
margin-left: -44px;
margin-top: 15px;
float: right;
position: relative;
display: block;
border: none;
z-index: 15;
background: none;
padding: 4 1 13 1;
:hover {
background: none;
color: red;
}
}
.eye-button-2 {
margin-left: -70px;
margin-top: 12px;
float: right;
position: relative;
display: block;
border: none;
z-index: 15;
background: none;
padding: 4px 30px 4px 1px;
:hover {
background: none;
color: red;
}
}

View File

@ -0,0 +1,70 @@
/** @file
* @author Edouard DUPIN
* @copyright 2018, Edouard DUPIN, all right reserved
* @license PROPRIETARY (see license file)
*/
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { isNumeric } from 'common/utils';
@Component({
selector: 'app-entry-number',
templateUrl: 'entry-number.html',
styleUrls: ['entry-number.less'],
})
export class EntryNumberComponent implements OnInit {
/// Value of the password
@Input() value: string|undefined = '';
/// Placeholder of the Value
@Input() placeholder: string|undefined = '';
/// The element has an error
@Input() hasError: boolean = false;
/// event when change the value of the password
@Output() changeValue: EventEmitter<number|undefined> = new EventEmitter();
public notANumber: boolean = false;
ngOnInit(): void {
//if (value)
}
/**
* When input value change, need update the display and change the internal value.
* @param newValue New value set on the password
*/
onChangeValue(newValue: string): void {
if (newValue === "") {
this.value = undefined;
this.notANumber = false;
this.changeValue.emit(undefined);
return;
}
this.value = newValue;
this.notANumber = false;
if (!isNumeric(this.value)) {
this.notANumber = true;
}
const numValue = Number(this.value);
this.changeValue.emit(numValue);
}
onIncrement() {
this.notANumber = false;
let newValue = undefined;
if (!isNumeric(this.value)) {
newValue = 0;
} else {
newValue = Number(this.value) + 1;
}
this.value = "" + newValue;
this.changeValue.emit(newValue);
}
onDecrement() {
this.notANumber = false;
let newValue = undefined;
if (!isNumeric(this.value)) {
newValue = 0;
} else {
newValue = Number(this.value) - 1;
}
this.value = "" + newValue;
this.changeValue.emit(newValue);
}
}

View File

@ -1,7 +1,7 @@
<div class="top"> <div class="top">
<input <input
type="text" type="text"
[placeholder]="placeholder" [placeholder]="placeholder===undefined?'':placeholder"
required="" required=""
[style.border]="hasError? '2px dashed red' : ''" [style.border]="hasError? '2px dashed red' : ''"
[value]="value===undefined?'':value" [value]="value===undefined?'':value"

View File

@ -12,9 +12,9 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
}) })
export class EntryComponent implements OnInit { export class EntryComponent implements OnInit {
/// Value of the password /// Value of the password
@Input() value: string = ''; @Input() value: string|undefined = '';
/// Placeholder of the Value /// Placeholder of the Value
@Input() placeholder: string = ''; @Input() placeholder: string|undefined = '';
/// The element has an error /// The element has an error
@Input() hasError: boolean = false; @Input() hasError: boolean = false;
/// event when change the value of the password /// event when change the value of the password

View File

@ -1,6 +1,7 @@
import { AsyncActionState, AsyncActionStatusComponent } from './async-action-status/async-status-component'; import { AsyncActionState, AsyncActionStatusComponent } from './async-action-status/async-status-component';
import { BurgerPropertyComponent } from './burger-property/burger-property'; import { BurgerPropertyComponent } from './burger-property/burger-property';
import { CheckboxComponent } from './checkbox/checkbox'; import { CheckboxComponent } from './checkbox/checkbox';
import { EntryNumberComponent } from './entry-number/entry-number';
import { EntryValidatorComponent } from './entry-validator/entry-validator'; import { EntryValidatorComponent } from './entry-validator/entry-validator';
import { EntryComponent } from './entry/entry'; import { EntryComponent } from './entry/entry';
import { ErrorMessageStateComponent } from './error-message-state/error-message-state'; import { ErrorMessageStateComponent } from './error-message-state/error-message-state';
@ -13,4 +14,4 @@ import { SpinerComponent } from './spiner/spiner';
import { TopMenuComponent } from './top-menu/top-menu'; import { TopMenuComponent } from './top-menu/top-menu';
import { UploadFileComponent } from './upload-file/upload-file'; import { UploadFileComponent } from './upload-file/upload-file';
export { BurgerPropertyComponent, CheckboxComponent, RenderFormComponent, RenderSettingsComponent, ErrorMessageStateComponent, AsyncActionState, AsyncActionStatusComponent, EntryValidatorComponent, PopInComponent, TopMenuComponent, UploadFileComponent, ErrorComponent, SpinerComponent, PasswordEntryComponent, EntryComponent }; export { BurgerPropertyComponent, EntryNumberComponent, CheckboxComponent, RenderFormComponent, RenderSettingsComponent, ErrorMessageStateComponent, AsyncActionState, AsyncActionStatusComponent, EntryValidatorComponent, PopInComponent, TopMenuComponent, UploadFileComponent, ErrorComponent, SpinerComponent, PasswordEntryComponent, EntryComponent };

View File

@ -1,7 +1,7 @@
<div class="top"> <div class="top">
<input <input
[type]="passwordVisibility?'text':'password'" [type]="passwordVisibility?'text':'password'"
[placeholder]="placeholder" [placeholder]="placeholder===undefined?'':placeholder"
required="" required=""
[style.border]="hasError? '2px dashed red' : ''" [style.border]="hasError? '2px dashed red' : ''"
[value]="value" [value]="value"

View File

@ -1,23 +1,42 @@
<table width="100%"> <table width="100%">
<tr *ngFor="let elem of values"> <tr *ngFor="let elem of values">
<td width="15%" *ngIf="elem.type !== 'LINE'" <td width="15%" *ngIf="elem.type === 'STRING' || elem.type === 'PASSWORD' || elem.type === 'NUMBER'"
[style.color]="elem.require && elem.value.length === 0 && elem.newValue === undefined ? 'red' : ''" [style.color]="getStyleRequireError(elem)"
><b>{{elem.title}}</b></td> [style.font-weight]="elem.require === true ? 'bold' : ''"
<td width="85%" *ngIf="elem.type !== 'LINE'"> >{{elem.title}}</td>
<td width="15%" *ngIf="elem.type === 'BOOLEAN'"
[style.color]="getStyleRequireError(elem)"
[style.font-weight]="elem.require === true ? 'bold' : ''"
>{{elem.title}}</td>
<td width="15%" *ngIf="elem.type === 'VALUE'"><b>{{elem.title}}</b></td>
<td width="85%" *ngIf="elem.type === 'VALUE'">{{elem.value}}</td>
<td width="85%" *ngIf="elem.type === 'STRING'">
<app-entry <app-entry
*ngIf="elem.type === 'STRING'"
[value]="elem.value" [value]="elem.value"
[placeholder]="elem.placeholder" [placeholder]="elem.placeholder"
[hasError]="elem.state !== undefined" [hasError]="checkHasError(elem)"
(changeValue)="checkParameter($event, elem)"></app-entry> (changeValue)="checkParameter($event, elem)"></app-entry>
<app-password-entry <app-error-message-state [value]="elem.state"></app-error-message-state>
*ngIf="elem.type === 'PASSWORD'" </td>
<td width="85%" *ngIf="elem.type === 'NUMBER'">
<app-entry-number
[value]="elem.value" [value]="elem.value"
[placeholder]="elem.placeholder" [placeholder]="elem.placeholder"
[hasError]="elem.state !== true" [hasError]="checkHasError(elem)"
(changeValue)="checkParameter($event, elem)"></app-entry-number>
<app-error-message-state [value]="elem.state"></app-error-message-state>
</td>
<td width="85%" *ngIf="elem.type === 'PASSWORD'">
<app-password-entry
[value]="elem.value"
[placeholder]="elem.placeholder"
[hasError]="checkHasError(elem)"
(changeValue)="checkParameter($event, elem)"></app-password-entry> (changeValue)="checkParameter($event, elem)"></app-password-entry>
<app-error-message-state [value]="elem.state"></app-error-message-state>
</td>
<td width="85%" *ngIf="elem.type === 'BOOLEAN'">
<app-checkbox <app-checkbox
*ngIf="elem.type === 'BOOLEAN'"
[value]="elem.value" [value]="elem.value"
(changeValue)="checkParameter($event, elem)"></app-checkbox> (changeValue)="checkParameter($event, elem)"></app-checkbox>
<app-error-message-state [value]="elem.state"></app-error-message-state> <app-error-message-state [value]="elem.state"></app-error-message-state>

View File

@ -7,20 +7,21 @@ import { Component, EventEmitter, Input, Output } from '@angular/core';
import { isBoolean, isInArray, isNullOrUndefined, isNumber, isObject, isOptionalOf, isString, isUndefined } from 'common/utils'; import { isBoolean, isInArray, isNullOrUndefined, isNumber, isObject, isOptionalOf, isString, isUndefined } from 'common/utils';
export type ReturnFunction = (a: boolean|string) => void; export type ReturnFunction = (a: boolean|string) => void;
export type CheckerParameterType = string | number | boolean | undefined;
// if string ==> the error, if undefined, it is OK // if string ==> the error, if undefined, it is OK
export type CheckerParameter = (value: string) => string | undefined; export type CheckerParameter = (value: CheckerParameterType) => string | undefined;
export enum SettingType { export enum SettingType {
VALUE = 'VALUE',
LINE = 'LINE', LINE = 'LINE',
BOOLEAN = 'BOOLEAN', BOOLEAN = 'BOOLEAN',
NUMBER = 'NUMBER',
STRING = 'STRING', STRING = 'STRING',
PASSWORD = 'PASSWORD', PASSWORD = 'PASSWORD',
} }
export function isSettingType(data: any): data is SettingType { export function isSettingType(data: any): data is SettingType {
return isInArray(data, ['LINE', 'BOOLEAN', 'STRING', 'PASSWORD']); return isInArray(data, ['VALUE', 'LINE', 'NUMBER', 'BOOLEAN', 'STRING', 'PASSWORD']);
} }
export interface SettingsItem { export interface SettingsItem {
@ -101,7 +102,7 @@ export class RenderSettingsComponent {
/// event with the changed values /// event with the changed values
@Output() deltaValues: EventEmitter<any> = new EventEmitter(); @Output() deltaValues: EventEmitter<any> = new EventEmitter();
createOutputValues(): any { createOutputValues(): object {
let out = {}; let out = {};
//console.log(" Create values ... out ... "); //console.log(" Create values ... out ... ");
this.values.forEach( (value) => { this.values.forEach( (value) => {
@ -129,16 +130,50 @@ export class RenderSettingsComponent {
checkMissing(): boolean | undefined { checkMissing(): boolean | undefined {
let error = 0; let error = 0;
this.values.forEach( (value) => { this.values.forEach( (elem) => {
if (value.require === true && value.value === "" && isUndefined(value.newValue) ) { if (isNumber(elem.newValue)) {
error++; if ((isUndefined(elem.newValue) && elem.value === undefined) || elem.newValue === undefined) {
error++;
}
} else {
if ((isUndefined(elem.newValue) && elem.value === "") || elem.newValue === "") {
error++;
}
} }
}); });
return error !== 0; return error !== 0;
} }
getStyleRequireError(elem): string {
if (elem.require !== true) {
return "";
}
if (isNumber(elem.newValue)) {
//console.log(`>>>>>>>>>>>>>>>>>>>>>>>>>>>>><Is a number : ${elem.newValue} ${elem.value}`)
if ((isUndefined(elem.newValue) && elem.value === undefined) || elem.newValue === undefined) {
return "red";
}
} else {
if ((isUndefined(elem.newValue) && elem.value === "") || elem.newValue === "") {
return "red";
}
}
return "";
}
checkParameter(newValue: string, item: SettingsItem): void { checkHasError(item: SettingsItem) {
if (!isNullOrUndefined(item.checker)) { if (!isUndefined(item.state)) {
return true;
}
if (item.require === true && item.value === "" && isUndefined(item.newValue)) {
return true;
}
return false;
}
checkParameter(newValue: string | number | boolean | undefined, item: SettingsItem): void {
if (isNullOrUndefined(newValue) || newValue === "") {
item.state = undefined
} else if (!isNullOrUndefined(item.checker)) {
item.state = item.checker(newValue); item.state = item.checker(newValue);
} }
if (item.value === newValue) { if (item.value === newValue) {