[FEAT] change namespace and update to the last archidata

This commit is contained in:
Edouard DUPIN 2025-04-14 22:21:29 +02:00
parent 15dfdd8605
commit 50f0c903f4
75 changed files with 1849 additions and 2458 deletions

View File

@ -110,4 +110,4 @@ EXPOSE 80
HEALTHCHECK --start-period=10s --start-interval=2s --interval=30s --timeout=5s --retries=10 \ 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 wget --no-verbose --tries=1 --spider http://localhost:80/api/health_check || exit 1
CMD ["java", "-Xms64M", "-Xmx1G", "-cp", "/application/application.jar", "org.kar.karusic.WebLauncher"] CMD ["java", "-Xms64M", "-Xmx1G", "-cp", "/application/application.jar", "org.atriasoft.karusic.WebLauncher"]

View File

@ -82,7 +82,7 @@ Changing the Log Level
In a production environment, you can adjust the log level to help diagnose bugs more effectively. In a production environment, you can adjust the log level to help diagnose bugs more effectively.
The available log levels are: The available log levels are:
| **Log Level Tag** | **org.kar.karusic** | **org.kar.archidata** | **other** | | **Log Level Tag** | **org.atriasoft.karusic** | **org.kar.archidata** | **other** |
| ----------------- | ------------------- | --------------------- | --------- | | ----------------- | ------------------- | --------------------- | --------- |
| `prod` | INFO | INFO | INFO | | `prod` | INFO | INFO | INFO |
| `prod-debug` | DEBUG | INFO | INFO | | `prod-debug` | DEBUG | INFO | INFO |

View File

@ -18,5 +18,5 @@ WORKDIR /application/
EXPOSE 18080 EXPOSE 18080
CMD ["java", "-Xms64M", "-Xmx1G", "-cp", "/application/application.jar", "org.kar.karusic.WebLauncher"] CMD ["java", "-Xms64M", "-Xmx1G", "-cp", "/application/application.jar", "org.atriasoft.karusic.WebLauncher"]

View File

@ -11,7 +11,7 @@ mvn package
// download all dependency in out/maven/dependency // download all dependency in out/maven/dependency
mvn dependency:copy-dependencies mvn dependency:copy-dependencies
java -cp out/maven/kar-karusic-0.1.0.jar org.kar.karusic.WebLauncher java -cp out/maven/kar-karusic-0.1.0.jar org.atriasoft.karusic.WebLauncher
// create a single package jar // 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.kar.karusic.WebLauncher java -cp out/maven/karusic-0.1.0-jar-with-dependencies.jar org.atriasoft.karusic.WebLauncher

View File

@ -1,20 +1,14 @@
<?xml version="1.0"?> <?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"> <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> <modelVersion>4.0.0</modelVersion>
<groupId>org.kar</groupId> <groupId>org.atriasoft</groupId>
<artifactId>karusic</artifactId> <artifactId>karusic</artifactId>
<version>1.1.1-SNAPSHOT</version> <version>1.1.1-SNAPSHOT</version>
<repositories>
<repository>
<id>gitea</id>
<url>https://gitea.atria-soft.org/api/packages/kangaroo-and-rabbit/maven</url>
</repository>
</repositories>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>kangaroo-and-rabbit</groupId> <groupId>org.atria-soft</groupId>
<artifactId>archidata</artifactId> <artifactId>archidata</artifactId>
<version>0.25.6</version> <version>0.28.0</version>
</dependency> </dependency>
<!-- Loopback of logger JDK logging API to SLF4J --> <!-- Loopback of logger JDK logging API to SLF4J -->
<dependency> <dependency>
@ -106,7 +100,7 @@
<goal>java</goal> <goal>java</goal>
</goals> </goals>
<configuration> <configuration>
<mainClass>org.kar.karusic.WebLauncher</mainClass> <mainClass>org.atriasoft.karusic.WebLauncher</mainClass>
</configuration> </configuration>
</execution> </execution>
<execution> <execution>
@ -115,7 +109,7 @@
<goal>java</goal> <goal>java</goal>
</goals> </goals>
<configuration> <configuration>
<mainClass>org.kar.karusic.WebLauncherLocal</mainClass> <mainClass>org.atriasoft.karusic.WebLauncherLocal</mainClass>
</configuration> </configuration>
</execution> </execution>
<execution> <execution>
@ -124,7 +118,7 @@
<goal>java</goal> <goal>java</goal>
</goals> </goals>
<configuration> <configuration>
<mainClass>org.kar.karusic.GenerateApi</mainClass> <mainClass>org.atriasoft.karusic.GenerateApi</mainClass>
</configuration> </configuration>
</execution> </execution>
</executions> </executions>

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
package org.kar.karusic; package org.atriasoft.karusic;
import java.net.URI; import java.net.URI;
import java.util.Iterator; import java.util.Iterator;
@ -8,38 +8,39 @@ import javax.imageio.ImageIO;
import javax.imageio.ImageReader; import javax.imageio.ImageReader;
import javax.imageio.ImageWriter; 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.Migration20231126;
import org.atriasoft.karusic.migration.Migration20240225;
import org.atriasoft.karusic.migration.Migration20240226;
import org.atriasoft.karusic.migration.Migration20240907;
import org.atriasoft.karusic.migration.Migration20250104;
import org.atriasoft.karusic.migration.Migration20250414;
import org.glassfish.grizzly.http.server.HttpServer; import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory; import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.jackson.JacksonFeature; import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.media.multipart.MultiPartFeature; import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.validation.ValidationFeature; 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.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.slf4j.bridge.SLF4JBridgeHandler; import org.slf4j.bridge.SLF4JBridgeHandler;
@ -70,6 +71,7 @@ public class WebLauncher {
migrationEngine.add(new Migration20240226()); migrationEngine.add(new Migration20240226());
migrationEngine.add(new Migration20240907()); migrationEngine.add(new Migration20240907());
migrationEngine.add(new Migration20250104()); migrationEngine.add(new Migration20250104());
migrationEngine.add(new Migration20250414());
WebLauncher.LOGGER.info("Migrate the DB [START]"); WebLauncher.LOGGER.info("Migrate the DB [START]");
migrationEngine.migrateWaitAdmin(new DbConfig()); migrationEngine.migrateWaitAdmin(new DbConfig());
WebLauncher.LOGGER.info("Migrate the DB [STOP]"); WebLauncher.LOGGER.info("Migrate the DB [STOP]");

View File

@ -1,10 +1,10 @@
package org.kar.karusic; package org.atriasoft.karusic;
import java.util.logging.LogManager; import java.util.logging.LogManager;
import org.kar.archidata.exception.DataAccessException; import org.atriasoft.archidata.exception.DataAccessException;
import org.kar.archidata.tools.ConfigBaseVariable; import org.atriasoft.archidata.tools.ConfigBaseVariable;
import org.kar.karusic.migration.Initialization; import org.atriasoft.karusic.migration.Initialization;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.slf4j.bridge.SLF4JBridgeHandler; import org.slf4j.bridge.SLF4JBridgeHandler;

View File

@ -1,31 +1,29 @@
package org.kar.karusic.api; package org.atriasoft.karusic.api;
import java.io.InputStream; import java.io.InputStream;
import java.util.List; 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.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam; import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.annotation.apiGenerator.ApiAsyncType;
import org.kar.archidata.annotation.apiGenerator.ApiInputOptional;
import org.kar.archidata.annotation.apiGenerator.ApiTypeScriptProgress;
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.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import jakarta.annotation.security.RolesAllowed; import jakarta.annotation.security.RolesAllowed;
import jakarta.validation.Valid;
import jakarta.ws.rs.Consumes; import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE; import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET; import jakarta.ws.rs.GET;
import jakarta.ws.rs.PATCH;
import jakarta.ws.rs.POST; import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path; import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam; import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces; import jakarta.ws.rs.Produces;
@ -35,7 +33,6 @@ import jakarta.ws.rs.core.MediaType;
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
public class AlbumResource { public class AlbumResource {
private static final Logger LOGGER = LoggerFactory.getLogger(AlbumResource.class); private static final Logger LOGGER = LoggerFactory.getLogger(AlbumResource.class);
static final AlbumChecker CHECKER = new AlbumChecker();
@GET @GET
@Path("{id}") @Path("{id}")
@ -59,29 +56,29 @@ public class AlbumResource {
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
@Operation(description = "Add an album (when all the data already exist)") @Operation(description = "Add an album (when all the data already exist)")
public Album post(final Album data) throws Exception { public Album post(@Valid final Album data) throws Exception {
// TODO: how to manage the checker ??? // TODO: how to manage the checker ???
// final Album ret = this.morphiaService.getDatastore().save(data); // final Album ret = this.morphiaService.getDatastore().save(data);
// return ret; // return ret;
/* final MongoCollection<Track> trackCollection = db.getCollection("TTRACLK", Track.class); final InsertOneResult res = trackCollection.insertOne(plop); LOGGER.warn("plpop {}", res); final /* 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 = * 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); */ * trackCollection.find(Filters.eq("_id", res.getInsertedId().asObjectId().getValue())) .first(); System.out.println("Grade found:\t" + ret); */
return DataAccess.insert(data, new CheckFunction(CHECKER)); return DataAccess.insert(data);
} }
@PATCH @PUT
@Path("{id}") @Path("{id}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
@Operation(description = "Update a specific album") @Operation(description = "Update a specific album")
public Album patch(@PathParam("id") final Long id, @ApiAsyncType(Album.class) final String jsonRequest) throws Exception { public Album put(@PathParam("id") final Long id, @Valid final Album album) throws Exception {
// final Query<Album> query = this.morphiaService.getDatastore().find(Album.class).filter(Filters.eq("id", id)); // final Query<Album> query = this.morphiaService.getDatastore().find(Album.class).filter(Filters.eq("id", id));
// final UpdateOperations<Album> ops = this.morphiaService.getDatastore().createUpdateOperations(Album.class) // final UpdateOperations<Album> ops = this.morphiaService.getDatastore().createUpdateOperations(Album.class)
// .set("name", master.getName()); // .set("name", master.getName());
// this.morphiaService.getDatastore().update(query, ops); // this.morphiaService.getDatastore().update(query, ops);
// return Response.ok(master).build(); // return Response.ok(master).build();
album.id = id;
DataAccess.updateWithJson(Album.class, id, jsonRequest, new CheckFunction(CHECKER)); DataAccess.update(album, id);
return DataAccess.get(Album.class, id); return DataAccess.get(Album.class, id);
} }
@ -136,7 +133,7 @@ public class AlbumResource {
@Path("{id}/cover/{coverId}") @Path("{id}/cover/{coverId}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Operation(description = "Remove a cover on a specific album") @Operation(description = "Remove a cover on a specific album")
public Album removeCover(@PathParam("id") final Long id, @PathParam("coverId") final UUID coverId) throws Exception { public Album removeCover(@PathParam("id") final Long id, @PathParam("coverId") final ObjectId coverId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) { try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Album.class, "id", id, "covers", coverId); AddOnDataJson.removeLink(db, Album.class, "id", id, "covers", coverId);
return db.get(Album.class, id); return db.get(Album.class, id);

View File

@ -1,20 +1,18 @@
package org.kar.karusic.api; package org.atriasoft.karusic.api;
import java.io.InputStream; import java.io.InputStream;
import java.util.List; 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.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam; import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.annotation.apiGenerator.ApiInputOptional;
import org.kar.archidata.annotation.apiGenerator.ApiTypeScriptProgress;
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.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -34,7 +32,6 @@ import jakarta.ws.rs.core.MediaType;
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
public class ArtistResource { public class ArtistResource {
private static final Logger LOGGER = LoggerFactory.getLogger(ArtistResource.class); private static final Logger LOGGER = LoggerFactory.getLogger(ArtistResource.class);
static final ArtistChecker CHECKER = new ArtistChecker();
@GET @GET
@Path("{id}") @Path("{id}")
@ -52,17 +49,17 @@ public class ArtistResource {
@POST @POST
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Artist post(final Artist data) throws Exception { public Artist post(@Valid final Artist data) throws Exception {
return DataAccess.insert(data, new CheckFunction(CHECKER)); return DataAccess.insert(data);
} }
@PUT @PUT
@Path("{id}") @Path("{id}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Artist patch(@PathParam("id") final Long id, @Valid final Artist jsonRequest) throws Exception { public Artist put(@PathParam("id") final Long id, @Valid final Artist artist) throws Exception {
// new CheckFunction(CHECKER) artist.id = id;
DataAccess.update(id, jsonRequest); DataAccess.update(artist, id);
return DataAccess.get(Artist.class, id); return DataAccess.get(Artist.class, id);
} }

View File

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

View File

@ -1,30 +1,28 @@
package org.kar.karusic.api; package org.atriasoft.karusic.api;
import java.io.InputStream; import java.io.InputStream;
import java.util.List; 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.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam; import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.annotation.apiGenerator.ApiAsyncType;
import org.kar.archidata.annotation.apiGenerator.ApiInputOptional;
import org.kar.archidata.annotation.apiGenerator.ApiTypeScriptProgress;
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.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import jakarta.annotation.security.RolesAllowed; import jakarta.annotation.security.RolesAllowed;
import jakarta.validation.Valid;
import jakarta.ws.rs.Consumes; import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE; import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET; import jakarta.ws.rs.GET;
import jakarta.ws.rs.PATCH;
import jakarta.ws.rs.POST; import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path; import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam; import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces; import jakarta.ws.rs.Produces;
@ -34,7 +32,6 @@ import jakarta.ws.rs.core.MediaType;
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
public class GenderResource { public class GenderResource {
private static final Logger LOGGER = LoggerFactory.getLogger(GenderResource.class); private static final Logger LOGGER = LoggerFactory.getLogger(GenderResource.class);
static final GenderChecker CHECKER = new GenderChecker();
@GET @GET
@Path("{id}") @Path("{id}")
@ -52,16 +49,17 @@ public class GenderResource {
@POST @POST
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Gender post(final Gender data) throws Exception { public Gender post(@Valid final Gender data) throws Exception {
return DataAccess.insert(data, new CheckFunction(CHECKER)); return DataAccess.insert(data);
} }
@PATCH @PUT
@Path("{id}") @Path("{id}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Gender patch(@PathParam("id") final Long id, @ApiAsyncType(Gender.class) final String jsonRequest) throws Exception { public Gender patch(@PathParam("id") final Long id, @Valid final Gender gender) throws Exception {
DataAccess.updateWithJson(Gender.class, id, jsonRequest, new CheckFunction(CHECKER)); gender.id = id;
DataAccess.update(gender, id);
return DataAccess.get(Gender.class, id); return DataAccess.get(Gender.class, id);
} }

View File

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

View File

@ -1,28 +1,27 @@
package org.kar.karusic.api; package org.atriasoft.karusic.api;
import java.io.InputStream; import java.io.InputStream;
import java.util.List; 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.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam; import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.annotation.apiGenerator.ApiAsyncType;
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.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import jakarta.annotation.security.RolesAllowed; import jakarta.annotation.security.RolesAllowed;
import jakarta.validation.Valid;
import jakarta.ws.rs.Consumes; import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE; import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET; import jakarta.ws.rs.GET;
import jakarta.ws.rs.PATCH;
import jakarta.ws.rs.POST; import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path; import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam; import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces; import jakarta.ws.rs.Produces;
@ -32,7 +31,6 @@ import jakarta.ws.rs.core.MediaType;
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
public class PlaylistResource { public class PlaylistResource {
private static final Logger LOGGER = LoggerFactory.getLogger(PlaylistResource.class); private static final Logger LOGGER = LoggerFactory.getLogger(PlaylistResource.class);
static final TrackChecker CHECKER = new TrackChecker();
@GET @GET
@Path("{id}") @Path("{id}")
@ -50,16 +48,17 @@ public class PlaylistResource {
@POST @POST
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Playlist post(final Playlist data) throws Exception { public Playlist post(@Valid final Playlist data) throws Exception {
return DataAccess.insert(data, new CheckFunction(CHECKER)); return DataAccess.insert(data);
} }
@PATCH @PUT
@Path("{id}") @Path("{id}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Playlist patch(@PathParam("id") final Long id, @ApiAsyncType(Playlist.class) final String jsonRequest) throws Exception { public Playlist put(@PathParam("id") final Long id, @Valid final Playlist playlist) throws Exception {
DataAccess.updateWithJson(Playlist.class, id, jsonRequest, new CheckFunction(CHECKER)); playlist.id = id;
DataAccess.update(playlist, id);
return DataAccess.get(Playlist.class, id); return DataAccess.get(Playlist.class, id);
} }
@ -70,27 +69,6 @@ public class PlaylistResource {
DataAccess.delete(Playlist.class, id); 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 @POST
@Path("{id}/cover") @Path("{id}/cover")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")

View File

@ -1,4 +1,4 @@
package org.kar.karusic.api; package org.atriasoft.karusic.api;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -6,29 +6,28 @@ import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; 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.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam; import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.annotation.apiGenerator.ApiAsyncType;
import org.kar.archidata.annotation.apiGenerator.ApiInputOptional;
import org.kar.archidata.annotation.apiGenerator.ApiTypeScriptProgress;
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.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import jakarta.annotation.security.RolesAllowed; import jakarta.annotation.security.RolesAllowed;
import jakarta.validation.Valid;
import jakarta.ws.rs.Consumes; import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE; import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET; import jakarta.ws.rs.GET;
import jakarta.ws.rs.PATCH;
import jakarta.ws.rs.POST; import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path; import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam; import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces; import jakarta.ws.rs.Produces;
@ -39,7 +38,6 @@ import jakarta.ws.rs.core.Response;
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
public class TrackResource { public class TrackResource {
private static final Logger LOGGER = LoggerFactory.getLogger(TrackResource.class); private static final Logger LOGGER = LoggerFactory.getLogger(TrackResource.class);
static final TrackChecker CHECKER = new TrackChecker();
@GET @GET
@Path("{id}") @Path("{id}")
@ -57,16 +55,17 @@ public class TrackResource {
@POST @POST
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Track post(final Track data) throws Exception { public Track post(@Valid final Track data) throws Exception {
return DataAccess.insert(data, new CheckFunction(CHECKER)); return DataAccess.insert(data);
} }
@PATCH @PUT
@Path("{id}") @Path("{id}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Track patch(@PathParam("id") final Long id, @ApiAsyncType(Track.class) final String jsonRequest) throws Exception { public Track put(@PathParam("id") final Long id, @Valid final Track track) throws Exception {
DataAccess.updateWithJson(Track.class, id, jsonRequest, new CheckFunction(CHECKER)); track.id = id;
DataAccess.update(track, id);
return DataAccess.get(Track.class, id); return DataAccess.get(Track.class, id);
} }
@ -77,27 +76,6 @@ public class TrackResource {
DataAccess.delete(Track.class, id); DataAccess.delete(Track.class, id);
} }
@POST
@Path("{id}/artist/{artistId}")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
public Track addTrack(@PathParam("id") final Long id, @PathParam("artistId") final Long artistId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Track.class, "id", id, "artist", artistId);
return DataAccess.get(Track.class, id);
}
}
@DELETE
@Path("{id}/artist/{trackId}")
@RolesAllowed("ADMIN")
public Track removeTrack(@PathParam("id") final Long id, @PathParam("artistId") final Long artistId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Track.class, "id", id, "artist", artistId);
return DataAccess.get(Track.class, id);
}
}
@POST @POST
@Path("{id}/cover") @Path("{id}/cover")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@ -196,7 +174,9 @@ public class TrackResource {
trackElem.artists = new ArrayList<>(); trackElem.artists = new ArrayList<>();
trackElem.artists.add(artistId != null ? Long.parseLong(artistId) : null); trackElem.artists.add(artistId != null ? Long.parseLong(artistId) : null);
} }
trackElem = DataAccess.insert(trackElem, new CheckFunction(CHECKER)); // TODO: maybe validate here ....
trackElem = DataAccess.insert(trackElem);
/* 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); } */ /* 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(); return Response.ok(trackElem).build();
} catch (final Exception ex) { } catch (final Exception ex) {

View File

@ -1,13 +1,13 @@
package org.kar.karusic.api; package org.atriasoft.karusic.api;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.kar.archidata.dataAccess.DataAccess; import org.atriasoft.archidata.dataAccess.DataAccess;
import org.kar.archidata.filter.GenericContext; import org.atriasoft.archidata.filter.GenericContext;
import org.kar.karusic.api.UserResourceModel.PartRight; import org.atriasoft.karusic.api.UserResourceModel.PartRight;
import org.kar.karusic.api.UserResourceModel.UserMe; import org.atriasoft.karusic.api.UserResourceModel.UserMe;
import org.kar.karusic.model.UserKarusic; import org.atriasoft.karusic.model.UserKarusic;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@ -1,4 +1,4 @@
package org.kar.karusic.api.UserResourceModel; package org.atriasoft.karusic.api.UserResourceModel;
import java.util.HashMap; import java.util.HashMap;

View File

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

View File

@ -1,4 +1,4 @@
package org.kar.karusic.api.UserResourceModel; package org.atriasoft.karusic.api.UserResourceModel;
import java.util.Map; import java.util.Map;

View File

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

View File

@ -1,29 +1,30 @@
package org.kar.karusic.migration; package org.atriasoft.karusic.migration;
import java.util.List; import java.util.List;
import org.kar.archidata.api.DataResource; import org.atriasoft.archidata.api.DataResource;
import org.kar.archidata.api.ProxyResource; import org.atriasoft.archidata.api.ProxyResource;
import org.kar.archidata.dataAccess.DBAccess; import org.atriasoft.archidata.dataAccess.DBAccess;
import org.kar.archidata.externalRestApi.AnalyzeApi; import org.atriasoft.archidata.externalRestApi.AnalyzeApi;
import org.kar.archidata.externalRestApi.TsGenerateApi; import org.atriasoft.archidata.externalRestApi.TsGenerateApi;
import org.kar.archidata.migration.MigrationSqlStep; import org.atriasoft.archidata.filter.PartRight;
import org.kar.archidata.model.Data; import org.atriasoft.archidata.migration.MigrationSqlStep;
import org.kar.archidata.model.User; import org.atriasoft.archidata.model.Data;
import org.kar.archidata.model.token.JwtToken; import org.atriasoft.archidata.model.User;
import org.kar.karusic.api.AlbumResource; import org.atriasoft.archidata.model.token.JwtToken;
import org.kar.karusic.api.ArtistResource; import org.atriasoft.karusic.api.AlbumResource;
import org.kar.karusic.api.Front; import org.atriasoft.karusic.api.ArtistResource;
import org.kar.karusic.api.GenderResource; import org.atriasoft.karusic.api.Front;
import org.kar.karusic.api.HealthCheck; import org.atriasoft.karusic.api.GenderResource;
import org.kar.karusic.api.PlaylistResource; import org.atriasoft.karusic.api.HealthCheck;
import org.kar.karusic.api.TrackResource; import org.atriasoft.karusic.api.PlaylistResource;
import org.kar.karusic.api.UserResource; import org.atriasoft.karusic.api.TrackResource;
import org.kar.karusic.model.Album; import org.atriasoft.karusic.api.UserResource;
import org.kar.karusic.model.Artist; import org.atriasoft.karusic.model.Album;
import org.kar.karusic.model.Gender; import org.atriasoft.karusic.model.Artist;
import org.kar.karusic.model.Playlist; import org.atriasoft.karusic.model.Gender;
import org.kar.karusic.model.Track; import org.atriasoft.karusic.model.Playlist;
import org.atriasoft.karusic.model.Track;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -45,6 +46,7 @@ public class Initialization extends MigrationSqlStep {
final AnalyzeApi api = new AnalyzeApi(); final AnalyzeApi api = new AnalyzeApi();
api.addAllApi(listOfResources); api.addAllApi(listOfResources);
api.addModel(JwtToken.class); api.addModel(JwtToken.class);
api.addModel(PartRight.class);
TsGenerateApi.generateApi(api, "../front/src/back-api/"); TsGenerateApi.generateApi(api, "../front/src/back-api/");
LOGGER.info("Generate APIs (DONE)"); LOGGER.info("Generate APIs (DONE)");
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,30 @@
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,10 +1,10 @@
package org.kar.karusic.migration.model; package org.atriasoft.karusic.migration.model;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import org.bson.types.ObjectId; import org.bson.types.ObjectId;
import org.kar.archidata.annotation.DataJson; import org.atriasoft.archidata.annotation.DataJson;
import jakarta.persistence.Id; import jakarta.persistence.Id;

View File

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

View File

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

View File

@ -0,0 +1,48 @@
package org.atriasoft.karusic.model;
import java.util.Date;
import java.util.List;
import org.atriasoft.archidata.annotation.DataIfNotExists;
import org.atriasoft.archidata.annotation.DataJson;
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.GenericDataSoftDelete;
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.persistence.Table;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
@Entity("Album")
@Table(name = "album")
@DataIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
@ApiGenerationMode(create = true, update = true)
public class Album extends GenericDataSoftDelete {
@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")
@DataJson()
@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,15 +1,18 @@
package org.kar.karusic.model; package org.atriasoft.karusic.model;
import java.time.LocalDate; import java.util.Date;
import java.util.List; import java.util.List;
import org.atriasoft.archidata.annotation.DataIfNotExists;
import org.atriasoft.archidata.annotation.DataJson;
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.GenericDataSoftDelete;
import org.bson.types.ObjectId; import org.bson.types.ObjectId;
import org.kar.archidata.annotation.DataIfNotExists; import org.hibernate.validator.constraints.UniqueElements;
import org.kar.archidata.annotation.DataJson;
import org.kar.archidata.annotation.apiGenerator.ApiGenerationMode;
import org.kar.archidata.checker.CheckJPA;
import org.kar.archidata.model.Data;
import org.kar.archidata.model.GenericDataSoftDelete;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
@ -18,6 +21,8 @@ import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable; import jakarta.annotation.Nullable;
import jakarta.persistence.Column; import jakarta.persistence.Column;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
@Entity("Artist") @Entity("Artist")
@Table(name = "artist") @Table(name = "artist")
@ -25,26 +30,27 @@ import jakarta.persistence.Table;
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
@ApiGenerationMode(create = true, update = true) @ApiGenerationMode(create = true, update = true)
public class Artist extends GenericDataSoftDelete { public class Artist extends GenericDataSoftDelete {
public static class ArtistChecker extends CheckJPA<Artist> {
public ArtistChecker() {
super(Artist.class);
}
}
@Column(length = 256) @Column(length = 256)
@Size(min = 1, max = 256)
public String name = null; public String name = null;
@Column(length = 0) @Column(length = 0)
@Size(min = 0, max = 8192)
public String description = null; public String description = null;
@Schema(description = "List of Id of the specific covers") @Schema(description = "List of Id of the specific covers")
@DataJson(targetEntity = Data.class) @DataJson()
@Nullable @Nullable
public List<ObjectId> covers = null; @CollectionNotEmpty
@UniqueElements
@ApiAccessLimitation(readable = true, creatable = false, updatable = false)
public List<@CheckForeignKey(target = Data.class) @NotNull ObjectId> covers = null;
@Column(length = 256) @Column(length = 256)
@Size(min = 1, max = 256)
public String firstName = null; public String firstName = null;
@Column(length = 256) @Column(length = 256)
@Size(min = 1, max = 256)
public String surname = null; public String surname = null;
public LocalDate birth = null; public Date birth = null;
public LocalDate death = null; public Date death = null;
@Override @Override
public String toString() { public String toString() {

View File

@ -1,4 +1,4 @@
package org.kar.karusic.model; package org.atriasoft.karusic.model;
/* /*
CREATE TABLE `node` ( CREATE TABLE `node` (
`id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY, `id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY,
@ -14,13 +14,16 @@ CREATE TABLE `node` (
import java.util.List; import java.util.List;
import org.atriasoft.archidata.annotation.DataIfNotExists;
import org.atriasoft.archidata.annotation.DataJson;
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.GenericDataSoftDelete;
import org.bson.types.ObjectId; import org.bson.types.ObjectId;
import org.kar.archidata.annotation.DataIfNotExists; import org.hibernate.validator.constraints.UniqueElements;
import org.kar.archidata.annotation.DataJson;
import org.kar.archidata.annotation.apiGenerator.ApiGenerationMode;
import org.kar.archidata.checker.CheckJPA;
import org.kar.archidata.model.Data;
import org.kar.archidata.model.GenericDataSoftDelete;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
@ -29,6 +32,8 @@ import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable; import jakarta.annotation.Nullable;
import jakarta.persistence.Column; import jakarta.persistence.Column;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
@Entity("Gender") @Entity("Gender")
@Table(name = "gender") @Table(name = "gender")
@ -36,20 +41,19 @@ import jakarta.persistence.Table;
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
@ApiGenerationMode(create = true, update = true) @ApiGenerationMode(create = true, update = true)
public class Gender extends GenericDataSoftDelete { public class Gender extends GenericDataSoftDelete {
public static class GenderChecker extends CheckJPA<Gender> {
public GenderChecker() {
super(Gender.class);
}
}
@Column(length = 256) @Column(length = 256)
@Size(min = 1, max = 256)
public String name = null; public String name = null;
@Column(length = 0) @Column(length = 0)
@Size(min = 0, max = 8192)
public String description = null; public String description = null;
@Schema(description = "List of Id of the specific covers") @Schema(description = "List of Id of the specific covers")
@DataJson(targetEntity = Data.class) @DataJson()
@Nullable @Nullable
public List<ObjectId> covers = null; @CollectionNotEmpty
@UniqueElements
@ApiAccessLimitation(readable = true, creatable = false, updatable = false)
public List<@CheckForeignKey(target = Data.class) @NotNull ObjectId> covers = null;
public Gender() {} public Gender() {}

View File

@ -1,4 +1,4 @@
package org.kar.karusic.model; package org.atriasoft.karusic.model;
/* /*
CREATE TABLE `node` ( CREATE TABLE `node` (
`id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY, `id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY,
@ -14,13 +14,16 @@ CREATE TABLE `node` (
import java.util.List; import java.util.List;
import org.atriasoft.archidata.annotation.DataIfNotExists;
import org.atriasoft.archidata.annotation.DataJson;
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.GenericDataSoftDelete;
import org.bson.types.ObjectId; import org.bson.types.ObjectId;
import org.kar.archidata.annotation.DataIfNotExists; import org.hibernate.validator.constraints.UniqueElements;
import org.kar.archidata.annotation.DataJson;
import org.kar.archidata.annotation.apiGenerator.ApiGenerationMode;
import org.kar.archidata.checker.CheckJPA;
import org.kar.archidata.model.Data;
import org.kar.archidata.model.GenericDataSoftDelete;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
@ -28,9 +31,9 @@ import dev.morphia.annotations.Entity;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable; import jakarta.annotation.Nullable;
import jakarta.persistence.Column; import jakarta.persistence.Column;
import jakarta.persistence.FetchType;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
@Entity("Playlist") @Entity("Playlist")
@Table(name = "playlist") @Table(name = "playlist")
@ -38,20 +41,19 @@ import jakarta.persistence.Table;
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
@ApiGenerationMode(create = true, update = true) @ApiGenerationMode(create = true, update = true)
public class Playlist extends GenericDataSoftDelete { public class Playlist extends GenericDataSoftDelete {
public static class PlaylistChecker extends CheckJPA<Playlist> {
public PlaylistChecker() {
super(Playlist.class);
}
}
@Column(length = 256) @Column(length = 256)
@Size(min = 1, max = 256)
public String name = null; public String name = null;
@Column(length = 0) @Column(length = 0)
@Size(min = 0, max = 8192)
public String description = null; public String description = null;
@Schema(description = "List of Id of the specific covers") @Schema(description = "List of Id of the specific covers")
@DataJson(targetEntity = Data.class) @DataJson()
@Nullable @Nullable
public List<ObjectId> covers = null; @CollectionNotEmpty
@ManyToMany(fetch = FetchType.LAZY, targetEntity = Track.class) @UniqueElements
public List<ObjectId> tracks = null; @ApiAccessLimitation(readable = true, creatable = false, updatable = false)
public List<@CheckForeignKey(target = Data.class) @NotNull ObjectId> covers = null;
@DataJson()
public List<@CheckForeignKey(target = Track.class) @NotNull Long> tracks = null;
} }

View File

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

View File

@ -1,4 +1,4 @@
package org.kar.karusic.model; package org.atriasoft.karusic.model;
/* /*
CREATE TABLE `node` ( CREATE TABLE `node` (
`id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY, `id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY,
@ -14,13 +14,16 @@ CREATE TABLE `node` (
import java.util.List; import java.util.List;
import org.atriasoft.archidata.annotation.DataIfNotExists;
import org.atriasoft.archidata.annotation.DataJson;
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.GenericDataSoftDelete;
import org.bson.types.ObjectId; import org.bson.types.ObjectId;
import org.kar.archidata.annotation.DataIfNotExists; import org.hibernate.validator.constraints.UniqueElements;
import org.kar.archidata.annotation.DataJson;
import org.kar.archidata.annotation.apiGenerator.ApiGenerationMode;
import org.kar.archidata.checker.CheckJPA;
import org.kar.archidata.model.Data;
import org.kar.archidata.model.GenericDataSoftDelete;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
@ -29,6 +32,9 @@ import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable; import jakarta.annotation.Nullable;
import jakarta.persistence.Column; import jakarta.persistence.Column;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.PositiveOrZero;
import jakarta.validation.constraints.Size;
@Entity("Track") @Entity("Track")
@Table(name = "track") @Table(name = "track")
@ -37,28 +43,31 @@ import jakarta.persistence.Table;
@ApiGenerationMode(create = true, update = true) @ApiGenerationMode(create = true, update = true)
public class Track extends GenericDataSoftDelete { public class Track extends GenericDataSoftDelete {
public static class TrackChecker extends CheckJPA<Track> {
public TrackChecker() {
super(Track.class);
}
}
@Column(length = 256) @Column(length = 256)
@Size(min = 1, max = 256)
public String name = null; public String name = null;
@Column(length = 0) @Column(length = 0)
@Size(min = 0, max = 8192)
public String description = null; public String description = null;
@Schema(description = "List of Id of the specific covers") @Schema(description = "List of Id of the specific covers")
@DataJson(targetEntity = Data.class) @DataJson()
@Nullable @Nullable
public List<ObjectId> covers = null; @CollectionNotEmpty
@UniqueElements
@ApiAccessLimitation(readable = true, creatable = false, updatable = false)
public List<@CheckForeignKey(target = Data.class) @NotNull ObjectId> covers = null;
@CheckForeignKey(target = Gender.class)
public Long genderId = null; public Long genderId = null;
@CheckForeignKey(target = Album.class)
public Long albumId = null; public Long albumId = null;
@PositiveOrZero
public Long track = null; public Long track = null;
@CheckForeignKey(target = Data.class)
public ObjectId dataId = null; public ObjectId dataId = null;
// @ManyToMany(fetch = FetchType.LAZY, targetEntity = Artist.class) // @ManyToMany(fetch = FetchType.LAZY, targetEntity = Artist.class)
@DataJson @DataJson
@Column(length = 0) @Column(length = 0)
public List<Long> artists = null; public List<@CheckForeignKey(target = Artist.class) @NotNull Long> artists = null;
@Override @Override
public String toString() { public String toString() {

View File

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

View File

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

View File

@ -1,43 +0,0 @@
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.annotation.apiGenerator.ApiGenerationMode;
import org.kar.archidata.checker.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)
@ApiGenerationMode(create = true, update = true)
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

@ -10,8 +10,8 @@
<pattern>%green(%d{HH:mm:ss.SSS}) %highlight(%-5level) %-30((%file:%line\)): %msg%n</pattern> <pattern>%green(%d{HH:mm:ss.SSS}) %highlight(%-5level) %-30((%file:%line\)): %msg%n</pattern>
</encoder> </encoder>
</appender> </appender>
<logger name="org.kar.karusic" level="TRACE" /> <logger name="org.atriasoft.karusic" level="TRACE" />
<logger name="org.kar.archidata" level="DEBUG" /> <logger name="org.atriasoft.archidata" level="DEBUG" />
<root level="INFO"> <root level="INFO">
<appender-ref ref="CONSOLE" /> <appender-ref ref="CONSOLE" />
</root> </root>
@ -32,19 +32,19 @@
</if> </if>
<if condition="property(&quot;LOG_LEVEL_ENV&quot;).equals(&quot;prod-debug&quot;)"> <if condition="property(&quot;LOG_LEVEL_ENV&quot;).equals(&quot;prod-debug&quot;)">
<then> <then>
<logger name="org.kar.karusic" level="DEBUG" /> <logger name="org.atriasoft.karusic" level="DEBUG" />
</then> </then>
</if> </if>
<if condition="property(&quot;LOG_LEVEL_ENV&quot;).equals(&quot;prod-trace&quot;)"> <if condition="property(&quot;LOG_LEVEL_ENV&quot;).equals(&quot;prod-trace&quot;)">
<then> <then>
<logger name="org.kar.karusic" level="TRACE" /> <logger name="org.atriasoft.karusic" level="TRACE" />
<logger name="org.kar.archidata" level="DEBUG" /> <logger name="org.atriasoft.archidata" level="DEBUG" />
</then> </then>
</if> </if>
<if condition="property(&quot;LOG_LEVEL_ENV&quot;).equals(&quot;prod-trace-full&quot;)"> <if condition="property(&quot;LOG_LEVEL_ENV&quot;).equals(&quot;prod-trace-full&quot;)">
<then> <then>
<logger name="org.kar.karusic" level="TRACE" /> <logger name="org.atriasoft.karusic" level="TRACE" />
<logger name="org.kar.archidata" level="TRACE" /> <logger name="org.atriasoft.archidata" level="TRACE" />
</then> </then>
</if> </if>
</configuration> </configuration>

View File

@ -1,9 +1,9 @@
package test.kar.karusic; package test.atriasoft.karusic;
import java.util.Map; import java.util.Map;
import org.kar.archidata.filter.PartRight; import org.atriasoft.archidata.filter.PartRight;
import org.kar.archidata.tools.JWTWrapper; import org.atriasoft.archidata.tools.JWTWrapper;
public class Common { 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 USER_TOKEN = JWTWrapper.createJwtTestToken(16512, "test_user_login", "KarAuth", "karusic", Map.of("karusic", Map.of("USER", PartRight.READ)));

View File

@ -1,19 +1,19 @@
package test.kar.karusic; package test.atriasoft.karusic;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import org.kar.archidata.dataAccess.DBAccess; import org.atriasoft.archidata.dataAccess.DBAccess;
import org.kar.archidata.db.DbConfig; import org.atriasoft.archidata.db.DbConfig;
import org.kar.archidata.db.DbIoFactory; import org.atriasoft.archidata.db.DbIoFactory;
import org.kar.archidata.exception.DataAccessException; import org.atriasoft.archidata.exception.DataAccessException;
import org.kar.archidata.tools.ConfigBaseVariable; import org.atriasoft.archidata.tools.ConfigBaseVariable;
import org.kar.karusic.model.Album; import org.atriasoft.karusic.model.Album;
import org.kar.karusic.model.Artist; import org.atriasoft.karusic.model.Artist;
import org.kar.karusic.model.Gender; import org.atriasoft.karusic.model.Gender;
import org.kar.karusic.model.Playlist; import org.atriasoft.karusic.model.Playlist;
import org.kar.karusic.model.Track; import org.atriasoft.karusic.model.Track;
import org.kar.karusic.model.UserKarusic; import org.atriasoft.karusic.model.UserKarusic;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -59,15 +59,15 @@ public class ConfigureDb {
ConfigBaseVariable.dbKeepConnected = "true"; ConfigBaseVariable.dbKeepConnected = "true";
} else if ("MY-SQL".equalsIgnoreCase(modeTest)) { } else if ("MY-SQL".equalsIgnoreCase(modeTest)) {
ConfigBaseVariable.dbType = "mysql"; ConfigBaseVariable.dbType = "mysql";
ConfigBaseVariable.bdDatabase = "test_karusic_db"; ConfigBaseVariable.bdDatabase = "test.atriasoftusic_db";
ConfigBaseVariable.dbPort = "3906"; ConfigBaseVariable.dbPort = "3906";
ConfigBaseVariable.dbUser = "root"; ConfigBaseVariable.dbUser = "root";
} else if ("MONGO".equalsIgnoreCase(modeTest)) { } else if ("MONGO".equalsIgnoreCase(modeTest)) {
ConfigBaseVariable.dbType = "mongo"; ConfigBaseVariable.dbType = "mongo";
ConfigBaseVariable.bdDatabase = "test_karusic_db"; ConfigBaseVariable.bdDatabase = "test.atriasoftusic_db";
} else { } else {
// User local modification ... // User local modification ...
ConfigBaseVariable.bdDatabase = "test_karusic_db"; ConfigBaseVariable.bdDatabase = "test.atriasoftusic_db";
ConfigBaseVariable.dbPort = "3906"; ConfigBaseVariable.dbPort = "3906";
ConfigBaseVariable.dbUser = "root"; ConfigBaseVariable.dbUser = "root";
} }

View File

@ -1,4 +1,4 @@
package test.kar.karusic; package test.atriasoft.karusic;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;

View File

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

View File

@ -1,4 +1,4 @@
package test.kar.karusic; package test.atriasoft.karusic;
import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
@ -8,10 +8,10 @@ import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.kar.archidata.exception.RESTErrorResponseException; import org.atriasoft.archidata.exception.RESTErrorResponseException;
import org.kar.archidata.tools.ConfigBaseVariable; import org.atriasoft.archidata.tools.ConfigBaseVariable;
import org.kar.archidata.tools.RESTApi; import org.atriasoft.archidata.tools.RESTApi;
import org.kar.karusic.api.HealthCheck.HealthResult; import org.atriasoft.karusic.api.HealthCheck.HealthResult;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@ -1,4 +1,4 @@
package test.kar.karusic; package test.atriasoft.karusic;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -15,9 +15,9 @@ import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.kar.archidata.tools.ConfigBaseVariable; import org.atriasoft.archidata.tools.ConfigBaseVariable;
import org.kar.archidata.tools.RESTApi; import org.atriasoft.archidata.tools.RESTApi;
import org.kar.karusic.model.Track; import org.atriasoft.karusic.model.Track;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

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

View File

@ -32,19 +32,19 @@
"react-speech-recognition": "4.0.0", "react-speech-recognition": "4.0.0",
"regenerator-runtime": "0.14.1", "regenerator-runtime": "0.14.1",
"@trivago/prettier-plugin-sort-imports": "5.2.2", "@trivago/prettier-plugin-sort-imports": "5.2.2",
"@chakra-ui/cli": "3.13.0", "@chakra-ui/cli": "3.16.0",
"@chakra-ui/react": "3.13.0", "@chakra-ui/react": "3.16.0",
"@emotion/react": "11.14.0", "@emotion/react": "11.14.0",
"allotment": "1.20.3", "allotment": "1.20.3",
"css-mediaquery": "0.1.2", "css-mediaquery": "0.1.2",
"dayjs": "1.11.13", "dayjs": "1.11.13",
"history": "5.3.0", "history": "5.3.0",
"next-themes": "^0.4.6", "next-themes": "^0.4.6",
"react": "19.0.0", "react": "19.1.0",
"react-dom": "19.0.0", "react-dom": "19.1.0",
"react-error-boundary": "5.0.0", "react-error-boundary": "5.0.0",
"react-icons": "5.5.0", "react-icons": "5.5.0",
"react-router-dom": "7.4.0", "react-router-dom": "7.5.0",
"react-select": "5.10.1", "react-select": "5.10.1",
"react-use": "17.6.0", "react-use": "17.6.0",
"zod": "3.24.2", "zod": "3.24.2",
@ -53,41 +53,41 @@
"devDependencies": { "devDependencies": {
"@chakra-ui/styled-system": "^2.12.0", "@chakra-ui/styled-system": "^2.12.0",
"@playwright/test": "1.51.1", "@playwright/test": "1.51.1",
"@storybook/addon-actions": "8.6.8", "@storybook/addon-actions": "8.6.12",
"@storybook/addon-essentials": "8.6.8", "@storybook/addon-essentials": "8.6.12",
"@storybook/addon-links": "8.6.8", "@storybook/addon-links": "8.6.12",
"@storybook/addon-mdx-gfm": "8.6.8", "@storybook/addon-mdx-gfm": "8.6.12",
"@storybook/react": "8.6.8", "@storybook/react": "8.6.12",
"@storybook/react-vite": "8.6.8", "@storybook/react-vite": "8.6.12",
"@storybook/theming": "8.6.8", "@storybook/theming": "8.6.12",
"@testing-library/jest-dom": "6.6.3", "@testing-library/jest-dom": "6.6.3",
"@testing-library/react": "16.2.0", "@testing-library/react": "16.3.0",
"@testing-library/user-event": "14.6.1", "@testing-library/user-event": "14.6.1",
"@trivago/prettier-plugin-sort-imports": "5.2.2", "@trivago/prettier-plugin-sort-imports": "5.2.2",
"@types/jest": "29.5.14", "@types/jest": "29.5.14",
"@types/node": "22.13.11", "@types/node": "22.14.1",
"@types/react": "19.0.12", "@types/react": "19.1.1",
"@types/react-dom": "19.0.4", "@types/react-dom": "19.1.2",
"@typescript-eslint/eslint-plugin": "8.27.0", "@typescript-eslint/eslint-plugin": "8.30.0",
"@typescript-eslint/parser": "8.27.0", "@typescript-eslint/parser": "8.30.0",
"@vitejs/plugin-react": "4.3.4", "@vitejs/plugin-react": "4.3.4",
"eslint": "9.23.0", "eslint": "9.24.0",
"eslint-plugin-import": "2.31.0", "eslint-plugin-import": "2.31.0",
"eslint-plugin-react": "7.37.4", "eslint-plugin-react": "7.37.5",
"eslint-plugin-react-hooks": "5.2.0", "eslint-plugin-react-hooks": "5.2.0",
"eslint-plugin-storybook": "0.11.6", "eslint-plugin-storybook": "0.12.0",
"jest": "29.7.0", "jest": "29.7.0",
"jest-environment-jsdom": "29.7.0", "jest-environment-jsdom": "29.7.0",
"knip": "5.46.0", "knip": "5.50.3",
"lint-staged": "15.5.0", "lint-staged": "15.5.1",
"npm-check-updates": "^17.1.16", "npm-check-updates": "^17.1.18",
"prettier": "3.5.3", "prettier": "3.5.3",
"puppeteer": "24.4.0", "puppeteer": "24.6.1",
"react-is": "19.0.0", "react-is": "19.1.0",
"storybook": "8.6.8", "storybook": "8.6.12",
"ts-node": "10.9.2", "ts-node": "10.9.2",
"typescript": "5.8.2", "typescript": "5.8.3",
"vite": "6.2.2", "vite": "6.2.6",
"vitest": "3.0.9" "vitest": "3.1.1"
} }
} }

2919
front/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -16,7 +16,7 @@ import {
AlbumCreate, AlbumCreate,
AlbumUpdate, AlbumUpdate,
Long, Long,
UUID, ObjectId,
ZodAlbum, ZodAlbum,
isAlbum, isAlbum,
} from "../model"; } from "../model";
@ -76,32 +76,6 @@ export namespace AlbumResource {
restConfig, restConfig,
}, isGetsTypeReturn); }, isGetsTypeReturn);
}; };
/**
* Update a specific album
*/
export function patch({
restConfig,
params,
data,
}: {
restConfig: RESTConfig,
params: {
id: Long,
},
data: Partial<AlbumUpdate>,
}): 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) * Add an album (when all the data already exist)
*/ */
@ -123,6 +97,32 @@ export namespace AlbumResource {
data, data,
}, isAlbum); }, isAlbum);
}; };
/**
* Update a specific album
*/
export function put({
restConfig,
params,
data,
}: {
restConfig: RESTConfig,
params: {
id: Long,
},
data: AlbumUpdate,
}): Promise<Album> {
return RESTRequestJson({
restModel: {
endPoint: "/album/{id}",
requestType: HTTPRequestModel.PUT,
contentType: HTTPMimeType.JSON,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
}, isAlbum);
};
/** /**
* Remove a specific album * Remove a specific album
*/ */
@ -154,7 +154,7 @@ export namespace AlbumResource {
}: { }: {
restConfig: RESTConfig, restConfig: RESTConfig,
params: { params: {
coverId: UUID, coverId: ObjectId,
id: Long, id: Long,
}, },
}): Promise<Album> { }): Promise<Album> {

View File

@ -70,7 +70,25 @@ export namespace ArtistResource {
restConfig, restConfig,
}, isGetsTypeReturn); }, isGetsTypeReturn);
}; };
export function patch({ export function post({
restConfig,
data,
}: {
restConfig: RESTConfig,
data: ArtistCreate,
}): Promise<Artist> {
return RESTRequestJson({
restModel: {
endPoint: "/artist/",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.JSON,
accept: HTTPMimeType.JSON,
},
restConfig,
data,
}, isArtist);
};
export function put({
restConfig, restConfig,
params, params,
data, data,
@ -93,24 +111,6 @@ export namespace ArtistResource {
data, data,
}, isArtist); }, isArtist);
}; };
export function post({
restConfig,
data,
}: {
restConfig: RESTConfig,
data: ArtistCreate,
}): Promise<Artist> {
return RESTRequestJson({
restModel: {
endPoint: "/artist/",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.JSON,
accept: HTTPMimeType.JSON,
},
restConfig,
data,
}, isArtist);
};
export function remove({ export function remove({
restConfig, restConfig,
params, params,

View File

@ -79,12 +79,12 @@ export namespace GenderResource {
params: { params: {
id: Long, id: Long,
}, },
data: Partial<GenderUpdate>, data: GenderUpdate,
}): Promise<Gender> { }): Promise<Gender> {
return RESTRequestJson({ return RESTRequestJson({
restModel: { restModel: {
endPoint: "/gender/{id}", endPoint: "/gender/{id}",
requestType: HTTPRequestModel.PATCH, requestType: HTTPRequestModel.PUT,
contentType: HTTPMimeType.JSON, contentType: HTTPMimeType.JSON,
accept: HTTPMimeType.JSON, accept: HTTPMimeType.JSON,
}, },

View File

@ -22,27 +22,6 @@ import {
export namespace PlaylistResource { 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({ export function get({
restConfig, restConfig,
params, params,
@ -90,29 +69,6 @@ export namespace PlaylistResource {
restConfig, restConfig,
}, isGetsTypeReturn); }, isGetsTypeReturn);
}; };
export function patch({
restConfig,
params,
data,
}: {
restConfig: RESTConfig,
params: {
id: Long,
},
data: Partial<PlaylistUpdate>,
}): Promise<Playlist> {
return RESTRequestJson({
restModel: {
endPoint: "/playlist/{id}",
requestType: HTTPRequestModel.PATCH,
contentType: HTTPMimeType.JSON,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
}, isPlaylist);
};
export function post({ export function post({
restConfig, restConfig,
data, data,
@ -131,6 +87,29 @@ export namespace PlaylistResource {
data, data,
}, isPlaylist); }, isPlaylist);
}; };
export function put({
restConfig,
params,
data,
}: {
restConfig: RESTConfig,
params: {
id: Long,
},
data: PlaylistUpdate,
}): Promise<Playlist> {
return RESTRequestJson({
restModel: {
endPoint: "/playlist/{id}",
requestType: HTTPRequestModel.PUT,
contentType: HTTPMimeType.JSON,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
}, isPlaylist);
};
export function remove({ export function remove({
restConfig, restConfig,
params, params,
@ -171,27 +150,6 @@ export namespace PlaylistResource {
params, params,
}, isPlaylist); }, 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,
},
restConfig,
params,
}, isPlaylist);
};
export function uploadCover({ export function uploadCover({
restConfig, restConfig,
params, params,

View File

@ -23,27 +23,6 @@ import {
export namespace TrackResource { 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({ export function get({
restConfig, restConfig,
params, params,
@ -91,29 +70,6 @@ export namespace TrackResource {
restConfig, restConfig,
}, isGetsTypeReturn); }, isGetsTypeReturn);
}; };
export function patch({
restConfig,
params,
data,
}: {
restConfig: RESTConfig,
params: {
id: Long,
},
data: Partial<TrackUpdate>,
}): Promise<Track> {
return RESTRequestJson({
restModel: {
endPoint: "/track/{id}",
requestType: HTTPRequestModel.PATCH,
contentType: HTTPMimeType.JSON,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
}, isTrack);
};
export function post({ export function post({
restConfig, restConfig,
data, data,
@ -132,6 +88,29 @@ export namespace TrackResource {
data, data,
}, isTrack); }, isTrack);
}; };
export function put({
restConfig,
params,
data,
}: {
restConfig: RESTConfig,
params: {
id: Long,
},
data: TrackUpdate,
}): Promise<Track> {
return RESTRequestJson({
restModel: {
endPoint: "/track/{id}",
requestType: HTTPRequestModel.PUT,
contentType: HTTPMimeType.JSON,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
}, isTrack);
};
export function remove({ export function remove({
restConfig, restConfig,
params, params,
@ -172,27 +151,6 @@ export namespace TrackResource {
params, params,
}, isTrack); }, 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,
},
restConfig,
params,
}, isTrack);
};
export function uploadCover({ export function uploadCover({
restConfig, restConfig,
params, params,

View File

@ -3,18 +3,18 @@
*/ */
import { z as zod } from "zod"; import { z as zod } from "zod";
import {ZodIsoDate} from "./iso-date";
import {ZodObjectId} from "./object-id"; import {ZodObjectId} from "./object-id";
import {ZodLocalDate} from "./local-date";
import {ZodGenericDataSoftDelete, ZodGenericDataSoftDeleteUpdate , ZodGenericDataSoftDeleteCreate } from "./generic-data-soft-delete"; import {ZodGenericDataSoftDelete, ZodGenericDataSoftDeleteUpdate , ZodGenericDataSoftDeleteCreate } from "./generic-data-soft-delete";
export const ZodAlbum = ZodGenericDataSoftDelete.extend({ export const ZodAlbum = ZodGenericDataSoftDelete.extend({
name: zod.string().optional(), name: zod.string().min(1).max(256).optional(),
description: zod.string().optional(), description: zod.string().max(8192).optional(),
/** /**
* List of Id of the specific covers * List of Id of the specific covers
*/ */
covers: zod.array(ZodObjectId).optional(), covers: zod.array(ZodObjectId).readonly().optional(),
publication: ZodLocalDate.optional(), publication: ZodIsoDate.optional(),
}); });
@ -30,13 +30,9 @@ export function isAlbum(data: any): data is Album {
} }
} }
export const ZodAlbumUpdate = ZodGenericDataSoftDeleteUpdate.extend({ export const ZodAlbumUpdate = ZodGenericDataSoftDeleteUpdate.extend({
name: zod.string().nullable().optional(), name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().nullable().optional(), description: zod.string().max(8192).nullable().optional(),
/** publication: ZodIsoDate.nullable().optional(),
* List of Id of the specific covers
*/
covers: zod.array(ZodObjectId).nullable().optional(),
publication: ZodLocalDate.nullable().optional(),
}); });
@ -52,13 +48,9 @@ export function isAlbumUpdate(data: any): data is AlbumUpdate {
} }
} }
export const ZodAlbumCreate = ZodGenericDataSoftDeleteCreate.extend({ export const ZodAlbumCreate = ZodGenericDataSoftDeleteCreate.extend({
name: zod.string().nullable().optional(), name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().nullable().optional(), description: zod.string().max(8192).nullable().optional(),
/** publication: ZodIsoDate.nullable().optional(),
* List of Id of the specific covers
*/
covers: zod.array(ZodObjectId).nullable().optional(),
publication: ZodLocalDate.nullable().optional(),
}); });

View File

@ -3,21 +3,21 @@
*/ */
import { z as zod } from "zod"; import { z as zod } from "zod";
import {ZodIsoDate} from "./iso-date";
import {ZodObjectId} from "./object-id"; import {ZodObjectId} from "./object-id";
import {ZodLocalDate} from "./local-date";
import {ZodGenericDataSoftDelete, ZodGenericDataSoftDeleteUpdate , ZodGenericDataSoftDeleteCreate } from "./generic-data-soft-delete"; import {ZodGenericDataSoftDelete, ZodGenericDataSoftDeleteUpdate , ZodGenericDataSoftDeleteCreate } from "./generic-data-soft-delete";
export const ZodArtist = ZodGenericDataSoftDelete.extend({ export const ZodArtist = ZodGenericDataSoftDelete.extend({
name: zod.string().optional(), name: zod.string().min(1).max(256).optional(),
description: zod.string().optional(), description: zod.string().max(8192).optional(),
/** /**
* List of Id of the specific covers * List of Id of the specific covers
*/ */
covers: zod.array(ZodObjectId).optional(), covers: zod.array(ZodObjectId).readonly().optional(),
firstName: zod.string().optional(), firstName: zod.string().min(1).max(256).optional(),
surname: zod.string().optional(), surname: zod.string().min(1).max(256).optional(),
birth: ZodLocalDate.optional(), birth: ZodIsoDate.optional(),
death: ZodLocalDate.optional(), death: ZodIsoDate.optional(),
}); });
@ -33,16 +33,12 @@ export function isArtist(data: any): data is Artist {
} }
} }
export const ZodArtistUpdate = ZodGenericDataSoftDeleteUpdate.extend({ export const ZodArtistUpdate = ZodGenericDataSoftDeleteUpdate.extend({
name: zod.string().nullable().optional(), name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().nullable().optional(), description: zod.string().max(8192).nullable().optional(),
/** firstName: zod.string().min(1).max(256).nullable().optional(),
* List of Id of the specific covers surname: zod.string().min(1).max(256).nullable().optional(),
*/ birth: ZodIsoDate.nullable().optional(),
covers: zod.array(ZodObjectId).nullable().optional(), death: ZodIsoDate.nullable().optional(),
firstName: zod.string().nullable().optional(),
surname: zod.string().nullable().optional(),
birth: ZodLocalDate.nullable().optional(),
death: ZodLocalDate.nullable().optional(),
}); });
@ -58,16 +54,12 @@ export function isArtistUpdate(data: any): data is ArtistUpdate {
} }
} }
export const ZodArtistCreate = ZodGenericDataSoftDeleteCreate.extend({ export const ZodArtistCreate = ZodGenericDataSoftDeleteCreate.extend({
name: zod.string().nullable().optional(), name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().nullable().optional(), description: zod.string().max(8192).nullable().optional(),
/** firstName: zod.string().min(1).max(256).nullable().optional(),
* List of Id of the specific covers surname: zod.string().min(1).max(256).nullable().optional(),
*/ birth: ZodIsoDate.nullable().optional(),
covers: zod.array(ZodObjectId).nullable().optional(), death: ZodIsoDate.nullable().optional(),
firstName: zod.string().nullable().optional(),
surname: zod.string().nullable().optional(),
birth: ZodLocalDate.nullable().optional(),
death: ZodLocalDate.nullable().optional(),
}); });

View File

@ -7,12 +7,12 @@ import {ZodObjectId} from "./object-id";
import {ZodGenericDataSoftDelete, ZodGenericDataSoftDeleteUpdate , ZodGenericDataSoftDeleteCreate } from "./generic-data-soft-delete"; import {ZodGenericDataSoftDelete, ZodGenericDataSoftDeleteUpdate , ZodGenericDataSoftDeleteCreate } from "./generic-data-soft-delete";
export const ZodGender = ZodGenericDataSoftDelete.extend({ export const ZodGender = ZodGenericDataSoftDelete.extend({
name: zod.string().optional(), name: zod.string().min(1).max(256).optional(),
description: zod.string().optional(), description: zod.string().max(8192).optional(),
/** /**
* List of Id of the specific covers * List of Id of the specific covers
*/ */
covers: zod.array(ZodObjectId).optional(), covers: zod.array(ZodObjectId).readonly().optional(),
}); });
@ -28,12 +28,8 @@ export function isGender(data: any): data is Gender {
} }
} }
export const ZodGenderUpdate = ZodGenericDataSoftDeleteUpdate.extend({ export const ZodGenderUpdate = ZodGenericDataSoftDeleteUpdate.extend({
name: zod.string().nullable().optional(), name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().nullable().optional(), description: zod.string().max(8192).nullable().optional(),
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodObjectId).nullable().optional(),
}); });
@ -49,12 +45,8 @@ export function isGenderUpdate(data: any): data is GenderUpdate {
} }
} }
export const ZodGenderCreate = ZodGenericDataSoftDeleteCreate.extend({ export const ZodGenderCreate = ZodGenericDataSoftDeleteCreate.extend({
name: zod.string().nullable().optional(), name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().nullable().optional(), description: zod.string().max(8192).nullable().optional(),
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodObjectId).nullable().optional(),
}); });

View File

@ -3,8 +3,8 @@
*/ */
import { z as zod } from "zod"; import { z as zod } from "zod";
import {ZodLong} from "./long";
import {ZodGenericTiming, ZodGenericTimingUpdate , ZodGenericTimingCreate } from "./generic-timing"; import {ZodGenericTiming, ZodGenericTimingUpdate , ZodGenericTimingCreate } from "./generic-timing";
import {ZodLong} from "./long";
export const ZodGenericData = ZodGenericTiming.extend({ export const ZodGenericData = ZodGenericTiming.extend({
/** /**

View File

@ -13,10 +13,10 @@ export * from "./iso-date"
export * from "./jwt-header" export * from "./jwt-header"
export * from "./jwt-payload" export * from "./jwt-payload"
export * from "./jwt-token" export * from "./jwt-token"
export * from "./local-date"
export * from "./long" export * from "./long"
export * from "./object-id" export * from "./object-id"
export * from "./part-right" export * from "./part-right"
export * from "./part-right"
export * from "./playlist" export * from "./playlist"
export * from "./rest-error-response" export * from "./rest-error-response"
export * from "./rest-input-error" export * from "./rest-input-error"

View File

@ -3,8 +3,8 @@
*/ */
import { z as zod } from "zod"; import { z as zod } from "zod";
import {ZodJwtHeader} from "./jwt-header";
import {ZodJwtPayload} from "./jwt-payload"; import {ZodJwtPayload} from "./jwt-payload";
import {ZodJwtHeader} from "./jwt-header";
export const ZodJwtToken = zod.object({ export const ZodJwtToken = zod.object({
header: ZodJwtHeader, header: ZodJwtHeader,

View File

@ -6,6 +6,7 @@ import { z as zod } from "zod";
export enum PartRight { export enum PartRight {
READ = 1, READ = 1,
NONE = 0,
WRITE = 2, WRITE = 2,
READ_WRITE = 3, READ_WRITE = 3,
}; };

View File

@ -3,17 +3,18 @@
*/ */
import { z as zod } from "zod"; import { z as zod } from "zod";
import {ZodLong} from "./long";
import {ZodObjectId} from "./object-id"; import {ZodObjectId} from "./object-id";
import {ZodGenericDataSoftDelete, ZodGenericDataSoftDeleteUpdate , ZodGenericDataSoftDeleteCreate } from "./generic-data-soft-delete"; import {ZodGenericDataSoftDelete, ZodGenericDataSoftDeleteUpdate , ZodGenericDataSoftDeleteCreate } from "./generic-data-soft-delete";
export const ZodPlaylist = ZodGenericDataSoftDelete.extend({ export const ZodPlaylist = ZodGenericDataSoftDelete.extend({
name: zod.string().optional(), name: zod.string().min(1).max(256).optional(),
description: zod.string().optional(), description: zod.string().max(8192).optional(),
/** /**
* List of Id of the specific covers * List of Id of the specific covers
*/ */
covers: zod.array(ZodObjectId).optional(), covers: zod.array(ZodObjectId).readonly().optional(),
tracks: zod.array(ZodObjectId), tracks: zod.array(ZodLong),
}); });
@ -29,13 +30,9 @@ export function isPlaylist(data: any): data is Playlist {
} }
} }
export const ZodPlaylistUpdate = ZodGenericDataSoftDeleteUpdate.extend({ export const ZodPlaylistUpdate = ZodGenericDataSoftDeleteUpdate.extend({
name: zod.string().nullable().optional(), name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().nullable().optional(), description: zod.string().max(8192).nullable().optional(),
/** tracks: zod.array(ZodLong),
* List of Id of the specific covers
*/
covers: zod.array(ZodObjectId).nullable().optional(),
tracks: zod.array(ZodObjectId),
}); });
@ -51,13 +48,9 @@ export function isPlaylistUpdate(data: any): data is PlaylistUpdate {
} }
} }
export const ZodPlaylistCreate = ZodGenericDataSoftDeleteCreate.extend({ export const ZodPlaylistCreate = ZodGenericDataSoftDeleteCreate.extend({
name: zod.string().nullable().optional(), name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().nullable().optional(), description: zod.string().max(8192).nullable().optional(),
/** tracks: zod.array(ZodLong),
* List of Id of the specific covers
*/
covers: zod.array(ZodObjectId).nullable().optional(),
tracks: zod.array(ZodObjectId),
}); });

View File

@ -3,9 +3,9 @@
*/ */
import { z as zod } from "zod"; import { z as zod } from "zod";
import {ZodObjectId} from "./object-id";
import {ZodInteger} from "./integer";
import {ZodRestInputError} from "./rest-input-error"; import {ZodRestInputError} from "./rest-input-error";
import {ZodInteger} from "./integer";
import {ZodObjectId} from "./object-id";
export const ZodRestErrorResponse = zod.object({ export const ZodRestErrorResponse = zod.object({
oid: ZodObjectId.optional(), oid: ZodObjectId.optional(),

View File

@ -3,17 +3,17 @@
*/ */
import { z as zod } from "zod"; import { z as zod } from "zod";
import {ZodObjectId} from "./object-id";
import {ZodLong} from "./long"; import {ZodLong} from "./long";
import {ZodObjectId} from "./object-id";
import {ZodGenericDataSoftDelete, ZodGenericDataSoftDeleteUpdate , ZodGenericDataSoftDeleteCreate } from "./generic-data-soft-delete"; import {ZodGenericDataSoftDelete, ZodGenericDataSoftDeleteUpdate , ZodGenericDataSoftDeleteCreate } from "./generic-data-soft-delete";
export const ZodTrack = ZodGenericDataSoftDelete.extend({ export const ZodTrack = ZodGenericDataSoftDelete.extend({
name: zod.string().optional(), name: zod.string().min(1).max(256).optional(),
description: zod.string().optional(), description: zod.string().max(8192).optional(),
/** /**
* List of Id of the specific covers * List of Id of the specific covers
*/ */
covers: zod.array(ZodObjectId).optional(), covers: zod.array(ZodObjectId).readonly().optional(),
genderId: ZodLong.optional(), genderId: ZodLong.optional(),
albumId: ZodLong.optional(), albumId: ZodLong.optional(),
track: ZodLong.optional(), track: ZodLong.optional(),
@ -34,12 +34,8 @@ export function isTrack(data: any): data is Track {
} }
} }
export const ZodTrackUpdate = ZodGenericDataSoftDeleteUpdate.extend({ export const ZodTrackUpdate = ZodGenericDataSoftDeleteUpdate.extend({
name: zod.string().nullable().optional(), name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().nullable().optional(), description: zod.string().max(8192).nullable().optional(),
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodObjectId).nullable().optional(),
genderId: ZodLong.nullable().optional(), genderId: ZodLong.nullable().optional(),
albumId: ZodLong.nullable().optional(), albumId: ZodLong.nullable().optional(),
track: ZodLong.nullable().optional(), track: ZodLong.nullable().optional(),
@ -60,12 +56,8 @@ export function isTrackUpdate(data: any): data is TrackUpdate {
} }
} }
export const ZodTrackCreate = ZodGenericDataSoftDeleteCreate.extend({ export const ZodTrackCreate = ZodGenericDataSoftDeleteCreate.extend({
name: zod.string().nullable().optional(), name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().nullable().optional(), description: zod.string().max(8192).nullable().optional(),
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodObjectId).nullable().optional(),
genderId: ZodLong.nullable().optional(), genderId: ZodLong.nullable().optional(),
albumId: ZodLong.nullable().optional(), albumId: ZodLong.nullable().optional(),
track: ZodLong.nullable().optional(), track: ZodLong.nullable().optional(),

View File

@ -3,8 +3,8 @@
*/ */
import { z as zod } from "zod"; import { z as zod } from "zod";
import {ZodTimestamp} from "./timestamp";
import {ZodUUID} from "./uuid"; import {ZodUUID} from "./uuid";
import {ZodTimestamp} from "./timestamp";
import {ZodGenericDataSoftDelete, ZodGenericDataSoftDeleteUpdate , ZodGenericDataSoftDeleteCreate } from "./generic-data-soft-delete"; import {ZodGenericDataSoftDelete, ZodGenericDataSoftDeleteUpdate , ZodGenericDataSoftDeleteCreate } from "./generic-data-soft-delete";
export const ZodUser = ZodGenericDataSoftDelete.extend({ export const ZodUser = ZodGenericDataSoftDelete.extend({

View File

@ -1,7 +1,6 @@
import { ReactElement, useEffect, useState } from 'react'; import { ReactElement, useEffect, useState } from 'react';
import { Box, BoxProps, Flex, FlexProps } from '@chakra-ui/react'; import { Box, BoxProps, Flex, Image } from '@chakra-ui/react';
import { Image } from '@chakra-ui/react';
import { ObjectId } from '@/back-api'; import { ObjectId } from '@/back-api';
import { DataUrlAccess } from '@/utils/data-url-access'; import { DataUrlAccess } from '@/utils/data-url-access';
@ -9,7 +8,7 @@ import { DataUrlAccess } from '@/utils/data-url-access';
import { Icon } from './Icon'; import { Icon } from './Icon';
export type CoversProps = Omit<BoxProps, 'iconEmpty'> & { export type CoversProps = Omit<BoxProps, 'iconEmpty'> & {
data?: ObjectId[]; data?: readonly ObjectId[];
size?: BoxProps['width']; size?: BoxProps['width'];
iconEmpty?: ReactElement; iconEmpty?: ReactElement;
slideshow?: boolean; slideshow?: boolean;

View File

@ -47,6 +47,7 @@ import {
MenuRoot, MenuRoot,
MenuTrigger, MenuTrigger,
} from '@/components/ui/menu'; } from '@/components/ui/menu';
import { environment } from '@/environment';
import { useServiceContext } from '@/service/ServiceContext'; import { useServiceContext } from '@/service/ServiceContext';
import { useSessionService } from '@/service/session'; import { useSessionService } from '@/service/session';
import { colors } from '@/theme/colors'; import { colors } from '@/theme/colors';

View File

@ -9,7 +9,7 @@ import {
} from 'react-icons/md'; } from 'react-icons/md';
import { useNavigate, useParams } from 'react-router-dom'; import { useNavigate, useParams } from 'react-router-dom';
import { AlbumResource, AlbumUpdate } from '@/back-api'; import { AlbumResource, AlbumUpdate, ZodAlbumUpdate } from '@/back-api';
import { FormCovers } from '@/components/form/FormCovers'; import { FormCovers } from '@/components/form/FormCovers';
import { FormGroupShow } from '@/components/form/FormGroup'; import { FormGroupShow } from '@/components/form/FormGroup';
import { FormInput } from '@/components/form/FormInput'; import { FormInput } from '@/components/form/FormInput';
@ -68,15 +68,15 @@ export const AlbumEditPopUp = ({}: AlbumEditPopUpProps) => {
initialValues: dataAlbum, initialValues: dataAlbum,
deltaConfig: { omit: ['covers'] }, deltaConfig: { omit: ['covers'] },
}); });
const onSave = async (deltaData: Partial<AlbumUpdate>) => { const onSave = async (delta: AlbumUpdate) => {
if (isNullOrUndefined(albumIdInt)) { if (isNullOrUndefined(albumIdInt)) {
return; return;
} }
console.log(`onSave = ${JSON.stringify(deltaData, null, 2)}`); console.log(`onSave = ${JSON.stringify(delta, null, 2)}`);
store.update( store.update(
AlbumResource.patch({ AlbumResource.put({
restConfig: session.getRestConfig(), restConfig: session.getRestConfig(),
data: deltaData, data: ZodAlbumUpdate.parse(delta),
params: { params: {
id: albumIdInt, id: albumIdInt,
}, },
@ -147,7 +147,7 @@ export const AlbumEditPopUp = ({}: AlbumEditPopUpProps) => {
data-testid="album-edit-pop-up" data-testid="album-edit-pop-up"
> >
<DialogContent> <DialogContent>
<Formidable.From form={form} onSubmitDelta={onSave}> <Formidable.From form={form} onSubmit={onSave}>
<DialogHeader>Edit Album</DialogHeader> <DialogHeader>Edit Album</DialogHeader>
{/* <DialogCloseButton ref={finalRef} /> */} {/* <DialogCloseButton ref={finalRef} /> */}

View File

@ -9,7 +9,7 @@ import {
} from 'react-icons/md'; } from 'react-icons/md';
import { useNavigate, useParams } from 'react-router-dom'; import { useNavigate, useParams } from 'react-router-dom';
import { ArtistResource, ArtistUpdate } from '@/back-api'; import { ArtistResource, ArtistUpdate, ZodArtistUpdate } from '@/back-api';
import { FormCovers } from '@/components/form/FormCovers'; import { FormCovers } from '@/components/form/FormCovers';
import { FormInput } from '@/components/form/FormInput'; import { FormInput } from '@/components/form/FormInput';
import { FormTextarea } from '@/components/form/FormTextarea'; import { FormTextarea } from '@/components/form/FormTextarea';
@ -67,15 +67,15 @@ export const ArtistEditPopUp = ({}: ArtistEditPopUpProps) => {
initialValues: dataArtist, initialValues: dataArtist,
deltaConfig: { omit: ['covers'] }, deltaConfig: { omit: ['covers'] },
}); });
const onSave = async (dataDelta: Partial<ArtistUpdate>) => { const onSave = async (data: ArtistUpdate) => {
if (isNullOrUndefined(artistIdInt)) { if (isNullOrUndefined(artistIdInt)) {
return; return;
} }
console.log(`onSave = ${JSON.stringify(dataDelta, null, 2)}`); console.log(`onSave = ${JSON.stringify(data, null, 2)}`);
store.update( store.update(
ArtistResource.patch({ ArtistResource.put({
restConfig: session.getRestConfig(), restConfig: session.getRestConfig(),
data: dataDelta, data: ZodArtistUpdate.parse(data),
params: { params: {
id: artistIdInt, id: artistIdInt,
}, },
@ -146,7 +146,7 @@ export const ArtistEditPopUp = ({}: ArtistEditPopUpProps) => {
> >
{/* <DialogOverlay /> */} {/* <DialogOverlay /> */}
<DialogContent> <DialogContent>
<Formidable.From form={form} onSubmitDelta={onSave}> <Formidable.From form={form} onSubmit={onSave}>
<DialogHeader>Edit Artist</DialogHeader> <DialogHeader>Edit Artist</DialogHeader>
{/* <DialogCloseButton ref={finalRef} /> */} {/* <DialogCloseButton ref={finalRef} /> */}

View File

@ -9,7 +9,7 @@ import {
} from 'react-icons/md'; } from 'react-icons/md';
import { useNavigate, useParams } from 'react-router-dom'; import { useNavigate, useParams } from 'react-router-dom';
import { GenderResource, GenderUpdate } from '@/back-api'; import { GenderResource, GenderUpdate, ZodGenderUpdate } from '@/back-api';
import { FormCovers } from '@/components/form/FormCovers'; import { FormCovers } from '@/components/form/FormCovers';
import { FormInput } from '@/components/form/FormInput'; import { FormInput } from '@/components/form/FormInput';
import { FormTextarea } from '@/components/form/FormTextarea'; import { FormTextarea } from '@/components/form/FormTextarea';
@ -67,15 +67,15 @@ export const GenderEditPopUp = ({}: GenderEditPopUpProps) => {
initialValues: dataGender, initialValues: dataGender,
deltaConfig: { omit: ['covers'] }, deltaConfig: { omit: ['covers'] },
}); });
const onSave = async (dataDelta: Partial<GenderUpdate>) => { const onSave = async (data: GenderUpdate) => {
if (isNullOrUndefined(genderIdInt)) { if (isNullOrUndefined(genderIdInt)) {
return; return;
} }
console.log(`onSave = ${JSON.stringify(dataDelta, null, 2)}`); console.log(`onSave = ${JSON.stringify(data, null, 2)}`);
store.update( store.update(
GenderResource.patch({ GenderResource.patch({
restConfig: session.getRestConfig(), restConfig: session.getRestConfig(),
data: dataDelta, data: ZodGenderUpdate.parse(data),
params: { params: {
id: genderIdInt, id: genderIdInt,
}, },
@ -145,7 +145,7 @@ export const GenderEditPopUp = ({}: GenderEditPopUpProps) => {
> >
{/* <DialogOverlay /> */} {/* <DialogOverlay /> */}
<DialogContent> <DialogContent>
<Formidable.From form={form} onSubmitDelta={onSave}> <Formidable.From form={form} onSubmit={onSave}>
<DialogHeader>Edit Gender</DialogHeader> <DialogHeader>Edit Gender</DialogHeader>
{/* <DialogCloseButton ref={finalRef} /> */} {/* <DialogCloseButton ref={finalRef} /> */}

View File

@ -4,7 +4,7 @@ import { Button, Text, useDisclosure } from '@chakra-ui/react';
import { MdAdminPanelSettings, MdDeleteForever, MdEdit } from 'react-icons/md'; import { MdAdminPanelSettings, MdDeleteForever, MdEdit } from 'react-icons/md';
import { useNavigate, useParams } from 'react-router-dom'; import { useNavigate, useParams } from 'react-router-dom';
import { TrackResource, TrackUpdate } from '@/back-api'; import { TrackResource, TrackUpdate, ZodTrackUpdate } from '@/back-api';
import { FormGroupShow } from '@/components/form/FormGroup'; import { FormGroupShow } from '@/components/form/FormGroup';
import { FormInput } from '@/components/form/FormInput'; import { FormInput } from '@/components/form/FormInput';
import { FormNumber } from '@/components/form/FormNumber'; import { FormNumber } from '@/components/form/FormNumber';
@ -68,15 +68,20 @@ export const TrackEditPopUp = ({}: TrackEditPopUpProps) => {
initialValues: dataTrack, initialValues: dataTrack,
deltaConfig: { omit: ['covers'] }, deltaConfig: { omit: ['covers'] },
}); });
const onSave = async (dataDelta: Partial<TrackUpdate>) => { const onSave = async (data: TrackUpdate) => {
if (isNullOrUndefined(trackIdInt)) { if (isNullOrUndefined(trackIdInt)) {
return; return;
} }
console.log(`onSave = ${JSON.stringify(dataDelta, null, 2)}`); console.log(`onSave = ${JSON.stringify(data, null, 2)}`);
const { track, ...rest } = data;
let trackNumber: undefined | number = undefined;
if (track !== undefined && track !== null) {
trackNumber = parseInt(`${track}`, 10);
}
store.update( store.update(
TrackResource.patch({ TrackResource.put({
restConfig: session.getRestConfig(), restConfig: session.getRestConfig(),
data: dataDelta, data: ZodTrackUpdate.parse({ track: trackNumber, ...rest }),
params: { params: {
id: trackIdInt, id: trackIdInt,
}, },
@ -94,7 +99,7 @@ export const TrackEditPopUp = ({}: TrackEditPopUpProps) => {
> >
{/* <DialogOverlay /> */} {/* <DialogOverlay /> */}
<DialogContent> <DialogContent>
<Formidable.From form={form} onSubmitDelta={onSave}> <Formidable.From form={form} onSubmit={onSave}>
<DialogHeader>Edit Track</DialogHeader> <DialogHeader>Edit Track</DialogHeader>
{/* <DialogCloseButton ref={finalRef} /> */} {/* <DialogCloseButton ref={finalRef} /> */}

View File

@ -45,7 +45,7 @@ const environment_local: Environment = {
ssoSignUp: `${serverSSOAddress}/karso/signup/karusic-dev/`, ssoSignUp: `${serverSSOAddress}/karso/signup/karusic-dev/`,
ssoSignOut: `${serverSSOAddress}/karso/signout/karusic-dev/`, ssoSignOut: `${serverSSOAddress}/karso/signout/karusic-dev/`,
tokenStoredInPermanentStorage: false, tokenStoredInPermanentStorage: false,
replaceDataToRealServer: true, //replaceDataToRealServer: true,
}; };
/** /**
@ -60,7 +60,6 @@ export const environment = isDevelopmentEnvironment()
? environment_local ? environment_local
: environment_back_prod; : environment_back_prod;
/** /**
* get the current REST api URL. Depend on the VITE_API_BASE_URL env variable. * get the current REST api URL. Depend on the VITE_API_BASE_URL env variable.
* @returns The URL with http(s)://*** * @returns The URL with http(s)://***

View File

@ -10,7 +10,7 @@ import { ArtistServiceProps, useArtistServiceWrapped } from '@/service/Artist';
import { useGenderServiceWrapped } from '@/service/Gender'; import { useGenderServiceWrapped } from '@/service/Gender';
import { TrackServiceProps, useTrackServiceWrapped } from '@/service/Track'; import { TrackServiceProps, useTrackServiceWrapped } from '@/service/Track';
import { import {
RightPart, RightGroup,
SessionServiceProps, SessionServiceProps,
getRestConfig, getRestConfig,
useSessionServiceWrapped, useSessionServiceWrapped,
@ -62,8 +62,8 @@ export const ServiceContext = createContext<ServiceContextType>({
errorSession: undefined, errorSession: undefined,
setToken: (token: string) => {}, setToken: (token: string) => {},
clearToken: () => {}, clearToken: () => {},
hasReadRight: (part: RightPart) => false, hasReadRight: (part: RightGroup) => false,
hasWriteRight: (part: RightPart) => false, hasWriteRight: (part: RightGroup) => false,
getRestConfig: getRestConfig, getRestConfig: getRestConfig,
}, },
track: { track: {