[DEV] upgrade jakarta add service in back, add base of interface for application edition and basic burger property

This commit is contained in:
Edouard DUPIN 2023-02-02 00:04:24 +01:00
parent a4fe1f1ed1
commit 7abf7f5674
38 changed files with 868 additions and 654 deletions

View File

@ -23,22 +23,5 @@
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="out/maven/generated-sources/annotations">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="ignore_optional_problems" value="true"/>
<attribute name="m2e-apt" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="out/maven/test-classes" path="out/maven/generated-test-sources/test-annotations">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="ignore_optional_problems" value="true"/>
<attribute name="m2e-apt" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="out/maven/classes"/>
</classpath>

View File

@ -2,8 +2,8 @@
package org.kar.karso;
import org.kar.archidata.filter.OptionFilter;
import org.kar.archidata.model.User;
import org.kar.karso.api.ApplicationResource;
import org.kar.karso.api.ApplicationTokenResource;
import org.kar.karso.api.Front;
import org.kar.karso.api.HealthCheck;
import org.kar.karso.api.PublicKeyResource;
@ -20,7 +20,6 @@ import org.kar.archidata.catcher.ExceptionCatcher;
import org.kar.archidata.catcher.FailExceptionCatcher;
import org.kar.archidata.catcher.InputExceptionCatcher;
import org.kar.archidata.catcher.SystemExceptionCatcher;
import org.kar.archidata.filter.AuthenticationFilter;
import org.kar.archidata.filter.CORSFilter;
import org.kar.archidata.util.ConfigBaseVariable;
import org.kar.archidata.util.JWTWrapper;
@ -29,7 +28,7 @@ import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.server.ResourceConfig;
import javax.ws.rs.core.UriBuilder;
import jakarta.ws.rs.core.UriBuilder;
import java.net.URI;
public class WebLauncher {
@ -58,12 +57,29 @@ public class WebLauncher {
out += SqlWrapper.createTable(UserAuth.class);
out += SqlWrapper.createTable(Application.class);
out += SqlWrapper.createTable(ApplicationToken.class);
// default admin: "karadmin" password: "adminA@666"
out += """
INSERT INTO `user` (`login`, `password`, `email`, `admin`) VALUES
('karadmin', '0ddcac5ede3f1300a1ce5948ab15112f2810130531d578ab8bc4dc131652d7cf7a3ff6e827eb957bff43bc2c65a6a1d46722e5b3a2343ac3176a33ea7250080b',
'admin@admin.ZZZ', 1);
INSERT INTO `settings` (`key`, `right`, `type`, `value`) VALUES
('SIGN_UP_ENABLE', 'rwr-r-', 'BOOLEAN', 'false'),
('SIGN_IN_ENABLE', 'rwr-r-', 'BOOLEAN', 'true'),
('SIGN_UP_FILTER', 'rw----', 'STRING', '.*'),
('EMAIL_VALIDATION_REQUIRED', 'rwr-r-', 'BOOLEAN', 'false');
""";
//out += SqlWrapper.createTable(Migration.class);
System.out.println(out);
// Do initialization or migration:
//SqlWrapper.executeSimpleQuerry(out);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// ===================================================================
// Configure resources
// ===================================================================
@ -83,6 +99,7 @@ public class WebLauncher {
rc.registerClasses(UserResource.class);
rc.registerClasses(PublicKeyResource.class);
rc.registerClasses(ApplicationResource.class);
rc.registerClasses(ApplicationTokenResource.class);
rc.registerClasses(SystemConfigResource.class);
rc.registerClasses(Front.class);
rc.registerClasses(HealthCheck.class);

View File

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

View File

@ -9,11 +9,11 @@ import org.kar.archidata.exception.InputException;
import java.util.List;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.SecurityContext;
@Path("/application")
@ -144,7 +144,7 @@ public class ApplicationResource {
public Application create(Application application) throws Exception {
System.out.println("create new application " + application);
// verify login or email is correct:
if (application.name == null || application.name.length() < 6) {
if (application.name == null || application.name.length() < 5) {
throw new InputException("name", "create application (name too small: '" + application.name + "')");
}
if (application.redirect == null || application.redirect.length() < 6) {
@ -156,7 +156,7 @@ public class ApplicationResource {
application.modify_date = null;
return SqlWrapper.insert(application);
}
@PUT
@Path("{id}")
@RolesAllowed("ADMIN")
@ -165,6 +165,12 @@ public class ApplicationResource {
SqlWrapper.update(Application.class, id, jsonRequest);
return SqlWrapper.get(Application.class, id);
}
@GET
@Path("{id}")
@RolesAllowed("ADMIN")
public Application put(@PathParam("id") Long id) throws Exception {
return SqlWrapper.get(Application.class, id);
}
}

View File

@ -1,32 +1,22 @@
package org.kar.karso.api;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.SqlWrapper;
import org.kar.archidata.WhereCondition;
import org.kar.archidata.filter.GenericContext;
import org.kar.archidata.model.Data;
import org.kar.karso.model.*;
import org.kar.archidata.util.JWTWrapper;
import org.kar.archidata.annotation.security.PermitAll;
import org.kar.archidata.annotation.security.RolesAllowed;
import org.kar.archidata.api.DataResource;
import org.kar.archidata.exception.InputException;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.List;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.SecurityContext;
@ -114,7 +104,7 @@ public class ApplicationTokenResource {
// correct input string stream :
name = multipartCorrection(name);
//validity = multipartCorrection(validity);
System.out.println("create a nexw token...");
if (applicationId == null) {
throw new InputException("applicationId", "can not be null");
}
@ -123,6 +113,7 @@ public class ApplicationTokenResource {
validity = maximum;
}
// todo: set validity timestamp ...
// TODO: check if application exist ...
ApplicationToken token = new ApplicationToken();
token.token = randomToken();
token.name = multipartCorrection(name);

View File

@ -1,6 +1,6 @@
package org.kar.karso.api;
import javax.ws.rs.*;
import jakarta.ws.rs.*;
import org.kar.archidata.api.FrontGeneric;
import org.kar.karso.util.ConfigVariable;

View File

@ -1,8 +1,8 @@
package org.kar.karso.api;
import org.kar.archidata.annotation.security.PermitAll;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
@Path("/health_check")
@Produces(MediaType.APPLICATION_JSON)

View File

@ -11,8 +11,8 @@ import org.kar.archidata.annotation.security.RolesAllowed;
import java.security.interfaces.RSAPublicKey;
import java.util.Base64;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
@Path("/public_key")
@Produces(MediaType.APPLICATION_JSON)

View File

@ -12,11 +12,11 @@ import org.kar.archidata.exception.NotFoundException;
import java.util.List;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.SecurityContext;
@Path("/system_config")

View File

@ -13,11 +13,11 @@ import org.kar.archidata.filter.GenericContext;
import org.kar.karso.model.*;
import org.kar.karso.util.ConfigVariable;
import org.kar.archidata.util.JWTWrapper;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.SecurityContext;
import java.util.List;
import java.nio.charset.StandardCharsets;

View File

@ -5,14 +5,15 @@ import java.time.Instant;
import org.kar.archidata.filter.AuthenticationFilter;
import javax.annotation.Priority;
import javax.ws.rs.Priorities;
import javax.ws.rs.ext.Provider;
import jakarta.ws.rs.Priorities;
import jakarta.ws.rs.ext.Provider;
import org.kar.archidata.SqlWrapper;
import org.kar.archidata.model.UserByToken;
import org.kar.karso.model.ApplicationToken;
import jakarta.annotation.Priority;
//@PreMatching
@Provider
@Priority(Priorities.AUTHENTICATION)

View File

@ -32,10 +32,10 @@ public class Application extends GenericTable{
@SQLNotNull
public String redirect;
@SQLLimitSize(2048)
@SQLDefault("http://localhost:4200/sso/")
@SQLDefault("'http://localhost:4200/sso/'")
public String redirectDev;
@SQLLimitSize(2048)
@SQLDefault("http://localhost:4200/sso/notification")
@SQLDefault("'http://localhost:4200/sso/notification'")
public String notification;
@SQLNotNull
@SQLComment("Expiration time ")

View File

@ -28,6 +28,7 @@ public class UserAuth extends User {
@SQLNotNull
public String email;
@SQLNotNull
@SQLDefault("'0'")
public Timestamp emailValidate; // time of validation
@SQLLimitSize(512)
public String newEmail;

View File

@ -17,7 +17,8 @@ import {
SignUpScene,
HomeUnregisteredScene,
ManageAccountsScene,
ManageApplicationScene,
ApplicationsScene,
ApplicationEditScene,
} from './scene';
import { OnlyAdminGuard, OnlyUnregisteredGuardHome, OnlyUsersGuard, OnlyUsersGuardHome } from 'common/service/session';
import { ForbiddenScene, NotFound404Scene } from 'common/scene';
@ -74,8 +75,13 @@ const routes: Routes = [
canActivate: [OnlyAdminGuard],
},
{
path: 'manage_applications',
component: ManageApplicationScene,
path: 'applications',
component: ApplicationsScene,
canActivate: [OnlyAdminGuard],
},
{
path: 'application-edit/:applicationId',
component: ApplicationEditScene,
canActivate: [OnlyAdminGuard],
},
{

View File

@ -117,7 +117,7 @@ export class AppComponent implements OnInit {
hover: 'Admin of all the applications',
icon: 'app_registration',
title: 'Manage Applications',
navigateTo: 'manage_applications',
navigateTo: 'applications',
enable: this.sessionService.userAdmin === true,
},
],

View File

@ -23,7 +23,8 @@ import {
SettingsScene,
HomeUnregisteredScene,
ManageAccountsScene,
ManageApplicationScene,
ApplicationsScene,
ApplicationEditScene,
} from 'app/scene';
import {
BddService,
@ -41,9 +42,9 @@ import {
UserService,
} from 'common/service';
import { CommonModule } from '@angular/common';
import { ErrorComponent, PopInComponent, SpinerComponent, TopMenuComponent, UploadFileComponent, PasswordEntryComponent, EntryComponent, AsyncActionStatusComponent, ErrorMessageStateComponent, CheckboxComponent } from 'common/component';
import { ErrorComponent, PopInComponent, SpinerComponent, TopMenuComponent, UploadFileComponent, PasswordEntryComponent, EntryComponent, AsyncActionStatusComponent, ErrorMessageStateComponent, CheckboxComponent, BurgerPropertyComponent } from 'common/component';
import { ForbiddenScene } from 'common/scene';
import { AdminUserService, ApplicationService, SettingsService } from 'app/service';
import { AdminUserService, ApplicationService, ApplicationTokenService, SettingsService } from 'app/service';
import { PopInUploadProgress, PopInDeleteConfirm } from 'common/popin';
@NgModule({
@ -58,6 +59,7 @@ import { PopInUploadProgress, PopInDeleteConfirm } from 'common/popin';
AsyncActionStatusComponent,
ErrorMessageStateComponent,
CheckboxComponent,
BurgerPropertyComponent,
PopInComponent,
PopInUploadProgress,
@ -76,7 +78,8 @@ import { PopInUploadProgress, PopInDeleteConfirm } from 'common/popin';
ChangePasswordScene,
HomeUnregisteredScene,
ManageAccountsScene,
ManageApplicationScene,
ApplicationsScene,
ApplicationEditScene
],
imports: [
BrowserModule,
@ -92,6 +95,7 @@ import { PopInUploadProgress, PopInDeleteConfirm } from 'common/popin';
// application
AdminUserService,
ApplicationService,
ApplicationTokenService,
// common
BddService,
@ -115,7 +119,9 @@ import { PopInUploadProgress, PopInDeleteConfirm } from 'common/popin';
PasswordEntryComponent,
UploadFileComponent,
ErrorComponent,
BurgerPropertyComponent,
BurgerPropertyComponent,
PopInComponent,
PopInUploadProgress,
PopInDeleteConfirm,

View File

@ -0,0 +1,118 @@
<div class="generic-page">
<div class="title">Configure Application</div>
<div class="fill-all">
<burger-property>
<name>Application properties</name>
<description>Update property of the application:</description>
<body>
<table width="100%">
<tr>
<td width="25%"><b>id:</b></td>
<td width="75%">{{application.id}}</td>
</tr>
<tr>
<td><b>Name:</b></td>
<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>
<footer>
<button
class="button login color-button-validate color-shadow-black"
id="create-button"
[disabled]="validateButtonCreateApplicationDisabled"
(click)="onUpdateApplication()"
type="submit">
Update
</button>
</footer>
</burger-property>
</div>
<div class="clear"><br/></div>
<div style="padding-top:15px;">
<burger-property>
<name>Associated Tokens</name>
<description>All current token available for this application</description>
<body>
<table class="table-model">
<tr>
<th width="5%">id</th>
<th width="25%">Name</th>
<th width="30%">Expiration Time</th>
<th width="40%">Token</th>
</tr>
<tr *ngFor="let token of tokens">
<td>{{token.id}}</td>
<td>{{token.name}}</td>
<td>{{formatTimestamp(user.endValidityTime)}}</td>
<td>{{token.token}}</td>
</tr>
</table>
</body>
<footer>
<button
class="button login color-button-validate color-shadow-black"
id="create-button"
(click)="createToken()"
type="submit">
+ Create new Token
</button>
</footer>
</burger-property>
</div>
<div class="clear"></div>
</div>
<!--
<delete-confirm
[comment]="confirmDeleteComment"
(callback)="deleteConfirmed()"></delete-confirm>-->

View File

@ -0,0 +1,14 @@
.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;
}

View File

@ -0,0 +1,189 @@
/** @file
* @author Edouard DUPIN
* @copyright 2018, Edouard DUPIN, all right reserved
* @license PROPRIETARY (see license file)
*/
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { ApplicationService, ApplicationModel, ApplicationTokenService } from 'app/service';
import { ApplicationTokenModel } from 'app/service/application-token';
import { AsyncActionState } from 'common/component';
import { isNumeric } from 'common/utils';
@Component({
selector: 'application-setting-edit',
templateUrl: './application-edit.html',
styleUrls: ['./application-edit.less'],
changeDetection: ChangeDetectionStrategy.Default,
})
export class ApplicationEditScene implements OnInit {
id: number = undefined
application: ApplicationModel = undefined;
applicationRef: ApplicationModel = undefined;
tokens: any = undefined;
constructor(
private applicationService: ApplicationService,
private applicationTokenService: ApplicationTokenService,
private activatedRoute: ActivatedRoute,
) {
}
ngOnInit() {
this.id = Number(this.activatedRoute.snapshot.paramMap.get('applicationId'));
let self = this;
this.applicationService
.get(this.id)
.then((response: ApplicationModel) => {
console.log(`??? get full response: ${JSON.stringify(response, null, 4)}`);
self.application = response;
self.applicationRef = { ...response };
self.checkName(self.application.name);
self.checkRedirect(self.application.redirect);
})
.catch((error: any) => {
console.log(`??? get ERROR response: ${JSON.stringify(error, null, 4)}`);
});
this.applicationTokenService
.gets(this.id)
.then((response: ApplicationTokenModel) => {
console.log(`??? get full response: ${JSON.stringify(response, null, 4)}`);
self.tokens = response;
})
.catch((error: any) => {
console.log(`??? get ERROR response: ${JSON.stringify(error, null, 4)}`);
});
}
updateDescription(newValue: string): void {
this.application.description = newValue;
this.updateButtonVisibility();
}
updateRedirectDev(newValue: string): void {
this.application.redirectDev = newValue;
this.updateButtonVisibility();
}
updateNotification(newValue: string): void {
this.application.notification = newValue;
this.updateButtonVisibility();
}
updateTTL(newValue: string): void {
if (isNumeric(newValue)) {
this.application.ttl = Number(newValue);
}
this.updateButtonVisibility();
}
public nameState: boolean|string = false;
public redirectState: boolean|string = false;
public validateButtonCreateApplicationDisabled: boolean = true;
/**
* update the state of the validation button. if all is OK, the button will became clickable
*/
updateButtonVisibility(): void {
if ( ! (this.nameState === true && this.redirectState === true ) ) {
this.validateButtonCreateApplicationDisabled = true;
return;
}
if (this.application.name !== this.applicationRef.name) {
this.validateButtonCreateApplicationDisabled = false;
return;
}
if (this.application.description !== this.applicationRef.description) {
this.validateButtonCreateApplicationDisabled = false;
return;
}
if (this.application.redirect !== this.applicationRef.redirect) {
this.validateButtonCreateApplicationDisabled = false;
return;
}
if (this.application.redirectDev !== this.applicationRef.redirectDev) {
this.validateButtonCreateApplicationDisabled = false;
return;
}
if (this.application.notification !== this.applicationRef.notification) {
this.validateButtonCreateApplicationDisabled = false;
return;
}
if (this.application.ttl !== this.applicationRef.ttl) {
this.validateButtonCreateApplicationDisabled = false;
return;
}
this.validateButtonCreateApplicationDisabled = true;
}
/**
* Check the login writing rules
*/
checkName(newValue: string): void {
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
*/
checkRedirect(newValue: string): void {
this.application.redirect = newValue;
this.redirectState = true;
if (this.application.redirect.length <= 5) {
this.redirectState = "This redirect is too small.";
}
this.updateButtonVisibility();
}
createState: string | boolean = undefined;
/**
* Request the creation of a new application.
*/
onUpdateApplication(): void {
console.log(`create user:`);
this.createState = AsyncActionState.LOADING;
let self = this;
/*
this.applicationService.create(this.name, this.redirect)
.then(
(data: ApplicationModel) => {
self.createState = AsyncActionState.DONE;
console.log(`Get new user: ${JSON.stringify(data, null, 2)}`);
////////self.applications.push(data);
self.cdr.detectChanges();
self.name = null;
self.redirect = null;
setTimeout(() => {
this.createState = undefined;
}, 3000);
}
).catch(
(error: any) => {
self.createState = AsyncActionState.FAIL;
setTimeout(() => {
self.createState = undefined;
}, 3000);
}
);
*/
}
createToken(): void {
let self = this;
this.applicationTokenService
.create(this.id, "plpolp", 953)
.then((response: ApplicationTokenModel) => {
console.log(`??? get full response: ${JSON.stringify(response, null, 4)}`);
self.tokens.append(response);
})
.catch((error: any) => {
console.log(`??? get ERROR response: ${JSON.stringify(error, null, 4)}`);
});
}
}

View File

@ -0,0 +1,92 @@
<div class="generic-page">
<div class="title">Manage Applications</div>
<div class="fill-all">
<burger-property>
<name>Applications</name>
<description>Availlable applications for this SSO</description>
<body>
<table class="table-model">
<tr>
<th>id</th>
<th>name</th>
<th>Description</th>
<th>redirect</th>
<th>TTL</th>
<th>Notification</th>
<th>Actions</th>
</tr>
<tr *ngFor="let application of applications">
<td>{{application.id}}</td>
<td>{{application.name}}</td>
<td>{{application.description}}</td>
<td>{{application.redirect}}</td>
<td>{{application.ttl}}</td>
<td>{{application.notification}}</td>
<td>
<button
class="square-button login color-shadow-black"
(click)="onEditApplication($event, application)"
type="submit">
<i class="material-icons">edit</i>
</button>&nbsp;
<button
class="square-button login color-button-cancel color-shadow-black"
(click)="onRemoveApplication($event, application)"
type="submit">
<i class="material-icons">delete_forever</i>
</button>
</td>
</tr>
</table>
</body>
</burger-property>
</div>
<div class="clear"><br/></div>
<div style="padding-top:15px;">
<burger-property>
<name>Create new application</name>
<description>Add a new application on the server</description>
<body>
<table width="100%">
<tr>
<td width="15%"><b>Name:</b></td>
<td width="85%">
<app-entry
[value]="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 width="15%"><b>Redirect:</b></td>
<td width="85%">
<app-entry
[value]="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>
</table>
</body>
<footer>
<button
class="button login color-button-validate color-shadow-black"
id="create-button"
[disabled]="validateButtonCreateApplicationDisabled"
(click)="onCreateApplication()"
type="submit">
Create application
</button>
</footer>
</burger-property>
</div>
<div class="clear"></div>
</div>
<delete-confirm
[comment]="confirmDeleteComment"
(callback)="deleteConfirmed()"></delete-confirm>

View File

@ -0,0 +1,58 @@
.elem-hr {
width: 100%;
border-color: black;
border: dashed;
border-width: 1px 0 0 0;
margin: 10px auto;
}
.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%;
}
}
.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;
}
.table-model {
tr:nth-child(odd) {
background-color: rgb(180, 180, 180);
//color: #fff;
}
th {
background-color: darkgray;
text-align: center;
}
td {
text-align: center;
}
}
table {
width: 100%;
}

View File

@ -5,22 +5,24 @@
*/
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { ApplicationService, ApplicationModel } from 'app/service';
import { AsyncActionState } from 'common/component';
import { NotificationService, PopInService } from 'common/service';
@Component({
selector: 'app-settings',
templateUrl: './manage-application.html',
styleUrls: ['./manage-application.less'],
selector: 'application-setting',
templateUrl: './applications.html',
styleUrls: ['./applications.less'],
changeDetection: ChangeDetectionStrategy.Default,
})
export class ManageApplicationScene implements OnInit {
export class ApplicationsScene implements OnInit {
applications: ApplicationModel[] = [];
constructor(
private applicationService: ApplicationService,
private notificationService: NotificationService,
private router: Router,
private popInService: PopInService,
private cdr: ChangeDetectorRef,
) {
@ -73,9 +75,8 @@ export class ManageApplicationScene implements OnInit {
}
onEditApplication(_event: any, application: ApplicationModel) {
this.router.navigate(["application-edit", application.id]);
/*
user.admin = value;
console.log(`onSetAdmin: ${value} on ${user.login}`);

View File

@ -5,12 +5,13 @@ 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 { ManageApplicationScene } from './manage-application/manage-application';
import { ApplicationsScene } from './application/applications';
import { SettingsScene } from './settings/settings';
import { SignInScene } from './sign-in/sign-in';
import { SignOutScene } from './sign-out/sign-out';
import { SignUpScene } from './sign-up/sign-up';
import { ValidateEmailScene } from './validate-email/validate-email';
import { ApplicationEditScene } from './application-edit/application-edit';
export {
ErrorViewerScene,
@ -25,5 +26,6 @@ export {
SettingsScene,
HomeUnregisteredScene,
ManageAccountsScene,
ManageApplicationScene,
ApplicationsScene,
ApplicationEditScene,
};

View File

@ -1,12 +1,10 @@
<div class="generic-page">
<div class="title">Manage User Accounts</div>
<div class="fill-all">
<div>
<div class="settings-title">
<div class="group-title">Current users</div>
<div class="group-description">List of all users</div>
</div>
<div class="settings-elements">
<burger-property>
<name>Users</name>
<description>List of all users</description>
<body>
<table class="table-model">
<tr>
<th>id</th>
@ -45,65 +43,62 @@
<td>{{formatTimestamp(user.lastConnection)}}</td>
</tr>
</table>
</div>
<div class="settings-validation">
</div>
</div>
</body>
</burger-property>
</div>
<div class="clear"><br/></div>
<div style="padding-top:15px;">
<div class="settings-title">
<div class="group-title">Create new user</div>
<div class="group-description">Add a new user on the server</div>
</div>
<div class="settings-elements">
<table>
<tr>
<td width="15%"><b>Login:</b></td>
<td width="85%">
<app-entry
[value]="login"
placeholder="Enter Username"
[hasError]="loginState !== true"
(changeValue)="checkLogin($event)"></app-entry>
<app-error-message-state [value]="loginState"></app-error-message-state>
</td>
</tr>
<tr>
<td><b>email:</b></td>
<td>
<app-entry
[value]="email"
placeholder="Enter e-mail"
[hasError]="emailState !== true"
(changeValue)="checkEmail($event)"></app-entry>
<app-error-message-state [value]="emailState"></app-error-message-state>
</td>
</tr>
<tr>
<td><b>Password:</b></td>
<td>
<app-password-entry
[value]="password"
placeholder="Enter new password (verify)"
[hasError]="passwordState !== true"
(changeValue)="checkPassword($event)"></app-password-entry>
<app-error-message-state [value]="passwordState"></app-error-message-state>
</td>
<tr>
</table>
</div>
<div class="settings-validation">
<button
class="button login color-button-validate color-shadow-black"
id="login-button"
[disabled]="validateButtonCreateUserDisabled"
(click)="onCreateUser()"
type="submit">
Create user
</button>
</div>
<burger-property>
<name>Create new user</name>
<description>Add a new user on the server</description>
<body>
<table>
<tr>
<td width="15%"><b>Login:</b></td>
<td width="85%">
<app-entry
[value]="login"
placeholder="Enter Username"
[hasError]="loginState !== true"
(changeValue)="checkLogin($event)"></app-entry>
<app-error-message-state [value]="loginState"></app-error-message-state>
</td>
</tr>
<tr>
<td><b>email:</b></td>
<td>
<app-entry
[value]="email"
placeholder="Enter e-mail"
[hasError]="emailState !== true"
(changeValue)="checkEmail($event)"></app-entry>
<app-error-message-state [value]="emailState"></app-error-message-state>
</td>
</tr>
<tr>
<td><b>Password:</b></td>
<td>
<app-password-entry
[value]="password"
placeholder="Enter new password (verify)"
[hasError]="passwordState !== true"
(changeValue)="checkPassword($event)"></app-password-entry>
<app-error-message-state [value]="passwordState"></app-error-message-state>
</td>
<tr>
</table>
</body>
<footer>
<button
class="button login color-button-validate color-shadow-black"
id="login-button"
[disabled]="validateButtonCreateUserDisabled"
(click)="onCreateUser()"
type="submit">
Create user
</button>
</footer>
</burger-property>
</div>
<div class="clear"></div>
</div>

View File

@ -1,82 +1,3 @@
.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-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;
@ -90,60 +11,6 @@
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;
}
}
.table-model {
tr:nth-child(odd) {

View File

@ -1,97 +0,0 @@
<div class="generic-page">
<div class="title">Manage Applications</div>
<div class="fill-all">
<div>
<div class="settings-title">
<div class="group-title">Application</div>
<div class="group-description">Availlable applications for this SSO</div>
</div>
<div class="settings-elements">
<table class="table-model">
<tr>
<th>id</th>
<th>name</th>
<th>Description</th>
<th>redirect</th>
<th>TTL</th>
<th>Notification</th>
<th>Actions</th>
</tr>
<tr *ngFor="let application of applications">
<td>{{application.id}}</td>
<td>{{application.name}}</td>
<td>{{application.description}}</td>
<td>{{application.redirect}}</td>
<td>{{application.ttl}}</td>
<td>{{application.notification}}</td>
<td>
<button
class="square-button login color-shadow-black"
(click)="onEditApplication($event, application)"
type="submit">
<i class="material-icons">edit</i>
</button>&nbsp;
<button
class="square-button login color-button-cancel color-shadow-black"
(click)="onRemoveApplication($event, application)"
type="submit">
<i class="material-icons">delete_forever</i>
</button>
</td>
</tr>
</table>
</div>
<div class="settings-validation">
</div>
</div>
</div>
<div class="clear"><br/></div>
<div style="padding-top:15px;">
<div class="settings-title">
<div class="group-title">Create new application</div>
<div class="group-description">Add a new application on the server</div>
</div>
<div class="settings-elements">
<table width="100%">
<tr>
<td width="15%"><b>Name:</b></td>
<td width="85%">
<app-entry
[value]="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 width="15%"><b>Redirect:</b></td>
<td width="85%">
<app-entry
[value]="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>
</table>
</div>
<div class="settings-validation">
<button
class="button login color-button-validate color-shadow-black"
id="create-button"
[disabled]="validateButtonCreateApplicationDisabled"
(click)="onCreateApplication()"
type="submit">
Create application
</button>
</div>
</div>
<div class="clear"></div>
</div>
<delete-confirm
[comment]="confirmDeleteComment"
(callback)="deleteConfirmed()"></delete-confirm>

View File

@ -1,164 +0,0 @@
.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-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;
}
}
.table-model {
tr:nth-child(odd) {
background-color: rgb(180, 180, 180);
//color: #fff;
}
th {
background-color: darkgray;
text-align: center;
}
td {
text-align: center;
}
}
table {
width: 100%;
}

View File

@ -1,13 +1,11 @@
<div class="generic-page">
<div class="title">{{menu.title}}</div>
<div class="fill-all">
<div *ngFor="let data of menu.value">
<div class="settings-title">
<div class="group-title">{{data.title}}</div>
<div class="group-description">{{data.description}}</div>
</div>
<div class="settings-elements">
<div *ngFor="let elem of data.value" class="settings-element">
<burger-property *ngFor="let data of menu.value">
<name>{{data.title}}</name>
<description>{{data.description}}</description>
<body>
<div *ngFor="let elem of data.value" class="settings-elements">
<div *ngIf="elem.type === 'LINE'">
<div class="elem-hr"></div>
</div>
@ -39,8 +37,8 @@
</div>
</div>
</div>
</div>
<div class="settings-validation">
</body>
<footer>
<button
class="button login color-button-validate color-shadow-black"
[disabled]="!data.newValue"
@ -48,8 +46,8 @@
type="submit">
Update ...
</button>
</div>
</div>
</footer>
</burger-property>
<div class="clear"></div>
</div>
</div>

View File

@ -1,44 +1,5 @@
.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;
@ -70,18 +31,6 @@
}
}
.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;
@ -95,57 +44,3 @@
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;
}
}

View File

@ -0,0 +1,96 @@
/** @file
* @author Edouard DUPIN
* @copyright 2018, Edouard DUPIN, all right reserved
* @license PROPRIETARY (see license file)
*/
import { Injectable } from '@angular/core';
import {
SessionService,
HTTPMimeType,
HTTPRequestModel,
HttpWrapperService,
ModelResponseHttp,
} from 'common/service';
export interface ApplicationTokenModel {
id: number;
name: string;
endValidityTime: string;
token?: string;
}
@Injectable()
export class ApplicationTokenService {
constructor(private http: HttpWrapperService) {
console.log('Start ApplicationTokenService');
}
gets(applicationId: number): Promise<ApplicationTokenModel> {
let self = this;
return new Promise((resolve, reject) => {
this.http
.requestJson({
server: 'karso',
endPoint: `application_token/${applicationId}`,
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON,
contentType: HTTPMimeType.JSON,
})
.then((response: ModelResponseHttp) => {
// TODO: check type ...
console.log(
`retreive Token for application : get some data to check: ${JSON.stringify(response.data)}`
);
// tODO: check the format...
resolve(response.data);
})
.catch((error: any) => {
reject(`return ERROR ${JSON.stringify(error, null, 2)}`);
});
});
}
create(applicationId: number, name: string, validity: number): Promise<ApplicationTokenModel> {
let body = {
name,
validity,
};
return new Promise((resolve, reject) => {
this.http
.requestJson({
server: 'karso',
endPoint: `application_token/${applicationId}/create`,
requestType: HTTPRequestModel.POST,
accept: HTTPMimeType.JSON,
contentType: HTTPMimeType.JSON,
body,
})
.then((response: ModelResponseHttp) => {
resolve(response.data);
})
.catch((error: any) => {
reject(`return ERROR ${JSON.stringify(error, null, 2)}`);
});
});
}
remove(applicationId: number, tokenId: number): Promise<void> {
return new Promise((resolve, reject) => {
this.http
.request({
server: 'karso',
endPoint: `application_token/${applicationId}/${tokenId}`,
requestType: HTTPRequestModel.DELETE,
accept: HTTPMimeType.ALL,
contentType: HTTPMimeType.JSON,
})
.then(() => {
resolve();
})
.catch((error: any) => {
reject(`return ERROR ${JSON.stringify(error, null, 2)}`);
});
});
}
}

View File

@ -154,6 +154,25 @@ export class ApplicationService {
});
});
}
get(id: number): Promise<ApplicationModel> {
return new Promise((resolve, reject) => {
this.http
.requestJson({
server: 'karso',
endPoint: `application/${id}`,
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON,
contentType: HTTPMimeType.JSON,
})
.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> {
let body = {

View File

@ -1,5 +1,6 @@
import { AdminUserService } from './admin-user';
import { ApplicationModel, ApplicationService } from './application';
import { ApplicationTokenService } from './application-token';
import { SettingsService } from './settings';
export { AdminUserService, ApplicationService, SettingsService, ApplicationModel };
export { AdminUserService, ApplicationService, SettingsService, ApplicationModel, ApplicationTokenService };

View File

@ -0,0 +1,13 @@
<div>
<div class="bmp-title">
<div class="title"><ng-content select="name"></ng-content></div>
<div class="description"><ng-content select="description"></ng-content></div>
</div>
<div class="bmp-elements">
<ng-content select="body"></ng-content>
</div>
<div class="bmp-validation">
<ng-content select="footer"></ng-content>
</div>
</div>

View File

@ -0,0 +1,78 @@
.bmp-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;
.title {
font-size: 24px;
font-weight: bold;
line-height: 24px;
vertical-align: middle;
margin: 10px 0 10px 0;
text-align: Left;
}
.description {
font-size: 16px;
line-height: 16px;
vertical-align: middle;
margin: 10px 0 10px 0;
text-align: Left;
}
}
.bmp-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-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%;
}
}*/
}
.bmp-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;
}

View File

@ -0,0 +1,18 @@
/** @file
* @author Edouard DUPIN
* @copyright 2020, Edouard DUPIN, all right reserved
* @license MPL-2 (see license file)
*/
import { Component } from '@angular/core';
@Component({
// moduleId: module.id.toString(),
selector: 'burger-property',
templateUrl: './burger-property.html',
styleUrls: ['./burger-property.less'],
})
export class BurgerPropertyComponent {
constructor() {}
}

View File

@ -1,4 +1,5 @@
import { AsyncActionState, AsyncActionStatusComponent } from './async-action-status/async-status-component';
import { BurgerPropertyComponent } from './burger-property/burger-property';
import { CheckboxComponent } from './checkbox/checkbox';
import { EntryComponent } from './entry/entry';
import { ErrorMessageStateComponent } from './error-message-state/error-message-state';
@ -9,4 +10,4 @@ import { SpinerComponent } from './spiner/spiner';
import { TopMenuComponent } from './top-menu/top-menu';
import { UploadFileComponent } from './upload-file/upload-file';
export { CheckboxComponent, ErrorMessageStateComponent, AsyncActionState, AsyncActionStatusComponent, PopInComponent, TopMenuComponent, UploadFileComponent, ErrorComponent, SpinerComponent, PasswordEntryComponent, EntryComponent };
export { BurgerPropertyComponent, CheckboxComponent, ErrorMessageStateComponent, AsyncActionState, AsyncActionStatusComponent, PopInComponent, TopMenuComponent, UploadFileComponent, ErrorComponent, SpinerComponent, PasswordEntryComponent, EntryComponent };

View File

@ -17,6 +17,7 @@ import {
isArrayOfs,
isInArray,
isStringNullOrUndefined,
isNumeric,
} from './validator';
import { checkEmailValidity, checkLoginValidity, checkPasswordValidity, createLoginState, createPasswordState, getLoginType } from './validatorPasswordEmail';
@ -46,5 +47,5 @@ export {
checkLoginValidity,
getLoginType,
createLoginState,
isNumeric,
};

View File

@ -1,3 +1,8 @@
export function isNumeric(val: string): boolean {
return !isNaN(Number(val));
}
export function isNumber(data: any): data is number {
return typeof data === 'number';
}