[DEV] update new archidata envirinment and karso common front update

This commit is contained in:
Edouard DUPIN 2023-05-28 21:53:13 +02:00
parent c3a80dce51
commit 3cac58cc50
105 changed files with 3195 additions and 1388 deletions

View File

@ -22,7 +22,13 @@
<dependency>
<groupId>kangaroo-and-rabbit</groupId>
<artifactId>archidata</artifactId>
<version>0.3.3</version>
<version>0.3.7</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.7</version>
<!--<scope>test</scope>-->
</dependency>
</dependencies>
@ -30,6 +36,11 @@
<sourceDirectory>src</sourceDirectory>
<testSourceDirectory>test/src</testSourceDirectory>
<directory>${project.basedir}/out/maven/</directory>
<resources>
<resource>
<directory>src/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>

View File

@ -17,77 +17,91 @@ import org.kar.karusic.api.HealthCheck;
import org.kar.karusic.api.PlaylistResource;
import org.kar.karusic.api.TrackResource;
import org.kar.karusic.api.UserResource;
import org.kar.karusic.filter.KarusicAuthenticationFilter;
import org.kar.karusic.migration.Initialization;
import org.kar.archidata.GlobalConfiguration;
import org.kar.archidata.SqlWrapper;
import org.kar.archidata.UpdateJwtPublicKey;
import org.kar.archidata.api.DataResource;
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.filter.OptionFilter;
import org.kar.archidata.migration.MigrationEngine;
import org.kar.archidata.util.ConfigBaseVariable;
import org.kar.karusic.model.Track;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
public class WebLauncher {
private WebLauncher() {
final static Logger LOGGER = LoggerFactory.getLogger(WebLauncher.class);
protected UpdateJwtPublicKey keyUpdater = null;
public WebLauncher() {
ConfigBaseVariable.bdDatabase = "karusic";
}
private static URI getBaseURI() {
return UriBuilder.fromUri(ConfigBaseVariable.getlocalAddress()).build();
}
public static void main(String[] args) {
ConfigBaseVariable.bdDatabase = "karusic";
// generate the BDD:
try {
String out = "";
//out += SqlWrapper.createTable(User.class);
out += SqlWrapper.createTable(Track.class);
// out += SqlWrapper.createTable(Artist.class);
// out += SqlWrapper.createTable(Gender.class);
// out += SqlWrapper.createTable(Playlist.class);
// out += SqlWrapper.createTable(Album.class);
System.out.println(out);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
public void migrateDB() throws Exception {
WebLauncher.LOGGER.info("Create migration engine");
MigrationEngine migrationEngine = new MigrationEngine();
WebLauncher.LOGGER.info("Add initialization");
migrationEngine.setInit(new Initialization());
WebLauncher.LOGGER.info("Add migration since last version");
// NOTHING for now
WebLauncher.LOGGER.info("Migrate the DB [START]");
migrationEngine.migrate(GlobalConfiguration.dbConfig);
WebLauncher.LOGGER.info("Migrate the DB [STOP]");
}
public static void main(String[] args) throws Exception {
WebLauncher.LOGGER.info("[START] application wake UP");
WebLauncher launcher = new WebLauncher();
launcher.migrateDB();
launcher.process();
WebLauncher.LOGGER.info("end-configure the server & wait finish process:");
Thread.currentThread().join();
WebLauncher.LOGGER.info("STOP Key updater");
launcher.stopOther();
WebLauncher.LOGGER.info("STOP the REST server:");
}
public void process() throws InterruptedException {
// ===================================================================
// Configure resources
// ===================================================================
ResourceConfig rc = new ResourceConfig();
// add multipart models ..
rc.register(new MultiPartFeature());
rc.register(MultiPartFeature.class);
// global authentication system
rc.register(new OptionFilter());
rc.register(OptionFilter.class);
// remove cors ==> all time called by an other system...
rc.register(new CORSFilter());
rc.register(CORSFilter.class);
// global authentication system
rc.registerClasses(AuthenticationFilter.class);
rc.register(KarusicAuthenticationFilter.class);
// register exception catcher
rc.register(InputExceptionCatcher.class);
rc.register(SystemExceptionCatcher.class);
rc.register(FailExceptionCatcher.class);
rc.register(ExceptionCatcher.class);
// add default resource:
rc.registerClasses(UserResource.class);
rc.registerClasses(AlbumResource.class);
rc.registerClasses(ArtistResource.class);
rc.registerClasses(GenderResource.class);
rc.registerClasses(PlaylistResource.class);
rc.registerClasses(TrackResource.class);
rc.registerClasses(DataResource.class);
rc.register(UserResource.class);
rc.register(AlbumResource.class);
rc.register(ArtistResource.class);
rc.register(GenderResource.class);
rc.register(PlaylistResource.class);
rc.register(TrackResource.class);
rc.register(DataResource.class);
rc.registerClasses(HealthCheck.class);
rc.registerClasses(Front.class);
rc.register(HealthCheck.class);
rc.register(Front.class);
// add jackson to be discovenr when we are ins standalone server
// add jackson to be discover when we are ins standalone server
rc.register(JacksonFeature.class);
// enable this to show low level request
//rc.property(LoggingFeature.LOGGING_FEATURE_LOGGER_LEVEL_SERVER, Level.WARNING.getName());
@ -112,20 +126,22 @@ public class WebLauncher {
// ===================================================================
// start periodic update of the token ...
// ===================================================================
UpdateJwtPublicKey keyUpdater = new UpdateJwtPublicKey();
keyUpdater.start();
this.keyUpdater = new UpdateJwtPublicKey();
this.keyUpdater.start();
// ===================================================================
// run JERSEY
// ===================================================================
try {
server.start();
System.out.println("Jersey app started at " + getBaseURI());
Thread.currentThread().join();
LOGGER.info("Jersey app started at {}", getBaseURI());
} catch (Exception e) {
System.out.println("There was an error while starting Grizzly HTTP server.");
LOGGER.error("There was an error while starting Grizzly HTTP server.");
e.printStackTrace();
}
}
public void stopOther() {
keyUpdater.kill();
try {
keyUpdater.join(4000, 0);

View File

@ -1,17 +1,39 @@
package org.kar.karusic;
import org.kar.archidata.util.ConfigBaseVariable;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
public class WebLauncherLocal {
public class WebLauncherLocal extends WebLauncher {
final Logger logger = LoggerFactory.getLogger(WebLauncherLocal.class);
private WebLauncherLocal() {}
public static void main(String[] args) throws InterruptedException {
WebLauncherLocal launcher = new WebLauncherLocal();
launcher.process();
launcher.logger.info("end-configure the server & wait finish process:");
Thread.currentThread().join();
launcher.logger.info("STOP the REST server:");
}
@Override
public void process() throws InterruptedException {
if (true) {
// for local test:
ConfigBaseVariable.apiAdress = "http://0.0.0.0:19080/karusic/api/";
//ConfigBaseVariable.ssoAdress = "http://localhost:15080/karso/api/";
ConfigBaseVariable.ssoAdress = "https://atria-soft.org/karso/api/";
}
WebLauncher.main(args);
try {
super.migrateDB();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
while (true) {
logger.error("Migration fail ==> waiting intervention of administrator...");
Thread.sleep(60*60*1000);
}
}
super.process();
}
}

View File

@ -4,6 +4,10 @@ import org.kar.archidata.SqlWrapper;
import org.kar.archidata.filter.GenericContext;
import org.kar.archidata.model.User;
import org.kar.karusic.model.UserKarusic;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.kar.archidata.annotation.security.RolesAllowed;
import jakarta.ws.rs.*;
@ -16,6 +20,19 @@ import java.util.List;
@Path("/users")
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public class UserResource {
final Logger logger = LoggerFactory.getLogger(UserResource.class);
@JsonInclude(JsonInclude.Include.NON_NULL)
public class UserOut {
public long id;
public String login;
public UserOut(long id, String login) {
super();
this.id = id;
this.login = login;
}
}
public UserResource() {
}
@ -42,7 +59,7 @@ public class UserResource {
System.out.println("getUser " + userId);
GenericContext gc = (GenericContext) sc.getUserPrincipal();
System.out.println("===================================================");
System.out.println("== USER ? " + gc.user);
System.out.println("== USER ? " + gc.userByToken.name);
System.out.println("===================================================");
try {
return SqlWrapper.get(UserKarusic.class, userId);
@ -53,19 +70,16 @@ public class UserResource {
return null;
}
// curl http://localhost:9993/api/users/3
@GET
@Path("me")
@RolesAllowed("USER")
public User getMe(@Context SecurityContext sc) {
System.out.println("getMe()");
public UserOut getMe(@Context SecurityContext sc) {
logger.debug("getMe()");
GenericContext gc = (GenericContext) sc.getUserPrincipal();
System.out.println("===================================================");
System.out.println("== USER ? " + gc.user);
System.out.println("===================================================");
return gc.user;
logger.debug("== USER ? {}", gc.userByToken);
return new UserOut(gc.userByToken.id, gc.userByToken.name);
}
}

View File

@ -0,0 +1,23 @@
package org.kar.karusic.filter;
import org.kar.archidata.filter.AuthenticationFilter;
import jakarta.ws.rs.Priorities;
import jakarta.ws.rs.ext.Provider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.annotation.Priority;
//@PreMatching
@Provider
@Priority(Priorities.AUTHENTICATION)
public class KarusicAuthenticationFilter extends AuthenticationFilter {
final Logger logger = LoggerFactory.getLogger(KarusicAuthenticationFilter.class);
public KarusicAuthenticationFilter() {
super("karusic");
}
}

View File

@ -0,0 +1,83 @@
package org.kar.karusic.migration;
import org.kar.archidata.migration.MigrationSqlStep;
import org.kar.archidata.model.Data;
import org.kar.archidata.model.User;
import org.kar.karusic.model.Album;
import org.kar.karusic.model.Artist;
import org.kar.karusic.model.Gender;
import org.kar.karusic.model.Playlist;
import org.kar.karusic.model.Track;
public class Initialization extends MigrationSqlStep {
public static final int KARSO_INITIALISATION_ID = 1;
@Override
public String getName() {
return "Initialization";
}
public Initialization() throws Exception {
addClass(Album.class);
addClass(Artist.class);
addClass(Data.class);
addClass(Gender.class);
addClass(Playlist.class);
addClass(Track.class);
addClass(User.class);
addAction("""
INSERT INTO `gender` (`id`, `name`, `description`) VALUES
(1, 'Variété française', NULL),
(2, 'Pop', NULL),
(3, 'inconnue', NULL),
(4, 'Disco', NULL),
(5, 'Enfants', NULL),
(6, 'Portugaise', NULL),
(7, 'Apprentissage', NULL),
(8, 'Blues', NULL),
(9, 'Jazz', NULL),
(10, 'Chanson Noël', NULL),
(11, 'DubStep', NULL),
(12, 'Rap français', NULL),
(13, 'Classique', NULL),
(14, 'Rock', NULL),
(15, 'Electro', NULL),
(16, 'Celtique', NULL),
(17, 'Country', NULL),
(18, 'Variété Québéquoise', NULL),
(19, 'Médiéval', NULL),
(20, 'Variété Italienne', NULL),
(21, 'Comédie Musicale', NULL),
(22, 'Vianney', NULL),
(23, 'Bande Original', NULL),
(24, 'Bande Originale', NULL),
(25, 'Variété Belge', NULL),
(26, 'Gospel', NULL);
""");
// set start increment element to permit to add after default elements
addAction("""
ALTER TABLE `album` AUTO_INCREMENT = 1000;
""");
addAction("""
ALTER TABLE `artist` AUTO_INCREMENT = 1000;
""");
addAction("""
ALTER TABLE `data` AUTO_INCREMENT = 1000;
""");
addAction("""
ALTER TABLE `gender` AUTO_INCREMENT = 1000;
""");
addAction("""
ALTER TABLE `playlist` AUTO_INCREMENT = 1000;
""");
addAction("""
ALTER TABLE `track` AUTO_INCREMENT = 1000;
""");
addAction("""
ALTER TABLE `user` AUTO_INCREMENT = 1000;
""");
}
}

View File

@ -0,0 +1,35 @@
# SLF4J's SimpleLogger configuration file
# Simple implementation of Logger that sends all enabled log messages, for all defined loggers, to System.err.
# Default logging detail level for all instances of SimpleLogger.
# Must be one of ("trace", "debug", "info", "warn", or "error").
# If not specified, defaults to "info".
org.slf4j.simpleLogger.defaultLogLevel=trace
# Logging detail level for a SimpleLogger instance named "xxxxx".
# Must be one of ("trace", "debug", "info", "warn", or "error").
# If not specified, the default logging detail level is used.
#org.slf4j.simpleLogger.log.xxxxx=
# Set to true if you want the current date and time to be included in output messages.
# Default is false, and will output the number of milliseconds elapsed since startup.
#org.slf4j.simpleLogger.showDateTime=false
# The date and time format to be used in the output messages.
# The pattern describing the date and time format is the same that is used in java.text.SimpleDateFormat.
# If the format is not specified or is invalid, the default format is used.
# The default format is yyyy-MM-dd HH:mm:ss:SSS Z.
#org.slf4j.simpleLogger.dateTimeFormat=yyyy-MM-dd HH:mm:ss:SSS Z
# Set to true if you want to output the current thread name.
# Defaults to true.
org.slf4j.simpleLogger.showThreadName=true
# Set to true if you want the Logger instance name to be included in output messages.
# Defaults to true.
#org.slf4j.simpleLogger.showLogName=true
# Set to true if you want the last component of the name to be included in output messages.
# Defaults to false.
#org.slf4j.simpleLogger.showShortLogName=false

View File

@ -10,6 +10,7 @@ import { MenuItem, MenuPosition } from 'common/model';
import { UserService, SessionService, SSOService } from 'common/service';
import { isNullOrUndefined } from 'common/utils';
import { ArianeService } from './service';
import { UserRoles222 } from 'common/service/session';
enum MenuEventType {
SSO_LOGIN = "SSO_CALL_LOGIN",
@ -220,7 +221,7 @@ export class AppComponent implements OnInit {
icon: "add_circle",
title: "Add media",
navigateTo: "upload",
enable: this.sessionService.userAdmin === true,
enable: this.sessionService.hasRight(UserRoles222.admin),
}, {
position: MenuPosition.LEFT,
icon: "settings",

View File

@ -11,7 +11,7 @@ import { HttpClientModule } from '@angular/common/http';
import { FormsModule, ReactiveFormsModule } from '@angular/forms'; // this is needed for dynamic selection of the select
import { AppRoutingModule } from './app-routing.module';
import { ErrorComponent, PopInComponent, TopMenuComponent, UploadFileComponent } from 'common/component/';
import { AsyncActionStatusComponent, BurgerPropertyComponent, CheckboxComponent, EntryComponent, EntryNumberComponent, EntryValidatorComponent, ErrorComponent, ErrorMessageStateComponent, PasswordEntryComponent, PopInComponent, RenderFormComponent, RenderSettingsComponent, SpinerComponent, TopMenuComponent, UploadFileComponent } from 'common/component/';
import { ElementDataImageComponent } from './component/data-image/data-image';
import { ElementTypeComponent } from './component/element-type/element-type';
@ -19,8 +19,10 @@ import { PopInCreateType } from './popin/create-type/create-type';
import { PopInDeleteConfirm, PopInUploadProgress } from 'common/popin';
import { AppComponent } from './app.component';
import { HomeScene, HelpScene, GenderScene, PlaylistScene, ArtistScene, AlbumScene, AlbumsScene, TrackScene, SettingsScene,
TrackEditScene, AlbumEditScene, ArtistEditScene, ArtistsScene, ArtistAlbumScene } from './scene';
import {
HomeScene, HelpScene, GenderScene, PlaylistScene, ArtistScene, AlbumScene, AlbumsScene, TrackScene, SettingsScene,
TrackEditScene, AlbumEditScene, ArtistEditScene, ArtistsScene, ArtistAlbumScene
} from './scene';
import { GenderService, DataService, PlaylistService, ArtistService, AlbumService, TrackService, ArianeService, PlayerService } from './service';
import { BddService, CookiesService, HttpWrapperService, OnlyAdminGuard, OnlyUnregisteredGuardHome, OnlyUsersGuard, OnlyUsersGuardHome, PopInService, SessionService, SSOService, StorageService, UserService } from 'common/service';
import { ErrorViewerScene, ForbiddenScene, HomeOutScene, NotFound404Scene, SsoScene } from 'common/scene';
@ -40,6 +42,17 @@ import { ElementSeriesComponent, ElementTrackComponent, ElementSeasonComponent,
ElementVideoComponent,
ElementPlayerAudioComponent,
ErrorComponent,
PasswordEntryComponent,
EntryComponent,
EntryValidatorComponent,
SpinerComponent,
AsyncActionStatusComponent,
ErrorMessageStateComponent,
CheckboxComponent,
BurgerPropertyComponent,
RenderSettingsComponent,
RenderFormComponent,
EntryNumberComponent,
PopInComponent,
PopInCreateType,
@ -116,9 +129,11 @@ import { ElementSeriesComponent, ElementTrackComponent, ElementSeasonComponent,
bootstrap: [
AppComponent
],
/*
schemas: [
CUSTOM_ELEMENTS_SCHEMA,
NO_ERRORS_SCHEMA
]
*/
})
export class AppModule { }

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48"><path d="M24 44q-4.15 0-7.8-1.575-3.65-1.575-6.35-4.275-2.7-2.7-4.275-6.35Q4 28.15 4 24t1.575-7.8Q7.15 12.55 9.85 9.85q2.7-2.7 6.35-4.275Q19.85 4 24 4t7.8 1.575q3.65 1.575 6.35 4.275 2.7 2.7 4.275 6.35Q44 19.85 44 24t-1.575 7.8q-1.575 3.65-4.275 6.35-2.7 2.7-6.35 4.275Q28.15 44 24 44Zm0-3q7.1 0 12.05-4.95Q41 31.1 41 24q0-3.05-1.05-5.85T37 13.05L13.05 37q2.25 1.95 5.075 2.975Q20.95 41 24 41Zm-12.95-6.05 23.9-23.9q-2.3-1.95-5.1-3T24 7q-7.1 0-12.05 4.95Q7 16.9 7 24q0 3.05 1.1 5.875t2.95 5.075Z"/></svg>

After

Width:  |  Height:  |  Size: 567 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48"><path d="M25.5 19.5V6H42v13.5ZM6 25.5V6h16.5v19.5ZM25.5 42V22.5H42V42ZM6 42V28.5h16.5V42Zm3-19.5h10.5V9H9ZM28.5 39H39V25.5H28.5Zm0-22.5H39V9H28.5ZM9 39h10.5v-7.5H9Zm10.5-16.5Zm9-6Zm0 9Zm-9 6Z"/></svg>

After

Width:  |  Height:  |  Size: 263 B

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
height="48"
width="48"
version="1.1"
id="svg1543"
sodipodi:docname="group.svg"
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14, custom)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs1547" />
<sodipodi:namedview
id="namedview1545"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
inkscape:zoom="21.395833"
inkscape:cx="24"
inkscape:cy="24"
inkscape:window-width="3838"
inkscape:window-height="2118"
inkscape:window-x="0"
inkscape:window-y="20"
inkscape:window-maximized="1"
inkscape:current-layer="svg1543" />
<path
d="M1.9 40v-4.7q0-1.75.9-3.175Q3.7 30.7 5.3 30q3.65-1.6 6.575-2.3Q14.8 27 17.9 27q3.1 0 6 .7t6.55 2.3q1.6.7 2.525 2.125.925 1.425.925 3.175V40Zm35 0v-4.7q0-3.15-1.6-5.175t-4.2-3.275q3.45.4 6.5 1.175t4.95 1.775q1.65.95 2.6 2.35.95 1.4.95 3.15V40Zm-19-16.05q-3.3 0-5.4-2.1-2.1-2.1-2.1-5.4 0-3.3 2.1-5.4 2.1-2.1 5.4-2.1 3.3 0 5.4 2.1 2.1 2.1 2.1 5.4 0 3.3-2.1 5.4-2.1 2.1-5.4 2.1Zm18-7.5q0 3.3-2.1 5.4-2.1 2.1-5.4 2.1-.55 0-1.225-.075T25.95 23.6q1.2-1.25 1.825-3.075.625-1.825.625-4.075t-.625-3.975Q27.15 10.75 25.95 9.3q.55-.15 1.225-.25t1.225-.1q3.3 0 5.4 2.1 2.1 2.1 2.1 5.4ZM4.9 37h26v-1.7q0-.8-.475-1.55T29.25 32.7q-3.6-1.6-6.05-2.15-2.45-.55-5.3-.55-2.85 0-5.325.55T6.5 32.7q-.7.3-1.15 1.05-.45.75-.45 1.55Zm13-16.05q1.95 0 3.225-1.275Q22.4 18.4 22.4 16.45q0-1.95-1.275-3.225Q19.85 11.95 17.9 11.95q-1.95 0-3.225 1.275Q13.4 14.5 13.4 16.45q0 1.95 1.275 3.225Q15.95 20.95 17.9 20.95Zm0 16.05Zm0-20.55Z"
id="path1541"
style="fill:#ffffff;fill-opacity:1" />
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
height="48"
width="48"
version="1.1"
id="svg4"
sodipodi:docname="lan.svg"
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14, custom)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs8" />
<sodipodi:namedview
id="namedview6"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
inkscape:zoom="16.822701"
inkscape:cx="12.691184"
inkscape:cy="39.737971"
inkscape:window-width="3838"
inkscape:window-height="2118"
inkscape:window-x="0"
inkscape:window-y="20"
inkscape:window-maximized="1"
inkscape:current-layer="svg4" />
<rect
style="fill:#000000;stroke:#ffffff;stroke-width:3;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1"
id="rect897"
width="12.08835"
height="10.642548"
x="17.961397"
y="5.4625888" />
<rect
style="fill:#000000;stroke:#ffffff;stroke-width:3;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1"
id="rect897-3"
width="12.08835"
height="10.642548"
x="7.428793"
y="32.038437" />
<rect
style="fill:#000000;stroke:#ffffff;stroke-width:3;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1"
id="rect897-6"
width="12.08835"
height="10.642548"
x="28.561865"
y="31.936249" />
<path
style="fill:none;stroke:#ffffff;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-dasharray:none"
d="m 13.584028,32.01093 v -7.707304 h 20.889927 v 7.894963"
id="path990" />
<path
style="fill:none;stroke:#ffffff;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-dasharray:none"
d="M 24.032132,23.799058 V 16.118716"
id="path992" />
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
height="48"
width="48"
version="1.1"
id="svg1004"
sodipodi:docname="person.svg"
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14, custom)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs1008" />
<sodipodi:namedview
id="namedview1006"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
inkscape:zoom="21.395833"
inkscape:cx="24"
inkscape:cy="24"
inkscape:window-width="3838"
inkscape:window-height="2118"
inkscape:window-x="0"
inkscape:window-y="20"
inkscape:window-maximized="1"
inkscape:current-layer="svg1004" />
<path
d="M24 23.95q-3.3 0-5.4-2.1-2.1-2.1-2.1-5.4 0-3.3 2.1-5.4 2.1-2.1 5.4-2.1 3.3 0 5.4 2.1 2.1 2.1 2.1 5.4 0 3.3-2.1 5.4-2.1 2.1-5.4 2.1ZM8 40v-4.7q0-1.9.95-3.25T11.4 30q3.35-1.5 6.425-2.25Q20.9 27 24 27q3.1 0 6.15.775 3.05.775 6.4 2.225 1.55.7 2.5 2.05.95 1.35.95 3.25V40Zm3-3h26v-1.7q0-.8-.475-1.525-.475-.725-1.175-1.075-3.2-1.55-5.85-2.125Q26.85 30 24 30t-5.55.575q-2.7.575-5.85 2.125-.7.35-1.15 1.075Q11 34.5 11 35.3Zm13-16.05q1.95 0 3.225-1.275Q28.5 18.4 28.5 16.45q0-1.95-1.275-3.225Q25.95 11.95 24 11.95q-1.95 0-3.225 1.275Q19.5 14.5 19.5 16.45q0 1.95 1.275 3.225Q22.05 20.95 24 20.95Zm0-4.5ZM24 37Z"
id="path1002"
style="stroke:none;stroke-opacity:1;fill:#ffffff;fill-opacity:1" />
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48"><path d="m19.4 44-1-6.3q-.95-.35-2-.95t-1.85-1.25l-5.9 2.7L4 30l5.4-3.95q-.1-.45-.125-1.025Q9.25 24.45 9.25 24q0-.45.025-1.025T9.4 21.95L4 18l4.65-8.2 5.9 2.7q.8-.65 1.85-1.25t2-.9l1-6.35h9.2l1 6.3q.95.35 2.025.925Q32.7 11.8 33.45 12.5l5.9-2.7L44 18l-5.4 3.85q.1.5.125 1.075.025.575.025 1.075t-.025 1.05q-.025.55-.125 1.05L44 30l-4.65 8.2-5.9-2.7q-.8.65-1.825 1.275-1.025.625-2.025.925l-1 6.3ZM24 30.5q2.7 0 4.6-1.9 1.9-1.9 1.9-4.6 0-2.7-1.9-4.6-1.9-1.9-4.6-1.9-2.7 0-4.6 1.9-1.9 1.9-1.9 4.6 0 2.7 1.9 4.6 1.9 1.9 4.6 1.9Zm0-3q-1.45 0-2.475-1.025Q20.5 25.45 20.5 24q0-1.45 1.025-2.475Q22.55 20.5 24 20.5q1.45 0 2.475 1.025Q27.5 22.55 27.5 24q0 1.45-1.025 2.475Q25.45 27.5 24 27.5Zm0-3.5Zm-2.2 17h4.4l.7-5.6q1.65-.4 3.125-1.25T32.7 32.1l5.3 2.3 2-3.6-4.7-3.45q.2-.85.325-1.675.125-.825.125-1.675 0-.85-.1-1.675-.1-.825-.35-1.675L40 17.2l-2-3.6-5.3 2.3q-1.15-1.3-2.6-2.175-1.45-.875-3.2-1.125L26.2 7h-4.4l-.7 5.6q-1.7.35-3.175 1.2-1.475.85-2.625 2.1L10 13.6l-2 3.6 4.7 3.45q-.2.85-.325 1.675-.125.825-.125 1.675 0 .85.125 1.675.125.825.325 1.675L8 30.8l2 3.6 5.3-2.3q1.2 1.2 2.675 2.05Q19.45 35 21.1 35.4Z"/></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,3 @@
<div>
<img height="50px" [src]="getImage()"/>
</div>

View File

@ -0,0 +1,68 @@
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { PasswordEntryComponent } from './async-status-component';
describe('PasswordEntryComponent global test', () => {
let component: PasswordEntryComponent;
let fixture: ComponentFixture<PasswordEntryComponent>;
let input: HTMLInputElement;
let button: HTMLButtonElement;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [PasswordEntryComponent],
}).compileComponents();
fixture = TestBed.createComponent(PasswordEntryComponent);
component = fixture.componentInstance;
input = fixture.nativeElement.querySelector('div').querySelector('input');
button = fixture.nativeElement.querySelector('div').querySelector('button');
});
it('Test mode password (default)', () => {
fixture.detectChanges();
expect(input.textContent).toEqual('');
expect(button.textContent).toEqual('visibility_off');
expect(input.type).toEqual('password');
});
it('Test mode text', () => {
component.passwordVisibility = true;
fixture.detectChanges();
expect(input.textContent).toEqual('');
expect(button.textContent).toEqual('visibility');
expect(input.type).toEqual('text');
});
it('test click on hide button', fakeAsync(() => {
fixture.detectChanges();
expect(component.passwordVisibility).toEqual(false);
button.click();
tick();
fixture.detectChanges();
expect(component.passwordVisibility).toEqual(true);
expect(button.textContent).toEqual('visibility');
expect(input.type).toEqual('text');
button.click();
tick();
fixture.detectChanges();
expect(component.passwordVisibility).toEqual(false);
expect(button.textContent).toEqual('visibility_off');
expect(input.type).toEqual('password');
}));
it('Set password', fakeAsync(() => {
fixture.detectChanges();
expect(component.passwordVisibility).toEqual(false);
let tmpData = 'My beautifull Password';
input.value = tmpData;
input.dispatchEvent(new Event('input'));
fixture.detectChanges();
expect(input.textContent).toEqual(tmpData);
expect(component.value).toEqual(tmpData);
tmpData = '';
input.value = tmpData;
input.dispatchEvent(new Event('input'));
fixture.detectChanges();
expect(input.textContent).toEqual(tmpData);
expect(component.value).toEqual(tmpData);
}));
});

View File

@ -0,0 +1,37 @@
/** @file
* @author Edouard DUPIN
* @copyright 2018, Edouard DUPIN, all right reserved
* @license PROPRIETARY (see license file)
*/
import { Component, Input } from '@angular/core';
export enum AsyncActionState {
IDLE = "idle",
LOADING = "loading",
DONE = "done",
FAIL = "fail",
}
@Component({
selector: 'app-async-status-component',
templateUrl: 'async-status-component.html',
styleUrls: ['async-status-component.less'],
})
export class AsyncActionStatusComponent {
/// Value of the password
@Input() value: AsyncActionState = AsyncActionState.IDLE;
public getImage(): string {
switch(this.value) {
case AsyncActionState.IDLE:
return '';
case AsyncActionState.LOADING:
return 'assets/images/load.svg';
case AsyncActionState.DONE:
return 'assets/images/validate.svg';
case AsyncActionState.FAIL:
return 'assets/images/validate-not.svg';
}
}
}

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

@ -0,0 +1,7 @@
<div class="elem-checkbox">
<input
type="checkbox"
[checked]="value"
(change)="onChange($event.target.checked)" />
{{comment}}
</div>

View File

@ -0,0 +1,6 @@
.elem-checkbox {
font-size: 18px;
font-weight: bold;
margin: 0 10px 0 10px;
}

View File

@ -0,0 +1,29 @@
/** @file
* @author Edouard DUPIN
* @copyright 2018, Edouard DUPIN, all right reserved
* @license PROPRIETARY (see license file)
*/
import { Component, EventEmitter, Input, Output } from '@angular/core';
@Component({
selector: 'app-checkbox',
templateUrl: 'checkbox.html',
styleUrls: ['checkbox.less'],
})
export class CheckboxComponent {
/// Checkbox value
@Input() value: boolean = false;
/// Description of the checkbox
@Input() comment: string = "";
/// event when change the value of the password
@Output() changeValue: EventEmitter<boolean> = new EventEmitter();
/**
* When input value change, need update the display and change the internal value.
* @param newValue New value set on the password
*/
onChange(newValue: boolean): void {
this.value = newValue;
this.changeValue.emit(this.value);
}
}

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

@ -0,0 +1,8 @@
<div>
<app-entry
[value]="value"
[placeholder]="placeholder"
[hasError]="state !== true"
(changeValue)="check($event)"></app-entry>
<app-error-message-state [value]="state"></app-error-message-state>
</div>

View File

@ -0,0 +1,9 @@
input[type='text'] {
width: 100%;
padding: 12px 20px;
margin: 8px 0;
display: inline-block;
border: 1px solid #ccc;
box-sizing: border-box;
z-index: 5;
}

View File

@ -0,0 +1,59 @@
/** @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 { isNullOrUndefined } from 'common/utils';
export type ReturnFunction = (a: boolean|string) => void;
export type CheckerParameter = {
value: string,
result: ReturnFunction
}
@Component({
selector: 'app-entry-validator',
templateUrl: 'entry-validator.html',
styleUrls: ['entry-validator.less'],
})
export class EntryValidatorComponent implements OnInit {
/// Value of the password
@Input() value: string = '';
/// Placeholder of the Value
@Input() placeholder: string = '';
/// The element has an error
@Output() checker: EventEmitter<CheckerParameter> = new EventEmitter();
/// event when change the value of the password
@Output() changeValue: EventEmitter<string> = new EventEmitter();
public state: boolean|string = false;
ngOnInit(): void {
//if (value)
}
updateStatus(value: boolean|string): void {
this.state = value
if (this.state === true) {
this.changeValue.emit(this.value);
}
}
check(newValue: string): void {
let self = this;
let lambdaCallBack = (value: boolean|string) => {self.updateStatus(value)};
this.value = newValue;
if (isNullOrUndefined(this.checker)) {
this.changeValue.emit(this.value);
return;
}
this.checker.emit({
value: newValue,
result: lambdaCallBack,
});
}
}

View File

@ -0,0 +1,9 @@
<div class="top">
<input
type="text"
[placeholder]="placeholder===undefined?'':placeholder"
required=""
[style.border]="hasError? '2px dashed red' : ''"
[value]="value===undefined?'':value"
(input)="onChangeValue($event.target.value)" />
</div>

View File

@ -0,0 +1,9 @@
input[type='text'] {
width: 100%;
padding: 12px 20px;
margin: 8px 0;
display: inline-block;
border: 1px solid #ccc;
box-sizing: border-box;
z-index: 5;
}

View File

@ -0,0 +1,68 @@
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { PasswordEntryComponent } from './entry';
describe('PasswordEntryComponent global test', () => {
let component: PasswordEntryComponent;
let fixture: ComponentFixture<PasswordEntryComponent>;
let input: HTMLInputElement;
let button: HTMLButtonElement;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [PasswordEntryComponent],
}).compileComponents();
fixture = TestBed.createComponent(PasswordEntryComponent);
component = fixture.componentInstance;
input = fixture.nativeElement.querySelector('div').querySelector('input');
button = fixture.nativeElement.querySelector('div').querySelector('button');
});
it('Test mode password (default)', () => {
fixture.detectChanges();
expect(input.textContent).toEqual('');
expect(button.textContent).toEqual('visibility_off');
expect(input.type).toEqual('password');
});
it('Test mode text', () => {
component.passwordVisibility = true;
fixture.detectChanges();
expect(input.textContent).toEqual('');
expect(button.textContent).toEqual('visibility');
expect(input.type).toEqual('text');
});
it('test click on hide button', fakeAsync(() => {
fixture.detectChanges();
expect(component.passwordVisibility).toEqual(false);
button.click();
tick();
fixture.detectChanges();
expect(component.passwordVisibility).toEqual(true);
expect(button.textContent).toEqual('visibility');
expect(input.type).toEqual('text');
button.click();
tick();
fixture.detectChanges();
expect(component.passwordVisibility).toEqual(false);
expect(button.textContent).toEqual('visibility_off');
expect(input.type).toEqual('password');
}));
it('Set password', fakeAsync(() => {
fixture.detectChanges();
expect(component.passwordVisibility).toEqual(false);
let tmpData = 'My beautifull Password';
input.value = tmpData;
input.dispatchEvent(new Event('input'));
fixture.detectChanges();
expect(input.textContent).toEqual(tmpData);
expect(component.value).toEqual(tmpData);
tmpData = '';
input.value = tmpData;
input.dispatchEvent(new Event('input'));
fixture.detectChanges();
expect(input.textContent).toEqual(tmpData);
expect(component.value).toEqual(tmpData);
}));
});

View File

@ -0,0 +1,35 @@
/** @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';
@Component({
selector: 'app-entry',
templateUrl: 'entry.html',
styleUrls: ['entry.less'],
})
export class EntryComponent 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<string> = new EventEmitter();
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 {
this.value = newValue;
this.changeValue.emit(this.value);
}
}

View File

@ -0,0 +1 @@
<div class="error color-shadow-black" *ngIf="value !== true && value !== false && value !== undefined">{{value}}</div>

View File

@ -0,0 +1,34 @@
.error {
background-color: #f44336;
position: absolute;
z-index: 10;
display: block;
max-width: 450px;
padding: 5px 8px;
margin: 2px 0 0;
font-size: 16px;
font-weight: 400;
border-style: solid;
border-width: 0px;
box-sizing: border-box;
&:after,
&:before {
bottom: 100%;
left: 25px;
border: solid transparent;
content: ' ';
height: 0;
width: 0;
position: absolute;
pointer-events: none;
}
&:after {
border-bottom-color: #f44336;
border-width: 10px;
margin-left: -10px;
}
}

View File

@ -0,0 +1,17 @@
/** @file
* @author Edouard DUPIN
* @copyright 2018, Edouard DUPIN, all right reserved
* @license PROPRIETARY (see license file)
*/
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-error-message-state',
templateUrl: 'error-message-state.html',
styleUrls: ['error-message-state.less'],
})
export class ErrorMessageStateComponent {
/// Value of the password
@Input() value: boolean|string = false;
}

View File

@ -1,3 +1 @@
<p>
error works!
</p>
<p>error works!</p>

View File

@ -9,11 +9,10 @@ import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-error',
templateUrl: './error.html',
styleUrls: [ './error.less' ]
styleUrls: ['./error.less'],
})
export class ErrorComponent implements OnInit {
constructor() {}
ngOnInit() {
}
ngOnInit() {}
}

View File

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

View File

@ -0,0 +1,12 @@
<div class="top">
<input
[type]="passwordVisibility?'text':'password'"
[placeholder]="placeholder===undefined?'':placeholder"
required=""
[style.border]="hasError? '2px dashed red' : ''"
[value]="value"
(input)="onChangeValue($event.target.value)" />
<button class="eye-button unselectable" tabindex="-1" (click)="onVisibility()" type="submit">
<i class="material-icons">{{passwordVisibility?"visibility":"visibility_off"}}</i>
</button>
</div>

View File

@ -0,0 +1,25 @@
.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;
}
}
input[type='text'],
input[type='password'] {
width: 100%;
padding: 12px 20px;
margin: 8px 0;
display: inline-block;
border: 1px solid #ccc;
box-sizing: border-box;
z-index: 5;
}

View File

@ -0,0 +1,68 @@
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { PasswordEntryComponent } from './password-entry';
describe('PasswordEntryComponent global test', () => {
let component: PasswordEntryComponent;
let fixture: ComponentFixture<PasswordEntryComponent>;
let input: HTMLInputElement;
let button: HTMLButtonElement;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [PasswordEntryComponent],
}).compileComponents();
fixture = TestBed.createComponent(PasswordEntryComponent);
component = fixture.componentInstance;
input = fixture.nativeElement.querySelector('div').querySelector('input');
button = fixture.nativeElement.querySelector('div').querySelector('button');
});
it('Test mode password (default)', () => {
fixture.detectChanges();
expect(input.textContent).toEqual('');
expect(button.textContent).toEqual('visibility_off');
expect(input.type).toEqual('password');
});
it('Test mode text', () => {
component.passwordVisibility = true;
fixture.detectChanges();
expect(input.textContent).toEqual('');
expect(button.textContent).toEqual('visibility');
expect(input.type).toEqual('text');
});
it('test click on hide button', fakeAsync(() => {
fixture.detectChanges();
expect(component.passwordVisibility).toEqual(false);
button.click();
tick();
fixture.detectChanges();
expect(component.passwordVisibility).toEqual(true);
expect(button.textContent).toEqual('visibility');
expect(input.type).toEqual('text');
button.click();
tick();
fixture.detectChanges();
expect(component.passwordVisibility).toEqual(false);
expect(button.textContent).toEqual('visibility_off');
expect(input.type).toEqual('password');
}));
it('Set password', fakeAsync(() => {
fixture.detectChanges();
expect(component.passwordVisibility).toEqual(false);
let tmpData = 'My beautifull Password';
input.value = tmpData;
input.dispatchEvent(new Event('input'));
fixture.detectChanges();
expect(input.textContent).toEqual(tmpData);
expect(component.value).toEqual(tmpData);
tmpData = '';
input.value = tmpData;
input.dispatchEvent(new Event('input'));
fixture.detectChanges();
expect(input.textContent).toEqual(tmpData);
expect(component.value).toEqual(tmpData);
}));
});

View File

@ -0,0 +1,39 @@
/** @file
* @author Edouard DUPIN
* @copyright 2018, Edouard DUPIN, all right reserved
* @license PROPRIETARY (see license file)
*/
import { Component, EventEmitter, Input, Output } from '@angular/core';
@Component({
selector: 'app-password-entry',
templateUrl: 'password-entry.html',
styleUrls: ['password-entry.less'],
})
export class PasswordEntryComponent {
/// Value of the password
@Input() value: string = '';
/// Placeholder of the Value
@Input() placeholder: string = 'Write password.';
/// The element has an error
@Input() hasError: boolean = false;
/// event when change the value of the password
@Output() changeValue: EventEmitter<string> = new EventEmitter();
/// Local value of the password viwibility
public passwordVisibility: boolean = false;
/**
* Ov visibility request change (toggle the visibility)
*/
onVisibility(): void {
this.passwordVisibility = !this.passwordVisibility;
}
/**
* 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 {
this.value = newValue;
this.changeValue.emit(this.value);
}
}

View File

@ -5,14 +5,13 @@
*/
import { Component, Input, Output, OnInit, OnDestroy, EventEmitter } from '@angular/core';
import { PopInService } from 'common/service';
@Component({
// moduleId: module.id.toString(),
selector: 'app-popin',
templateUrl: './popin.html',
styleUrls: [ './popin.less' ]
styleUrls: ['./popin.less'],
})
export class PopInComponent implements OnInit, OnDestroy {
@Input() id: string;
@ -28,9 +27,7 @@ export class PopInComponent implements OnInit, OnDestroy {
public displayPopIn: boolean = false;
constructor(private popInService: PopInService) {
}
constructor(private popInService: PopInService) {}
ngOnInit(): void {
// ensure id attribute exists
if (!this.id) {

View File

@ -0,0 +1,47 @@
<table width="100%">
<tr *ngFor="let elem of values">
<td width="15%" *ngIf="elem.type === 'STRING' || elem.type === 'PASSWORD' || elem.type === 'NUMBER'"
[style.color]="getStyleRequireError(elem)"
[style.font-weight]="elem.require === true ? 'bold' : ''"
>{{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
[value]="elem.value"
[placeholder]="elem.placeholder"
[hasError]="checkHasError(elem)"
(changeValue)="checkParameter($event, elem)"></app-entry>
<app-error-message-state [value]="elem.state"></app-error-message-state>
</td>
<td width="85%" *ngIf="elem.type === 'NUMBER'">
<app-entry-number
[value]="elem.value"
[placeholder]="elem.placeholder"
[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>
<app-error-message-state [value]="elem.state"></app-error-message-state>
</td>
<td width="85%" *ngIf="elem.type === 'BOOLEAN'">
<app-checkbox
[value]="elem.value"
(changeValue)="checkParameter($event, elem)"></app-checkbox>
<app-error-message-state [value]="elem.state"></app-error-message-state>
</td>
<td width="85%" *ngIf="elem.type === 'LINE'"></td>
<td width="85%" *ngIf="elem.type === 'LINE'"></td>
</tr>
</table>

View File

@ -0,0 +1,17 @@
/** @file
* @author Edouard DUPIN
* @copyright 2018, Edouard DUPIN, all right reserved
* @license PROPRIETARY (see license file)
*/
import { Component } from '@angular/core';
import { RenderSettingsComponent } from './render-settings';
@Component({
selector: 'app-render-form',
templateUrl: 'render-form.html',
styleUrls: ['render-form.less'],
})
export class RenderFormComponent extends RenderSettingsComponent {
}

View File

@ -0,0 +1,39 @@
<div *ngFor="let elem of values" class="settings-elements">
<div *ngIf="elem.type === 'LINE'">
<div class="elem-hr"></div>
</div>
<div *ngIf="elem.type === 'BOOLEAN'">
<div class="elem-checkbox">
<app-checkbox
[value]="elem.value"
[comment]="elem.title"
(changeValue)="checkParameter($event, elem)"></app-checkbox>
</div>
<div class="elem-description">{{elem.description}}</div>
</div>
<div *ngIf="elem.type === 'STRING'">
<div class="elem-title">{{elem.title}}</div>
<div class="elem-description">{{elem.description}}</div>
<div class="elem-input">
<app-entry
[value]="elem.value"
[placeholder]="elem.placeholder"
[hasError]="elem.state !== undefined"
(changeValue)="checkParameter($event, elem)"></app-entry>
<app-error-message-state [value]="elem.state"></app-error-message-state>
</div>
</div>
<div *ngIf="elem.type === 'PASSWORD'">
<div class="elem-title">{{elem.title}}</div>
<div class="elem-description">{{elem.description}}</div>
<div class="elem-input">
<input [value]="elem.value" />
<app-password-entry
[value]="elem.value"
[placeholder]="elem.placeholder"
[hasError]="elem.state !== true"
(changeValue)="checkParameter($event, elem)"></app-password-entry>
<app-error-message-state [value]="elem.state"></app-error-message-state>
</div>
</div>
</div>

View File

@ -0,0 +1,32 @@
.settings-elements {
.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%;
}
}
}

View File

@ -0,0 +1,204 @@
/** @file
* @author Edouard DUPIN
* @copyright 2018, Edouard DUPIN, all right reserved
* @license PROPRIETARY (see license file)
*/
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { isBoolean, isInArray, isNullOrUndefined, isNumber, isObject, isOptionalOf, isString, isUndefined } from 'common/utils';
export type ReturnFunction = (a: boolean|string) => void;
export type CheckerParameterType = string | number | boolean | undefined;
// if string ==> the error, if undefined, it is OK
export type CheckerParameter = (value: CheckerParameterType) => string | undefined;
export enum SettingType {
VALUE = 'VALUE',
LINE = 'LINE',
BOOLEAN = 'BOOLEAN',
NUMBER = 'NUMBER',
STRING = 'STRING',
PASSWORD = 'PASSWORD',
}
export function isSettingType(data: any): data is SettingType {
return isInArray(data, ['VALUE', 'LINE', 'NUMBER', 'BOOLEAN', 'STRING', 'PASSWORD']);
}
export interface SettingsItem {
// Type of the menu Node
type: SettingType;
// Unique key reference
key?: string;
// Displayed Title
title?: string;
// Description of the parameter
description?: string;
// placeholder of the parameter
placeholder?: string;
// Parameter key to SET/GET or the sub-menu
value?: boolean | string | Number;
// when data is change the value is set here undefined if not correct (must be set @ undefined):
newValue?: boolean | string | Number;
// checker to validate the data:
checker?: CheckerParameter
// result of the checker (must be set @ undefined):
state?: boolean | string;
// The element is require to have a valid form.
require?: boolean
}
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 (!isString(data.key)) {
return false;
}
if (!isOptionalOf(data.title, isString)) {
return false;
}
if (!isOptionalOf(data.description, isString)) {
return false;
}
if (!isOptionalOf(data.placeholder, isString)) {
return false;
}
if (
!isOptionalOf(data.value, isBoolean) &&
!isOptionalOf(data.value, isString) &&
!isOptionalOf(data.value, isNumber)
) {
return false;
}
if (!isUndefined(data.newValue)) {
return false;
}
if (!isOptionalOf(data.state, isString)) {
return false;
}
if (!isOptionalOf(data.require, isBoolean)) {
return false;
}
return true;
}
@Component({
selector: 'app-render-settings',
templateUrl: 'render-settings.html',
styleUrls: ['render-settings.less'],
})
export class RenderSettingsComponent {
/// Value of the password
@Input() values: SettingsItem[] = [];
/// Number of error detected (undefined: No change or not ready, else the number of error)
@Output() changeState: EventEmitter<Number> = new EventEmitter();
/// event with the changed values
@Output() deltaValues: EventEmitter<any> = new EventEmitter();
createOutputValues(): object {
let out = {};
//console.log(" Create values ... out ... ");
this.values.forEach( (value) => {
if (isNullOrUndefined(value.key)) {
return;
}
//console.log(` key: ${value.key} : ${value.newValue}`);
if (!isNullOrUndefined(value.newValue)) {
//console.log(` ==> set`);
out[value.key] = value.newValue;
}
});
return out;
}
countErrors(): number | undefined {
let out = 0;
this.values.forEach( (value) => {
if (!isUndefined(value.state)) {
out++;
}
});
return out;
}
checkMissing(): boolean | undefined {
let error = 0;
this.values.forEach( (elem) => {
if (isNumber(elem.newValue)) {
if ((isUndefined(elem.newValue) && elem.value === undefined) || elem.newValue === undefined) {
error++;
}
} else {
if ((isUndefined(elem.newValue) && elem.value === "") || elem.newValue === "") {
error++;
}
}
});
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 "";
}
checkHasError(item: SettingsItem) {
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);
}
if (item.value === newValue) {
item.newValue = undefined;
} else {
item.newValue = newValue;
}
const missing = this.checkMissing();
const outValue = this.createOutputValues();
const nbError = this.countErrors();
const nbValuesChanges = Object.keys(outValue).length;
//console.log(`outValue=${JSON.stringify(outValue, null, 2)}`);
//console.log(`nbError=${nbError} nbValuesChanges=${nbValuesChanges}`);
if (nbValuesChanges === 0) {
this.changeState.emit(undefined);
return;
}
if (missing === true) {
this.changeState.emit(undefined);
return;
}
this.changeState.emit(nbError);
if (nbError === 0) {
this.deltaValues.emit(outValue);
}
}
}

View File

@ -0,0 +1,14 @@
/** @file
* @author Edouard DUPIN
* @copyright 2023, Edouard DUPIN, all right reserved
* @license MPL-2 (see license file)
*/
import { Component} from '@angular/core';
@Component({
selector: 'spiner',
template: '<img height="50px" src="assets/images/load.svg"/>',
})
export class SpinerComponent {
}

View File

@ -1,80 +1,64 @@
<div class="top">
<div id="main-menu" class="main-menu color-menu-background">
<div *ngFor="let data of menu">
<div class="inert_element"
<div
class="inert_element unselectable"
*ngIf="isNotButton(data)"
[ngStyle]="{'float': data.position}"
[ngClass]="getClassModel(data.model)">
<div class="xdesktop" *ngIf="data.icon">
<i class="material-icons">{{data.icon}}</i> {{data.title}}
</div>
<div class="xdesktop" *ngIf="data.icon"><i class="material-icons">{{data.icon}}</i> {{data.title}}</div>
<div class="xmobile" *ngIf="data.icon">
<i class="material-icons">{{data.icon}}</i>
</div>
<div class="xdesktop" *ngIf="!data.icon">
{{data.title}}
<div class="xdesktop" *ngIf="!data.icon">{{data.title}}</div>
</div>
</div>
<button class="item"
<button
class="item unselectable"
*ngIf="!isNotButton(data)"
(click)="onGeneric(data, $event)"
(auxclick)="onGeneric(data, $event)"
[ngStyle]="{'float': data.position}"
[ngClass]="getClassModel(data.model)"
[disable]="false">
<div class="avatar" *ngIf="data.image">
<img class="avatar" src="{{data.image}}"/> {{data.title}}
</div>
<div class="avatar unselectable" *ngIf="data.image"><img class="avatar" src="{{data.image}}" /> {{data.title}}</div>
<div class="xdesktop" *ngIf="data.icon && !data.image">
<i class="material-icons">{{data.icon}}</i> {{data.title}}
</div>
<div class="xmobile" *ngIf="data.icon && !data.image">
<i class="material-icons">{{data.icon}}</i>
</div>
<div class="xdesktop" *ngIf="!data.icon && !data.image">
{{data.title}}
</div>
<div class="xdesktop" *ngIf="!data.icon && !data.image">{{data.title}}</div>
</button>
</div>
</div>
<div class="fill-all" *ngIf="subMenu" (click)="onOutUserProperty()">
<div class="sub-menu color-menu-background"
[ngClass]="getClassMenuPosition()">
<div class="sub-menu color-menu-background unselectable" [ngClass]="getClassMenuPosition()">
<div *ngFor="let data of subMenu">
<div class="inert_element unselectable"
<div
class="inert_element unselectable"
*ngIf="isNotButton(data)"
[ngStyle]="{'float': data.position}"
[ngClass]="getClassModel(data.model)">
<div class="xdesktop"
*ngIf="data.icon"
[ngStyle]="{'float': data.position}">
<div class="xdesktop" *ngIf="data.icon" [ngStyle]="{'float': data.position}">
<i class="material-icons">{{data.icon}}</i> {{data.title}}
</div>
<div class="xmobile"
*ngIf="data.icon"
[ngStyle]="{'float': data.position}">
<div class="xmobile" *ngIf="data.icon" [ngStyle]="{'float': data.position}">
<i class="material-icons">{{data.icon}}</i>
</div>
<div *ngIf="!data.icon"
[ngStyle]="{'float': data.position}">
{{data.title}}
<div *ngIf="!data.icon" [ngStyle]="{'float': data.position}">{{data.title}}</div>
</div>
</div>
<button class="item"
<button
class="item"
*ngIf="isEnable(data) && !isNotButton(data)"
(click)="onGeneric(data, $event)"
(auxclick)="onGeneric(data, $event)"
[ngStyle]="{'float': data.position}"
[ngClass]="getClassModel(data.model)"
[disable]="false">
<div *ngIf="data.icon"
[ngStyle]="{'float': data.position}">
<div *ngIf="data.icon" [ngStyle]="{'float': data.position}">
<i class="material-icons">{{data.icon}}</i> {{data.title}}
</div>
<div *ngIf="!data.icon"
[ngStyle]="{'float': data.position}">
{{data.title}}
</div>
<div *ngIf="!data.icon" [ngStyle]="{'float': data.position}">{{data.title}}</div>
</button>
</div>
</div>

View File

@ -1,5 +1,3 @@
.element-pos-left {
z-index: 5;
float: left;
@ -24,7 +22,6 @@
}
.top {
.sub-menu {
position: fixed;
min-width: 150px;
@ -63,11 +60,12 @@
vertical-align: middle;
}
/* Create an Arraw on the top ob the box ... */
&:after, &:before {
&:after,
&:before {
bottom: 100%;
right: 13px;
border: solid transparent;
content: " ";
content: ' ';
height: 0;
width: 0;
position: absolute;
@ -80,7 +78,6 @@
border-width: 15px;
margin-left: -15px;
}
}
.menu-left {
top: 75px;
@ -137,14 +134,13 @@
font-weight: bold;
font-size: 17px;
.comment {
visibility: "hidden";
visibility: 'hidden';
}
@media all and (min-width: 700px) {
.comment {
visibility: "visible";
visibility: 'visible';
}
}
}
.inert_element {

View File

@ -9,8 +9,6 @@ import { Router } from '@angular/router';
import { isNullOrUndefined } from 'common/utils';
import { MenuItem } from 'common/model/menu-item';
export interface EventOnMenu {
menu: MenuItem;
newWindows: boolean;
@ -20,7 +18,7 @@ export interface EventOnMenu {
@Component({
selector: 'app-top-menu',
templateUrl: './top-menu.html',
styleUrls: [ './top-menu.less' ]
styleUrls: ['./top-menu.less'],
})
export class TopMenuComponent implements OnInit {
@Input() menu: MenuItem[];
@ -28,14 +26,14 @@ export class TopMenuComponent implements OnInit {
subMenuPosition: String = undefined;
@Output() callback: EventEmitter<EventOnMenu> = new EventEmitter();
constructor(private router: Router) {
}
constructor(private router: Router) {}
isNotButton(data: MenuItem) {
return isNullOrUndefined(data.navigateTo)
&& (isNullOrUndefined(data.callback) || data.callback === false)
&& isNullOrUndefined(data.subMenu);
return (
isNullOrUndefined(data.navigateTo) &&
(isNullOrUndefined(data.callback) || data.callback === false) &&
isNullOrUndefined(data.subMenu)
);
}
isEnable(data: MenuItem) {
if (!isNullOrUndefined(data) && !isNullOrUndefined(data.enable) && data.enable === false) {
@ -48,22 +46,20 @@ export class TopMenuComponent implements OnInit {
return `float: ${data}`;
}
ngOnInit() {
}
ngOnInit() {}
onOutUserProperty(): void {
//console.log('onOutUserProperty ==> event...');
this.subMenu = undefined;
}
getClassMenuPosition(): string {
if (isNullOrUndefined(this.subMenuPosition)) {
return "menu-left";
return 'menu-left';
}
return 'menu-' + this.subMenuPosition;
}
getClassModel(data?: string): string {
if (isNullOrUndefined(data)) {
return "";
return '';
}
return 'model_' + data;
}
@ -73,7 +69,7 @@ export class TopMenuComponent implements OnInit {
// check if we need to navigate
if (!isNullOrUndefined(data.navigateTo)) {
// remove in every case the subMenu:
this.subMenu = undefined
this.subMenu = undefined;
this.subMenuPosition = undefined;
this.router.navigate([data.navigateTo]);
return;
@ -105,5 +101,4 @@ export class TopMenuComponent implements OnInit {
this.subMenu = data.subMenu;
this.subMenuPosition = data.position;
}
}

View File

@ -1,11 +1,9 @@
<div>
<div class="uploadfilecontainer" (click)="fileInput.click()" appDragDrop (onFileDropped)="uploadFile($event)">
<input hidden type="file" #fileInput (change)="uploadFile($event.target.files)">
<input hidden type="file" #fileInput (change)="uploadFile($event.target.files)" />
</div>
<div class="files-list" *ngFor="let file of files;let i=index">
<p>{{ file }}</p>
<button class="delete-file" (click)="deleteAttachment(i)">
// DELETE //
</button>
<button class="delete-file" (click)="deleteAttachment(i)">// DELETE //</button>
</div>
</div>

View File

@ -6,7 +6,7 @@
height: 200px;
width: 80%;
margin: 20px auto;
border: 2px dashed #1C8ADB;
border: 2px dashed #1c8adb;
border-radius: 10px;
}

View File

@ -9,7 +9,7 @@ import { Component } from '@angular/core';
@Component({
selector: 'app-upload-file',
templateUrl: './upload-file.html',
styleUrls: [ './upload-file.less' ]
styleUrls: ['./upload-file.less'],
})
export class UploadFileComponent {
files: any = [];

View File

@ -1,8 +1,4 @@
import { isMenuItem, isMenuPosition, MenuItem, MenuPosition } from "./menu-item";
import { NodeData, isNodeData } from "./node";
import { isMenuItem, isMenuPosition, MenuItem, MenuPosition } from './menu-item';
import { NodeData, isNodeData } from './node';
export {
NodeData, isNodeData,
MenuPosition, isMenuPosition, MenuItem, isMenuItem,
}
export { NodeData, isNodeData, MenuPosition, isMenuPosition, MenuItem, isMenuItem };

View File

@ -1,16 +1,13 @@
import { isObject, isOptionalOf, isString, isNullOrUndefined, isOptionalArrayOf } from "common/utils";
import { isObject, isOptionalOf, isString, isNullOrUndefined, isOptionalArrayOf, isInArray } from 'common/utils';
export enum MenuPosition {
LEFT = "left",
RIGHT = "right",
CENTER = "none",
LEFT = 'left',
RIGHT = 'right',
CENTER = 'none',
}
export function isMenuPosition(data: any): data is MenuPosition {
return data === "left"
|| data === "right"
|| data === "none";
return isInArray(data, ['left', 'right', 'none']);
}
export interface MenuItem {
@ -20,24 +17,23 @@ export interface MenuItem {
hover?: string;
// Icon of the menue (need to be a meterial-icon name
icon?: string;
// If we want to display an image instead of an icon
// Displayed Title
image?: string;
// Displayed Title
title: string;
// Jump Link (If undefined: it is considered as text and not a button)
// Model of the display:
model?: string;
// Jump Link (If undefined: it is considered as text and not a button)
navigateTo?: string;
// if it request a callbak with the curent element: (not compatible with the previous)
// Menu model For a subList of elements
callback?: boolean;
// Other data that want to be set by the user
otherData?: any;
// Enable or not the elemnt
// Menu model For a subList of elements
enable?: boolean;
// Menu model For a subList of elements
subMenu?: MenuItem[];
};
}
export function isMenuItem(data: any): data is MenuItem {
if (isNullOrUndefined(data)) {

View File

@ -1,6 +1,4 @@
import { isArrayOf, isNumberFinite, isObject, isOptionalOf, isOptionalArrayOf, isString } from "common/utils";
import { isArrayOf, isNumberFinite, isObject, isOptionalOf, isOptionalArrayOf, isString } from 'common/utils';
export interface NodeData {
id: number;
@ -8,8 +6,7 @@ export interface NodeData {
description?: string;
parentId?: number;
covers?: number[];
};
}
export function isNodeData(data: any): data is NodeData {
if (!isObject(data)) {

View File

@ -1,5 +1,6 @@
<div>
<app-popin id="popin-delete-confirm"
<app-popin
id="popin-delete-confirm"
popSize="small"
popTitle="Confirm Remove"
[closeTitle]="closeButtonTitle"

View File

@ -1,15 +1,13 @@
.expand {
width: 100%;
input {
width: 100%;
};
}
div {
width: 100%;
};
}
textarea {
width: 100%;
};
}
text-align: center;
}

View File

@ -11,7 +11,7 @@ import { PopInService } from 'common/service';
@Component({
selector: 'delete-confirm',
templateUrl: './delete-confirm.html',
styleUrls: [ './delete-confirm.less' ]
styleUrls: ['./delete-confirm.less'],
})
export class PopInDeleteConfirm implements OnInit {
@Input() comment: string = null;
@ -21,17 +21,11 @@ export class PopInDeleteConfirm implements OnInit {
public closeButtonTitle: string = 'Cancel';
public validateButtonTitle: string = 'Validate';
constructor(private popInService: PopInService) {
constructor(private popInService: PopInService) {}
}
OnDestroy() {}
OnDestroy() {
}
ngOnInit() {
}
ngOnInit() {}
eventPopUp(_event: string): void {
console.log(`GET event: ${_event}`);

View File

@ -1,8 +1,4 @@
import { PopInDeleteConfirm } from "./delete-confirm/delete-confirm";
import { PopInUploadProgress } from "./upload-progress/upload-progress";
import { PopInDeleteConfirm } from './delete-confirm/delete-confirm';
import { PopInUploadProgress } from './upload-progress/upload-progress';
export {
PopInDeleteConfirm,
PopInUploadProgress,
}
export { PopInDeleteConfirm, PopInUploadProgress };

View File

@ -1,5 +1,6 @@
<div>
<app-popin id="popin-upload-progress"
<app-popin
id="popin-upload-progress"
popSize="medium"
popTitle="Upload Media File"
[closeTitle]="closeButtonTitle"
@ -13,18 +14,20 @@
<div class="progress-bar" style="width:{{progress}}%">&nbsp;&nbsp;&nbsp;{{progress}}%</div>
</div>
<div *ngIf="progress != 100">
<label class="unselectable">Upload:</label><label style="text-align: right;">{{uploadDisplay}}</label><br/>
<label class="unselectable">Size:</label><label style="text-align: right;">{{sizeDisplay}}</label>
<label class="unselectable">Upload:</label><label style="text-align: right">{{uploadDisplay}}</label><br />
<label class="unselectable">Size:</label><label style="text-align: right">{{sizeDisplay}}</label>
</div>
<div *ngIf="progress == 100 && error == null && result == null">
<label class="unselectable">Upload done ... waiting server answer</label>
</div>
<div *ngIf="error != null">
<label class="unselectable"><b>Get an error From the server:</b></label><br/>
<label class="unselectable"><b>Get an error From the server:</b></label
><br />
<label class="unselectable">{{error}}</label>
</div>
<div *ngIf="result != null">
<label class="unselectable"><b>Upload finished:</b></label><br/>
<label class="unselectable"><b>Upload finished:</b></label
><br />
<label class="unselectable">{{result}}</label>
</div>
</app-popin>

View File

@ -1,13 +1,11 @@
.expand {
width: 100%;
input {
width: 100%;
};
}
textarea {
width: 100%;
};
}
}
.progress-back {
@ -18,6 +16,6 @@
.progress-bar {
color: #000000 !important;
background-color:#4CAF50!important;
background-color: #4caf50 !important;
border-radius: 3px;
}

View File

@ -12,7 +12,7 @@ import { PopInService } from 'common/service';
@Component({
selector: 'upload-progress',
templateUrl: './upload-progress.html',
styleUrls: [ './upload-progress.less' ]
styleUrls: ['./upload-progress.less'],
})
export class PopInUploadProgress implements OnInit {
@Input() mediaTitle: string = '';
@ -26,23 +26,14 @@ export class PopInUploadProgress implements OnInit {
public uploadDisplay: string = '';
public sizeDisplay: string = '';
public progress: number = 0;
constructor(private router: Router,
private popInService: PopInService) {
}
OnDestroy() {
}
ngOnInit() {
}
constructor(private router: Router, private popInService: PopInService) {}
OnDestroy() {}
ngOnInit() {}
eventPopUp(_event: string): void {
console.log(`GET event: ${_event}`);
this.popInService.close('popin-upload-progress');
}
updateNeedSend():void {
}
updateNeedSend(): void {}
limit3(count: number): string {
if (count >= 1000) {
@ -87,7 +78,7 @@ export class PopInUploadProgress implements OnInit {
ngOnChanges(changes: SimpleChanges) {
//console.log(`Upload progress event : ${JSON.stringify(changes)}`);
this.progress = Math.trunc(this.mediaUploaded * 100 / this.mediaSize);
this.progress = Math.trunc((this.mediaUploaded * 100) / this.mediaSize);
this.uploadDisplay = this.convertInHuman(this.mediaUploaded);
this.sizeDisplay = this.convertInHuman(this.mediaSize);
if (this.error === null && this.result === null) {
@ -106,7 +97,6 @@ export class PopInUploadProgress implements OnInit {
}
}
export class UploadProgress {
labelMediaTitle: string = '';
mediaSendSize: number = 0;

View File

@ -1,6 +1,8 @@
<div class="full-mode">
<div class="centered">
<div class="error"><label class="unselectable"><i class="material-icons">report</i> 404 Not Found !</label></div>
<div class="error">
<label class="unselectable"><i class="material-icons">report</i> 404 Not Found !</label>
</div>
<div class="comment"><label class="unselectable">Unknwn this page.</label></div>
</div>
</div>

View File

@ -1,4 +1,3 @@
.full-mode {
width: 100%;
height: 100%;
@ -17,7 +16,7 @@
padding: 16px 32px 16px 32px;
top: 50%;
transform: ~"translate(0, -50%)";
transform: ~'translate(0, -50%)';
font-size: 30px;
font-weight: 600;

View File

@ -9,7 +9,7 @@ import { Component } from '@angular/core';
@Component({
selector: 'app-404-not-found',
templateUrl: './404.html',
styleUrls: [ './404.less' ]
styleUrls: ['./404.less'],
})
export class NotFound404Scene {
constructor() {}

View File

@ -1,3 +1 @@
<p>
error-viewer works!
</p>
<p>error-viewer works!</p>

View File

@ -10,13 +10,10 @@ import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-error-viewer',
templateUrl: './error-viewer.html',
styleUrls: [ './error-viewer.less' ]
styleUrls: ['./error-viewer.less'],
})
export class ErrorViewerScene implements OnInit {
constructor(private route: ActivatedRoute) {}
ngOnInit() {
ngOnInit() {}
}
}

View File

@ -1,6 +1,10 @@
<div class="full-mode">
<div class="centered">
<div class="error"><label class="unselectable"><i class="material-icons">gpp_bad</i> 403 Forbidden</label></div>
<div class="comment"><label class="unselectable">You don't have permission to access this resource.</label></div>
<div class="error">
<label class="unselectable"><i class="material-icons">gpp_bad</i> 403 Forbidden</label>
</div>
<div class="comment">
<label class="unselectable">You don't have permission to access this resource.</label>
</div>
</div>
</div>

View File

@ -1,4 +1,3 @@
.full-mode {
width: 100%;
height: 100%;
@ -18,7 +17,7 @@
top: 50%;
left: 50%;
transform: ~"translate(-50%, -50%)";
transform: ~'translate(-50%, -50%)';
font-size: 30px;
font-weight: 600;

View File

@ -9,7 +9,7 @@ import { Component } from '@angular/core';
@Component({
selector: 'app-forbidden',
templateUrl: './forbidden.html',
styleUrls: [ './forbidden.less' ]
styleUrls: ['./forbidden.less'],
})
export class ForbiddenScene {
constructor() {}

View File

@ -1,6 +1,8 @@
<div class="full-mode">
<div class="centered">
<div class="error"><label class="unselectable"><i class="material-icons">login</i> Not registered!</label></div>
<div class="error">
<label class="unselectable"><i class="material-icons">login</i> Not registered!</label>
</div>
<div class="comment"><label class="unselectable">you must login to access to this website.</label></div>
</div>
</div>

View File

@ -1,4 +1,3 @@
.full-mode {
width: 100%;
height: 100%;
@ -17,7 +16,7 @@
padding: 16px 32px 16px 32px;
top: 50%;
transform: ~"translate(0, -50%)";
transform: ~'translate(0, -50%)';
font-size: 30px;
font-weight: 600;

View File

@ -9,7 +9,7 @@ import { Component } from '@angular/core';
@Component({
selector: 'app-home-out',
templateUrl: './home-out.html',
styleUrls: [ './home-out.less' ]
styleUrls: ['./home-out.less'],
})
export class HomeOutScene {
constructor() {}

View File

@ -1,17 +1,8 @@
import { ErrorViewerScene } from "./error-viewer/error-viewer";
import { ForbiddenScene } from "./forbidden/forbidden";
import { SsoScene } from "./sso/sso";
//import { UploadScene } from "../../app/scene/upload/upload";
import { HomeOutScene } from "./home-out/home-out";
import { NotFound404Scene } from "./404/404";
export {
ErrorViewerScene,
SsoScene,
//UploadScene,
ForbiddenScene,
HomeOutScene,
NotFound404Scene,
};
//import { ErrorViewerScene } from "./error-viewer/error-viewer";
import { ErrorViewerScene } from './error-viewer/error-viewer';
import { ForbiddenScene } from './forbidden/forbidden';
import { SsoScene } from './sso/sso';
import { HomeOutScene } from './home-out/home-out';
import { NotFound404Scene } from './404/404';
export { ErrorViewerScene, SsoScene, ForbiddenScene, HomeOutScene, NotFound404Scene };

View File

@ -18,10 +18,14 @@
<div class="container" *ngIf="token === 'ERROR_ME'">
<label for="login_field"><b>ERROR: </b> can not retreive user local informations!</label>
</div>
<div class="container" *ngIf="token !== 'ERROR_ME' and token !== '__FAIL__' and token !== '__CANCEL__' and token === '__LOGOUT__'">
<div
class="container"
*ngIf="token !== 'ERROR_ME' and token !== '__FAIL__' and token !== '__CANCEL__' and token === '__LOGOUT__'">
<label for="login_field"><b>Connected: </b> Redirect soon!</label>
</div>
<div class="container" *ngIf="token !== 'ERROR_ME' and token !== '__FAIL__' and token !== '__CANCEL__' and token === '__LOGOUT__'">
<div
class="container"
*ngIf="token !== 'ERROR_ME' and token !== '__FAIL__' and token !== '__CANCEL__' and token === '__LOGOUT__'">
<label for="login_field"><b>Welcome back: </b> {{userName}}</label>
</div>
</div>

View File

@ -1,4 +1,3 @@
.full {
width: 100%;
height: 100%;
@ -10,7 +9,8 @@
display: block;
}
input[type=text], input[type=password] {
input[type='text'],
input[type='password'] {
width: 100%;
padding: 12px 20px;
margin: 8px 0;
@ -33,7 +33,6 @@ input[type=text], input[type=password] {
margin: 15px 0 0 0;
}
.imgContainer {
text-align: center;
margin: 15px 0 0 0;
@ -58,7 +57,7 @@ span.psw {
}
.forgot {
color: #00B;
color: #00b;
font-size: 14px;
float: right;
buttum: 0;
@ -78,11 +77,12 @@ span.psw {
border-width: 0px;
box-sizing: border-box;
&:after, &:before {
&:after,
&:before {
bottom: 100%;
left: 25px;
border: solid transparent;
content: " ";
content: ' ';
height: 0;
width: 0;
position: absolute;
@ -96,7 +96,6 @@ span.psw {
}
}
.container-global {
position: relative;
max-width: 400px;
@ -104,6 +103,6 @@ span.psw {
top: 50%;
left: 50%;
transform: ~"translate(-50%, -50%)";
transform: ~'translate(-50%, -50%)';
box-shadow: 0px 8px 20px 0 rgba(0, 0, 0, 0.9);
}

View File

@ -11,20 +11,21 @@ import { SSOService, UserService } from 'common/service';
@Component({
selector: 'app-sso',
templateUrl: './sso.html',
styleUrls: [ './sso.less' ]
styleUrls: ['./sso.less'],
})
export class SsoScene implements OnInit {
ssoData: string;
token: string;
keepConnected: boolean
userName: string
keepConnected: boolean;
userName: string;
constructor(
private router: Router,
private route: ActivatedRoute,
private ssoService: SSOService,
private userService: UserService) {
console.error("retreive data after SSO");
private userService: UserService
) {
console.error('retreive data after SSO');
}
ngOnInit() {
@ -52,21 +53,24 @@ export class SsoScene implements OnInit {
console.log(`token: '${token}'`);
console.log(`keepConnected: '${keepConnected}'`);
if (this.token !== '__CANCEL__' && this.token !== '__FAIL__' && this.token !== '__LOGOUT__') {
const destination = (this.ssoData);
const destination = this.ssoData;
console.log(`ssoData (decoded): '${destination}'`);
const realDst = this.ssoService.unHashLocalData(destination);
console.log(`realDst: '${realDst}'`);
this.userService.startSession(this.token, this.keepConnected).then((userName: string) => {
this.userService
.startSession(this.token, this.keepConnected)
.then((userName: string) => {
self.userName = userName;
setTimeout(function () {
self.router.navigate([realDst], { replaceUrl: true });
}, 500); // 2 seconds
}).catch(() => {
this.token = "ERROR_ME";
})
.catch(() => {
this.token = 'ERROR_ME';
});
} else if (this.token === '__LOGOUT__') {
this.userService.removeSession();
const destination = (this.ssoData);
const destination = this.ssoData;
console.error(`ssoData (decoded): '${destination}'`);
// sample : ZZ**DST:home
const realDst = this.ssoService.unHashLocalData(destination);
@ -78,8 +82,4 @@ export class SsoScene implements OnInit {
this.userService.removeSession();
}
}
}

View File

@ -9,7 +9,6 @@ import { HttpWrapperService } from 'common/service/http-wrapper';
import { isNullOrUndefined } from 'common/utils';
import { DataInterface } from 'common/utils/dataInterface';
@Injectable()
export class BddService {
private bdd = {};
@ -27,13 +26,14 @@ export class BddService {
self.get(name)
.then((response: DataInterface) => {
let responseTmp = response;
ret.then((response2) => {
ret.then(response2 => {
responseTmp.add(response2);
resolve(response2);
}).catch((response2) => {
}).catch(response2 => {
reject(response2);
});
}).catch((response) => {
})
.catch(response => {
reject(response);
});
});
@ -45,13 +45,14 @@ export class BddService {
self.get(name)
.then((response: DataInterface) => {
let responseTmp = response;
ret.then((response2) => {
ret.then(response2 => {
responseTmp.set(id, response2);
resolve(response2);
}).catch((response2) => {
}).catch(response2 => {
reject(response2);
});
}).catch((response) => {
})
.catch(response => {
reject(response);
});
});
@ -61,7 +62,8 @@ export class BddService {
self.get(name)
.then((response: DataInterface) => {
response.set(id, data);
}).catch((response) => {
})
.catch(response => {
// nothing to do ...
});
}
@ -72,13 +74,14 @@ export class BddService {
self.get(name)
.then((response: DataInterface) => {
let responseTmp = response;
ret.then((response2) => {
ret.then(response2 => {
responseTmp.delete(id);
resolve(response2);
}).catch((response2) => {
}).catch(response2 => {
reject(response2);
});
}).catch((response) => {
})
.catch(response => {
reject(response);
});
});
@ -112,29 +115,36 @@ export class BddService {
// brut force update of the BDD : TODO optimise it later ...
//console.log(`Update BDD (${ name })`);
self.http.getSpecific(name)
.then((response) => {
self.http
.getSpecific(name)
.then(response => {
//console.log(`end download DB: ==> ${ name } ${ response.length}`);
self.bdd[name] = new DataInterface(name, response);
localStorage.setItem(self.baseLocalStorageName + name, JSON.stringify(self.bdd[name].bdd));
}).catch((response) => {
})
.catch(response => {
console.log(`[E] ${self.constructor.name}: cant not get data from remote server: ${name}`);
});
} else {
//console.log(`Download BDD (${ name })`);
return new Promise((resolve, reject) => {
self.http.getSpecific(name)
.then((response) => {
self.http
.getSpecific(name)
.then(response => {
//console.log(`end download DB: ==> ${ name } ${ response.length}`);// + " " + JSON.stringify(response).length);
self.bdd[name] = new DataInterface(name, response);
if (self.useLocalStorage === true) {
localStorage.setItem(self.baseLocalStorageName + name, JSON.stringify(self.bdd[name].bdd));
localStorage.setItem(
self.baseLocalStorageName + name,
JSON.stringify(self.bdd[name].bdd)
);
}
for (let iii = 0; iii < self.bddPomise[name].length; iii++) {
self.bddPomise[name][iii].resolve(self.bdd[name]);
}
resolve(self.bdd[name]);
}).catch((response) => {
})
.catch(response => {
console.log(`[E] ${self.constructor.name}: can not get data from remote server: ${name}`);
for (let iii = 0; iii < self.bddPomise[name].length; iii++) {
self.bddPomise[name][iii].reject(response);
@ -153,4 +163,3 @@ export class BddService {
});
}
}

View File

@ -8,10 +8,7 @@
@Injectable()
export class CookiesService {
constructor() {
}
constructor() {}
set(cname: string, cvalue: string, exdays: number): void {
if (this.get(cname) !== '') {
@ -43,5 +40,3 @@
return '';
}
}

View File

@ -13,19 +13,19 @@ import { SessionService } from './session';
import { isArrayOfs, isBoolean, isNullOrUndefined, isNumber, isString } from 'common/utils';
export enum HTTPRequestModel {
POST = "POST",
GET = "GET",
PUT = "PUT",
DELETE = "DELETE",
PATCH = "PATCH",
POST = 'POST',
GET = 'GET',
PUT = 'PUT',
DELETE = 'DELETE',
PATCH = 'PATCH',
}
export enum HTTPMimeType {
ALL = "*/*",
JSON = "application/json",
OCTET_STREAM = "application/octet-stream",
IMAGE = "image/*",
IMAGE_JPEG = "image/jpeg",
IMAGE_PNG = "image/png",
ALL = '*/*',
JSON = 'application/json',
OCTET_STREAM = 'application/octet-stream',
IMAGE = 'image/*',
IMAGE_JPEG = 'image/jpeg',
IMAGE_PNG = 'image/png',
}
export type UrlPath = string | boolean | number | (string | boolean | number)[];
@ -46,8 +46,8 @@ export interface HTTPRequest {
}
export interface ModelResponseHttp {
status: number,
data: any,
status: number;
data: any;
}
/**
@ -56,10 +56,7 @@ export interface ModelResponseHttp {
@Injectable()
export class HttpWrapperService {
private displayReturn: boolean = false;
constructor(private http: HttpClient,
private session: SessionService) {
}
constructor(private http: HttpClient, private session: SessionService) { }
addTokenIfNeeded(headerOption: any): any {
const token = this.session.getToken();
@ -72,26 +69,26 @@ export class HttpWrapperService {
}
request(properties: HTTPRequest): Promise<Response> {
//uriRest:string, headerOption:any, params:any): Promise<{status:number, data:any}> {
//console.log(`-------------------------------------------------------\nHTTP-wrapper GET '${ properties.endPoint }'\n\t\tparams=${ JSON.stringify(properties, null, 2)}`);
let connectionAdresse = this.createRESTCall2({
let connectionAddresses = this.createRESTCall2({
server: properties.server,
api: properties.endPoint,
inputOptions: properties.params,
});
let headers: any = {
'Accept': properties.accept,
Accept: properties.accept,
//'Content-Type': properties.contentType,
}
};
if (properties.authorization !== undefined && properties.authorization !== null) {
headers['Authorization'] = properties.authorization;
}
if (properties.requestType !== HTTPRequestModel.GET) {
headers['Content-Type'] = properties.contentType;
}
//console.log(`disble tocken : ${JSON.stringify(properties)} properties.disableTocken=${properties.disableTocken}`);
if (properties.disableTocken === undefined || properties.disableTocken === null || properties.disableTocken === false) {
if (
properties.disableTocken === undefined ||
properties.disableTocken === null ||
properties.disableTocken === false
) {
headers = this.addTokenIfNeeded(headers);
}
//console.log(`header: ${JSON.stringify(headers)}`);
@ -99,44 +96,56 @@ export class HttpWrapperService {
if (properties.contentType === HTTPMimeType.JSON) {
body = JSON.stringify(properties.body);
}
const result = fetch(connectionAdresse, {
console.log(`Call ${connectionAddresses}`)
const result = fetch(connectionAddresses, {
method: properties.requestType,
headers,
body
})
body,
});
return result;
};
}
requestJson(properties: HTTPRequest): Promise<ModelResponseHttp> {
return new Promise((resolve, reject) => {
this.request(properties).then((response: Response) => {
this.request(properties)
.then((response: Response) => {
if (response.status >= 200 && response.status <= 299) {
const contentType = response.headers.get('Content-Type');
if (contentType === HTTPMimeType.JSON) {
response.json().then((value:any) => {
//console.log(`REICEIVE ==> ${response.status}=${ JSON.stringify(value, null, 2)}`);
response
.json()
.then((value: any) => {
//console.log(`RECEIVE ==> ${response.status}=${ JSON.stringify(value, null, 2)}`);
resolve({ status: response.status, data: value });
}).catch((reason:any)=> {
})
.catch((reason: any) => {
reject({ status: 999, data: reason });
});
} else {
console.error(`content Type is not Json: ${contentType}`)
console.error(`content Type is not Json: ${contentType}`);
reject({ status: 999, data: `content Type is not Json: ${contentType}` });
}
} else {
console.error(`wring correct status: ${response.status}`)
console.error(`wring correct status: ${response.status}`);
reject({ status: 900, data: response });
}
}).catch((error: any) => {
reject({ status:error.status, data:error.error });
})
.catch((error: any) => {
reject({
time: Date(),
status: 999,
error: error,
statusMessage: "Fetch error",
message: "http-wrapper.ts detect an error in the fetch request"
});
});
};
});
}
requestImage(properties: HTTPRequest): Promise<ModelResponseHttp> {
return new Promise((resolve, reject) => {
this.request(properties).then((response: Response) => {
this.request(properties)
.then((response: Response) => {
if (response.status >= 200 && response.status <= 299) {
const contentType = response.headers.get('Content-Type');
//console.log(`REICEIVE ==> ${response.status}`);
@ -152,24 +161,39 @@ export class HttpWrapperService {
}
*/
} else {
console.error(`wring correct status: ${response.status}`)
console.error(`wring correct status: ${response.status}`);
resolve({ status: 900, data: response });
}
}).catch((error: any) => {
reject({ status:error.status, data:error.error });
})
.catch((error: any) => {
reject({
time: Date(),
status: 999,
error: error,
statusMessage: "Fetch image error",
message: "http-wrapper.ts detect an error in the fetch request"
});
});
});
}
createRESTCall2({ api, server, inputOptions, addURLToken }: { server?: string; api: UrlPath; inputOptions?: object; addURLToken?:boolean }) {
createRESTCall2({
api,
server,
inputOptions,
addURLToken,
}: {
server?: string;
api: UrlPath;
inputOptions?: object;
addURLToken?: boolean;
}) {
if (isNullOrUndefined(server)) {
server = environment.defaultServer;
}
const basePage = environment.server[server];
let addressServerRest = basePage;
if (!basePage.endsWith("/")) {
if (!basePage.endsWith('/')) {
addressServerRest = `${basePage}/`;
}
let options = inputOptions;
@ -180,7 +204,7 @@ export class HttpWrapperService {
if (isArrayOfs(api, isString, isNumber, isBoolean)) {
for (let iii = 0; iii < api.length; iii++) {
let elem = api[iii];
if (out.endsWith("/")) {
if (out.endsWith('/')) {
out += elem;
} else {
out += `/${elem}`;
@ -200,7 +224,7 @@ export class HttpWrapperService {
}
out = out + keys[iii];
if (options[keys[iii]] != null) {
out = out + "=" + options[keys[iii]];
out = out + '=' + options[keys[iii]];
}
}
//console.log(`try to get session : ${this.session.getToken()}`);
@ -242,20 +266,20 @@ export class HttpWrapperService {
post(uriRest: string, headerOption: any, data: any, progress: ProgressCallback = null) {
//console.log(`-------------------------------------------------------\nHTTP-wrapper POST '${ uriRest }'\n\t\theaderOption=${ JSON.stringify(headerOption, null, 2)}\n\t\tdata=${ JSON.stringify(data, null, 2)}`);
this.addTokenIfNeeded(headerOption);
let connectionAdresse = this.createRESTCall(uriRest, {});
let connectionAddresses = this.createRESTCall(uriRest, {});
return new Promise((resolve, reject) => {
if (this.displayReturn === true) {
console.log(`call POST ${ connectionAdresse } data=${ JSON.stringify(data, null, 2)}`);
console.log(`call POST ${connectionAddresses} data=${JSON.stringify(data, null, 2)}`);
}
let request = this.http.post(connectionAdresse, data, {
let request = this.http.post(connectionAddresses, data, {
headers: new HttpHeaders(headerOption),
reportProgress: true,
observe: 'events'
observe: 'events',
});
let self = this;
request.subscribe((res: any) => {
request.subscribe(
(res: any) => {
if (self.displayReturn === true) {
console.log(`!! data ${JSON.stringify(res, null, 2)}`);
}
@ -287,13 +311,14 @@ export class HttpWrapperService {
console.log(`post : get unknown ... ${res.type}`);
}
},
(error) => {
error => {
if (self.displayReturn === true) {
console.log(`an error occured status: ${error.status}`);
console.log(`answer: ${JSON.stringify(error, null, 2)}`);
}
reject({ status: error.status, data: error.error });
});
}
);
});
}
// Deprecated ... old model stream
@ -307,21 +332,23 @@ export class HttpWrapperService {
// 'Content-Type': 'multipart/form-data',
}; // new Headers();
self.post(url, headers, multipart, progress)
.then((response: any) => {
self.post(url, headers, multipart, progress).then(
(response: any) => {
//console.log(`URL: ${ url }\nRespond(${ response.status }): ${ JSON.stringify(response.data, null, 2)}`);
if (response.status >= 200 && response.status <= 299) {
resolve(response.data.body);
return;
}
reject('An error occured');
}, (response: any) => {
},
(response: any) => {
if (typeof response.data === 'undefined') {
reject('return ERROR undefined');
} else {
reject('return ERROR ...'); // + JSON.stringify(response, null, 2));
}
});
}
);
});
}
@ -333,21 +360,23 @@ export class HttpWrapperService {
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON,
contentType: HTTPMimeType.JSON,
})
.then((response: ModelResponseHttp) => {
}).then(
(response: ModelResponseHttp) => {
//console.log("URL: " + url + "\nRespond(" + response.status + "): " + JSON.stringify(response.data, null, 2));
if (response.status === 200) {
resolve(response.data);
return;
}
reject('An error occured');
}, (response: ModelResponseHttp) => {
},
(response: ModelResponseHttp) => {
if (isNullOrUndefined(response.data)) {
reject('return ERROR undefined');
} else {
reject(`return ERROR ${JSON.stringify(response.data, null, 2)}`);
}
});
}
);
});
}
@ -360,25 +389,30 @@ export class HttpWrapperService {
accept: HTTPMimeType.JSON,
contentType: HTTPMimeType.JSON,
body: data,
}).then((response: Response) => {
})
.then((response: Response) => {
if (response.status >= 200 && response.status <= 201) {
const contentType = response.headers.get('Content-Type');
if (contentType === HTTPMimeType.JSON) {
response.json().then((value:any) => {
response
.json()
.then((value: any) => {
//console.log(`REICEIVE ==> ${response.status}=${ JSON.stringify(value, null, 2)}`);
resolve({ status: response.status, data: value });
}).catch((reason:any)=> {
})
.catch((reason: any) => {
reject({ status: 999, data: reason });
});
} else {
console.error(`content Type is not Json: ${contentType}`)
console.error(`content Type is not Json: ${contentType}`);
reject({ status: 998, data: `content Type is not Json: ${contentType}` });
}
} else {
console.error(`wrong correct status: ${response.status}`)
console.error(`wrong correct status: ${response.status}`);
reject({ status: 900, data: response });
}
}).catch((error: any) => {
})
.catch((error: any) => {
reject({ status: error.status, data: error.error });
});
});
@ -391,25 +425,30 @@ export class HttpWrapperService {
accept: HTTPMimeType.JSON,
contentType: HTTPMimeType.JSON,
body: data,
}).then((response: Response) => {
})
.then((response: Response) => {
if (response.status >= 200 && response.status <= 201) {
const contentType = response.headers.get('Content-Type');
if (contentType === HTTPMimeType.JSON) {
response.json().then((value:any) => {
response
.json()
.then((value: any) => {
//console.log(`REICEIVE ==> ${response.status}=${ JSON.stringify(value, null, 2)}`);
resolve({ status: response.status, data: value });
}).catch((reason:any)=> {
})
.catch((reason: any) => {
reject({ status: 999, data: reason });
});
} else {
console.error(`content Type is not Json: ${contentType}`)
console.error(`content Type is not Json: ${contentType}`);
reject({ status: 998, data: `content Type is not Json: ${contentType}` });
}
} else {
console.error(`wrong correct status: ${response.status}`)
console.error(`wrong correct status: ${response.status}`);
reject({ status: 900, data: response });
}
}).catch((error: any) => {
})
.catch((error: any) => {
reject({ status: error.status, data: error.error });
});
});
@ -421,25 +460,30 @@ export class HttpWrapperService {
requestType: HTTPRequestModel.DELETE,
accept: HTTPMimeType.JSON,
contentType: HTTPMimeType.JSON,
}).then((response: Response) => {
})
.then((response: Response) => {
if (response.status >= 200 && response.status <= 201) {
const contentType = response.headers.get('Content-Type');
if (contentType === HTTPMimeType.JSON) {
response.json().then((value:any) => {
response
.json()
.then((value: any) => {
//console.log(`REICEIVE ==> ${response.status}=${ JSON.stringify(value, null, 2)}`);
resolve({ status: response.status, data: value });
}).catch((reason:any)=> {
})
.catch((reason: any) => {
reject({ status: 999, data: reason });
});
} else {
console.error(`content Type is not Json: ${contentType}`)
console.error(`content Type is not Json: ${contentType}`);
reject({ status: 998, data: `content Type is not Json: ${contentType}` });
}
} else {
console.error(`wrong correct status: ${response.status}`)
console.error(`wrong correct status: ${response.status}`);
reject({ status: 900, data: response });
}
}).catch((error: any) => {
})
.catch((error: any) => {
reject({ status: error.status, data: error.error });
});
});

View File

@ -1,11 +1,18 @@
import { BddService } from "./bdd";
import { CookiesService } from "./cookies";
import { HttpWrapperService, ModelResponseHttp, HTTPRequest, HTTPMimeType, HTTPRequestModel } from "./http-wrapper";
import { StorageService } from "./local-storage";
import { PopInService } from "./popin";
import { OnlyAdminGuard, OnlyUnregisteredGuardHome, OnlyUsersGuard, OnlyUsersGuardHome, SessionService } from "./session";
import { SSOService } from "./sso";
import { UserService } from "./user";
import { BddService } from './bdd';
import { CookiesService } from './cookies';
import { HttpWrapperService, ModelResponseHttp, HTTPRequest, HTTPMimeType, HTTPRequestModel } from './http-wrapper';
import { StorageService } from './local-storage';
import { NotificationService } from './notification';
import { PopInService } from './popin';
import {
OnlyAdminGuard,
OnlyUnregisteredGuardHome,
OnlyUsersGuard,
OnlyUsersGuardHome,
SessionService,
} from './session';
import { SSOService } from './sso';
import { UserService } from './user';
export {
BddService,
@ -24,6 +31,5 @@ export {
OnlyUsersGuardHome,
OnlyUnregisteredGuardHome,
OnlyAdminGuard,
NotificationService,
};

View File

@ -11,9 +11,7 @@ import { environment } from 'environments/environment';
export class StorageService {
private baseLocalStorageName = environment.applName + '_';
constructor() {
}
constructor() {}
set(cname: string, cvalue: string): void {
//console.debug(`storage set: ${cname} : ${cvalue}`);
@ -50,5 +48,3 @@ import { environment } from 'environments/environment';
return data;
}
}

View File

@ -0,0 +1,25 @@
/** @file
* @author Edouard DUPIN
* @copyright 2018, Edouard DUPIN, all right reserved
* @license PROPRIETARY (see license file)
*/
import { Injectable } from '@angular/core';
@Injectable()
export class NotificationService {
constructor() {
console.log('Start Notification Service');
}
errorRaw(data: any) {
console.error(`get notification error: ${data}`)
}
warningRaw(data: any) {
console.info(`get notification warning: ${data}`)
}
infoRaw(data: any) {
console.info(`get notification info: ${data}`)
}
}

View File

@ -30,16 +30,17 @@ export class PopInService {
}
open(_id: string) {
// console.log("Try to open pop-in: '" + _id + "'");
console.log("Try to open pop-in: '" + _id + "'");
// open popin specified by id
for (let iii = 0; iii < this.popins.length; iii++) {
console.log(` check: ${this.popins[iii].id}`);
if (this.popins[iii].id === _id) {
// console.log(" ==>find it ...");
console.log(" ==>find it ...");
this.popins[iii].open();
return;
}
}
// console.log(" ==> NOT found !!!!!");
console.log(" ==> NOT found !!!!!");
}
close(_id: string) {

View File

@ -6,90 +6,97 @@
import { Injectable, Output, EventEmitter } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { isNullOrUndefined } from 'common/utils';
import { environment } from 'environments/environment';
export enum UserRoles222 {
admin = 10000,
user = 1,
guest = 10
admin = 'admin',
user = 'user',
guest = 'guest',
}
@Injectable()
export class SessionService {
private tokenJwt = null;
public sessionId = null;
public userLogin = null;
public userAdmin = null;
public userEMail = null;
public userAvatar = null;
public userId = null;
public right: any = {};
@Output() change: EventEmitter<boolean> = new EventEmitter();
constructor() {
}
constructor() { }
/**
* @brief Create a new session.
*
* @param sessionId -
* @param userId -
* @param userLogin -
* @param userEMail -
* @param userAdmin -
* @param userAvatar -
* @param tokenJwt -
*/
create({ sessionId, userId, userLogin, userEMail, userAdmin, userAvatar, tokenJwt }: {
sessionId;
create({
userId,
userLogin,
tokenJwt,
}: {
userId: string;
userLogin: string;
userEMail: string;
userAdmin: boolean;
userBlocked: boolean;
userRemoved: boolean;
userAvatar: string;
tokenJwt: string;
}) {
console.log(`Session Create: userId=${userId} userLogin=${userLogin} userEMail=${userEMail} userAdmin=${userAdmin} userAvatar=${userAvatar} sessionId = ${sessionId} tokenJwt = ${tokenJwt}`);
console.log(
`Session Create: userId=${userId} userLogin=${userLogin} tokenJwt = ${tokenJwt}`
);
this.tokenJwt = tokenJwt;
this.sessionId = sessionId;
this.userId = userId;
this.userLogin = userLogin;
this.userAdmin = userAdmin;
this.userEMail = userEMail;
this.userAvatar = userAvatar;
this.right = this.parseToken(tokenJwt);
console.log(`Retrieve right: ${JSON.stringify(this.right, null, 4)}`);
this.change.emit(true);
}
b64_to_utf8(str: string): string {
return decodeURIComponent(window.atob(str));
}
parseToken(token: string): any {
const cut = token.split('.');
const decoded = this.b64_to_utf8(cut[1]);
const jsonModel = JSON.parse(decoded);
if (isNullOrUndefined(jsonModel.right)) {
return {};
}
if (isNullOrUndefined(jsonModel.right[environment.applName])) {
return {};
}
return jsonModel.right[environment.applName];
}
/**
* @brief destroy the current session.
*/
destroy() {
console.log('Session REMOVE');
let last = this.sessionId;
this.sessionId = null;
this.tokenJwt = undefined;
this.userId = null;
this.userLogin = null;
this.userAdmin = null;
this.userEMail = null;
this.userAvatar = null;
this.right = {};
this.change.emit(false);
}
getToken(): string | undefined {
return this.tokenJwt;
}
islogged() {
return this.sessionId !== null;
return this.userId !== null;
}
hasRight(type) {
hasRight(type: UserRoles222): boolean {
if (type === UserRoles222.admin) {
// sometime needed...
return this.userAdmin;
if (isNullOrUndefined(this.right.ADMIN)) {
return false;
}
return this.right.ADMIN;
}
if (type === UserRoles222.user) {
// is connected ==> is user
return this.sessionId !== null;
if (isNullOrUndefined(this.right.USER)) {
return false;
}
return this.right.USER;
}
if (type === UserRoles222.guest) {
// all the other ... maybe unneeded
@ -116,11 +123,10 @@ export class SessionService {
@Injectable()
export class OnlyUsersGuard implements CanActivate {
constructor(private sessionService: SessionService,
private router: Router) {};
constructor(private sessionService: SessionService, private router: Router) { }
canActivate() {
console.log("OnlyLoggedInUsers");
console.log('OnlyLoggedInUsers');
if (this.sessionService.hasRight(UserRoles222.user) || this.sessionService.hasRight(UserRoles222.admin)) {
return true;
} else {
@ -132,8 +138,7 @@ export class OnlyUsersGuard implements CanActivate {
@Injectable()
export class OnlyUsersGuardHome implements CanActivate {
constructor(private sessionService: SessionService,
private router: Router) {};
constructor(private sessionService: SessionService, private router: Router) { }
canActivate() {
if (this.sessionService.hasRight(UserRoles222.user) || this.sessionService.hasRight(UserRoles222.admin)) {
@ -146,8 +151,7 @@ export class OnlyUsersGuardHome implements CanActivate {
}
@Injectable()
export class OnlyUnregisteredGuardHome implements CanActivate {
constructor(private sessionService: SessionService,
private router: Router) {};
constructor(private sessionService: SessionService, private router: Router) { }
canActivate() {
if (!this.sessionService.islogged()) {
@ -161,8 +165,7 @@ export class OnlyUnregisteredGuardHome implements CanActivate {
@Injectable()
export class OnlyAdminGuard implements CanActivate {
constructor(private sessionService: SessionService,
private router: Router) {};
constructor(private sessionService: SessionService, private router: Router) { }
canActivate() {
if (this.sessionService.hasRight(UserRoles222.user)) {

View File

@ -13,14 +13,12 @@ import { HTTPMimeType, HTTPRequestModel, HttpWrapperService, ModelResponseHttp }
export class SSOService {
signUpEnable: boolean = undefined;
constructor(
private http: HttpWrapperService,
) {
constructor(private http: HttpWrapperService) {
console.log('Start SSOService');
}
utf8_to_b64(str: string): string {
// remove unneeded "=" padding
return window.btoa(encodeURIComponent( str )).replace("=", "");
return window.btoa(encodeURIComponent(str)).replace('=', '');
}
b64_to_utf8(str: string): string {
@ -30,14 +28,40 @@ export class SSOService {
* Request SSO connection
*/
hashLocalData(data?: string): string {
if (!isNullOrUndefined(data) && !isInArray(data, ["", "null", "NULL", "undefined", "---", "unregistered", "unregistered/", "forbidden", "forbidden/"])) {
if (
!isNullOrUndefined(data) &&
!isInArray(data, [
'',
'null',
'NULL',
'undefined',
'---',
'unregistered',
'unregistered/',
'forbidden',
'forbidden/',
])
) {
return this.utf8_to_b64(data);
}
let pathName = getApplicationLocation();
if (isInArray(pathName, ["sso", "/sso", "/sso/"])) {
const pathName = getApplicationLocation();
if (isInArray(pathName, ['sso', '/sso', '/sso/'])) {
return this.utf8_to_b64('home');
}
if (!isNullOrUndefined(pathName) && !isInArray(pathName, ["", "null", "NULL", "undefined", "---", "unregistered", "unregistered/", "forbidden", "forbidden/"])) {
if (
!isNullOrUndefined(pathName) &&
!isInArray(pathName, [
'',
'null',
'NULL',
'undefined',
'---',
'unregistered',
'unregistered/',
'forbidden',
'forbidden/',
])
) {
return this.utf8_to_b64(pathName);
}
return this.utf8_to_b64('home');
@ -46,17 +70,22 @@ export class SSOService {
* Request SSO connection
*/
unHashLocalData(data: string): string | undefined {
if (isNullOrUndefined(data) || isInArray(data, ["", "null", "NULL", "undefined", "---"])) {
if (isNullOrUndefined(data) || isInArray(data, ['', 'null', 'NULL', 'undefined', '---'])) {
return undefined;
}
try {
return this.b64_to_utf8(data);
}
catch (ex) {
} catch (ex) {
console.error(`Can not convert the data: ${data}`);
}
return undefined;
}
/**
* Request Open SSO Global website
*/
requestOpenSite(): void {
window.location.href = environment.ssoSite;
}
/**
* Request SSO connection
*/
@ -83,24 +112,24 @@ export class SSOService {
let self = this;
return new Promise((resolve, reject) => {
if (isNullOrUndefined(self.signUpEnable)) {
this.http.requestJson({
this.http
.requestJson({
server: 'karso',
endPoint: 'system_config/is_sign_up_availlable',
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON,
contentType: HTTPMimeType.JSON,
}).then((response: ModelResponseHttp) =>{
})
.then((response: ModelResponseHttp) => {
self.signUpEnable = response.data.signup;
resolve(self.signUpEnable);
}).catch((error:any) => {
})
.catch((error: any) => {
reject(`return ERROR ${JSON.stringify(error, null, 2)}`);
});
return;
}
resolve(self.signUpEnable);
});
}
}

View File

@ -14,22 +14,21 @@ import { SessionService } from './session';
import { SSOService } from './sso';
import { getApplicationLocation, isNullOrUndefined, sha512 } from 'common/utils';
/*
interface MessageLogIn {
login: string;
method: string;
time: number;
password: string;
}
interface MessageAnswer_USER_CONNECT {
sessionId: string,
login: string,
eMail: string,
role: string,
avatar: string
sessionId: string;
login: string;
eMail: string;
role: string;
avatar: string;
}
*/
@Injectable()
export class UserService {
// 0: Not hide password; 1 hide password;
@ -42,7 +41,8 @@ export class UserService {
private storageService: StorageService,
private http: HttpWrapperService,
private sessionService: SessionService,
private ssoService: SSOService) {
private ssoService: SSOService
) {
console.log('Start UserService');
}
@ -51,8 +51,7 @@ export class UserService {
*/
logOut(): void {
this.removeSession();
this.ssoService.requestSignOut("home");
this.ssoService.requestSignOut('home');
}
removeSession(): void {
this.storageService.remove(this.cookiesRememberMe);
@ -74,34 +73,44 @@ export class UserService {
const tokenData = decodeURIComponent(window.atob(elems[1]));
// console.error(`Retreive local token: \nheader=${tokenHeader} \ndata=${tokenData}`);
const parsedData = JSON.parse(tokenData);
console.debug(`Retreive token exp data=${new Date(parsedData.exp*1000).toISOString()} < ${new Date().toISOString()}`);
console.debug(
`Retreive token exp data=${new Date(parsedData.exp * 1000).toISOString()} < ${new Date().toISOString()}`
);
const expireIn = new Date(parsedData.exp * 1000);
const nowTime = new Date();
// TODO: set a marging of 2 hours...
return expireIn > nowTime;
}
getRememberMe(): boolean {
return this.storageService.get(this.cookiesRememberMe) === 'true';
}
/**
* Check if the system can be connected
*/
checkAutoConnect(): Promise<void> {
let locationOrigin = getApplicationLocation();
let self = this;
const self = this;
return new Promise<void>((resolve, reject) => {
// Need to use the windows global route to prevent the log in cycle ...
// And in the mlain application position, the route does not have curently root the page
let pathName = window.location.pathname;
// console.log("start Path-name: '" + pathName + "'");
// console.log("check with: '" + environment.applName + "/sso/" + "'");
if (pathName.startsWith("/sso/") || pathName.startsWith(environment.applName + "/sso/")) {
console.log(" ==> SSo section");
if (pathName.startsWith('/sso/') || pathName.startsWith(environment.applName + '/sso/')) {
console.log(' ==> SSo section');
reject();
return;
}
console.log(" ==> Check if need reconnect?");
let rememberMe = self.storageService.get(self.cookiesRememberMe)==="true";
console.log(' ==> Check if need reconnect?');
let rememberMe = self.getRememberMe();
// TODO: in case of jest reload ==> no need to manage the SSO ==> just keep the token ... it in enought...
let token = null;
if (isNullOrUndefined(environment.tokenStoredInPermanentStorage) || environment.tokenStoredInPermanentStorage !== true) {
if (
isNullOrUndefined(environment.tokenStoredInPermanentStorage) ||
environment.tokenStoredInPermanentStorage !== true
) {
token = self.storageService.getSession(self.cookiesToken);
} else {
token = self.storageService.get(self.cookiesToken);
@ -111,11 +120,13 @@ export class UserService {
// remove in case of fail !!!
this.storageService.removeSession(this.cookiesToken);
this.storageService.remove(this.cookiesToken);
self.startSession(token, rememberMe).then(() => {
self.startSession(token, rememberMe)
.then(() => {
self.router.navigateByUrl(locationOrigin);
console.log(`update global URL = ${locationOrigin}`);
resolve();
}).catch(() => {
})
.catch(() => {
// jump in the sign-in page (automatically of request remember-me)
if (rememberMe) {
// jump to the sso !!! (remove local data to prevent login loop)
@ -143,52 +154,58 @@ export class UserService {
}
startSession(token: string, rememberMe: boolean): Promise<string> {
let self = this;
const self = this;
return new Promise((resolve, reject) => {
self.retreiveMe(token).then(
(value2: boolean) => {
self.retreiveMe(token)
.then((value2: boolean) => {
if (rememberMe === true) {
self.storageService.set(self.cookiesRememberMe, rememberMe?"true":"false");
self.storageService.set(self.cookiesRememberMe, rememberMe ? 'true' : 'false');
}
if (isNullOrUndefined(environment.tokenStoredInPermanentStorage) || environment.tokenStoredInPermanentStorage !== true) {
if (
isNullOrUndefined(environment.tokenStoredInPermanentStorage) ||
environment.tokenStoredInPermanentStorage !== true
) {
self.storageService.setSession(self.cookiesToken, token);
} else {
self.storageService.set(self.cookiesToken, token);
}
resolve(self.sessionService.getLogin());
}).catch(() => {
})
.catch(() => {
reject('sdfsdfsdf');
});
});
}
retreiveMe(token: string): Promise<boolean> {
console.log(`AuthService.loginWithToken ... '${token}'`);
let self = this;
const self = this;
return new Promise((resolve, reject) => {
this.http.requestJson({
this.http
.requestJson({
// server: 'karso',
endPoint: 'users/me',
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON,
contentType: HTTPMimeType.JSON,
authorization: `Yota ${token}`, // special case, the token is set after this request...
}).then((response: ModelResponseHttp) =>{
})
.then((response: ModelResponseHttp) => {
// TODO: check type ...
console.log(`loginWithToken : get some data to check: ${JSON.stringify(response.data)}`)
self.sessionService.create(
{
sessionId: response.data.sessionId,
console.log(`loginWithToken : get some data to check: ${JSON.stringify(response.data)}`);
self.sessionService.create({
//sessionId: response.data.sessionId,
userId: response.data.id,
userLogin: response.data.login,
userEMail: response.data.email,
userAdmin: response.data.admin,
userBlocked: response.data.blocked,
userRemoved: response.data.removed,
userAvatar: response.data.avatar,
//userEMail: response.data.email,
//userAdmin: response.data.admin,
//userBlocked: response.data.blocked,
//userRemoved: response.data.removed,
//userAvatar: response.data.avatar,
tokenJwt: token,
});
resolve(true);
}).catch((error:any) => {
})
.catch((error: any) => {
reject(`return ERROR ${JSON.stringify(error, null, 2)}`);
});
});
@ -202,7 +219,7 @@ export class UserService {
method: 'v?',
login: login,
email: email,
password: password
password: password,
};
console.log(`call users data=${JSON.stringify(data, null, 2)}`);
@ -211,18 +228,21 @@ export class UserService {
}
return new Promise((resolve, reject) => {
this.http.requestJson({
this.http
.requestJson({
server: 'karso',
endPoint: 'users',
requestType: HTTPRequestModel.POST,
accept: HTTPMimeType.JSON,
contentType: HTTPMimeType.JSON,
body: data,
}).then((response: ModelResponseHttp) =>{
})
.then((response: ModelResponseHttp) => {
// TODO: check type ...
console.log(`createSha : get some data to check: ${JSON.stringify(response.data)}`)
console.log(`createSha : get some data to check: ${JSON.stringify(response.data)}`);
resolve(response.data);
}).catch((error:any) => {
})
.catch((error: any) => {
reject(`return ERROR ${JSON.stringify(error, null, 2)}`);
});
});
@ -244,4 +264,3 @@ export class UserService {
return false;
}
}

View File

@ -1,4 +1,4 @@
import { environment } from "environments/environment";
import { environment } from 'environments/environment';
export function getApplicationLocation(): string {
let pathName = location.pathname;

View File

@ -4,8 +4,8 @@
* @license PROPRIETARY (see license file)
*/
import { NodeData } from "../model";
import { isArray, isNullOrUndefined } from "./validator";
import { NodeData } from '../model';
import { isArray, isNullOrUndefined } from './validator';
export enum TypeCheck {
CONTAINS = 'C',
@ -51,10 +51,7 @@ export class DataInterface {
}
return out;
}
constructor(
private name: string,
private bdd: NodeData[] ) {
}
constructor(private name: string, private bdd: NodeData[]) {}
public getTableIndex(id: number) {
for (let iii = 0; iii < this.bdd.length; iii++) {
@ -173,7 +170,10 @@ export class DataInterface {
}
return value === listValues;
}
public static containsOneIn(value: number|string|boolean|number[]|string[], listValues:number|string|boolean|number[]|string[]): boolean {
public static containsOneIn(
value: number | string | boolean | number[] | string[],
listValues: number | string | boolean | number[] | string[]
): boolean {
if (isArray(value)) {
for (let iii = 0; iii < value.length; iii++) {
if (this.existIn(value[iii], listValues) === true) {
@ -192,10 +192,10 @@ export class DataInterface {
if (select.length === 0) {
find = false;
}
// console.log("Check : " + JSON.stringify(_values[iii_elem], null, 2));
//console.log("Check : " + JSON.stringify(values[iiiElem], null, 2));
for (let iiiSelect = 0; iiiSelect < select.length; iiiSelect++) {
let control = select[iiiSelect];
let valueElement = values[iiiElem][control.key]
let valueElement = values[iiiElem][control.key];
//console.log(" valueElement : " + JSON.stringify(valueElement, null, 2));
if (isArray(control.value)) {
if (control.check === TypeCheck.CONTAINS) {
@ -328,4 +328,3 @@ export class DataInterface {
return out;
}
}

View File

@ -1,9 +1,25 @@
import { getApplicationLocation } from "./applPath";
import { DataInterface, TypeCheck } from "./dataInterface";
import { sha512 } from "./sha512";
import { isArray, isArrayOf, isBoolean, isNull, isNullOrUndefined, isNumber, isNumberFinite, isObject, isOptionalOf, isOptionalArrayOf, isString, isUndefined, isArrayOfs, isInArray, isStringNullOrUndefined } from "./validator";
import { getApplicationLocation } from './applPath';
import { DataInterface, TypeCheck } from './dataInterface';
import { sha512 } from './sha512';
import {
isArray,
isArrayOf,
isBoolean,
isNull,
isNullOrUndefined,
isNumber,
isNumberFinite,
isObject,
isOptionalOf,
isOptionalArrayOf,
isString,
isUndefined,
isArrayOfs,
isInArray,
isStringNullOrUndefined,
isNumeric,
} from './validator';
import { checkEmailValidity, checkLoginValidity, checkPasswordValidity, createLoginState, createPasswordState, getLoginType } from './validatorPasswordEmail';
export {
isNumber,
@ -25,5 +41,11 @@ export {
TypeCheck,
getApplicationLocation,
sha512,
}
createPasswordState,
checkEmailValidity,
checkPasswordValidity,
checkLoginValidity,
getLoginType,
createLoginState,
isNumeric,
};

View File

@ -1,7 +1,3 @@
export function isMobileAgent() {
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
}

View File

@ -8,51 +8,99 @@ export function sha512(str) {
this.lowOrder = lsint_32;
}
let H = [new int64(0x6a09e667, 0xf3bcc908), new int64(0xbb67ae85, 0x84caa73b),
new int64(0x3c6ef372, 0xfe94f82b), new int64(0xa54ff53a, 0x5f1d36f1),
new int64(0x510e527f, 0xade682d1), new int64(0x9b05688c, 0x2b3e6c1f),
new int64(0x1f83d9ab, 0xfb41bd6b), new int64(0x5be0cd19, 0x137e2179)];
let H = [
new int64(0x6a09e667, 0xf3bcc908),
new int64(0xbb67ae85, 0x84caa73b),
new int64(0x3c6ef372, 0xfe94f82b),
new int64(0xa54ff53a, 0x5f1d36f1),
new int64(0x510e527f, 0xade682d1),
new int64(0x9b05688c, 0x2b3e6c1f),
new int64(0x1f83d9ab, 0xfb41bd6b),
new int64(0x5be0cd19, 0x137e2179),
];
let K = [new int64(0x428a2f98, 0xd728ae22), new int64(0x71374491, 0x23ef65cd),
new int64(0xb5c0fbcf, 0xec4d3b2f), new int64(0xe9b5dba5, 0x8189dbbc),
new int64(0x3956c25b, 0xf348b538), new int64(0x59f111f1, 0xb605d019),
new int64(0x923f82a4, 0xaf194f9b), new int64(0xab1c5ed5, 0xda6d8118),
new int64(0xd807aa98, 0xa3030242), new int64(0x12835b01, 0x45706fbe),
new int64(0x243185be, 0x4ee4b28c), new int64(0x550c7dc3, 0xd5ffb4e2),
new int64(0x72be5d74, 0xf27b896f), new int64(0x80deb1fe, 0x3b1696b1),
new int64(0x9bdc06a7, 0x25c71235), new int64(0xc19bf174, 0xcf692694),
new int64(0xe49b69c1, 0x9ef14ad2), new int64(0xefbe4786, 0x384f25e3),
new int64(0x0fc19dc6, 0x8b8cd5b5), new int64(0x240ca1cc, 0x77ac9c65),
new int64(0x2de92c6f, 0x592b0275), new int64(0x4a7484aa, 0x6ea6e483),
new int64(0x5cb0a9dc, 0xbd41fbd4), new int64(0x76f988da, 0x831153b5),
new int64(0x983e5152, 0xee66dfab), new int64(0xa831c66d, 0x2db43210),
new int64(0xb00327c8, 0x98fb213f), new int64(0xbf597fc7, 0xbeef0ee4),
new int64(0xc6e00bf3, 0x3da88fc2), new int64(0xd5a79147, 0x930aa725),
new int64(0x06ca6351, 0xe003826f), new int64(0x14292967, 0x0a0e6e70),
new int64(0x27b70a85, 0x46d22ffc), new int64(0x2e1b2138, 0x5c26c926),
new int64(0x4d2c6dfc, 0x5ac42aed), new int64(0x53380d13, 0x9d95b3df),
new int64(0x650a7354, 0x8baf63de), new int64(0x766a0abb, 0x3c77b2a8),
new int64(0x81c2c92e, 0x47edaee6), new int64(0x92722c85, 0x1482353b),
new int64(0xa2bfe8a1, 0x4cf10364), new int64(0xa81a664b, 0xbc423001),
new int64(0xc24b8b70, 0xd0f89791), new int64(0xc76c51a3, 0x0654be30),
new int64(0xd192e819, 0xd6ef5218), new int64(0xd6990624, 0x5565a910),
new int64(0xf40e3585, 0x5771202a), new int64(0x106aa070, 0x32bbd1b8),
new int64(0x19a4c116, 0xb8d2d0c8), new int64(0x1e376c08, 0x5141ab53),
new int64(0x2748774c, 0xdf8eeb99), new int64(0x34b0bcb5, 0xe19b48a8),
new int64(0x391c0cb3, 0xc5c95a63), new int64(0x4ed8aa4a, 0xe3418acb),
new int64(0x5b9cca4f, 0x7763e373), new int64(0x682e6ff3, 0xd6b2b8a3),
new int64(0x748f82ee, 0x5defb2fc), new int64(0x78a5636f, 0x43172f60),
new int64(0x84c87814, 0xa1f0ab72), new int64(0x8cc70208, 0x1a6439ec),
new int64(0x90befffa, 0x23631e28), new int64(0xa4506ceb, 0xde82bde9),
new int64(0xbef9a3f7, 0xb2c67915), new int64(0xc67178f2, 0xe372532b),
new int64(0xca273ece, 0xea26619c), new int64(0xd186b8c7, 0x21c0c207),
new int64(0xeada7dd6, 0xcde0eb1e), new int64(0xf57d4f7f, 0xee6ed178),
new int64(0x06f067aa, 0x72176fba), new int64(0x0a637dc5, 0xa2c898a6),
new int64(0x113f9804, 0xbef90dae), new int64(0x1b710b35, 0x131c471b),
new int64(0x28db77f5, 0x23047d84), new int64(0x32caab7b, 0x40c72493),
new int64(0x3c9ebe0a, 0x15c9bebc), new int64(0x431d67c4, 0x9c100d4c),
new int64(0x4cc5d4be, 0xcb3e42b6), new int64(0x597f299c, 0xfc657e2a),
new int64(0x5fcb6fab, 0x3ad6faec), new int64(0x6c44198c, 0x4a475817)];
let K = [
new int64(0x428a2f98, 0xd728ae22),
new int64(0x71374491, 0x23ef65cd),
new int64(0xb5c0fbcf, 0xec4d3b2f),
new int64(0xe9b5dba5, 0x8189dbbc),
new int64(0x3956c25b, 0xf348b538),
new int64(0x59f111f1, 0xb605d019),
new int64(0x923f82a4, 0xaf194f9b),
new int64(0xab1c5ed5, 0xda6d8118),
new int64(0xd807aa98, 0xa3030242),
new int64(0x12835b01, 0x45706fbe),
new int64(0x243185be, 0x4ee4b28c),
new int64(0x550c7dc3, 0xd5ffb4e2),
new int64(0x72be5d74, 0xf27b896f),
new int64(0x80deb1fe, 0x3b1696b1),
new int64(0x9bdc06a7, 0x25c71235),
new int64(0xc19bf174, 0xcf692694),
new int64(0xe49b69c1, 0x9ef14ad2),
new int64(0xefbe4786, 0x384f25e3),
new int64(0x0fc19dc6, 0x8b8cd5b5),
new int64(0x240ca1cc, 0x77ac9c65),
new int64(0x2de92c6f, 0x592b0275),
new int64(0x4a7484aa, 0x6ea6e483),
new int64(0x5cb0a9dc, 0xbd41fbd4),
new int64(0x76f988da, 0x831153b5),
new int64(0x983e5152, 0xee66dfab),
new int64(0xa831c66d, 0x2db43210),
new int64(0xb00327c8, 0x98fb213f),
new int64(0xbf597fc7, 0xbeef0ee4),
new int64(0xc6e00bf3, 0x3da88fc2),
new int64(0xd5a79147, 0x930aa725),
new int64(0x06ca6351, 0xe003826f),
new int64(0x14292967, 0x0a0e6e70),
new int64(0x27b70a85, 0x46d22ffc),
new int64(0x2e1b2138, 0x5c26c926),
new int64(0x4d2c6dfc, 0x5ac42aed),
new int64(0x53380d13, 0x9d95b3df),
new int64(0x650a7354, 0x8baf63de),
new int64(0x766a0abb, 0x3c77b2a8),
new int64(0x81c2c92e, 0x47edaee6),
new int64(0x92722c85, 0x1482353b),
new int64(0xa2bfe8a1, 0x4cf10364),
new int64(0xa81a664b, 0xbc423001),
new int64(0xc24b8b70, 0xd0f89791),
new int64(0xc76c51a3, 0x0654be30),
new int64(0xd192e819, 0xd6ef5218),
new int64(0xd6990624, 0x5565a910),
new int64(0xf40e3585, 0x5771202a),
new int64(0x106aa070, 0x32bbd1b8),
new int64(0x19a4c116, 0xb8d2d0c8),
new int64(0x1e376c08, 0x5141ab53),
new int64(0x2748774c, 0xdf8eeb99),
new int64(0x34b0bcb5, 0xe19b48a8),
new int64(0x391c0cb3, 0xc5c95a63),
new int64(0x4ed8aa4a, 0xe3418acb),
new int64(0x5b9cca4f, 0x7763e373),
new int64(0x682e6ff3, 0xd6b2b8a3),
new int64(0x748f82ee, 0x5defb2fc),
new int64(0x78a5636f, 0x43172f60),
new int64(0x84c87814, 0xa1f0ab72),
new int64(0x8cc70208, 0x1a6439ec),
new int64(0x90befffa, 0x23631e28),
new int64(0xa4506ceb, 0xde82bde9),
new int64(0xbef9a3f7, 0xb2c67915),
new int64(0xc67178f2, 0xe372532b),
new int64(0xca273ece, 0xea26619c),
new int64(0xd186b8c7, 0x21c0c207),
new int64(0xeada7dd6, 0xcde0eb1e),
new int64(0xf57d4f7f, 0xee6ed178),
new int64(0x06f067aa, 0x72176fba),
new int64(0x0a637dc5, 0xa2c898a6),
new int64(0x113f9804, 0xbef90dae),
new int64(0x1b710b35, 0x131c471b),
new int64(0x28db77f5, 0x23047d84),
new int64(0x32caab7b, 0x40c72493),
new int64(0x3c9ebe0a, 0x15c9bebc),
new int64(0x431d67c4, 0x9c100d4c),
new int64(0x4cc5d4be, 0xcb3e42b6),
new int64(0x597f299c, 0xfc657e2a),
new int64(0x5fcb6fab, 0x3ad6faec),
new int64(0x6c44198c, 0x4a475817),
];
let W = new Array(64);
let a, b, c, d, e, f, g, h, i, j;
@ -76,14 +124,14 @@ export function sha512(str) {
}
function binb2hex(binarray) {
let hex_tab = "0123456789abcdef";
let str = "";
let hex_tab = '0123456789abcdef';
let str = '';
let length = binarray.length * 4;
let srcByte;
for (let i = 0; i < length; i += 1) {
srcByte = binarray[i >> 2] >> ((3 - (i % 4)) * 8);
str += hex_tab.charAt((srcByte >> 4) & 0xF) + hex_tab.charAt(srcByte & 0xF);
str += hex_tab.charAt((srcByte >> 4) & 0xf) + hex_tab.charAt(srcByte & 0xf);
}
return str;
@ -92,13 +140,13 @@ export function sha512(str) {
function safe_add_2(x, y) {
let lsw, msw, lowOrder, highOrder;
lsw = (x.lowOrder & 0xFFFF) + (y.lowOrder & 0xFFFF);
lsw = (x.lowOrder & 0xffff) + (y.lowOrder & 0xffff);
msw = (x.lowOrder >>> 16) + (y.lowOrder >>> 16) + (lsw >>> 16);
lowOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF);
lowOrder = ((msw & 0xffff) << 16) | (lsw & 0xffff);
lsw = (x.highOrder & 0xFFFF) + (y.highOrder & 0xFFFF) + (msw >>> 16);
lsw = (x.highOrder & 0xffff) + (y.highOrder & 0xffff) + (msw >>> 16);
msw = (x.highOrder >>> 16) + (y.highOrder >>> 16) + (lsw >>> 16);
highOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF);
highOrder = ((msw & 0xffff) << 16) | (lsw & 0xffff);
return new int64(highOrder, lowOrder);
}
@ -106,13 +154,18 @@ export function sha512(str) {
function safe_add_4(a, b, c, d) {
let lsw, msw, lowOrder, highOrder;
lsw = (a.lowOrder & 0xFFFF) + (b.lowOrder & 0xFFFF) + (c.lowOrder & 0xFFFF) + (d.lowOrder & 0xFFFF);
lsw = (a.lowOrder & 0xffff) + (b.lowOrder & 0xffff) + (c.lowOrder & 0xffff) + (d.lowOrder & 0xffff);
msw = (a.lowOrder >>> 16) + (b.lowOrder >>> 16) + (c.lowOrder >>> 16) + (d.lowOrder >>> 16) + (lsw >>> 16);
lowOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF);
lowOrder = ((msw & 0xffff) << 16) | (lsw & 0xffff);
lsw = (a.highOrder & 0xFFFF) + (b.highOrder & 0xFFFF) + (c.highOrder & 0xFFFF) + (d.highOrder & 0xFFFF) + (msw >>> 16);
lsw =
(a.highOrder & 0xffff) +
(b.highOrder & 0xffff) +
(c.highOrder & 0xffff) +
(d.highOrder & 0xffff) +
(msw >>> 16);
msw = (a.highOrder >>> 16) + (b.highOrder >>> 16) + (c.highOrder >>> 16) + (d.highOrder >>> 16) + (lsw >>> 16);
highOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF);
highOrder = ((msw & 0xffff) << 16) | (lsw & 0xffff);
return new int64(highOrder, lowOrder);
}
@ -120,13 +173,36 @@ export function sha512(str) {
function safe_add_5(a, b, c, d, e) {
let lsw, msw, lowOrder, highOrder;
lsw = (a.lowOrder & 0xFFFF) + (b.lowOrder & 0xFFFF) + (c.lowOrder & 0xFFFF) + (d.lowOrder & 0xFFFF) + (e.lowOrder & 0xFFFF);
msw = (a.lowOrder >>> 16) + (b.lowOrder >>> 16) + (c.lowOrder >>> 16) + (d.lowOrder >>> 16) + (e.lowOrder >>> 16) + (lsw >>> 16);
lowOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF);
lsw =
(a.lowOrder & 0xffff) +
(b.lowOrder & 0xffff) +
(c.lowOrder & 0xffff) +
(d.lowOrder & 0xffff) +
(e.lowOrder & 0xffff);
msw =
(a.lowOrder >>> 16) +
(b.lowOrder >>> 16) +
(c.lowOrder >>> 16) +
(d.lowOrder >>> 16) +
(e.lowOrder >>> 16) +
(lsw >>> 16);
lowOrder = ((msw & 0xffff) << 16) | (lsw & 0xffff);
lsw = (a.highOrder & 0xFFFF) + (b.highOrder & 0xFFFF) + (c.highOrder & 0xFFFF) + (d.highOrder & 0xFFFF) + (e.highOrder & 0xFFFF) + (msw >>> 16);
msw = (a.highOrder >>> 16) + (b.highOrder >>> 16) + (c.highOrder >>> 16) + (d.highOrder >>> 16) + (e.highOrder >>> 16) + (lsw >>> 16);
highOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF);
lsw =
(a.highOrder & 0xffff) +
(b.highOrder & 0xffff) +
(c.highOrder & 0xffff) +
(d.highOrder & 0xffff) +
(e.highOrder & 0xffff) +
(msw >>> 16);
msw =
(a.highOrder >>> 16) +
(b.highOrder >>> 16) +
(c.highOrder >>> 16) +
(d.highOrder >>> 16) +
(e.highOrder >>> 16) +
(lsw >>> 16);
highOrder = ((msw & 0xffff) << 16) | (lsw & 0xffff);
return new int64(highOrder, lowOrder);
}
@ -182,7 +258,9 @@ export function sha512(str) {
}
function gamma0(x) {
let rotr1 = rotr(x, 1), rotr8 = rotr(x, 8), shr7 = shr(x, 7);
let rotr1 = rotr(x, 1),
rotr8 = rotr(x, 8),
shr7 = shr(x, 7);
return new int64(
rotr1.highOrder ^ rotr8.highOrder ^ shr7.highOrder,
@ -203,15 +281,9 @@ export function sha512(str) {
function shr(x, n) {
if (n <= 32) {
return new int64(
x.highOrder >>> n,
x.lowOrder >>> n | (x.highOrder << (32 - n))
);
return new int64(x.highOrder >>> n, (x.lowOrder >>> n) | (x.highOrder << (32 - n)));
} else {
return new int64(
0,
x.highOrder << (32 - n)
);
return new int64(0, x.highOrder << (32 - n));
}
}
@ -219,7 +291,7 @@ export function sha512(str) {
let strlen = str.length * charsize;
str = str2binb(str);
str[strlen >> 5] |= 0x80 << (24 - strlen % 32);
str[strlen >> 5] |= 0x80 << (24 - (strlen % 32));
str[(((strlen + 128) >> 10) << 5) + 31] = strlen;
for (let i = 0; i < str.length; i += 32) {

View File

@ -1,15 +1,19 @@
export function isNumeric(val: string): boolean {
return !isNaN(Number(val));
}
export function isNumber(data: any): data is number {
return typeof data === "number";
return typeof data === 'number';
}
export function isNumberFinite(data: any): data is number {
return isNumber(data) && isFinite(data);
}
export function isBoolean(data: any): data is boolean {
return typeof data === "boolean";
return typeof data === 'boolean';
}
export function isString(data: any): data is string {
return typeof data === "string";
return typeof data === 'string';
}
export function isArray(data: any): data is any[] {
return Array.isArray(data);
@ -24,12 +28,10 @@ export function isNullOrUndefined(data: any): data is undefined | null {
return data === undefined || data === null;
}
export function isStringNullOrUndefined(data: any): data is undefined | null {
return data === "undefined" || data === "null" || data === "";
return data === 'undefined' || data === 'null' || data === '';
}
export function isObject(data: any): data is any {
return !isNullOrUndefined(data)
&& typeof data === 'object'
&& !isArray(data);
return !isNullOrUndefined(data) && typeof data === 'object' && !isArray(data);
}
export function isInArray(data: any, listElment: any[]): boolean {
for (let iii = 0; iii < listElment.length; iii++) {
@ -40,7 +42,11 @@ export function isInArray(data: any, listElment: any[]): boolean {
return false;
}
export function isArrayOf<TYPE>(data: any, typeChecker: (subData: any) => subData is TYPE, length?: number): data is TYPE[] {
export function isArrayOf<TYPE>(
data: any,
typeChecker: (subData: any) => subData is TYPE,
length?: number
): data is TYPE[] {
if (!isArray(data)) {
return false;
}
@ -52,10 +58,12 @@ export function isArrayOf<TYPE>(data: any, typeChecker: (subData: any) => subDat
}
return true;
}
export function isArrayOfs<TYPE,TYPE2,TYPE3>(data: any,
export function isArrayOfs<TYPE, TYPE2, TYPE3>(
data: any,
typeChecker: (subData: any) => subData is TYPE,
typeChecker2?: (subData: any) => subData is TYPE2,
typeChecker3?: (subData: any) => subData is TYPE3): data is (TYPE|TYPE2|TYPE3)[] {
typeChecker3?: (subData: any) => subData is TYPE3
): data is (TYPE | TYPE2 | TYPE3)[] {
if (!isArray(data)) {
return false;
}
@ -75,11 +83,16 @@ export function isArrayOfs<TYPE,TYPE2,TYPE3>(data: any,
return true;
}
export function isOptionalOf<TYPE>(data: any, typeChecker: (subData: any) => subData is TYPE): data is TYPE | undefined {
export function isOptionalOf<TYPE>(
data: any,
typeChecker: (subData: any) => subData is TYPE
): data is TYPE | undefined {
return isUndefined(data) || typeChecker(data);
}
export function isOptionalArrayOf<TYPE>(data: any, typeChecker: (subData: any) => subData is TYPE): data is TYPE[] | undefined {
export function isOptionalArrayOf<TYPE>(
data: any,
typeChecker: (subData: any) => subData is TYPE
): data is TYPE[] | undefined {
return isUndefined(data) || isArrayOf(data, typeChecker);
}

Some files were not shown because too many files have changed in this diff Show More