[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 \
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.
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-debug` | DEBUG | INFO | INFO |

View File

@ -18,5 +18,5 @@ WORKDIR /application/
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
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
@ -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"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.kar</groupId>
<groupId>org.atriasoft</groupId>
<artifactId>karusic</artifactId>
<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>
<dependency>
<groupId>kangaroo-and-rabbit</groupId>
<groupId>org.atria-soft</groupId>
<artifactId>archidata</artifactId>
<version>0.25.6</version>
<version>0.28.0</version>
</dependency>
<!-- Loopback of logger JDK logging API to SLF4J -->
<dependency>
@ -106,7 +100,7 @@
<goal>java</goal>
</goals>
<configuration>
<mainClass>org.kar.karusic.WebLauncher</mainClass>
<mainClass>org.atriasoft.karusic.WebLauncher</mainClass>
</configuration>
</execution>
<execution>
@ -115,7 +109,7 @@
<goal>java</goal>
</goals>
<configuration>
<mainClass>org.kar.karusic.WebLauncherLocal</mainClass>
<mainClass>org.atriasoft.karusic.WebLauncherLocal</mainClass>
</configuration>
</execution>
<execution>
@ -124,7 +118,7 @@
<goal>java</goal>
</goals>
<configuration>
<mainClass>org.kar.karusic.GenerateApi</mainClass>
<mainClass>org.atriasoft.karusic.GenerateApi</mainClass>
</configuration>
</execution>
</executions>

View File

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

View File

@ -1,4 +1,4 @@
package org.kar.karusic.CodecBson;
package org.atriasoft.karusic.CodecBson;
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.LoggerFactory;

View File

@ -1,4 +1,4 @@
package org.kar.karusic;
package org.atriasoft.karusic;
import java.net.URI;
import java.util.Iterator;
@ -8,38 +8,39 @@ import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.ImageWriter;
import org.atriasoft.archidata.UpdateJwtPublicKey;
import org.atriasoft.archidata.api.DataResource;
import org.atriasoft.archidata.api.ProxyResource;
import org.atriasoft.archidata.catcher.GenericCatcher;
import org.atriasoft.archidata.db.DbConfig;
import org.atriasoft.archidata.exception.DataAccessException;
import org.atriasoft.archidata.filter.CORSFilter;
import org.atriasoft.archidata.filter.OptionFilter;
import org.atriasoft.archidata.migration.MigrationEngine;
import org.atriasoft.archidata.tools.ConfigBaseVariable;
import org.atriasoft.archidata.tools.ContextGenericTools;
import org.atriasoft.karusic.api.AlbumResource;
import org.atriasoft.karusic.api.ArtistResource;
import org.atriasoft.karusic.api.Front;
import org.atriasoft.karusic.api.GenderResource;
import org.atriasoft.karusic.api.HealthCheck;
import org.atriasoft.karusic.api.PlaylistResource;
import org.atriasoft.karusic.api.TrackResource;
import org.atriasoft.karusic.api.UserResource;
import org.atriasoft.karusic.filter.KarusicAuthenticationFilter;
import org.atriasoft.karusic.migration.Initialization;
import org.atriasoft.karusic.migration.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.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.validation.ValidationFeature;
import org.kar.archidata.UpdateJwtPublicKey;
import org.kar.archidata.api.DataResource;
import org.kar.archidata.api.ProxyResource;
import org.kar.archidata.catcher.GenericCatcher;
import org.kar.archidata.db.DbConfig;
import org.kar.archidata.exception.DataAccessException;
import org.kar.archidata.filter.CORSFilter;
import org.kar.archidata.filter.OptionFilter;
import org.kar.archidata.migration.MigrationEngine;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.kar.archidata.tools.ContextGenericTools;
import org.kar.karusic.api.AlbumResource;
import org.kar.karusic.api.ArtistResource;
import org.kar.karusic.api.Front;
import org.kar.karusic.api.GenderResource;
import org.kar.karusic.api.HealthCheck;
import org.kar.karusic.api.PlaylistResource;
import org.kar.karusic.api.TrackResource;
import org.kar.karusic.api.UserResource;
import org.kar.karusic.filter.KarusicAuthenticationFilter;
import org.kar.karusic.migration.Initialization;
import org.kar.karusic.migration.Migration20231126;
import org.kar.karusic.migration.Migration20240225;
import org.kar.karusic.migration.Migration20240226;
import org.kar.karusic.migration.Migration20240907;
import org.kar.karusic.migration.Migration20250104;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.bridge.SLF4JBridgeHandler;
@ -70,6 +71,7 @@ public class WebLauncher {
migrationEngine.add(new Migration20240226());
migrationEngine.add(new Migration20240907());
migrationEngine.add(new Migration20250104());
migrationEngine.add(new Migration20250414());
WebLauncher.LOGGER.info("Migrate the DB [START]");
migrationEngine.migrateWaitAdmin(new DbConfig());
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 org.kar.archidata.exception.DataAccessException;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.kar.karusic.migration.Initialization;
import org.atriasoft.archidata.exception.DataAccessException;
import org.atriasoft.archidata.tools.ConfigBaseVariable;
import org.atriasoft.karusic.migration.Initialization;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.bridge.SLF4JBridgeHandler;

View File

@ -1,31 +1,29 @@
package org.kar.karusic.api;
package org.atriasoft.karusic.api;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;
import org.atriasoft.archidata.annotation.apiGenerator.ApiInputOptional;
import org.atriasoft.archidata.annotation.apiGenerator.ApiTypeScriptProgress;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.dataAccess.DataAccess;
import org.atriasoft.archidata.dataAccess.addOnSQL.AddOnDataJson;
import org.atriasoft.archidata.tools.DataTools;
import org.atriasoft.karusic.model.Album;
import org.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.annotation.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.LoggerFactory;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.annotation.security.RolesAllowed;
import jakarta.validation.Valid;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PATCH;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
@ -35,7 +33,6 @@ import jakarta.ws.rs.core.MediaType;
@Produces({ MediaType.APPLICATION_JSON })
public class AlbumResource {
private static final Logger LOGGER = LoggerFactory.getLogger(AlbumResource.class);
static final AlbumChecker CHECKER = new AlbumChecker();
@GET
@Path("{id}")
@ -59,29 +56,29 @@ public class AlbumResource {
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
@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 ???
// final Album ret = this.morphiaService.getDatastore().save(data);
// return ret;
/* final MongoCollection<Track> trackCollection = db.getCollection("TTRACLK", Track.class); final InsertOneResult res = trackCollection.insertOne(plop); LOGGER.warn("plpop {}", res); final
* ObjectId ploppppp = res.getInsertedId().asObjectId().getValue(); LOGGER.warn("plpop 2522 {}", res.getInsertedId().asObjectId().getValue()); final Track ret =
* trackCollection.find(Filters.eq("_id", res.getInsertedId().asObjectId().getValue())) .first(); System.out.println("Grade found:\t" + ret); */
return DataAccess.insert(data, new CheckFunction(CHECKER));
return DataAccess.insert(data);
}
@PATCH
@PUT
@Path("{id}")
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
@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 UpdateOperations<Album> ops = this.morphiaService.getDatastore().createUpdateOperations(Album.class)
// .set("name", master.getName());
// this.morphiaService.getDatastore().update(query, ops);
// return Response.ok(master).build();
DataAccess.updateWithJson(Album.class, id, jsonRequest, new CheckFunction(CHECKER));
album.id = id;
DataAccess.update(album, id);
return DataAccess.get(Album.class, id);
}
@ -136,7 +133,7 @@ public class AlbumResource {
@Path("{id}/cover/{coverId}")
@RolesAllowed("ADMIN")
@Operation(description = "Remove a cover on a specific album")
public Album removeCover(@PathParam("id") final Long id, @PathParam("coverId") final UUID coverId) throws Exception {
public Album removeCover(@PathParam("id") final Long id, @PathParam("coverId") final ObjectId coverId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Album.class, "id", id, "covers", coverId);
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.util.List;
import org.atriasoft.archidata.annotation.apiGenerator.ApiInputOptional;
import org.atriasoft.archidata.annotation.apiGenerator.ApiTypeScriptProgress;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.dataAccess.DataAccess;
import org.atriasoft.archidata.dataAccess.addOnSQL.AddOnDataJson;
import org.atriasoft.archidata.tools.DataTools;
import org.atriasoft.karusic.model.Artist;
import org.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.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.LoggerFactory;
@ -34,7 +32,6 @@ import jakarta.ws.rs.core.MediaType;
@Produces({ MediaType.APPLICATION_JSON })
public class ArtistResource {
private static final Logger LOGGER = LoggerFactory.getLogger(ArtistResource.class);
static final ArtistChecker CHECKER = new ArtistChecker();
@GET
@Path("{id}")
@ -52,17 +49,17 @@ public class ArtistResource {
@POST
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Artist post(final Artist data) throws Exception {
return DataAccess.insert(data, new CheckFunction(CHECKER));
public Artist post(@Valid final Artist data) throws Exception {
return DataAccess.insert(data);
}
@PUT
@Path("{id}")
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Artist patch(@PathParam("id") final Long id, @Valid final Artist jsonRequest) throws Exception {
// new CheckFunction(CHECKER)
DataAccess.update(id, jsonRequest);
public Artist put(@PathParam("id") final Long id, @Valid final Artist artist) throws Exception {
artist.id = id;
DataAccess.update(artist, 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.kar.karusic.util.ConfigVariable;
import org.atriasoft.archidata.api.FrontGeneric;
import org.atriasoft.karusic.util.ConfigVariable;
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.util.List;
import org.atriasoft.archidata.annotation.apiGenerator.ApiInputOptional;
import org.atriasoft.archidata.annotation.apiGenerator.ApiTypeScriptProgress;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.dataAccess.DataAccess;
import org.atriasoft.archidata.dataAccess.addOnSQL.AddOnDataJson;
import org.atriasoft.archidata.tools.DataTools;
import org.atriasoft.karusic.model.Gender;
import org.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.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.LoggerFactory;
import jakarta.annotation.security.RolesAllowed;
import jakarta.validation.Valid;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PATCH;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
@ -34,7 +32,6 @@ import jakarta.ws.rs.core.MediaType;
@Produces({ MediaType.APPLICATION_JSON })
public class GenderResource {
private static final Logger LOGGER = LoggerFactory.getLogger(GenderResource.class);
static final GenderChecker CHECKER = new GenderChecker();
@GET
@Path("{id}")
@ -52,16 +49,17 @@ public class GenderResource {
@POST
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Gender post(final Gender data) throws Exception {
return DataAccess.insert(data, new CheckFunction(CHECKER));
public Gender post(@Valid final Gender data) throws Exception {
return DataAccess.insert(data);
}
@PATCH
@PUT
@Path("{id}")
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Gender patch(@PathParam("id") final Long id, @ApiAsyncType(Gender.class) final String jsonRequest) throws Exception {
DataAccess.updateWithJson(Gender.class, id, jsonRequest, new CheckFunction(CHECKER));
public Gender patch(@PathParam("id") final Long id, @Valid final Gender gender) throws Exception {
gender.id = id;
DataAccess.update(gender, 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.kar.archidata.tools.ConfigBaseVariable;
import org.kar.archidata.tools.JWTWrapper;
import org.atriasoft.archidata.exception.FailException;
import org.atriasoft.archidata.tools.ConfigBaseVariable;
import org.atriasoft.archidata.tools.JWTWrapper;
import jakarta.annotation.security.PermitAll;
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.util.List;
import org.atriasoft.archidata.annotation.apiGenerator.ApiAsyncType;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.dataAccess.DataAccess;
import org.atriasoft.archidata.dataAccess.addOnSQL.AddOnDataJson;
import org.atriasoft.archidata.tools.DataTools;
import org.atriasoft.karusic.model.Playlist;
import org.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.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.LoggerFactory;
import jakarta.annotation.security.RolesAllowed;
import jakarta.validation.Valid;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PATCH;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
@ -32,7 +31,6 @@ import jakarta.ws.rs.core.MediaType;
@Produces({ MediaType.APPLICATION_JSON })
public class PlaylistResource {
private static final Logger LOGGER = LoggerFactory.getLogger(PlaylistResource.class);
static final TrackChecker CHECKER = new TrackChecker();
@GET
@Path("{id}")
@ -50,16 +48,17 @@ public class PlaylistResource {
@POST
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Playlist post(final Playlist data) throws Exception {
return DataAccess.insert(data, new CheckFunction(CHECKER));
public Playlist post(@Valid final Playlist data) throws Exception {
return DataAccess.insert(data);
}
@PATCH
@PUT
@Path("{id}")
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Playlist patch(@PathParam("id") final Long id, @ApiAsyncType(Playlist.class) final String jsonRequest) throws Exception {
DataAccess.updateWithJson(Playlist.class, id, jsonRequest, new CheckFunction(CHECKER));
public Playlist put(@PathParam("id") final Long id, @Valid final Playlist playlist) throws Exception {
playlist.id = id;
DataAccess.update(playlist, id);
return DataAccess.get(Playlist.class, id);
}
@ -70,27 +69,6 @@ public class PlaylistResource {
DataAccess.delete(Playlist.class, id);
}
@POST
@Path("{id}/track/{trackId}")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
public Playlist addTrack(@PathParam("id") final Long id, @PathParam("trackId") final Long trackId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Playlist.class, "id", id, "track", trackId);
return db.get(Playlist.class, id);
}
}
@DELETE
@Path("{id}/track/{trackId}")
@RolesAllowed("ADMIN")
public Playlist removeTrack(@PathParam("id") final Long id, @PathParam("trackId") final Long trackId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Playlist.class, "id", id, "track", trackId);
return db.get(Playlist.class, id);
}
}
@POST
@Path("{id}/cover")
@RolesAllowed("ADMIN")

View File

@ -1,4 +1,4 @@
package org.kar.karusic.api;
package org.atriasoft.karusic.api;
import java.io.IOException;
import java.io.InputStream;
@ -6,29 +6,28 @@ import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.atriasoft.archidata.annotation.apiGenerator.ApiAsyncType;
import org.atriasoft.archidata.annotation.apiGenerator.ApiInputOptional;
import org.atriasoft.archidata.annotation.apiGenerator.ApiTypeScriptProgress;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.dataAccess.DataAccess;
import org.atriasoft.archidata.dataAccess.addOnSQL.AddOnDataJson;
import org.atriasoft.archidata.model.Data;
import org.atriasoft.archidata.tools.DataTools;
import org.atriasoft.karusic.model.Track;
import org.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.annotation.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.LoggerFactory;
import jakarta.annotation.security.RolesAllowed;
import jakarta.validation.Valid;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PATCH;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
@ -39,7 +38,6 @@ import jakarta.ws.rs.core.Response;
@Produces({ MediaType.APPLICATION_JSON })
public class TrackResource {
private static final Logger LOGGER = LoggerFactory.getLogger(TrackResource.class);
static final TrackChecker CHECKER = new TrackChecker();
@GET
@Path("{id}")
@ -57,16 +55,17 @@ public class TrackResource {
@POST
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Track post(final Track data) throws Exception {
return DataAccess.insert(data, new CheckFunction(CHECKER));
public Track post(@Valid final Track data) throws Exception {
return DataAccess.insert(data);
}
@PATCH
@PUT
@Path("{id}")
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Track patch(@PathParam("id") final Long id, @ApiAsyncType(Track.class) final String jsonRequest) throws Exception {
DataAccess.updateWithJson(Track.class, id, jsonRequest, new CheckFunction(CHECKER));
public Track put(@PathParam("id") final Long id, @Valid final Track track) throws Exception {
track.id = id;
DataAccess.update(track, id);
return DataAccess.get(Track.class, id);
}
@ -77,27 +76,6 @@ public class TrackResource {
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
@Path("{id}/cover")
@RolesAllowed("ADMIN")
@ -196,7 +174,9 @@ public class TrackResource {
trackElem.artists = new ArrayList<>();
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); } */
return Response.ok(trackElem).build();
} 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.Map;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.filter.GenericContext;
import org.kar.karusic.api.UserResourceModel.PartRight;
import org.kar.karusic.api.UserResourceModel.UserMe;
import org.kar.karusic.model.UserKarusic;
import org.atriasoft.archidata.dataAccess.DataAccess;
import org.atriasoft.archidata.filter.GenericContext;
import org.atriasoft.karusic.api.UserResourceModel.PartRight;
import org.atriasoft.karusic.api.UserResourceModel.UserMe;
import org.atriasoft.karusic.model.UserKarusic;
import org.slf4j.Logger;
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;

View File

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

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.ext.Provider;

View File

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

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 {

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 {

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.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.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.NoSuchFileException;
@ -9,14 +9,14 @@ import java.util.List;
import java.util.UUID;
import org.bson.types.ObjectId;
import org.kar.archidata.api.DataResource;
import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.dataAccess.options.AccessDeletedItems;
import org.kar.archidata.dataAccess.options.OverrideTableName;
import org.kar.archidata.migration.MigrationSqlStep;
import org.kar.karusic.migration.model.CoverConversion;
import org.kar.karusic.migration.model.MediaConversion;
import org.kar.karusic.migration.model.OIDConversion;
import org.atriasoft.archidata.api.DataResource;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.dataAccess.options.AccessDeletedItems;
import org.atriasoft.archidata.dataAccess.options.OverrideTableName;
import org.atriasoft.archidata.migration.MigrationSqlStep;
import org.atriasoft.karusic.migration.model.CoverConversion;
import org.atriasoft.karusic.migration.model.MediaConversion;
import org.atriasoft.karusic.migration.model.OIDConversion;
import org.slf4j.Logger;
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.UUID;
import org.bson.types.ObjectId;
import org.kar.archidata.annotation.DataJson;
import org.atriasoft.archidata.annotation.DataJson;
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;

View File

@ -1,4 +1,4 @@
package org.kar.karusic.migration.model;
package org.atriasoft.karusic.migration.model;
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 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.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 org.hibernate.validator.constraints.UniqueElements;
import com.fasterxml.jackson.annotation.JsonInclude;
@ -18,6 +21,8 @@ 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("Artist")
@Table(name = "artist")
@ -25,26 +30,27 @@ import jakarta.persistence.Table;
@JsonInclude(JsonInclude.Include.NON_NULL)
@ApiGenerationMode(create = true, update = true)
public class Artist extends GenericDataSoftDelete {
public static class ArtistChecker extends CheckJPA<Artist> {
public ArtistChecker() {
super(Artist.class);
}
}
@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(targetEntity = Data.class)
@DataJson()
@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)
@Size(min = 1, max = 256)
public String firstName = null;
@Column(length = 256)
@Size(min = 1, max = 256)
public String surname = null;
public LocalDate birth = null;
public LocalDate death = null;
public Date birth = null;
public Date death = null;
@Override
public String toString() {

View File

@ -1,4 +1,4 @@
package org.kar.karusic.model;
package org.atriasoft.karusic.model;
/*
CREATE TABLE `node` (
`id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY,
@ -14,13 +14,16 @@ CREATE TABLE `node` (
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.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 org.hibernate.validator.constraints.UniqueElements;
import com.fasterxml.jackson.annotation.JsonInclude;
@ -29,6 +32,8 @@ 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("Gender")
@Table(name = "gender")
@ -36,20 +41,19 @@ import jakarta.persistence.Table;
@JsonInclude(JsonInclude.Include.NON_NULL)
@ApiGenerationMode(create = true, update = true)
public class Gender extends GenericDataSoftDelete {
public static class GenderChecker extends CheckJPA<Gender> {
public GenderChecker() {
super(Gender.class);
}
}
@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(targetEntity = Data.class)
@DataJson()
@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() {}

View File

@ -1,4 +1,4 @@
package org.kar.karusic.model;
package org.atriasoft.karusic.model;
/*
CREATE TABLE `node` (
`id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY,
@ -14,13 +14,16 @@ CREATE TABLE `node` (
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.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 org.hibernate.validator.constraints.UniqueElements;
import com.fasterxml.jackson.annotation.JsonInclude;
@ -28,9 +31,9 @@ import dev.morphia.annotations.Entity;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable;
import jakarta.persistence.Column;
import jakarta.persistence.FetchType;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.Table;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
@Entity("Playlist")
@Table(name = "playlist")
@ -38,20 +41,19 @@ import jakarta.persistence.Table;
@JsonInclude(JsonInclude.Include.NON_NULL)
@ApiGenerationMode(create = true, update = true)
public class Playlist extends GenericDataSoftDelete {
public static class PlaylistChecker extends CheckJPA<Playlist> {
public PlaylistChecker() {
super(Playlist.class);
}
}
@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(targetEntity = Data.class)
@DataJson()
@Nullable
public List<ObjectId> covers = null;
@ManyToMany(fetch = FetchType.LAZY, targetEntity = Track.class)
public List<ObjectId> tracks = null;
@CollectionNotEmpty
@UniqueElements
@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 {
// User has remove his account

View File

@ -1,4 +1,4 @@
package org.kar.karusic.model;
package org.atriasoft.karusic.model;
/*
CREATE TABLE `node` (
`id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY,
@ -14,13 +14,16 @@ CREATE TABLE `node` (
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.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 org.hibernate.validator.constraints.UniqueElements;
import com.fasterxml.jackson.annotation.JsonInclude;
@ -29,6 +32,9 @@ 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.PositiveOrZero;
import jakarta.validation.constraints.Size;
@Entity("Track")
@Table(name = "track")
@ -37,28 +43,31 @@ import jakarta.persistence.Table;
@ApiGenerationMode(create = true, update = true)
public class Track extends GenericDataSoftDelete {
public static class TrackChecker extends CheckJPA<Track> {
public TrackChecker() {
super(Track.class);
}
}
@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(targetEntity = Data.class)
@DataJson()
@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;
@CheckForeignKey(target = Album.class)
public Long albumId = null;
@PositiveOrZero
public Long track = null;
@CheckForeignKey(target = Data.class)
public ObjectId dataId = null;
// @ManyToMany(fetch = FetchType.LAZY, targetEntity = Artist.class)
@DataJson
@Column(length = 0)
public List<Long> artists = null;
public List<@CheckForeignKey(target = Artist.class) @NotNull Long> artists = null;
@Override
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.kar.archidata.model.User;
import org.atriasoft.archidata.annotation.DataIfNotExists;
import org.atriasoft.archidata.model.User;
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 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>
</encoder>
</appender>
<logger name="org.kar.karusic" level="TRACE" />
<logger name="org.kar.archidata" level="DEBUG" />
<logger name="org.atriasoft.karusic" level="TRACE" />
<logger name="org.atriasoft.archidata" level="DEBUG" />
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
@ -32,19 +32,19 @@
</if>
<if condition="property(&quot;LOG_LEVEL_ENV&quot;).equals(&quot;prod-debug&quot;)">
<then>
<logger name="org.kar.karusic" level="DEBUG" />
<logger name="org.atriasoft.karusic" level="DEBUG" />
</then>
</if>
<if condition="property(&quot;LOG_LEVEL_ENV&quot;).equals(&quot;prod-trace&quot;)">
<then>
<logger name="org.kar.karusic" level="TRACE" />
<logger name="org.kar.archidata" level="DEBUG" />
<logger name="org.atriasoft.karusic" level="TRACE" />
<logger name="org.atriasoft.archidata" level="DEBUG" />
</then>
</if>
<if condition="property(&quot;LOG_LEVEL_ENV&quot;).equals(&quot;prod-trace-full&quot;)">
<then>
<logger name="org.kar.karusic" level="TRACE" />
<logger name="org.kar.archidata" level="TRACE" />
<logger name="org.atriasoft.karusic" level="TRACE" />
<logger name="org.atriasoft.archidata" level="TRACE" />
</then>
</if>
</configuration>

View File

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

View File

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

View File

@ -1,4 +1,4 @@
package test.kar.karusic;
package test.atriasoft.karusic;
import java.io.File;
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.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.Assertions;
@ -8,10 +8,10 @@ import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith;
import org.kar.archidata.exception.RESTErrorResponseException;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.kar.archidata.tools.RESTApi;
import org.kar.karusic.api.HealthCheck.HealthResult;
import org.atriasoft.archidata.exception.RESTErrorResponseException;
import org.atriasoft.archidata.tools.ConfigBaseVariable;
import org.atriasoft.archidata.tools.RESTApi;
import org.atriasoft.karusic.api.HealthCheck.HealthResult;
import org.slf4j.Logger;
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.IOException;
@ -15,9 +15,9 @@ import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.kar.archidata.tools.RESTApi;
import org.kar.karusic.model.Track;
import org.atriasoft.archidata.tools.ConfigBaseVariable;
import org.atriasoft.archidata.tools.RESTApi;
import org.atriasoft.karusic.model.Track;
import org.slf4j.Logger;
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.LoggerFactory;

View File

@ -32,19 +32,19 @@
"react-speech-recognition": "4.0.0",
"regenerator-runtime": "0.14.1",
"@trivago/prettier-plugin-sort-imports": "5.2.2",
"@chakra-ui/cli": "3.13.0",
"@chakra-ui/react": "3.13.0",
"@chakra-ui/cli": "3.16.0",
"@chakra-ui/react": "3.16.0",
"@emotion/react": "11.14.0",
"allotment": "1.20.3",
"css-mediaquery": "0.1.2",
"dayjs": "1.11.13",
"history": "5.3.0",
"next-themes": "^0.4.6",
"react": "19.0.0",
"react-dom": "19.0.0",
"react": "19.1.0",
"react-dom": "19.1.0",
"react-error-boundary": "5.0.0",
"react-icons": "5.5.0",
"react-router-dom": "7.4.0",
"react-router-dom": "7.5.0",
"react-select": "5.10.1",
"react-use": "17.6.0",
"zod": "3.24.2",
@ -53,41 +53,41 @@
"devDependencies": {
"@chakra-ui/styled-system": "^2.12.0",
"@playwright/test": "1.51.1",
"@storybook/addon-actions": "8.6.8",
"@storybook/addon-essentials": "8.6.8",
"@storybook/addon-links": "8.6.8",
"@storybook/addon-mdx-gfm": "8.6.8",
"@storybook/react": "8.6.8",
"@storybook/react-vite": "8.6.8",
"@storybook/theming": "8.6.8",
"@storybook/addon-actions": "8.6.12",
"@storybook/addon-essentials": "8.6.12",
"@storybook/addon-links": "8.6.12",
"@storybook/addon-mdx-gfm": "8.6.12",
"@storybook/react": "8.6.12",
"@storybook/react-vite": "8.6.12",
"@storybook/theming": "8.6.12",
"@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",
"@trivago/prettier-plugin-sort-imports": "5.2.2",
"@types/jest": "29.5.14",
"@types/node": "22.13.11",
"@types/react": "19.0.12",
"@types/react-dom": "19.0.4",
"@typescript-eslint/eslint-plugin": "8.27.0",
"@typescript-eslint/parser": "8.27.0",
"@types/node": "22.14.1",
"@types/react": "19.1.1",
"@types/react-dom": "19.1.2",
"@typescript-eslint/eslint-plugin": "8.30.0",
"@typescript-eslint/parser": "8.30.0",
"@vitejs/plugin-react": "4.3.4",
"eslint": "9.23.0",
"eslint": "9.24.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-storybook": "0.11.6",
"eslint-plugin-storybook": "0.12.0",
"jest": "29.7.0",
"jest-environment-jsdom": "29.7.0",
"knip": "5.46.0",
"lint-staged": "15.5.0",
"npm-check-updates": "^17.1.16",
"knip": "5.50.3",
"lint-staged": "15.5.1",
"npm-check-updates": "^17.1.18",
"prettier": "3.5.3",
"puppeteer": "24.4.0",
"react-is": "19.0.0",
"storybook": "8.6.8",
"puppeteer": "24.6.1",
"react-is": "19.1.0",
"storybook": "8.6.12",
"ts-node": "10.9.2",
"typescript": "5.8.2",
"vite": "6.2.2",
"vitest": "3.0.9"
"typescript": "5.8.3",
"vite": "6.2.6",
"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,
AlbumUpdate,
Long,
UUID,
ObjectId,
ZodAlbum,
isAlbum,
} from "../model";
@ -76,32 +76,6 @@ export namespace AlbumResource {
restConfig,
}, 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)
*/
@ -123,6 +97,32 @@ export namespace AlbumResource {
data,
}, 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
*/
@ -154,7 +154,7 @@ export namespace AlbumResource {
}: {
restConfig: RESTConfig,
params: {
coverId: UUID,
coverId: ObjectId,
id: Long,
},
}): Promise<Album> {

View File

@ -70,7 +70,25 @@ export namespace ArtistResource {
restConfig,
}, 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,
params,
data,
@ -93,24 +111,6 @@ export namespace ArtistResource {
data,
}, 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({
restConfig,
params,

View File

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

View File

@ -22,27 +22,6 @@ import {
export namespace PlaylistResource {
export function addTrack({
restConfig,
params,
}: {
restConfig: RESTConfig,
params: {
trackId: Long,
id: Long,
},
}): Promise<Playlist> {
return RESTRequestJson({
restModel: {
endPoint: "/playlist/{id}/track/{trackId}",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isPlaylist);
};
export function get({
restConfig,
params,
@ -90,29 +69,6 @@ export namespace PlaylistResource {
restConfig,
}, 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({
restConfig,
data,
@ -131,6 +87,29 @@ export namespace PlaylistResource {
data,
}, 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({
restConfig,
params,
@ -171,27 +150,6 @@ export namespace PlaylistResource {
params,
}, isPlaylist);
};
export function removeTrack({
restConfig,
params,
}: {
restConfig: RESTConfig,
params: {
trackId: Long,
id: Long,
},
}): Promise<Playlist> {
return RESTRequestJson({
restModel: {
endPoint: "/playlist/{id}/track/{trackId}",
requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isPlaylist);
};
export function uploadCover({
restConfig,
params,

View File

@ -23,27 +23,6 @@ import {
export namespace TrackResource {
export function addTrack({
restConfig,
params,
}: {
restConfig: RESTConfig,
params: {
artistId: Long,
id: Long,
},
}): Promise<Track> {
return RESTRequestJson({
restModel: {
endPoint: "/track/{id}/artist/{artistId}",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isTrack);
};
export function get({
restConfig,
params,
@ -91,29 +70,6 @@ export namespace TrackResource {
restConfig,
}, 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({
restConfig,
data,
@ -132,6 +88,29 @@ export namespace TrackResource {
data,
}, 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({
restConfig,
params,
@ -172,27 +151,6 @@ export namespace TrackResource {
params,
}, isTrack);
};
export function removeTrack({
restConfig,
params,
}: {
restConfig: RESTConfig,
params: {
artistId: Long,
id: Long,
},
}): Promise<Track> {
return RESTRequestJson({
restModel: {
endPoint: "/track/{id}/artist/{trackId}",
requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isTrack);
};
export function uploadCover({
restConfig,
params,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -9,7 +9,7 @@ import {
} from 'react-icons/md';
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 { FormInput } from '@/components/form/FormInput';
import { FormTextarea } from '@/components/form/FormTextarea';
@ -67,15 +67,15 @@ export const GenderEditPopUp = ({}: GenderEditPopUpProps) => {
initialValues: dataGender,
deltaConfig: { omit: ['covers'] },
});
const onSave = async (dataDelta: Partial<GenderUpdate>) => {
const onSave = async (data: GenderUpdate) => {
if (isNullOrUndefined(genderIdInt)) {
return;
}
console.log(`onSave = ${JSON.stringify(dataDelta, null, 2)}`);
console.log(`onSave = ${JSON.stringify(data, null, 2)}`);
store.update(
GenderResource.patch({
restConfig: session.getRestConfig(),
data: dataDelta,
data: ZodGenderUpdate.parse(data),
params: {
id: genderIdInt,
},
@ -145,7 +145,7 @@ export const GenderEditPopUp = ({}: GenderEditPopUpProps) => {
>
{/* <DialogOverlay /> */}
<DialogContent>
<Formidable.From form={form} onSubmitDelta={onSave}>
<Formidable.From form={form} onSubmit={onSave}>
<DialogHeader>Edit Gender</DialogHeader>
{/* <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 { 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 { FormInput } from '@/components/form/FormInput';
import { FormNumber } from '@/components/form/FormNumber';
@ -68,15 +68,20 @@ export const TrackEditPopUp = ({}: TrackEditPopUpProps) => {
initialValues: dataTrack,
deltaConfig: { omit: ['covers'] },
});
const onSave = async (dataDelta: Partial<TrackUpdate>) => {
const onSave = async (data: TrackUpdate) => {
if (isNullOrUndefined(trackIdInt)) {
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(
TrackResource.patch({
TrackResource.put({
restConfig: session.getRestConfig(),
data: dataDelta,
data: ZodTrackUpdate.parse({ track: trackNumber, ...rest }),
params: {
id: trackIdInt,
},
@ -94,7 +99,7 @@ export const TrackEditPopUp = ({}: TrackEditPopUpProps) => {
>
{/* <DialogOverlay /> */}
<DialogContent>
<Formidable.From form={form} onSubmitDelta={onSave}>
<Formidable.From form={form} onSubmit={onSave}>
<DialogHeader>Edit Track</DialogHeader>
{/* <DialogCloseButton ref={finalRef} /> */}

View File

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

View File

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