Compare commits

..

No commits in common. "061fc51138c48a62945a6eaaebeb1f53ca0ba537" and "8f026d47e1ac9ff2d6b62af433040eb10d986807" have entirely different histories.

250 changed files with 9909 additions and 21404 deletions

1
.gitignore vendored
View File

@ -65,4 +65,3 @@ __pycache__
.design/
.vscode/
front/storybook-static
back/bin

View File

@ -6,7 +6,7 @@
FROM archlinux:base-devel AS common
# update system
RUN pacman -Syu --noconfirm && pacman-db-upgrade \
&& pacman -S --noconfirm jdk-openjdk wget\
&& pacman -S --noconfirm jdk-openjdk \
&& pacman -Scc --noconfirm
WORKDIR /tmp
@ -53,15 +53,14 @@ RUN pnpm install --prod=false
FROM dependency_front AS load_sources_front
# JUST to get the vertion of the application and his sha...
COPY \
COPY front/build.js \
front/version.txt \
front/tsconfig.json \
front/tsconfig.node.json \
front/vite.config.mts \
front/index.html \
./
COPY front/public ./public
COPY front/public/icons ./public/icons
COPY front/src ./src
#We are not in prod mode ==> we need to overwrite the production env.
@ -100,14 +99,8 @@ ENV LANG C.UTF-8
COPY --from=build_back /tmp/out/maven/*.jar /application/application.jar
COPY --from=build_front /tmp/dist /application/front/
# COPY front/public/icons /application/front/public/icons
# COPY front/public/icons /application/front/icons
WORKDIR /application/
EXPOSE 80
# To verify health-check: docker inspect --format "{{json .State.Health }}" YOUR_SERVICE_NAME | jq
HEALTHCHECK --start-period=10s --start-interval=2s --interval=30s --timeout=5s --retries=10 \
CMD wget --no-verbose --tries=1 --spider http://localhost:80/api/health_check || exit 1
CMD ["java", "-Xms64M", "-Xmx1G", "-cp", "/application/application.jar", "org.atriasoft.karusic.WebLauncher"]
CMD ["java", "-Xms64M", "-Xmx1G", "-cp", "/application/application.jar", "org.kar.karusic.WebLauncher"]

View File

@ -1,4 +1,4 @@
Karusic
Karideo
=======
**K**angaroo **A**nd **R**abbit (m)usic is a simple framework to propose music streaming for personal network
@ -6,90 +6,40 @@ Karusic
Run in local:
=============
Start tools
-----------
Start the server basic interfaces: (DB(mySQL), Adminer)
so simple...
```{.bash}
# start the Bdd interface (no big data > 50Mo)
docker compose -f env_dev/docker-compose.yaml up -d
cd bdd
docker-compose up -d
# start the REST API
cd back
docker-compose up -d
# start the front API
cd ../front
docker-compose up -d
```
Start the Back-end:
-------------------
backend is developed in JAVA
convert in an angular application:
https://betterprogramming.pub/how-to-convert-your-angular-application-to-a-native-mobile-app-android-and-ios-c212b38976df
The first step is configuring your JAVA version (or select the JVM with the OS)
```bash
export PATH=$(ls -d --color=never /usr/lib/jvm/java-2*-openjdk)/bin:$PATH
```
Install the dependency:
```bash
mvn install
```
Link with the external sub-library (front)
------------------------------------------
Run the test
```bash
mvn test
```
Install it for external use
```bash
mvn install
```
Execute the local server:
```bash
mvn exec:java@dev-mode
```
Start the Front-end:
--------------------
backend is developed in JAVA
Link:
```bash
cd front
pnpm install
pnpm dev
pnpm run link_kar_cw
```
Display the result:
-------------------
[show the webpage: http://localhost:4203](http://localhost:4203)
Some other dev tools:
=====================
Format code:
------------
un-link:
```bash
export PATH=$(ls -d --color=never /usr/lib/jvm/java-2*-openjdk)/bin:$PATH
mvn formatter:format
mvn test
cd front
pnpm run unlink_kar_cw
```
Tools in production mode
========================
Changing the Log Level
----------------------
In a production environment, you can adjust the log level to help diagnose bugs more effectively.
The available log levels are:
| **Log Level Tag** | **org.atriasoft.karusic** | **org.kar.archidata** | **other** |
| ----------------- | ------------------- | --------------------- | --------- |
| `prod` | INFO | INFO | INFO |
| `prod-debug` | DEBUG | INFO | INFO |
| `prod-trace` | TRACE | DEBUG | INFO |
| `prod-trace-full` | TRACE | TRACE | INFO |
| `dev` | TRACE | DEBUG | INFO |
Manual set in production:
=========================
@ -122,4 +72,4 @@ export TAG_DOCKER=latest
export REGISTRY_ADDRESS=gitea.atria-soft.org
docker build -t ${REGISTRY_ADDRESS}/kangaroo-and-rabbit/karusic:${TAG_DOCKER} .
docker push ${REGISTRY_ADDRESS}/kangaroo-and-rabbit/karusic:${TAG_DOCKER}
```
```

View File

@ -53,9 +53,6 @@ Checkstyle configuration that checks the sun coding conventions.
<module name="LambdaParameterName"/>
<module name="Regexp"/>
<module name="RegexpSinglelineJava"/>
<module name="UnusedPrivateField">
<property name="ignorePattern" value="LOGGER"/>
</module>
</module>
<module name="BeforeExecutionExclusionFileFilter">
<property name="fileNamePattern" value="module\-info\.java$"/>

View File

@ -1,8 +1,7 @@
FROM maven:3-openjdk-23 AS build
FROM maven:3-openjdk-18 AS build
COPY pom.xml /tmp/
COPY src /tmp/src/
COPY Formatter.xml /tmp/
WORKDIR /tmp/
RUN mvn clean compile assembly:single
@ -18,5 +17,5 @@ WORKDIR /application/
EXPOSE 18080
CMD ["java", "-Xms64M", "-Xmx1G", "-cp", "/application/application.jar", "org.atriasoft.karusic.WebLauncher"]
CMD ["java", "-Xms64M", "-Xmx1G", "-cp", "/application/application.jar", "org.kar.karusic.WebLauncher"]

View File

@ -11,7 +11,7 @@ mvn package
// download all dependency in out/maven/dependency
mvn dependency:copy-dependencies
java -cp out/maven/kar-karusic-0.1.0.jar org.atriasoft.karusic.WebLauncher
java -cp out/maven/kar-karusic-0.1.0.jar org.kar.karusic.WebLauncher
// create a single package jar
@ -19,7 +19,7 @@ mvn clean compile assembly:single
java -cp out/maven/karusic-0.1.0-jar-with-dependencies.jar org.atriasoft.karusic.WebLauncher
java -cp out/maven/karusic-0.1.0-jar-with-dependencies.jar org.kar.karusic.WebLauncher

View File

@ -1,14 +1,26 @@
<?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.atriasoft</groupId>
<groupId>org.kar</groupId>
<artifactId>karusic</artifactId>
<version>1.2.0</version>
<version>1.0.4</version>
<properties>
<maven.compiler.version>3.1</maven.compiler.version>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<maven.dependency.version>3.1.1</maven.dependency.version>
</properties>
<repositories>
<repository>
<id>gitea</id>
<url>https://gitea.atria-soft.org/api/packages/kangaroo-and-rabbit/maven</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.atria-soft</groupId>
<groupId>kangaroo-and-rabbit</groupId>
<artifactId>archidata</artifactId>
<version>0.30.4</version>
<version>0.20.4</version>
</dependency>
<!-- Loopback of logger JDK logging API to SLF4J -->
<dependency>
@ -27,15 +39,10 @@
<artifactId>xercesImpl</artifactId>
<version>2.12.2</version>
</dependency>
<dependency>
<groupId>org.codehaus.janino</groupId>
<artifactId>janino</artifactId>
<version>3.1.9</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.18.3</version>
<version>2.18.0-rc1</version>
</dependency>
<!--
************************************************************
@ -45,24 +52,24 @@
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.12.1</version>
<version>5.11.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.12.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.25.0</version>
<version>2.24.1</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.6.0</version>
<version>3.5.0</version>
</dependency>
</dependencies>
<build>
@ -83,54 +90,25 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.0</version>
<version>${maven.compiler.version}</version>
<configuration>
<source>21</source>
<target>21</target>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>prod-mode</id>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>org.atriasoft.karusic.WebLauncher</mainClass>
</configuration>
</execution>
<execution>
<id>dev-mode</id>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>org.atriasoft.karusic.WebLauncherLocal</mainClass>
</configuration>
</execution>
<execution>
<id>generate-api</id>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>org.atriasoft.karusic.GenerateApi</mainClass>
</configuration>
</execution>
</executions>
<version>1.4.0</version>
<configuration>
<mainClass/>
<mainClass>org.kar.karusic.WebLauncher</mainClass>
</configuration>
</plugin>
<!-- Create the source bundle -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>4.0.0-beta-1</version>
<version>3.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
@ -144,12 +122,10 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
<version>3.0.0-M5</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.7.1</version>
<configuration>
<archive>
<manifest>
@ -161,21 +137,81 @@
</descriptorRefs>
</configuration>
</plugin>
<!-- Create coverage -->
<!--
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.10</version>
<executions>
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
<execution>
<id>jacoco-check</id>
<goals>
<goal>check</goal>
</goals>
<configuration>
<rules>
<rule>
<element>PACKAGE</element>
<limits>
<limit>
<counter>LINE</counter>
<value>COVEREDRATIO</value>
<minimum>0.50</minimum>
</limit>
</limits>
</rule>
</rules>
</configuration>
</execution>
</executions>
</plugin>
-->
<!-- Java-doc generation for stand-alone site -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.3.0</version>
<version>3.2.0</version>
<configuration>
<show>private</show>
<nohelp>true</nohelp>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>exec-application</id>
<phase>package</phase>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>org.kar.karusic.WebLauncher</mainClass>
</configuration>
</plugin>
<!-- Check the style of the code -->
<plugin>
<groupId>net.revelc.code.formatter</groupId>
<artifactId>formatter-maven-plugin</artifactId>
<version>2.24.1</version>
<version>2.23.0</version>
<configuration>
<encoding>UTF-8</encoding>
<lineEnding>LF</lineEnding>
@ -206,6 +242,14 @@
<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>
@ -216,7 +260,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.3.0</version>
<version>3.2.0</version>
<configuration>
<show>public</show>
</configuration>

View File

@ -1,9 +1,9 @@
org.atriasoft.karideo.dataTmpFolder=/application/data/tmp
org.atriasoft.karideo.dataTmpFolder=/application/data/media
org.atriasoft.karideo.rest.oauth=http://192.168.1.156:21080/oauth/api/
org.atriasoft.karideo.db.host=1992.156.1.156
org.atriasoft.karideo.db.port=20306
org.atriasoft.karideo.db.login=root
org.atriasoft.karideo.db.port=klkhj456gkgtkhjgvkujfhjgkjhgsdfhb3467465fgdhdesfgh
org.atriasoft.karideo.db.name=karideo
org.atriasoft.karideo.address=http://0.0.0.0:18080/karideo/api/
org.kar.karideo.dataTmpFolder=/application/data/tmp
org.kar.karideo.dataTmpFolder=/application/data/media
org.kar.karideo.rest.oauth=http://192.168.1.156:21080/oauth/api/
org.kar.karideo.db.host=1992.156.1.156
org.kar.karideo.db.port=20306
org.kar.karideo.db.login=root
org.kar.karideo.db.port=klkhj456gkgtkhjgvkujfhjgkjhgsdfhb3467465fgdhdesfgh
org.kar.karideo.db.name=karideo
org.kar.karideo.address=http://0.0.0.0:18080/karideo/api/

View File

@ -1,17 +0,0 @@
package org.atriasoft.karusic;
import org.atriasoft.karusic.migration.Initialization;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class GenerateApi {
private final static Logger LOGGER = LoggerFactory.getLogger(GenerateApi.class);
private GenerateApi() {}
public static void main(final String[] args) throws Exception {
LOGGER.info("Generate API");
Initialization.generateObjects();
LOGGER.info("STOP the REST server.");
}
}

View File

@ -1,52 +0,0 @@
package org.atriasoft.karusic;
import java.util.logging.LogManager;
import org.atriasoft.archidata.exception.DataAccessException;
import org.atriasoft.archidata.tools.ConfigBaseVariable;
import org.atriasoft.karusic.migration.Initialization;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.bridge.SLF4JBridgeHandler;
public class WebLauncherLocal extends WebLauncher {
private static final Logger LOGGER = LoggerFactory.getLogger(WebLauncherLocal.class);
private WebLauncherLocal() {}
public static void main(final String[] args) throws Exception {
// Loop-back of logger JDK logging API to SLF4J
LogManager.getLogManager().reset();
SLF4JBridgeHandler.install();
// Generate the APIs in type-script
Initialization.generateObjects();
final WebLauncherLocal launcher = new WebLauncherLocal();
launcher.process();
LOGGER.info("end-configure the server & wait finish process:");
Thread.currentThread().join();
LOGGER.info("STOP the REST server:");
}
@Override
public void process() throws InterruptedException, DataAccessException {
if (true) {
// for local test:
ConfigBaseVariable.apiAdress = "http://0.0.0.0:19080/karusic/api/";
ConfigBaseVariable.testMode = "true";
ConfigBaseVariable.dbType = "mongo";
}
// Test fail of SSO: ConfigBaseVariable.ssoAdress = null;
try {
super.migrateDB();
} catch (final Exception e) {
e.printStackTrace();
while (true) {
LOGGER.error("============================================================================");
LOGGER.error("== Migration fail ==> waiting intervention of administrator...");
LOGGER.error("============================================================================");
Thread.sleep(60 * 60 * 1000);
}
}
super.process();
}
}

View File

@ -1,99 +0,0 @@
package org.atriasoft.karusic.api;
import java.io.InputStream;
import java.util.List;
import org.atriasoft.archidata.annotation.apiGenerator.ApiInputOptional;
import org.atriasoft.archidata.annotation.apiGenerator.ApiTypeScriptProgress;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.dataAccess.DataAccess;
import org.atriasoft.archidata.dataAccess.addOnSQL.AddOnDataJson;
import org.atriasoft.archidata.tools.DataTools;
import org.atriasoft.karusic.model.Artist;
import org.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.annotation.security.RolesAllowed;
import jakarta.validation.Valid;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
@Path("/artist")
@Produces({ MediaType.APPLICATION_JSON })
public class ArtistResource {
private static final Logger LOGGER = LoggerFactory.getLogger(ArtistResource.class);
@GET
@Path("{oid}")
@RolesAllowed("USER")
public Artist get(@PathParam("oid") final ObjectId oid) throws Exception {
return DataAccess.get(Artist.class, oid);
}
@GET
@RolesAllowed("USER")
public List<Artist> gets() throws Exception {
return DataAccess.gets(Artist.class);
}
@POST
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Artist post(@Valid final Artist data) throws Exception {
return DataAccess.insert(data);
}
@PUT
@Path("{oid}")
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Artist put(@PathParam("oid") final ObjectId oid, @Valid final Artist artist) throws Exception {
artist.oid = oid;
DataAccess.update(artist, oid);
return DataAccess.get(Artist.class, oid);
}
@DELETE
@Path("{oid}")
@RolesAllowed("ADMIN")
public void remove(@PathParam("oid") final ObjectId oid) throws Exception {
DataAccess.delete(Artist.class, oid);
}
@POST
@Path("{oid}/cover")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
@ApiTypeScriptProgress
public Artist uploadCover(@PathParam("oid") final ObjectId oid, @ApiInputOptional @FormDataParam("uri") final String uri,
@ApiInputOptional @FormDataParam("file") final InputStream fileInputStream, @ApiInputOptional @FormDataParam("file") final FormDataContentDisposition fileMetaData) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
if (uri != null) {
DataTools.uploadCoverFromUri(db, Artist.class, oid, uri);
} else {
DataTools.uploadCover(db, Artist.class, oid, fileInputStream, fileMetaData);
}
return db.get(Artist.class, oid);
}
}
@DELETE
@Path("{oid}/cover/{coverId}")
@RolesAllowed("ADMIN")
public Artist removeCover(@PathParam("oid") final ObjectId oid, @PathParam("coverId") final ObjectId coverId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Artist.class, "id", oid, "covers", coverId);
return db.get(Artist.class, oid);
}
}
}

View File

@ -1,99 +0,0 @@
package org.atriasoft.karusic.api;
import java.io.InputStream;
import java.util.List;
import org.atriasoft.archidata.annotation.apiGenerator.ApiInputOptional;
import org.atriasoft.archidata.annotation.apiGenerator.ApiTypeScriptProgress;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.dataAccess.DataAccess;
import org.atriasoft.archidata.dataAccess.addOnSQL.AddOnDataJson;
import org.atriasoft.archidata.tools.DataTools;
import org.atriasoft.karusic.model.Gender;
import org.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.annotation.security.RolesAllowed;
import jakarta.validation.Valid;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
@Path("/gender")
@Produces({ MediaType.APPLICATION_JSON })
public class GenderResource {
private static final Logger LOGGER = LoggerFactory.getLogger(GenderResource.class);
@GET
@Path("{oid}")
@RolesAllowed("USER")
public Gender get(@PathParam("oid") final ObjectId oid) throws Exception {
return DataAccess.get(Gender.class, oid);
}
@GET
@RolesAllowed("USER")
public List<Gender> gets() throws Exception {
return DataAccess.gets(Gender.class);
}
@POST
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Gender post(@Valid final Gender data) throws Exception {
return DataAccess.insert(data);
}
@PUT
@Path("{oid}")
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Gender patch(@PathParam("oid") final ObjectId oid, @Valid final Gender gender) throws Exception {
gender.oid = oid;
DataAccess.update(gender, oid);
return DataAccess.get(Gender.class, oid);
}
@DELETE
@Path("{oid}")
@RolesAllowed("ADMIN")
public void remove(@PathParam("oid") final ObjectId oid) throws Exception {
DataAccess.delete(Gender.class, oid);
}
@POST
@Path("{oid}/cover")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
@ApiTypeScriptProgress
public Gender uploadCover(@PathParam("oid") final ObjectId oid, @ApiInputOptional @FormDataParam("uri") final String uri,
@ApiInputOptional @FormDataParam("file") final InputStream fileInputStream, @ApiInputOptional @FormDataParam("file") final FormDataContentDisposition fileMetaData) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
if (uri != null) {
DataTools.uploadCoverFromUri(db, Gender.class, oid, uri);
} else {
DataTools.uploadCover(db, Gender.class, oid, fileInputStream, fileMetaData);
}
return db.get(Gender.class, oid);
}
}
@DELETE
@Path("{oid}/cover/{coverId}")
@RolesAllowed("ADMIN")
public Gender removeCover(@PathParam("oid") final ObjectId oid, @PathParam("coverId") final ObjectId coverId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Gender.class, "_id", oid, "covers", coverId);
return db.get(Gender.class, oid);
}
}
}

View File

@ -1,93 +0,0 @@
package org.atriasoft.karusic.api;
import java.io.InputStream;
import java.util.List;
import org.atriasoft.archidata.annotation.apiGenerator.ApiAsyncType;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.dataAccess.DataAccess;
import org.atriasoft.archidata.dataAccess.addOnSQL.AddOnDataJson;
import org.atriasoft.archidata.tools.DataTools;
import org.atriasoft.karusic.model.Playlist;
import org.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.annotation.security.RolesAllowed;
import jakarta.validation.Valid;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
@Path("/playlist")
@Produces({ MediaType.APPLICATION_JSON })
public class PlaylistResource {
private static final Logger LOGGER = LoggerFactory.getLogger(PlaylistResource.class);
@GET
@Path("{id}")
@RolesAllowed("USER")
public Playlist get(@PathParam("id") final ObjectId oid) throws Exception {
return DataAccess.get(Playlist.class, oid);
}
@GET
@RolesAllowed("USER")
public List<Playlist> gets() throws Exception {
return DataAccess.gets(Playlist.class);
}
@POST
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Playlist post(@Valid final Playlist data) throws Exception {
return DataAccess.insert(data);
}
@PUT
@Path("{oid}")
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Playlist put(@PathParam("oid") final ObjectId oid, @Valid final Playlist playlist) throws Exception {
playlist.oid = oid;
DataAccess.update(playlist, oid);
return DataAccess.get(Playlist.class, oid);
}
@DELETE
@Path("{oid}")
@RolesAllowed("ADMIN")
public void remove(@PathParam("oid") final ObjectId oid) throws Exception {
DataAccess.delete(Playlist.class, oid);
}
@POST
@Path("{oid}/cover")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
@ApiAsyncType(Playlist.class)
public void uploadCover(@PathParam("oid") final ObjectId oid, @FormDataParam("file") final InputStream fileInputStream, @FormDataParam("file") final FormDataContentDisposition fileMetaData)
throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
DataTools.uploadCover(db, Playlist.class, oid, fileInputStream, fileMetaData);
}
}
@DELETE
@Path("{oid}/cover/{coverId}")
@RolesAllowed("ADMIN")
public Playlist removeCover(@PathParam("oid") final ObjectId oid, @PathParam("coverId") final ObjectId coverId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Playlist.class, "id", oid, "covers", coverId);
return DataAccess.get(Playlist.class, oid);
}
}
}

View File

@ -1,112 +0,0 @@
package org.atriasoft.karusic.migration;
import java.util.List;
import org.atriasoft.archidata.api.DataResource;
import org.atriasoft.archidata.api.ProxyResource;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.externalRestApi.AnalyzeApi;
import org.atriasoft.archidata.externalRestApi.TsGenerateApi;
import org.atriasoft.archidata.filter.PartRight;
import org.atriasoft.archidata.migration.MigrationSqlStep;
import org.atriasoft.archidata.model.Data;
import org.atriasoft.archidata.model.User;
import org.atriasoft.archidata.model.token.JwtToken;
import org.atriasoft.karusic.api.AlbumResource;
import org.atriasoft.karusic.api.ArtistResource;
import org.atriasoft.karusic.api.Front;
import org.atriasoft.karusic.api.GenderResource;
import org.atriasoft.karusic.api.HealthCheck;
import org.atriasoft.karusic.api.PlaylistResource;
import org.atriasoft.karusic.api.TrackResource;
import org.atriasoft.karusic.api.UserResource;
import org.atriasoft.karusic.model.Album;
import org.atriasoft.karusic.model.Artist;
import org.atriasoft.karusic.model.Gender;
import org.atriasoft.karusic.model.Playlist;
import org.atriasoft.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);
@Override
public String getName() {
return "Initialization";
}
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);
api.addModel(JwtToken.class);
api.addModel(PartRight.class);
TsGenerateApi.generateApi(api, "../front/src/back-api/");
LOGGER.info("Generate APIs (DONE)");
}
@Override
public void generateStep() throws Exception {
for (final Class<?> clazz : CLASSES_BASE) {
addClass(clazz);
}
addAction((final DBAccess da) -> {
final List<Gender> data = List.of(//
new Gender("Variété française"), //
new Gender("Pop"), //
new Gender("inconnue"), //
new Gender("Disco"), //
new Gender("Enfants"), //
new Gender("Portugaise"), //
new Gender("Apprentissage"), //
new Gender("Blues"), //
new Gender("Jazz"), //
new Gender("Chanson Noël"), //
new Gender("DubStep"), //
new Gender("Rap français"), //
new Gender("Classique"), //
new Gender("Rock"), //
new Gender("Electro"), //
new Gender("Celtique"), //
new Gender("Country"), //
new Gender("Variété Québéquoise"), //
new Gender("Médiéval"), //
new Gender("Variété Italienne"), //
new Gender("Comédie Musicale"), //
new Gender("Vianney"), //
new Gender("Bande Original"), //
new Gender("Bande Originale"), //
new Gender("Variété Belge"), //
new Gender("Gospel"));
da.insertMultiple(data);
});
}
public static void dropAll(final DBAccess 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 DBAccess da) {
for (final Class<?> element : CLASSES_BASE) {
try {
da.cleanAll(element);
} catch (final Exception ex) {
LOGGER.error("Fail to clean table !!!!!!");
ex.printStackTrace();
}
}
}
}

View File

@ -1,30 +0,0 @@
package org.atriasoft.karusic.migration;
import org.atriasoft.archidata.migration.MigrationSqlStep;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Migration20250414 extends MigrationSqlStep {
private static final Logger LOGGER = LoggerFactory.getLogger(Migration20240226.class);
public static final int KARSO_INITIALISATION_ID = 1;
@Override
public String getName() {
return "migration-2025-04-14: update constraints";
}
@Override
public void generateStep() throws Exception {
addAction("""
ALTER TABLE `artist`
CHANGE `birth` `birth` timestamp(3) NULL AFTER `surname`,
CHANGE `death` `death` timestamp(3) NULL AFTER `birth`;
""");
addAction("""
ALTER TABLE `album`
CHANGE `publication` `publication` timestamp(3) NULL AFTER `description`;
""");
}
}

View File

@ -1,148 +0,0 @@
package org.atriasoft.karusic.migration;
import java.util.ArrayList;
import java.util.List;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.dataAccess.options.AccessDeletedItems;
import org.atriasoft.archidata.dataAccess.options.DirectData;
import org.atriasoft.archidata.dataAccess.options.ReadAllColumn;
import org.atriasoft.archidata.db.DbConfig;
import org.atriasoft.archidata.migration.MigrationSqlStep;
import org.atriasoft.archidata.model.Data;
import org.atriasoft.archidata.tools.ConfigBaseVariable;
import org.atriasoft.karusic.model.Album;
import org.atriasoft.karusic.model.Artist;
import org.atriasoft.karusic.model.Gender;
import org.atriasoft.karusic.model.Track;
import org.atriasoft.karusic.modelOld.AlbumOld;
import org.atriasoft.karusic.modelOld.ArtistOld;
import org.atriasoft.karusic.modelOld.GenderOld;
import org.atriasoft.karusic.modelOld.TrackOld;
import org.bson.types.ObjectId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Migration20250427 extends MigrationSqlStep {
private static final Logger LOGGER = LoggerFactory.getLogger(Migration20240226.class);
public static final int KARSO_INITIALISATION_ID = 1;
@Override
public String getName() {
return "migration-2025-04-27: Migrate to MongoDB";
}
public static ObjectId getElementArtist(final List<ArtistOld> datas, final Long id) throws Exception {
if (id == null) {
return null;
}
for (final var elem : datas) {
if (elem.id.equals(id)) {
return elem.getOid();
}
}
throw new Exception("Does not exist");
}
public static ObjectId getElementAlbum(final List<AlbumOld> datas, final Long id) throws Exception {
if (id == null) {
return null;
}
for (final var elem : datas) {
if (elem.id.equals(id)) {
return elem.getOid();
}
}
throw new Exception("Does not exist");
}
public static ObjectId getElementGender(final List<GenderOld> datas, final Long id) throws Exception {
if (id == null) {
return null;
}
for (final var elem : datas) {
if (elem.id.equals(id)) {
return elem.getOid();
}
}
throw new Exception("Does not exist");
}
@Override
public void generateStep() throws Exception {
addAction((final DBAccess daMongo) -> {
// Create the previous connection on SQL:
final DbConfig configSQL = new DbConfig("mysql", ConfigBaseVariable.getDBHost(), (short) 3906,
// final DbConfig config = new DbConfig("mysql", "db", (short) 3306,
ConfigBaseVariable.getDBLogin(), ConfigBaseVariable.getDBPassword(), ConfigBaseVariable.getDBName(), ConfigBaseVariable.getDBKeepConnected(),
List.of(ConfigBaseVariable.getBbInterfacesClasses()));
try (final DBAccess daSQL = DBAccess.createInterface(configSQL)) {
final List<Data> allData = daSQL.gets(Data.class, new ReadAllColumn(), new AccessDeletedItems());
final List<AlbumOld> allOldAlbums = daSQL.gets(AlbumOld.class, new ReadAllColumn(), new AccessDeletedItems());
final List<ArtistOld> allOldArtist = daSQL.gets(ArtistOld.class, new ReadAllColumn(), new AccessDeletedItems());
final List<GenderOld> allOldGender = daSQL.gets(GenderOld.class, new ReadAllColumn(), new AccessDeletedItems());
final List<TrackOld> allTOldrack = daSQL.gets(TrackOld.class, new ReadAllColumn(), new AccessDeletedItems());
for (final Data elem : allData) {
daMongo.insert(elem, new DirectData());
}
for (final AlbumOld elem : allOldAlbums) {
final Album tmp = new Album();
tmp.oid = elem.getOid();
tmp.deleted = elem.deleted;
tmp.updatedAt = elem.updatedAt;
tmp.createdAt = elem.createdAt;
tmp.name = elem.name;
tmp.description = elem.description;
tmp.covers = elem.covers;
daMongo.insert(tmp, new DirectData());
}
for (final ArtistOld elem : allOldArtist) {
final Artist tmp = new Artist();
tmp.oid = elem.getOid();
tmp.deleted = elem.deleted;
tmp.updatedAt = elem.updatedAt;
tmp.createdAt = elem.createdAt;
tmp.name = elem.name;
tmp.description = elem.description;
tmp.covers = elem.covers;
tmp.firstName = elem.firstName;
tmp.birth = elem.birth;
tmp.death = elem.death;
daMongo.insert(tmp, new DirectData());
}
for (final GenderOld elem : allOldGender) {
final Gender tmp = new Gender();
tmp.oid = elem.getOid();
tmp.deleted = elem.deleted;
tmp.updatedAt = elem.updatedAt;
tmp.createdAt = elem.createdAt;
tmp.name = elem.name;
tmp.description = elem.description;
tmp.covers = elem.covers;
daMongo.insert(tmp, new DirectData());
}
for (final TrackOld elem : allTOldrack) {
final Track tmp = new Track();
tmp.oid = elem.getOid();
tmp.deleted = elem.deleted;
tmp.updatedAt = elem.updatedAt;
tmp.createdAt = elem.createdAt;
tmp.name = elem.name;
tmp.description = elem.description;
tmp.covers = elem.covers;
tmp.genderId = getElementGender(allOldGender, elem.genderId);
tmp.albumId = getElementAlbum(allOldAlbums, elem.albumId);
tmp.track = elem.track;
tmp.dataId = elem.dataId;
tmp.artists = new ArrayList<>();
for (final Long artistId : elem.artists) {
tmp.artists.add(getElementArtist(allOldArtist, artistId));
}
daMongo.insert(tmp, new DirectData());
}
}
});
}
}

View File

@ -1,44 +0,0 @@
package org.atriasoft.karusic.model;
import java.util.Date;
import java.util.List;
import org.atriasoft.archidata.annotation.DataIfNotExists;
import org.atriasoft.archidata.annotation.apiGenerator.ApiAccessLimitation;
import org.atriasoft.archidata.annotation.apiGenerator.ApiGenerationMode;
import org.atriasoft.archidata.annotation.checker.CheckForeignKey;
import org.atriasoft.archidata.annotation.checker.CollectionNotEmpty;
import org.atriasoft.archidata.model.Data;
import org.atriasoft.archidata.model.OIDGenericDataSoftDelete;
import org.bson.types.ObjectId;
import org.hibernate.validator.constraints.UniqueElements;
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.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
@Entity()
@DataIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
@ApiGenerationMode(create = true, update = true)
public class Album extends OIDGenericDataSoftDelete {
@Column(length = 256)
@Size(min = 1, max = 256)
public String name = null;
@Column(length = 0)
@Size(min = 0, max = 8192)
public String description = null;
@Schema(description = "List of Id of the specific covers")
@Nullable
@CollectionNotEmpty
@UniqueElements
@ApiAccessLimitation(readable = true, creatable = false, updatable = false)
public List<@CheckForeignKey(target = Data.class) @NotNull ObjectId> covers = null;
public Date publication;
}

View File

@ -1,56 +0,0 @@
package org.atriasoft.karusic.model;
import java.util.Date;
import java.util.List;
import org.atriasoft.archidata.annotation.DataIfNotExists;
import org.atriasoft.archidata.annotation.apiGenerator.ApiAccessLimitation;
import org.atriasoft.archidata.annotation.apiGenerator.ApiGenerationMode;
import org.atriasoft.archidata.annotation.checker.CheckForeignKey;
import org.atriasoft.archidata.annotation.checker.CollectionNotEmpty;
import org.atriasoft.archidata.model.Data;
import org.atriasoft.archidata.model.OIDGenericDataSoftDelete;
import org.bson.types.ObjectId;
import org.hibernate.validator.constraints.UniqueElements;
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.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
@Entity()
@DataIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
@ApiGenerationMode(create = true, update = true)
public class Artist extends OIDGenericDataSoftDelete {
@Column(length = 256)
@Size(min = 1, max = 256)
public String name = null;
@Column(length = 0)
@Size(min = 0, max = 8192)
public String description = null;
@Schema(description = "List of Id of the specific covers")
@Nullable
@CollectionNotEmpty
@UniqueElements
@ApiAccessLimitation(readable = true, creatable = false, updatable = false)
public List<@CheckForeignKey(target = Data.class) @NotNull ObjectId> covers = null;
@Column(length = 256)
@Size(min = 1, max = 256)
public String firstName = null;
@Column(length = 256)
@Size(min = 1, max = 256)
public String surname = null;
public Date birth = null;
public Date death = null;
@Override
public String toString() {
return "Artist [id=" + this.oid + ", name=" + this.name + ", description=" + this.description + ", covers=" + this.covers + ", firstName=" + this.firstName + ", surname=" + this.surname
+ ", birth=" + this.birth + ", death=" + this.death + "]";
}
}

View File

@ -1,65 +0,0 @@
package org.atriasoft.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 org.atriasoft.archidata.annotation.DataIfNotExists;
import org.atriasoft.archidata.annotation.apiGenerator.ApiAccessLimitation;
import org.atriasoft.archidata.annotation.apiGenerator.ApiGenerationMode;
import org.atriasoft.archidata.annotation.checker.CheckForeignKey;
import org.atriasoft.archidata.annotation.checker.CollectionNotEmpty;
import org.atriasoft.archidata.model.Data;
import org.atriasoft.archidata.model.OIDGenericDataSoftDelete;
import org.bson.types.ObjectId;
import org.hibernate.validator.constraints.UniqueElements;
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.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
@Entity()
@DataIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
@ApiGenerationMode(create = true, update = true)
public class Gender extends OIDGenericDataSoftDelete {
@Column(length = 256)
@Size(min = 1, max = 256)
public String name = null;
@Column(length = 0)
@Size(min = 0, max = 8192)
public String description = null;
@Schema(description = "List of Id of the specific covers")
@Nullable
@CollectionNotEmpty
@UniqueElements
@ApiAccessLimitation(readable = true, creatable = false, updatable = false)
public List<@CheckForeignKey(target = Data.class) @NotNull ObjectId> covers = null;
public Gender() {}
public Gender(final String name) {
this.name = name;
}
public Gender(final ObjectId oid, final String name) {
this.oid = oid;
this.name = name;
}
}

View File

@ -1,54 +0,0 @@
package org.atriasoft.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 org.atriasoft.archidata.annotation.DataIfNotExists;
import org.atriasoft.archidata.annotation.apiGenerator.ApiAccessLimitation;
import org.atriasoft.archidata.annotation.apiGenerator.ApiGenerationMode;
import org.atriasoft.archidata.annotation.checker.CheckForeignKey;
import org.atriasoft.archidata.annotation.checker.CollectionNotEmpty;
import org.atriasoft.archidata.model.Data;
import org.atriasoft.archidata.model.OIDGenericDataSoftDelete;
import org.bson.types.ObjectId;
import org.hibernate.validator.constraints.UniqueElements;
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.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
@Entity()
@DataIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
@ApiGenerationMode(create = true, update = true)
public class Playlist extends OIDGenericDataSoftDelete {
@Column(length = 256)
@Size(min = 1, max = 256)
public String name = null;
@Column(length = 0)
@Size(min = 0, max = 8192)
public String description = null;
@Schema(description = "List of Id of the specific covers")
@Nullable
@CollectionNotEmpty
@UniqueElements
@ApiAccessLimitation(readable = true, creatable = false, updatable = false)
public List<@CheckForeignKey(target = Data.class) @NotNull ObjectId> covers = null;
public List<@CheckForeignKey(target = Track.class) @NotNull ObjectId> tracks = null;
}

View File

@ -1,71 +0,0 @@
package org.atriasoft.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 org.atriasoft.archidata.annotation.DataIfNotExists;
import org.atriasoft.archidata.annotation.apiGenerator.ApiAccessLimitation;
import org.atriasoft.archidata.annotation.apiGenerator.ApiGenerationMode;
import org.atriasoft.archidata.annotation.checker.CheckForeignKey;
import org.atriasoft.archidata.annotation.checker.CollectionNotEmpty;
import org.atriasoft.archidata.model.Data;
import org.atriasoft.archidata.model.OIDGenericDataSoftDelete;
import org.bson.types.ObjectId;
import org.hibernate.validator.constraints.UniqueElements;
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.validation.constraints.NotNull;
import jakarta.validation.constraints.PositiveOrZero;
import jakarta.validation.constraints.Size;
@Entity()
@DataIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
@ApiGenerationMode(create = true, update = true)
public class Track extends OIDGenericDataSoftDelete {
@Column(length = 256)
@Size(min = 1, max = 256)
public String name = null;
@Column(length = 0)
@Size(min = 0, max = 8192)
public String description = null;
@Schema(description = "List of Id of the specific covers")
@Nullable
@CollectionNotEmpty
@UniqueElements
@ApiAccessLimitation(readable = true, creatable = false, updatable = false)
public List<@CheckForeignKey(target = Data.class) @NotNull ObjectId> covers = null;
@CheckForeignKey(target = Gender.class)
public ObjectId genderId = null;
@CheckForeignKey(target = Album.class)
public ObjectId albumId = null;
@PositiveOrZero
public Long track = null;
@CheckForeignKey(target = Data.class)
public ObjectId dataId = null;
@Column(length = 0)
public List<@CheckForeignKey(target = Artist.class) @NotNull ObjectId> artists = null;
@Override
public String toString() {
return "Track [oid=" + this.oid + ", deleted=" + this.deleted + ", createdAt=" + this.createdAt + ", updatedAt=" + this.updatedAt + ", name=" + this.name + ", description=" + this.description
+ ", covers=" + this.covers + ", genderId=" + this.genderId + ", albumId=" + this.albumId + ", track=" + this.track + ", dataId=" + this.dataId + ", artists=" + this.artists + "]";
}
}

View File

@ -1,32 +0,0 @@
package org.atriasoft.karusic.modelOld;
import java.util.Date;
import java.util.List;
import org.atriasoft.archidata.annotation.DataJson;
import org.atriasoft.archidata.model.GenericDataSoftDelete;
import org.bson.types.ObjectId;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Column;
import jakarta.persistence.Table;
@Table(name = "album")
public class AlbumOld 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()
public List<ObjectId> covers = null;
public Date publication;
@Column(nullable = true)
private final ObjectId oid = new ObjectId();
public ObjectId getOid() {
return this.oid;
}
}

View File

@ -1,34 +0,0 @@
package org.atriasoft.karusic.modelOld;
import java.util.Date;
import java.util.List;
import org.atriasoft.archidata.annotation.DataJson;
import org.atriasoft.archidata.model.GenericDataSoftDelete;
import org.bson.types.ObjectId;
import jakarta.persistence.Column;
import jakarta.persistence.Table;
@Table(name = "artist")
public class ArtistOld extends GenericDataSoftDelete {
@Column(length = 256)
public String name = null;
@Column(length = 0)
public String description = null;
@DataJson()
public List<ObjectId> covers = null;
@Column(length = 256)
public String firstName = null;
@Column(length = 256)
public String surname = null;
public Date birth = null;
public Date death = null;
@Column(nullable = true)
private final ObjectId oid = new ObjectId();
public ObjectId getOid() {
return this.oid;
}
}

View File

@ -1,53 +0,0 @@
package org.atriasoft.karusic.modelOld;
/*
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 org.atriasoft.archidata.annotation.DataJson;
import org.atriasoft.archidata.annotation.checker.CheckForeignKey;
import org.atriasoft.archidata.model.Data;
import org.atriasoft.archidata.model.GenericDataSoftDelete;
import org.bson.types.ObjectId;
import jakarta.persistence.Column;
import jakarta.persistence.Table;
import jakarta.validation.constraints.NotNull;
@Table(name = "gender")
public class GenderOld extends GenericDataSoftDelete {
@Column(length = 256)
public String name = null;
@Column(length = 0)
public String description = null;
@DataJson()
public List<@CheckForeignKey(target = Data.class) @NotNull ObjectId> covers = null;
public GenderOld() {}
public GenderOld(final String name) {
this.name = name;
}
public GenderOld(final Long id, final String name) {
this.id = id;
this.name = name;
}
@Column(nullable = true)
private final ObjectId oid = new ObjectId();
public ObjectId getOid() {
return this.oid;
}
}

View File

@ -1,48 +0,0 @@
package org.atriasoft.karusic.modelOld;
/*
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 org.atriasoft.archidata.annotation.DataJson;
import org.atriasoft.archidata.annotation.checker.CheckForeignKey;
import org.atriasoft.archidata.model.Data;
import org.atriasoft.archidata.model.GenericDataSoftDelete;
import org.bson.types.ObjectId;
import jakarta.persistence.Column;
import jakarta.persistence.Table;
import jakarta.validation.constraints.NotNull;
@Table(name = "track")
public class TrackOld extends GenericDataSoftDelete {
@Column(length = 256)
public String name = null;
@Column(length = 0)
public String description = null;
@DataJson()
public List<@CheckForeignKey(target = Data.class) @NotNull ObjectId> covers = null;
public Long genderId = null;
public Long albumId = null;
public Long track = null;
public ObjectId dataId = null;
@DataJson
public List<Long> artists = null;
@Column(nullable = true)
private final ObjectId oid = new ObjectId();
public ObjectId getOid() {
return this.oid;
}
}

View File

@ -1,4 +1,4 @@
package org.atriasoft.karusic.CodecBson;
package org.kar.karusic.CodecBson;
import java.util.UUID;

View File

@ -1,42 +1,44 @@
package org.atriasoft.karusic;
package org.kar.karusic;
import java.net.URI;
import java.util.Iterator;
import java.util.TimeZone;
import java.util.logging.LogManager;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.ImageWriter;
import org.atriasoft.archidata.UpdateJwtPublicKey;
import org.atriasoft.archidata.api.DataResource;
import org.atriasoft.archidata.api.ProxyResource;
import org.atriasoft.archidata.catcher.GenericCatcher;
import org.atriasoft.archidata.db.DbConfig;
import org.atriasoft.archidata.exception.DataAccessException;
import org.atriasoft.archidata.filter.CORSFilter;
import org.atriasoft.archidata.filter.OptionFilter;
import org.atriasoft.archidata.migration.MigrationEngine;
import org.atriasoft.archidata.tools.ConfigBaseVariable;
import org.atriasoft.archidata.tools.ContextGenericTools;
import org.atriasoft.karusic.api.AlbumResource;
import org.atriasoft.karusic.api.ArtistResource;
import org.atriasoft.karusic.api.Front;
import org.atriasoft.karusic.api.GenderResource;
import org.atriasoft.karusic.api.HealthCheck;
import org.atriasoft.karusic.api.PlaylistResource;
import org.atriasoft.karusic.api.TrackResource;
import org.atriasoft.karusic.api.UserResource;
import org.atriasoft.karusic.filter.KarusicAuthenticationFilter;
import org.atriasoft.karusic.migration.Initialization;
import org.atriasoft.karusic.migration.Migration20250427;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.validation.ValidationFeature;
import org.kar.archidata.UpdateJwtPublicKey;
import org.kar.archidata.api.DataResource;
import org.kar.archidata.api.ProxyResource;
import org.kar.archidata.catcher.GenericCatcher;
import org.kar.archidata.db.DbConfig;
import org.kar.archidata.exception.DataAccessException;
import org.kar.archidata.filter.CORSFilter;
import org.kar.archidata.filter.OptionFilter;
import org.kar.archidata.migration.MigrationEngine;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.kar.archidata.tools.ContextGenericTools;
import org.kar.karusic.api.AlbumResource;
import org.kar.karusic.api.ArtistResource;
import org.kar.karusic.api.Front;
import org.kar.karusic.api.GenderResource;
import org.kar.karusic.api.HealthCheck;
import org.kar.karusic.api.PlaylistResource;
import org.kar.karusic.api.TrackResource;
import org.kar.karusic.api.UserResource;
import org.kar.karusic.filter.KarusicAuthenticationFilter;
import org.kar.karusic.migration.Initialization;
import org.kar.karusic.migration.Migration20231126;
import org.kar.karusic.migration.Migration20240225;
import org.kar.karusic.migration.Migration20240226;
import org.kar.karusic.migration.Migration20240907;
import org.kar.karusic.migration.Migration20250104;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.bridge.SLF4JBridgeHandler;
@ -49,7 +51,6 @@ public class WebLauncher {
protected HttpServer server = null;
public WebLauncher() {
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
ConfigBaseVariable.bdDatabase = "karusic";
}
@ -63,7 +64,11 @@ public class WebLauncher {
WebLauncher.LOGGER.info("Add initialization");
migrationEngine.setInit(new Initialization());
WebLauncher.LOGGER.info("Add migration since last version");
migrationEngine.add(new Migration20250427());
migrationEngine.add(new Migration20231126());
migrationEngine.add(new Migration20240225());
migrationEngine.add(new Migration20240226());
migrationEngine.add(new Migration20240907());
migrationEngine.add(new Migration20250104());
WebLauncher.LOGGER.info("Migrate the DB [START]");
migrationEngine.migrateWaitAdmin(new DbConfig());
WebLauncher.LOGGER.info("Migrate the DB [STOP]");
@ -146,8 +151,6 @@ public class WebLauncher {
// add jackson to be discover when we are ins standalone server
rc.register(JacksonFeature.class);
// enable jersey specific validations (@Valid)
rc.register(ValidationFeature.class);
// enable this to show low level request
// rc.property(LoggingFeature.LOGGING_FEATURE_LOGGER_LEVEL_SERVER, Level.WARNING.getName());

View File

@ -0,0 +1,74 @@
package org.kar.karusic;
import java.util.List;
import java.util.logging.LogManager;
import org.kar.archidata.api.DataResource;
import org.kar.archidata.api.ProxyResource;
import org.kar.archidata.exception.DataAccessException;
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;
import org.kar.karusic.api.Front;
import org.kar.karusic.api.GenderResource;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.bridge.SLF4JBridgeHandler;
public class WebLauncherLocal extends WebLauncher {
private static final Logger LOGGER = LoggerFactory.getLogger(WebLauncherLocal.class);
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 {
// Loop-back of logger JDK logging API to SLF4J
LogManager.getLogManager().reset();
SLF4JBridgeHandler.install();
// Generate the APIs in type-script
generateObjects();
final WebLauncherLocal launcher = new WebLauncherLocal();
launcher.process();
launcher.LOGGER.info("end-configure the server & wait finish process:");
Thread.currentThread().join();
launcher.LOGGER.info("STOP the REST server:");
}
@Override
public void process() throws InterruptedException, DataAccessException {
if (true) {
// for local test:
ConfigBaseVariable.apiAdress = "http://0.0.0.0:19080/karusic/api/";
// ConfigBaseVariable.ssoAdress = "https://atria-soft.org/karso/api/";
ConfigBaseVariable.dbPort = "3906";
ConfigBaseVariable.testMode = "true";
}
try {
super.migrateDB();
} catch (final Exception e) {
e.printStackTrace();
while (true) {
LOGGER.error("============================================================================");
LOGGER.error("== Migration fail ==> waiting intervention of administrator...");
LOGGER.error("============================================================================");
Thread.sleep(60 * 60 * 1000);
}
}
super.process();
}
}

View File

@ -1,29 +1,31 @@
package org.atriasoft.karusic.api;
package org.kar.karusic.api;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;
import org.atriasoft.archidata.annotation.apiGenerator.ApiInputOptional;
import org.atriasoft.archidata.annotation.apiGenerator.ApiTypeScriptProgress;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.dataAccess.DataAccess;
import org.atriasoft.archidata.dataAccess.addOnSQL.AddOnDataJson;
import org.atriasoft.archidata.tools.DataTools;
import org.atriasoft.karusic.model.Album;
import org.bson.types.ObjectId;
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.DBAccess;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.addOnSQL.AddOnDataJson;
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;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.annotation.security.RolesAllowed;
import jakarta.validation.Valid;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PATCH;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
@ -33,13 +35,14 @@ import jakarta.ws.rs.core.MediaType;
@Produces({ MediaType.APPLICATION_JSON })
public class AlbumResource {
private static final Logger LOGGER = LoggerFactory.getLogger(AlbumResource.class);
static final AlbumChecker CHECKER = new AlbumChecker();
@GET
@Path("{oid}")
@Path("{id}")
@RolesAllowed("USER")
@Operation(description = "Get a specific Album with his ID")
public Album get(@PathParam("oid") final ObjectId oid) throws Exception {
return DataAccess.get(Album.class, oid);
public Album get(@PathParam("id") final Long id) throws Exception {
return DataAccess.get(Album.class, id);
// return this.morphiaService.getDatastore().find(Album.class).filter(Filters.eq("id", id)).first();
}
@ -56,30 +59,30 @@ public class AlbumResource {
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
@Operation(description = "Add an album (when all the data already exist)")
public Album post(@Valid final Album data) throws Exception {
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 DataAccess.insert(data);
return DataAccess.insert(data, new CheckFunction(CHECKER));
}
@PUT
@Path("{oid}")
@PATCH
@Path("{id}")
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
@Operation(description = "Update a specific album")
public Album put(@PathParam("oid") final ObjectId oid, @Valid final Album album) throws Exception {
public Album patch(@PathParam("id") final Long id, @AsyncType(Album.class) final String jsonRequest) 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", master.getName());
// this.morphiaService.getDatastore().update(query, ops);
// return Response.ok(master).build();
album.oid = oid;
DataAccess.update(album, oid);
return DataAccess.get(Album.class, oid);
DataAccess.updateWithJson(Album.class, id, jsonRequest, new CheckFunction(CHECKER));
return DataAccess.get(Album.class, id);
}
// @PUT
@ -87,7 +90,7 @@ public class AlbumResource {
// @RolesAllowed("ADMIN")
// @Consumes(MediaType.APPLICATION_JSON)
// @Operation(description = "Update a specific album")
// public Album put(@PathParam("id") final ObjectId oid, final Album 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)
@ -97,11 +100,11 @@ public class AlbumResource {
// }
@DELETE
@Path("{oid}")
@Path("{id}")
@RolesAllowed("ADMIN")
@Operation(description = "Remove a specific album")
public void remove(@PathParam("oid") final ObjectId oid) throws Exception {
DataAccess.delete(Album.class, oid);
public void remove(@PathParam("id") final Long id) throws Exception {
DataAccess.delete(Album.class, id);
// this.morphiaService.getDatastore().find(Album.class).filter(Filters.eq("id", id)).delete();
}
@ -109,34 +112,34 @@ public class AlbumResource {
* @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 ObjectId oid, @PathParam("trackId") final Long trackId) throws Exception {
* @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("{oid}/cover")
@Path("{id}/cover")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
@Operation(description = "Add a cover on a specific album")
@ApiTypeScriptProgress
public Album uploadCover(@PathParam("oid") final ObjectId oid, @ApiInputOptional @FormDataParam("uri") final String uri, @ApiInputOptional @FormDataParam("file") final InputStream fileInputStream,
@ApiInputOptional @FormDataParam("file") final FormDataContentDisposition fileMetaData) throws Exception {
@TypeScriptProgress
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 {
try (DBAccess db = DBAccess.createInterface()) {
if (uri != null) {
DataTools.uploadCoverFromUri(db, Album.class, oid, uri);
DataTools.uploadCoverFromUri(db, Album.class, id, uri);
} else {
DataTools.uploadCover(db, Album.class, oid, fileInputStream, fileMetaData);
DataTools.uploadCover(db, Album.class, id, fileInputStream, fileMetaData);
}
return db.get(Album.class, oid);
return db.get(Album.class, id);
}
}
@DELETE
@Path("{oid}/cover/{coverId}")
@Path("{id}/cover/{coverId}")
@RolesAllowed("ADMIN")
@Operation(description = "Remove a cover on a specific album")
public Album removeCover(@PathParam("oid") final ObjectId oid, @PathParam("coverId") final ObjectId coverId) throws Exception {
public Album removeCover(@PathParam("id") final Long id, @PathParam("coverId") final UUID coverId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Album.class, "id", oid, "covers", coverId);
return db.get(Album.class, oid);
AddOnDataJson.removeLink(db, Album.class, "id", id, "covers", coverId);
return db.get(Album.class, id);
}
}
}

View File

@ -0,0 +1,101 @@
package org.kar.karusic.api;
import java.io.InputStream;
import java.util.List;
import org.bson.types.ObjectId;
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.DBAccess;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.addOnSQL.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;
import jakarta.annotation.security.RolesAllowed;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PATCH;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
@Path("/artist")
@Produces({ MediaType.APPLICATION_JSON })
public class ArtistResource {
private static final Logger LOGGER = LoggerFactory.getLogger(ArtistResource.class);
static final ArtistChecker CHECKER = new ArtistChecker();
@GET
@Path("{id}")
@RolesAllowed("USER")
public Artist get(@PathParam("id") final Long id) throws Exception {
return DataAccess.get(Artist.class, id);
}
@GET
@RolesAllowed("USER")
public List<Artist> gets() throws Exception {
return DataAccess.gets(Artist.class);
}
@POST
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Artist post(final Artist data) throws Exception {
return DataAccess.insert(data, new CheckFunction(CHECKER));
}
@PATCH
@Path("{id}")
@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, new CheckFunction(CHECKER));
return DataAccess.get(Artist.class, id);
}
@DELETE
@Path("{id}")
@RolesAllowed("ADMIN")
public void remove(@PathParam("id") final Long id) throws Exception {
DataAccess.delete(Artist.class, id);
}
@POST
@Path("{id}/cover")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
@TypeScriptProgress
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 {
try (DBAccess db = DBAccess.createInterface()) {
if (uri != null) {
DataTools.uploadCoverFromUri(db, Artist.class, id, uri);
} else {
DataTools.uploadCover(db, Artist.class, id, fileInputStream, fileMetaData);
}
return db.get(Artist.class, id);
}
}
@DELETE
@Path("{id}/cover/{coverId}")
@RolesAllowed("ADMIN")
public Artist removeCover(@PathParam("id") final Long id, @PathParam("coverId") final ObjectId coverId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Artist.class, "id", id, "covers", coverId);
return db.get(Artist.class, id);
}
}
}

View File

@ -1,7 +1,7 @@
package org.atriasoft.karusic.api;
package org.kar.karusic.api;
import org.atriasoft.archidata.api.FrontGeneric;
import org.atriasoft.karusic.util.ConfigVariable;
import org.kar.archidata.api.FrontGeneric;
import org.kar.karusic.util.ConfigVariable;
import jakarta.ws.rs.Path;

View File

@ -0,0 +1,101 @@
package org.kar.karusic.api;
import java.io.InputStream;
import java.util.List;
import org.bson.types.ObjectId;
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.DBAccess;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.addOnSQL.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;
import jakarta.annotation.security.RolesAllowed;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PATCH;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
@Path("/gender")
@Produces({ MediaType.APPLICATION_JSON })
public class GenderResource {
private static final Logger LOGGER = LoggerFactory.getLogger(GenderResource.class);
static final GenderChecker CHECKER = new GenderChecker();
@GET
@Path("{id}")
@RolesAllowed("USER")
public Gender get(@PathParam("id") final Long id) throws Exception {
return DataAccess.get(Gender.class, id);
}
@GET
@RolesAllowed("USER")
public List<Gender> gets() throws Exception {
return DataAccess.gets(Gender.class);
}
@POST
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Gender post(final Gender data) throws Exception {
return DataAccess.insert(data, new CheckFunction(CHECKER));
}
@PATCH
@Path("{id}")
@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, new CheckFunction(CHECKER));
return DataAccess.get(Gender.class, id);
}
@DELETE
@Path("{id}")
@RolesAllowed("ADMIN")
public void remove(@PathParam("id") final Long id) throws Exception {
DataAccess.delete(Gender.class, id);
}
@POST
@Path("{id}/cover")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
@TypeScriptProgress
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 {
try (DBAccess db = DBAccess.createInterface()) {
if (uri != null) {
DataTools.uploadCoverFromUri(db, Gender.class, id, uri);
} else {
DataTools.uploadCover(db, Gender.class, id, fileInputStream, fileMetaData);
}
return db.get(Gender.class, id);
}
}
@DELETE
@Path("{id}/cover/{coverId}")
@RolesAllowed("ADMIN")
public Gender removeCover(@PathParam("id") final Long id, @PathParam("coverId") final ObjectId coverId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Gender.class, "id", id, "covers", coverId);
return db.get(Gender.class, id);
}
}
}

View File

@ -1,8 +1,8 @@
package org.atriasoft.karusic.api;
package org.kar.karusic.api;
import org.atriasoft.archidata.exception.FailException;
import org.atriasoft.archidata.tools.ConfigBaseVariable;
import org.atriasoft.archidata.tools.JWTWrapper;
import org.kar.archidata.exception.FailException;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.kar.archidata.tools.JWTWrapper;
import jakarta.annotation.security.PermitAll;
import jakarta.ws.rs.GET;

View File

@ -0,0 +1,115 @@
package org.kar.karusic.api;
import java.io.InputStream;
import java.util.List;
import org.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.annotation.AsyncType;
import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.addOnSQL.AddOnDataJson;
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;
import jakarta.annotation.security.RolesAllowed;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PATCH;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
@Path("/playlist")
@Produces({ MediaType.APPLICATION_JSON })
public class PlaylistResource {
private static final Logger LOGGER = LoggerFactory.getLogger(PlaylistResource.class);
static final TrackChecker CHECKER = new TrackChecker();
@GET
@Path("{id}")
@RolesAllowed("USER")
public Playlist get(@PathParam("id") final Long id) throws Exception {
return DataAccess.get(Playlist.class, id);
}
@GET
@RolesAllowed("USER")
public List<Playlist> gets() throws Exception {
return DataAccess.gets(Playlist.class);
}
@POST
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Playlist post(final Playlist data) throws Exception {
return DataAccess.insert(data, new CheckFunction(CHECKER));
}
@PATCH
@Path("{id}")
@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, new CheckFunction(CHECKER));
return DataAccess.get(Playlist.class, id);
}
@DELETE
@Path("{id}")
@RolesAllowed("ADMIN")
public void remove(@PathParam("id") final Long id) throws Exception {
DataAccess.delete(Playlist.class, id);
}
@POST
@Path("{id}/track/{trackId}")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
public Playlist addTrack(@PathParam("id") final Long id, @PathParam("trackId") final Long trackId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Playlist.class, "id", id, "track", trackId);
return db.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 {
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Playlist.class, "id", id, "track", trackId);
return db.get(Playlist.class, id);
}
}
@POST
@Path("{id}/cover")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
@AsyncType(Playlist.class)
public void uploadCover(@PathParam("id") final Long id, @FormDataParam("file") final InputStream fileInputStream, @FormDataParam("file") final FormDataContentDisposition fileMetaData)
throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
DataTools.uploadCover(db, Playlist.class, id, fileInputStream, fileMetaData);
}
}
@DELETE
@Path("{id}/cover/{coverId}")
@RolesAllowed("ADMIN")
public Playlist removeCover(@PathParam("id") final Long id, @PathParam("coverId") final ObjectId coverId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Playlist.class, "id", id, "covers", coverId);
return DataAccess.get(Playlist.class, id);
}
}
}

View File

@ -1,4 +1,4 @@
package org.atriasoft.karusic.api;
package org.kar.karusic.api;
import java.io.IOException;
import java.io.InputStream;
@ -6,28 +6,29 @@ import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.atriasoft.archidata.annotation.apiGenerator.ApiAsyncType;
import org.atriasoft.archidata.annotation.apiGenerator.ApiInputOptional;
import org.atriasoft.archidata.annotation.apiGenerator.ApiTypeScriptProgress;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.dataAccess.DataAccess;
import org.atriasoft.archidata.dataAccess.addOnSQL.AddOnDataJson;
import org.atriasoft.archidata.model.Data;
import org.atriasoft.archidata.tools.DataTools;
import org.atriasoft.karusic.model.Track;
import org.bson.types.ObjectId;
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.DBAccess;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.addOnSQL.AddOnDataJson;
import org.kar.archidata.dataAccess.options.CheckFunction;
import org.kar.archidata.model.Data;
import org.kar.archidata.tools.DataTools;
import org.kar.karusic.model.Track;
import org.kar.karusic.model.Track.TrackChecker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.annotation.security.RolesAllowed;
import jakarta.validation.Valid;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PATCH;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
@ -38,12 +39,13 @@ 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();
@GET
@Path("{oid}")
@Path("{id}")
@RolesAllowed("USER")
public Track get(@PathParam("oid") final ObjectId oid) throws Exception {
return DataAccess.get(Track.class, oid);
public Track get(@PathParam("id") final Long id) throws Exception {
return DataAccess.get(Track.class, id);
}
@GET
@ -55,51 +57,71 @@ public class TrackResource {
@POST
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Track post(@Valid final Track data) throws Exception {
return DataAccess.insert(data);
public Track post(final Track data) throws Exception {
return DataAccess.insert(data, new CheckFunction(CHECKER));
}
@PUT
@Path("{oid}")
@PATCH
@Path("{id}")
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Track put(@PathParam("oid") final ObjectId oid, @Valid final Track track) throws Exception {
track.oid = oid;
DataAccess.update(track, oid);
return DataAccess.get(Track.class, oid);
public Track patch(@PathParam("id") final Long id, @AsyncType(Track.class) final String jsonRequest) throws Exception {
DataAccess.updateWithJson(Track.class, id, jsonRequest, new CheckFunction(CHECKER));
return DataAccess.get(Track.class, id);
}
@DELETE
@Path("{oid}")
@Path("{id}")
@RolesAllowed("ADMIN")
public void remove(@PathParam("oid") final ObjectId oid) throws Exception {
DataAccess.delete(Track.class, oid);
public void remove(@PathParam("id") final Long id) throws Exception {
DataAccess.delete(Track.class, id);
}
@POST
@Path("{oid}/cover")
@Path("{id}/artist/{artistId}")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
@ApiTypeScriptProgress
public Track uploadCover(@PathParam("oid") final ObjectId oid, @FormDataParam("uri") final String uri, @FormDataParam("file") final InputStream fileInputStream,
@FormDataParam("file") final FormDataContentDisposition fileMetaData) throws Exception {
public Track addTrack(@PathParam("id") final Long id, @PathParam("artistId") final Long artistId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
if (uri != null) {
DataTools.uploadCoverFromUri(db, Track.class, oid, uri);
} else {
DataTools.uploadCover(db, Track.class, oid, fileInputStream, fileMetaData);
}
return DataAccess.get(Track.class, oid);
AddOnDataJson.removeLink(db, Track.class, "id", id, "artist", artistId);
return DataAccess.get(Track.class, id);
}
}
@DELETE
@Path("{oid}/cover/{coverId}")
@Path("{id}/artist/{trackId}")
@RolesAllowed("ADMIN")
public Track removeCover(@PathParam("oid") final ObjectId oid, @PathParam("coverId") final ObjectId coverId) throws Exception {
public Track removeTrack(@PathParam("id") final Long id, @PathParam("artistId") final Long artistId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Track.class, "_id", oid, "covers", coverId);
return db.get(Track.class, oid);
AddOnDataJson.removeLink(db, Track.class, "id", id, "artist", artistId);
return DataAccess.get(Track.class, id);
}
}
@POST
@Path("{id}/cover")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
@TypeScriptProgress
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 {
try (DBAccess db = DBAccess.createInterface()) {
if (uri != null) {
DataTools.uploadCoverFromUri(db, Track.class, id, uri);
} else {
DataTools.uploadCover(db, Track.class, id, fileInputStream, fileMetaData);
}
return DataAccess.get(Track.class, id);
}
}
@DELETE
@Path("{id}/cover/{coverId}")
@RolesAllowed("ADMIN")
public Track removeCover(@PathParam("id") final Long id, @PathParam("coverId") final ObjectId coverId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Track.class, "id", id, "covers", coverId);
return db.get(Track.class, id);
}
}
@ -107,14 +129,14 @@ public class TrackResource {
@Path("upload/")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
@ApiAsyncType(Track.class)
@ApiTypeScriptProgress
@AsyncType(Track.class)
@TypeScriptProgress
public Response uploadTrack( //
@FormDataParam("title") String title, //
@ApiInputOptional @ApiAsyncType(ObjectId.class) @FormDataParam("genderId") String genderId, //
@ApiInputOptional @ApiAsyncType(ObjectId.class) @FormDataParam("artistId") String artistId, //
@ApiInputOptional @ApiAsyncType(ObjectId.class) @FormDataParam("albumId") String albumId, //
@ApiInputOptional @ApiAsyncType(Long.class) @FormDataParam("trackId") String trackId, //
@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 //
) {
@ -135,7 +157,7 @@ public class TrackResource {
LOGGER.info(" > title: " + title);
LOGGER.info(" > fileInputStream: " + fileInputStream);
LOGGER.info(" > fileMetaData: " + fileMetaData);
/* if (typeId == null) { return Response.status(406). entity("Missing 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);
@ -166,17 +188,15 @@ public class TrackResource {
Track trackElem = new Track();
trackElem.name = title;
trackElem.track = trackId != null ? Long.parseLong(trackId) : null;
trackElem.albumId = albumId != null ? new ObjectId(albumId) : null;
trackElem.genderId = genderId != null ? new ObjectId(genderId) : null;
trackElem.albumId = albumId != null ? Long.parseLong(albumId) : null;
trackElem.genderId = genderId != null ? Long.parseLong(genderId) : null;
trackElem.dataId = data.oid;
// Now list of artist has an internal management:
if (artistId != null) {
trackElem.artists = new ArrayList<>();
trackElem.artists.add(artistId != null ? new ObjectId(artistId) : null);
trackElem.artists.add(artistId != null ? Long.parseLong(artistId) : null);
}
// TODO: maybe validate here ....
trackElem = DataAccess.insert(trackElem);
trackElem = DataAccess.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) {

View File

@ -1,13 +1,13 @@
package org.atriasoft.karusic.api;
package org.kar.karusic.api;
import java.util.List;
import java.util.Map;
import org.atriasoft.archidata.dataAccess.DataAccess;
import org.atriasoft.archidata.filter.GenericContext;
import org.atriasoft.karusic.api.UserResourceModel.PartRight;
import org.atriasoft.karusic.api.UserResourceModel.UserMe;
import org.atriasoft.karusic.model.UserKarusic;
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;

View File

@ -1,7 +1,10 @@
package org.atriasoft.karusic.api.UserResourceModel;
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;

View File

@ -1,4 +1,4 @@
package org.atriasoft.karusic.api.UserResourceModel;
package org.kar.karusic.api.UserResourceModel;
import com.fasterxml.jackson.annotation.JsonValue;

View File

@ -1,9 +1,12 @@
package org.atriasoft.karusic.api.UserResourceModel;
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;

View File

@ -1,6 +1,6 @@
package org.atriasoft.karusic.filter;
package org.kar.karusic.filter;
import org.atriasoft.archidata.filter.AuthenticationFilter;
import org.kar.archidata.filter.AuthenticationFilter;
import jakarta.ws.rs.Priorities;
import jakarta.ws.rs.ext.Provider;

View File

@ -0,0 +1,60 @@
package org.kar.karusic.internal;
//import io.scenarium.logger.LogLevel;
//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);
// }
}

View File

@ -0,0 +1,109 @@
package org.kar.karusic.migration;
import java.util.List;
import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.migration.MigrationSqlStep;
import org.kar.archidata.model.Data;
import org.kar.archidata.model.User;
import org.kar.karusic.model.Album;
import org.kar.karusic.model.Artist;
import org.kar.karusic.model.Gender;
import org.kar.karusic.model.Playlist;
import org.kar.karusic.model.Track;
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);
@Override
public String getName() {
return "Initialization";
}
public Initialization() {
}
@Override
public void generateStep() throws Exception {
for (final Class<?> elem : CLASSES_BASE) {
addClass(elem);
}
addAction((final DBAccess 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;
""", "mysql");
addAction("""
ALTER TABLE `artist` AUTO_INCREMENT = 1000;
""", "mysql");
addAction("""
ALTER TABLE `gender` AUTO_INCREMENT = 1000;
""", "mysql");
addAction("""
ALTER TABLE `playlist` AUTO_INCREMENT = 1000;
""", "mysql");
addAction("""
ALTER TABLE `track` AUTO_INCREMENT = 1000;
""", "mysql");
addAction("""
ALTER TABLE `user` AUTO_INCREMENT = 1000;
""", "mysql");
}
public static void dropAll(final DBAccess 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 DBAccess da) {
for (final Class<?> element : CLASSES_BASE) {
try {
da.cleanAll(element);
} catch (final Exception ex) {
LOGGER.error("Fail to clean table !!!!!!");
ex.printStackTrace();
}
}
}
}

View File

@ -1,6 +1,6 @@
package org.atriasoft.karusic.migration;
package org.kar.karusic.migration;
import org.atriasoft.archidata.migration.MigrationSqlStep;
import org.kar.archidata.migration.MigrationSqlStep;
public class Migration20231126 extends MigrationSqlStep {

View File

@ -1,6 +1,6 @@
package org.atriasoft.karusic.migration;
package org.kar.karusic.migration;
import org.atriasoft.archidata.migration.MigrationSqlStep;
import org.kar.archidata.migration.MigrationSqlStep;
public class Migration20240225 extends MigrationSqlStep {

View File

@ -1,6 +1,6 @@
package org.atriasoft.karusic.migration;
package org.kar.karusic.migration;
import org.atriasoft.archidata.migration.MigrationSqlStep;
import org.kar.archidata.migration.MigrationSqlStep;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

View File

@ -1,6 +1,6 @@
package org.atriasoft.karusic.migration;
package org.kar.karusic.migration;
import org.atriasoft.archidata.migration.MigrationSqlStep;
import org.kar.archidata.migration.MigrationSqlStep;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

View File

@ -1,4 +1,4 @@
package org.atriasoft.karusic.migration;
package org.kar.karusic.migration;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
@ -9,14 +9,14 @@ import java.util.List;
import java.util.UUID;
import org.bson.types.ObjectId;
import org.atriasoft.archidata.api.DataResource;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.dataAccess.options.AccessDeletedItems;
import org.atriasoft.archidata.dataAccess.options.OverrideTableName;
import org.atriasoft.archidata.migration.MigrationSqlStep;
import org.atriasoft.karusic.migration.model.CoverConversion;
import org.atriasoft.karusic.migration.model.MediaConversion;
import org.atriasoft.karusic.migration.model.OIDConversion;
import org.kar.archidata.api.DataResource;
import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.dataAccess.options.AccessDeletedItems;
import org.kar.archidata.dataAccess.options.OverrideTableName;
import org.kar.archidata.migration.MigrationSqlStep;
import org.kar.karusic.migration.model.CoverConversion;
import org.kar.karusic.migration.model.MediaConversion;
import org.kar.karusic.migration.model.OIDConversion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

View File

@ -1,10 +1,10 @@
package org.atriasoft.karusic.migration.model;
package org.kar.karusic.migration.model;
import java.util.List;
import java.util.UUID;
import org.bson.types.ObjectId;
import org.atriasoft.archidata.annotation.DataJson;
import org.kar.archidata.annotation.DataJson;
import jakarta.persistence.Id;

View File

@ -1,4 +1,4 @@
package org.atriasoft.karusic.migration.model;
package org.kar.karusic.migration.model;
import java.util.UUID;

View File

@ -1,4 +1,4 @@
package org.atriasoft.karusic.migration.model;
package org.kar.karusic.migration.model;
import java.util.UUID;

View File

@ -0,0 +1,41 @@
package org.kar.karusic.model;
import java.time.LocalDate;
import java.util.List;
import org.bson.types.ObjectId;
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 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<ObjectId> covers = null;
public LocalDate publication = null;
}

View File

@ -0,0 +1,52 @@
package org.kar.karusic.model;
import java.time.LocalDate;
import java.util.List;
import org.bson.types.ObjectId;
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 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<ObjectId> covers = null;
@Column(length = 256)
public String firstName = null;
@Column(length = 256)
public String surname = null;
public LocalDate birth = null;
public LocalDate death = null;
@Override
public String toString() {
return "Artist [id=" + this.id + ", name=" + this.name + ", description=" + this.description + ", covers=" + this.covers + ", firstName=" + this.firstName + ", surname=" + this.surname
+ ", birth=" + this.birth + ", death=" + this.death + "]";
}
}

View File

@ -0,0 +1,59 @@
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 org.bson.types.ObjectId;
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 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<ObjectId> covers = null;
public Gender() {}
public Gender(final Long id, final String name) {
this.id = id;
this.name = name;
}
}

View File

@ -0,0 +1,55 @@
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 org.bson.types.ObjectId;
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 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<ObjectId> covers = null;
@ManyToMany(fetch = FetchType.LAZY, targetEntity = Track.class)
public List<ObjectId> tracks = null;
}

View File

@ -1,4 +1,4 @@
package org.atriasoft.karusic.model;
package org.kar.karusic.model;
public enum State {
// User has remove his account

View File

@ -0,0 +1,66 @@
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 org.bson.types.ObjectId;
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 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<ObjectId> covers = null;
public Long genderId = null;
public Long albumId = null;
public Long track = null;
public ObjectId dataId = null;
// @ManyToMany(fetch = FetchType.LAZY, targetEntity = Artist.class)
@DataJson
@Column(length = 0)
public List<Long> artists = null;
@Override
public String toString() {
return "Track [id=" + this.id + ", deleted=" + this.deleted + ", createdAt=" + this.createdAt + ", updatedAt=" + this.updatedAt + ", name=" + this.name + ", description=" + this.description
+ ", covers=" + this.covers + ", genderId=" + this.genderId + ", albumId=" + this.albumId + ", track=" + this.track + ", dataId=" + this.dataId + ", artists=" + this.artists + "]";
}
}

View File

@ -1,7 +1,7 @@
package org.atriasoft.karusic.model;
package org.kar.karusic.model;
import org.atriasoft.archidata.annotation.DataIfNotExists;
import org.atriasoft.archidata.model.User;
import org.kar.archidata.annotation.DataIfNotExists;
import org.kar.archidata.model.User;
import com.fasterxml.jackson.annotation.JsonInclude;

View File

@ -1,4 +1,4 @@
package org.atriasoft.karusic.util;
package org.kar.karusic.util;
public class ConfigVariable {
public static final String BASE_NAME = "ORG_KARUSIC_";

View File

@ -1,50 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- environment detection (defaut: dev) -->
<property name="LOG_LEVEL_ENV" value="${LOG_LEVEL:-dev}" />
<!-- Appender for development -->
<if condition="property(&quot;LOG_LEVEL_ENV&quot;).equals(&quot;dev&quot;)">
<then>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%green(%d{HH:mm:ss.SSS}) %highlight(%-5level) %-30((%file:%line\)): %msg%n</pattern>
</encoder>
</appender>
<logger name="org.atriasoft.karusic" level="TRACE" />
<logger name="org.atriasoft.archidata" level="DEBUG" />
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
</then>
</if>
<!-- Appender for production -->
<if condition="property(&quot;LOG_LEVEL_ENV&quot;).matches(&quot;^prod.*&quot;)">
<then>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>[%thread] %level %logger - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
</then>
</if>
<if condition="property(&quot;LOG_LEVEL_ENV&quot;).equals(&quot;prod-debug&quot;)">
<then>
<logger name="org.atriasoft.karusic" level="DEBUG" />
</then>
</if>
<if condition="property(&quot;LOG_LEVEL_ENV&quot;).equals(&quot;prod-trace&quot;)">
<then>
<logger name="org.atriasoft.karusic" level="TRACE" />
<logger name="org.atriasoft.archidata" level="DEBUG" />
</then>
</if>
<if condition="property(&quot;LOG_LEVEL_ENV&quot;).equals(&quot;prod-trace-full&quot;)">
<then>
<logger name="org.atriasoft.karusic" level="TRACE" />
<logger name="org.atriasoft.archidata" level="TRACE" />
</then>
</if>
</configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>
%d{HH:mm:ss.SSS} [%thread] %highlight(%-5level) %logger - %msg%n
</pattern>
<!--
<pattern>
%d{HH:mm:ss.SSS} | %thread | %highlight(%-5level) | %logger - %msg%n
</pattern>
-->
</encoder>
</appender>
<root level="info">
<appender-ref ref="CONSOLE" />
</root>
</configuration>

View File

@ -0,0 +1,42 @@
# SLF4J's SimpleLogger configuration file
# Simple implementation of Logger that sends all enabled log messages, for all defined loggers, to System.err.
# Default logging detail level for all instances of SimpleLogger.
# Must be one of ("trace", "debug", "info", "warn", or "error").
# If not specified, defaults to "info".
org.slf4j.simpleLogger.defaultLogLevel=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.
#org.slf4j.simpleLogger.showDateTime=false
# The date and time format to be used in the output messages.
# The pattern describing the date and time format is the same that is used in java.text.SimpleDateFormat.
# If the format is not specified or is invalid, the default format is used.
# The default format is yyyy-MM-dd HH:mm:ss:SSS Z.
#org.slf4j.simpleLogger.dateTimeFormat=yyyy-MM-dd HH:mm:ss:SSS Z
# Set to true if you want to output the current thread name.
# Defaults to true.
org.slf4j.simpleLogger.showThreadName=true
# Set to true if you want the Logger instance name to be included in output messages.
# Defaults to true.
#org.slf4j.simpleLogger.showLogName=true
# Set to true if you want the last component of the name to be included in output messages.
# Defaults to false.
#org.slf4j.simpleLogger.showShortLogName=false
# Utilise les codes ANSI pour la couleur
org.slf4j.simpleLogger.warnColor=\u001B[33m
org.slf4j.simpleLogger.errorColor=\u001B[31m
org.slf4j.simpleLogger.infoColor=\u001B[32m
org.slf4j.simpleLogger.debugColor=\u001B[34m

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@ -1,15 +0,0 @@
package test.atriasoft.karusic;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Objects;
public class ResourceUtils {
public static File getResourceFile(final String resourcePath) throws IOException {
final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
final URL resource = Objects.requireNonNull(classLoader.getResource(resourcePath), "Fichier non trouvé : " + resourcePath);
return new File(resource.getFile());
}
}

View File

@ -1,115 +0,0 @@
package test.atriasoft.karusic;
import java.io.File;
import java.io.IOException;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Map;
import org.atriasoft.archidata.tools.ConfigBaseVariable;
import org.atriasoft.archidata.tools.RESTApi;
import org.atriasoft.karusic.model.Track;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ExtendWith(StepwiseExtension.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class TestTrack {
private final static Logger LOGGER = LoggerFactory.getLogger(TestTrack.class);
public final static String ENDPOINT_NAME = "track";
public final static String ENDPOINT_DATA_NAME = "data";
static WebLauncherTest webInterface = null;
static RESTApi api = null;
@BeforeAll
public static void configureWebServer() throws Exception {
ConfigureDb.configure();
LOGGER.info("configure server ...");
webInterface = new WebLauncherTest();
LOGGER.info("Create BDD");
webInterface.migrateDB();
LOGGER.info("Start REST (BEGIN)");
webInterface.process();
LOGGER.info("Start REST (DONE)");
api = new RESTApi(ConfigBaseVariable.apiAdress);
api.setToken(Common.ADMIN_TOKEN);
}
@AfterAll
public static void stopWebServer() throws Exception {
LOGGER.info("Kill the web server");
webInterface.stop();
webInterface = null;
ConfigureDb.clear();
}
public static boolean compareResponseWithFile(final byte[] responseBody, final File file) throws IOException {
final byte[] fileBytes = Files.readAllBytes(file.toPath());
if (responseBody == null && fileBytes == null) {
return true;
}
if (responseBody == null || fileBytes == null) {
return false;
}
if (responseBody.length != fileBytes.length) {
LOGGER.error("The data have not the same size: {} != {}(ref)", responseBody.length, fileBytes.length);
return false;
}
for (int iii = 0; iii < responseBody.length; iii++) {
if (responseBody[iii] != fileBytes[iii]) {
LOGGER.error("Detect error at the {}/{} element", iii, responseBody.length);
return false;
}
}
return true;
}
@Order(1)
@Test
public void createTrack() throws Exception {
final File dataToUpload = ResourceUtils.getResourceFile("icon-192x192.png");
final Track data = new Track();
data.name = "test track";
data.description = "My track description";
final Map<String, Object> multipart = new HashMap<>();
multipart.put("title", data.name);
multipart.put("genderId", null);
multipart.put("artistId", null);
multipart.put("albumId", null);
multipart.put("trackId", 9);
multipart.put("file", dataToUpload);
final Track inserted = api.request(TestTrack.ENDPOINT_NAME, "upload").post().bodyMultipart(multipart).fetch(Track.class);
Assertions.assertNotNull(inserted);
Assertions.assertNotNull(inserted.oid);
// Assertions.assertTrue(inserted.oid >= 0);
Assertions.assertNull(inserted.updatedAt);
Assertions.assertNull(inserted.createdAt);
Assertions.assertNull(inserted.deleted);
Assertions.assertNotNull(inserted.name);
Assertions.assertEquals(data.name, inserted.name);
Assertions.assertNotNull(inserted.dataId);
// Retrieve Data:
final HttpResponse<byte[]> retreiveData = api.request(TestTrack.ENDPOINT_DATA_NAME, inserted.dataId.toString()).get().fetchByte();
Assertions.assertNotNull(retreiveData);
Assertions.assertEquals(200, retreiveData.statusCode());
Assertions.assertEquals("11999", retreiveData.headers().firstValue("content-length").orElse(null));
final String contentType = retreiveData.headers().firstValue("content-type").orElse(null);
Assertions.assertEquals("image/png", contentType);
Assertions.assertTrue(compareResponseWithFile(retreiveData.body(), dataToUpload));
}
}

View File

@ -1,11 +1,10 @@
package test.atriasoft.karusic;
package test.kar.karusic;
import java.util.Map;
import org.atriasoft.archidata.filter.PartRight;
import org.atriasoft.archidata.tools.JWTWrapper;
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", PartRight.READ)));
static String ADMIN_TOKEN = JWTWrapper.createJwtTestToken(16512, "test_admin_login", "KarAuth", "karusic", Map.of("karusic", Map.of("USER", PartRight.READ_WRITE, "ADMIN", PartRight.READ_WRITE)));
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)));
}

View File

@ -1,12 +1,19 @@
package test.atriasoft.karusic;
package test.kar.karusic;
import java.io.IOException;
import java.util.List;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.db.DbConfig;
import org.atriasoft.archidata.db.DbIoFactory;
import org.atriasoft.archidata.exception.DataAccessException;
import org.atriasoft.archidata.tools.ConfigBaseVariable;
import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.db.DbConfig;
import org.kar.archidata.db.DbIoFactory;
import org.kar.archidata.exception.DataAccessException;
import org.kar.archidata.tools.ConfigBaseVariable;
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;
import org.kar.karusic.model.UserKarusic;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -28,10 +35,14 @@ public class ConfigureDb {
if (modeTestForced != null) {
modeTest = modeTestForced;
}
// for local test:
ConfigBaseVariable.apiAdress = "http://127.0.0.1:12342/test/api/";
// Enable the test mode permit to access to the test token (never use it in production).
ConfigBaseVariable.testMode = "true";
final List<Class<?>> listObject = List.of( //
Album.class, //
Artist.class, //
Gender.class, //
Playlist.class, //
Track.class, //
UserKarusic.class //
);
if ("SQLITE-MEMORY".equalsIgnoreCase(modeTest)) {
ConfigBaseVariable.dbType = "sqlite";
ConfigBaseVariable.bdDatabase = null;
@ -44,15 +55,15 @@ public class ConfigureDb {
ConfigBaseVariable.dbKeepConnected = "true";
} else if ("MY-SQL".equalsIgnoreCase(modeTest)) {
ConfigBaseVariable.dbType = "mysql";
ConfigBaseVariable.bdDatabase = "test.atriasoftusic_db";
ConfigBaseVariable.bdDatabase = "test_karusic_db";
ConfigBaseVariable.dbPort = "3906";
ConfigBaseVariable.dbUser = "root";
} else if ("MONGO".equalsIgnoreCase(modeTest)) {
ConfigBaseVariable.dbType = "mongo";
ConfigBaseVariable.bdDatabase = "test.atriasoftusic_db";
ConfigBaseVariable.bdDatabase = "test_karusic_db";
} else {
// User local modification ...
ConfigBaseVariable.bdDatabase = "test.atriasoftusic_db";
ConfigBaseVariable.bdDatabase = "test_karusic_db";
ConfigBaseVariable.dbPort = "3906";
ConfigBaseVariable.dbUser = "root";
}

View File

@ -1,4 +1,4 @@
package test.atriasoft.karusic;
package test.kar.karusic;
import org.junit.jupiter.api.extension.ConditionEvaluationResult;
import org.junit.jupiter.api.extension.ExecutionCondition;

View File

@ -1,24 +1,21 @@
package test.atriasoft.karusic;
package test.kar.karusic;
import org.atriasoft.archidata.exception.RESTErrorResponseException;
import org.atriasoft.archidata.tools.ConfigBaseVariable;
import org.atriasoft.archidata.tools.RESTApi;
import org.atriasoft.karusic.api.HealthCheck.HealthResult;
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.tools.ConfigBaseVariable;
import org.kar.archidata.tools.RESTApi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ExtendWith(StepwiseExtension.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class TestHealthCheck {
private final static Logger LOGGER = LoggerFactory.getLogger(TestHealthCheck.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;
@ -28,6 +25,8 @@ public class TestHealthCheck {
ConfigureDb.configure();
LOGGER.info("configure server ...");
webInterface = new WebLauncherTest();
LOGGER.info("Clean previous table");
LOGGER.info("Start REST (BEGIN)");
webInterface.process();
LOGGER.info("Start REST (DONE)");
@ -43,17 +42,9 @@ public class TestHealthCheck {
ConfigureDb.clear();
}
@Order(1)
@Test
public void checkHealthCheck() throws Exception {
final HealthResult result = api.request("health_check").get().fetch(HealthResult.class);
Assertions.assertEquals(result.value(), "alive and kicking");
}
public static void TestEmpty() throws Exception {
@Order(2)
@Test
public void checkHealthCheckWrongAPI() throws Exception {
Assertions.assertThrows(RESTErrorResponseException.class, () -> api.request("health_check_kaboom").get().fetch());
}
}

View File

@ -1,7 +1,7 @@
package test.atriasoft.karusic;
package test.kar.karusic;
import org.atriasoft.karusic.WebLauncher;
import org.kar.karusic.WebLauncher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

View File

@ -1 +0,0 @@
NODE_ENV=development

View File

@ -4,11 +4,23 @@ import { Box } from '@chakra-ui/react';
import { ChakraProvider } from '@chakra-ui/react';
import { MemoryRouter } from 'react-router-dom';
import { ColorModeProvider } from '../src/components/ui/color-mode';
import { Toaster } from '../src/components/ui/toaster';
import { systemTheme } from '../src/theme/theme';
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">
@ -19,16 +31,13 @@ const DocumentationWrapper = ({ children }) => {
export const decorators = [
(Story, context) => (
<ColorModeProvider>
<ChakraProvider value={systemTheme}>
{/* Using MemoryRouter to avoid route clashing with Storybook */}
<MemoryRouter>
<DocumentationWrapper>
<Story {...context} />
</DocumentationWrapper>
</MemoryRouter>
<Toaster />
</ChakraProvider>
</ColorModeProvider>
<ChakraProvider theme={theme}>
{/* Using MemoryRouter to avoid route clashing with Storybook */}
<MemoryRouter>
<DocumentationWrapper>
<Story {...context} />
</DocumentationWrapper>
</MemoryRouter>
</ChakraProvider>
),
];

6
front/app-build.json Normal file
View File

@ -0,0 +1,6 @@
{
"display": "2025-01-06",
"version": "0.0.1-dev\n - 2025-01-06T00:49:52+01:00",
"commit": "0.0.1-dev\n",
"date": "2025-01-06T00:49:52+01:00"
}

25
front/build.js Normal file
View 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();

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,6 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="manifest" href="/manifest.json" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Karusic</title>
<link rel="icon" href="/favicon.ico" />

View File

@ -3,7 +3,16 @@ import type { KnipConfig } from 'knip';
const config: KnipConfig = {
// Ignoring mostly shell binaries
ignoreBinaries: ['export', 'sleep'],
ignore: [],
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;

View File

@ -12,13 +12,12 @@
"node": ">=20"
},
"scripts": {
"update_packages": "ncu --target minor",
"upgrade_packages": "ncu --upgrade ",
"update_packages": "ncu --upgrade",
"install_dependency": "pnpm install",
"test": "vitest run",
"test:watch": "vitest watch",
"build": "tsc && vite build",
"static:build": "pnpm build",
"static:build": "node build.js && pnpm build",
"dev": "vite",
"pretty": "prettier -w .",
"lint": "pnpm tsc --noEmit",
@ -29,65 +28,84 @@
"*.{ts,tsx,js,jsx,json}": "prettier --write"
},
"dependencies": {
"react-speech-recognition": "4.0.1",
"regenerator-runtime": "0.14.1",
"@trivago/prettier-plugin-sort-imports": "5.2.2",
"@chakra-ui/cli": "3.17.0",
"@chakra-ui/react": "3.17.0",
"@chakra-ui/anatomy": "2.2.2",
"@chakra-ui/cli": "2.4.1",
"@chakra-ui/react": "2.8.2",
"@chakra-ui/theme-tools": "2.2.6",
"@dnd-kit/core": "6.3.1",
"@dnd-kit/modifiers": "9.0.0",
"@dnd-kit/sortable": "10.0.0",
"@dnd-kit/utilities": "3.2.2",
"@emotion/react": "11.14.0",
"allotment": "1.20.3",
"@emotion/styled": "11.14.0",
"@formiz/core": "2.4.5",
"@formiz/validations": "2.0.1",
"allotment": "1.20.2",
"css-mediaquery": "0.1.2",
"dayjs": "1.11.13",
"history": "5.3.0",
"next-themes": "^0.4.6",
"react": "19.1.0",
"react-dom": "19.1.0",
"react-error-boundary": "5.0.0",
"react-icons": "5.5.0",
"react-router-dom": "7.5.3",
"react-select": "5.10.1",
"react": "18.3.1",
"react-color-palette": "7.3.0",
"react-currency-input-field": "3.9.0",
"react-custom-scrollbars": "4.2.1",
"react-day-picker": "9.5.0",
"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.9.0",
"react-simple-keyboard": "3.8.33",
"react-sticky-el": "2.1.1",
"react-use": "17.6.0",
"zod": "3.24.3",
"zustand": "5.0.3"
"react-use-draggable-scroll": "0.4.7",
"react-virtuoso": "4.12.3",
"ts-pattern": "5.6.0",
"uuid": "11.0.4",
"zod": "3.24.1",
"zustand": "5.0.2"
},
"devDependencies": {
"@chakra-ui/styled-system": "^2.12.0",
"@playwright/test": "1.52.0",
"@storybook/addon-actions": "8.6.12",
"@storybook/addon-essentials": "8.6.12",
"@storybook/addon-links": "8.6.12",
"@storybook/addon-mdx-gfm": "8.6.12",
"@storybook/react": "8.6.12",
"@storybook/react-vite": "8.6.12",
"@storybook/theming": "8.6.12",
"@chakra-ui/styled-system": "2.12.0",
"@playwright/test": "1.49.1",
"@storybook/addon-actions": "8.4.7",
"@storybook/addon-essentials": "8.4.7",
"@storybook/addon-links": "8.4.7",
"@storybook/addon-mdx-gfm": "8.4.7",
"@storybook/react": "8.4.7",
"@storybook/react-vite": "8.4.7",
"@storybook/theming": "8.4.7",
"@testing-library/jest-dom": "6.6.3",
"@testing-library/react": "16.3.0",
"@testing-library/user-event": "14.6.1",
"@trivago/prettier-plugin-sort-imports": "5.2.2",
"@testing-library/react": "16.1.0",
"@testing-library/user-event": "14.5.2",
"@trivago/prettier-plugin-sort-imports": "5.2.1",
"@types/jest": "29.5.14",
"@types/node": "22.15.3",
"@types/react": "19.1.2",
"@types/react-dom": "19.1.3",
"@typescript-eslint/eslint-plugin": "8.31.1",
"@typescript-eslint/parser": "8.31.1",
"@vitejs/plugin-react": "4.4.1",
"eslint": "9.25.1",
"@types/node": "22.10.5",
"@types/react": "18.3.8",
"@types/react-dom": "18.3.0",
"@types/react-sticky-el": "1.0.7",
"@typescript-eslint/eslint-plugin": "8.19.0",
"@typescript-eslint/parser": "8.19.0",
"@vitejs/plugin-react": "4.3.4",
"eslint": "9.17.0",
"eslint-plugin-codeceptjs": "1.3.0",
"eslint-plugin-import": "2.31.0",
"eslint-plugin-react": "7.37.5",
"eslint-plugin-react-hooks": "5.2.0",
"eslint-plugin-storybook": "0.12.0",
"eslint-plugin-react": "7.37.3",
"eslint-plugin-react-hooks": "5.1.0",
"eslint-plugin-storybook": "0.11.2",
"jest": "29.7.0",
"jest-environment-jsdom": "29.7.0",
"knip": "5.52.0",
"lint-staged": "15.5.1",
"npm-check-updates": "^18.0.1",
"prettier": "3.5.3",
"puppeteer": "24.7.2",
"react-is": "19.1.0",
"storybook": "8.6.12",
"knip": "5.41.1",
"lint-staged": "15.3.0",
"npm-check-updates": "^17.1.13",
"prettier": "3.4.2",
"puppeteer": "23.11.1",
"react-is": "19.0.0",
"storybook": "8.4.7",
"ts-node": "10.9.2",
"typescript": "5.8.3",
"vite": "6.3.4",
"vitest": "3.1.2"
"typescript": "5.7.2",
"vite": "6.0.7",
"vitest": "2.1.8"
}
}

7643
front/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

View File

@ -1,21 +0,0 @@
{
"name": "Karusic",
"short_name": "Karusic",
"description": "(K)angaroo (A)nd (R)abbit m(usic) is a music streaming",
"start_url": "/karusic/",
"display": "standalone",
"background_color": "#000000",
"theme_color": "#FFFFFF",
"icons": [
{
"src": "/karusic/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/karusic/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}

View File

@ -1,19 +1,117 @@
import { ErrorBoundary } from '@/errors/ErrorBoundary';
import { useState } from 'react';
import { AudioPlayer } from './components';
import { EnvDevelopment } from './components/EnvDevelopment/EnvDevelopment';
import { AppRoutes } from './scene/AppRoutes';
import { ServiceContextProvider } from './service/ServiceContext';
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]}`;
}
};
export const App = () => {
return (
<ServiceContextProvider>
<EnvDevelopment />
<ErrorBoundary>
<AppRoutes />
</ErrorBoundary>
<AudioPlayer />
</ServiceContextProvider>
<>
<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>
);
};

View File

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
stroke="currentColor"
fill="currentColor"
stroke-width="0"
viewBox="0 0 24 24"
height="250px"
width="250px"
version="1.1"
id="svg2"
sodipodi:docname="404.svg"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs2" />
<sodipodi:namedview
id="namedview2"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="true"
inkscape:zoom="3.448"
inkscape:cx="134.28074"
inkscape:cy="125"
inkscape:window-width="1918"
inkscape:window-height="1044"
inkscape:window-x="0"
inkscape:window-y="17"
inkscape:window-maximized="1"
inkscape:current-layer="svg2">
<inkscape:grid
id="grid2"
units="px"
originx="0"
originy="0"
spacingx="0.096"
spacingy="0.096"
empcolor="#0099e5"
empopacity="0.30196078"
color="#0099e5"
opacity="0.14901961"
empspacing="5"
dotted="false"
gridanglex="30"
gridanglez="30"
visible="true" />
</sodipodi:namedview>
<path
fill="none"
d="M0 0h24v24H0z"
id="path1" />
<path
d="M13 10h5l3-3-3-3h-5V2h-2v2H4v6h7v2H6l-3 3 3 3h5v4h2v-4h7v-6h-7z"
id="path2" />
<path
id="rect2"
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.384;stroke-linecap:square"
d="M 17.394219,5.0400499 19.459554,6.9903325 17.438107,9.0722051 4.9259029,9.0569946 4.9284452,5.0338374 Z"
sodipodi:nodetypes="cccccc" />
<path
id="rect2-3"
style="fill:#f8fefb;fill-opacity:1;stroke:none;stroke-width:0.384;stroke-linecap:square"
d="m 6.5757719,13.021525 -2.065335,1.950283 2.021447,2.081873 12.5122061,-0.01521 -0.0025,-4.023157 z"
sodipodi:nodetypes="cccccc" />
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -13,9 +13,9 @@ import {
import { z as zod } from "zod"
import {
Album,
AlbumCreate,
AlbumUpdate,
ObjectId,
AlbumWrite,
Long,
UUID,
ZodAlbum,
isAlbum,
} from "../model";
@ -31,12 +31,12 @@ export namespace AlbumResource {
}: {
restConfig: RESTConfig,
params: {
oid: ObjectId,
id: Long,
},
}): Promise<Album> {
return RESTRequestJson({
restModel: {
endPoint: "/album/{oid}",
endPoint: "/album/{id}",
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON,
},
@ -75,6 +75,32 @@ export namespace AlbumResource {
restConfig,
}, isGetsTypeReturn);
};
/**
* Update a specific album
*/
export function patch({
restConfig,
params,
data,
}: {
restConfig: RESTConfig,
params: {
id: Long,
},
data: AlbumWrite,
}): Promise<Album> {
return RESTRequestJson({
restModel: {
endPoint: "/album/{id}",
requestType: HTTPRequestModel.PATCH,
contentType: HTTPMimeType.JSON,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
}, isAlbum);
};
/**
* Add an album (when all the data already exist)
*/
@ -83,7 +109,7 @@ export namespace AlbumResource {
data,
}: {
restConfig: RESTConfig,
data: AlbumCreate,
data: AlbumWrite,
}): Promise<Album> {
return RESTRequestJson({
restModel: {
@ -96,32 +122,6 @@ export namespace AlbumResource {
data,
}, isAlbum);
};
/**
* Update a specific album
*/
export function put({
restConfig,
params,
data,
}: {
restConfig: RESTConfig,
params: {
oid: ObjectId,
},
data: AlbumUpdate,
}): Promise<Album> {
return RESTRequestJson({
restModel: {
endPoint: "/album/{oid}",
requestType: HTTPRequestModel.PUT,
contentType: HTTPMimeType.JSON,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
}, isAlbum);
};
/**
* Remove a specific album
*/
@ -131,12 +131,12 @@ export namespace AlbumResource {
}: {
restConfig: RESTConfig,
params: {
oid: ObjectId,
id: Long,
},
}): Promise<void> {
return RESTRequestVoid({
restModel: {
endPoint: "/album/{oid}",
endPoint: "/album/{id}",
requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN,
},
@ -153,13 +153,13 @@ export namespace AlbumResource {
}: {
restConfig: RESTConfig,
params: {
coverId: ObjectId,
oid: ObjectId,
coverId: UUID,
id: Long,
},
}): Promise<Album> {
return RESTRequestJson({
restModel: {
endPoint: "/album/{oid}/cover/{coverId}",
endPoint: "/album/{id}/cover/{coverId}",
requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN,
accept: HTTPMimeType.JSON,
@ -179,7 +179,7 @@ export namespace AlbumResource {
}: {
restConfig: RESTConfig,
params: {
oid: ObjectId,
id: Long,
},
data: {
file?: File,
@ -189,7 +189,7 @@ export namespace AlbumResource {
}): Promise<Album> {
return RESTRequestJson({
restModel: {
endPoint: "/album/{oid}/cover",
endPoint: "/album/{id}/cover",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,

View File

@ -13,8 +13,8 @@ import {
import { z as zod } from "zod"
import {
Artist,
ArtistCreate,
ArtistUpdate,
ArtistWrite,
Long,
ObjectId,
ZodArtist,
isArtist,
@ -28,12 +28,12 @@ export namespace ArtistResource {
}: {
restConfig: RESTConfig,
params: {
oid: ObjectId,
id: Long,
},
}): Promise<Artist> {
return RESTRequestJson({
restModel: {
endPoint: "/artist/{oid}",
endPoint: "/artist/{id}",
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON,
},
@ -69,12 +69,35 @@ export namespace ArtistResource {
restConfig,
}, isGetsTypeReturn);
};
export function patch({
restConfig,
params,
data,
}: {
restConfig: RESTConfig,
params: {
id: Long,
},
data: ArtistWrite,
}): Promise<Artist> {
return RESTRequestJson({
restModel: {
endPoint: "/artist/{id}",
requestType: HTTPRequestModel.PATCH,
contentType: HTTPMimeType.JSON,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
}, isArtist);
};
export function post({
restConfig,
data,
}: {
restConfig: RESTConfig,
data: ArtistCreate,
data: ArtistWrite,
}): Promise<Artist> {
return RESTRequestJson({
restModel: {
@ -87,41 +110,18 @@ export namespace ArtistResource {
data,
}, isArtist);
};
export function put({
restConfig,
params,
data,
}: {
restConfig: RESTConfig,
params: {
oid: ObjectId,
},
data: ArtistUpdate,
}): Promise<Artist> {
return RESTRequestJson({
restModel: {
endPoint: "/artist/{oid}",
requestType: HTTPRequestModel.PUT,
contentType: HTTPMimeType.JSON,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
}, isArtist);
};
export function remove({
restConfig,
params,
}: {
restConfig: RESTConfig,
params: {
oid: ObjectId,
id: Long,
},
}): Promise<void> {
return RESTRequestVoid({
restModel: {
endPoint: "/artist/{oid}",
endPoint: "/artist/{id}",
requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN,
},
@ -136,12 +136,12 @@ export namespace ArtistResource {
restConfig: RESTConfig,
params: {
coverId: ObjectId,
oid: ObjectId,
id: Long,
},
}): Promise<Artist> {
return RESTRequestJson({
restModel: {
endPoint: "/artist/{oid}/cover/{coverId}",
endPoint: "/artist/{id}/cover/{coverId}",
requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN,
accept: HTTPMimeType.JSON,
@ -158,7 +158,7 @@ export namespace ArtistResource {
}: {
restConfig: RESTConfig,
params: {
oid: ObjectId,
id: Long,
},
data: {
file?: File,
@ -168,7 +168,7 @@ export namespace ArtistResource {
}): Promise<Artist> {
return RESTRequestJson({
restModel: {
endPoint: "/artist/{oid}/cover",
endPoint: "/artist/{id}/cover",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,

View File

@ -22,7 +22,7 @@ export namespace DataResource {
restConfig,
queries,
params,
headers,
data,
}: {
restConfig: RESTConfig,
queries: {
@ -32,9 +32,7 @@ export namespace DataResource {
name: string,
oid: ObjectId,
},
headers?: {
Range?: string,
},
data: string,
}): Promise<object> {
return RESTRequestJson({
restModel: {
@ -44,7 +42,7 @@ export namespace DataResource {
restConfig,
params,
queries,
headers,
data,
});
};
/**
@ -54,7 +52,7 @@ export namespace DataResource {
restConfig,
queries,
params,
headers,
data,
}: {
restConfig: RESTConfig,
queries: {
@ -63,9 +61,7 @@ export namespace DataResource {
params: {
oid: ObjectId,
},
headers?: {
Range: string,
},
data: string,
}): Promise<object> {
return RESTRequestJson({
restModel: {
@ -75,7 +71,7 @@ export namespace DataResource {
restConfig,
params,
queries,
headers,
data,
});
};
/**
@ -85,7 +81,7 @@ export namespace DataResource {
restConfig,
queries,
params,
headers,
data,
}: {
restConfig: RESTConfig,
queries: {
@ -94,9 +90,7 @@ export namespace DataResource {
params: {
oid: ObjectId,
},
headers?: {
Range: string,
},
data: string,
}): Promise<object> {
return RESTRequestJson({
restModel: {
@ -106,7 +100,7 @@ export namespace DataResource {
restConfig,
params,
queries,
headers,
data,
});
};
/**

View File

@ -13,8 +13,8 @@ import {
import { z as zod } from "zod"
import {
Gender,
GenderCreate,
GenderUpdate,
GenderWrite,
Long,
ObjectId,
ZodGender,
isGender,
@ -28,12 +28,12 @@ export namespace GenderResource {
}: {
restConfig: RESTConfig,
params: {
oid: ObjectId,
id: Long,
},
}): Promise<Gender> {
return RESTRequestJson({
restModel: {
endPoint: "/gender/{oid}",
endPoint: "/gender/{id}",
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON,
},
@ -76,14 +76,14 @@ export namespace GenderResource {
}: {
restConfig: RESTConfig,
params: {
oid: ObjectId,
id: Long,
},
data: GenderUpdate,
data: GenderWrite,
}): Promise<Gender> {
return RESTRequestJson({
restModel: {
endPoint: "/gender/{oid}",
requestType: HTTPRequestModel.PUT,
endPoint: "/gender/{id}",
requestType: HTTPRequestModel.PATCH,
contentType: HTTPMimeType.JSON,
accept: HTTPMimeType.JSON,
},
@ -97,7 +97,7 @@ export namespace GenderResource {
data,
}: {
restConfig: RESTConfig,
data: GenderCreate,
data: GenderWrite,
}): Promise<Gender> {
return RESTRequestJson({
restModel: {
@ -116,12 +116,12 @@ export namespace GenderResource {
}: {
restConfig: RESTConfig,
params: {
oid: ObjectId,
id: Long,
},
}): Promise<void> {
return RESTRequestVoid({
restModel: {
endPoint: "/gender/{oid}",
endPoint: "/gender/{id}",
requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN,
},
@ -136,12 +136,12 @@ export namespace GenderResource {
restConfig: RESTConfig,
params: {
coverId: ObjectId,
oid: ObjectId,
id: Long,
},
}): Promise<Gender> {
return RESTRequestJson({
restModel: {
endPoint: "/gender/{oid}/cover/{coverId}",
endPoint: "/gender/{id}/cover/{coverId}",
requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN,
accept: HTTPMimeType.JSON,
@ -158,7 +158,7 @@ export namespace GenderResource {
}: {
restConfig: RESTConfig,
params: {
oid: ObjectId,
id: Long,
},
data: {
file?: File,
@ -168,7 +168,7 @@ export namespace GenderResource {
}): Promise<Gender> {
return RESTRequestJson({
restModel: {
endPoint: "/gender/{oid}/cover",
endPoint: "/gender/{id}/cover",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,

View File

@ -11,23 +11,44 @@ import {
import { z as zod } from "zod"
import {
Long,
ObjectId,
Playlist,
PlaylistCreate,
PlaylistUpdate,
PlaylistWrite,
ZodPlaylist,
isPlaylist,
} from "../model";
export namespace PlaylistResource {
export function addTrack({
restConfig,
params,
}: {
restConfig: RESTConfig,
params: {
trackId: Long,
id: Long,
},
}): Promise<Playlist> {
return RESTRequestJson({
restModel: {
endPoint: "/playlist/{id}/track/{trackId}",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isPlaylist);
};
export function get({
restConfig,
params,
}: {
restConfig: RESTConfig,
params: {
id: ObjectId,
id: Long,
},
}): Promise<Playlist> {
return RESTRequestJson({
@ -68,12 +89,35 @@ export namespace PlaylistResource {
restConfig,
}, isGetsTypeReturn);
};
export function patch({
restConfig,
params,
data,
}: {
restConfig: RESTConfig,
params: {
id: Long,
},
data: PlaylistWrite,
}): Promise<Playlist> {
return RESTRequestJson({
restModel: {
endPoint: "/playlist/{id}",
requestType: HTTPRequestModel.PATCH,
contentType: HTTPMimeType.JSON,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
}, isPlaylist);
};
export function post({
restConfig,
data,
}: {
restConfig: RESTConfig,
data: PlaylistCreate,
data: PlaylistWrite,
}): Promise<Playlist> {
return RESTRequestJson({
restModel: {
@ -86,41 +130,18 @@ export namespace PlaylistResource {
data,
}, isPlaylist);
};
export function put({
restConfig,
params,
data,
}: {
restConfig: RESTConfig,
params: {
oid: ObjectId,
},
data: PlaylistUpdate,
}): Promise<Playlist> {
return RESTRequestJson({
restModel: {
endPoint: "/playlist/{oid}",
requestType: HTTPRequestModel.PUT,
contentType: HTTPMimeType.JSON,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
}, isPlaylist);
};
export function remove({
restConfig,
params,
}: {
restConfig: RESTConfig,
params: {
oid: ObjectId,
id: Long,
},
}): Promise<void> {
return RESTRequestVoid({
restModel: {
endPoint: "/playlist/{oid}",
endPoint: "/playlist/{id}",
requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN,
},
@ -135,12 +156,33 @@ export namespace PlaylistResource {
restConfig: RESTConfig,
params: {
coverId: ObjectId,
oid: ObjectId,
id: Long,
},
}): Promise<Playlist> {
return RESTRequestJson({
restModel: {
endPoint: "/playlist/{oid}/cover/{coverId}",
endPoint: "/playlist/{id}/cover/{coverId}",
requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isPlaylist);
};
export function removeTrack({
restConfig,
params,
}: {
restConfig: RESTConfig,
params: {
trackId: Long,
id: Long,
},
}): Promise<Playlist> {
return RESTRequestJson({
restModel: {
endPoint: "/playlist/{id}/track/{trackId}",
requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN,
accept: HTTPMimeType.JSON,
@ -156,7 +198,7 @@ export namespace PlaylistResource {
}: {
restConfig: RESTConfig,
params: {
oid: ObjectId,
id: Long,
},
data: {
file: File,
@ -164,7 +206,7 @@ export namespace PlaylistResource {
}): Promise<Playlist> {
return RESTRequestJson({
restModel: {
endPoint: "/playlist/{oid}/cover",
endPoint: "/playlist/{id}/cover",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,

View File

@ -15,26 +15,46 @@ import {
Long,
ObjectId,
Track,
TrackCreate,
TrackUpdate,
TrackWrite,
ZodTrack,
isTrack,
} from "../model";
export namespace TrackResource {
export function addTrack({
restConfig,
params,
}: {
restConfig: RESTConfig,
params: {
artistId: Long,
id: Long,
},
}): Promise<Track> {
return RESTRequestJson({
restModel: {
endPoint: "/track/{id}/artist/{artistId}",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isTrack);
};
export function get({
restConfig,
params,
}: {
restConfig: RESTConfig,
params: {
oid: ObjectId,
id: Long,
},
}): Promise<Track> {
return RESTRequestJson({
restModel: {
endPoint: "/track/{oid}",
endPoint: "/track/{id}",
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON,
},
@ -70,12 +90,35 @@ export namespace TrackResource {
restConfig,
}, isGetsTypeReturn);
};
export function patch({
restConfig,
params,
data,
}: {
restConfig: RESTConfig,
params: {
id: Long,
},
data: TrackWrite,
}): Promise<Track> {
return RESTRequestJson({
restModel: {
endPoint: "/track/{id}",
requestType: HTTPRequestModel.PATCH,
contentType: HTTPMimeType.JSON,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
}, isTrack);
};
export function post({
restConfig,
data,
}: {
restConfig: RESTConfig,
data: TrackCreate,
data: TrackWrite,
}): Promise<Track> {
return RESTRequestJson({
restModel: {
@ -88,41 +131,18 @@ export namespace TrackResource {
data,
}, isTrack);
};
export function put({
restConfig,
params,
data,
}: {
restConfig: RESTConfig,
params: {
oid: ObjectId,
},
data: TrackUpdate,
}): Promise<Track> {
return RESTRequestJson({
restModel: {
endPoint: "/track/{oid}",
requestType: HTTPRequestModel.PUT,
contentType: HTTPMimeType.JSON,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
}, isTrack);
};
export function remove({
restConfig,
params,
}: {
restConfig: RESTConfig,
params: {
oid: ObjectId,
id: Long,
},
}): Promise<void> {
return RESTRequestVoid({
restModel: {
endPoint: "/track/{oid}",
endPoint: "/track/{id}",
requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN,
},
@ -137,12 +157,33 @@ export namespace TrackResource {
restConfig: RESTConfig,
params: {
coverId: ObjectId,
oid: ObjectId,
id: Long,
},
}): Promise<Track> {
return RESTRequestJson({
restModel: {
endPoint: "/track/{oid}/cover/{coverId}",
endPoint: "/track/{id}/cover/{coverId}",
requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isTrack);
};
export function removeTrack({
restConfig,
params,
}: {
restConfig: RESTConfig,
params: {
artistId: Long,
id: Long,
},
}): Promise<Track> {
return RESTRequestJson({
restModel: {
endPoint: "/track/{id}/artist/{trackId}",
requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN,
accept: HTTPMimeType.JSON,
@ -159,7 +200,7 @@ export namespace TrackResource {
}: {
restConfig: RESTConfig,
params: {
oid: ObjectId,
id: Long,
},
data: {
file: File,
@ -169,7 +210,7 @@ export namespace TrackResource {
}): Promise<Track> {
return RESTRequestJson({
restModel: {
endPoint: "/track/{oid}/cover",
endPoint: "/track/{id}/cover",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
@ -189,9 +230,9 @@ export namespace TrackResource {
data: {
file: File,
trackId?: Long,
genderId?: ObjectId,
albumId?: ObjectId,
artistId?: ObjectId,
genderId?: Long,
albumId?: Long,
artistId?: Long,
title: string,
},
callbacks?: RESTCallbacks,

View File

@ -3,18 +3,18 @@
*/
import { z as zod } from "zod";
import {ZodIsoDate} from "./iso-date";
import {ZodObjectId} from "./object-id";
import {ZodOIDGenericDataSoftDelete, ZodOIDGenericDataSoftDeleteUpdate , ZodOIDGenericDataSoftDeleteCreate } from "./oid-generic-data-soft-delete";
import {ZodLocalDate} from "./local-date";
import {ZodGenericDataSoftDelete, ZodGenericDataSoftDeleteWrite } from "./generic-data-soft-delete";
export const ZodAlbum = ZodOIDGenericDataSoftDelete.extend({
name: zod.string().min(1).max(256).optional(),
description: zod.string().max(8192).optional(),
export const ZodAlbum = ZodGenericDataSoftDelete.extend({
name: zod.string().max(256).optional(),
description: zod.string().optional(),
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodObjectId).readonly().optional(),
publication: ZodIsoDate.optional(),
covers: zod.array(ZodObjectId).optional(),
publication: ZodLocalDate.optional(),
});
@ -29,39 +29,25 @@ export function isAlbum(data: any): data is Album {
return false;
}
}
export const ZodAlbumUpdate = ZodOIDGenericDataSoftDeleteUpdate.extend({
name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().max(8192).nullable().optional(),
publication: ZodIsoDate.nullable().optional(),
export const ZodAlbumWrite = ZodGenericDataSoftDeleteWrite.extend({
name: zod.string().max(256).nullable().optional(),
description: zod.string().nullable().optional(),
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodObjectId).nullable().optional(),
publication: ZodLocalDate.nullable().optional(),
});
export type AlbumUpdate = zod.infer<typeof ZodAlbumUpdate>;
export type AlbumWrite = zod.infer<typeof ZodAlbumWrite>;
export function isAlbumUpdate(data: any): data is AlbumUpdate {
export function isAlbumWrite(data: any): data is AlbumWrite {
try {
ZodAlbumUpdate.parse(data);
ZodAlbumWrite.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodAlbumUpdate' error=${e}`);
return false;
}
}
export const ZodAlbumCreate = ZodOIDGenericDataSoftDeleteCreate.extend({
name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().max(8192).nullable().optional(),
publication: ZodIsoDate.nullable().optional(),
});
export type AlbumCreate = zod.infer<typeof ZodAlbumCreate>;
export function isAlbumCreate(data: any): data is AlbumCreate {
try {
ZodAlbumCreate.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodAlbumCreate' error=${e}`);
console.log(`Fail to parse data type='ZodAlbumWrite' error=${e}`);
return false;
}
}

View File

@ -3,21 +3,21 @@
*/
import { z as zod } from "zod";
import {ZodIsoDate} from "./iso-date";
import {ZodObjectId} from "./object-id";
import {ZodOIDGenericDataSoftDelete, ZodOIDGenericDataSoftDeleteUpdate , ZodOIDGenericDataSoftDeleteCreate } from "./oid-generic-data-soft-delete";
import {ZodLocalDate} from "./local-date";
import {ZodGenericDataSoftDelete, ZodGenericDataSoftDeleteWrite } from "./generic-data-soft-delete";
export const ZodArtist = ZodOIDGenericDataSoftDelete.extend({
name: zod.string().min(1).max(256).optional(),
description: zod.string().max(8192).optional(),
export const ZodArtist = ZodGenericDataSoftDelete.extend({
name: zod.string().max(256).optional(),
description: zod.string().optional(),
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodObjectId).readonly().optional(),
firstName: zod.string().min(1).max(256).optional(),
surname: zod.string().min(1).max(256).optional(),
birth: ZodIsoDate.optional(),
death: ZodIsoDate.optional(),
covers: zod.array(ZodObjectId).optional(),
firstName: zod.string().max(256).optional(),
surname: zod.string().max(256).optional(),
birth: ZodLocalDate.optional(),
death: ZodLocalDate.optional(),
});
@ -32,45 +32,28 @@ export function isArtist(data: any): data is Artist {
return false;
}
}
export const ZodArtistUpdate = ZodOIDGenericDataSoftDeleteUpdate.extend({
name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().max(8192).nullable().optional(),
firstName: zod.string().min(1).max(256).nullable().optional(),
surname: zod.string().min(1).max(256).nullable().optional(),
birth: ZodIsoDate.nullable().optional(),
death: ZodIsoDate.nullable().optional(),
export const ZodArtistWrite = ZodGenericDataSoftDeleteWrite.extend({
name: zod.string().max(256).nullable().optional(),
description: zod.string().nullable().optional(),
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodObjectId).nullable().optional(),
firstName: zod.string().max(256).nullable().optional(),
surname: zod.string().max(256).nullable().optional(),
birth: ZodLocalDate.nullable().optional(),
death: ZodLocalDate.nullable().optional(),
});
export type ArtistUpdate = zod.infer<typeof ZodArtistUpdate>;
export type ArtistWrite = zod.infer<typeof ZodArtistWrite>;
export function isArtistUpdate(data: any): data is ArtistUpdate {
export function isArtistWrite(data: any): data is ArtistWrite {
try {
ZodArtistUpdate.parse(data);
ZodArtistWrite.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodArtistUpdate' error=${e}`);
return false;
}
}
export const ZodArtistCreate = ZodOIDGenericDataSoftDeleteCreate.extend({
name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().max(8192).nullable().optional(),
firstName: zod.string().min(1).max(256).nullable().optional(),
surname: zod.string().min(1).max(256).nullable().optional(),
birth: ZodIsoDate.nullable().optional(),
death: ZodIsoDate.nullable().optional(),
});
export type ArtistCreate = zod.infer<typeof ZodArtistCreate>;
export function isArtistCreate(data: any): data is ArtistCreate {
try {
ZodArtistCreate.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodArtistCreate' error=${e}`);
console.log(`Fail to parse data type='ZodArtistWrite' error=${e}`);
return false;
}
}

View File

@ -4,15 +4,15 @@
import { z as zod } from "zod";
import {ZodObjectId} from "./object-id";
import {ZodOIDGenericDataSoftDelete, ZodOIDGenericDataSoftDeleteUpdate , ZodOIDGenericDataSoftDeleteCreate } from "./oid-generic-data-soft-delete";
import {ZodGenericDataSoftDelete, ZodGenericDataSoftDeleteWrite } from "./generic-data-soft-delete";
export const ZodGender = ZodOIDGenericDataSoftDelete.extend({
name: zod.string().min(1).max(256).optional(),
description: zod.string().max(8192).optional(),
export const ZodGender = ZodGenericDataSoftDelete.extend({
name: zod.string().max(256).optional(),
description: zod.string().optional(),
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodObjectId).readonly().optional(),
covers: zod.array(ZodObjectId).optional(),
});
@ -27,37 +27,24 @@ export function isGender(data: any): data is Gender {
return false;
}
}
export const ZodGenderUpdate = ZodOIDGenericDataSoftDeleteUpdate.extend({
name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().max(8192).nullable().optional(),
export const ZodGenderWrite = ZodGenericDataSoftDeleteWrite.extend({
name: zod.string().max(256).nullable().optional(),
description: zod.string().nullable().optional(),
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodObjectId).nullable().optional(),
});
export type GenderUpdate = zod.infer<typeof ZodGenderUpdate>;
export type GenderWrite = zod.infer<typeof ZodGenderWrite>;
export function isGenderUpdate(data: any): data is GenderUpdate {
export function isGenderWrite(data: any): data is GenderWrite {
try {
ZodGenderUpdate.parse(data);
ZodGenderWrite.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodGenderUpdate' error=${e}`);
return false;
}
}
export const ZodGenderCreate = ZodOIDGenericDataSoftDeleteCreate.extend({
name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().max(8192).nullable().optional(),
});
export type GenderCreate = zod.infer<typeof ZodGenderCreate>;
export function isGenderCreate(data: any): data is GenderCreate {
try {
ZodGenderCreate.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodGenderCreate' error=${e}`);
console.log(`Fail to parse data type='ZodGenderWrite' error=${e}`);
return false;
}
}

View File

@ -3,7 +3,7 @@
*/
import { z as zod } from "zod";
import {ZodGenericData, ZodGenericDataUpdate , ZodGenericDataCreate } from "./generic-data";
import {ZodGenericData, ZodGenericDataWrite } from "./generic-data";
export const ZodGenericDataSoftDelete = ZodGenericData.extend({
/**
@ -24,29 +24,18 @@ export function isGenericDataSoftDelete(data: any): data is GenericDataSoftDelet
return false;
}
}
export const ZodGenericDataSoftDeleteUpdate = ZodGenericDataUpdate;
export const ZodGenericDataSoftDeleteWrite = ZodGenericDataWrite.extend({
export type GenericDataSoftDeleteUpdate = zod.infer<typeof ZodGenericDataSoftDeleteUpdate>;
});
export function isGenericDataSoftDeleteUpdate(data: any): data is GenericDataSoftDeleteUpdate {
export type GenericDataSoftDeleteWrite = zod.infer<typeof ZodGenericDataSoftDeleteWrite>;
export function isGenericDataSoftDeleteWrite(data: any): data is GenericDataSoftDeleteWrite {
try {
ZodGenericDataSoftDeleteUpdate.parse(data);
ZodGenericDataSoftDeleteWrite.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodGenericDataSoftDeleteUpdate' error=${e}`);
return false;
}
}
export const ZodGenericDataSoftDeleteCreate = ZodGenericDataCreate;
export type GenericDataSoftDeleteCreate = zod.infer<typeof ZodGenericDataSoftDeleteCreate>;
export function isGenericDataSoftDeleteCreate(data: any): data is GenericDataSoftDeleteCreate {
try {
ZodGenericDataSoftDeleteCreate.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodGenericDataSoftDeleteCreate' error=${e}`);
console.log(`Fail to parse data type='ZodGenericDataSoftDeleteWrite' error=${e}`);
return false;
}
}

View File

@ -3,8 +3,8 @@
*/
import { z as zod } from "zod";
import {ZodGenericTiming, ZodGenericTimingUpdate , ZodGenericTimingCreate } from "./generic-timing";
import {ZodLong} from "./long";
import {ZodGenericTiming, ZodGenericTimingWrite } from "./generic-timing";
export const ZodGenericData = ZodGenericTiming.extend({
/**
@ -25,29 +25,18 @@ export function isGenericData(data: any): data is GenericData {
return false;
}
}
export const ZodGenericDataUpdate = ZodGenericTimingUpdate;
export const ZodGenericDataWrite = ZodGenericTimingWrite.extend({
export type GenericDataUpdate = zod.infer<typeof ZodGenericDataUpdate>;
});
export function isGenericDataUpdate(data: any): data is GenericDataUpdate {
export type GenericDataWrite = zod.infer<typeof ZodGenericDataWrite>;
export function isGenericDataWrite(data: any): data is GenericDataWrite {
try {
ZodGenericDataUpdate.parse(data);
ZodGenericDataWrite.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodGenericDataUpdate' error=${e}`);
return false;
}
}
export const ZodGenericDataCreate = ZodGenericTimingCreate;
export type GenericDataCreate = zod.infer<typeof ZodGenericDataCreate>;
export function isGenericDataCreate(data: any): data is GenericDataCreate {
try {
ZodGenericDataCreate.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodGenericDataCreate' error=${e}`);
console.log(`Fail to parse data type='ZodGenericDataWrite' error=${e}`);
return false;
}
}

View File

@ -28,33 +28,18 @@ export function isGenericTiming(data: any): data is GenericTiming {
return false;
}
}
export const ZodGenericTimingUpdate = zod.object({
export const ZodGenericTimingWrite = zod.object({
});
export type GenericTimingUpdate = zod.infer<typeof ZodGenericTimingUpdate>;
export type GenericTimingWrite = zod.infer<typeof ZodGenericTimingWrite>;
export function isGenericTimingUpdate(data: any): data is GenericTimingUpdate {
export function isGenericTimingWrite(data: any): data is GenericTimingWrite {
try {
ZodGenericTimingUpdate.parse(data);
ZodGenericTimingWrite.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodGenericTimingUpdate' error=${e}`);
return false;
}
}
export const ZodGenericTimingCreate = zod.object({
});
export type GenericTimingCreate = zod.infer<typeof ZodGenericTimingCreate>;
export function isGenericTimingCreate(data: any): data is GenericTimingCreate {
try {
ZodGenericTimingCreate.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodGenericTimingCreate' error=${e}`);
console.log(`Fail to parse data type='ZodGenericTimingWrite' error=${e}`);
return false;
}
}

View File

@ -19,3 +19,18 @@ export function isHealthResult(data: any): data is HealthResult {
return false;
}
}
export const ZodHealthResultWrite = zod.object({
});
export type HealthResultWrite = zod.infer<typeof ZodHealthResultWrite>;
export function isHealthResultWrite(data: any): data is HealthResultWrite {
try {
ZodHealthResultWrite.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodHealthResultWrite' error=${e}`);
return false;
}
}

View File

@ -10,20 +10,15 @@ export * from "./generic-timing"
export * from "./health-result"
export * from "./integer"
export * from "./iso-date"
export * from "./jwt-header"
export * from "./jwt-payload"
export * from "./jwt-token"
export * from "./local-date"
export * from "./long"
export * from "./object-id"
export * from "./oid-generic-data"
export * from "./oid-generic-data-soft-delete"
export * from "./part-right"
export * from "./part-right"
export * from "./playlist"
export * from "./rest-error-response"
export * from "./rest-input-error"
export * from "./timestamp"
export * from "./track"
export * from "./user"
export * from "./user-karusic"
export * from "./user-me"
export * from "./uuid"

View File

@ -1,23 +0,0 @@
/**
* Interface of the server (auto-generated code)
*/
import { z as zod } from "zod";
export const ZodJwtHeader = zod.object({
typ: zod.string().max(128),
alg: zod.string().max(128),
});
export type JwtHeader = zod.infer<typeof ZodJwtHeader>;
export function isJwtHeader(data: any): data is JwtHeader {
try {
ZodJwtHeader.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodJwtHeader' error=${e}`);
return false;
}
}

View File

@ -1,29 +0,0 @@
/**
* Interface of the server (auto-generated code)
*/
import { z as zod } from "zod";
import {ZodLong} from "./long";
export const ZodJwtPayload = zod.object({
sub: zod.string(),
application: zod.string(),
iss: zod.string(),
right: zod.record(zod.string(), zod.record(zod.string(), ZodLong)),
login: zod.string(),
exp: ZodLong,
iat: ZodLong,
});
export type JwtPayload = zod.infer<typeof ZodJwtPayload>;
export function isJwtPayload(data: any): data is JwtPayload {
try {
ZodJwtPayload.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodJwtPayload' error=${e}`);
return false;
}
}

View File

@ -1,26 +0,0 @@
/**
* Interface of the server (auto-generated code)
*/
import { z as zod } from "zod";
import {ZodJwtHeader} from "./jwt-header";
import {ZodJwtPayload} from "./jwt-payload";
export const ZodJwtToken = zod.object({
header: ZodJwtHeader,
payload: ZodJwtPayload,
signature: zod.string(),
});
export type JwtToken = zod.infer<typeof ZodJwtToken>;
export function isJwtToken(data: any): data is JwtToken {
try {
ZodJwtToken.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodJwtToken' error=${e}`);
return false;
}
}

View File

@ -1,52 +0,0 @@
/**
* Interface of the server (auto-generated code)
*/
import { z as zod } from "zod";
import {ZodOIDGenericData, ZodOIDGenericDataUpdate , ZodOIDGenericDataCreate } from "./oid-generic-data";
export const ZodOIDGenericDataSoftDelete = ZodOIDGenericData.extend({
/**
* Deleted state
*/
deleted: zod.boolean().readonly().optional(),
});
export type OIDGenericDataSoftDelete = zod.infer<typeof ZodOIDGenericDataSoftDelete>;
export function isOIDGenericDataSoftDelete(data: any): data is OIDGenericDataSoftDelete {
try {
ZodOIDGenericDataSoftDelete.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodOIDGenericDataSoftDelete' error=${e}`);
return false;
}
}
export const ZodOIDGenericDataSoftDeleteUpdate = ZodOIDGenericDataUpdate;
export type OIDGenericDataSoftDeleteUpdate = zod.infer<typeof ZodOIDGenericDataSoftDeleteUpdate>;
export function isOIDGenericDataSoftDeleteUpdate(data: any): data is OIDGenericDataSoftDeleteUpdate {
try {
ZodOIDGenericDataSoftDeleteUpdate.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodOIDGenericDataSoftDeleteUpdate' error=${e}`);
return false;
}
}
export const ZodOIDGenericDataSoftDeleteCreate = ZodOIDGenericDataCreate;
export type OIDGenericDataSoftDeleteCreate = zod.infer<typeof ZodOIDGenericDataSoftDeleteCreate>;
export function isOIDGenericDataSoftDeleteCreate(data: any): data is OIDGenericDataSoftDeleteCreate {
try {
ZodOIDGenericDataSoftDeleteCreate.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodOIDGenericDataSoftDeleteCreate' error=${e}`);
return false;
}
}

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