Compare commits
35 Commits
Author | SHA1 | Date | |
---|---|---|---|
2c0fb99202 | |||
1cf08390ec | |||
6107b95dcd | |||
e9af64405b | |||
725cd54d92 | |||
08eb0f878a | |||
619e9aa4b8 | |||
6181022814 | |||
3f96b870a0 | |||
5eba6d32b6 | |||
a24484b5f9 | |||
77f8527fc4 | |||
75cca15898 | |||
f0b2a859db | |||
a6fe889d4c | |||
ad7ff2c340 | |||
1271885124 | |||
dde514a1a0 | |||
dc7131843d | |||
091390e025 | |||
3377f80fbc | |||
4cf71f35b6 | |||
faaf3b280b | |||
0687369164 | |||
147264eb7f | |||
ec93c31acb | |||
873f0acff5 | |||
244f8a988e | |||
d49e1d06fe | |||
53c3cfefe3 | |||
90fb1ed411 | |||
30bc82edb3 | |||
1d4c547d89 | |||
21d53b77f2 | |||
3b27edfa3b |
3
.gitignore
vendored
3
.gitignore
vendored
@ -53,6 +53,8 @@ testem.log
|
||||
# System Files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
/env_dev/data
|
||||
/env_dev/dataMongo
|
||||
|
||||
backPY/env
|
||||
|
||||
@ -62,3 +64,4 @@ __pycache__
|
||||
|
||||
.design/
|
||||
.vscode/
|
||||
front/storybook-static
|
||||
|
@ -5,7 +5,7 @@ version_file="../version.txt"
|
||||
# update new release dependency
|
||||
cd back
|
||||
# update the Maven version number
|
||||
mvn versions:set -DnewVersion=$(sed 's/DEV/SNAPSHOT/g' $version_file)
|
||||
mvn versions:set -DnewVersion=$(sed 's/dev/SNAPSHOT/g' $version_file)
|
||||
if grep -q "DEV" "$version_file"; then
|
||||
# update all versions release of dependency
|
||||
mvn versions:use-latest-releases
|
||||
@ -19,11 +19,14 @@ cd -
|
||||
|
||||
|
||||
cd front
|
||||
if grep -q "DEV" "$version_file"; then
|
||||
if grep -q "dev" "$version_file"; then
|
||||
# update all dependency
|
||||
pnpm install
|
||||
pnpm run update_packages
|
||||
else
|
||||
# in case of release ==> can not do it automatically ...
|
||||
echo not implemented
|
||||
fi
|
||||
|
||||
cd -
|
||||
|
||||
|
74
Dockerfile
74
Dockerfile
@ -3,23 +3,31 @@
|
||||
## buyilding-end install applications:
|
||||
##
|
||||
######################################################################################
|
||||
FROM archlinux:base-devel AS builder
|
||||
FROM archlinux:base-devel AS common
|
||||
# update system
|
||||
RUN pacman -Syu --noconfirm && pacman-db-upgrade \
|
||||
&& pacman -S --noconfirm jdk-openjdk maven npm pnpm \
|
||||
&& pacman -S --noconfirm jdk-openjdk \
|
||||
&& pacman -Scc --noconfirm
|
||||
|
||||
WORKDIR /tmp
|
||||
|
||||
FROM common AS builder
|
||||
# update system
|
||||
RUN pacman -Syu --noconfirm && pacman-db-upgrade \
|
||||
&& pacman -S --noconfirm maven npm pnpm \
|
||||
&& pacman -Scc --noconfirm
|
||||
|
||||
ENV PATH /tmp/node_modules/.bin:$PATH
|
||||
WORKDIR /tmp
|
||||
|
||||
######################################################################################
|
||||
##
|
||||
## Build back:
|
||||
##
|
||||
######################################################################################
|
||||
FROM builder AS buildBack
|
||||
COPY back/pom.xml /tmp
|
||||
COPY back/src /tmp/src/
|
||||
FROM builder AS build_back
|
||||
COPY back/pom.xml ./
|
||||
COPY back/Formatter.xml ./
|
||||
COPY back/src ./src/
|
||||
RUN mvn clean compile assembly:single
|
||||
|
||||
######################################################################################
|
||||
@ -27,27 +35,44 @@ RUN mvn clean compile assembly:single
|
||||
## Build front:
|
||||
##
|
||||
######################################################################################
|
||||
FROM builder AS buildFront
|
||||
FROM builder AS dependency_front
|
||||
|
||||
RUN echo "@kangaroo-and-rabbit:registry=https://gitea.atria-soft.org/api/packages/kangaroo-and-rabbit/npm/" > /root/.npmrc
|
||||
|
||||
ADD front/package.json \
|
||||
front/karma.conf.js \
|
||||
front/protractor.conf.js \
|
||||
/tmp/
|
||||
front/pnpm-lock.yaml \
|
||||
./
|
||||
ADD front/src/theme ./src/theme
|
||||
|
||||
# install and cache app dependencies
|
||||
RUN pnpm install
|
||||
RUN pnpm install --prod=false
|
||||
|
||||
ADD front/e2e \
|
||||
###############################################################
|
||||
## Install sources
|
||||
###############################################################
|
||||
FROM dependency_front AS load_sources_front
|
||||
|
||||
# JUST to get the vertion of the application and his sha...
|
||||
COPY front/build.js \
|
||||
front/version.txt \
|
||||
front/tsconfig.json \
|
||||
front/tslint.json \
|
||||
front/angular.json \
|
||||
/tmp/
|
||||
ADD front/src /tmp/src
|
||||
front/tsconfig.node.json \
|
||||
front/vite.config.mts \
|
||||
front/index.html \
|
||||
./
|
||||
COPY front/public ./public
|
||||
COPY front/src ./src
|
||||
|
||||
# generate build
|
||||
RUN ng build --output-path=dist --configuration=production --base-href=/karusic/ --deploy-url=/karusic/
|
||||
#We are not in prod mode ==> we need to overwrite the production env.
|
||||
ARG env=front/.env.production
|
||||
COPY ${env} .env
|
||||
|
||||
###############################################################
|
||||
## Build the sources
|
||||
###############################################################
|
||||
FROM load_sources_front AS build_front
|
||||
# build in bundle mode all the application
|
||||
RUN pnpm static:build
|
||||
|
||||
######################################################################################
|
||||
##
|
||||
@ -55,9 +80,10 @@ RUN ng build --output-path=dist --configuration=production --base-href=/karusic/
|
||||
##
|
||||
######################################################################################
|
||||
|
||||
FROM bellsoft/liberica-openjdk-alpine:latest
|
||||
# add wget to manage the health check...
|
||||
RUN apk add --no-cache wget
|
||||
#FROM bellsoft/liberica-openjdk-alpine:latest
|
||||
## add wget to manage the health check...
|
||||
#RUN apk add --no-cache wget
|
||||
FROM common
|
||||
|
||||
#FROM archlinux:base
|
||||
#RUN pacman -Syu --noconfirm && pacman-db-upgrade
|
||||
@ -68,10 +94,10 @@ RUN apk add --no-cache wget
|
||||
## clean all the caches Need only on the release environment
|
||||
#RUN pacman -Scc --noconfirm
|
||||
|
||||
ENV LANG=C.UTF-8
|
||||
ENV LANG C.UTF-8
|
||||
|
||||
COPY --from=buildBack /tmp/out/maven/*.jar /application/application.jar
|
||||
COPY --from=buildFront /tmp/dist /application/front/
|
||||
COPY --from=build_back /tmp/out/maven/*.jar /application/application.jar
|
||||
COPY --from=build_front /tmp/dist /application/front/
|
||||
|
||||
WORKDIR /application/
|
||||
|
||||
|
@ -1,4 +0,0 @@
|
||||
|
||||
|
||||
|
||||
|
53
back/pom.xml
53
back/pom.xml
@ -1,10 +1,10 @@
|
||||
<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.kar</groupId>
|
||||
<artifactId>karusic</artifactId>
|
||||
<version>0.1.0</version>
|
||||
<properties>
|
||||
|
||||
<maven.compiler.version>3.1</maven.compiler.version>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
@ -20,17 +20,17 @@
|
||||
<dependency>
|
||||
<groupId>kangaroo-and-rabbit</groupId>
|
||||
<artifactId>archidata</artifactId>
|
||||
<version>0.7.1</version>
|
||||
<version>0.14.3-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
<version>2.0.9</version>
|
||||
<version>2.1.0-alpha1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||
<version>2.16.1</version>
|
||||
<version>2.18.0-rc1</version>
|
||||
</dependency>
|
||||
<!--
|
||||
************************************************************
|
||||
@ -40,15 +40,25 @@
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>5.10.1</version>
|
||||
<version>5.11.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>5.10.1</version>
|
||||
<version>5.11.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.revelc.code.formatter</groupId>
|
||||
<artifactId>formatter-maven-plugin</artifactId>
|
||||
<version>2.24.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<version>3.5.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<sourceDirectory>src</sourceDirectory>
|
||||
@ -186,23 +196,10 @@
|
||||
</configuration>
|
||||
</plugin>
|
||||
<!-- Check the style of the code -->
|
||||
<!--
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<configuration>
|
||||
<configLocation>CheckStyle.xml</configLocation>
|
||||
<consoleOutput>true</consoleOutput>
|
||||
<failOnViolation>true</failOnViolation>
|
||||
<failsOnError>true</failsOnError>
|
||||
<includeTestSourceDirectory>true</includeTestSourceDirectory>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>net.revelc.code.formatter</groupId>
|
||||
<artifactId>formatter-maven-plugin</artifactId>
|
||||
<version>2.12.2</version>
|
||||
<version>2.23.0</version>
|
||||
<configuration>
|
||||
<encoding>UTF-8</encoding>
|
||||
<lineEnding>LF</lineEnding>
|
||||
@ -226,7 +223,23 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.github.spotbugs</groupId>
|
||||
<artifactId>spotbugs-maven-plugin</artifactId>
|
||||
<version>4.8.5.0</version>
|
||||
<configuration>
|
||||
<includeFilterFile>spotbugs-security-include.xml</includeFilterFile>
|
||||
<excludeFilterFile>spotbugs-security-exclude.xml</excludeFilterFile>
|
||||
<!--<plugins>
|
||||
<plugin>
|
||||
<groupId>com.h3xstream.findsecbugs</groupId>
|
||||
<artifactId>findsecbugs-plugin</artifactId>
|
||||
<version>1.12.0</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
-->
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<!-- Generate Java-docs As Part Of Project Reports -->
|
||||
|
17
back/src/org/kar/karusic/MorphiaService.java
Normal file
17
back/src/org/kar/karusic/MorphiaService.java
Normal file
@ -0,0 +1,17 @@
|
||||
package org.kar.karusic;
|
||||
|
||||
import org.kar.archidata.db.DbInterfaceMorphia;
|
||||
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 MorphiaService extends DbInterfaceMorphia {
|
||||
|
||||
public MorphiaService() {
|
||||
super("mongodb://root:base_db_password@localhost:27017", "karusic", Album.class, Artist.class, Gender.class, Playlist.class, Track.class);
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +1,11 @@
|
||||
package org.kar.karusic;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.ImageWriter;
|
||||
|
||||
import org.glassfish.grizzly.http.server.HttpServer;
|
||||
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
|
||||
@ -10,11 +15,9 @@ import org.glassfish.jersey.server.ResourceConfig;
|
||||
import org.kar.archidata.GlobalConfiguration;
|
||||
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.JacksonCatcher;
|
||||
import org.kar.archidata.catcher.SystemExceptionCatcher;
|
||||
import org.kar.archidata.api.ProxyResource;
|
||||
import org.kar.archidata.catcher.GenericCatcher;
|
||||
import org.kar.archidata.dataAccess.DataAccess;
|
||||
import org.kar.archidata.filter.CORSFilter;
|
||||
import org.kar.archidata.filter.OptionFilter;
|
||||
import org.kar.archidata.migration.MigrationEngine;
|
||||
@ -32,6 +35,7 @@ import org.kar.karusic.migration.Initialization;
|
||||
import org.kar.karusic.migration.Migration20231126;
|
||||
import org.kar.karusic.migration.Migration20240225;
|
||||
import org.kar.karusic.migration.Migration20240226;
|
||||
import org.kar.karusic.migration.Migration20240907;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -42,8 +46,11 @@ public class WebLauncher {
|
||||
protected UpdateJwtPublicKey keyUpdater = null;
|
||||
protected HttpServer server = null;
|
||||
|
||||
private final DataAccess da;
|
||||
|
||||
public WebLauncher() {
|
||||
ConfigBaseVariable.bdDatabase = "karusic";
|
||||
this.da = DataAccess.createInterface();
|
||||
}
|
||||
|
||||
private static URI getBaseURI() {
|
||||
@ -52,15 +59,16 @@ public class WebLauncher {
|
||||
|
||||
public void migrateDB() throws Exception {
|
||||
WebLauncher.LOGGER.info("Create migration engine");
|
||||
final MigrationEngine migrationEngine = new MigrationEngine();
|
||||
final MigrationEngine migrationEngine = new MigrationEngine(this.da);
|
||||
WebLauncher.LOGGER.info("Add initialization");
|
||||
migrationEngine.setInit(new Initialization());
|
||||
WebLauncher.LOGGER.info("Add migration since last version");
|
||||
migrationEngine.add(new Migration20231126());
|
||||
migrationEngine.add(new Migration20240225());
|
||||
migrationEngine.add(new Migration20240226());
|
||||
migrationEngine.add(new Migration20240907());
|
||||
WebLauncher.LOGGER.info("Migrate the DB [START]");
|
||||
migrationEngine.migrateWaitAdmin(GlobalConfiguration.dbConfig);
|
||||
migrationEngine.migrateWaitAdmin(GlobalConfiguration.getDbconfig());
|
||||
WebLauncher.LOGGER.info("Migrate the DB [STOP]");
|
||||
}
|
||||
|
||||
@ -77,7 +85,34 @@ public class WebLauncher {
|
||||
WebLauncher.LOGGER.info("STOP the REST server:");
|
||||
}
|
||||
|
||||
public void plop(final String aaa) {
|
||||
// List available Image Readers
|
||||
System.out.println("Available Image Readers:");
|
||||
final Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName(aaa);
|
||||
while (readers.hasNext()) {
|
||||
final ImageReader reader = readers.next();
|
||||
System.out.println("Reader: " + reader.getOriginatingProvider().getDescription(null));
|
||||
System.out.println("Reader CN: " + reader.getOriginatingProvider().getPluginClassName());
|
||||
// ImageIO.deregisterServiceProvider(reader.getOriginatingProvider());
|
||||
}
|
||||
|
||||
// List available Image Writers
|
||||
System.out.println("\nAvailable Image Writers:");
|
||||
final Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(aaa);
|
||||
while (writers.hasNext()) {
|
||||
final ImageWriter writer = writers.next();
|
||||
System.out.println("Writer: " + writer.getOriginatingProvider().getDescription(null));
|
||||
System.out.println("Writer CN: " + writer.getOriginatingProvider().getPluginClassName());
|
||||
}
|
||||
}
|
||||
|
||||
public void process() throws InterruptedException {
|
||||
|
||||
ImageIO.scanForPlugins();
|
||||
plop("jpeg");
|
||||
plop("png");
|
||||
plop("webmp");
|
||||
plop("webp");
|
||||
// ===================================================================
|
||||
// Configure resources
|
||||
// ===================================================================
|
||||
@ -92,11 +127,7 @@ public class WebLauncher {
|
||||
// global authentication system
|
||||
rc.register(KarusicAuthenticationFilter.class);
|
||||
// register exception catcher
|
||||
rc.register(JacksonCatcher.class);
|
||||
rc.register(InputExceptionCatcher.class);
|
||||
rc.register(SystemExceptionCatcher.class);
|
||||
rc.register(FailExceptionCatcher.class);
|
||||
rc.register(ExceptionCatcher.class);
|
||||
GenericCatcher.addAll(rc);
|
||||
// add default resource:
|
||||
rc.register(UserResource.class);
|
||||
rc.register(AlbumResource.class);
|
||||
@ -105,6 +136,7 @@ public class WebLauncher {
|
||||
rc.register(PlaylistResource.class);
|
||||
rc.register(TrackResource.class);
|
||||
rc.register(DataResource.class);
|
||||
rc.register(ProxyResource.class);
|
||||
|
||||
rc.register(HealthCheck.class);
|
||||
rc.register(Front.class);
|
||||
@ -112,15 +144,15 @@ public class WebLauncher {
|
||||
// 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());
|
||||
// rc.property(LoggingFeature.LOGGING_FEATURE_LOGGER_LEVEL_SERVER, Level.WARNING.getName());
|
||||
|
||||
//System.out.println("Connect on the BDD:");
|
||||
//System.out.println(" getDBHost: '" + ConfigVariable.getDBHost() + "'");
|
||||
//System.out.println(" getDBPort: '" + ConfigVariable.getDBPort() + "'");
|
||||
//System.out.println(" getDBLogin: '" + ConfigVariable.getDBLogin() + "'");
|
||||
//System.out.println(" getDBPassword: '" + ConfigVariable.getDBPassword() + "'");
|
||||
//System.out.println(" getDBName: '" + ConfigVariable.getDBName() + "'");
|
||||
System.out.println(" ==> " + GlobalConfiguration.dbConfig);
|
||||
// System.out.println("Connect on the BDD:");
|
||||
// System.out.println(" getDBHost: '" + ConfigVariable.getDBHost() + "'");
|
||||
// System.out.println(" getDBPort: '" + ConfigVariable.getDBPort() + "'");
|
||||
// System.out.println(" getDBLogin: '" + ConfigVariable.getDBLogin() + "'");
|
||||
// System.out.println(" getDBPassword: '" + ConfigVariable.getDBPassword() + "'");
|
||||
// System.out.println(" getDBName: '" + ConfigVariable.getDBName() + "'");
|
||||
System.out.println(" ==> " + GlobalConfiguration.getDbconfig());
|
||||
System.out.println("OAuth service " + getBaseURI());
|
||||
this.server = GrizzlyHttpServerFactory.createHttpServer(getBaseURI(), rc);
|
||||
final HttpServer serverLink = this.server;
|
||||
|
@ -3,7 +3,9 @@ package org.kar.karusic;
|
||||
import java.util.List;
|
||||
|
||||
import org.kar.archidata.api.DataResource;
|
||||
import org.kar.archidata.dataAccess.DataFactoryTsApi;
|
||||
import org.kar.archidata.api.ProxyResource;
|
||||
import org.kar.archidata.externalRestApi.AnalyzeApi;
|
||||
import org.kar.archidata.externalRestApi.TsGenerateApi;
|
||||
import org.kar.archidata.tools.ConfigBaseVariable;
|
||||
import org.kar.karusic.api.AlbumResource;
|
||||
import org.kar.karusic.api.ArtistResource;
|
||||
@ -13,7 +15,6 @@ 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.migration.Initialization;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -22,18 +23,18 @@ public class WebLauncherLocal extends WebLauncher {
|
||||
|
||||
private WebLauncherLocal() {}
|
||||
|
||||
public static void generateObjects() throws Exception {
|
||||
LOGGER.info("Generate APIs");
|
||||
final List<Class<?>> listOfResources = List.of(AlbumResource.class, ArtistResource.class, Front.class, GenderResource.class, HealthCheck.class, PlaylistResource.class, UserResource.class,
|
||||
TrackResource.class, DataResource.class, ProxyResource.class);
|
||||
final AnalyzeApi api = new AnalyzeApi();
|
||||
api.addAllApi(listOfResources);
|
||||
TsGenerateApi.generateApi(api, "../front/src/back-api/");
|
||||
LOGGER.info("Generate APIs (DONE)");
|
||||
}
|
||||
|
||||
public static void main(final String[] args) throws Exception {
|
||||
DataFactoryTsApi.generatePackage(List.of(
|
||||
AlbumResource.class,
|
||||
ArtistResource.class,
|
||||
Front.class,
|
||||
GenderResource.class,
|
||||
HealthCheck.class,
|
||||
PlaylistResource.class,
|
||||
UserResource.class,
|
||||
TrackResource.class,
|
||||
DataResource.class),
|
||||
Initialization.CLASSES_BASE, "../front/src/app/back-api/");
|
||||
generateObjects();
|
||||
final WebLauncherLocal launcher = new WebLauncherLocal();
|
||||
launcher.process();
|
||||
launcher.LOGGER.info("end-configure the server & wait finish process:");
|
||||
@ -46,8 +47,9 @@ public class WebLauncherLocal extends WebLauncher {
|
||||
if (true) {
|
||||
// for local test:
|
||||
ConfigBaseVariable.apiAdress = "http://0.0.0.0:19080/karusic/api/";
|
||||
//ConfigBaseVariable.ssoAdress = "https://atria-soft.org/karso/api/";
|
||||
// ConfigBaseVariable.ssoAdress = "https://atria-soft.org/karso/api/";
|
||||
ConfigBaseVariable.dbPort = "3906";
|
||||
ConfigBaseVariable.testMode = "true";
|
||||
}
|
||||
try {
|
||||
super.migrateDB();
|
||||
|
@ -7,12 +7,14 @@ import java.util.UUID;
|
||||
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
|
||||
import org.glassfish.jersey.media.multipart.FormDataParam;
|
||||
import org.kar.archidata.annotation.AsyncType;
|
||||
import org.kar.archidata.annotation.FormDataOptional;
|
||||
import org.kar.archidata.annotation.TypeScriptProgress;
|
||||
import org.kar.archidata.dataAccess.DataAccess;
|
||||
import org.kar.archidata.dataAccess.addOn.AddOnDataJson;
|
||||
import org.kar.archidata.dataAccess.addOn.AddOnManyToMany;
|
||||
import org.kar.archidata.dataAccess.options.CheckFunction;
|
||||
import org.kar.archidata.tools.DataTools;
|
||||
import org.kar.karusic.model.Album;
|
||||
import org.kar.karusic.model.Album.AlbumChecker;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -27,34 +29,45 @@ import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
|
||||
@Path("/album")
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public class AlbumResource {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(AlbumResource.class);
|
||||
static final AlbumChecker CHECKER = new AlbumChecker();
|
||||
|
||||
private final DataAccess da = DataAccess.createInterface();
|
||||
|
||||
@GET
|
||||
@Path("{id}")
|
||||
@RolesAllowed("USER")
|
||||
@Operation(description = "Get a specific Album with his ID")
|
||||
public static Album get(@PathParam("id") final Long id) throws Exception {
|
||||
return DataAccess.get(Album.class, id);
|
||||
public Album get(@PathParam("id") final Long id) throws Exception {
|
||||
return this.da.get(Album.class, id);
|
||||
// return this.morphiaService.getDatastore().find(Album.class).filter(Filters.eq("id", id)).first();
|
||||
}
|
||||
|
||||
@GET
|
||||
@RolesAllowed("USER")
|
||||
@Operation(description = "Get all the available Albums")
|
||||
public List<Album> gets() throws Exception {
|
||||
return DataAccess.gets(Album.class);
|
||||
return this.da.gets(Album.class);
|
||||
// final Query<Album> query = this.morphiaService.getDatastore().find(Album.class);
|
||||
// return query.stream().toList();
|
||||
}
|
||||
|
||||
@POST
|
||||
@RolesAllowed("ADMIN")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Operation(description = "Add an album (when all the data already exist)")
|
||||
public Album post(@AsyncType(Album.class) final String jsonRequest) throws Exception {
|
||||
return DataAccess.insertWithJson(Album.class, jsonRequest);
|
||||
public Album post(final Album data) throws Exception {
|
||||
// TODO: how to manage the checker ???
|
||||
// final Album ret = this.morphiaService.getDatastore().save(data);
|
||||
// return ret;
|
||||
/* final MongoCollection<Track> trackCollection = db.getCollection("TTRACLK", Track.class); final InsertOneResult res = trackCollection.insertOne(plop); LOGGER.warn("plpop {}", res); final
|
||||
* ObjectId ploppppp = res.getInsertedId().asObjectId().getValue(); LOGGER.warn("plpop 2522 {}", res.getInsertedId().asObjectId().getValue()); final Track ret =
|
||||
* trackCollection.find(Filters.eq("_id", res.getInsertedId().asObjectId().getValue())) .first(); System.out.println("Grade found:\t" + ret); */
|
||||
return this.da.insert(data, new CheckFunction(CHECKER));
|
||||
}
|
||||
|
||||
@PATCH
|
||||
@ -63,47 +76,59 @@ public class AlbumResource {
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Operation(description = "Update a specific album")
|
||||
public Album patch(@PathParam("id") final Long id, @AsyncType(Album.class) final String jsonRequest) throws Exception {
|
||||
DataAccess.updateWithJson(Album.class, id, jsonRequest);
|
||||
return DataAccess.get(Album.class, id);
|
||||
// final Query<Album> query = this.morphiaService.getDatastore().find(Album.class).filter(Filters.eq("id", id));
|
||||
// final UpdateOperations<Album> ops = this.morphiaService.getDatastore().createUpdateOperations(Album.class)
|
||||
// .set("name", master.getName());
|
||||
// this.morphiaService.getDatastore().update(query, ops);
|
||||
// return Response.ok(master).build();
|
||||
|
||||
this.da.updateWithJson(Album.class, id, jsonRequest, new CheckFunction(CHECKER));
|
||||
return this.da.get(Album.class, id);
|
||||
}
|
||||
|
||||
// @PUT
|
||||
// @Path("{id}")
|
||||
// @RolesAllowed("ADMIN")
|
||||
// @Consumes(MediaType.APPLICATION_JSON)
|
||||
// @Operation(description = "Update a specific album")
|
||||
// public Album put(@PathParam("id") final Long id, final Album album)
|
||||
// throws Exception {
|
||||
// final Query<Album> query = this.morphiaService.getDatastore().find(Album.class).filter(Filters.eq("id", id));
|
||||
// final UpdateOperations<Album> ops = this.morphiaService.getDatastore().createUpdateOperations(Album.class)
|
||||
// .set("name", album.getName());
|
||||
// this.morphiaService.getDatastore().update(query, ops);
|
||||
// return Response.ok(album).build();
|
||||
// }
|
||||
|
||||
@DELETE
|
||||
@Path("{id}")
|
||||
@RolesAllowed("ADMIN")
|
||||
@Operation(description = "Remove a specific album")
|
||||
public void remove(@PathParam("id") final Long id) throws Exception {
|
||||
DataAccess.delete(Album.class, id);
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("{id}/track/{trackId}")
|
||||
@RolesAllowed("ADMIN")
|
||||
@Consumes({ MediaType.MULTIPART_FORM_DATA })
|
||||
@Operation(description = "Add a Track on a specific album")
|
||||
public Album addTrack(@PathParam("id") final Long id, @PathParam("trackId") final Long trackId) throws Exception {
|
||||
AddOnManyToMany.removeLink(Album.class, id, "track", trackId);
|
||||
return DataAccess.get(Album.class, id);
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("{id}/track/{trackId}")
|
||||
@RolesAllowed("ADMIN")
|
||||
@Operation(description = "Remove a Track on a specific album")
|
||||
public Album removeTrack(@PathParam("id") final Long id, @PathParam("trackId") final Long trackId) throws Exception {
|
||||
AddOnManyToMany.removeLink(Album.class, id, "track", trackId);
|
||||
return DataAccess.get(Album.class, id);
|
||||
this.da.delete(Album.class, id);
|
||||
// this.morphiaService.getDatastore().find(Album.class).filter(Filters.eq("id", id)).delete();
|
||||
}
|
||||
|
||||
/* @POST
|
||||
* @Path("{id}/track/{trackId}")
|
||||
* @RolesAllowed("ADMIN")
|
||||
* @Consumes({ MediaType.MULTIPART_FORM_DATA })
|
||||
* @Operation(description = "Add a Track on a specific album") public Album addTrack(@PathParam("id") final Long id, @PathParam("trackId") final Long trackId) throws Exception {
|
||||
* AddOnManyToMany.removeLink(this.dam, Album.class, id, "track", trackId); return this.dam.get(Album.class, id); } */
|
||||
@POST
|
||||
@Path("{id}/cover")
|
||||
@RolesAllowed("ADMIN")
|
||||
@Consumes({ MediaType.MULTIPART_FORM_DATA })
|
||||
@Operation(description = "Add a cover on a specific album")
|
||||
@AsyncType(Album.class)
|
||||
@TypeScriptProgress
|
||||
public Response uploadCover(@PathParam("id") final Long id, @FormDataParam("fileName") final String fileName, @FormDataParam("file") final InputStream fileInputStream,
|
||||
@FormDataParam("file") final FormDataContentDisposition fileMetaData) {
|
||||
return DataTools.uploadCover(Album.class, id, fileName, fileInputStream, fileMetaData);
|
||||
public Album uploadCover(@PathParam("id") final Long id, @FormDataOptional @FormDataParam("uri") final String uri, @FormDataOptional @FormDataParam("file") final InputStream fileInputStream,
|
||||
@FormDataOptional @FormDataParam("file") final FormDataContentDisposition fileMetaData) throws Exception {
|
||||
if (uri != null) {
|
||||
DataTools.uploadCoverFromUri(this.da, Album.class, id, uri);
|
||||
} else {
|
||||
DataTools.uploadCover(this.da, Album.class, id, fileInputStream, fileMetaData);
|
||||
}
|
||||
return this.da.get(Album.class, id);
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@ -111,7 +136,7 @@ public class AlbumResource {
|
||||
@RolesAllowed("ADMIN")
|
||||
@Operation(description = "Remove a cover on a specific album")
|
||||
public Album removeCover(@PathParam("id") final Long id, @PathParam("coverId") final UUID coverId) throws Exception {
|
||||
AddOnDataJson.removeLink(Album.class, id, "covers", coverId);
|
||||
return DataAccess.get(Album.class, id);
|
||||
AddOnDataJson.removeLink(this.da, Album.class, id, "covers", coverId);
|
||||
return this.da.get(Album.class, id);
|
||||
}
|
||||
}
|
||||
|
@ -7,11 +7,14 @@ import java.util.UUID;
|
||||
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
|
||||
import org.glassfish.jersey.media.multipart.FormDataParam;
|
||||
import org.kar.archidata.annotation.AsyncType;
|
||||
import org.kar.archidata.annotation.FormDataOptional;
|
||||
import org.kar.archidata.annotation.TypeScriptProgress;
|
||||
import org.kar.archidata.dataAccess.DataAccess;
|
||||
import org.kar.archidata.dataAccess.addOn.AddOnDataJson;
|
||||
import org.kar.archidata.dataAccess.options.CheckFunction;
|
||||
import org.kar.archidata.tools.DataTools;
|
||||
import org.kar.karusic.model.Artist;
|
||||
import org.kar.karusic.model.Artist.ArtistChecker;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -25,31 +28,32 @@ import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
|
||||
@Path("/artist")
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public class ArtistResource {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ArtistResource.class);
|
||||
static final ArtistChecker CHECKER = new ArtistChecker();
|
||||
private final DataAccess da = DataAccess.createInterface();
|
||||
|
||||
@GET
|
||||
@Path("{id}")
|
||||
@RolesAllowed("USER")
|
||||
public static Artist get(@PathParam("id") final Long id) throws Exception {
|
||||
return DataAccess.get(Artist.class, id);
|
||||
public Artist get(@PathParam("id") final Long id) throws Exception {
|
||||
return this.da.get(Artist.class, id);
|
||||
}
|
||||
|
||||
@GET
|
||||
@RolesAllowed("USER")
|
||||
public List<Artist> gets() throws Exception {
|
||||
return DataAccess.gets(Artist.class);
|
||||
return this.da.gets(Artist.class);
|
||||
}
|
||||
|
||||
@POST
|
||||
@RolesAllowed("ADMIN")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Artist post(@AsyncType(Artist.class) final String jsonRequest) throws Exception {
|
||||
return DataAccess.insertWithJson(Artist.class, jsonRequest);
|
||||
public Artist post(final Artist data) throws Exception {
|
||||
return this.da.insert(data, new CheckFunction(CHECKER));
|
||||
}
|
||||
|
||||
@PATCH
|
||||
@ -57,26 +61,30 @@ public class ArtistResource {
|
||||
@RolesAllowed("ADMIN")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Artist patch(@PathParam("id") final Long id, @AsyncType(Artist.class) final String jsonRequest) throws Exception {
|
||||
DataAccess.updateWithJson(Artist.class, id, jsonRequest);
|
||||
return DataAccess.get(Artist.class, id);
|
||||
this.da.updateWithJson(Artist.class, id, jsonRequest, new CheckFunction(CHECKER));
|
||||
return this.da.get(Artist.class, id);
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("{id}")
|
||||
@RolesAllowed("ADMIN")
|
||||
public void remove(@PathParam("id") final Long id) throws Exception {
|
||||
DataAccess.delete(Artist.class, id);
|
||||
this.da.delete(Artist.class, id);
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("{id}/cover")
|
||||
@RolesAllowed("ADMIN")
|
||||
@Consumes({ MediaType.MULTIPART_FORM_DATA })
|
||||
@AsyncType(Artist.class)
|
||||
@TypeScriptProgress
|
||||
public Response uploadCover(@PathParam("id") final Long id, @FormDataParam("fileName") final String fileName, @FormDataParam("file") final InputStream fileInputStream,
|
||||
@FormDataParam("file") final FormDataContentDisposition fileMetaData) {
|
||||
return DataTools.uploadCover(Artist.class, id, fileName, fileInputStream, fileMetaData);
|
||||
public Artist uploadCover(@PathParam("id") final Long id, @FormDataOptional @FormDataParam("uri") final String uri, @FormDataOptional @FormDataParam("file") final InputStream fileInputStream,
|
||||
@FormDataOptional @FormDataParam("file") final FormDataContentDisposition fileMetaData) throws Exception {
|
||||
if (uri != null) {
|
||||
DataTools.uploadCoverFromUri(this.da, Artist.class, id, uri);
|
||||
} else {
|
||||
DataTools.uploadCover(this.da, Artist.class, id, fileInputStream, fileMetaData);
|
||||
}
|
||||
return this.da.get(Artist.class, id);
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@ -84,7 +92,7 @@ public class ArtistResource {
|
||||
@RolesAllowed("ADMIN")
|
||||
public Artist removeCover(@PathParam("id") final Long id, @PathParam("coverId") final UUID coverId) throws Exception {
|
||||
LOGGER.error("klmlmkmlkmlklmklmk");
|
||||
AddOnDataJson.removeLink(Artist.class, id, "covers", coverId);
|
||||
return DataAccess.get(Artist.class, id);
|
||||
AddOnDataJson.removeLink(this.da, Artist.class, id, "covers", coverId);
|
||||
return this.da.get(Artist.class, id);
|
||||
}
|
||||
}
|
||||
|
@ -7,11 +7,14 @@ import java.util.UUID;
|
||||
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
|
||||
import org.glassfish.jersey.media.multipart.FormDataParam;
|
||||
import org.kar.archidata.annotation.AsyncType;
|
||||
import org.kar.archidata.annotation.FormDataOptional;
|
||||
import org.kar.archidata.annotation.TypeScriptProgress;
|
||||
import org.kar.archidata.dataAccess.DataAccess;
|
||||
import org.kar.archidata.dataAccess.addOn.AddOnDataJson;
|
||||
import org.kar.archidata.dataAccess.options.CheckFunction;
|
||||
import org.kar.archidata.tools.DataTools;
|
||||
import org.kar.karusic.model.Gender;
|
||||
import org.kar.karusic.model.Gender.GenderChecker;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -25,31 +28,32 @@ import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
|
||||
@Path("/gender")
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public class GenderResource {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(GenderResource.class);
|
||||
static final GenderChecker CHECKER = new GenderChecker();
|
||||
private final DataAccess da = DataAccess.createInterface();
|
||||
|
||||
@GET
|
||||
@Path("{id}")
|
||||
@RolesAllowed("USER")
|
||||
public static Gender get(@PathParam("id") final Long id) throws Exception {
|
||||
return DataAccess.get(Gender.class, id);
|
||||
public Gender get(@PathParam("id") final Long id) throws Exception {
|
||||
return this.da.get(Gender.class, id);
|
||||
}
|
||||
|
||||
@GET
|
||||
@RolesAllowed("USER")
|
||||
public List<Gender> gets() throws Exception {
|
||||
return DataAccess.gets(Gender.class);
|
||||
return this.da.gets(Gender.class);
|
||||
}
|
||||
|
||||
@POST
|
||||
@RolesAllowed("ADMIN")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Gender post(@AsyncType(Gender.class) final String jsonRequest) throws Exception {
|
||||
return DataAccess.insertWithJson(Gender.class, jsonRequest);
|
||||
public Gender post(final Gender data) throws Exception {
|
||||
return this.da.insert(data, new CheckFunction(CHECKER));
|
||||
}
|
||||
|
||||
@PATCH
|
||||
@ -57,33 +61,37 @@ public class GenderResource {
|
||||
@RolesAllowed("ADMIN")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Gender patch(@PathParam("id") final Long id, @AsyncType(Gender.class) final String jsonRequest) throws Exception {
|
||||
DataAccess.updateWithJson(Gender.class, id, jsonRequest);
|
||||
return DataAccess.get(Gender.class, id);
|
||||
this.da.updateWithJson(Gender.class, id, jsonRequest, new CheckFunction(CHECKER));
|
||||
return this.da.get(Gender.class, id);
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("{id}")
|
||||
@RolesAllowed("ADMIN")
|
||||
public void remove(@PathParam("id") final Long id) throws Exception {
|
||||
DataAccess.delete(Gender.class, id);
|
||||
this.da.delete(Gender.class, id);
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("{id}/cover")
|
||||
@RolesAllowed("ADMIN")
|
||||
@Consumes({ MediaType.MULTIPART_FORM_DATA })
|
||||
@AsyncType(Gender.class)
|
||||
@TypeScriptProgress
|
||||
public Response uploadCover(@PathParam("id") final Long id, @FormDataParam("fileName") final String fileName, @FormDataParam("file") final InputStream fileInputStream,
|
||||
@FormDataParam("file") final FormDataContentDisposition fileMetaData) {
|
||||
return DataTools.uploadCover(Gender.class, id, fileName, fileInputStream, fileMetaData);
|
||||
public Gender uploadCover(@PathParam("id") final Long id, @FormDataOptional @FormDataParam("uri") final String uri, @FormDataOptional @FormDataParam("file") final InputStream fileInputStream,
|
||||
@FormDataOptional @FormDataParam("file") final FormDataContentDisposition fileMetaData) throws Exception {
|
||||
if (uri != null) {
|
||||
DataTools.uploadCoverFromUri(this.da, Gender.class, id, uri);
|
||||
} else {
|
||||
DataTools.uploadCover(this.da, Gender.class, id, fileInputStream, fileMetaData);
|
||||
}
|
||||
return this.da.get(Gender.class, id);
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("{id}/cover/{coverId}")
|
||||
@RolesAllowed("ADMIN")
|
||||
public Gender removeCover(@PathParam("id") final Long id, @PathParam("coverId") final UUID coverId) throws Exception {
|
||||
AddOnDataJson.removeLink(Gender.class, id, "covers", coverId);
|
||||
return DataAccess.get(Gender.class, id);
|
||||
AddOnDataJson.removeLink(this.da, Gender.class, id, "covers", coverId);
|
||||
return this.da.get(Gender.class, id);
|
||||
}
|
||||
}
|
||||
|
@ -15,8 +15,8 @@ import jakarta.ws.rs.core.Response;
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public class HealthCheck {
|
||||
|
||||
public record HealthResult(
|
||||
String value) {};
|
||||
public record HealthResult(String value) {
|
||||
};
|
||||
|
||||
@GET
|
||||
@PermitAll
|
||||
|
@ -9,9 +9,10 @@ import org.glassfish.jersey.media.multipart.FormDataParam;
|
||||
import org.kar.archidata.annotation.AsyncType;
|
||||
import org.kar.archidata.dataAccess.DataAccess;
|
||||
import org.kar.archidata.dataAccess.addOn.AddOnDataJson;
|
||||
import org.kar.archidata.dataAccess.addOn.AddOnManyToMany;
|
||||
import org.kar.archidata.dataAccess.options.CheckFunction;
|
||||
import org.kar.archidata.tools.DataTools;
|
||||
import org.kar.karusic.model.Playlist;
|
||||
import org.kar.karusic.model.Track.TrackChecker;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -25,31 +26,32 @@ import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
|
||||
@Path("/playlist")
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public class PlaylistResource {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(PlaylistResource.class);
|
||||
static final TrackChecker CHECKER = new TrackChecker();
|
||||
private final DataAccess da = DataAccess.createInterface();
|
||||
|
||||
@GET
|
||||
@Path("{id}")
|
||||
@RolesAllowed("USER")
|
||||
public static Playlist get(@PathParam("id") final Long id) throws Exception {
|
||||
return DataAccess.get(Playlist.class, id);
|
||||
public Playlist get(@PathParam("id") final Long id) throws Exception {
|
||||
return this.da.get(Playlist.class, id);
|
||||
}
|
||||
|
||||
@GET
|
||||
@RolesAllowed("USER")
|
||||
public List<Playlist> gets() throws Exception {
|
||||
return DataAccess.gets(Playlist.class);
|
||||
return this.da.gets(Playlist.class);
|
||||
}
|
||||
|
||||
@POST
|
||||
@RolesAllowed("ADMIN")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Playlist post(@AsyncType(Playlist.class) final String jsonRequest) throws Exception {
|
||||
return DataAccess.insertWithJson(Playlist.class, jsonRequest);
|
||||
public Playlist post(final Playlist data) throws Exception {
|
||||
return this.da.insert(data, new CheckFunction(CHECKER));
|
||||
}
|
||||
|
||||
@PATCH
|
||||
@ -57,15 +59,15 @@ public class PlaylistResource {
|
||||
@RolesAllowed("ADMIN")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Playlist patch(@PathParam("id") final Long id, @AsyncType(Playlist.class) final String jsonRequest) throws Exception {
|
||||
DataAccess.updateWithJson(Playlist.class, id, jsonRequest);
|
||||
return DataAccess.get(Playlist.class, id);
|
||||
this.da.updateWithJson(Playlist.class, id, jsonRequest, new CheckFunction(CHECKER));
|
||||
return this.da.get(Playlist.class, id);
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("{id}")
|
||||
@RolesAllowed("ADMIN")
|
||||
public void remove(@PathParam("id") final Long id) throws Exception {
|
||||
DataAccess.delete(Playlist.class, id);
|
||||
this.da.delete(Playlist.class, id);
|
||||
}
|
||||
|
||||
@POST
|
||||
@ -73,16 +75,16 @@ public class PlaylistResource {
|
||||
@RolesAllowed("ADMIN")
|
||||
@Consumes({ MediaType.MULTIPART_FORM_DATA })
|
||||
public Playlist addTrack(@PathParam("id") final Long id, @PathParam("trackId") final Long trackId) throws Exception {
|
||||
AddOnManyToMany.removeLink(Playlist.class, id, "track", trackId);
|
||||
return DataAccess.get(Playlist.class, id);
|
||||
AddOnDataJson.removeLink(this.da, Playlist.class, id, "track", trackId);
|
||||
return this.da.get(Playlist.class, id);
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("{id}/track/{trackId}")
|
||||
@RolesAllowed("ADMIN")
|
||||
public Playlist removeTrack(@PathParam("id") final Long id, @PathParam("trackId") final Long trackId) throws Exception {
|
||||
AddOnManyToMany.removeLink(Playlist.class, id, "track", trackId);
|
||||
return DataAccess.get(Playlist.class, id);
|
||||
AddOnDataJson.removeLink(this.da, Playlist.class, id, "track", trackId);
|
||||
return this.da.get(Playlist.class, id);
|
||||
}
|
||||
|
||||
@POST
|
||||
@ -90,16 +92,16 @@ public class PlaylistResource {
|
||||
@RolesAllowed("ADMIN")
|
||||
@Consumes({ MediaType.MULTIPART_FORM_DATA })
|
||||
@AsyncType(Playlist.class)
|
||||
public Response uploadCover(@PathParam("id") final Long id, @FormDataParam("fileName") final String fileName, @FormDataParam("file") final InputStream fileInputStream,
|
||||
@FormDataParam("file") final FormDataContentDisposition fileMetaData) {
|
||||
return DataTools.uploadCover(Playlist.class, id, fileName, fileInputStream, fileMetaData);
|
||||
public void uploadCover(@PathParam("id") final Long id, @FormDataParam("file") final InputStream fileInputStream, @FormDataParam("file") final FormDataContentDisposition fileMetaData)
|
||||
throws Exception {
|
||||
DataTools.uploadCover(this.da, Playlist.class, id, fileInputStream, fileMetaData);
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("{id}/cover/{coverId}")
|
||||
@RolesAllowed("ADMIN")
|
||||
public Playlist removeCover(@PathParam("id") final Long id, @PathParam("coverId") final UUID coverId) throws Exception {
|
||||
AddOnDataJson.removeLink(Playlist.class, id, "covers", coverId);
|
||||
return DataAccess.get(Playlist.class, id);
|
||||
AddOnDataJson.removeLink(this.da, Playlist.class, id, "covers", coverId);
|
||||
return this.da.get(Playlist.class, id);
|
||||
}
|
||||
}
|
||||
|
@ -10,18 +10,15 @@ import java.util.UUID;
|
||||
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
|
||||
import org.glassfish.jersey.media.multipart.FormDataParam;
|
||||
import org.kar.archidata.annotation.AsyncType;
|
||||
import org.kar.archidata.annotation.FormDataOptional;
|
||||
import org.kar.archidata.annotation.TypeScriptProgress;
|
||||
import org.kar.archidata.dataAccess.DataAccess;
|
||||
import org.kar.archidata.dataAccess.QueryCondition;
|
||||
import org.kar.archidata.dataAccess.addOn.AddOnDataJson;
|
||||
import org.kar.archidata.dataAccess.addOn.AddOnManyToMany;
|
||||
import org.kar.archidata.dataAccess.options.Condition;
|
||||
import org.kar.archidata.dataAccess.options.CheckFunction;
|
||||
import org.kar.archidata.model.Data;
|
||||
import org.kar.archidata.tools.DataTools;
|
||||
import org.kar.karusic.model.Album;
|
||||
import org.kar.karusic.model.Artist;
|
||||
import org.kar.karusic.model.Gender;
|
||||
import org.kar.karusic.model.Track;
|
||||
import org.kar.karusic.model.Track.TrackChecker;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -41,25 +38,27 @@ import jakarta.ws.rs.core.Response;
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public class TrackResource {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(TrackResource.class);
|
||||
static final TrackChecker CHECKER = new TrackChecker();
|
||||
private final DataAccess da = DataAccess.createInterface();
|
||||
|
||||
@GET
|
||||
@Path("{id}")
|
||||
@RolesAllowed("USER")
|
||||
public static Track get(@PathParam("id") final Long id) throws Exception {
|
||||
return DataAccess.get(Track.class, id);
|
||||
public Track get(@PathParam("id") final Long id) throws Exception {
|
||||
return this.da.get(Track.class, id);
|
||||
}
|
||||
|
||||
@GET
|
||||
@RolesAllowed("USER")
|
||||
public List<Track> gets() throws Exception {
|
||||
return DataAccess.gets(Track.class);
|
||||
return this.da.gets(Track.class);
|
||||
}
|
||||
|
||||
@POST
|
||||
@RolesAllowed("ADMIN")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Track post(@AsyncType(Track.class) final String jsonRequest) throws Exception {
|
||||
return DataAccess.insertWithJson(Track.class, jsonRequest);
|
||||
public Track post(final Track data) throws Exception {
|
||||
return this.da.insert(data, new CheckFunction(CHECKER));
|
||||
}
|
||||
|
||||
@PATCH
|
||||
@ -67,15 +66,15 @@ public class TrackResource {
|
||||
@RolesAllowed("ADMIN")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Track patch(@PathParam("id") final Long id, @AsyncType(Track.class) final String jsonRequest) throws Exception {
|
||||
DataAccess.updateWithJson(Track.class, id, jsonRequest);
|
||||
return DataAccess.get(Track.class, id);
|
||||
this.da.updateWithJson(Track.class, id, jsonRequest, new CheckFunction(CHECKER));
|
||||
return this.da.get(Track.class, id);
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("{id}")
|
||||
@RolesAllowed("ADMIN")
|
||||
public void remove(@PathParam("id") final Long id) throws Exception {
|
||||
DataAccess.delete(Track.class, id);
|
||||
this.da.delete(Track.class, id);
|
||||
}
|
||||
|
||||
@POST
|
||||
@ -83,92 +82,83 @@ public class TrackResource {
|
||||
@RolesAllowed("ADMIN")
|
||||
@Consumes({ MediaType.MULTIPART_FORM_DATA })
|
||||
public Track addTrack(@PathParam("id") final Long id, @PathParam("artistId") final Long artistId) throws Exception {
|
||||
AddOnManyToMany.removeLink(Track.class, id, "artist", artistId);
|
||||
return DataAccess.get(Track.class, id);
|
||||
AddOnDataJson.removeLink(this.da, Track.class, id, "artist", artistId);
|
||||
return this.da.get(Track.class, id);
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("{id}/artist/{trackId}")
|
||||
@RolesAllowed("ADMIN")
|
||||
public Track removeTrack(@PathParam("id") final Long id, @PathParam("artistId") final Long artistId) throws Exception {
|
||||
AddOnManyToMany.removeLink(Track.class, id, "artist", artistId);
|
||||
return DataAccess.get(Track.class, id);
|
||||
AddOnDataJson.removeLink(this.da, Track.class, id, "artist", artistId);
|
||||
return this.da.get(Track.class, id);
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("{id}/cover")
|
||||
@RolesAllowed("ADMIN")
|
||||
@Consumes({ MediaType.MULTIPART_FORM_DATA })
|
||||
@AsyncType(Track.class)
|
||||
@TypeScriptProgress
|
||||
public Response uploadCover(@PathParam("id") final Long id, @FormDataParam("fileName") final String fileName, @FormDataParam("file") final InputStream fileInputStream,
|
||||
@FormDataParam("file") final FormDataContentDisposition fileMetaData) {
|
||||
return DataTools.uploadCover(Track.class, id, fileName, fileInputStream, fileMetaData);
|
||||
public Track uploadCover(@PathParam("id") final Long id, @FormDataParam("uri") final String uri, @FormDataParam("file") final InputStream fileInputStream,
|
||||
@FormDataParam("file") final FormDataContentDisposition fileMetaData) throws Exception {
|
||||
if (uri != null) {
|
||||
DataTools.uploadCoverFromUri(this.da, Track.class, id, uri);
|
||||
} else {
|
||||
DataTools.uploadCover(this.da, Track.class, id, fileInputStream, fileMetaData);
|
||||
}
|
||||
return this.da.get(Track.class, id);
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("{id}/cover/{coverId}")
|
||||
@RolesAllowed("ADMIN")
|
||||
public Track removeCover(@PathParam("id") final Long id, @PathParam("coverId") final UUID coverId) throws Exception {
|
||||
AddOnDataJson.removeLink(Track.class, id, "covers", coverId);
|
||||
return DataAccess.get(Track.class, id);
|
||||
AddOnDataJson.removeLink(this.da, Track.class, id, "covers", coverId);
|
||||
return this.da.get(Track.class, id);
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("upload/")
|
||||
@RolesAllowed("ADMIN")
|
||||
@Consumes({ MediaType.MULTIPART_FORM_DATA })
|
||||
// Formatter:off
|
||||
@AsyncType(Track.class)
|
||||
@TypeScriptProgress
|
||||
public Response uploadTrack(
|
||||
@FormDataParam("fileName") String fileName, //
|
||||
@FormDataParam("gender") String gender, //
|
||||
@FormDataParam("artist") String artist, //
|
||||
//@FormDataParam("seriesId") String seriesId, Not used ...
|
||||
@FormDataParam("album") String album, //
|
||||
@AsyncType(Long.class) @FormDataParam("trackId") String trackId, //
|
||||
public Response uploadTrack( //
|
||||
@FormDataParam("title") String title, //
|
||||
@FormDataOptional @AsyncType(Long.class) @FormDataParam("genderId") String genderId, //
|
||||
@FormDataOptional @AsyncType(Long.class) @FormDataParam("artistId") String artistId, //
|
||||
@FormDataOptional @AsyncType(Long.class) @FormDataParam("albumId") String albumId, //
|
||||
@FormDataOptional @AsyncType(Long.class) @FormDataParam("trackId") String trackId, //
|
||||
@FormDataParam("file") final InputStream fileInputStream, //
|
||||
@FormDataParam("file") final FormDataContentDisposition fileMetaData //
|
||||
) {
|
||||
// Formatter:on
|
||||
try {
|
||||
// correct input string stream :
|
||||
fileName = DataTools.multipartCorrection(fileName);
|
||||
gender = DataTools.multipartCorrection(gender);
|
||||
artist = DataTools.multipartCorrection(artist);
|
||||
album = DataTools.multipartCorrection(album);
|
||||
trackId = DataTools.multipartCorrection(trackId);
|
||||
albumId = DataTools.multipartCorrection(albumId);
|
||||
artistId = DataTools.multipartCorrection(artistId);
|
||||
genderId = DataTools.multipartCorrection(genderId);
|
||||
title = DataTools.multipartCorrection(title);
|
||||
|
||||
//public NodeSmall uploadFile(final FormDataMultiPart form) {
|
||||
// public NodeSmall uploadFile(final FormDataMultiPart form) {
|
||||
LOGGER.info("Upload media file: " + fileMetaData);
|
||||
LOGGER.info(" > fileName: " + fileName);
|
||||
LOGGER.info(" > gender: " + gender);
|
||||
LOGGER.info(" > artist: " + artist);
|
||||
LOGGER.info(" > album: " + album);
|
||||
LOGGER.info(" > genderId: " + genderId);
|
||||
LOGGER.info(" > artistId: " + artistId);
|
||||
LOGGER.info(" > albumId: " + albumId);
|
||||
LOGGER.info(" > trackId: " + trackId);
|
||||
LOGGER.info(" > title: " + title);
|
||||
LOGGER.info(" > fileInputStream: " + fileInputStream);
|
||||
LOGGER.info(" > fileMetaData: " + fileMetaData);
|
||||
/*
|
||||
if (typeId == null) {
|
||||
return Response.status(406).
|
||||
entity("Missong Input 'type'").
|
||||
type("text/plain").
|
||||
build();
|
||||
}
|
||||
*/
|
||||
/* if (typeId == null) { return Response.status(406). entity("Missong Input 'type'"). type("text/plain"). build(); } */
|
||||
|
||||
final long tmpUID = DataTools.getTmpDataId();
|
||||
final String sha512 = DataTools.saveTemporaryFile(fileInputStream, tmpUID);
|
||||
Data data = DataTools.getWithSha512(sha512);
|
||||
Data data = DataTools.getWithSha512(this.da, sha512);
|
||||
if (data == null) {
|
||||
LOGGER.info("Need to add the data in the BDD ... ");
|
||||
|
||||
try {
|
||||
data = DataTools.createNewData(tmpUID, fileName, sha512);
|
||||
data = DataTools.createNewData(this.da, tmpUID, fileMetaData.getFileName(), sha512);
|
||||
} catch (final IOException ex) {
|
||||
DataTools.removeTemporaryFile(tmpUID);
|
||||
ex.printStackTrace();
|
||||
@ -180,73 +170,26 @@ public class TrackResource {
|
||||
}
|
||||
} else if (data.deleted) {
|
||||
LOGGER.info("Data already exist but deleted");
|
||||
DataTools.undelete(data.id);
|
||||
DataTools.undelete(this.da, data.uuid);
|
||||
data.deleted = false;
|
||||
} else {
|
||||
LOGGER.info("Data already exist ... all good");
|
||||
}
|
||||
// Fist step: retrieve all the Id of each parents:...
|
||||
LOGGER.info("Find typeNode");
|
||||
Gender genderElem = null;
|
||||
if (gender != null) {
|
||||
genderElem = DataAccess.getWhere(Gender.class, new Condition(new QueryCondition("name", "=", gender)));
|
||||
if (genderElem == null) {
|
||||
genderElem = new Gender();
|
||||
genderElem.name = gender;
|
||||
genderElem = DataAccess.insert(genderElem);
|
||||
}
|
||||
}
|
||||
// NodeSmall typeNode = TypeResource.getWithId(Long.parseLong(typeId));
|
||||
// if (typeNode == null) {
|
||||
// DataTools.removeTemporaryFile(tmpUID);
|
||||
// return Response.notModified("TypeId does not exist ...").build();
|
||||
// }
|
||||
LOGGER.info(" ==> genderElem={}", genderElem);
|
||||
|
||||
Artist artistElem = null;
|
||||
if (artist != null) {
|
||||
LOGGER.info(" Try to find Artist: '{}'", artist);
|
||||
artistElem = DataAccess.getWhere(Artist.class, new Condition(new QueryCondition("name", "=", artist)));
|
||||
if (artistElem == null) {
|
||||
LOGGER.info(" ** Create a new one...");
|
||||
artistElem = new Artist();
|
||||
artistElem.name = artist;
|
||||
artistElem = DataAccess.insert(artistElem);
|
||||
}
|
||||
}
|
||||
LOGGER.info(" ==> artistElem={}", artistElem);
|
||||
|
||||
Album albumElem = null;
|
||||
if (album != null) {
|
||||
albumElem = DataAccess.getWhere(Album.class, new Condition(new QueryCondition("name", "=", album)));
|
||||
if (albumElem == null) {
|
||||
albumElem = new Album();
|
||||
albumElem.name = album;
|
||||
albumElem = DataAccess.insert(albumElem);
|
||||
}
|
||||
}
|
||||
LOGGER.info(" ==> " + album);
|
||||
|
||||
LOGGER.info("add media");
|
||||
|
||||
Track trackElem = new Track();
|
||||
trackElem.name = title;
|
||||
trackElem.track = trackId != null ? Long.parseLong(trackId) : null;
|
||||
trackElem.albumId = albumElem != null ? albumElem.id : null;
|
||||
trackElem.genderId = genderElem != null ? genderElem.id : null;
|
||||
trackElem.dataId = data.id;
|
||||
trackElem.albumId = albumId != null ? Long.parseLong(albumId) : null;
|
||||
trackElem.genderId = genderId != null ? Long.parseLong(genderId) : null;
|
||||
trackElem.dataId = data.uuid;
|
||||
// Now list of artist has an internal management:
|
||||
if (artistElem != null) {
|
||||
if (artistId != null) {
|
||||
trackElem.artists = new ArrayList<>();
|
||||
trackElem.artists.add(artistElem.id);
|
||||
trackElem.artists.add(artistId != null ? Long.parseLong(artistId) : null);
|
||||
}
|
||||
trackElem = DataAccess.insert(trackElem);
|
||||
/*
|
||||
Old mode of artist insertion (removed due to the slowlest request of getting value
|
||||
if (artistElem != null) {
|
||||
DataAccess.addLink(Track.class, trackElem.id, "artist", artistElem.id);
|
||||
}
|
||||
*/
|
||||
trackElem = this.da.insert(trackElem, new CheckFunction(CHECKER));
|
||||
/* Old mode of artist insertion (removed due to the slowlest request of getting value if (artistElem != null) { this.dam.addLink(Track.class, trackElem.id, "artist", artistElem.id); } */
|
||||
return Response.ok(trackElem).build();
|
||||
} catch (final Exception ex) {
|
||||
LOGGER.info("Catch an unexpected error ... {}", ex.getMessage());
|
||||
|
@ -1,9 +1,12 @@
|
||||
package org.kar.karusic.api;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.kar.archidata.dataAccess.DataAccess;
|
||||
import org.kar.archidata.filter.GenericContext;
|
||||
import org.kar.karusic.api.UserResourceModel.PartRight;
|
||||
import org.kar.karusic.api.UserResourceModel.UserMe;
|
||||
import org.kar.karusic.model.UserKarusic;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -20,9 +23,10 @@ import jakarta.ws.rs.core.MediaType;
|
||||
import jakarta.ws.rs.core.SecurityContext;
|
||||
|
||||
@Path("/users")
|
||||
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public class UserResource {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(UserResource.class);
|
||||
private final DataAccess da = DataAccess.createInterface();
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class UserOut {
|
||||
@ -44,7 +48,7 @@ public class UserResource {
|
||||
public List<UserKarusic> gets() {
|
||||
LOGGER.info("getUsers");
|
||||
try {
|
||||
return DataAccess.gets(UserKarusic.class);
|
||||
return this.da.gets(UserKarusic.class);
|
||||
} catch (final Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
@ -63,7 +67,7 @@ public class UserResource {
|
||||
LOGGER.info("== USER {} ", gc.userByToken.name);
|
||||
LOGGER.info("===================================================");
|
||||
try {
|
||||
return DataAccess.get(UserKarusic.class, userId);
|
||||
return this.da.get(UserKarusic.class, userId);
|
||||
} catch (final Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
@ -74,10 +78,15 @@ public class UserResource {
|
||||
@GET
|
||||
@Path("me")
|
||||
@RolesAllowed("USER")
|
||||
public UserOut getMe(@Context final SecurityContext sc) {
|
||||
public UserMe getMe(@Context final SecurityContext sc) {
|
||||
LOGGER.debug("getMe()");
|
||||
final GenericContext gc = (GenericContext) sc.getUserPrincipal();
|
||||
LOGGER.debug("== USER ? {}", gc.userByToken);
|
||||
return new UserOut(gc.userByToken.id, gc.userByToken.name);
|
||||
return new UserMe(gc.userByToken.id, gc.userByToken.name, //
|
||||
Map.of(gc.userByToken.name, //
|
||||
Map.of("admin", PartRight.READ_WRITE, //
|
||||
"user", PartRight.READ_WRITE), //
|
||||
"karusic", //
|
||||
Map.of("user", PartRight.READ)));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,12 @@
|
||||
package org.kar.karusic.api.UserResourceModel;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.kar.archidata.annotation.NoWriteSpecificMode;
|
||||
|
||||
@NoWriteSpecificMode
|
||||
public class ModuleAuthorizations extends HashMap<String, PartRight> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ModuleAuthorizations() {}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package org.kar.karusic.api.UserResourceModel;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonValue;
|
||||
|
||||
public enum PartRight {
|
||||
READ(1), //
|
||||
WRITE(2), //
|
||||
READ_WRITE(3);
|
||||
|
||||
private final int value;
|
||||
|
||||
PartRight(final int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@JsonValue
|
||||
public int getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public static PartRight fromValue(final int value) {
|
||||
for (final PartRight species : PartRight.values()) {
|
||||
if (species.getValue() == value) {
|
||||
return species;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("PartRight: Unknown value: " + value);
|
||||
}
|
||||
}
|
24
back/src/org/kar/karusic/api/UserResourceModel/UserMe.java
Normal file
24
back/src/org/kar/karusic/api/UserResourceModel/UserMe.java
Normal file
@ -0,0 +1,24 @@
|
||||
package org.kar.karusic.api.UserResourceModel;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.kar.archidata.annotation.NoWriteSpecificMode;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
@NoWriteSpecificMode
|
||||
public class UserMe {
|
||||
public long id;
|
||||
public String login;
|
||||
@Schema(description = "Map<EntityName, Map<PartName, Right>>")
|
||||
public Map<String, Map<String, PartRight>> rights;
|
||||
|
||||
public UserMe() {}
|
||||
|
||||
public UserMe(final long id, final String login, final Map<String, Map<String, PartRight>> rights) {
|
||||
this.id = id;
|
||||
this.login = login;
|
||||
this.rights = rights;
|
||||
}
|
||||
|
||||
}
|
@ -4,57 +4,57 @@ package org.kar.karusic.internal;
|
||||
//import io.scenarium.logger.Logger;
|
||||
|
||||
public class Log {
|
||||
// private static final String LIB_NAME = "logger";
|
||||
// private static final String LIB_NAME_DRAW = Logger.getDrawableName(LIB_NAME);
|
||||
// private static final boolean PRINT_CRITICAL = Logger.getNeedPrint(LIB_NAME, LogLevel.CRITICAL);
|
||||
// private static final boolean PRINT_ERROR = Logger.getNeedPrint(LIB_NAME, LogLevel.ERROR);
|
||||
// private static final boolean PRINT_WARNING = Logger.getNeedPrint(LIB_NAME, LogLevel.WARNING);
|
||||
// private static final boolean PRINT_INFO = Logger.getNeedPrint(LIB_NAME, LogLevel.INFO);
|
||||
// private static final boolean PRINT_DEBUG = Logger.getNeedPrint(LIB_NAME, LogLevel.DEBUG);
|
||||
// private static final boolean PRINT_VERBOSE = Logger.getNeedPrint(LIB_NAME, LogLevel.VERBOSE);
|
||||
// private static final boolean PRINT_TODO = Logger.getNeedPrint(LIB_NAME, LogLevel.TODO);
|
||||
// private static final boolean PRINT_PRINT = Logger.getNeedPrint(LIB_NAME, LogLevel.PRINT);
|
||||
//
|
||||
// private Log() {}
|
||||
//
|
||||
// public static void print(String data) {
|
||||
// if (PRINT_PRINT)
|
||||
// Logger.print(LIB_NAME_DRAW, data);
|
||||
// }
|
||||
//
|
||||
// public static void todo(String data) {
|
||||
// if (PRINT_TODO)
|
||||
// Logger.todo(LIB_NAME_DRAW, data);
|
||||
// }
|
||||
//
|
||||
// public static void critical(String data) {
|
||||
// if (PRINT_CRITICAL)
|
||||
// Logger.critical(LIB_NAME_DRAW, data);
|
||||
// }
|
||||
//
|
||||
// public static void error(String data) {
|
||||
// if (PRINT_ERROR)
|
||||
// Logger.error(LIB_NAME_DRAW, data);
|
||||
// }
|
||||
//
|
||||
// public static void warning(String data) {
|
||||
// if (PRINT_WARNING)
|
||||
// Logger.warning(LIB_NAME_DRAW, data);
|
||||
// }
|
||||
//
|
||||
// public static void info(String data) {
|
||||
// if (PRINT_INFO)
|
||||
// Logger.info(LIB_NAME_DRAW, data);
|
||||
// }
|
||||
//
|
||||
// public static void debug(String data) {
|
||||
// if (PRINT_DEBUG)
|
||||
// Logger.debug(LIB_NAME_DRAW, data);
|
||||
// }
|
||||
//
|
||||
// public static void verbose(String data) {
|
||||
// if (PRINT_VERBOSE)
|
||||
// Logger.verbose(LIB_NAME_DRAW, data);
|
||||
// }
|
||||
// private static final String LIB_NAME = "logger";
|
||||
// private static final String LIB_NAME_DRAW = Logger.getDrawableName(LIB_NAME);
|
||||
// private static final boolean PRINT_CRITICAL = Logger.getNeedPrint(LIB_NAME, LogLevel.CRITICAL);
|
||||
// private static final boolean PRINT_ERROR = Logger.getNeedPrint(LIB_NAME, LogLevel.ERROR);
|
||||
// private static final boolean PRINT_WARNING = Logger.getNeedPrint(LIB_NAME, LogLevel.WARNING);
|
||||
// private static final boolean PRINT_INFO = Logger.getNeedPrint(LIB_NAME, LogLevel.INFO);
|
||||
// private static final boolean PRINT_DEBUG = Logger.getNeedPrint(LIB_NAME, LogLevel.DEBUG);
|
||||
// private static final boolean PRINT_VERBOSE = Logger.getNeedPrint(LIB_NAME, LogLevel.VERBOSE);
|
||||
// private static final boolean PRINT_TODO = Logger.getNeedPrint(LIB_NAME, LogLevel.TODO);
|
||||
// private static final boolean PRINT_PRINT = Logger.getNeedPrint(LIB_NAME, LogLevel.PRINT);
|
||||
//
|
||||
// private Log() {}
|
||||
//
|
||||
// public static void print(String data) {
|
||||
// if (PRINT_PRINT)
|
||||
// Logger.print(LIB_NAME_DRAW, data);
|
||||
// }
|
||||
//
|
||||
// public static void todo(String data) {
|
||||
// if (PRINT_TODO)
|
||||
// Logger.todo(LIB_NAME_DRAW, data);
|
||||
// }
|
||||
//
|
||||
// public static void critical(String data) {
|
||||
// if (PRINT_CRITICAL)
|
||||
// Logger.critical(LIB_NAME_DRAW, data);
|
||||
// }
|
||||
//
|
||||
// public static void error(String data) {
|
||||
// if (PRINT_ERROR)
|
||||
// Logger.error(LIB_NAME_DRAW, data);
|
||||
// }
|
||||
//
|
||||
// public static void warning(String data) {
|
||||
// if (PRINT_WARNING)
|
||||
// Logger.warning(LIB_NAME_DRAW, data);
|
||||
// }
|
||||
//
|
||||
// public static void info(String data) {
|
||||
// if (PRINT_INFO)
|
||||
// Logger.info(LIB_NAME_DRAW, data);
|
||||
// }
|
||||
//
|
||||
// public static void debug(String data) {
|
||||
// if (PRINT_DEBUG)
|
||||
// Logger.debug(LIB_NAME_DRAW, data);
|
||||
// }
|
||||
//
|
||||
// public static void verbose(String data) {
|
||||
// if (PRINT_VERBOSE)
|
||||
// Logger.verbose(LIB_NAME_DRAW, data);
|
||||
// }
|
||||
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package org.kar.karusic.migration;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.kar.archidata.dataAccess.DataAccess;
|
||||
import org.kar.archidata.migration.MigrationSqlStep;
|
||||
import org.kar.archidata.model.Data;
|
||||
import org.kar.archidata.model.User;
|
||||
@ -10,11 +11,14 @@ import org.kar.karusic.model.Artist;
|
||||
import org.kar.karusic.model.Gender;
|
||||
import org.kar.karusic.model.Playlist;
|
||||
import org.kar.karusic.model.Track;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class Initialization extends MigrationSqlStep {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(Initialization.class);
|
||||
|
||||
public static final int KARSO_INITIALISATION_ID = 1;
|
||||
public static final List<Class<?>> CLASSES_BASE = List.of(Album.class,Artist.class,Data.class,Gender.class,Playlist.class,Track.class,User.class);
|
||||
public static final List<Class<?>> CLASSES_BASE = List.of(Album.class, Artist.class, Data.class, Gender.class, Playlist.class, Track.class, User.class);
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
@ -31,35 +35,35 @@ public class Initialization extends MigrationSqlStep {
|
||||
addClass(elem);
|
||||
}
|
||||
|
||||
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);
|
||||
""");
|
||||
addAction((final DataAccess da) -> {
|
||||
final List<Gender> data = List.of(//
|
||||
new Gender(1L, "Variété française"), //
|
||||
new Gender(2L, "Pop"), //
|
||||
new Gender(3L, "inconnue"), //
|
||||
new Gender(4L, "Disco"), //
|
||||
new Gender(5L, "Enfants"), //
|
||||
new Gender(6L, "Portugaise"), //
|
||||
new Gender(7L, "Apprentissage"), //
|
||||
new Gender(8L, "Blues"), //
|
||||
new Gender(9L, "Jazz"), //
|
||||
new Gender(10L, "Chanson Noël"), //
|
||||
new Gender(11L, "DubStep"), //
|
||||
new Gender(12L, "Rap français"), //
|
||||
new Gender(13L, "Classique"), //
|
||||
new Gender(14L, "Rock"), //
|
||||
new Gender(15L, "Electro"), //
|
||||
new Gender(16L, "Celtique"), //
|
||||
new Gender(17L, "Country"), //
|
||||
new Gender(18L, "Variété Québéquoise"), //
|
||||
new Gender(19L, "Médiéval"), //
|
||||
new Gender(20L, "Variété Italienne"), //
|
||||
new Gender(21L, "Comédie Musicale"), //
|
||||
new Gender(22L, "Vianney"), //
|
||||
new Gender(23L, "Bande Original"), //
|
||||
new Gender(24L, "Bande Originale"), //
|
||||
new Gender(25L, "Variété Belge"), //
|
||||
new Gender(26L, "Gospel"));
|
||||
});
|
||||
// set start increment element to permit to add after default elements
|
||||
addAction("""
|
||||
ALTER TABLE `album` AUTO_INCREMENT = 1000;
|
||||
@ -81,4 +85,25 @@ public class Initialization extends MigrationSqlStep {
|
||||
""", "mysql");
|
||||
}
|
||||
|
||||
public static void dropAll(final DataAccess da) {
|
||||
for (final Class<?> element : CLASSES_BASE) {
|
||||
try {
|
||||
da.drop(element);
|
||||
} catch (final Exception ex) {
|
||||
LOGGER.error("Fail to drop table !!!!!!");
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void cleanAll(final DataAccess da) {
|
||||
for (final Class<?> element : CLASSES_BASE) {
|
||||
try {
|
||||
da.cleanAll(element);
|
||||
} catch (final Exception ex) {
|
||||
LOGGER.error("Fail to clean table !!!!!!");
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import java.util.UUID;
|
||||
|
||||
import org.kar.archidata.api.DataResource;
|
||||
import org.kar.archidata.dataAccess.DataAccess;
|
||||
import org.kar.archidata.dataAccess.addOn.model.LinkTable;
|
||||
import org.kar.archidata.dataAccess.addOn.model.LinkTableLongLong;
|
||||
import org.kar.archidata.dataAccess.options.AccessDeletedItems;
|
||||
import org.kar.archidata.dataAccess.options.OverrideTableName;
|
||||
import org.kar.archidata.migration.MigrationSqlStep;
|
||||
@ -41,10 +41,10 @@ public class Migration20240226 extends MigrationSqlStep {
|
||||
""");
|
||||
addAction(() -> {
|
||||
final List<UUIDConversion> datas = DataAccess.gets(UUIDConversion.class, new AccessDeletedItems(), new OverrideTableName("data"));
|
||||
for (final UUIDConversion elem: datas) {
|
||||
for (final UUIDConversion elem : datas) {
|
||||
elem.uuid = UuidUtils.nextUUID();
|
||||
}
|
||||
for (final UUIDConversion elem: datas) {
|
||||
for (final UUIDConversion elem : datas) {
|
||||
DataAccess.update(elem, elem.id, List.of("uuid"), new OverrideTableName("data"));
|
||||
}
|
||||
});
|
||||
@ -52,18 +52,18 @@ public class Migration20240226 extends MigrationSqlStep {
|
||||
ALTER TABLE `data` CHANGE `uuid` `uuid` binary(16) DEFAULT (UUID_TO_BIN(UUID(), TRUE));
|
||||
""");
|
||||
final List<String> tableToTransform = List.of("album", "artist", "gender", "playlist", "track", "user");
|
||||
for (final String tableName : tableToTransform ) {
|
||||
for (final String tableName : tableToTransform) {
|
||||
addAction("ALTER TABLE `" + tableName + "` ADD `covers` text NULL;");
|
||||
addAction(() -> {
|
||||
final List<UUIDConversion> datas = DataAccess.gets(UUIDConversion.class, new AccessDeletedItems(), new OverrideTableName("data"));
|
||||
final List<CoverConversion> medias = DataAccess.gets(CoverConversion.class, new AccessDeletedItems(), new OverrideTableName(tableName));
|
||||
final List<LinkTable> links = DataAccess.gets(LinkTable.class, new OverrideTableName(tableName + "_link_cover"));
|
||||
final List<LinkTableLongLong> links = DataAccess.gets(LinkTableLongLong.class, new OverrideTableName(tableName + "_link_cover"));
|
||||
LOGGER.info("Get somes data: {} {} {}", datas.size(), medias.size(), links.size());
|
||||
for (final CoverConversion media: medias) {
|
||||
for (final CoverConversion media : medias) {
|
||||
final List<UUID> values = new ArrayList<>();
|
||||
for (final LinkTable link: links) {
|
||||
for (final LinkTableLongLong link : links) {
|
||||
if (link.object1Id.equals(media.id)) {
|
||||
for (final UUIDConversion data: datas) {
|
||||
for (final UUIDConversion data : datas) {
|
||||
if (data.id.equals(link.object2Id)) {
|
||||
values.add(data.uuid);
|
||||
break;
|
||||
@ -87,8 +87,8 @@ public class Migration20240226 extends MigrationSqlStep {
|
||||
addAction(() -> {
|
||||
final List<UUIDConversion> datas = DataAccess.gets(UUIDConversion.class, new AccessDeletedItems(), new OverrideTableName("data"));
|
||||
final List<MediaConversion> medias = DataAccess.gets(MediaConversion.class, new AccessDeletedItems(), new OverrideTableName("track"));
|
||||
for (final MediaConversion media: medias) {
|
||||
for (final UUIDConversion data: datas) {
|
||||
for (final MediaConversion media : medias) {
|
||||
for (final UUIDConversion data : datas) {
|
||||
if (data.id.equals(media.dataId)) {
|
||||
media.dataUUID = data.uuid;
|
||||
DataAccess.update(media, media.id, List.of("dataUUID"), new OverrideTableName("track"));
|
||||
@ -113,7 +113,7 @@ public class Migration20240226 extends MigrationSqlStep {
|
||||
// Move the files...
|
||||
addAction(() -> {
|
||||
final List<UUIDConversion> datas = DataAccess.gets(UUIDConversion.class, new AccessDeletedItems(), new OverrideTableName("data"));
|
||||
for (final UUIDConversion data: datas) {
|
||||
for (final UUIDConversion data : datas) {
|
||||
final String origin = DataResource.getFileDataOld(data.id);
|
||||
final String destination = DataResource.getFileData(data.uuid);
|
||||
LOGGER.info("move file = {}", origin);
|
||||
|
34
back/src/org/kar/karusic/migration/Migration20240907.java
Normal file
34
back/src/org/kar/karusic/migration/Migration20240907.java
Normal file
@ -0,0 +1,34 @@
|
||||
package org.kar.karusic.migration;
|
||||
|
||||
import org.kar.archidata.migration.MigrationSqlStep;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class Migration20240907 extends MigrationSqlStep {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(Migration20240907.class);
|
||||
|
||||
public static final int KARSO_INITIALISATION_ID = 1;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "migration-2024-09-07: convert data id in uuid";
|
||||
}
|
||||
|
||||
public Migration20240907() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateStep() throws Exception {
|
||||
addAction("""
|
||||
ALTER TABLE `data` DROP INDEX `PRIMARY`;
|
||||
""");
|
||||
addAction("""
|
||||
ALTER TABLE `data` CHANGE `id` `uuid` binary(16) DEFAULT (UUID_TO_BIN(UUID(), TRUE));
|
||||
""");
|
||||
addAction("""
|
||||
ALTER TABLE `data` ADD PRIMARY KEY `uuid` (`uuid`);
|
||||
""");
|
||||
}
|
||||
|
||||
}
|
@ -1,16 +1,41 @@
|
||||
package org.kar.karusic.model;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.kar.archidata.annotation.DataIfNotExists;
|
||||
import org.kar.archidata.annotation.DataJson;
|
||||
import org.kar.archidata.dataAccess.options.CheckJPA;
|
||||
import org.kar.archidata.model.Data;
|
||||
import org.kar.archidata.model.GenericDataSoftDelete;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.annotation.Nullable;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
@Entity("Album")
|
||||
@Table(name = "album")
|
||||
@DataIfNotExists
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class Album extends NodeSmall {
|
||||
public class Album extends GenericDataSoftDelete {
|
||||
public static class AlbumChecker extends CheckJPA<Album> {
|
||||
public AlbumChecker() {
|
||||
super(Album.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Column(length = 256)
|
||||
public String name = null;
|
||||
@Column(length = 0)
|
||||
public String description = null;
|
||||
@Schema(description = "List of Id of the specific covers")
|
||||
@DataJson(targetEntity = Data.class)
|
||||
@Nullable
|
||||
public List<UUID> covers = null;
|
||||
public LocalDate publication = null;
|
||||
}
|
||||
|
@ -1,18 +1,42 @@
|
||||
package org.kar.karusic.model;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.kar.archidata.annotation.DataIfNotExists;
|
||||
import org.kar.archidata.annotation.DataJson;
|
||||
import org.kar.archidata.dataAccess.options.CheckJPA;
|
||||
import org.kar.archidata.model.Data;
|
||||
import org.kar.archidata.model.GenericDataSoftDelete;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.annotation.Nullable;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
@Entity("Artist")
|
||||
@Table(name = "artist")
|
||||
@DataIfNotExists
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class Artist extends NodeSmall {
|
||||
public class Artist extends GenericDataSoftDelete {
|
||||
public static class ArtistChecker extends CheckJPA<Artist> {
|
||||
public ArtistChecker() {
|
||||
super(Artist.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Column(length = 256)
|
||||
public String name = null;
|
||||
@Column(length = 0)
|
||||
public String description = null;
|
||||
@Schema(description = "List of Id of the specific covers")
|
||||
@DataJson(targetEntity = Data.class)
|
||||
@Nullable
|
||||
public List<UUID> covers = null;
|
||||
@Column(length = 256)
|
||||
public String firstName = null;
|
||||
@Column(length = 256)
|
||||
|
@ -12,15 +12,48 @@ CREATE TABLE `node` (
|
||||
) AUTO_INCREMENT=10;
|
||||
*/
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.kar.archidata.annotation.DataIfNotExists;
|
||||
import org.kar.archidata.annotation.DataJson;
|
||||
import org.kar.archidata.dataAccess.options.CheckJPA;
|
||||
import org.kar.archidata.model.Data;
|
||||
import org.kar.archidata.model.GenericDataSoftDelete;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.annotation.Nullable;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
@Entity("Gender")
|
||||
@Table(name = "gender")
|
||||
@DataIfNotExists
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class Gender extends NodeSmall {
|
||||
public class Gender extends GenericDataSoftDelete {
|
||||
public static class GenderChecker extends CheckJPA<Gender> {
|
||||
public GenderChecker() {
|
||||
super(Gender.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Column(length = 256)
|
||||
public String name = null;
|
||||
@Column(length = 0)
|
||||
public String description = null;
|
||||
@Schema(description = "List of Id of the specific covers")
|
||||
@DataJson(targetEntity = Data.class)
|
||||
@Nullable
|
||||
public List<UUID> covers = null;
|
||||
|
||||
public Gender() {}
|
||||
|
||||
public Gender(final Long id, final String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,36 +0,0 @@
|
||||
package org.kar.karusic.model;
|
||||
/*
|
||||
CREATE TABLE `node` (
|
||||
`id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY,
|
||||
`deleted` BOOLEAN NOT NULL DEFAULT false,
|
||||
`create_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been created',
|
||||
`modify_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been update',
|
||||
`type` enum("TYPE", "UNIVERS", "SERIE", "SAISON", "MEDIA") NOT NULL DEFAULT 'TYPE',
|
||||
`name` TEXT COLLATE 'utf8_general_ci' NOT NULL,
|
||||
`description` TEXT COLLATE 'utf8_general_ci',
|
||||
`parent_id` bigint
|
||||
) AUTO_INCREMENT=10;
|
||||
*/
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.kar.archidata.annotation.DataJson;
|
||||
import org.kar.archidata.model.Data;
|
||||
import org.kar.archidata.model.GenericDataSoftDelete;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.persistence.Column;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class NodeSmall extends GenericDataSoftDelete {
|
||||
@Column(length = 256)
|
||||
public String name = null;
|
||||
@Column(length = 0)
|
||||
public String description = null;
|
||||
@Schema(description = "List of Id of the specific covers")
|
||||
@DataJson(targetEntity = Data.class)
|
||||
public List<UUID> covers = null;
|
||||
}
|
@ -13,19 +13,43 @@ CREATE TABLE `node` (
|
||||
*/
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.kar.archidata.annotation.DataIfNotExists;
|
||||
import org.kar.archidata.annotation.DataJson;
|
||||
import org.kar.archidata.dataAccess.options.CheckJPA;
|
||||
import org.kar.archidata.model.Data;
|
||||
import org.kar.archidata.model.GenericDataSoftDelete;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.annotation.Nullable;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.ManyToMany;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
@Entity("Playlist")
|
||||
@Table(name = "playlist")
|
||||
@DataIfNotExists
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class Playlist extends NodeSmall {
|
||||
public class Playlist extends GenericDataSoftDelete {
|
||||
public static class PlaylistChecker extends CheckJPA<Playlist> {
|
||||
public PlaylistChecker() {
|
||||
super(Playlist.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Column(length = 256)
|
||||
public String name = null;
|
||||
@Column(length = 0)
|
||||
public String description = null;
|
||||
@Schema(description = "List of Id of the specific covers")
|
||||
@DataJson(targetEntity = Data.class)
|
||||
@Nullable
|
||||
public List<UUID> covers = null;
|
||||
@ManyToMany(fetch = FetchType.LAZY, targetEntity = Track.class)
|
||||
public List<Long> tracks = null;
|
||||
}
|
||||
|
@ -17,21 +17,43 @@ import java.util.UUID;
|
||||
|
||||
import org.kar.archidata.annotation.DataIfNotExists;
|
||||
import org.kar.archidata.annotation.DataJson;
|
||||
import org.kar.archidata.dataAccess.options.CheckJPA;
|
||||
import org.kar.archidata.model.Data;
|
||||
import org.kar.archidata.model.GenericDataSoftDelete;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.annotation.Nullable;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
@Entity("Track")
|
||||
@Table(name = "track")
|
||||
@DataIfNotExists
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class Track extends NodeSmall {
|
||||
public class Track extends GenericDataSoftDelete {
|
||||
|
||||
public static class TrackChecker extends CheckJPA<Track> {
|
||||
public TrackChecker() {
|
||||
super(Track.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Column(length = 256)
|
||||
public String name = null;
|
||||
@Column(length = 0)
|
||||
public String description = null;
|
||||
@Schema(description = "List of Id of the specific covers")
|
||||
@DataJson(targetEntity = Data.class)
|
||||
@Nullable
|
||||
public List<UUID> covers = null;
|
||||
public Long genderId = null;
|
||||
public Long albumId = null;
|
||||
public Long track = null;
|
||||
public UUID dataId = null;
|
||||
//@ManyToMany(fetch = FetchType.LAZY, targetEntity = Artist.class)
|
||||
// @ManyToMany(fetch = FetchType.LAZY, targetEntity = Artist.class)
|
||||
@DataJson
|
||||
@Column(length = 0)
|
||||
public List<Long> artists = null;
|
||||
|
@ -3,7 +3,6 @@ package org.kar.karusic.util;
|
||||
public class ConfigVariable {
|
||||
public static final String BASE_NAME = "ORG_KARUSIC_";
|
||||
|
||||
|
||||
public static String getFrontFolder() {
|
||||
String out = System.getenv(BASE_NAME + "FRONT_FOLDER");
|
||||
if (out == null) {
|
||||
|
@ -3,12 +3,14 @@
|
||||
# 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
|
||||
org.slf4j.simpleLogger.defaultLogLevel=INFO
|
||||
|
||||
# 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=
|
||||
org.slf4j.simpleLogger.log.org.kar.archidata=TRACE
|
||||
org.slf4j.simpleLogger.log.org.kar.karusic=TRACE
|
||||
|
||||
# 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.
|
||||
|
10
back/test/src/test/kar/karusic/Common.java
Normal file
10
back/test/src/test/kar/karusic/Common.java
Normal file
@ -0,0 +1,10 @@
|
||||
package test.kar.karusic;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.kar.archidata.tools.JWTWrapper;
|
||||
|
||||
public class Common {
|
||||
static String USER_TOKEN = JWTWrapper.createJwtTestToken(16512, "test_user_login", "KarAuth", "karusic", Map.of("karusic", Map.of("USER", Boolean.TRUE)));
|
||||
static String ADMIN_TOKEN = JWTWrapper.createJwtTestToken(16512, "test_admin_login", "KarAuth", "karusic", Map.of("karusic", Map.of("USER", Boolean.TRUE, "ADMIN", Boolean.TRUE)));
|
||||
}
|
@ -1,51 +1,43 @@
|
||||
package test.kar.karusic;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.MethodOrderer;
|
||||
import org.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestMethodOrder;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.kar.archidata.exception.RESTErrorResponseExeption;
|
||||
import org.kar.archidata.model.GetToken;
|
||||
import org.kar.archidata.tools.ConfigBaseVariable;
|
||||
import org.kar.archidata.tools.JWTWrapper;
|
||||
import org.kar.archidata.tools.RESTApi;
|
||||
import org.kar.karusic.api.HealthCheck.HealthResult;
|
||||
import org.kar.karusic.migration.Initialization;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.nimbusds.jwt.JWTClaimsSet;
|
||||
|
||||
@ExtendWith(StepwiseExtension.class)
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
public class TestBase {
|
||||
private final static Logger LOGGER = LoggerFactory.getLogger(TestBase.class);
|
||||
public final static String ENDPOINT_NAME = "species/";
|
||||
|
||||
static WebLauncherTest webInterface = null;
|
||||
static RESTApi api = null;
|
||||
|
||||
public void login(final String login, final String password) {
|
||||
try {
|
||||
final GetToken token = api.post(GetToken.class, "users/get_token", DataGetToken.generate(login, "v1", "202515252", password));
|
||||
api.setToken(token.jwt());
|
||||
} catch (final Exception ex) {
|
||||
Assertions.fail("Can not get Authentication for '" + login + "' ==> " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void loginAdmin() {
|
||||
login("karadmin", "adminA@666");
|
||||
}
|
||||
private static UUID idTest;
|
||||
|
||||
@BeforeAll
|
||||
public static void configureWebServer() throws Exception {
|
||||
LOGGER.info("configure server ...");
|
||||
webInterface = new WebLauncherTest();
|
||||
LOGGER.info("Clean previous table");
|
||||
|
||||
try {
|
||||
Initialization.dropAll();
|
||||
} catch (final Exception ex) {
|
||||
ex.printStackTrace();
|
||||
LOGGER.error("plop: {}", ex.getLocalizedMessage());
|
||||
throw ex;
|
||||
}
|
||||
|
||||
LOGGER.info("Create DB");
|
||||
try {
|
||||
webInterface.migrateDB();
|
||||
@ -57,194 +49,18 @@ public class TestBase {
|
||||
webInterface.process();
|
||||
LOGGER.info("Start REST (DONE)");
|
||||
api = new RESTApi(ConfigBaseVariable.apiAdress);
|
||||
api.setToken(Common.USER_TOKEN);
|
||||
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void stopWebServer() throws InterruptedException {
|
||||
public static void stopWebServer() throws Exception {
|
||||
LOGGER.info("Kill the web server");
|
||||
webInterface.stop();
|
||||
webInterface = null;
|
||||
// TODO: do it better...
|
||||
}
|
||||
|
||||
@Order(1)
|
||||
@Test
|
||||
//@RepeatedTest(10)
|
||||
public void checkHealthCheck() throws Exception {
|
||||
final HealthResult result = api.get(HealthResult.class, "health_check");
|
||||
Assertions.assertEquals(result.value(), "alive and kicking");
|
||||
}
|
||||
|
||||
@Order(2)
|
||||
@Test
|
||||
public void checkHealthCheckWrongAPI() throws Exception {
|
||||
Assertions.assertThrows(RESTErrorResponseExeption.class, () -> api.get(HealthResult.class, "health_checks"));
|
||||
}
|
||||
|
||||
@Order(3)
|
||||
@Test
|
||||
public void firstUserConnect() throws Exception {
|
||||
final GetToken result = api.post(GetToken.class, "users/get_token", DataGetToken.generate("karadmin", "v1", "202515252", "adminA@666"));
|
||||
final String[] splitted = result.jwt().split("\\.");
|
||||
Assertions.assertEquals(3, splitted.length);
|
||||
final String authorization = result.jwt();
|
||||
LOGGER.debug(" validate token : " + authorization);
|
||||
// Note with local access we get the internal key of the system.
|
||||
final JWTClaimsSet ret = JWTWrapper.validateToken(authorization, "KarAuth", null);
|
||||
// check the token is valid !!! (signed and coherent issuer...
|
||||
Assertions.assertNotNull(ret);
|
||||
// check userID
|
||||
final String userUID = ret.getSubject();
|
||||
final long id = Long.parseLong(userUID);
|
||||
Assertions.assertEquals(1, id);
|
||||
final String name = (String) ret.getClaim("login");
|
||||
Assertions.assertEquals("karadmin", name);
|
||||
|
||||
final Object rowRight = ret.getClaim("right");
|
||||
Assertions.assertNotNull(rowRight);
|
||||
final Map<String, Map<String, Object>> rights = (Map<String, Map<String, Object>>) ret.getClaim("right");
|
||||
// Check if the element contain the basic keys:
|
||||
Assertions.assertEquals(rights.size(), 1);
|
||||
Assertions.assertTrue(rights.containsKey("karusic"));
|
||||
final Map<String, Object> applRight = rights.get("karusic");
|
||||
//logger.error("full right: {}", applRight);
|
||||
Assertions.assertEquals(applRight.size(), 2);
|
||||
Assertions.assertTrue(applRight.containsKey("ADMIN"));
|
||||
Assertions.assertEquals(true, applRight.get("ADMIN"));
|
||||
Assertions.assertTrue(applRight.containsKey("USER"));
|
||||
Assertions.assertEquals(true, applRight.get("USER"));
|
||||
|
||||
//logger.debug("request user: '{}' right: '{}' row='{}'", userUID, applRight, rowRight);
|
||||
|
||||
//Assertions.assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9", splitted[0]);
|
||||
//Assertions.assertEquals("eyJzdWIiOiIwIiwiYXBwbGljYXRpb24iOiJrYXJzbyIsImlzcyI6IkthckF1dGgiLCJyaWdodCI6eyJrYXJzbyI6eyJBRE1JTiI6dHJ1ZSwiVVNFUiI6dHJ1ZX19LCJsb2dpbiI6ImthcmFkbWluIiwiZXhwIjoxNjg0MTk5MTkzLCJpYXQiOjE2ODI3NTU0MjV9", splitted[1]);
|
||||
// TODO ... Assertions.assertEquals("????", splitted[2]);
|
||||
}
|
||||
|
||||
public void checkFail(final String type, final String urlOffset, final int errorStatus) {
|
||||
checkFail(type, urlOffset, errorStatus, null);
|
||||
}
|
||||
|
||||
public void checkFail(final String type, final String urlOffset, final int errorStatus, final String data) {
|
||||
LOGGER.info("Test API: url={} urlOffset={}", type, urlOffset);
|
||||
try {
|
||||
if ("GET".equals(type)) {
|
||||
api.get(String.class, urlOffset);
|
||||
} else if ("POST".equals(type)) {
|
||||
api.post(String.class, urlOffset, data);
|
||||
} else if ("PUT".equals(type)) {
|
||||
api.put(String.class, urlOffset, data);
|
||||
} else if ("DELETE".equals(type)) {
|
||||
api.delete(String.class, urlOffset);
|
||||
}
|
||||
Assertions.fail("Request on URL does not fail as expected: '" + type + "' url='" + urlOffset + "'");
|
||||
} catch (final RESTErrorResponseExeption ex) {
|
||||
if (errorStatus != ex.status) {
|
||||
LOGGER.error("Fail in test with the wrong return errors: {}", ex.toString());
|
||||
}
|
||||
Assertions.assertEquals(errorStatus, ex.status);
|
||||
} catch (final Exception ex) {
|
||||
LOGGER.error("Unexpected throw error: {}", ex);
|
||||
Assertions.fail("Unexpected throws...");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void checkWork(final String type, final String urlOffset) {
|
||||
checkWork(type, urlOffset, null);
|
||||
}
|
||||
|
||||
public void checkWork(final String type, final String urlOffset, final String data) {
|
||||
LOGGER.info("Test API: url={} urlOffset={}", type, urlOffset);
|
||||
try {
|
||||
if ("GET".equals(type)) {
|
||||
api.get(String.class, urlOffset);
|
||||
} else if ("POST".equals(type)) {
|
||||
api.post(String.class, urlOffset, data);
|
||||
} else if ("PUT".equals(type)) {
|
||||
api.put(String.class, urlOffset, data);
|
||||
} else if ("DELETE".equals(type)) {
|
||||
api.delete(String.class, urlOffset);
|
||||
}
|
||||
//Assertions.fail("Request on URL does not fail as expected: '" + type + "' url='" + urlOffset + "'");
|
||||
} catch (final RESTErrorResponseExeption ex) {
|
||||
Assertions.fail("Must not fail ... " + ex.toString());
|
||||
} catch (final Exception ex) {
|
||||
LOGGER.error("Unexpected throw error: {}", ex);
|
||||
Assertions.fail("Unexpected throws...");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Order(4)
|
||||
@Test
|
||||
public void checkUnAuthorizedAPI() throws Exception {
|
||||
// /application/
|
||||
checkFail("GET", "application/", 401);
|
||||
checkFail("POST", "application/", 401, "{}");
|
||||
checkFail("PUT", "application/", 405, "{}"); // does not exist
|
||||
checkFail("DELETE", "application/", 405); // does not exist
|
||||
// /application/{id}
|
||||
checkFail("GET", "application/0", 401);
|
||||
checkFail("PUT", "application/0", 401, "{}");
|
||||
checkFail("POST", "application/0", 405, "{}");
|
||||
checkFail("DELETE", "application/0", 401);
|
||||
// /application/{id}/*
|
||||
checkFail("GET", "application/0/users", 401);
|
||||
// /application/*
|
||||
checkFail("GET", "application/small", 401);
|
||||
checkFail("GET", "application/get_token", 401);
|
||||
checkFail("GET", "application/return", 401);
|
||||
|
||||
// /application_token/ section:
|
||||
checkFail("GET", "application_token/0", 401);
|
||||
checkFail("DELETE", "application_token/0/5", 401);
|
||||
checkFail("DELETE", "application_token/0/create", 401);
|
||||
|
||||
// /front/*
|
||||
checkFail("GET", "front", 404); // no index in test section
|
||||
// health check
|
||||
checkWork("GET", "health_check");
|
||||
|
||||
// public_key (only application)
|
||||
checkFail("GET", "public_key", 401);
|
||||
checkFail("GET", "public_key/pem", 401);
|
||||
|
||||
// /right
|
||||
checkFail("GET", "right", 401);
|
||||
checkFail("POST", "right", 401, "{}");
|
||||
checkFail("GET", "right/0", 401);
|
||||
checkFail("PUT", "right/0", 401, "{}");
|
||||
checkFail("DELETE", "right/0", 401);
|
||||
|
||||
// /system_config
|
||||
checkWork("GET", "system_config/is_sign_up_availlable");
|
||||
checkFail("GET", "system_config/key/skjdfhkjsdhfkjsh", 401);
|
||||
checkFail("PUT", "system_config/key/skjdfhkjsdhfkjsh", 401, "{}");
|
||||
|
||||
// /users
|
||||
checkFail("GET", "users", 401);
|
||||
checkFail("GET", "users/0", 401);
|
||||
checkFail("POST", "users/0/application/0/link", 401, "{}");
|
||||
checkFail("POST", "users/0/set_admin", 401, "{}");
|
||||
checkFail("POST", "users/0/set_blocked", 401, "{}");
|
||||
checkFail("POST", "users/create_new_user", 401, "{}");
|
||||
checkFail("GET", "users/me", 401, "{}");
|
||||
checkFail("POST", "users/password", 401, "{}");
|
||||
checkWork("GET", "users/check_login?login=karadmin");
|
||||
checkFail("GET", "users/check_login?login=jhkjhkjh", 404);
|
||||
checkWork("GET", "users/check_email?email=admin@admin.ZZZ");
|
||||
checkFail("GET", "users/check_email?email=ksjhdkjfhskjdh", 404);
|
||||
// not testable : get_token
|
||||
|
||||
}
|
||||
|
||||
@Order(5)
|
||||
@Test
|
||||
public void testMeWithToken() throws Exception {
|
||||
loginAdmin();
|
||||
final String result = api.get(String.class, "users/me");
|
||||
Assertions.assertEquals("{\"id\":1,\"login\":\"karadmin\"}", result);
|
||||
|
||||
LOGGER.info("Remove the test db");
|
||||
DBEntry.closeAllForceMode();
|
||||
ConfigBaseVariable.clearAllValue();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -12,17 +12,23 @@ public class WebLauncherTest extends WebLauncher {
|
||||
public WebLauncherTest() {
|
||||
LOGGER.debug("Configure REST system");
|
||||
// for local test:
|
||||
ConfigBaseVariable.apiAdress = "http://127.0.0.1:12345/test/api/";
|
||||
|
||||
ConfigBaseVariable.dbPort = "3306";
|
||||
ConfigBaseVariable.apiAdress = "http://127.0.0.1:13212/test/api/";
|
||||
// Enable the test mode permit to access to the test token (never use it in production).
|
||||
ConfigBaseVariable.testMode = "true";
|
||||
// for the test we a in memory sqlite..
|
||||
if (true) {
|
||||
if (!"true".equalsIgnoreCase(System.getenv("TEST_E2E_MODE"))) {
|
||||
ConfigBaseVariable.dbType = "sqlite";
|
||||
ConfigBaseVariable.dbHost = "memory";
|
||||
// for test we need to connect all time the DB
|
||||
ConfigBaseVariable.dbKeepConnected = "true";
|
||||
|
||||
ConfigBaseVariable.dbHost = "localhost";
|
||||
}
|
||||
} else {
|
||||
// Enable this if you want to access to a local MySQL base to test with an adminer
|
||||
ConfigBaseVariable.bdDatabase = "test_db";
|
||||
ConfigBaseVariable.dbPort = "3309";
|
||||
ConfigBaseVariable.dbUser = "root";
|
||||
ConfigBaseVariable.dbPassword = "ZERTYSDGFVHSDFGHJYZSDFGSQxfgsqdfgsqdrf4564654";
|
||||
// ConfigBaseVariable.dbPassword = "password";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
55
env_dev/docker-compose.yaml
Normal file
55
env_dev/docker-compose.yaml
Normal file
@ -0,0 +1,55 @@
|
||||
services:
|
||||
kar_db_service:
|
||||
image: mysql:latest
|
||||
restart: always
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=base_db_password
|
||||
volumes:
|
||||
- ./data:/var/lib/mysql
|
||||
mem_limit: 300m
|
||||
ports:
|
||||
- 3906:3306
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
# perform a 1 minute grace to let the DB to perform the initialization
|
||||
start_period: 1m
|
||||
start_interval: 1m
|
||||
|
||||
kar_mongodb_service:
|
||||
image: mongo:latest
|
||||
environment:
|
||||
MONGO_INITDB_ROOT_USERNAME: root
|
||||
MONGO_INITDB_ROOT_PASSWORD: base_db_password
|
||||
ports:
|
||||
- 27017:27017
|
||||
volumes:
|
||||
- ./dataMongo:/data/db
|
||||
|
||||
kar_adminer_service:
|
||||
image: adminer:latest
|
||||
restart: always
|
||||
depends_on:
|
||||
kar_db_service:
|
||||
condition: service_healthy
|
||||
links:
|
||||
- kar_db_service:db
|
||||
- kar_mongodb_service:dbm
|
||||
ports:
|
||||
- 4079:8080
|
||||
mem_limit: 50m
|
||||
|
||||
mongo_express_service:
|
||||
image: mongo-express
|
||||
restart: always
|
||||
ports:
|
||||
- 4077:8081
|
||||
links:
|
||||
- kar_mongodb_service:db
|
||||
environment:
|
||||
ME_CONFIG_MONGODB_ADMINUSERNAME: root
|
||||
ME_CONFIG_MONGODB_ADMINPASSWORD: base_db_password
|
||||
ME_CONFIG_MONGODB_URL: mongodb://root:base_db_password@db:27017/
|
||||
ME_CONFIG_BASICAUTH: false
|
||||
|
@ -1,12 +0,0 @@
|
||||
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
|
||||
# For additional information regarding the format and rule options, please see:
|
||||
# https://github.com/browserslist/browserslist#queries
|
||||
|
||||
# You can see what browsers were selected by your queries by running:
|
||||
# npx browserslist
|
||||
|
||||
> 0.5%
|
||||
last 2 versions
|
||||
Firefox ESR
|
||||
not dead
|
||||
not IE 9-11 # For IE 9-11 support, remove 'not'.
|
@ -1,13 +0,0 @@
|
||||
# Editor configuration, see http://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
2
front/.env.production
Normal file
2
front/.env.production
Normal file
@ -0,0 +1,2 @@
|
||||
# URL for database connection
|
||||
VITE_API_BASE_URL=karusic/api/
|
@ -1,4 +0,0 @@
|
||||
node_modules/*
|
||||
build/*
|
||||
out/*
|
||||
dist/*
|
@ -1,225 +0,0 @@
|
||||
var OFF = 0, WARN = 1, ERROR = 2;
|
||||
|
||||
module.exports = {
|
||||
'env': {
|
||||
'browser': true,
|
||||
'es2021': true,
|
||||
},
|
||||
'extends': [
|
||||
'eslint:recommended',
|
||||
],
|
||||
'parser': '@typescript-eslint/parser',
|
||||
'parserOptions': {
|
||||
'ecmaVersion': 'latest',
|
||||
'sourceType': 'module',
|
||||
},
|
||||
'plugins': [
|
||||
'@typescript-eslint',
|
||||
],
|
||||
"rules": {
|
||||
// Possible Errors (overrides from recommended set)
|
||||
"no-extra-parens": ERROR,
|
||||
"no-unexpected-multiline": ERROR,
|
||||
// All JSDoc comments must be valid
|
||||
"valid-jsdoc": [ OFF, {
|
||||
"requireReturn": false,
|
||||
"requireReturnDescription": false,
|
||||
"requireParamDescription": true,
|
||||
"prefer": {
|
||||
"return": "returns"
|
||||
}
|
||||
}],
|
||||
|
||||
// Best Practices
|
||||
|
||||
// Allowed a getter without setter, but all setters require getters
|
||||
"accessor-pairs": [ OFF, {
|
||||
"getWithoutSet": false,
|
||||
"setWithoutGet": true
|
||||
}],
|
||||
"block-scoped-var": WARN,
|
||||
"consistent-return": OFF,
|
||||
"curly": ERROR,
|
||||
"default-case": WARN,
|
||||
// the dot goes with the property when doing multiline
|
||||
"dot-location": [ WARN, "property" ],
|
||||
"dot-notation": WARN,
|
||||
"eqeqeq": [ ERROR, "smart" ],
|
||||
"guard-for-in": WARN,
|
||||
"no-alert": ERROR,
|
||||
"no-caller": ERROR,
|
||||
"no-case-declarations": WARN,
|
||||
"no-div-regex": WARN,
|
||||
"no-else-return": WARN,
|
||||
"no-empty-pattern": WARN,
|
||||
"no-eq-null": ERROR,
|
||||
"no-eval": ERROR,
|
||||
"no-extend-native": ERROR,
|
||||
"no-extra-bind": WARN,
|
||||
"no-floating-decimal": WARN,
|
||||
"no-implicit-coercion": [ WARN, {
|
||||
"boolean": true,
|
||||
"number": true,
|
||||
"string": true
|
||||
}],
|
||||
"no-implied-eval": ERROR,
|
||||
"no-invalid-this": ERROR,
|
||||
"no-iterator": ERROR,
|
||||
"no-labels": WARN,
|
||||
"no-lone-blocks": WARN,
|
||||
"no-loop-func": ERROR,
|
||||
"no-magic-numbers": OFF,
|
||||
"no-multi-spaces": ERROR,
|
||||
"no-multi-str": WARN,
|
||||
"no-native-reassign": ERROR,
|
||||
"no-new-func": ERROR,
|
||||
"no-new-wrappers": ERROR,
|
||||
"no-new": ERROR,
|
||||
"no-octal-escape": ERROR,
|
||||
"no-param-reassign": ERROR,
|
||||
"no-process-env": WARN,
|
||||
"no-proto": ERROR,
|
||||
"no-redeclare": ERROR,
|
||||
"no-return-assign": ERROR,
|
||||
"no-script-url": ERROR,
|
||||
"no-self-compare": ERROR,
|
||||
"no-throw-literal": ERROR,
|
||||
"no-unused-expressions": ERROR,
|
||||
"no-useless-call": ERROR,
|
||||
"no-useless-concat": ERROR,
|
||||
"no-void": WARN,
|
||||
// Produce warnings when something is commented as TODO or FIXME
|
||||
"no-warning-comments": [ WARN, {
|
||||
"terms": [ "TODO", "FIXME" ],
|
||||
"location": "start"
|
||||
}],
|
||||
"no-with": WARN,
|
||||
"radix": WARN,
|
||||
"vars-on-top": ERROR,
|
||||
// Enforces the style of wrapped functions
|
||||
"wrap-iife": [ ERROR, "outside" ],
|
||||
"yoda": ERROR,
|
||||
|
||||
// Strict Mode - for ES6, never use strict.
|
||||
"strict": [ ERROR, "never" ],
|
||||
|
||||
// Variables
|
||||
"init-declarations": [ OFF, "always" ],
|
||||
"no-catch-shadow": WARN,
|
||||
"no-delete-var": ERROR,
|
||||
"no-label-var": ERROR,
|
||||
"no-shadow-restricted-names": ERROR,
|
||||
"no-shadow": WARN,
|
||||
// We require all vars to be initialized (see init-declarations)
|
||||
// If we NEED a var to be initialized to undefined, it needs to be explicit
|
||||
"no-undef-init": OFF,
|
||||
"no-undef": ERROR,
|
||||
"no-undefined": OFF,
|
||||
"no-unused-vars": OFF,
|
||||
// Disallow hoisting - let & const don't allow hoisting anyhow
|
||||
"no-use-before-define": ERROR,
|
||||
|
||||
// Node.js and CommonJS
|
||||
"callback-return": [ WARN, [ "callback", "next" ]],
|
||||
"global-require": ERROR,
|
||||
"handle-callback-err": WARN,
|
||||
"no-mixed-requires": WARN,
|
||||
"no-new-require": ERROR,
|
||||
// Use path.concat instead
|
||||
"no-path-concat": ERROR,
|
||||
"no-process-exit": ERROR,
|
||||
"no-restricted-modules": OFF,
|
||||
"no-sync": WARN,
|
||||
|
||||
// ECMAScript 6 support
|
||||
"arrow-body-style": [ ERROR, "always" ],
|
||||
"arrow-parens": [ ERROR, "always" ],
|
||||
"arrow-spacing": [ ERROR, { "before": true, "after": true }],
|
||||
"constructor-super": ERROR,
|
||||
"generator-star-spacing": [ ERROR, "before" ],
|
||||
"no-confusing-arrow": ERROR,
|
||||
"no-class-assign": ERROR,
|
||||
"no-const-assign": ERROR,
|
||||
"no-dupe-class-members": ERROR,
|
||||
"no-this-before-super": ERROR,
|
||||
"no-var": WARN,
|
||||
"object-shorthand": [ WARN, "never" ],
|
||||
"prefer-arrow-callback": WARN,
|
||||
"prefer-spread": WARN,
|
||||
"prefer-template": WARN,
|
||||
"require-yield": ERROR,
|
||||
|
||||
// Stylistic - everything here is a warning because of style.
|
||||
"array-bracket-spacing": [ WARN, "always" ],
|
||||
"block-spacing": [ WARN, "always" ],
|
||||
"brace-style": [ WARN, "1tbs", { "allowSingleLine": false } ],
|
||||
"camelcase": WARN,
|
||||
"comma-spacing": [ WARN, { "before": false, "after": true } ],
|
||||
"comma-style": [ WARN, "last" ],
|
||||
"computed-property-spacing": [ WARN, "never" ],
|
||||
"consistent-this": [ WARN, "self" ],
|
||||
"eol-last": WARN,
|
||||
"func-names": WARN,
|
||||
"func-style": [ WARN, "declaration" ],
|
||||
"id-length": [ WARN, { "min": 2, "max": 32 } ],
|
||||
"indent": [ WARN, 'tab' ],
|
||||
"jsx-quotes": [ WARN, "prefer-double" ],
|
||||
"linebreak-style": [ WARN, "unix" ],
|
||||
"lines-around-comment": [ OFF, { "beforeBlockComment": true } ],
|
||||
"max-depth": [ WARN, 8 ],
|
||||
"max-len": [ WARN, 182 ],
|
||||
"max-nested-callbacks": [ WARN, 8 ],
|
||||
"max-params": [ WARN, 10 ],
|
||||
"new-cap": OFF,
|
||||
"new-parens": WARN,
|
||||
"no-array-constructor": WARN,
|
||||
"no-bitwise": OFF,
|
||||
"no-continue": OFF,
|
||||
"no-inline-comments": OFF,
|
||||
"no-lonely-if": OFF,
|
||||
"no-mixed-spaces-and-tabs": OFF,
|
||||
"no-multiple-empty-lines": WARN,
|
||||
"no-negated-condition": OFF,
|
||||
"no-nested-ternary": WARN,
|
||||
"no-new-object": WARN,
|
||||
"no-plusplus": OFF,
|
||||
"no-spaced-func": WARN,
|
||||
"no-ternary": OFF,
|
||||
"no-trailing-spaces": WARN,
|
||||
"no-underscore-dangle": WARN,
|
||||
"no-unneeded-ternary": WARN,
|
||||
"object-curly-spacing": [ WARN, "always" ],
|
||||
"one-var": OFF,
|
||||
"operator-assignment": [ WARN, "never" ],
|
||||
"operator-linebreak": [ WARN, "after" ],
|
||||
"padded-blocks": [ WARN, "never" ],
|
||||
"quote-props": [ WARN, "consistent-as-needed" ],
|
||||
"quotes": [ WARN, "single" ],
|
||||
"require-jsdoc": [ OFF, {
|
||||
"require": {
|
||||
"FunctionDeclaration": true,
|
||||
"MethodDefinition": true,
|
||||
"ClassDeclaration": false
|
||||
}
|
||||
}],
|
||||
"semi-spacing": [ WARN, { "before": false, "after": true }],
|
||||
"semi": [ ERROR, "always" ],
|
||||
"sort-vars": OFF,
|
||||
"keyword-spacing": [WARN, {
|
||||
"overrides": {
|
||||
"if": { "after": false },
|
||||
"for": { "after": false },
|
||||
"while": { "after": false },
|
||||
"static": { "after": false },
|
||||
"as": { "after": false }
|
||||
}
|
||||
}],
|
||||
"space-before-blocks": [ WARN, "always" ],
|
||||
"space-before-function-paren": [ WARN, "never" ],
|
||||
"space-in-parens": [ WARN, "never" ],
|
||||
"space-infix-ops": [ WARN, { "int32Hint": true } ],
|
||||
"space-unary-ops": ERROR,
|
||||
"spaced-comment": [ WARN, "always" ],
|
||||
"wrap-regex": WARN,
|
||||
},
|
||||
};
|
3
front/.gitignore
vendored
3
front/.gitignore
vendored
@ -1,3 +0,0 @@
|
||||
/node_modules/
|
||||
/.angular/
|
||||
/.idea/
|
27
front/.storybook/main.ts
Normal file
27
front/.storybook/main.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import type { StorybookConfig } from '@storybook/react-vite';
|
||||
|
||||
const config: StorybookConfig = {
|
||||
framework: {
|
||||
name: '@storybook/react-vite',
|
||||
options: {},
|
||||
},
|
||||
|
||||
core: {
|
||||
disableTelemetry: true,
|
||||
builder: '@storybook/builder-vite',
|
||||
},
|
||||
|
||||
stories: ['../src/**/*.@(mdx|stories.@(js|jsx|ts|tsx))'],
|
||||
|
||||
addons: ['@storybook/addon-links', '@storybook/addon-essentials'],
|
||||
|
||||
staticDirs: ['../public'],
|
||||
|
||||
typescript: {
|
||||
reactDocgen: false,
|
||||
},
|
||||
|
||||
docs: {},
|
||||
};
|
||||
|
||||
export default config;
|
16
front/.storybook/preview-head.html
Normal file
16
front/.storybook/preview-head.html
Normal file
@ -0,0 +1,16 @@
|
||||
<style>
|
||||
html {
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
.docs-story > :first-child {
|
||||
padding: 0;
|
||||
}
|
||||
.docs-story > * {
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
#root #start-ui-storybook-wrapper {
|
||||
min-height: 100vh;
|
||||
}
|
||||
</style>
|
43
front/.storybook/preview.tsx
Normal file
43
front/.storybook/preview.tsx
Normal file
@ -0,0 +1,43 @@
|
||||
import React from 'react';
|
||||
|
||||
import { Box } from '@chakra-ui/react';
|
||||
import { ChakraProvider } from '@chakra-ui/react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
|
||||
import theme from '../src/theme';
|
||||
|
||||
// .storybook/preview.js
|
||||
export const parameters = {
|
||||
options: {
|
||||
storySort: {
|
||||
order: ['StyleGuide', 'Components', 'Fields', 'App Layout'],
|
||||
},
|
||||
},
|
||||
actions: {},
|
||||
layout: 'fullscreen',
|
||||
backgrounds: { disable: true, grid: { disable: true } },
|
||||
chakra: {
|
||||
theme,
|
||||
},
|
||||
};
|
||||
|
||||
const DocumentationWrapper = ({ children }) => {
|
||||
return (
|
||||
<Box id="start-ui-storybook-wrapper" p="4" pb="8" flex="1">
|
||||
{children}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export const decorators = [
|
||||
(Story, context) => (
|
||||
<ChakraProvider theme={theme}>
|
||||
{/* Using MemoryRouter to avoid route clashing with Storybook */}
|
||||
<MemoryRouter>
|
||||
<DocumentationWrapper>
|
||||
<Story {...context} />
|
||||
</DocumentationWrapper>
|
||||
</MemoryRouter>
|
||||
</ChakraProvider>
|
||||
),
|
||||
];
|
@ -1,33 +0,0 @@
|
||||
# base image
|
||||
FROM node:lts as build
|
||||
|
||||
# add `/application/node_modules/.bin` to $PATH
|
||||
ENV PATH /application/node_modules/.bin:$PATH
|
||||
|
||||
ADD package-lock.json /application/
|
||||
ADD package.json /application/
|
||||
#ADD browserslist /application/
|
||||
ADD karma.conf.js /application/
|
||||
ADD protractor.conf.js /application/
|
||||
WORKDIR /application/
|
||||
|
||||
# install and cache app dependencies
|
||||
RUN npm install
|
||||
|
||||
ADD e2e /application/e2e
|
||||
ADD tsconfig.json tslint.json angular.json ./
|
||||
ADD src /application/src
|
||||
|
||||
# generate build
|
||||
RUN ng build --output-path=dist --configuration=production --base-href=/karideo/ --deploy-url=/karideo/
|
||||
|
||||
############
|
||||
### prod ###
|
||||
############
|
||||
|
||||
# base image
|
||||
FROM httpd:latest
|
||||
|
||||
# copy artifact build from the 'build environment'
|
||||
COPY --from=build /application/dist /usr/local/apache2/htdocs/
|
||||
COPY httpd/httpd.conf /usr/local/apache2/conf/httpd.conf
|
@ -1,24 +0,0 @@
|
||||
# base image
|
||||
FROM node:latest
|
||||
|
||||
ADD src /application/src
|
||||
ADD e2e /application/e2e
|
||||
ADD package-lock.json /application/
|
||||
ADD package.json /application/
|
||||
ADD angular.json /application/
|
||||
ADD browserslist /application/
|
||||
ADD karma.conf.js /application/
|
||||
ADD protractor.conf.js /application/
|
||||
ADD tsconfig.json /application/
|
||||
ADD tslint.json /application/
|
||||
WORKDIR /application/
|
||||
|
||||
# add `/app/node_modules/.bin` to $PATH
|
||||
ENV PATH /app/node_modules/.bin:$PATH
|
||||
|
||||
# install and cache app dependencies
|
||||
RUN npm install
|
||||
|
||||
# start app
|
||||
CMD ["npx", "ng", "serve", "--host", "0.0.0.0"]
|
||||
|
2
front/LICENSE
Normal file
2
front/LICENSE
Normal file
@ -0,0 +1,2 @@
|
||||
Proprietary
|
||||
@copyright Edouard Dupin 2024
|
@ -1,172 +0,0 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"karusic": {
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"projectType": "application",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"outputPath": "dist",
|
||||
"index": "src/index.html",
|
||||
"main": "src/main.ts",
|
||||
"tsConfig": "src/tsconfig.app.json",
|
||||
"preserveSymlinks": true,
|
||||
"polyfills": [
|
||||
"zone.js"
|
||||
],
|
||||
"assets": [
|
||||
"src/assets",
|
||||
"src/favicon.ico"
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.less",
|
||||
"src/generic_page.less",
|
||||
"src/theme.color.blue.less",
|
||||
"src/theme.checkbox.less",
|
||||
"src/theme.modal.less"
|
||||
],
|
||||
"scripts": []
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"optimization": true,
|
||||
"outputHashing": "all",
|
||||
"sourceMap": false,
|
||||
"namedChunks": false,
|
||||
"aot": true,
|
||||
"extractLicenses": true,
|
||||
"vendorChunk": false,
|
||||
"buildOptimizer": true,
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
]
|
||||
},
|
||||
"develop": {
|
||||
"optimization": false,
|
||||
"outputHashing": "none",
|
||||
"namedChunks": true,
|
||||
"aot": false,
|
||||
"extractLicenses": true,
|
||||
"vendorChunk": true,
|
||||
"buildOptimizer": false,
|
||||
"sourceMap": {
|
||||
"scripts": true,
|
||||
"styles": true,
|
||||
"hidden": false,
|
||||
"vendor": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"options": {
|
||||
"buildTarget": "karusic:build"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"buildTarget": "karusic:build:production"
|
||||
},
|
||||
"develop": {
|
||||
"buildTarget": "karusic:build:develop"
|
||||
}
|
||||
}
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"buildTarget": "karusic:build"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "src/test.ts",
|
||||
"karmaConfig": "./karma.conf.js",
|
||||
"polyfills": [
|
||||
"zone.js"
|
||||
],
|
||||
"tsConfig": "src/tsconfig.spec.json",
|
||||
"scripts": [],
|
||||
"styles": [
|
||||
"src/styles.less",
|
||||
"src/generic_page.less",
|
||||
"src/theme.color.blue.less",
|
||||
"src/theme.checkbox.less",
|
||||
"src/theme.modal.less"
|
||||
],
|
||||
"assets": [
|
||||
"src/assets",
|
||||
"src/favicon.ico"
|
||||
]
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-eslint/builder:lint",
|
||||
"options": {
|
||||
"fix": true,
|
||||
"eslintConfig": ".eslintrc.js",
|
||||
"lintFilePatterns": [
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.ts"
|
||||
]
|
||||
}
|
||||
},
|
||||
"TTTTTTlint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"src/tsconfig.app.json",
|
||||
"src/tsconfig.spec.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"karusic-e2e": {
|
||||
"root": "e2e",
|
||||
"sourceRoot": "e2e",
|
||||
"projectType": "application",
|
||||
"architect": {
|
||||
"e2e": {
|
||||
"builder": "@angular-devkit/build-angular:protractor",
|
||||
"options": {
|
||||
"protractorConfig": "./protractor.conf.js",
|
||||
"devServerTarget": "karusic:serve"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"e2e/tsconfig.e2e.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"schematics": {
|
||||
"@schematics/angular:component": {
|
||||
"prefix": "app",
|
||||
"style": "less"
|
||||
},
|
||||
"@schematics/angular:directive": {
|
||||
"prefix": "app"
|
||||
}
|
||||
}
|
||||
}
|
6
front/app-build.json
Normal file
6
front/app-build.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"display": "__DEVELOPMENT__",
|
||||
"version": "__VERSION__",
|
||||
"commit": "__COMMIT__",
|
||||
"date": "__DATE__"
|
||||
}
|
25
front/build.js
Normal file
25
front/build.js
Normal file
@ -0,0 +1,25 @@
|
||||
const dayjs = require('dayjs');
|
||||
|
||||
const fs = require('fs');
|
||||
|
||||
const generateAppBuild = () => {
|
||||
const getVersion = () => fs.readFileSync('version.txt', 'utf8');
|
||||
|
||||
const commit = process.env.VERCEL_GIT_COMMIT_SHA
|
||||
? process.env.VERCEL_GIT_COMMIT_SHA
|
||||
: getVersion();
|
||||
|
||||
const appBuildContent = {
|
||||
display: `${dayjs().format('YYYY-MM-DD')}`,
|
||||
version: `${commit} - ${dayjs().format()}`,
|
||||
commit,
|
||||
date: dayjs().format(),
|
||||
};
|
||||
|
||||
fs.writeFileSync(
|
||||
'./app-build.json',
|
||||
JSON.stringify(appBuildContent, null, 2)
|
||||
);
|
||||
};
|
||||
|
||||
generateAppBuild();
|
@ -1,11 +0,0 @@
|
||||
version: '3'
|
||||
services:
|
||||
karideo_service:
|
||||
build: .
|
||||
restart: always
|
||||
image: yui.heero/karideo
|
||||
container_name: karideo
|
||||
ports:
|
||||
#- 15081:4200
|
||||
- 15081:80
|
||||
|
@ -1,14 +0,0 @@
|
||||
import { AppPage } from './app.po';
|
||||
|
||||
describe('karusic App', () => {
|
||||
let page: AppPage;
|
||||
|
||||
beforeEach(() => {
|
||||
page = new AppPage();
|
||||
});
|
||||
|
||||
it('should display welcome message', () => {
|
||||
page.navigateTo();
|
||||
expect(page.getParagraphText()).toEqual('Welcome to app!');
|
||||
});
|
||||
});
|
@ -1,11 +0,0 @@
|
||||
import { browser, by, element } from 'protractor';
|
||||
|
||||
export class AppPage {
|
||||
navigateTo() {
|
||||
return browser.get('/');
|
||||
}
|
||||
|
||||
getParagraphText() {
|
||||
return element(by.css('app-root h1')).getText();
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/e2e",
|
||||
"baseUrl": "./",
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"jasminewd2",
|
||||
"node"
|
||||
]
|
||||
}
|
||||
}
|
@ -1,541 +0,0 @@
|
||||
#
|
||||
# This is the main Apache HTTP server configuration file. It contains the
|
||||
# configuration directives that give the server its instructions.
|
||||
# See <URL:http://httpd.apache.org/docs/2.4/> for detailed information.
|
||||
# In particular, see
|
||||
# <URL:http://httpd.apache.org/docs/2.4/mod/directives.html>
|
||||
# for a discussion of each configuration directive.
|
||||
#
|
||||
# Do NOT simply read the instructions in here without understanding
|
||||
# what they do. They're here only as hints or reminders. If you are unsure
|
||||
# consult the online docs. You have been warned.
|
||||
#
|
||||
# Configuration and logfile names: If the filenames you specify for many
|
||||
# of the server's control files begin with "/" (or "drive:/" for Win32), the
|
||||
# server will use that explicit path. If the filenames do *not* begin
|
||||
# with "/", the value of ServerRoot is prepended -- so "logs/access_log"
|
||||
# with ServerRoot set to "/usr/local/apache2" will be interpreted by the
|
||||
# server as "/usr/local/apache2/logs/access_log", whereas "/logs/access_log"
|
||||
# will be interpreted as '/logs/access_log'.
|
||||
|
||||
#
|
||||
# ServerRoot: The top of the directory tree under which the server's
|
||||
# configuration, error, and log files are kept.
|
||||
#
|
||||
# Do not add a slash at the end of the directory path. If you point
|
||||
# ServerRoot at a non-local disk, be sure to specify a local disk on the
|
||||
# Mutex directive, if file-based mutexes are used. If you wish to share the
|
||||
# same ServerRoot for multiple httpd daemons, you will need to change at
|
||||
# least PidFile.
|
||||
#
|
||||
ServerRoot "/usr/local/apache2"
|
||||
|
||||
#
|
||||
# Mutex: Allows you to set the mutex mechanism and mutex file directory
|
||||
# for individual mutexes, or change the global defaults
|
||||
#
|
||||
# Uncomment and change the directory if mutexes are file-based and the default
|
||||
# mutex file directory is not on a local disk or is not appropriate for some
|
||||
# other reason.
|
||||
#
|
||||
# Mutex default:logs
|
||||
|
||||
#
|
||||
# Listen: Allows you to bind Apache to specific IP addresses and/or
|
||||
# ports, instead of the default. See also the <VirtualHost>
|
||||
# directive.
|
||||
#
|
||||
# Change this to Listen on specific IP addresses as shown below to
|
||||
# prevent Apache from glomming onto all bound IP addresses.
|
||||
#
|
||||
Listen 80
|
||||
Listen 443
|
||||
|
||||
#
|
||||
# Dynamic Shared Object (DSO) Support
|
||||
#
|
||||
# To be able to use the functionality of a module which was built as a DSO you
|
||||
# have to place corresponding `LoadModule' lines at this location so the
|
||||
# directives contained in it are actually available _before_ they are used.
|
||||
# Statically compiled modules (those listed by `httpd -l') do not need
|
||||
# to be loaded here.
|
||||
#
|
||||
# Example:
|
||||
# LoadModule foo_module modules/mod_foo.so
|
||||
#
|
||||
LoadModule mpm_event_module modules/mod_mpm_event.so
|
||||
#LoadModule mpm_prefork_module modules/mod_mpm_prefork.so
|
||||
#LoadModule mpm_worker_module modules/mod_mpm_worker.so
|
||||
LoadModule authn_file_module modules/mod_authn_file.so
|
||||
#LoadModule authn_dbm_module modules/mod_authn_dbm.so
|
||||
#LoadModule authn_anon_module modules/mod_authn_anon.so
|
||||
#LoadModule authn_dbd_module modules/mod_authn_dbd.so
|
||||
#LoadModule authn_socache_module modules/mod_authn_socache.so
|
||||
LoadModule authn_core_module modules/mod_authn_core.so
|
||||
LoadModule authz_host_module modules/mod_authz_host.so
|
||||
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
|
||||
LoadModule authz_user_module modules/mod_authz_user.so
|
||||
#LoadModule authz_dbm_module modules/mod_authz_dbm.so
|
||||
#LoadModule authz_owner_module modules/mod_authz_owner.so
|
||||
#LoadModule authz_dbd_module modules/mod_authz_dbd.so
|
||||
LoadModule authz_core_module modules/mod_authz_core.so
|
||||
#LoadModule authnz_ldap_module modules/mod_authnz_ldap.so
|
||||
#LoadModule authnz_fcgi_module modules/mod_authnz_fcgi.so
|
||||
LoadModule access_compat_module modules/mod_access_compat.so
|
||||
LoadModule auth_basic_module modules/mod_auth_basic.so
|
||||
#LoadModule auth_form_module modules/mod_auth_form.so
|
||||
#LoadModule auth_digest_module modules/mod_auth_digest.so
|
||||
#LoadModule allowmethods_module modules/mod_allowmethods.so
|
||||
#LoadModule isapi_module modules/mod_isapi.so
|
||||
#LoadModule file_cache_module modules/mod_file_cache.so
|
||||
#LoadModule cache_module modules/mod_cache.so
|
||||
#LoadModule cache_disk_module modules/mod_cache_disk.so
|
||||
#LoadModule cache_socache_module modules/mod_cache_socache.so
|
||||
#LoadModule socache_shmcb_module modules/mod_socache_shmcb.so
|
||||
#LoadModule socache_dbm_module modules/mod_socache_dbm.so
|
||||
#LoadModule socache_memcache_module modules/mod_socache_memcache.so
|
||||
#LoadModule watchdog_module modules/mod_watchdog.so
|
||||
#LoadModule macro_module modules/mod_macro.so
|
||||
#LoadModule dbd_module modules/mod_dbd.so
|
||||
#LoadModule bucketeer_module modules/mod_bucketeer.so
|
||||
#LoadModule dumpio_module modules/mod_dumpio.so
|
||||
#LoadModule echo_module modules/mod_echo.so
|
||||
#LoadModule example_hooks_module modules/mod_example_hooks.so
|
||||
#LoadModule case_filter_module modules/mod_case_filter.so
|
||||
#LoadModule case_filter_in_module modules/mod_case_filter_in.so
|
||||
#LoadModule example_ipc_module modules/mod_example_ipc.so
|
||||
#LoadModule buffer_module modules/mod_buffer.so
|
||||
#LoadModule data_module modules/mod_data.so
|
||||
#LoadModule ratelimit_module modules/mod_ratelimit.so
|
||||
LoadModule reqtimeout_module modules/mod_reqtimeout.so
|
||||
#LoadModule ext_filter_module modules/mod_ext_filter.so
|
||||
#LoadModule request_module modules/mod_request.so
|
||||
#LoadModule include_module modules/mod_include.so
|
||||
LoadModule filter_module modules/mod_filter.so
|
||||
#LoadModule reflector_module modules/mod_reflector.so
|
||||
#LoadModule substitute_module modules/mod_substitute.so
|
||||
#LoadModule sed_module modules/mod_sed.so
|
||||
#LoadModule charset_lite_module modules/mod_charset_lite.so
|
||||
#LoadModule deflate_module modules/mod_deflate.so
|
||||
LoadModule xml2enc_module modules/mod_xml2enc.so
|
||||
LoadModule proxy_html_module modules/mod_proxy_html.so
|
||||
LoadModule mime_module modules/mod_mime.so
|
||||
#LoadModule ldap_module modules/mod_ldap.so
|
||||
LoadModule log_config_module modules/mod_log_config.so
|
||||
#LoadModule log_debug_module modules/mod_log_debug.so
|
||||
#LoadModule log_forensic_module modules/mod_log_forensic.so
|
||||
#LoadModule logio_module modules/mod_logio.so
|
||||
#LoadModule lua_module modules/mod_lua.so
|
||||
LoadModule env_module modules/mod_env.so
|
||||
#LoadModule mime_magic_module modules/mod_mime_magic.so
|
||||
#LoadModule cern_meta_module modules/mod_cern_meta.so
|
||||
#LoadModule expires_module modules/mod_expires.so
|
||||
LoadModule headers_module modules/mod_headers.so
|
||||
#LoadModule ident_module modules/mod_ident.so
|
||||
#LoadModule usertrack_module modules/mod_usertrack.so
|
||||
#LoadModule unique_id_module modules/mod_unique_id.so
|
||||
LoadModule setenvif_module modules/mod_setenvif.so
|
||||
LoadModule version_module modules/mod_version.so
|
||||
#LoadModule remoteip_module modules/mod_remoteip.so
|
||||
LoadModule proxy_module modules/mod_proxy.so
|
||||
#LoadModule proxy_connect_module modules/mod_proxy_connect.so
|
||||
#LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
|
||||
LoadModule proxy_http_module modules/mod_proxy_http.so
|
||||
#LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so
|
||||
#LoadModule proxy_scgi_module modules/mod_proxy_scgi.so
|
||||
#LoadModule proxy_uwsgi_module modules/mod_proxy_uwsgi.so
|
||||
#LoadModule proxy_fdpass_module modules/mod_proxy_fdpass.so
|
||||
#LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
|
||||
#LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
|
||||
#LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
|
||||
#LoadModule proxy_express_module modules/mod_proxy_express.so
|
||||
#LoadModule proxy_hcheck_module modules/mod_proxy_hcheck.so
|
||||
#LoadModule session_module modules/mod_session.so
|
||||
#LoadModule session_cookie_module modules/mod_session_cookie.so
|
||||
#LoadModule session_crypto_module modules/mod_session_crypto.so
|
||||
#LoadModule session_dbd_module modules/mod_session_dbd.so
|
||||
#LoadModule slotmem_shm_module modules/mod_slotmem_shm.so
|
||||
#LoadModule slotmem_plain_module modules/mod_slotmem_plain.so
|
||||
LoadModule ssl_module modules/mod_ssl.so
|
||||
#LoadModule optional_hook_export_module modules/mod_optional_hook_export.so
|
||||
#LoadModule optional_hook_import_module modules/mod_optional_hook_import.so
|
||||
#LoadModule optional_fn_import_module modules/mod_optional_fn_import.so
|
||||
#LoadModule optional_fn_export_module modules/mod_optional_fn_export.so
|
||||
#LoadModule dialup_module modules/mod_dialup.so
|
||||
#LoadModule http2_module modules/mod_http2.so
|
||||
#LoadModule proxy_http2_module modules/mod_proxy_http2.so
|
||||
#LoadModule lbmethod_byrequests_module modules/mod_lbmethod_byrequests.so
|
||||
#LoadModule lbmethod_bytraffic_module modules/mod_lbmethod_bytraffic.so
|
||||
#LoadModule lbmethod_bybusyness_module modules/mod_lbmethod_bybusyness.so
|
||||
#LoadModule lbmethod_heartbeat_module modules/mod_lbmethod_heartbeat.so
|
||||
LoadModule unixd_module modules/mod_unixd.so
|
||||
#LoadModule heartbeat_module modules/mod_heartbeat.so
|
||||
#LoadModule heartmonitor_module modules/mod_heartmonitor.so
|
||||
#LoadModule dav_module modules/mod_dav.so
|
||||
LoadModule status_module modules/mod_status.so
|
||||
LoadModule autoindex_module modules/mod_autoindex.so
|
||||
#LoadModule asis_module modules/mod_asis.so
|
||||
#LoadModule info_module modules/mod_info.so
|
||||
#LoadModule suexec_module modules/mod_suexec.so
|
||||
<IfModule !mpm_prefork_module>
|
||||
#LoadModule cgid_module modules/mod_cgid.so
|
||||
</IfModule>
|
||||
<IfModule mpm_prefork_module>
|
||||
#LoadModule cgi_module modules/mod_cgi.so
|
||||
</IfModule>
|
||||
#LoadModule dav_fs_module modules/mod_dav_fs.so
|
||||
#LoadModule dav_lock_module modules/mod_dav_lock.so
|
||||
#LoadModule vhost_alias_module modules/mod_vhost_alias.so
|
||||
#LoadModule negotiation_module modules/mod_negotiation.so
|
||||
LoadModule dir_module modules/mod_dir.so
|
||||
#LoadModule imagemap_module modules/mod_imagemap.so
|
||||
#LoadModule actions_module modules/mod_actions.so
|
||||
#LoadModule speling_module modules/mod_speling.so
|
||||
#LoadModule userdir_module modules/mod_userdir.so
|
||||
LoadModule alias_module modules/mod_alias.so
|
||||
LoadModule rewrite_module modules/mod_rewrite.so
|
||||
|
||||
<IfModule unixd_module>
|
||||
#
|
||||
# If you wish httpd to run as a different user or group, you must run
|
||||
# httpd as root initially and it will switch.
|
||||
#
|
||||
# User/Group: The name (or #number) of the user/group to run httpd as.
|
||||
# It is usually good practice to create a dedicated user and group for
|
||||
# running httpd, as with most system services.
|
||||
#
|
||||
User daemon
|
||||
Group daemon
|
||||
|
||||
</IfModule>
|
||||
|
||||
# 'Main' server configuration
|
||||
#
|
||||
# The directives in this section set up the values used by the 'main'
|
||||
# server, which responds to any requests that aren't handled by a
|
||||
# <VirtualHost> definition. These values also provide defaults for
|
||||
# any <VirtualHost> containers you may define later in the file.
|
||||
#
|
||||
# All of these directives may appear inside <VirtualHost> containers,
|
||||
# in which case these default settings will be overridden for the
|
||||
# virtual host being defined.
|
||||
#
|
||||
|
||||
#
|
||||
# ServerAdmin: Your address, where problems with the server should be
|
||||
# e-mailed. This address appears on some server-generated pages, such
|
||||
# as error documents. e.g. admin@your-domain.com
|
||||
#
|
||||
ServerAdmin yui.heero@gmail.com
|
||||
|
||||
#
|
||||
# ServerName gives the name and port that the server uses to identify itself.
|
||||
# This can often be determined automatically, but we recommend you specify
|
||||
# it explicitly to prevent problems during startup.
|
||||
#
|
||||
# If your host doesn't have a registered DNS name, enter its IP address here.
|
||||
#
|
||||
#ServerName www.example.com:80
|
||||
|
||||
#
|
||||
# Deny access to the entirety of your server's filesystem. You must
|
||||
# explicitly permit access to web content directories in other
|
||||
# <Directory> blocks below.
|
||||
#
|
||||
<Directory />
|
||||
AllowOverride none
|
||||
Require all denied
|
||||
</Directory>
|
||||
|
||||
# intermediate configuration, tweak to your needs
|
||||
SSLProtocol all -SSLv2 -SSLv3
|
||||
SSLCipherSuite ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS
|
||||
SSLHonorCipherOrder on
|
||||
|
||||
#
|
||||
# Note that from this point forward you must specifically allow
|
||||
# particular features to be enabled - so if something's not working as
|
||||
# you might expect, make sure that you have specifically enabled it
|
||||
# below.
|
||||
#
|
||||
|
||||
#
|
||||
# DocumentRoot: The directory out of which you will serve your
|
||||
# documents. By default, all requests are taken from this directory, but
|
||||
# symbolic links and aliases may be used to point to other locations.
|
||||
#
|
||||
<VirtualHost *:80>
|
||||
ServerName my-app
|
||||
DocumentRoot "/usr/local/apache2/htdocs"
|
||||
<Directory "/usr/local/apache2/htdocs">
|
||||
Options Indexes FollowSymLinks
|
||||
AllowOverride None
|
||||
Require all granted
|
||||
RewriteEngine on
|
||||
# Don't rewrite files or directories
|
||||
RewriteCond %{REQUEST_FILENAME} -f [OR]
|
||||
RewriteCond %{REQUEST_FILENAME} -d
|
||||
RewriteRule ^ - [L]
|
||||
# Rewrite everything else to index.html to allow HTML5 state links
|
||||
RewriteRule ^ index.html [L]
|
||||
</Directory>
|
||||
</VirtualHost>
|
||||
#
|
||||
# DirectoryIndex: sets the file that Apache will serve if a directory
|
||||
# is requested.
|
||||
#
|
||||
<IfModule dir_module>
|
||||
DirectoryIndex index.html
|
||||
</IfModule>
|
||||
|
||||
#
|
||||
# The following lines prevent .htaccess and .htpasswd files from being
|
||||
# viewed by Web clients.
|
||||
#
|
||||
<Files ".ht*">
|
||||
Require all denied
|
||||
</Files>
|
||||
|
||||
#
|
||||
# ErrorLog: The location of the error log file.
|
||||
# If you do not specify an ErrorLog directive within a <VirtualHost>
|
||||
# container, error messages relating to that virtual host will be
|
||||
# logged here. If you *do* define an error logfile for a <VirtualHost>
|
||||
# container, that host's errors will be logged there and not here.
|
||||
#
|
||||
ErrorLog /proc/self/fd/2
|
||||
|
||||
#
|
||||
# LogLevel: Control the number of messages logged to the error_log.
|
||||
# Possible values include: debug, info, notice, warn, error, crit,
|
||||
# alert, emerg.
|
||||
#
|
||||
LogLevel warn
|
||||
|
||||
<IfModule log_config_module>
|
||||
#
|
||||
# The following directives define some format nicknames for use with
|
||||
# a CustomLog directive (see below).
|
||||
#
|
||||
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
|
||||
LogFormat "%h %l %u %t \"%r\" %>s %b" common
|
||||
|
||||
<IfModule logio_module>
|
||||
# You need to enable mod_logio.c to use %I and %O
|
||||
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
|
||||
</IfModule>
|
||||
|
||||
#
|
||||
# The location and format of the access logfile (Common Logfile Format).
|
||||
# If you do not define any access logfiles within a <VirtualHost>
|
||||
# container, they will be logged here. Contrariwise, if you *do*
|
||||
# define per-<VirtualHost> access logfiles, transactions will be
|
||||
# logged therein and *not* in this file.
|
||||
#
|
||||
CustomLog /proc/self/fd/1 common
|
||||
|
||||
#
|
||||
# If you prefer a logfile with access, agent, and referer information
|
||||
# (Combined Logfile Format) you can use the following directive.
|
||||
#
|
||||
#CustomLog "logs/access_log" combined
|
||||
</IfModule>
|
||||
|
||||
<IfModule alias_module>
|
||||
#
|
||||
# Redirect: Allows you to tell clients about documents that used to
|
||||
# exist in your server's namespace, but do not anymore. The client
|
||||
# will make a new request for the document at its new location.
|
||||
# Example:
|
||||
# Redirect permanent /foo http://www.example.com/bar
|
||||
|
||||
#
|
||||
# Alias: Maps web paths into filesystem paths and is used to
|
||||
# access content that does not live under the DocumentRoot.
|
||||
# Example:
|
||||
# Alias /webpath /full/filesystem/path
|
||||
#
|
||||
# If you include a trailing / on /webpath then the server will
|
||||
# require it to be present in the URL. You will also likely
|
||||
# need to provide a <Directory> section to allow access to
|
||||
# the filesystem path.
|
||||
|
||||
#
|
||||
# ScriptAlias: This controls which directories contain server scripts.
|
||||
# ScriptAliases are essentially the same as Aliases, except that
|
||||
# documents in the target directory are treated as applications and
|
||||
# run by the server when requested rather than as documents sent to the
|
||||
# client. The same rules about trailing "/" apply to ScriptAlias
|
||||
# directives as to Alias.
|
||||
#
|
||||
ScriptAlias /cgi-bin/ "/usr/local/apache2/cgi-bin/"
|
||||
|
||||
</IfModule>
|
||||
|
||||
<IfModule cgid_module>
|
||||
#
|
||||
# ScriptSock: On threaded servers, designate the path to the UNIX
|
||||
# socket used to communicate with the CGI daemon of mod_cgid.
|
||||
#
|
||||
#Scriptsock cgisock
|
||||
</IfModule>
|
||||
|
||||
#
|
||||
# "/usr/local/apache2/cgi-bin" should be changed to whatever your ScriptAliased
|
||||
# CGI directory exists, if you have that configured.
|
||||
#
|
||||
<Directory "/usr/local/apache2/cgi-bin">
|
||||
AllowOverride None
|
||||
Options None
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
<IfModule headers_module>
|
||||
#
|
||||
# Avoid passing HTTP_PROXY environment to CGI's on this or any proxied
|
||||
# backend servers which have lingering "httpoxy" defects.
|
||||
# 'Proxy' request header is undefined by the IETF, not listed by IANA
|
||||
#
|
||||
RequestHeader unset Proxy early
|
||||
</IfModule>
|
||||
|
||||
<IfModule mime_module>
|
||||
#
|
||||
# TypesConfig points to the file containing the list of mappings from
|
||||
# filename extension to MIME-type.
|
||||
#
|
||||
TypesConfig conf/mime.types
|
||||
|
||||
#
|
||||
# AddType allows you to add to or override the MIME configuration
|
||||
# file specified in TypesConfig for specific file types.
|
||||
#
|
||||
#AddType application/x-gzip .tgz
|
||||
#
|
||||
# AddEncoding allows you to have certain browsers uncompress
|
||||
# information on the fly. Note: Not all browsers support this.
|
||||
#
|
||||
#AddEncoding x-compress .Z
|
||||
#AddEncoding x-gzip .gz .tgz
|
||||
#
|
||||
# If the AddEncoding directives above are commented-out, then you
|
||||
# probably should define those extensions to indicate media types:
|
||||
#
|
||||
AddType application/x-compress .Z
|
||||
AddType application/x-gzip .gz .tgz
|
||||
|
||||
#
|
||||
# AddHandler allows you to map certain file extensions to "handlers":
|
||||
# actions unrelated to filetype. These can be either built into the server
|
||||
# or added with the Action directive (see below)
|
||||
#
|
||||
# To use CGI scripts outside of ScriptAliased directories:
|
||||
# (You will also need to add "ExecCGI" to the "Options" directive.)
|
||||
#
|
||||
#AddHandler cgi-script .cgi
|
||||
|
||||
# For type maps (negotiated resources):
|
||||
#AddHandler type-map var
|
||||
|
||||
#
|
||||
# Filters allow you to process content before it is sent to the client.
|
||||
#
|
||||
# To parse .shtml files for server-side includes (SSI):
|
||||
# (You will also need to add "Includes" to the "Options" directive.)
|
||||
#
|
||||
#AddType text/html .shtml
|
||||
#AddOutputFilter INCLUDES .shtml
|
||||
</IfModule>
|
||||
|
||||
#
|
||||
# The mod_mime_magic module allows the server to use various hints from the
|
||||
# contents of the file itself to determine its type. The MIMEMagicFile
|
||||
# directive tells the module where the hint definitions are located.
|
||||
#
|
||||
#MIMEMagicFile conf/magic
|
||||
|
||||
#
|
||||
# Customizable error responses come in three flavors:
|
||||
# 1) plain text 2) local redirects 3) external redirects
|
||||
#
|
||||
# Some examples:
|
||||
#ErrorDocument 500 "The server made a boo boo."
|
||||
#ErrorDocument 404 /missing.html
|
||||
#ErrorDocument 404 "/cgi-bin/missing_handler.pl"
|
||||
#ErrorDocument 402 http://www.example.com/subscription_info.html
|
||||
#
|
||||
|
||||
#
|
||||
# MaxRanges: Maximum number of Ranges in a request before
|
||||
# returning the entire resource, or one of the special
|
||||
# values 'default', 'none' or 'unlimited'.
|
||||
# Default setting is to accept 200 Ranges.
|
||||
#MaxRanges unlimited
|
||||
|
||||
#
|
||||
# EnableMMAP and EnableSendfile: On systems that support it,
|
||||
# memory-mapping or the sendfile syscall may be used to deliver
|
||||
# files. This usually improves server performance, but must
|
||||
# be turned off when serving from networked-mounted
|
||||
# filesystems or if support for these functions is otherwise
|
||||
# broken on your system.
|
||||
# Defaults: EnableMMAP On, EnableSendfile Off
|
||||
#
|
||||
#EnableMMAP off
|
||||
#EnableSendfile on
|
||||
|
||||
# Supplemental configuration
|
||||
#
|
||||
# The configuration files in the conf/extra/ directory can be
|
||||
# included to add extra features or to modify the default configuration of
|
||||
# the server, or you may simply copy their contents here and change as
|
||||
# necessary.
|
||||
|
||||
# Server-pool management (MPM specific)
|
||||
#Include conf/extra/httpd-mpm.conf
|
||||
|
||||
# Multi-language error messages
|
||||
#Include conf/extra/httpd-multilang-errordoc.conf
|
||||
|
||||
# Fancy directory listings
|
||||
#Include conf/extra/httpd-autoindex.conf
|
||||
|
||||
# Language settings
|
||||
#Include conf/extra/httpd-languages.conf
|
||||
|
||||
# User home directories
|
||||
#Include conf/extra/httpd-userdir.conf
|
||||
|
||||
# Real-time info on requests and configuration
|
||||
#Include conf/extra/httpd-info.conf
|
||||
|
||||
# Virtual hosts
|
||||
#Include conf/extra/httpd-vhosts.conf
|
||||
|
||||
# Local access to the Apache HTTP Server Manual
|
||||
#Include conf/extra/httpd-manual.conf
|
||||
|
||||
# Distributed authoring and versioning (WebDAV)
|
||||
#Include conf/extra/httpd-dav.conf
|
||||
|
||||
# Various default settings
|
||||
#Include conf/extra/httpd-default.conf
|
||||
|
||||
|
||||
# Configure mod_proxy_html to understand HTML4/XHTML1
|
||||
<IfModule proxy_html_module>
|
||||
Include conf/extra/proxy-html.conf
|
||||
</IfModule>
|
||||
|
||||
# Secure (SSL/TLS) connections
|
||||
#Include conf/extra/httpd-ssl.conf
|
||||
#
|
||||
# Note: The following must must be present to support
|
||||
# starting without SSL on platforms with no /dev/random equivalent
|
||||
# but a statically compiled-in mod_ssl.
|
||||
#
|
||||
<IfModule ssl_module>
|
||||
SSLRandomSeed startup builtin
|
||||
SSLRandomSeed connect builtin
|
||||
</IfModule>
|
||||
|
13
front/index.html
Normal file
13
front/index.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Karusic</title>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
</head>
|
||||
<body style="width:100vw;height:100vh;min-width:100%;min-height:100%;">
|
||||
<div id="root" style="width:100%;height:100%;min-width:100%;min-height:100%;"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
@ -1,31 +0,0 @@
|
||||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage-istanbul-reporter'),
|
||||
require('@angular-devkit/build-angular/plugins/karma')
|
||||
],
|
||||
client:{
|
||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
dir: require('path').join(__dirname, 'coverage'), reports: [ 'html', 'lcovonly' ],
|
||||
fixWebpackSourcePaths: true
|
||||
},
|
||||
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false
|
||||
});
|
||||
};
|
18
front/knip.ts
Normal file
18
front/knip.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import type { KnipConfig } from 'knip';
|
||||
|
||||
const config: KnipConfig = {
|
||||
// Ignoring mostly shell binaries
|
||||
ignoreBinaries: ['export', 'sleep'],
|
||||
ignore: [
|
||||
// Related to tests
|
||||
'tests/**',
|
||||
'**.conf.js',
|
||||
'steps.d.ts',
|
||||
'steps_file.js',
|
||||
'env_ci/codecept.conf.js',
|
||||
// Generic components are useful.
|
||||
'src/components/**',
|
||||
],
|
||||
};
|
||||
|
||||
export default config;
|
@ -1,49 +1,111 @@
|
||||
{
|
||||
"name": "karusic",
|
||||
"version": "0.0.0",
|
||||
"license": "MPL-2",
|
||||
"scripts": {
|
||||
"all": "npm run build && pnpm run test",
|
||||
"ng": "ng",
|
||||
"dev": "ng serve --configuration=develop --watch --port 4203",
|
||||
"build": "ng build --prod",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"style": "prettier --write .",
|
||||
"e2e": "ng e2e",
|
||||
"update_packages": "ncu --upgrade",
|
||||
"install_dependency": "pnpm install --force",
|
||||
"link_kar_cw": "pnpm link ../../kar-cw/dist/kar-cw/",
|
||||
"unlink_kar_cw": "pnpm unlink ../../kar-cw/dist/kar-cw/"
|
||||
},
|
||||
"private": true,
|
||||
"version": "0.0.1",
|
||||
"description": "KAR web music application",
|
||||
"author": {
|
||||
"name": "Edouard DUPIN",
|
||||
"email": "yui.heero@gmail.farm"
|
||||
},
|
||||
"license": "PROPRIETARY",
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"scripts": {
|
||||
"update_packages": "ncu --upgrade",
|
||||
"install_dependency": "pnpm install",
|
||||
"test": "vitest run",
|
||||
"test:watch": "vitest watch",
|
||||
"build": "tsc && vite build",
|
||||
"static:build": "node build.js && pnpm build",
|
||||
"dev": "vite",
|
||||
"pretty": "prettier -w .",
|
||||
"lint": "pnpm tsc --noEmit",
|
||||
"storybook": "storybook dev -p 3001",
|
||||
"storybook:build": "storybook build && mv ./storybook-static ./public/storybook"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{ts,tsx,js,jsx,json}": "prettier --write"
|
||||
},
|
||||
"dependencies": {
|
||||
"@angular/animations": "^17.3.4",
|
||||
"@angular/cdk": "^17.3.4",
|
||||
"@angular/common": "^17.3.4",
|
||||
"@angular/compiler": "^17.3.4",
|
||||
"@angular/core": "^17.3.4",
|
||||
"@angular/forms": "^17.3.4",
|
||||
"@angular/material": "^17.3.4",
|
||||
"@angular/platform-browser": "^17.3.4",
|
||||
"@angular/platform-browser-dynamic": "^17.3.4",
|
||||
"@angular/router": "^17.3.4",
|
||||
"rxjs": "^7.8.1",
|
||||
"zone.js": "^0.14.4",
|
||||
"zod": "3.22.4",
|
||||
"@kangaroo-and-rabbit/kar-cw": "^0.2.0"
|
||||
"@chakra-ui/anatomy": "2.2.2",
|
||||
"@chakra-ui/cli": "2.4.1",
|
||||
"@chakra-ui/react": "2.8.2",
|
||||
"@chakra-ui/theme-tools": "2.1.2",
|
||||
"@dnd-kit/core": "6.1.0",
|
||||
"@dnd-kit/modifiers": "7.0.0",
|
||||
"@dnd-kit/sortable": "8.0.0",
|
||||
"@dnd-kit/utilities": "3.2.2",
|
||||
"@emotion/react": "11.13.3",
|
||||
"@emotion/styled": "11.13.0",
|
||||
"@formiz/core": "2.3.1",
|
||||
"@formiz/validations": "2.0.1",
|
||||
"allotment": "1.20.2",
|
||||
"css-mediaquery": "0.1.2",
|
||||
"dayjs": "1.11.13",
|
||||
"history": "5.3.0",
|
||||
"react": "18.3.1",
|
||||
"react-color-palette": "7.3.0",
|
||||
"react-currency-input-field": "3.8.0",
|
||||
"react-custom-scrollbars": "4.2.1",
|
||||
"react-day-picker": "9.0.9",
|
||||
"react-dom": "18.3.1",
|
||||
"react-error-boundary": "4.0.13",
|
||||
"react-focus-lock": "2.13.2",
|
||||
"react-icons": "5.3.0",
|
||||
"react-popper": "2.3.0",
|
||||
"react-router-dom": "6.26.2",
|
||||
"react-select": "5.8.0",
|
||||
"react-simple-keyboard": "3.8.1",
|
||||
"react-sticky-el": "2.1.1",
|
||||
"react-use": "17.5.1",
|
||||
"react-use-draggable-scroll": "0.4.7",
|
||||
"react-virtuoso": "4.10.4",
|
||||
"ts-pattern": "5.3.1",
|
||||
"uuid": "10.0.0",
|
||||
"zod": "3.23.8",
|
||||
"zustand": "4.5.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^17.3.4",
|
||||
"@angular-eslint/builder": "17.3.0",
|
||||
"@angular-eslint/eslint-plugin": "17.3.0",
|
||||
"@angular-eslint/eslint-plugin-template": "17.3.0",
|
||||
"@angular-eslint/schematics": "17.3.0",
|
||||
"@angular-eslint/template-parser": "17.3.0",
|
||||
"@angular/cli": "^17.3.4",
|
||||
"@angular/compiler-cli": "^17.3.4",
|
||||
"@angular/language-service": "^17.3.4",
|
||||
"npm-check-updates": "^16.14.18",
|
||||
"tslib": "^2.6.2"
|
||||
"@chakra-ui/styled-system": "2.9.2",
|
||||
"@playwright/test": "1.47.1",
|
||||
"@storybook/addon-actions": "8.3.0",
|
||||
"@storybook/addon-essentials": "8.3.0",
|
||||
"@storybook/addon-links": "8.3.0",
|
||||
"@storybook/addon-mdx-gfm": "8.3.0",
|
||||
"@storybook/react": "8.3.0",
|
||||
"@storybook/react-vite": "8.3.0",
|
||||
"@storybook/theming": "8.3.0",
|
||||
"@testing-library/jest-dom": "6.5.0",
|
||||
"@testing-library/react": "16.0.1",
|
||||
"@testing-library/user-event": "14.5.2",
|
||||
"@trivago/prettier-plugin-sort-imports": "4.3.0",
|
||||
"@types/jest": "29.5.13",
|
||||
"@types/node": "22.5.5",
|
||||
"@types/react": "18.3.5",
|
||||
"@types/react-dom": "18.3.0",
|
||||
"@types/react-sticky-el": "1.0.7",
|
||||
"@typescript-eslint/eslint-plugin": "8.5.0",
|
||||
"@typescript-eslint/parser": "8.5.0",
|
||||
"@vitejs/plugin-react": "4.3.1",
|
||||
"eslint": "9.10.0",
|
||||
"eslint-plugin-codeceptjs": "1.3.0",
|
||||
"eslint-plugin-import": "2.30.0",
|
||||
"eslint-plugin-react": "7.36.1",
|
||||
"eslint-plugin-react-hooks": "4.6.2",
|
||||
"eslint-plugin-storybook": "0.8.0",
|
||||
"jest": "29.7.0",
|
||||
"jest-environment-jsdom": "29.7.0",
|
||||
"knip": "5.30.2",
|
||||
"lint-staged": "15.2.10",
|
||||
"npm-check-updates": "^17.1.1",
|
||||
"prettier": "3.3.3",
|
||||
"puppeteer": "23.3.0",
|
||||
"react-is": "18.3.1",
|
||||
"storybook": "8.3.0",
|
||||
"ts-node": "10.9.2",
|
||||
"typescript": "5.6.2",
|
||||
"vite": "5.4.5",
|
||||
"vitest": "2.1.1"
|
||||
}
|
||||
}
|
18532
front/pnpm-lock.yaml
18532
front/pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
16
front/prettier.config.js
Normal file
16
front/prettier.config.js
Normal file
@ -0,0 +1,16 @@
|
||||
// Using a JS file, allowing us to add comments
|
||||
module.exports = {
|
||||
// This plugins line is mandatory for the plugin to work with pnpm.
|
||||
// https://github.com/trivago/prettier-plugin-sort-imports/blob/61d069711008c530f5a41ca4e254781abc5de358/README.md?plain=1#L89-L96
|
||||
plugins: ['@trivago/prettier-plugin-sort-imports'],
|
||||
endOfLine: 'lf',
|
||||
semi: true,
|
||||
singleQuote: true,
|
||||
tabWidth: 2,
|
||||
trailingComma: 'es5',
|
||||
arrowParens: 'always',
|
||||
importOrder: ['^react$', '^(?!^react$|^@/|^[./]).*', '^@/(.*)$', '^[./]'],
|
||||
importOrderSeparation: true,
|
||||
importOrderSortSpecifiers: true,
|
||||
importOrderParserPlugins: ['jsx', 'typescript'],
|
||||
};
|
@ -1,28 +0,0 @@
|
||||
// Protractor configuration file, see link for more information
|
||||
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||
|
||||
const { SpecReporter } = require('jasmine-spec-reporter');
|
||||
|
||||
exports.config = {
|
||||
allScriptsTimeout: 11000,
|
||||
specs: [
|
||||
'./e2e/**/*.e2e-spec.ts'
|
||||
],
|
||||
capabilities: {
|
||||
'browserName': 'chrome'
|
||||
},
|
||||
directConnect: true,
|
||||
baseUrl: 'http://localhost:4200/',
|
||||
framework: 'jasmine',
|
||||
jasmineNodeOpts: {
|
||||
showColors: true,
|
||||
defaultTimeoutInterval: 30000,
|
||||
print: function() {}
|
||||
},
|
||||
onPrepare() {
|
||||
require('ts-node').register({
|
||||
project: 'e2e/tsconfig.e2e.json'
|
||||
});
|
||||
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
|
||||
}
|
||||
};
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
@ -1,43 +0,0 @@
|
||||
|
||||
|
||||
Start the application:
|
||||
|
||||
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
upgrade package
|
||||
```
|
||||
npm audit fix
|
||||
```
|
||||
|
||||
## npm install -g angular-cli
|
||||
|
||||
start the application:
|
||||
```
|
||||
npx ng serve --watch
|
||||
```
|
||||
|
||||
plus facilement:
|
||||
npm install @angular-devkit/build-angular@0.901.9
|
||||
npm start
|
||||
|
||||
|
||||
|
||||
Apply linter:
|
||||
==============
|
||||
```
|
||||
npx ng lint
|
||||
```
|
||||
|
||||
|
||||
|
||||
build the local image:
|
||||
|
||||
docker build -t gitea.atria-soft.org/kangaroo-and-rabbit/karusic:latest .
|
||||
|
||||
docker login gitea.atria-soft.org
|
||||
|
||||
docker push gitea.atria-soft.org/kangaroo-and-rabbit/karusic:latest
|
||||
|
118
front/src/App.tsx
Normal file
118
front/src/App.tsx
Normal file
@ -0,0 +1,118 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
import { ChakraProvider, Select } from '@chakra-ui/react';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Modal,
|
||||
ModalBody,
|
||||
ModalCloseButton,
|
||||
ModalContent,
|
||||
ModalFooter,
|
||||
ModalHeader,
|
||||
ModalOverlay,
|
||||
Stack,
|
||||
Text,
|
||||
useDisclosure,
|
||||
} from '@chakra-ui/react';
|
||||
|
||||
import { environment } from '@/environment';
|
||||
import { App as SpaApp } from '@/scene/App';
|
||||
import { USERS } from '@/service/session';
|
||||
import theme from '@/theme';
|
||||
import { hashLocalData } from '@/utils/sso';
|
||||
|
||||
const AppEnvHint = () => {
|
||||
const modal = useDisclosure();
|
||||
const [selectUserTest, setSelectUserTest] = useState<string>('NO_USER');
|
||||
//const setUser = useRightsStore((store) => store.setUser);
|
||||
const buildEnv =
|
||||
process.env.NODE_ENV === 'development'
|
||||
? 'Development'
|
||||
: import.meta.env.VITE_DEV_ENV_NAME;
|
||||
const envName: Array<string> = [];
|
||||
!!buildEnv && envName.push(buildEnv);
|
||||
if (!envName.length) {
|
||||
return null;
|
||||
}
|
||||
const handleChange = (selectedOption) => {
|
||||
console.log(`SELECT: [${selectedOption.target.value}]`);
|
||||
setSelectUserTest(selectedOption.target.value);
|
||||
};
|
||||
const onClose = () => {
|
||||
modal.onClose();
|
||||
if (selectUserTest == 'NO_USER') {
|
||||
window.location.href = `/${environment.applName}/sso/${hashLocalData()}/false/__LOGOUT__`;
|
||||
} else {
|
||||
window.location.href = `/${environment.applName}/sso/${hashLocalData()}/true/${USERS[selectUserTest]}`;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box
|
||||
zIndex="100000"
|
||||
position="fixed"
|
||||
top="0"
|
||||
insetStart="0"
|
||||
insetEnd="0"
|
||||
h="2px"
|
||||
bg="warning.400"
|
||||
as="button"
|
||||
cursor="pointer"
|
||||
data-test-id="devtools"
|
||||
onClick={modal.onOpen}
|
||||
>
|
||||
<Text
|
||||
position="fixed"
|
||||
top="0"
|
||||
insetStart="4"
|
||||
bg="warning.400"
|
||||
color="warning.900"
|
||||
fontSize="0.6rem"
|
||||
fontWeight="bold"
|
||||
px="10px"
|
||||
marginLeft="25%"
|
||||
borderBottomStartRadius="sm"
|
||||
borderBottomEndRadius="sm"
|
||||
textTransform="uppercase"
|
||||
>
|
||||
{envName.join(' : ')}
|
||||
</Text>
|
||||
</Box>
|
||||
<Modal isOpen={modal.isOpen} onClose={modal.onClose}>
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalHeader>Outils développeurs</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<ModalBody>
|
||||
<Stack>
|
||||
<Text>Utilisateur</Text>
|
||||
<Select placeholder="Select test user" onChange={handleChange}>
|
||||
{Object.keys(USERS).map((key) => (
|
||||
<option value={key} key={key}>
|
||||
{key}
|
||||
</option>
|
||||
))}
|
||||
</Select>
|
||||
</Stack>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button onClick={onClose}>Apply</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
<ChakraProvider theme={theme}>
|
||||
<AppEnvHint />
|
||||
<SpaApp />
|
||||
</ChakraProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
@ -1,184 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2018, Edouard DUPIN, all right reserved
|
||||
* @license PROPRIETARY (see license file)
|
||||
*/
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router'; // CLI imports router
|
||||
|
||||
import {
|
||||
HelpScene, HomeScene, AlbumEditScene, AlbumsScene, ArtistEditScene, ArtistScene, SettingsScene,
|
||||
GenderScene, PlaylistScene, TrackEditScene, TrackScene, UploadScene, ArtistsScene, ArtistAlbumScene, AlbumScene
|
||||
} from './scene';
|
||||
import { ForbiddenScene, OnlyUsersGuardHome, HomeOutScene, OnlyUnregisteredGuardHome, SsoScene, OnlyAdminGuard, OnlyUsersGuard, NotFound404Scene } from '@kangaroo-and-rabbit/kar-cw';
|
||||
|
||||
// import { HelpComponent } from './help/help.component';
|
||||
|
||||
// see https://angular.io/guide/router
|
||||
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', redirectTo: '/home', pathMatch: 'full' },
|
||||
|
||||
{ path: 'forbidden', component: ForbiddenScene },
|
||||
|
||||
// ------------------------------------
|
||||
// -- home global interface
|
||||
// ------------------------------------
|
||||
{
|
||||
path: 'home',
|
||||
component: HomeScene,
|
||||
canActivate: [OnlyUsersGuardHome], // this route to unregistered path when not logged ==> permit to simplify display
|
||||
},
|
||||
{
|
||||
path: 'unregistered',
|
||||
component: HomeOutScene,
|
||||
canActivate: [OnlyUnregisteredGuardHome], // jump to the home when registered
|
||||
},
|
||||
// ------------------------------------
|
||||
// -- SSO Generic interface
|
||||
// ------------------------------------
|
||||
{ path: 'sso/:data/:keepConnected/:token', component: SsoScene },
|
||||
{ path: 'sso/:keepConnected/:token', component: SsoScene },
|
||||
{ path: 'sso', component: SsoScene },
|
||||
|
||||
// ------------------------------------
|
||||
// -- Generic pages
|
||||
// ------------------------------------
|
||||
{ path: 'help/:page', component: HelpScene },
|
||||
{ path: 'help', component: HelpScene },
|
||||
|
||||
// ------------------------------------
|
||||
// -- upload new data:
|
||||
// ------------------------------------
|
||||
{
|
||||
path: 'upload',
|
||||
component: UploadScene,
|
||||
canActivate: [OnlyAdminGuard],
|
||||
},
|
||||
// ------------------------------------
|
||||
// -- gender:
|
||||
// ------------------------------------
|
||||
// display all gender
|
||||
{
|
||||
path: 'gender',
|
||||
component: GenderScene,
|
||||
canActivate: [OnlyUsersGuard],
|
||||
},
|
||||
// display all (artist | album | tracks)
|
||||
{
|
||||
path: 'gender/:genderId',
|
||||
component: GenderScene,
|
||||
canActivate: [OnlyUsersGuard],
|
||||
},
|
||||
//{ path: 'gender-edit/:genderId', component: GenderEditScene },
|
||||
|
||||
//{ path: 'gender/:genderId', component: GenderScene },
|
||||
//{ path: 'gender/:genderId/:artistId/:albumId/:trackId', component: GenderScene },
|
||||
|
||||
// ------------------------------------
|
||||
// -- playlist:
|
||||
// ------------------------------------
|
||||
{
|
||||
path: 'playlist',
|
||||
component: PlaylistScene,
|
||||
canActivate: [OnlyUsersGuard],
|
||||
},
|
||||
{
|
||||
path: 'playlist/:playlistId',
|
||||
component: PlaylistScene,
|
||||
canActivate: [OnlyUsersGuard],
|
||||
},
|
||||
|
||||
//{ path: 'playlist-edit/:playlistId', component: PlaylistEditScene },
|
||||
|
||||
// ------------------------------------
|
||||
// -- Artist:
|
||||
// ------------------------------------
|
||||
// display list of all artist
|
||||
{
|
||||
path: 'artist',
|
||||
component: ArtistsScene,
|
||||
canActivate: [OnlyUsersGuard],
|
||||
},
|
||||
// display list af all artist with a specific gender
|
||||
{
|
||||
path: 'artist/:artistId',
|
||||
component: ArtistScene,
|
||||
canActivate: [OnlyUsersGuard],
|
||||
},
|
||||
{
|
||||
path: 'artist/:artistId/edit',
|
||||
component: ArtistEditScene,
|
||||
canActivate: [OnlyAdminGuard],
|
||||
},
|
||||
{
|
||||
path: 'artist/:artistId/:albumId',
|
||||
component: ArtistAlbumScene,
|
||||
canActivate: [OnlyUsersGuard],
|
||||
},
|
||||
|
||||
// ------------------------------------
|
||||
// -- Album:
|
||||
// ------------------------------------
|
||||
// display all Album
|
||||
{
|
||||
path: 'album',
|
||||
component: AlbumsScene,
|
||||
canActivate: [OnlyUsersGuard],
|
||||
},
|
||||
{
|
||||
path: 'album/:albumId/edit',
|
||||
component: AlbumEditScene,
|
||||
canActivate: [OnlyAdminGuard],
|
||||
},
|
||||
{
|
||||
path: 'album/:albumId',
|
||||
component: AlbumScene,
|
||||
canActivate: [OnlyUsersGuard],
|
||||
},
|
||||
|
||||
// ------------------------------------
|
||||
// -- Tracks:
|
||||
// ------------------------------------
|
||||
{
|
||||
path: 'track/:trackId/edit',
|
||||
component: TrackEditScene,
|
||||
canActivate: [OnlyAdminGuard],
|
||||
},
|
||||
{
|
||||
path: 'track/:genderId/:artistId/:albumId/:trackId',
|
||||
component: TrackScene,
|
||||
canActivate: [OnlyUsersGuard],
|
||||
},
|
||||
|
||||
// ------------------------------------
|
||||
// -- setting:
|
||||
// ------------------------------------
|
||||
{
|
||||
path: 'settings',
|
||||
component: SettingsScene,
|
||||
canActivate: [OnlyUsersGuard],
|
||||
},
|
||||
{
|
||||
path: '**',
|
||||
component: NotFound404Scene,
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
RouterModule.forRoot(
|
||||
routes,
|
||||
{
|
||||
//enableTracing: true, // <-- debugging purposes only
|
||||
},
|
||||
),
|
||||
],
|
||||
exports: [
|
||||
RouterModule,
|
||||
]
|
||||
})
|
||||
export class AppRoutingModule { }
|
||||
|
@ -1,17 +0,0 @@
|
||||
<!-- Generic global menu -->
|
||||
<karcw-top-menu [menu]="currentMenu" (callback)="eventOnMenu($event)"/>
|
||||
<!-- all interfaced pages -->
|
||||
<div class="main-content">
|
||||
@if(autoConnectedDone) {
|
||||
<router-outlet ></router-outlet>
|
||||
}
|
||||
@else {
|
||||
<div class="generic-page">
|
||||
<div class="fill-all colomn_mutiple">
|
||||
<b style="color:red;">Auto-connection in progress</b>
|
||||
<div class="clear"></div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<app-element-player-audio></app-element-player-audio>
|
@ -1,46 +0,0 @@
|
||||
|
||||
|
||||
#create-exercice-button {
|
||||
position: fixed;
|
||||
display: block;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
margin-right: 40px;
|
||||
margin-bottom: 40px;
|
||||
z-index: 900;
|
||||
}
|
||||
|
||||
#save-exercice-button {
|
||||
position: fixed;
|
||||
display: block;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
margin-right: 110px;
|
||||
margin-bottom: 40px;
|
||||
z-index: 900;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
position: absolute;
|
||||
//width: ~"calc(calc(100% / 5 ) * 5)";
|
||||
width: 100%;
|
||||
height: ~"calc(100% - 56px)";
|
||||
top: 56px;
|
||||
left: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: block;
|
||||
position: fixed;
|
||||
overflow-y: auto;
|
||||
//background-color:#FF0;
|
||||
/*
|
||||
.main-reduce {
|
||||
width: 40%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0px 10% 0px 10%;
|
||||
display: block;
|
||||
overflow-y:scroll;
|
||||
}
|
||||
*/
|
||||
}
|
@ -1,300 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2018, Edouard DUPIN, all right reserved
|
||||
* @license PROPRIETARY (see license file)
|
||||
*/
|
||||
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ArianeService } from './service';
|
||||
import {
|
||||
MenuItem,
|
||||
SSOService,
|
||||
SessionService,
|
||||
UserService,
|
||||
UserRoles222,
|
||||
EventOnMenu,
|
||||
MenuPosition,
|
||||
isNullOrUndefined,
|
||||
} from '@kangaroo-and-rabbit/kar-cw';
|
||||
|
||||
enum MenuEventType {
|
||||
SSO_LOGIN = "SSO_CALL_LOGIN",
|
||||
SSO_LOGOUT = "SSO_CALL_LOGOUT",
|
||||
SSO_SIGNUP = "SSO_CALL_SIGNUP",
|
||||
SEGMENT = "SEGMENT",
|
||||
TYPE = "TYPE",
|
||||
ARTIST = "ARTIST",
|
||||
ALBUM = "ALBUM",
|
||||
TRACK = "TRACK",
|
||||
PLAYLIST = "PLAYLIST",
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: [
|
||||
'./app.component.less',
|
||||
]
|
||||
})
|
||||
export class AppComponent implements OnInit {
|
||||
title: string = 'Karideo';
|
||||
autoConnectedDone: boolean = false;
|
||||
isConnected: boolean = false;
|
||||
signUpEnable: boolean = true;
|
||||
currentMenu: MenuItem[] = [];
|
||||
location: string = "home";
|
||||
|
||||
constructor(
|
||||
private sessionService: SessionService,
|
||||
private ssoService: SSOService,
|
||||
private arianeService: ArianeService,
|
||||
private userService: UserService
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.autoConnectedDone = false;
|
||||
this.isConnected = false;
|
||||
this.updateMainMenu();
|
||||
let self = this;
|
||||
this.sessionService.change.subscribe((isConnected) => {
|
||||
console.log(`receive event from session ...${isConnected}`);
|
||||
self.isConnected = isConnected;
|
||||
self.autoConnectedDone = true;
|
||||
self.updateMainMenu();
|
||||
});
|
||||
this.ssoService.checkSignUpEnable()
|
||||
.then((value: boolean) => {
|
||||
console.log(`Get value signUp = ${value}`);
|
||||
self.signUpEnable = value;
|
||||
self.updateMainMenu();
|
||||
}).catch((error: any) => {
|
||||
console.log(`Can not call the sso to check the sign-up_interface: ${error}`);
|
||||
});
|
||||
|
||||
this.userService.checkAutoConnect().then(() => {
|
||||
console.log(` ==>>>>> Autoconnect THEN !!!`);
|
||||
self.autoConnectedDone = true;
|
||||
}).catch(() => {
|
||||
console.log(` ==>>>>> Autoconnect CATCH !!!`);
|
||||
self.autoConnectedDone = true;
|
||||
}).finally(() => {
|
||||
console.log(` ==>>>>> Autoconnect FINALLY !!!`);
|
||||
self.autoConnectedDone = true;
|
||||
});
|
||||
|
||||
this.arianeService.segmentChange.subscribe((_segmentName: string) => {
|
||||
//console.log(`>>> change typeId=${typeId}`);
|
||||
self.updateMainMenu();
|
||||
});
|
||||
this.arianeService.typeChange.subscribe((_typeId: number) => {
|
||||
//console.log(`>>> change typeId=${typeId}`);
|
||||
self.updateMainMenu();
|
||||
});
|
||||
this.arianeService.playlistChange.subscribe((_universId: number) => {
|
||||
//console.log(`>>> change universId=${universId}`);
|
||||
self.updateMainMenu();
|
||||
});
|
||||
this.arianeService.artistChange.subscribe((_artistId: number) => {
|
||||
//console.log(`>>> change artistId=${artistId}`);
|
||||
self.updateMainMenu();
|
||||
});
|
||||
this.arianeService.albumChange.subscribe((_albumId: number) => {
|
||||
//console.log(`>>> change albumId=${albumId}`);
|
||||
self.updateMainMenu();
|
||||
});
|
||||
this.arianeService.trackChange.subscribe((_trackId: number) => {
|
||||
//console.log(`>>> change trackId=${trackId}`);
|
||||
self.updateMainMenu();
|
||||
});
|
||||
}
|
||||
|
||||
eventOnMenu(data: EventOnMenu): void {
|
||||
console.log(`Get event on menu: ${JSON.stringify(data, null, 4)}`);
|
||||
switch (data.menu.otherData) {
|
||||
case MenuEventType.SSO_LOGIN:
|
||||
this.ssoService.requestSignIn();
|
||||
break;
|
||||
case MenuEventType.SSO_LOGOUT:
|
||||
this.ssoService.requestSignOut();
|
||||
break;
|
||||
case MenuEventType.SSO_SIGNUP:
|
||||
this.ssoService.requestSignUp();
|
||||
break;
|
||||
case MenuEventType.SEGMENT:
|
||||
if (this.arianeService.getCurrrentSegment() === "artist") {
|
||||
this.arianeService.navigateArtist({});
|
||||
} else if (this.arianeService.getCurrrentSegment() === "gender") {
|
||||
this.arianeService.navigateGender({});
|
||||
} else if (this.arianeService.getCurrrentSegment() === "playlist") {
|
||||
this.arianeService.navigatePlaylist({});
|
||||
} else if (this.arianeService.getCurrrentSegment() === "track") {
|
||||
this.arianeService.navigateTrack({});
|
||||
} else if (this.arianeService.getCurrrentSegment() === "album") {
|
||||
this.arianeService.navigateAlbum({});
|
||||
}
|
||||
break;
|
||||
case MenuEventType.TYPE:
|
||||
|
||||
break;
|
||||
case MenuEventType.ARTIST:
|
||||
if (this.arianeService.getCurrrentSegment() === "artist") {
|
||||
this.arianeService.navigateArtist({ artistId: this.arianeService.getArtistId() });
|
||||
}
|
||||
break;
|
||||
case MenuEventType.ALBUM:
|
||||
break;
|
||||
case MenuEventType.TRACK:
|
||||
break;
|
||||
case MenuEventType.PLAYLIST:
|
||||
break;
|
||||
}
|
||||
}
|
||||
updateMainMenu(): void {
|
||||
console.log("update main menu :");
|
||||
|
||||
if (this.isConnected) {
|
||||
this.currentMenu = [
|
||||
{
|
||||
position: MenuPosition.LEFT,
|
||||
hover: "lkjljlk", //`You are logged as: ${this.sessionService.getLogin()}`,
|
||||
icon: "menu",
|
||||
title: "Menu",
|
||||
subMenu: [
|
||||
{
|
||||
position: MenuPosition.LEFT,
|
||||
hover: "Go to Home page",
|
||||
icon: "home",
|
||||
title: "Home",
|
||||
navigateTo: "home",
|
||||
}, {
|
||||
position: MenuPosition.LEFT,
|
||||
icon: "group_work",
|
||||
title: this.getSegmentDisplayable(),
|
||||
otherData: MenuEventType.SEGMENT,
|
||||
callback: true,
|
||||
enable: this.getSegmentDisplayable() !== "",
|
||||
}, {
|
||||
position: MenuPosition.LEFT,
|
||||
icon: "piano",
|
||||
title: this.getSegmentDisplayable(),
|
||||
otherData: MenuEventType.TYPE,
|
||||
callback: true,
|
||||
enable: !isNullOrUndefined(this.arianeService.getTypeId()),
|
||||
}, {
|
||||
position: MenuPosition.LEFT,
|
||||
icon: "person",
|
||||
title: this.arianeService.getArtistName(),
|
||||
otherData: MenuEventType.ARTIST,
|
||||
callback: true,
|
||||
enable: !isNullOrUndefined(this.arianeService.getArtistId()),
|
||||
}, {
|
||||
position: MenuPosition.LEFT,
|
||||
icon: "album",
|
||||
title: this.arianeService.getAlbumName(),
|
||||
otherData: MenuEventType.ALBUM,
|
||||
callback: true,
|
||||
enable: !isNullOrUndefined(this.arianeService.getAlbumId()),
|
||||
}, {
|
||||
position: MenuPosition.LEFT,
|
||||
icon: "music_note",
|
||||
title: this.arianeService.getTrackName(),
|
||||
otherData: MenuEventType.TRACK,
|
||||
callback: true,
|
||||
enable: !isNullOrUndefined(this.arianeService.getTrackId()),
|
||||
}, {
|
||||
position: MenuPosition.LEFT,
|
||||
icon: "queue_music",
|
||||
title: "true",//this.arianeService.getPlaylistName(),
|
||||
otherData: MenuEventType.PLAYLIST,
|
||||
callback: true,
|
||||
enable: !isNullOrUndefined(this.arianeService.getPlaylistId()),
|
||||
}
|
||||
],
|
||||
}, {
|
||||
position: MenuPosition.RIGHT,
|
||||
image: "assets/images/avatar_generic.svg",
|
||||
title: "",
|
||||
subMenu: [
|
||||
{
|
||||
position: MenuPosition.LEFT,
|
||||
hover: `You are logged as: <b>${this.sessionService.getLogin()}</b>`,
|
||||
title: `Sign in as ${this.sessionService.getLogin()}`,
|
||||
}, {
|
||||
position: MenuPosition.LEFT,
|
||||
icon: "add_circle",
|
||||
title: "Add media",
|
||||
navigateTo: "upload",
|
||||
enable: this.sessionService.hasRight(UserRoles222.admin),
|
||||
}, {
|
||||
position: MenuPosition.LEFT,
|
||||
icon: "settings",
|
||||
title: "Settings",
|
||||
navigateTo: "settings",
|
||||
}, {
|
||||
position: MenuPosition.LEFT,
|
||||
icon: "help",
|
||||
title: "Help",
|
||||
navigateTo: "help",
|
||||
}, {
|
||||
position: MenuPosition.LEFT,
|
||||
hover: "Exit connection",
|
||||
icon: "exit_to_app",
|
||||
title: "Sign out",
|
||||
callback: true,
|
||||
otherData: MenuEventType.SSO_LOGOUT,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
} else {
|
||||
this.currentMenu = [
|
||||
{
|
||||
position: MenuPosition.LEFT,
|
||||
hover: "Go to Home page",
|
||||
icon: "home",
|
||||
title: "Home",
|
||||
navigateTo: "home",
|
||||
}, {
|
||||
position: MenuPosition.RIGHT,
|
||||
hover: "Create a new account",
|
||||
icon: "add_circle_outline",
|
||||
title: "Sign-up",
|
||||
callback: true,
|
||||
model: this.signUpEnable ? undefined : "disable",
|
||||
otherData: MenuEventType.SSO_SIGNUP,
|
||||
}, {
|
||||
position: MenuPosition.RIGHT,
|
||||
hover: "Login page",
|
||||
icon: "account_circle",
|
||||
title: "Sign-in",
|
||||
callback: true,
|
||||
otherData: MenuEventType.SSO_LOGIN,
|
||||
},
|
||||
];
|
||||
}
|
||||
console.log(" ==> DONE");
|
||||
|
||||
}
|
||||
getSegmentDisplayable(): string {
|
||||
let segment = this.arianeService.getCurrrentSegment();
|
||||
if (segment === "artist") {
|
||||
return "Artists"
|
||||
}
|
||||
if (segment === "gender") {
|
||||
return "Genders"
|
||||
}
|
||||
if (segment === "album") {
|
||||
return "Albums"
|
||||
}
|
||||
if (segment === "track") {
|
||||
return "Tracks"
|
||||
}
|
||||
if (segment === "playlist") {
|
||||
return "Playlist"
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
@ -1,96 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2018, Edouard DUPIN, all right reserved
|
||||
* @license PROPRIETARY (see license file)
|
||||
*/
|
||||
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA, NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
|
||||
import { ElementDataImageComponent } from './component/data-image/data-image';
|
||||
import { ElementTypeComponent } from './component/element-type/element-type';
|
||||
|
||||
import { PopInCreateType } from './popin/create-type/create-type';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
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 { UploadScene } from './scene/upload/upload';
|
||||
import { ElementSeriesComponent, ElementTrackComponent, ElementSeasonComponent, ElementVideoComponent, ElementPlayerAudioComponent, DescriptionAreaComponent } from './component';
|
||||
import { KarCWModule } from '@kangaroo-and-rabbit/kar-cw';
|
||||
import { environment } from 'environments/environment';
|
||||
|
||||
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
|
||||
import { CommonModule } from "@angular/common";
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
ElementDataImageComponent,
|
||||
ElementTypeComponent,
|
||||
ElementSeriesComponent,
|
||||
ElementTrackComponent,
|
||||
ElementSeasonComponent,
|
||||
ElementVideoComponent,
|
||||
ElementPlayerAudioComponent,
|
||||
DescriptionAreaComponent,
|
||||
PopInCreateType,
|
||||
HomeScene,
|
||||
HelpScene,
|
||||
GenderScene,
|
||||
PlaylistScene,
|
||||
ArtistAlbumScene,
|
||||
ArtistsScene,
|
||||
ArtistScene,
|
||||
AlbumScene,
|
||||
AlbumsScene,
|
||||
TrackScene,
|
||||
SettingsScene,
|
||||
TrackEditScene,
|
||||
AlbumEditScene,
|
||||
ArtistEditScene,
|
||||
UploadScene,
|
||||
],
|
||||
imports: [
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
CommonModule,
|
||||
|
||||
BrowserModule,
|
||||
RouterModule,
|
||||
AppRoutingModule,
|
||||
HttpClientModule,
|
||||
KarCWModule,
|
||||
],
|
||||
providers: [
|
||||
{ provide: 'ENVIRONMENT', useValue: environment },
|
||||
ArianeService,
|
||||
PlayerService,
|
||||
GenderService,
|
||||
DataService,
|
||||
PlaylistService,
|
||||
ArtistService,
|
||||
AlbumService,
|
||||
TrackService,
|
||||
],
|
||||
exports: [
|
||||
AppComponent,
|
||||
ElementTypeComponent,
|
||||
ElementSeriesComponent,
|
||||
ElementSeasonComponent,
|
||||
ElementVideoComponent,
|
||||
PopInCreateType,
|
||||
],
|
||||
bootstrap: [
|
||||
AppComponent
|
||||
],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA],
|
||||
})
|
||||
export class AppModule { }
|
@ -1,8 +0,0 @@
|
||||
/**
|
||||
* API of the server (auto-generated code)
|
||||
*/
|
||||
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
|
||||
import {} from "./model"
|
||||
export namespace Front {
|
||||
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
/**
|
||||
* API of the server (auto-generated code)
|
||||
*/
|
||||
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
|
||||
import {HealthResult, isHealthResult, } from "./model"
|
||||
export namespace HealthCheck {
|
||||
|
||||
export function getHealth({ restConfig, }: {
|
||||
restConfig: RESTConfig,
|
||||
}): Promise<HealthResult> {
|
||||
return RESTRequestJson({
|
||||
restModel: {
|
||||
endPoint: "/health_check",
|
||||
requestType: HTTPRequestModel.GET,
|
||||
accept: HTTPMimeType.JSON,
|
||||
},
|
||||
restConfig,
|
||||
}, isHealthResult);
|
||||
};
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
/**
|
||||
* Global import of the package
|
||||
*/
|
||||
export * from "./model";
|
||||
export * from "./album-resource";
|
||||
export * from "./artist-resource";
|
||||
export * from "./front";
|
||||
export * from "./gender-resource";
|
||||
export * from "./health-check";
|
||||
export * from "./playlist-resource";
|
||||
export * from "./user-resource";
|
||||
export * from "./track-resource";
|
||||
export * from "./data-resource";
|
@ -1,407 +0,0 @@
|
||||
/**
|
||||
* Interface of the server (auto-generated code)
|
||||
*/
|
||||
import { z as zod } from "zod";
|
||||
|
||||
export const ZodUUID = zod.string().uuid();
|
||||
export type UUID = zod.infer<typeof ZodUUID>;
|
||||
export function isUUID(data: any): data is UUID {
|
||||
try {
|
||||
ZodUUID.parse(data);
|
||||
return true;
|
||||
} catch (e: any) {
|
||||
console.log(`Fail to parse data ${e}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const ZodLong = zod.number();
|
||||
export type Long = zod.infer<typeof ZodLong>;
|
||||
export function isLong(data: any): data is Long {
|
||||
try {
|
||||
ZodLong.parse(data);
|
||||
return true;
|
||||
} catch (e: any) {
|
||||
console.log(`Fail to parse data ${e}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const ZodInteger = zod.number().safe();
|
||||
export type Integer = zod.infer<typeof ZodInteger>;
|
||||
export function isInteger(data: any): data is Integer {
|
||||
try {
|
||||
ZodInteger.parse(data);
|
||||
return true;
|
||||
} catch (e: any) {
|
||||
console.log(`Fail to parse data ${e}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const ZodFloat = zod.number();
|
||||
export type Float = zod.infer<typeof ZodFloat>;
|
||||
export function isFloat(data: any): data is Float {
|
||||
try {
|
||||
ZodFloat.parse(data);
|
||||
return true;
|
||||
} catch (e: any) {
|
||||
console.log(`Fail to parse data ${e}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const ZodInstant = zod.string();
|
||||
export type Instant = zod.infer<typeof ZodInstant>;
|
||||
export function isInstant(data: any): data is Instant {
|
||||
try {
|
||||
ZodInstant.parse(data);
|
||||
return true;
|
||||
} catch (e: any) {
|
||||
console.log(`Fail to parse data ${e}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const ZodDate = zod.date();
|
||||
export type Date = zod.infer<typeof ZodDate>;
|
||||
export function isDate(data: any): data is Date {
|
||||
try {
|
||||
ZodDate.parse(data);
|
||||
return true;
|
||||
} catch (e: any) {
|
||||
console.log(`Fail to parse data ${e}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const ZodTimestamp = zod.date();
|
||||
export type Timestamp = zod.infer<typeof ZodTimestamp>;
|
||||
export function isTimestamp(data: any): data is Timestamp {
|
||||
try {
|
||||
ZodTimestamp.parse(data);
|
||||
return true;
|
||||
} catch (e: any) {
|
||||
console.log(`Fail to parse data ${e}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const ZodLocalDate = zod.date();
|
||||
export type LocalDate = zod.infer<typeof ZodLocalDate>;
|
||||
export function isLocalDate(data: any): data is LocalDate {
|
||||
try {
|
||||
ZodLocalDate.parse(data);
|
||||
return true;
|
||||
} catch (e: any) {
|
||||
console.log(`Fail to parse data ${e}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const ZodLocalTime = zod.date();
|
||||
export type LocalTime = zod.infer<typeof ZodLocalTime>;
|
||||
export function isLocalTime(data: any): data is LocalTime {
|
||||
try {
|
||||
ZodLocalTime.parse(data);
|
||||
return true;
|
||||
} catch (e: any) {
|
||||
console.log(`Fail to parse data ${e}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const ZodRestErrorResponse = zod.object({
|
||||
uuid: ZodUUID.optional(),
|
||||
time: zod.string().max(255).optional(),
|
||||
error: zod.string().max(255).optional(),
|
||||
message: zod.string().max(255).optional(),
|
||||
status: ZodInteger,
|
||||
statusMessage: zod.string().max(255).optional()
|
||||
});
|
||||
export type RestErrorResponse = zod.infer<typeof ZodRestErrorResponse>;
|
||||
export function isRestErrorResponse(data: any): data is RestErrorResponse {
|
||||
try {
|
||||
ZodRestErrorResponse.parse(data);
|
||||
return true;
|
||||
} catch (e: any) {
|
||||
console.log(`Fail to parse data ${e}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const ZodGenericTiming = zod.object({
|
||||
// Create time of the object
|
||||
createdAt: ZodDate.readonly().optional(),
|
||||
// When update the object
|
||||
updatedAt: ZodDate.readonly().optional()
|
||||
});
|
||||
export type GenericTiming = zod.infer<typeof ZodGenericTiming>;
|
||||
export function isGenericTiming(data: any): data is GenericTiming {
|
||||
try {
|
||||
ZodGenericTiming.parse(data);
|
||||
return true;
|
||||
} catch (e: any) {
|
||||
console.log(`Fail to parse data ${e}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const ZodGenericData = ZodGenericTiming.extend({
|
||||
// Unique Id of the object
|
||||
id: ZodLong.readonly().optional()
|
||||
});
|
||||
export type GenericData = zod.infer<typeof ZodGenericData>;
|
||||
export function isGenericData(data: any): data is GenericData {
|
||||
try {
|
||||
ZodGenericData.parse(data);
|
||||
return true;
|
||||
} catch (e: any) {
|
||||
console.log(`Fail to parse data ${e}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const ZodGenericDataSoftDelete = ZodGenericData.extend({
|
||||
// Deleted state
|
||||
deleted: zod.boolean().readonly().optional()
|
||||
});
|
||||
export type GenericDataSoftDelete = zod.infer<typeof ZodGenericDataSoftDelete>;
|
||||
export function isGenericDataSoftDelete(data: any): data is GenericDataSoftDelete {
|
||||
try {
|
||||
ZodGenericDataSoftDelete.parse(data);
|
||||
return true;
|
||||
} catch (e: any) {
|
||||
console.log(`Fail to parse data ${e}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const ZodNodeSmall = ZodGenericDataSoftDelete.extend({
|
||||
name: zod.string().max(256).optional(),
|
||||
description: zod.string().optional(),
|
||||
// List of Id of the specific covers
|
||||
covers: zod.array(ZodUUID).optional()
|
||||
});
|
||||
export type NodeSmall = zod.infer<typeof ZodNodeSmall>;
|
||||
export function isNodeSmall(data: any): data is NodeSmall {
|
||||
try {
|
||||
ZodNodeSmall.parse(data);
|
||||
return true;
|
||||
} catch (e: any) {
|
||||
console.log(`Fail to parse data ${e}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const ZodAlbum = ZodNodeSmall.extend({
|
||||
publication: ZodLocalDate.optional()
|
||||
});
|
||||
export type Album = zod.infer<typeof ZodAlbum>;
|
||||
export function isAlbum(data: any): data is Album {
|
||||
try {
|
||||
ZodAlbum.parse(data);
|
||||
return true;
|
||||
} catch (e: any) {
|
||||
console.log(`Fail to parse data ${e}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const ZodArtist = ZodNodeSmall.extend({
|
||||
firstName: zod.string().max(256).optional(),
|
||||
surname: zod.string().max(256).optional(),
|
||||
birth: ZodLocalDate.optional(),
|
||||
death: ZodLocalDate.optional()
|
||||
});
|
||||
export type Artist = zod.infer<typeof ZodArtist>;
|
||||
export function isArtist(data: any): data is Artist {
|
||||
try {
|
||||
ZodArtist.parse(data);
|
||||
return true;
|
||||
} catch (e: any) {
|
||||
console.log(`Fail to parse data ${e}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const ZodGender = ZodNodeSmall.extend({
|
||||
});
|
||||
export type Gender = zod.infer<typeof ZodGender>;
|
||||
export function isGender(data: any): data is Gender {
|
||||
try {
|
||||
ZodGender.parse(data);
|
||||
return true;
|
||||
} catch (e: any) {
|
||||
console.log(`Fail to parse data ${e}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const ZodHealthResult = zod.object({
|
||||
});
|
||||
export type HealthResult = zod.infer<typeof ZodHealthResult>;
|
||||
export function isHealthResult(data: any): data is HealthResult {
|
||||
try {
|
||||
ZodHealthResult.parse(data);
|
||||
return true;
|
||||
} catch (e: any) {
|
||||
console.log(`Fail to parse data ${e}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const ZodPlaylist = ZodNodeSmall.extend({
|
||||
tracks: zod.array(ZodLong).optional()
|
||||
});
|
||||
export type Playlist = zod.infer<typeof ZodPlaylist>;
|
||||
export function isPlaylist(data: any): data is Playlist {
|
||||
try {
|
||||
ZodPlaylist.parse(data);
|
||||
return true;
|
||||
} catch (e: any) {
|
||||
console.log(`Fail to parse data ${e}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const ZodUser = ZodGenericDataSoftDelete.extend({
|
||||
login: zod.string().max(128).optional(),
|
||||
lastConnection: ZodTimestamp.optional(),
|
||||
admin: zod.boolean(),
|
||||
blocked: zod.boolean(),
|
||||
removed: zod.boolean(),
|
||||
covers: zod.array(ZodLong).optional()
|
||||
});
|
||||
export type User = zod.infer<typeof ZodUser>;
|
||||
export function isUser(data: any): data is User {
|
||||
try {
|
||||
ZodUser.parse(data);
|
||||
return true;
|
||||
} catch (e: any) {
|
||||
console.log(`Fail to parse data ${e}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const ZodUserKarusic = ZodUser.extend({
|
||||
});
|
||||
export type UserKarusic = zod.infer<typeof ZodUserKarusic>;
|
||||
export function isUserKarusic(data: any): data is UserKarusic {
|
||||
try {
|
||||
ZodUserKarusic.parse(data);
|
||||
return true;
|
||||
} catch (e: any) {
|
||||
console.log(`Fail to parse data ${e}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const ZodUserOut = zod.object({
|
||||
id: ZodLong,
|
||||
login: zod.string().max(255).optional()
|
||||
});
|
||||
export type UserOut = zod.infer<typeof ZodUserOut>;
|
||||
export function isUserOut(data: any): data is UserOut {
|
||||
try {
|
||||
ZodUserOut.parse(data);
|
||||
return true;
|
||||
} catch (e: any) {
|
||||
console.log(`Fail to parse data ${e}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const ZodTrack = ZodNodeSmall.extend({
|
||||
genderId: ZodLong.optional(),
|
||||
albumId: ZodLong.optional(),
|
||||
track: ZodLong.optional(),
|
||||
dataId: ZodUUID.optional(),
|
||||
artists: zod.array(ZodLong).optional()
|
||||
});
|
||||
export type Track = zod.infer<typeof ZodTrack>;
|
||||
export function isTrack(data: any): data is Track {
|
||||
try {
|
||||
ZodTrack.parse(data);
|
||||
return true;
|
||||
} catch (e: any) {
|
||||
console.log(`Fail to parse data ${e}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const ZodUUIDGenericData = ZodGenericTiming.extend({
|
||||
// Unique UUID of the object
|
||||
id: ZodUUID.readonly().optional()
|
||||
});
|
||||
export type UUIDGenericData = zod.infer<typeof ZodUUIDGenericData>;
|
||||
export function isUUIDGenericData(data: any): data is UUIDGenericData {
|
||||
try {
|
||||
ZodUUIDGenericData.parse(data);
|
||||
return true;
|
||||
} catch (e: any) {
|
||||
console.log(`Fail to parse data ${e}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const ZodUUIDGenericDataSoftDelete = ZodUUIDGenericData.extend({
|
||||
// Deleted state
|
||||
deleted: zod.boolean().readonly().optional()
|
||||
});
|
||||
export type UUIDGenericDataSoftDelete = zod.infer<typeof ZodUUIDGenericDataSoftDelete>;
|
||||
export function isUUIDGenericDataSoftDelete(data: any): data is UUIDGenericDataSoftDelete {
|
||||
try {
|
||||
ZodUUIDGenericDataSoftDelete.parse(data);
|
||||
return true;
|
||||
} catch (e: any) {
|
||||
console.log(`Fail to parse data ${e}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const ZodData = ZodUUIDGenericDataSoftDelete.extend({
|
||||
// Sha512 of the data
|
||||
sha512: zod.string().max(128).optional(),
|
||||
// Mime -type of the media
|
||||
mimeType: zod.string().max(128).optional(),
|
||||
// Size in Byte of the data
|
||||
size: ZodLong.optional()
|
||||
});
|
||||
export type Data = zod.infer<typeof ZodData>;
|
||||
export function isData(data: any): data is Data {
|
||||
try {
|
||||
ZodData.parse(data);
|
||||
return true;
|
||||
} catch (e: any) {
|
||||
console.log(`Fail to parse data ${e}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,246 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2024, Edouard DUPIN, all right reserved
|
||||
* @license MPL-2
|
||||
*/
|
||||
|
||||
import { RestErrorResponse } from "./model"
|
||||
|
||||
export enum HTTPRequestModel {
|
||||
DELETE = 'DELETE',
|
||||
GET = 'GET',
|
||||
PATCH = 'PATCH',
|
||||
POST = 'POST',
|
||||
PUT = 'PUT',
|
||||
}
|
||||
export enum HTTPMimeType {
|
||||
ALL = '*/*',
|
||||
CSV = 'text/csv',
|
||||
IMAGE = 'image/*',
|
||||
IMAGE_JPEG = 'image/jpeg',
|
||||
IMAGE_PNG = 'image/png',
|
||||
JSON = 'application/json',
|
||||
MULTIPART = 'multipart/form-data',
|
||||
OCTET_STREAM = 'application/octet-stream',
|
||||
TEXT_PLAIN = 'text/plain',
|
||||
}
|
||||
|
||||
export interface RESTConfig {
|
||||
// base of the server: http(s)://my.server.org/plop/api/
|
||||
server: string;
|
||||
// Token to access of the data.
|
||||
token?: string;
|
||||
}
|
||||
|
||||
export interface RESTModel {
|
||||
// base of the local API request: "sheep/{id}".
|
||||
endPoint: string;
|
||||
// Type of the request.
|
||||
requestType?: HTTPRequestModel;
|
||||
// Input type requested.
|
||||
accept?: HTTPMimeType;
|
||||
// Content of the local data.
|
||||
contentType?: HTTPMimeType;
|
||||
// Mode of the TOKEN in urk or Header
|
||||
tokenInUrl?: boolean;
|
||||
}
|
||||
|
||||
export interface ModelResponseHttp {
|
||||
status: number;
|
||||
data: any;
|
||||
}
|
||||
|
||||
export function isArrayOf<TYPE>(
|
||||
data: any,
|
||||
typeChecker: (subData: any) => subData is TYPE,
|
||||
length?: number
|
||||
): data is TYPE[] {
|
||||
if (!Array.isArray(data)) {
|
||||
return false;
|
||||
}
|
||||
if (!data.every(typeChecker)) {
|
||||
return false;
|
||||
}
|
||||
if (length !== undefined && data.length != length) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export type RESTRequestType = {
|
||||
restModel: RESTModel,
|
||||
restConfig: RESTConfig,
|
||||
data?: any,
|
||||
params?: object,
|
||||
queries?: object,
|
||||
};
|
||||
|
||||
function removeTrailingSlashes(input: string): string {
|
||||
return input.replace(/\/+$/, '');
|
||||
}
|
||||
function removeLeadingSlashes(input: string): string {
|
||||
return input.replace(/^\/+/, '');
|
||||
}
|
||||
|
||||
export function RESTUrl({ restModel, restConfig, data, params, queries }: RESTRequestType): string {
|
||||
// Create the URL PATH:
|
||||
let generateUrl = `${removeTrailingSlashes(restConfig.server)}/${removeLeadingSlashes(restModel.endPoint)}`;
|
||||
if (params !== undefined) {
|
||||
for (let key of Object.keys(params)) {
|
||||
generateUrl = generateUrl.replaceAll(`{${key}}`, `${params[key]}`);
|
||||
}
|
||||
}
|
||||
if (queries === undefined && (restConfig.token === undefined || restModel.tokenInUrl !== true)) {
|
||||
return generateUrl;
|
||||
}
|
||||
const searchParams = new URLSearchParams();
|
||||
if (queries !== undefined) {
|
||||
for (let key of Object.keys(queries)) {
|
||||
const value = queries[key];
|
||||
if (Array.isArray(value)) {
|
||||
for (let iii = 0; iii < value.length; iii++) {
|
||||
searchParams.append(`${key}`, `${value[iii]}`);
|
||||
}
|
||||
} else {
|
||||
searchParams.append(`${key}`, `${value}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (restConfig.token !== undefined && restModel.tokenInUrl === true) {
|
||||
searchParams.append('Authorization', `Bearer ${restConfig.token}`);
|
||||
}
|
||||
return generateUrl + "?" + searchParams.toString();
|
||||
}
|
||||
|
||||
export function RESTRequest({ restModel, restConfig, data, params, queries }: RESTRequestType): Promise<ModelResponseHttp> {
|
||||
// Create the URL PATH:
|
||||
let generateUrl = RESTUrl({ restModel, restConfig, data, params, queries });
|
||||
let headers: any = {};
|
||||
if (restConfig.token !== undefined && restModel.tokenInUrl !== true) {
|
||||
headers['Authorization'] = `Bearer ${restConfig.token}`;
|
||||
}
|
||||
if (restModel.accept !== undefined) {
|
||||
headers['Accept'] = restModel.accept;
|
||||
}
|
||||
if (restModel.requestType !== HTTPRequestModel.GET) {
|
||||
// if Get we have not a content type, the body is empty
|
||||
if (restModel.contentType !== HTTPMimeType.MULTIPART) {
|
||||
// special case of multi-part ==> no content type otherwise the browser does not set the ";bundary=--****"
|
||||
headers['Content-Type'] = restModel.contentType;
|
||||
}
|
||||
}
|
||||
let body = data;
|
||||
if (restModel.contentType === HTTPMimeType.JSON) {
|
||||
body = JSON.stringify(data);
|
||||
} else if (restModel.contentType === HTTPMimeType.MULTIPART) {
|
||||
const formData = new FormData();
|
||||
for (const name in data) {
|
||||
formData.append(name, data[name]);
|
||||
}
|
||||
body = formData
|
||||
}
|
||||
console.log(`Call ${generateUrl}`)
|
||||
return new Promise((resolve, reject) => {
|
||||
fetch(generateUrl, {
|
||||
method: restModel.requestType,
|
||||
headers,
|
||||
body,
|
||||
}).then((response: Response) => {
|
||||
if (response.status >= 200 && response.status <= 299) {
|
||||
const contentType = response.headers.get('Content-Type');
|
||||
if (restModel.accept !== contentType) {
|
||||
reject({
|
||||
time: Date().toString(),
|
||||
status: 901,
|
||||
error: `REST check wrong type: ${restModel.accept} != ${contentType}`,
|
||||
statusMessage: "Fetch error",
|
||||
message: "rest-tools.ts Wrong type in the message return type"
|
||||
} as RestErrorResponse);
|
||||
} else if (contentType === HTTPMimeType.JSON) {
|
||||
response
|
||||
.json()
|
||||
.then((value: any) => {
|
||||
//console.log(`RECEIVE ==> ${response.status}=${ JSON.stringify(value, null, 2)}`);
|
||||
resolve({ status: response.status, data: value });
|
||||
})
|
||||
.catch((reason: any) => {
|
||||
reject({
|
||||
time: Date().toString(),
|
||||
status: 902,
|
||||
error: `REST parse json fail: ${reason}`,
|
||||
statusMessage: "Fetch parse error",
|
||||
message: "rest-tools.ts Wrong message model to parse"
|
||||
} as RestErrorResponse);
|
||||
});
|
||||
} else {
|
||||
resolve({ status: response.status, data: response.body });
|
||||
}
|
||||
} else {
|
||||
reject({
|
||||
time: Date().toString(),
|
||||
status: response.status,
|
||||
error: `${response.body}`,
|
||||
statusMessage: "Fetch code error",
|
||||
message: "rest-tools.ts Wrong return code"
|
||||
} as RestErrorResponse);
|
||||
}
|
||||
}).catch((error: any) => {
|
||||
reject({
|
||||
time: Date(),
|
||||
status: 999,
|
||||
error: error,
|
||||
statusMessage: "Fetch catch error",
|
||||
message: "http-wrapper.ts detect an error in the fetch request"
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function RESTRequestJson<TYPE>(request: RESTRequestType, checker: (data: any) => data is TYPE): Promise<TYPE> {
|
||||
return new Promise((resolve, reject) => {
|
||||
RESTRequest(request).then((value: ModelResponseHttp) => {
|
||||
if (checker(value.data)) {
|
||||
resolve(value.data);
|
||||
} else {
|
||||
reject({
|
||||
time: Date().toString(),
|
||||
status: 950,
|
||||
error: "REST Fail to verify the data",
|
||||
statusMessage: "API cast ERROR",
|
||||
message: "api.ts Check type as fail"
|
||||
} as RestErrorResponse);
|
||||
}
|
||||
}).catch((reason: RestErrorResponse) => {
|
||||
reject(reason);
|
||||
});
|
||||
});
|
||||
}
|
||||
export function RESTRequestJsonArray<TYPE>(request: RESTRequestType, checker: (data: any) => data is TYPE): Promise<TYPE[]> {
|
||||
return new Promise((resolve, reject) => {
|
||||
RESTRequest(request).then((value: ModelResponseHttp) => {
|
||||
if (isArrayOf(value.data, checker)) {
|
||||
resolve(value.data);
|
||||
} else {
|
||||
reject({
|
||||
time: Date().toString(),
|
||||
status: 950,
|
||||
error: "REST Fail to verify the data",
|
||||
statusMessage: "API cast ERROR",
|
||||
message: "api.ts Check type as fail"
|
||||
} as RestErrorResponse);
|
||||
}
|
||||
}).catch((reason: RestErrorResponse) => {
|
||||
reject(reason);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function RESTRequestVoid(request: RESTRequestType): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
RESTRequest(request).then((value: ModelResponseHttp) => {
|
||||
resolve();
|
||||
}).catch((reason: RestErrorResponse) => {
|
||||
reject(reason);
|
||||
});
|
||||
});
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
/**
|
||||
* API of the server (auto-generated code)
|
||||
*/
|
||||
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
|
||||
import {UserOut, Long, UserKarusic, isUserOut, isUserKarusic, } from "./model"
|
||||
export namespace UserResource {
|
||||
|
||||
export function get({ restConfig, params, produce, }: {
|
||||
restConfig: RESTConfig,
|
||||
params: {
|
||||
id: Long,
|
||||
},
|
||||
produce: HTTPMimeType.JSON,
|
||||
}): Promise<UserKarusic> {
|
||||
return RESTRequestJson({
|
||||
restModel: {
|
||||
endPoint: "/users/{id}",
|
||||
requestType: HTTPRequestModel.GET,
|
||||
accept: produce,
|
||||
},
|
||||
restConfig,
|
||||
params,
|
||||
}, isUserKarusic);
|
||||
};
|
||||
export function gets({ restConfig, produce, }: {
|
||||
restConfig: RESTConfig,
|
||||
produce: HTTPMimeType.JSON,
|
||||
}): Promise<UserKarusic[]> {
|
||||
return RESTRequestJsonArray({
|
||||
restModel: {
|
||||
endPoint: "/users",
|
||||
requestType: HTTPRequestModel.GET,
|
||||
accept: produce,
|
||||
},
|
||||
restConfig,
|
||||
}, isUserKarusic);
|
||||
};
|
||||
export function getMe({ restConfig, produce, }: {
|
||||
restConfig: RESTConfig,
|
||||
produce: HTTPMimeType.JSON,
|
||||
}): Promise<UserOut> {
|
||||
return RESTRequestJson({
|
||||
restModel: {
|
||||
endPoint: "/users/me",
|
||||
requestType: HTTPRequestModel.GET,
|
||||
accept: produce,
|
||||
},
|
||||
restConfig,
|
||||
}, isUserOut);
|
||||
};
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
<!--<canvas width="200" height="250" style="border:1px solid #d3d3d3;" id="imageCanvas" #imageCanvas></canvas>-->
|
||||
<img src="{{cover}}"/>
|
@ -1,5 +0,0 @@
|
||||
|
||||
img {
|
||||
max-height: 250px;
|
||||
max-width: 200px;
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2018, Edouard DUPIN, all right reserved
|
||||
* @license PROPRIETARY (see license file)
|
||||
*/
|
||||
import { Component, OnInit, Input } from '@angular/core';
|
||||
//import { ModelResponseHttp } from '@app/service/http-wrapper';
|
||||
import { DataService } from 'app/service/data';
|
||||
|
||||
@Component({
|
||||
selector: 'data-image',
|
||||
templateUrl: './data-image.html',
|
||||
styleUrls: ['./data-image.less']
|
||||
})
|
||||
export class ElementDataImageComponent implements OnInit {
|
||||
// input parameters
|
||||
@Input() id: string = "0";
|
||||
cover: string = '';
|
||||
/*
|
||||
imageCanvas:any;
|
||||
@ViewChild('imageCanvas')
|
||||
set mainDivEl(el: ElementRef) {
|
||||
if(el !== null && el !== undefined) {
|
||||
this.imageCanvas = el.nativeElement;
|
||||
}
|
||||
}
|
||||
*/
|
||||
constructor(private dataService: DataService) {
|
||||
|
||||
}
|
||||
ngOnInit() {
|
||||
this.cover = this.dataService.getThumbnailUrl(this.id);
|
||||
/*
|
||||
let canvas = this.imageCanvas.nativeElement;
|
||||
let ctx = canvas.getContext("2d");
|
||||
console.log(`Request thumbnail for ---> ${this.id}`);
|
||||
this.dataService.getImageThumbnail(this.id)
|
||||
.then((result:ModelResponseHttp) => {
|
||||
console.log(`plop ---> ${result.status}`);
|
||||
const response = result.data as Response;
|
||||
response.blob().then((value:Blob) => {
|
||||
let img = new Image();
|
||||
img.onload = function() {
|
||||
//ctx.drawImage(img, 0, 0)
|
||||
}
|
||||
let imageUrl = URL.createObjectURL(value);
|
||||
console.log(`get new image url blob: ${imageUrl}`);
|
||||
//img.src = imageUrl;
|
||||
})
|
||||
|
||||
}).catch(()=>{
|
||||
console.log("plop ---> ");
|
||||
});
|
||||
//img.src = "../../assets/aCRF-PRV111_CLN-001 v1.4-images/aCRF-PRV111_CLN-001 v1.4-blank_0.jpg";
|
||||
//ctx.drawImage(img, 10, 10, 250, 250);
|
||||
*/
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
<div class="fill-title">
|
||||
<div class="description-area">
|
||||
@if(title) {
|
||||
<div class="shadow-text title">
|
||||
{{title}}
|
||||
</div>
|
||||
}
|
||||
@if(name) {
|
||||
<div class="shadow-text sub-title-main">
|
||||
{{name}}
|
||||
</div>
|
||||
}
|
||||
@if(description) {
|
||||
<div class="description">
|
||||
{{description}}
|
||||
</div>
|
||||
}
|
||||
<div class="button-area">
|
||||
<button class="circular-button" (click)="playAll($event)" type="submit">
|
||||
<i class="material-icons">play_arrow</i>
|
||||
</button>
|
||||
<button class="circular-button" (click)="playShuffle($event)" type="submit">
|
||||
<i class="material-icons">shuffle</i>
|
||||
</button>
|
||||
<div style="flex:1;"></div>
|
||||
</div>
|
||||
</div>
|
||||
@if (cover1 && cover1.length > 0) {
|
||||
<div class="cover-area">
|
||||
<div class="cover">
|
||||
<img src="{{cover1[0]}}"/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@if (cover2 && cover2.length > 0) {
|
||||
<div class="cover-area">
|
||||
<div class="cover">
|
||||
<img src="{{cover2[0]}}"/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
@ -1,31 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2018, Edouard DUPIN, all right reserved
|
||||
* @license PROPRIETARY (see license file)
|
||||
*/
|
||||
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'description-area',
|
||||
templateUrl: './description-area.html',
|
||||
styleUrls: ['./description-area.less']
|
||||
})
|
||||
export class DescriptionAreaComponent {
|
||||
@Input() title: string;
|
||||
@Input() name?: string;
|
||||
@Input() description?: string;
|
||||
@Input() cover1?: number[];
|
||||
@Input() cover2?: number[];
|
||||
|
||||
@Output() play = new EventEmitter<void>();
|
||||
@Output() shuffle = new EventEmitter<void>();
|
||||
|
||||
playShuffle(event: any): void {
|
||||
this.shuffle.emit();
|
||||
}
|
||||
|
||||
playAll(event: any): void {
|
||||
this.play.emit();
|
||||
}
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
@if(mediaSource) {
|
||||
<div>
|
||||
<audio width="1" height="1" src="{{mediaSource}}"
|
||||
#mediaPlayer
|
||||
preload
|
||||
(play)="changeStateToPlay()"
|
||||
(pause)="changeStateToPause()"
|
||||
(timeupdate)="changeTimeupdate($event.currentTime)"
|
||||
(durationchange)="changeDurationchange($event.duration)"
|
||||
(loadedmetadata)="changeMetadata()"
|
||||
autoplay
|
||||
(ended)="onAudioEnded()"
|
||||
>
|
||||
</audio>
|
||||
<div class="controls">
|
||||
<div class="controls-inner">
|
||||
<div class="title text-ellipsis">
|
||||
<label class="unselectable">{{dataTitle}}</label>
|
||||
</div>
|
||||
<div class="text-ellipsis">
|
||||
<label class="unselectable">{{dataAuthor}} / {{dataAlbum}}</label>
|
||||
</div>
|
||||
<div class="timer-slider">
|
||||
<input type="range" min="0" class="slider"
|
||||
[value]="currentTime"
|
||||
[max]="duration"
|
||||
(input)="seek($event.target)">
|
||||
</div>
|
||||
<div class="flex-row">
|
||||
<label class="unselectable">{{currentTimeDisplay}}</label>
|
||||
<label class="unselectable flex-row-last">{{durationDisplay}}</label>
|
||||
</div>
|
||||
<div class="control">
|
||||
@if(!isPlaying) {
|
||||
<button (click)="onPlay()"><i class="material-icons">play_arrow</i></button>
|
||||
}
|
||||
@else {
|
||||
<button (click)="onPause()"><i class="material-icons">pause</i></button>
|
||||
}
|
||||
<button (click)="onStop()"><i class="material-icons">stop</i></button>
|
||||
<div style="margin:auto"></div>
|
||||
<button [disabled]="havePrevious" (click)="onBefore()"><i class="material-icons">navigate_before</i></button>
|
||||
<button (click)="onRewind()"><i class="material-icons">fast_rewind</i></button>
|
||||
<button (click)="onForward()"><i class="material-icons">fast_forward</i></button>
|
||||
<button [disabled]="haveNext" (click)="onNext()"><i class="material-icons">navigate_next</i></button>
|
||||
<div style="margin:auto"></div>
|
||||
<button (click)="onPlayMode()"><i class="material-icons">{{playMode}}</i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
@ -1,113 +0,0 @@
|
||||
.controls {
|
||||
//visibility: hidden;
|
||||
opacity: 0.85;
|
||||
width: 96%;
|
||||
//height: 150px;
|
||||
border-radius: 10px;
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
left: 2%;
|
||||
//margin-left: -200px;
|
||||
background-color: black;
|
||||
box-shadow: 3px 3px 5px black;
|
||||
transition: 1s all;
|
||||
display: flex;
|
||||
font-size: 40px;
|
||||
min-width: 380px;
|
||||
|
||||
|
||||
.controls-inner {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-width: 350px;
|
||||
font-family: monospace;
|
||||
color: white;
|
||||
margin: 10px 15px 1px 15px;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.material-icons {
|
||||
color: #FFF;
|
||||
font-size: 40px;
|
||||
}
|
||||
|
||||
button {
|
||||
border: none;
|
||||
background: none;
|
||||
}
|
||||
|
||||
button:disabled,
|
||||
button[disabled] {
|
||||
.material-icons {
|
||||
color: rgb(46, 46, 46);
|
||||
}
|
||||
}
|
||||
|
||||
.slider {
|
||||
position: relative;
|
||||
//-webkit-appearance: none;
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
top: 5px;
|
||||
border-radius: 5px;
|
||||
background: #d3d3d3;
|
||||
outline: none;
|
||||
opacity: 0.7;
|
||||
-webkit-transition: .2s;
|
||||
transition: opacity .2s;
|
||||
flex: 5;
|
||||
}
|
||||
|
||||
.slider::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
border-radius: 50%;
|
||||
background: #4CAF50;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.slider::-moz-range-thumb {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
border-radius: 50%;
|
||||
background: #4CAF50;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.text-ellipsis {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.timer-slider {
|
||||
width: 100%;
|
||||
margin: 4px 0px 4px 0px;
|
||||
font-size: 20px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
|
||||
.control {
|
||||
width: 100%;
|
||||
font-size: 30px;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
button:before {
|
||||
font-family: HeydingsControlsRegular;
|
||||
font-size: 30px;
|
||||
position: relative;
|
||||
color: #FFF;
|
||||
}
|
@ -1,359 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2018, Edouard DUPIN, all right reserved
|
||||
* @license PROPRIETARY (see license file)
|
||||
*/
|
||||
import { Component, OnInit, ViewChild, ElementRef, Inject } from '@angular/core';
|
||||
|
||||
import { DataService, PlayerService, TrackService, AlbumService, ArtistService } from 'app/service';
|
||||
import { PlaylistCurrent } from 'app/service/player';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
import { Album, Artist, Track } from 'app/back-api';
|
||||
import { isArray, isNullOrUndefined, Environment } from '@kangaroo-and-rabbit/kar-cw';
|
||||
|
||||
|
||||
export enum PlayMode {
|
||||
PLAY_ONE = "check",
|
||||
PLAY_ALL = "trending_flat",
|
||||
PLAY_ONE_LOOP = "repeat_one",
|
||||
PLAY_ALL_LOOP = "repeat",
|
||||
};
|
||||
|
||||
// note: all the input is managed with the player service ...
|
||||
@Component({
|
||||
selector: 'app-element-player-audio',
|
||||
templateUrl: './element-player-audio.html',
|
||||
styleUrls: ['./element-player-audio.less']
|
||||
})
|
||||
export class ElementPlayerAudioComponent implements OnInit {
|
||||
mediaPlayer: HTMLAudioElement;
|
||||
duration: number;
|
||||
durationDisplay: string;
|
||||
@ViewChild('mediaPlayer')
|
||||
set mainVideoEl(el: ElementRef) {
|
||||
if (el !== null && el !== undefined) {
|
||||
this.mediaPlayer = el.nativeElement;
|
||||
}
|
||||
}
|
||||
public mediaSource: string = undefined;
|
||||
|
||||
public name: string = 'rr';
|
||||
public description: string;
|
||||
|
||||
public countTrack: number;
|
||||
|
||||
public covers: string[];
|
||||
|
||||
public volume_value: number = 100;
|
||||
public volume_displayMenu: boolean = false;
|
||||
|
||||
dataTitle: string;
|
||||
dataAlbum: string;
|
||||
dataAuthor: string;
|
||||
playStream: boolean;
|
||||
isPlaying: boolean;
|
||||
currentTime: any;
|
||||
currentTimeDisplay: string;
|
||||
havePrevious: boolean = false;
|
||||
haveNext: boolean = false;
|
||||
playMode: PlayMode = PlayMode.PLAY_ALL;
|
||||
onPlayMode() {
|
||||
if (this.playMode === PlayMode.PLAY_ONE) {
|
||||
this.playMode = PlayMode.PLAY_ALL;
|
||||
} else if (this.playMode === PlayMode.PLAY_ALL) {
|
||||
this.playMode = PlayMode.PLAY_ONE_LOOP;
|
||||
} else if (this.playMode === PlayMode.PLAY_ONE_LOOP) {
|
||||
this.playMode = PlayMode.PLAY_ALL_LOOP;
|
||||
} else {
|
||||
this.playMode = PlayMode.PLAY_ONE;
|
||||
}
|
||||
}
|
||||
constructor(
|
||||
@Inject('ENVIRONMENT') private environment: Environment,
|
||||
private playerService: PlayerService,
|
||||
private trackService: TrackService,
|
||||
private dataService: DataService,
|
||||
private albumService: AlbumService,
|
||||
private artistService: ArtistService,
|
||||
private titleService: Title) {
|
||||
// nothing to do...
|
||||
}
|
||||
private currentLMedia: Track;
|
||||
private localIdStreaming: number;
|
||||
private localListStreaming: number[] = [];
|
||||
ngOnInit() {
|
||||
/*
|
||||
export interface PlaylistCurrent {
|
||||
playTrackList: number[];
|
||||
trackLocalId?: number;
|
||||
}
|
||||
*/
|
||||
let self = this;
|
||||
this.playerService.playChange.subscribe((newProperty: PlaylistCurrent) => {
|
||||
self.localIdStreaming = newProperty.trackLocalId;
|
||||
self.localListStreaming = newProperty.playTrackList;
|
||||
self.updateMediaStreamed();
|
||||
});
|
||||
}
|
||||
updateMediaStreamed() {
|
||||
if (isNullOrUndefined(this.localIdStreaming)) {
|
||||
this.mediaSource = undefined;
|
||||
return;
|
||||
}
|
||||
let self = this;
|
||||
this.havePrevious = this.localIdStreaming <= 0;
|
||||
this.haveNext = this.localIdStreaming >= this.localListStreaming.length - 1;
|
||||
this.trackService.get(this.localListStreaming[this.localIdStreaming])
|
||||
.then((response: Track) => {
|
||||
console.log(`get response of video : ${JSON.stringify(response, null, 2)}`);
|
||||
self.currentLMedia = response;
|
||||
self.dataTitle = response.name;
|
||||
if (!isNullOrUndefined(response.albumId)) {
|
||||
this.albumService.get(response.albumId)
|
||||
.then((response2: Album) => {
|
||||
self.dataAlbum = response2.name;
|
||||
self.updateTitle();
|
||||
})
|
||||
.catch(() => { });
|
||||
}
|
||||
if (!isNullOrUndefined(response.artists) && isArray(response.artists) && response.artists.length > 0) {
|
||||
this.artistService.get(response.artists[0])
|
||||
.then((response2: Artist) => {
|
||||
self.dataAuthor = response2.name;
|
||||
})
|
||||
.catch(() => { });
|
||||
}
|
||||
if (isNullOrUndefined(self.currentLMedia)) {
|
||||
console.log("Can not retrieve the media ...")
|
||||
return;
|
||||
}
|
||||
if (isNullOrUndefined(self.currentLMedia.dataId)) {
|
||||
console.log("Can not retrieve the media ... null or undefined data ID")
|
||||
return;
|
||||
}
|
||||
self.mediaSource = self.dataService.getUrl(self.currentLMedia.dataId, "unknownMediaName.webm");
|
||||
}).catch((error) => {
|
||||
console.error(`error not unmanaged in audio player ... 111 ${error}`);
|
||||
})
|
||||
}
|
||||
updateTitle() {
|
||||
let title = this.dataTitle;
|
||||
if (!isNullOrUndefined(this.dataAlbum)) {
|
||||
title = `${this.dataAlbum} - ${title}`;
|
||||
}
|
||||
if (!isNullOrUndefined(this.dataAuthor)) {
|
||||
title = `${title} (${this.dataAuthor})`;
|
||||
}
|
||||
|
||||
this.titleService.setTitle(`${this.environment.applName} > ${title}`)
|
||||
}
|
||||
changeMetadata() {
|
||||
console.log('list of the stream:');
|
||||
}
|
||||
myPeriodicCheckFunction() {
|
||||
console.log('check ... ');
|
||||
}
|
||||
onRequirePlay() {
|
||||
this.playStream = true;
|
||||
}
|
||||
onRequireStop() {
|
||||
|
||||
this.playStream = false;
|
||||
}
|
||||
onAudioEnded() {
|
||||
if (this.playMode === PlayMode.PLAY_ONE) {
|
||||
this.playStream = false;
|
||||
} else if (this.playMode === PlayMode.PLAY_ALL) {
|
||||
this.onNext();
|
||||
} else if (this.playMode === PlayMode.PLAY_ONE_LOOP) {
|
||||
this.mediaPlayer.currentTime = 0;
|
||||
this.onPlay();
|
||||
} else {
|
||||
if (this.localIdStreaming == this.localListStreaming.length - 1) {
|
||||
this.localIdStreaming = 0;
|
||||
this.updateMediaStreamed();
|
||||
if (this.localListStreaming.length == 1) {
|
||||
this.mediaPlayer.currentTime = 0;
|
||||
this.onPlay();
|
||||
}
|
||||
} else {
|
||||
this.onNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
changeStateToPlay() {
|
||||
this.isPlaying = true;
|
||||
}
|
||||
changeStateToPause() {
|
||||
this.isPlaying = false;
|
||||
}
|
||||
|
||||
convertInDisplayTime(time: number): string {
|
||||
let temporaryValue = parseInt(`${time}`, 10);
|
||||
let hours = parseInt(`${temporaryValue / 3600}`, 10);
|
||||
temporaryValue = temporaryValue - hours * 3600;
|
||||
let minutes = parseInt(`${temporaryValue / 60}`, 10);
|
||||
let seconds = temporaryValue - minutes * 60;
|
||||
let out = '';
|
||||
if (hours !== 0) {
|
||||
out = `${out}${hours}:`;
|
||||
}
|
||||
if (minutes >= 10) {
|
||||
out = `${out}${minutes}:`;
|
||||
} else {
|
||||
out = `${out}0${minutes}:`;
|
||||
}
|
||||
if (seconds >= 10) {
|
||||
out = out + seconds;
|
||||
} else {
|
||||
out = `${out}0${seconds}`;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
changeTimeupdate(currentTime: any) {
|
||||
// console.log("time change ");
|
||||
// console.log(" ==> " + this.audioPlayer.currentTime);
|
||||
this.currentTime = this.mediaPlayer.currentTime;
|
||||
this.currentTimeDisplay = this.convertInDisplayTime(this.currentTime);
|
||||
// console.log(" ==> " + this.currentTimeDisplay);
|
||||
}
|
||||
changeDurationchange(duration: any) {
|
||||
console.log('duration change ');
|
||||
console.log(` ==> ${this.mediaPlayer.duration}`);
|
||||
this.duration = this.mediaPlayer.duration;
|
||||
this.durationDisplay = this.convertInDisplayTime(this.duration);
|
||||
}
|
||||
|
||||
onPlay() {
|
||||
console.log('play');
|
||||
if (isNullOrUndefined(this.mediaPlayer)) {
|
||||
console.log(`error element: ${this.mediaPlayer}`);
|
||||
return;
|
||||
}
|
||||
this.lockPlayerEnable();
|
||||
this.mediaPlayer.play();
|
||||
}
|
||||
|
||||
onPause() {
|
||||
console.log('pause');
|
||||
if (isNullOrUndefined(this.mediaPlayer)) {
|
||||
console.log(`error element: ${this.mediaPlayer}`);
|
||||
return;
|
||||
}
|
||||
this.unlockPlayerEnable();
|
||||
this.mediaPlayer.pause();
|
||||
}
|
||||
|
||||
onPauseToggle() {
|
||||
console.log('pause toggle ...');
|
||||
if (this.isPlaying === true) {
|
||||
this.onPause();
|
||||
} else {
|
||||
this.onPlay();
|
||||
}
|
||||
}
|
||||
|
||||
onStop() {
|
||||
console.log('stop');
|
||||
if (this.mediaPlayer.paused && this.mediaPlayer.currentTime == 0) {
|
||||
this.mediaSource = null;
|
||||
return;
|
||||
}
|
||||
if (isNullOrUndefined(this.mediaPlayer)) {
|
||||
console.log(`error element: ${this.mediaPlayer}`);
|
||||
return;
|
||||
}
|
||||
this.unlockPlayerEnable();
|
||||
this.mediaPlayer.pause();
|
||||
this.mediaPlayer.currentTime = 0;
|
||||
}
|
||||
|
||||
onBefore() {
|
||||
console.log('before');
|
||||
if (this.localIdStreaming <= 0) {
|
||||
console.error("have no previous !!!");
|
||||
return;
|
||||
}
|
||||
this.localIdStreaming--;
|
||||
this.updateMediaStreamed();
|
||||
this.playerService.previous();
|
||||
}
|
||||
|
||||
onNext() {
|
||||
console.log('next');
|
||||
if (this.localIdStreaming >= this.localListStreaming.length - 1) {
|
||||
console.error("have no next !!!");
|
||||
return;
|
||||
}
|
||||
this.localIdStreaming++;
|
||||
this.updateMediaStreamed();
|
||||
this.playerService.next();
|
||||
}
|
||||
|
||||
seek(newValue: any) {
|
||||
console.log(`seek ${newValue.value}`);
|
||||
if (isNullOrUndefined(this.mediaPlayer)) {
|
||||
console.log(`error element: ${this.mediaPlayer}`);
|
||||
return;
|
||||
}
|
||||
this.mediaPlayer.currentTime = newValue.value;
|
||||
}
|
||||
|
||||
onRewind() {
|
||||
console.log('rewind');
|
||||
if (isNullOrUndefined(this.mediaPlayer)) {
|
||||
console.log(`error element: ${this.mediaPlayer}`);
|
||||
return;
|
||||
}
|
||||
this.mediaPlayer.currentTime = this.currentTime - 10;
|
||||
}
|
||||
|
||||
onForward() {
|
||||
console.log('forward');
|
||||
if (isNullOrUndefined(this.mediaPlayer)) {
|
||||
console.log(`error element: ${this.mediaPlayer}`);
|
||||
return;
|
||||
}
|
||||
this.mediaPlayer.currentTime = this.currentTime + 10;
|
||||
}
|
||||
|
||||
onMore() {
|
||||
console.log('more');
|
||||
if (isNullOrUndefined(this.mediaPlayer)) {
|
||||
console.log(`error element: ${this.mediaPlayer}`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// these element is to permit to not stop music when sceen is off !!
|
||||
wakeLock = null;
|
||||
unlockPlayerEnable() {
|
||||
let temporaryValue = this.wakeLock;
|
||||
this.wakeLock = null;
|
||||
if (!isNullOrUndefined(temporaryValue)) {
|
||||
console.log(`plopppp ${temporaryValue}`);
|
||||
temporaryValue.release();
|
||||
}
|
||||
try {
|
||||
let tmp = navigator as any;
|
||||
this.wakeLock = tmp.wakeLock.request('screen');
|
||||
} catch (err) {
|
||||
// The Wake Lock request has failed - usually system related, such as battery.
|
||||
console.log(`Can not lock screen element: ${err.name}, ${err.message}`);
|
||||
}
|
||||
}
|
||||
async lockPlayerEnable() {
|
||||
if ('wakeLock' in navigator) {
|
||||
try {
|
||||
let tmp = navigator as any;
|
||||
this.wakeLock = await tmp.wakeLock.request('screen');
|
||||
} catch (err) {
|
||||
// The Wake Lock request has failed - usually system related, such as battery.
|
||||
console.log(`Can not lock screen element: ${err.name}, ${err.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
|
||||
<div class="imgContainer-small">
|
||||
@if(covers && covers.length > 0) {
|
||||
<div>
|
||||
<img src="{{covers[0]}}"/>
|
||||
</div>
|
||||
}
|
||||
@else {
|
||||
<div class="noImage"></div>
|
||||
}
|
||||
</div>
|
||||
<div class="season-small">
|
||||
{{prefixName}} {{numberAlbum}}
|
||||
</div>
|
||||
@if(countSubType) {
|
||||
<div class="description-small">
|
||||
@if(!count || count == 0) {
|
||||
No {{countSubType}}
|
||||
}
|
||||
@else {
|
||||
{{count}} {{countSubType}}{{count>1?"s":""}}
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
@if(countSubType2) {
|
||||
<div class="description-small">
|
||||
@if(!count2 || count2 == 0) {
|
||||
No {{countSubType2}}
|
||||
}
|
||||
@else {
|
||||
{{count2}} {{countSubType2}}{{count2>1?"s":""}}
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@if(subValueData) {
|
||||
<div class="description-small">
|
||||
{{subValues}}: {{subValueData}}
|
||||
</div>
|
||||
}
|
||||
@if(!description) {
|
||||
<div class="description-small">
|
||||
{{description}}
|
||||
</div>
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
|
||||
.imgContainer-small {
|
||||
text-align: center;
|
||||
width: 100px;
|
||||
margin: 4px 15px 4px 10px;
|
||||
height: 100px;
|
||||
img {
|
||||
max-height: 100px;
|
||||
max-width: 100px;
|
||||
}
|
||||
.noImage {
|
||||
height: 95px;
|
||||
width: 95px;
|
||||
//box-shadow: 0px 2px 4px 0 rgba(0, 0, 0, 0.7);
|
||||
border: solid 2px;
|
||||
border-color: rgba(0, 0, 0, 0.7);
|
||||
margin: auto;
|
||||
}
|
||||
float: left;
|
||||
}
|
||||
|
||||
.title-small {
|
||||
height: 50px;
|
||||
//width: 100%;
|
||||
font-size: 35px;
|
||||
display:inline-block;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.description-small {
|
||||
height: 30px;
|
||||
font-size: 16px;
|
||||
overflow:hidden;
|
||||
vertical-align: middle;
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2018, Edouard DUPIN, all right reserved
|
||||
* @license PROPRIETARY (see license file)
|
||||
*/
|
||||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { isNullOrUndefined } from '@kangaroo-and-rabbit/kar-cw';
|
||||
import { NodeSmall } from 'app/back-api';
|
||||
|
||||
import { AlbumService, DataService } from 'app/service';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-element-season',
|
||||
templateUrl: './element-season.html',
|
||||
styleUrls: ['./element-season.less']
|
||||
})
|
||||
export class ElementSeasonComponent implements OnInit {
|
||||
// input parameters
|
||||
@Input() element: NodeSmall;
|
||||
@Input() prefix: String;
|
||||
@Input() countSubTypeCallBack: (arg0: number) => Promise<number>;
|
||||
@Input() countSubType: String;
|
||||
@Input() countSubType2CallBack: (arg0: number) => Promise<number>;
|
||||
@Input() countSubType2: String;
|
||||
@Input() subValuesCallBack: (arg0: number) => Promise<string[]>;
|
||||
@Input() subValues: String;
|
||||
|
||||
prefixName: string = "";
|
||||
numberAlbum: string;
|
||||
count: number;
|
||||
count2: number;
|
||||
subValueData: String;
|
||||
covers: string[];
|
||||
description: string;
|
||||
|
||||
constructor(
|
||||
private albumService: AlbumService,
|
||||
private dataService: DataService) {
|
||||
|
||||
}
|
||||
ngOnInit() {
|
||||
this.prefix = this.prefixName ?? "";
|
||||
this.count = undefined;
|
||||
this.count2 = undefined;
|
||||
//console.log(`element: ${JSON.stringify(this.element, null, 2)}`);
|
||||
|
||||
if (isNullOrUndefined(this.element)) {
|
||||
this.numberAlbum = undefined;
|
||||
this.covers = undefined;
|
||||
this.description = undefined;
|
||||
}
|
||||
this.numberAlbum = this.element.name;
|
||||
this.description = this.element.description;
|
||||
this.covers = this.dataService.getListThumbnailUrl(this.element.covers);
|
||||
let self = this;
|
||||
if (!isNullOrUndefined(this.countSubTypeCallBack)) {
|
||||
this.countSubTypeCallBack(this.element.id)
|
||||
.then((response) => {
|
||||
self.count = response;
|
||||
//console.log(`get values: ${this.element.id} ==> ${self.count}`)
|
||||
}).catch((response) => {
|
||||
self.count = undefined;
|
||||
});
|
||||
}
|
||||
if (!isNullOrUndefined(this.countSubType2CallBack)) {
|
||||
this.countSubType2CallBack(this.element.id)
|
||||
.then((response) => {
|
||||
self.count2 = response;
|
||||
//console.log(`get values: ${this.element.id} ==> ${self.count}`)
|
||||
}).catch((response) => {
|
||||
self.count2 = undefined;
|
||||
});
|
||||
}
|
||||
if (!isNullOrUndefined(this.subValuesCallBack)) {
|
||||
//console.log(`Value call back define ==> call values`)
|
||||
this.subValuesCallBack(this.element.id)
|
||||
.then((response: string[]) => {
|
||||
this.subValueData = "";
|
||||
for (let kkk = 0; kkk < response.length; kkk++) {
|
||||
if (kkk != 0) {
|
||||
this.subValueData += ", ";
|
||||
}
|
||||
this.subValueData += response[kkk];
|
||||
}
|
||||
//console.log(`get values: ${this.element.id} ==> ${self.subValueData}`)
|
||||
}).catch((response) => {
|
||||
self.count2 = undefined;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
<div>
|
||||
<div class="count-base">
|
||||
@if(countTrack) {
|
||||
<div class="count">
|
||||
{{countTrack}}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="imgContainer-small">
|
||||
@if(covers && covers.length > 0) {
|
||||
<div>
|
||||
<!--<data-image id="{{cover}}"></data-image>-->
|
||||
<img src="{{covers[0]}}"/>
|
||||
</div>
|
||||
}
|
||||
@else {
|
||||
<div class="noImage"></div>
|
||||
}
|
||||
</div>
|
||||
<div class="title-small">
|
||||
{{name}}
|
||||
</div>
|
||||
</div>
|
@ -1,63 +0,0 @@
|
||||
|
||||
.count-base {
|
||||
height: 0px;
|
||||
width: 0px;
|
||||
.count {
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
font-size: 17px;
|
||||
line-height: 30px;
|
||||
overflow:hidden;
|
||||
position:relative;
|
||||
z-index: 12;
|
||||
left: 165px;
|
||||
top: 2px;
|
||||
text-align: center;
|
||||
//padding: 5px 10px;
|
||||
color: rgba(0, 0, 0, 1.0);
|
||||
background: rgba(256, 256, 256, 0.3);
|
||||
border: 1px solid;
|
||||
border-color: rgba(256, 256, 256, 0.8);
|
||||
border-radius: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.imgContainer-small {
|
||||
right: 2px;
|
||||
top: 2px;
|
||||
text-align: center;
|
||||
width: 200px;
|
||||
margin: 0 auto;
|
||||
height: 250px;
|
||||
img {
|
||||
//width: 100%;
|
||||
max-height: 250px;
|
||||
max-width: 200px;
|
||||
}
|
||||
.noImage {
|
||||
height: 243px;
|
||||
width: 193px;
|
||||
border: solid 3px;
|
||||
border-color: rgba(0, 0, 0, 0.7);
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.title-small {
|
||||
height: 40px;
|
||||
width: 200px;
|
||||
font-size: 17px;
|
||||
overflow:hidden;
|
||||
display:inline-block;
|
||||
text-align: center;
|
||||
padding:auto;
|
||||
background: rgba(256, 256, 256, 0.3);
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
.description-small {
|
||||
height: 30px;
|
||||
font-size: 12px;
|
||||
overflow:hidden;
|
||||
vertical-align: middle;
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2018, Edouard DUPIN, all right reserved
|
||||
* @license PROPRIETARY (see license file)
|
||||
*/
|
||||
import { Component, OnInit, Input } from '@angular/core';
|
||||
|
||||
import { DataService, TrackService } from 'app/service';
|
||||
import { NodeSmall } from 'app/back-api';
|
||||
import { isNullOrUndefined } from '@kangaroo-and-rabbit/kar-cw';
|
||||
|
||||
@Component({
|
||||
selector: 'app-element-series',
|
||||
templateUrl: './element-series.html',
|
||||
styleUrls: ['./element-series.less']
|
||||
})
|
||||
export class ElementSeriesComponent implements OnInit {
|
||||
// input parameters
|
||||
@Input() element: NodeSmall;
|
||||
|
||||
name: string = 'plouf';
|
||||
description: string = '';
|
||||
countTrack: number = null;
|
||||
|
||||
covers: string[];
|
||||
|
||||
constructor(
|
||||
private trackService: TrackService,
|
||||
private dataService: DataService) {
|
||||
|
||||
}
|
||||
ngOnInit() {
|
||||
if (isNullOrUndefined(this.element)) {
|
||||
this.name = '!!ERROR!!';
|
||||
this.description = undefined;
|
||||
return;
|
||||
}
|
||||
this.name = this.element.name;
|
||||
this.description = this.element.description;
|
||||
this.covers = this.dataService.getListThumbnailUrl(this.element.covers);
|
||||
|
||||
this.trackService.countTracksOfAnArtist(this.element.id)
|
||||
.then((response) => {
|
||||
this.countTrack = response;
|
||||
}).catch((response) => {
|
||||
this.countTrack = 0;
|
||||
});
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
<div class="item-list-element">
|
||||
<div class="season-small">
|
||||
{{name}}
|
||||
</div>
|
||||
@if(track) {
|
||||
<div class="description-small">
|
||||
n° {{track}}
|
||||
</div>
|
||||
}
|
||||
</div>
|
@ -1,47 +0,0 @@
|
||||
|
||||
|
||||
.item-list-element {
|
||||
font-size: 20px;
|
||||
padding: 1px;
|
||||
height: 55px;
|
||||
width: 80%;
|
||||
margin: 5px auto 5px auto;
|
||||
padding: 5px;
|
||||
overflow: hidden;
|
||||
line-height: normal;
|
||||
border: none;
|
||||
font-family: "Roboto","Helvetica","Arial",sans-serif;
|
||||
font-weight: 500;
|
||||
will-change: box-shadow;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
background: rgba(256, 256, 256, 0.3);
|
||||
border-radius: 7px;
|
||||
.material-icons {
|
||||
vertical-align: middle;
|
||||
}
|
||||
.material-icons {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: ~"translate(-12px,-12px)";
|
||||
line-height: 24px;
|
||||
width: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.title-small {
|
||||
height: 50px;
|
||||
//width: 100%;
|
||||
font-size: 35px;
|
||||
display:inline-block;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.description-small {
|
||||
height: 30px;
|
||||
font-size: 16px;
|
||||
overflow:hidden;
|
||||
vertical-align: middle;
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2018, Edouard DUPIN, all right reserved
|
||||
* @license PROPRIETARY (see license file)
|
||||
*/
|
||||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { isNullOrUndefined } from '@kangaroo-and-rabbit/kar-cw';
|
||||
import { NodeSmall } from 'app/back-api';
|
||||
|
||||
import { DataService } from 'app/service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-element-track',
|
||||
templateUrl: './element-track.html',
|
||||
styleUrls: ['./element-track.less']
|
||||
})
|
||||
export class ElementTrackComponent implements OnInit {
|
||||
// input parameters
|
||||
@Input() element: NodeSmall;
|
||||
@Input() prefix: String;
|
||||
|
||||
prefixName: string = "";
|
||||
name: string;
|
||||
track: number;
|
||||
covers: string[];
|
||||
description: string;
|
||||
|
||||
constructor(
|
||||
private dataService: DataService) {
|
||||
|
||||
}
|
||||
ngOnInit() {
|
||||
this.prefix = this.prefixName ?? "";
|
||||
if (isNullOrUndefined(this.element)) {
|
||||
this.name = undefined;
|
||||
this.covers = undefined;
|
||||
this.description = undefined;
|
||||
}
|
||||
this.name = this.element.name;
|
||||
this.description = this.element.description;
|
||||
this.track = this.element["track"];
|
||||
this.covers = this.dataService.getListThumbnailUrl(this.element.covers);
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
<div>
|
||||
@if(countTrack) {
|
||||
<div class="count-base">
|
||||
<span class="count">{{countTrack}}</span>
|
||||
</div>
|
||||
}
|
||||
<div class="imgContainer-small">
|
||||
@if(covers && covers.length > 0) {
|
||||
<div>
|
||||
<img src="{{covers[0]}}" class="miniature-small"/>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="title-small">
|
||||
{{name}}
|
||||
</div>
|
||||
@if(description) {
|
||||
<div class="description-small">
|
||||
{{description}}
|
||||
</div>
|
||||
}
|
||||
</div>
|
@ -1,52 +0,0 @@
|
||||
|
||||
.count-base {
|
||||
height: 0px;
|
||||
width: 100%;
|
||||
right: 0px;
|
||||
z-index: 12;
|
||||
//position:flex;
|
||||
text-align: right;
|
||||
.count {
|
||||
height: 30px;
|
||||
//width: 30px;
|
||||
font-size: 17px;
|
||||
line-height: 30px;
|
||||
overflow:hidden;
|
||||
position:relative;
|
||||
z-index: 12;
|
||||
right: 2px;
|
||||
top: 4px;
|
||||
text-align: right;
|
||||
padding: 5px 10px;
|
||||
color: rgba(0, 0, 0, 1.0);
|
||||
background: rgba(256, 256, 256, 0.3);
|
||||
border: 1px solid;
|
||||
border-color: rgba(256, 256, 256, 0.8);
|
||||
border-radius: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.imgContainer-small {
|
||||
text-align: center;
|
||||
margin: 15px 0 0 0;
|
||||
}
|
||||
|
||||
img.miniature-small {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
//border-radius: 50%;
|
||||
}
|
||||
|
||||
.title-small {
|
||||
height: 60px;
|
||||
font-size: 24px;
|
||||
overflow:hidden;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.description-small {
|
||||
height: 30px;
|
||||
font-size: 12px;
|
||||
overflow:hidden;
|
||||
vertical-align: middle;
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2018, Edouard DUPIN, all right reserved
|
||||
* @license PROPRIETARY (see license file)
|
||||
*/
|
||||
import { Component, OnInit, Input } from '@angular/core';
|
||||
|
||||
import { DataService } from 'app/service';
|
||||
import { NodeSmall } from 'app/back-api';
|
||||
import { isNullOrUndefined } from '@kangaroo-and-rabbit/kar-cw';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-element-type',
|
||||
templateUrl: './element-type.html',
|
||||
styleUrls: ['./element-type.less']
|
||||
})
|
||||
export class ElementTypeComponent implements OnInit {
|
||||
// input parameters
|
||||
@Input() element: NodeSmall;
|
||||
@Input() functionVignette: (number) => Promise<Number>;
|
||||
|
||||
public name: string = 'rr';
|
||||
public description: string;
|
||||
|
||||
public countTrack: number;
|
||||
|
||||
public covers: string[];
|
||||
|
||||
constructor(
|
||||
private dataService: DataService) {
|
||||
|
||||
}
|
||||
ngOnInit() {
|
||||
if (isNullOrUndefined(this.element)) {
|
||||
this.name = 'Not a media';
|
||||
this.description = undefined;
|
||||
this.countTrack = undefined;
|
||||
this.covers = undefined;
|
||||
return;
|
||||
}
|
||||
let self = this;
|
||||
console.log(" ??? Get element ! " + JSON.stringify(this.element));
|
||||
self.name = this.element.name;
|
||||
self.description = this.element.description;
|
||||
self.covers = self.dataService.getListThumbnailUrl(this.element.covers);
|
||||
|
||||
if (!isNullOrUndefined(this.functionVignette)) {
|
||||
this.functionVignette(this.element.id)
|
||||
.then((response: number) => {
|
||||
self.countTrack = response;
|
||||
}).catch(() => {
|
||||
self.countTrack = 0;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
<div>
|
||||
<div class="videoImgContainer">
|
||||
@if(covers && covers.length > 0) {
|
||||
<div>
|
||||
<!--<data-image id="{{cover}}"></data-image>-->
|
||||
<img src="{{covers[0]}}"/>
|
||||
</div>
|
||||
}
|
||||
@else {
|
||||
<div class="noImage"></div>
|
||||
}
|
||||
</div>
|
||||
@if(element) {
|
||||
<div class="title-small">
|
||||
{{episodeDisplay}} {{name}}
|
||||
</div>
|
||||
}
|
||||
@else {
|
||||
<div class="title-small">
|
||||
Error meda: {{element?.id}}
|
||||
</div>
|
||||
}
|
||||
</div>
|
@ -1,38 +0,0 @@
|
||||
|
||||
.videoImgContainer {
|
||||
text-align: center;
|
||||
width: 200px;
|
||||
margin: 0 auto;
|
||||
height: 250px;
|
||||
img {
|
||||
//width: 100%;
|
||||
max-height: 250px;
|
||||
max-width: 200px;
|
||||
}
|
||||
.noImage {
|
||||
height: 243px;
|
||||
width: 193px;
|
||||
border: solid 3px;
|
||||
border-color: rgba(0, 0, 0, 0.7);
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.title-small {
|
||||
height: 40px;
|
||||
width: 200px;
|
||||
font-size: 17px;
|
||||
overflow:hidden;
|
||||
display:inline-block;
|
||||
text-align: center;
|
||||
padding:auto;
|
||||
background: rgba(256, 256, 256, 0.3);
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
.description-small {
|
||||
height: 30px;
|
||||
font-size: 12px;
|
||||
overflow:hidden;
|
||||
vertical-align: middle;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user