[FEAT] upgrade to MongoDb and use ObjectId

This commit is contained in:
Edouard DUPIN 2025-05-01 23:10:05 +02:00
parent 50f0c903f4
commit d23f1a945c
72 changed files with 12764 additions and 1596 deletions

View File

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

View File

@ -8,7 +8,7 @@
<dependency> <dependency>
<groupId>org.atria-soft</groupId> <groupId>org.atria-soft</groupId>
<artifactId>archidata</artifactId> <artifactId>archidata</artifactId>
<version>0.28.0</version> <version>0.30.3-SNAPSHOT</version>
</dependency> </dependency>
<!-- Loopback of logger JDK logging API to SLF4J --> <!-- Loopback of logger JDK logging API to SLF4J -->
<dependency> <dependency>

View File

@ -2,6 +2,7 @@ package org.atriasoft.karusic;
import java.net.URI; import java.net.URI;
import java.util.Iterator; import java.util.Iterator;
import java.util.TimeZone;
import java.util.logging.LogManager; import java.util.logging.LogManager;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
@ -29,12 +30,7 @@ import org.atriasoft.karusic.api.TrackResource;
import org.atriasoft.karusic.api.UserResource; import org.atriasoft.karusic.api.UserResource;
import org.atriasoft.karusic.filter.KarusicAuthenticationFilter; import org.atriasoft.karusic.filter.KarusicAuthenticationFilter;
import org.atriasoft.karusic.migration.Initialization; import org.atriasoft.karusic.migration.Initialization;
import org.atriasoft.karusic.migration.Migration20231126; import org.atriasoft.karusic.migration.Migration20250427;
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;
@ -53,6 +49,7 @@ public class WebLauncher {
protected HttpServer server = null; protected HttpServer server = null;
public WebLauncher() { public WebLauncher() {
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
ConfigBaseVariable.bdDatabase = "karusic"; ConfigBaseVariable.bdDatabase = "karusic";
} }
@ -66,12 +63,7 @@ public class WebLauncher {
WebLauncher.LOGGER.info("Add initialization"); WebLauncher.LOGGER.info("Add initialization");
migrationEngine.setInit(new Initialization()); migrationEngine.setInit(new Initialization());
WebLauncher.LOGGER.info("Add migration since last version"); WebLauncher.LOGGER.info("Add migration since last version");
migrationEngine.add(new Migration20231126()); migrationEngine.add(new Migration20250427());
migrationEngine.add(new Migration20240225());
migrationEngine.add(new Migration20240226());
migrationEngine.add(new Migration20240907());
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

@ -32,8 +32,8 @@ public class WebLauncherLocal extends WebLauncher {
if (true) { if (true) {
// for local test: // for local test:
ConfigBaseVariable.apiAdress = "http://0.0.0.0:19080/karusic/api/"; ConfigBaseVariable.apiAdress = "http://0.0.0.0:19080/karusic/api/";
ConfigBaseVariable.dbPort = "3906";
ConfigBaseVariable.testMode = "true"; ConfigBaseVariable.testMode = "true";
ConfigBaseVariable.dbType = "mongo";
} }
// Test fail of SSO: ConfigBaseVariable.ssoAdress = null; // Test fail of SSO: ConfigBaseVariable.ssoAdress = null;
try { try {

View File

@ -35,11 +35,11 @@ public class AlbumResource {
private static final Logger LOGGER = LoggerFactory.getLogger(AlbumResource.class); private static final Logger LOGGER = LoggerFactory.getLogger(AlbumResource.class);
@GET @GET
@Path("{id}") @Path("{oid}")
@RolesAllowed("USER") @RolesAllowed("USER")
@Operation(description = "Get a specific Album with his ID") @Operation(description = "Get a specific Album with his ID")
public Album get(@PathParam("id") final Long id) throws Exception { public Album get(@PathParam("oid") final ObjectId oid) throws Exception {
return DataAccess.get(Album.class, id); return DataAccess.get(Album.class, oid);
// return this.morphiaService.getDatastore().find(Album.class).filter(Filters.eq("id", id)).first(); // return this.morphiaService.getDatastore().find(Album.class).filter(Filters.eq("id", id)).first();
} }
@ -67,19 +67,19 @@ public class AlbumResource {
} }
@PUT @PUT
@Path("{id}") @Path("{oid}")
@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 put(@PathParam("id") final Long id, @Valid final Album album) throws Exception { public Album put(@PathParam("oid") final ObjectId oid, @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; album.oid = oid;
DataAccess.update(album, id); DataAccess.update(album, oid);
return DataAccess.get(Album.class, id); return DataAccess.get(Album.class, oid);
} }
// @PUT // @PUT
@ -87,7 +87,7 @@ public class AlbumResource {
// @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 put(@PathParam("id") final Long id, final Album album) // public Album put(@PathParam("id") final ObjectId oid, final Album album)
// throws Exception { // 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)
@ -97,11 +97,11 @@ public class AlbumResource {
// } // }
@DELETE @DELETE
@Path("{id}") @Path("{oid}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Operation(description = "Remove a specific album") @Operation(description = "Remove a specific album")
public void remove(@PathParam("id") final Long id) throws Exception { public void remove(@PathParam("oid") final ObjectId oid) throws Exception {
DataAccess.delete(Album.class, id); DataAccess.delete(Album.class, oid);
// this.morphiaService.getDatastore().find(Album.class).filter(Filters.eq("id", id)).delete(); // this.morphiaService.getDatastore().find(Album.class).filter(Filters.eq("id", id)).delete();
} }
@ -109,34 +109,34 @@ public class AlbumResource {
* @Path("{id}/track/{trackId}") * @Path("{id}/track/{trackId}")
* @RolesAllowed("ADMIN") * @RolesAllowed("ADMIN")
* @Consumes({ MediaType.MULTIPART_FORM_DATA }) * @Consumes({ MediaType.MULTIPART_FORM_DATA })
* @Operation(description = "Add a Track on a specific album") public Album addTrack(@PathParam("id") final Long id, @PathParam("trackId") final Long trackId) throws Exception { * @Operation(description = "Add a Track on a specific album") public Album addTrack(@PathParam("id") final ObjectId oid, @PathParam("trackId") final Long trackId) throws Exception {
* AddOnManyToMany.removeLink(this.dam, Album.class, id, "track", trackId); return this.dam.get(Album.class, id); } */ * AddOnManyToMany.removeLink(this.dam, Album.class, id, "track", trackId); return this.dam.get(Album.class, id); } */
@POST @POST
@Path("{id}/cover") @Path("{oid}/cover")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA }) @Consumes({ MediaType.MULTIPART_FORM_DATA })
@Operation(description = "Add a cover on a specific album") @Operation(description = "Add a cover on a specific album")
@ApiTypeScriptProgress @ApiTypeScriptProgress
public Album uploadCover(@PathParam("id") final Long id, @ApiInputOptional @FormDataParam("uri") final String uri, @ApiInputOptional @FormDataParam("file") final InputStream fileInputStream, public Album uploadCover(@PathParam("oid") final ObjectId oid, @ApiInputOptional @FormDataParam("uri") final String uri, @ApiInputOptional @FormDataParam("file") final InputStream fileInputStream,
@ApiInputOptional @FormDataParam("file") final FormDataContentDisposition fileMetaData) throws Exception { @ApiInputOptional @FormDataParam("file") final FormDataContentDisposition fileMetaData) throws Exception {
try (DBAccess db = DBAccess.createInterface()) { try (DBAccess db = DBAccess.createInterface()) {
if (uri != null) { if (uri != null) {
DataTools.uploadCoverFromUri(db, Album.class, id, uri); DataTools.uploadCoverFromUri(db, Album.class, oid, uri);
} else { } else {
DataTools.uploadCover(db, Album.class, id, fileInputStream, fileMetaData); DataTools.uploadCover(db, Album.class, oid, fileInputStream, fileMetaData);
} }
return db.get(Album.class, id); return db.get(Album.class, oid);
} }
} }
@DELETE @DELETE
@Path("{id}/cover/{coverId}") @Path("{oid}/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 ObjectId coverId) throws Exception { public Album removeCover(@PathParam("oid") final ObjectId oid, @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", oid, "covers", coverId);
return db.get(Album.class, id); return db.get(Album.class, oid);
} }
} }
} }

View File

@ -34,10 +34,10 @@ public class ArtistResource {
private static final Logger LOGGER = LoggerFactory.getLogger(ArtistResource.class); private static final Logger LOGGER = LoggerFactory.getLogger(ArtistResource.class);
@GET @GET
@Path("{id}") @Path("{oid}")
@RolesAllowed("USER") @RolesAllowed("USER")
public Artist get(@PathParam("id") final Long id) throws Exception { public Artist get(@PathParam("oid") final ObjectId oid) throws Exception {
return DataAccess.get(Artist.class, id); return DataAccess.get(Artist.class, oid);
} }
@GET @GET
@ -54,46 +54,46 @@ public class ArtistResource {
} }
@PUT @PUT
@Path("{id}") @Path("{oid}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Artist put(@PathParam("id") final Long id, @Valid final Artist artist) throws Exception { public Artist put(@PathParam("oid") final ObjectId oid, @Valid final Artist artist) throws Exception {
artist.id = id; artist.oid = oid;
DataAccess.update(artist, id); DataAccess.update(artist, oid);
return DataAccess.get(Artist.class, id); return DataAccess.get(Artist.class, oid);
} }
@DELETE @DELETE
@Path("{id}") @Path("{oid}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
public void remove(@PathParam("id") final Long id) throws Exception { public void remove(@PathParam("oid") final ObjectId oid) throws Exception {
DataAccess.delete(Artist.class, id); DataAccess.delete(Artist.class, oid);
} }
@POST @POST
@Path("{id}/cover") @Path("{oid}/cover")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA }) @Consumes({ MediaType.MULTIPART_FORM_DATA })
@ApiTypeScriptProgress @ApiTypeScriptProgress
public Artist uploadCover(@PathParam("id") final Long id, @ApiInputOptional @FormDataParam("uri") final String uri, @ApiInputOptional @FormDataParam("file") final InputStream fileInputStream, public Artist uploadCover(@PathParam("oid") final ObjectId oid, @ApiInputOptional @FormDataParam("uri") final String uri,
@ApiInputOptional @FormDataParam("file") final FormDataContentDisposition fileMetaData) throws Exception { @ApiInputOptional @FormDataParam("file") final InputStream fileInputStream, @ApiInputOptional @FormDataParam("file") final FormDataContentDisposition fileMetaData) throws Exception {
try (DBAccess db = DBAccess.createInterface()) { try (DBAccess db = DBAccess.createInterface()) {
if (uri != null) { if (uri != null) {
DataTools.uploadCoverFromUri(db, Artist.class, id, uri); DataTools.uploadCoverFromUri(db, Artist.class, oid, uri);
} else { } else {
DataTools.uploadCover(db, Artist.class, id, fileInputStream, fileMetaData); DataTools.uploadCover(db, Artist.class, oid, fileInputStream, fileMetaData);
} }
return db.get(Artist.class, id); return db.get(Artist.class, oid);
} }
} }
@DELETE @DELETE
@Path("{id}/cover/{coverId}") @Path("{oid}/cover/{coverId}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
public Artist removeCover(@PathParam("id") final Long id, @PathParam("coverId") final ObjectId coverId) throws Exception { public Artist removeCover(@PathParam("oid") final ObjectId oid, @PathParam("coverId") final ObjectId coverId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) { try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Artist.class, "id", id, "covers", coverId); AddOnDataJson.removeLink(db, Artist.class, "id", oid, "covers", coverId);
return db.get(Artist.class, id); return db.get(Artist.class, oid);
} }
} }
} }

View File

@ -34,10 +34,10 @@ public class GenderResource {
private static final Logger LOGGER = LoggerFactory.getLogger(GenderResource.class); private static final Logger LOGGER = LoggerFactory.getLogger(GenderResource.class);
@GET @GET
@Path("{id}") @Path("{oid}")
@RolesAllowed("USER") @RolesAllowed("USER")
public Gender get(@PathParam("id") final Long id) throws Exception { public Gender get(@PathParam("oid") final ObjectId oid) throws Exception {
return DataAccess.get(Gender.class, id); return DataAccess.get(Gender.class, oid);
} }
@GET @GET
@ -54,46 +54,46 @@ public class GenderResource {
} }
@PUT @PUT
@Path("{id}") @Path("{oid}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Gender patch(@PathParam("id") final Long id, @Valid final Gender gender) throws Exception { public Gender patch(@PathParam("oid") final ObjectId oid, @Valid final Gender gender) throws Exception {
gender.id = id; gender.oid = oid;
DataAccess.update(gender, id); DataAccess.update(gender, oid);
return DataAccess.get(Gender.class, id); return DataAccess.get(Gender.class, oid);
} }
@DELETE @DELETE
@Path("{id}") @Path("{oid}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
public void remove(@PathParam("id") final Long id) throws Exception { public void remove(@PathParam("oid") final ObjectId oid) throws Exception {
DataAccess.delete(Gender.class, id); DataAccess.delete(Gender.class, oid);
} }
@POST @POST
@Path("{id}/cover") @Path("{oid}/cover")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA }) @Consumes({ MediaType.MULTIPART_FORM_DATA })
@ApiTypeScriptProgress @ApiTypeScriptProgress
public Gender uploadCover(@PathParam("id") final Long id, @ApiInputOptional @FormDataParam("uri") final String uri, @ApiInputOptional @FormDataParam("file") final InputStream fileInputStream, public Gender uploadCover(@PathParam("oid") final ObjectId oid, @ApiInputOptional @FormDataParam("uri") final String uri,
@ApiInputOptional @FormDataParam("file") final FormDataContentDisposition fileMetaData) throws Exception { @ApiInputOptional @FormDataParam("file") final InputStream fileInputStream, @ApiInputOptional @FormDataParam("file") final FormDataContentDisposition fileMetaData) throws Exception {
try (DBAccess db = DBAccess.createInterface()) { try (DBAccess db = DBAccess.createInterface()) {
if (uri != null) { if (uri != null) {
DataTools.uploadCoverFromUri(db, Gender.class, id, uri); DataTools.uploadCoverFromUri(db, Gender.class, oid, uri);
} else { } else {
DataTools.uploadCover(db, Gender.class, id, fileInputStream, fileMetaData); DataTools.uploadCover(db, Gender.class, oid, fileInputStream, fileMetaData);
} }
return db.get(Gender.class, id); return db.get(Gender.class, oid);
} }
} }
@DELETE @DELETE
@Path("{id}/cover/{coverId}") @Path("{oid}/cover/{coverId}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
public Gender removeCover(@PathParam("id") final Long id, @PathParam("coverId") final ObjectId coverId) throws Exception { public Gender removeCover(@PathParam("oid") final ObjectId oid, @PathParam("coverId") final ObjectId coverId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) { try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Gender.class, "id", id, "covers", coverId); AddOnDataJson.removeLink(db, Gender.class, "_id", oid, "covers", coverId);
return db.get(Gender.class, id); return db.get(Gender.class, oid);
} }
} }
} }

View File

@ -35,8 +35,8 @@ public class PlaylistResource {
@GET @GET
@Path("{id}") @Path("{id}")
@RolesAllowed("USER") @RolesAllowed("USER")
public Playlist get(@PathParam("id") final Long id) throws Exception { public Playlist get(@PathParam("id") final ObjectId oid) throws Exception {
return DataAccess.get(Playlist.class, id); return DataAccess.get(Playlist.class, oid);
} }
@GET @GET
@ -53,41 +53,41 @@ public class PlaylistResource {
} }
@PUT @PUT
@Path("{id}") @Path("{oid}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Playlist put(@PathParam("id") final Long id, @Valid final Playlist playlist) throws Exception { public Playlist put(@PathParam("oid") final ObjectId oid, @Valid final Playlist playlist) throws Exception {
playlist.id = id; playlist.oid = oid;
DataAccess.update(playlist, id); DataAccess.update(playlist, oid);
return DataAccess.get(Playlist.class, id); return DataAccess.get(Playlist.class, oid);
} }
@DELETE @DELETE
@Path("{id}") @Path("{oid}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
public void remove(@PathParam("id") final Long id) throws Exception { public void remove(@PathParam("oid") final ObjectId oid) throws Exception {
DataAccess.delete(Playlist.class, id); DataAccess.delete(Playlist.class, oid);
} }
@POST @POST
@Path("{id}/cover") @Path("{oid}/cover")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA }) @Consumes({ MediaType.MULTIPART_FORM_DATA })
@ApiAsyncType(Playlist.class) @ApiAsyncType(Playlist.class)
public void uploadCover(@PathParam("id") final Long id, @FormDataParam("file") final InputStream fileInputStream, @FormDataParam("file") final FormDataContentDisposition fileMetaData) public void uploadCover(@PathParam("oid") final ObjectId oid, @FormDataParam("file") final InputStream fileInputStream, @FormDataParam("file") final FormDataContentDisposition fileMetaData)
throws Exception { throws Exception {
try (DBAccess db = DBAccess.createInterface()) { try (DBAccess db = DBAccess.createInterface()) {
DataTools.uploadCover(db, Playlist.class, id, fileInputStream, fileMetaData); DataTools.uploadCover(db, Playlist.class, oid, fileInputStream, fileMetaData);
} }
} }
@DELETE @DELETE
@Path("{id}/cover/{coverId}") @Path("{oid}/cover/{coverId}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
public Playlist removeCover(@PathParam("id") final Long id, @PathParam("coverId") final ObjectId coverId) throws Exception { public Playlist removeCover(@PathParam("oid") final ObjectId oid, @PathParam("coverId") final ObjectId coverId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) { try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Playlist.class, "id", id, "covers", coverId); AddOnDataJson.removeLink(db, Playlist.class, "id", oid, "covers", coverId);
return DataAccess.get(Playlist.class, id); return DataAccess.get(Playlist.class, oid);
} }
} }
} }

View File

@ -40,10 +40,10 @@ public class TrackResource {
private static final Logger LOGGER = LoggerFactory.getLogger(TrackResource.class); private static final Logger LOGGER = LoggerFactory.getLogger(TrackResource.class);
@GET @GET
@Path("{id}") @Path("{oid}")
@RolesAllowed("USER") @RolesAllowed("USER")
public Track get(@PathParam("id") final Long id) throws Exception { public Track get(@PathParam("oid") final ObjectId oid) throws Exception {
return DataAccess.get(Track.class, id); return DataAccess.get(Track.class, oid);
} }
@GET @GET
@ -60,46 +60,46 @@ public class TrackResource {
} }
@PUT @PUT
@Path("{id}") @Path("{oid}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Track put(@PathParam("id") final Long id, @Valid final Track track) throws Exception { public Track put(@PathParam("oid") final ObjectId oid, @Valid final Track track) throws Exception {
track.id = id; track.oid = oid;
DataAccess.update(track, id); DataAccess.update(track, oid);
return DataAccess.get(Track.class, id); return DataAccess.get(Track.class, oid);
} }
@DELETE @DELETE
@Path("{id}") @Path("{oid}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
public void remove(@PathParam("id") final Long id) throws Exception { public void remove(@PathParam("oid") final ObjectId oid) throws Exception {
DataAccess.delete(Track.class, id); DataAccess.delete(Track.class, oid);
} }
@POST @POST
@Path("{id}/cover") @Path("{oid}/cover")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA }) @Consumes({ MediaType.MULTIPART_FORM_DATA })
@ApiTypeScriptProgress @ApiTypeScriptProgress
public Track uploadCover(@PathParam("id") final Long id, @FormDataParam("uri") final String uri, @FormDataParam("file") final InputStream fileInputStream, public Track uploadCover(@PathParam("oid") final ObjectId oid, @FormDataParam("uri") final String uri, @FormDataParam("file") final InputStream fileInputStream,
@FormDataParam("file") final FormDataContentDisposition fileMetaData) throws Exception { @FormDataParam("file") final FormDataContentDisposition fileMetaData) throws Exception {
try (DBAccess db = DBAccess.createInterface()) { try (DBAccess db = DBAccess.createInterface()) {
if (uri != null) { if (uri != null) {
DataTools.uploadCoverFromUri(db, Track.class, id, uri); DataTools.uploadCoverFromUri(db, Track.class, oid, uri);
} else { } else {
DataTools.uploadCover(db, Track.class, id, fileInputStream, fileMetaData); DataTools.uploadCover(db, Track.class, oid, fileInputStream, fileMetaData);
} }
return DataAccess.get(Track.class, id); return DataAccess.get(Track.class, oid);
} }
} }
@DELETE @DELETE
@Path("{id}/cover/{coverId}") @Path("{oid}/cover/{coverId}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
public Track removeCover(@PathParam("id") final Long id, @PathParam("coverId") final ObjectId coverId) throws Exception { public Track removeCover(@PathParam("oid") final ObjectId oid, @PathParam("coverId") final ObjectId coverId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) { try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Track.class, "id", id, "covers", coverId); AddOnDataJson.removeLink(db, Track.class, "_id", oid, "covers", coverId);
return db.get(Track.class, id); return db.get(Track.class, oid);
} }
} }
@ -111,9 +111,9 @@ public class TrackResource {
@ApiTypeScriptProgress @ApiTypeScriptProgress
public Response uploadTrack( // public Response uploadTrack( //
@FormDataParam("title") String title, // @FormDataParam("title") String title, //
@ApiInputOptional @ApiAsyncType(Long.class) @FormDataParam("genderId") String genderId, // @ApiInputOptional @ApiAsyncType(ObjectId.class) @FormDataParam("genderId") String genderId, //
@ApiInputOptional @ApiAsyncType(Long.class) @FormDataParam("artistId") String artistId, // @ApiInputOptional @ApiAsyncType(ObjectId.class) @FormDataParam("artistId") String artistId, //
@ApiInputOptional @ApiAsyncType(Long.class) @FormDataParam("albumId") String albumId, // @ApiInputOptional @ApiAsyncType(ObjectId.class) @FormDataParam("albumId") String albumId, //
@ApiInputOptional @ApiAsyncType(Long.class) @FormDataParam("trackId") String trackId, // @ApiInputOptional @ApiAsyncType(Long.class) @FormDataParam("trackId") String trackId, //
@FormDataParam("file") final InputStream fileInputStream, // @FormDataParam("file") final InputStream fileInputStream, //
@FormDataParam("file") final FormDataContentDisposition fileMetaData // @FormDataParam("file") final FormDataContentDisposition fileMetaData //
@ -166,13 +166,13 @@ public class TrackResource {
Track trackElem = new Track(); Track trackElem = new Track();
trackElem.name = title; trackElem.name = title;
trackElem.track = trackId != null ? Long.parseLong(trackId) : null; trackElem.track = trackId != null ? Long.parseLong(trackId) : null;
trackElem.albumId = albumId != null ? Long.parseLong(albumId) : null; trackElem.albumId = albumId != null ? new ObjectId(albumId) : null;
trackElem.genderId = genderId != null ? Long.parseLong(genderId) : null; trackElem.genderId = genderId != null ? new ObjectId(genderId) : null;
trackElem.dataId = data.oid; trackElem.dataId = data.oid;
// Now list of artist has an internal management: // Now list of artist has an internal management:
if (artistId != null) { if (artistId != null) {
trackElem.artists = new ArrayList<>(); trackElem.artists = new ArrayList<>();
trackElem.artists.add(artistId != null ? Long.parseLong(artistId) : null); trackElem.artists.add(artistId != null ? new ObjectId(artistId) : null);
} }
// TODO: maybe validate here .... // TODO: maybe validate here ....

View File

@ -56,56 +56,36 @@ public class Initialization extends MigrationSqlStep {
for (final Class<?> clazz : CLASSES_BASE) { for (final Class<?> clazz : CLASSES_BASE) {
addClass(clazz); addClass(clazz);
} }
addAction((final DBAccess da) -> { addAction((final DBAccess da) -> {
final List<Gender> data = List.of(// final List<Gender> data = List.of(//
new Gender(1L, "Variété française"), // new Gender("Variété française"), //
new Gender(2L, "Pop"), // new Gender("Pop"), //
new Gender(3L, "inconnue"), // new Gender("inconnue"), //
new Gender(4L, "Disco"), // new Gender("Disco"), //
new Gender(5L, "Enfants"), // new Gender("Enfants"), //
new Gender(6L, "Portugaise"), // new Gender("Portugaise"), //
new Gender(7L, "Apprentissage"), // new Gender("Apprentissage"), //
new Gender(8L, "Blues"), // new Gender("Blues"), //
new Gender(9L, "Jazz"), // new Gender("Jazz"), //
new Gender(10L, "Chanson Noël"), // new Gender("Chanson Noël"), //
new Gender(11L, "DubStep"), // new Gender("DubStep"), //
new Gender(12L, "Rap français"), // new Gender("Rap français"), //
new Gender(13L, "Classique"), // new Gender("Classique"), //
new Gender(14L, "Rock"), // new Gender("Rock"), //
new Gender(15L, "Electro"), // new Gender("Electro"), //
new Gender(16L, "Celtique"), // new Gender("Celtique"), //
new Gender(17L, "Country"), // new Gender("Country"), //
new Gender(18L, "Variété Québéquoise"), // new Gender("Variété Québéquoise"), //
new Gender(19L, "Médiéval"), // new Gender("Médiéval"), //
new Gender(20L, "Variété Italienne"), // new Gender("Variété Italienne"), //
new Gender(21L, "Comédie Musicale"), // new Gender("Comédie Musicale"), //
new Gender(22L, "Vianney"), // new Gender("Vianney"), //
new Gender(23L, "Bande Original"), // new Gender("Bande Original"), //
new Gender(24L, "Bande Originale"), // new Gender("Bande Originale"), //
new Gender(25L, "Variété Belge"), // new Gender("Variété Belge"), //
new Gender(26L, "Gospel")); new Gender("Gospel"));
da.insertMultiple(data); da.insertMultiple(data);
}); });
// set start increment element to permit to add after default elements
addAction("""
ALTER TABLE `album` AUTO_INCREMENT = 1000;
""", "mysql");
addAction("""
ALTER TABLE `artist` AUTO_INCREMENT = 1000;
""", "mysql");
addAction("""
ALTER TABLE `gender` AUTO_INCREMENT = 1000;
""", "mysql");
addAction("""
ALTER TABLE `playlist` AUTO_INCREMENT = 1000;
""", "mysql");
addAction("""
ALTER TABLE `track` AUTO_INCREMENT = 1000;
""", "mysql");
addAction("""
ALTER TABLE `user` AUTO_INCREMENT = 1000;
""", "mysql");
} }
public static void dropAll(final DBAccess da) { public static void dropAll(final DBAccess da) {

View File

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

View File

@ -4,13 +4,12 @@ import java.util.Date;
import java.util.List; import java.util.List;
import org.atriasoft.archidata.annotation.DataIfNotExists; 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.ApiAccessLimitation;
import org.atriasoft.archidata.annotation.apiGenerator.ApiGenerationMode; import org.atriasoft.archidata.annotation.apiGenerator.ApiGenerationMode;
import org.atriasoft.archidata.annotation.checker.CheckForeignKey; import org.atriasoft.archidata.annotation.checker.CheckForeignKey;
import org.atriasoft.archidata.annotation.checker.CollectionNotEmpty; import org.atriasoft.archidata.annotation.checker.CollectionNotEmpty;
import org.atriasoft.archidata.model.Data; import org.atriasoft.archidata.model.Data;
import org.atriasoft.archidata.model.GenericDataSoftDelete; import org.atriasoft.archidata.model.OIDGenericDataSoftDelete;
import org.bson.types.ObjectId; import org.bson.types.ObjectId;
import org.hibernate.validator.constraints.UniqueElements; import org.hibernate.validator.constraints.UniqueElements;
@ -20,16 +19,14 @@ 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.Table;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
@Entity("Album") @Entity()
@Table(name = "album")
@DataIfNotExists @DataIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
@ApiGenerationMode(create = true, update = true) @ApiGenerationMode(create = true, update = true)
public class Album extends GenericDataSoftDelete { public class Album extends OIDGenericDataSoftDelete {
@Column(length = 256) @Column(length = 256)
@Size(min = 1, max = 256) @Size(min = 1, max = 256)
public String name = null; public String name = null;
@ -37,7 +34,6 @@ public class Album extends GenericDataSoftDelete {
@Size(min = 0, max = 8192) @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()
@Nullable @Nullable
@CollectionNotEmpty @CollectionNotEmpty
@UniqueElements @UniqueElements

View File

@ -4,13 +4,12 @@ import java.util.Date;
import java.util.List; import java.util.List;
import org.atriasoft.archidata.annotation.DataIfNotExists; 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.ApiAccessLimitation;
import org.atriasoft.archidata.annotation.apiGenerator.ApiGenerationMode; import org.atriasoft.archidata.annotation.apiGenerator.ApiGenerationMode;
import org.atriasoft.archidata.annotation.checker.CheckForeignKey; import org.atriasoft.archidata.annotation.checker.CheckForeignKey;
import org.atriasoft.archidata.annotation.checker.CollectionNotEmpty; import org.atriasoft.archidata.annotation.checker.CollectionNotEmpty;
import org.atriasoft.archidata.model.Data; import org.atriasoft.archidata.model.Data;
import org.atriasoft.archidata.model.GenericDataSoftDelete; import org.atriasoft.archidata.model.OIDGenericDataSoftDelete;
import org.bson.types.ObjectId; import org.bson.types.ObjectId;
import org.hibernate.validator.constraints.UniqueElements; import org.hibernate.validator.constraints.UniqueElements;
@ -20,16 +19,14 @@ 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.Table;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
@Entity("Artist") @Entity()
@Table(name = "artist")
@DataIfNotExists @DataIfNotExists
@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 OIDGenericDataSoftDelete {
@Column(length = 256) @Column(length = 256)
@Size(min = 1, max = 256) @Size(min = 1, max = 256)
public String name = null; public String name = null;
@ -37,7 +34,6 @@ public class Artist extends GenericDataSoftDelete {
@Size(min = 0, max = 8192) @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()
@Nullable @Nullable
@CollectionNotEmpty @CollectionNotEmpty
@UniqueElements @UniqueElements
@ -54,7 +50,7 @@ public class Artist extends GenericDataSoftDelete {
@Override @Override
public String toString() { public String toString() {
return "Artist [id=" + this.id + ", name=" + this.name + ", description=" + this.description + ", covers=" + this.covers + ", firstName=" + this.firstName + ", surname=" + this.surname return "Artist [id=" + this.oid + ", name=" + this.name + ", description=" + this.description + ", covers=" + this.covers + ", firstName=" + this.firstName + ", surname=" + this.surname
+ ", birth=" + this.birth + ", death=" + this.death + "]"; + ", birth=" + this.birth + ", death=" + this.death + "]";
} }
} }

View File

@ -15,13 +15,12 @@ CREATE TABLE `node` (
import java.util.List; import java.util.List;
import org.atriasoft.archidata.annotation.DataIfNotExists; 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.ApiAccessLimitation;
import org.atriasoft.archidata.annotation.apiGenerator.ApiGenerationMode; import org.atriasoft.archidata.annotation.apiGenerator.ApiGenerationMode;
import org.atriasoft.archidata.annotation.checker.CheckForeignKey; import org.atriasoft.archidata.annotation.checker.CheckForeignKey;
import org.atriasoft.archidata.annotation.checker.CollectionNotEmpty; import org.atriasoft.archidata.annotation.checker.CollectionNotEmpty;
import org.atriasoft.archidata.model.Data; import org.atriasoft.archidata.model.Data;
import org.atriasoft.archidata.model.GenericDataSoftDelete; import org.atriasoft.archidata.model.OIDGenericDataSoftDelete;
import org.bson.types.ObjectId; import org.bson.types.ObjectId;
import org.hibernate.validator.constraints.UniqueElements; import org.hibernate.validator.constraints.UniqueElements;
@ -31,16 +30,14 @@ 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.Table;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
@Entity("Gender") @Entity()
@Table(name = "gender")
@DataIfNotExists @DataIfNotExists
@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 OIDGenericDataSoftDelete {
@Column(length = 256) @Column(length = 256)
@Size(min = 1, max = 256) @Size(min = 1, max = 256)
public String name = null; public String name = null;
@ -48,7 +45,6 @@ public class Gender extends GenericDataSoftDelete {
@Size(min = 0, max = 8192) @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()
@Nullable @Nullable
@CollectionNotEmpty @CollectionNotEmpty
@UniqueElements @UniqueElements
@ -57,8 +53,12 @@ public class Gender extends GenericDataSoftDelete {
public Gender() {} public Gender() {}
public Gender(final Long id, final String name) { public Gender(final String name) {
this.id = id; this.name = name;
}
public Gender(final ObjectId oid, final String name) {
this.oid = oid;
this.name = name; this.name = name;
} }

View File

@ -15,13 +15,12 @@ CREATE TABLE `node` (
import java.util.List; import java.util.List;
import org.atriasoft.archidata.annotation.DataIfNotExists; 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.ApiAccessLimitation;
import org.atriasoft.archidata.annotation.apiGenerator.ApiGenerationMode; import org.atriasoft.archidata.annotation.apiGenerator.ApiGenerationMode;
import org.atriasoft.archidata.annotation.checker.CheckForeignKey; import org.atriasoft.archidata.annotation.checker.CheckForeignKey;
import org.atriasoft.archidata.annotation.checker.CollectionNotEmpty; import org.atriasoft.archidata.annotation.checker.CollectionNotEmpty;
import org.atriasoft.archidata.model.Data; import org.atriasoft.archidata.model.Data;
import org.atriasoft.archidata.model.GenericDataSoftDelete; import org.atriasoft.archidata.model.OIDGenericDataSoftDelete;
import org.bson.types.ObjectId; import org.bson.types.ObjectId;
import org.hibernate.validator.constraints.UniqueElements; import org.hibernate.validator.constraints.UniqueElements;
@ -31,16 +30,14 @@ 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.Table;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
@Entity("Playlist") @Entity()
@Table(name = "playlist")
@DataIfNotExists @DataIfNotExists
@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 OIDGenericDataSoftDelete {
@Column(length = 256) @Column(length = 256)
@Size(min = 1, max = 256) @Size(min = 1, max = 256)
public String name = null; public String name = null;
@ -48,12 +45,10 @@ public class Playlist extends GenericDataSoftDelete {
@Size(min = 0, max = 8192) @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()
@Nullable @Nullable
@CollectionNotEmpty @CollectionNotEmpty
@UniqueElements @UniqueElements
@ApiAccessLimitation(readable = true, creatable = false, updatable = false) @ApiAccessLimitation(readable = true, creatable = false, updatable = false)
public List<@CheckForeignKey(target = Data.class) @NotNull ObjectId> covers = null; public List<@CheckForeignKey(target = Data.class) @NotNull ObjectId> covers = null;
@DataJson() public List<@CheckForeignKey(target = Track.class) @NotNull ObjectId> tracks = null;
public List<@CheckForeignKey(target = Track.class) @NotNull Long> tracks = null;
} }

View File

@ -15,13 +15,12 @@ CREATE TABLE `node` (
import java.util.List; import java.util.List;
import org.atriasoft.archidata.annotation.DataIfNotExists; 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.ApiAccessLimitation;
import org.atriasoft.archidata.annotation.apiGenerator.ApiGenerationMode; import org.atriasoft.archidata.annotation.apiGenerator.ApiGenerationMode;
import org.atriasoft.archidata.annotation.checker.CheckForeignKey; import org.atriasoft.archidata.annotation.checker.CheckForeignKey;
import org.atriasoft.archidata.annotation.checker.CollectionNotEmpty; import org.atriasoft.archidata.annotation.checker.CollectionNotEmpty;
import org.atriasoft.archidata.model.Data; import org.atriasoft.archidata.model.Data;
import org.atriasoft.archidata.model.GenericDataSoftDelete; import org.atriasoft.archidata.model.OIDGenericDataSoftDelete;
import org.bson.types.ObjectId; import org.bson.types.ObjectId;
import org.hibernate.validator.constraints.UniqueElements; import org.hibernate.validator.constraints.UniqueElements;
@ -31,17 +30,15 @@ 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.Table;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.PositiveOrZero; import jakarta.validation.constraints.PositiveOrZero;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
@Entity("Track") @Entity()
@Table(name = "track")
@DataIfNotExists @DataIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
@ApiGenerationMode(create = true, update = true) @ApiGenerationMode(create = true, update = true)
public class Track extends GenericDataSoftDelete { public class Track extends OIDGenericDataSoftDelete {
@Column(length = 256) @Column(length = 256)
@Size(min = 1, max = 256) @Size(min = 1, max = 256)
@ -50,28 +47,25 @@ public class Track extends GenericDataSoftDelete {
@Size(min = 0, max = 8192) @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()
@Nullable @Nullable
@CollectionNotEmpty @CollectionNotEmpty
@UniqueElements @UniqueElements
@ApiAccessLimitation(readable = true, creatable = false, updatable = false) @ApiAccessLimitation(readable = true, creatable = false, updatable = false)
public List<@CheckForeignKey(target = Data.class) @NotNull ObjectId> covers = null; public List<@CheckForeignKey(target = Data.class) @NotNull ObjectId> covers = null;
@CheckForeignKey(target = Gender.class) @CheckForeignKey(target = Gender.class)
public Long genderId = null; public ObjectId genderId = null;
@CheckForeignKey(target = Album.class) @CheckForeignKey(target = Album.class)
public Long albumId = null; public ObjectId albumId = null;
@PositiveOrZero @PositiveOrZero
public Long track = null; public Long track = null;
@CheckForeignKey(target = Data.class) @CheckForeignKey(target = Data.class)
public ObjectId dataId = null; public ObjectId dataId = null;
// @ManyToMany(fetch = FetchType.LAZY, targetEntity = Artist.class)
@DataJson
@Column(length = 0) @Column(length = 0)
public List<@CheckForeignKey(target = Artist.class) @NotNull Long> artists = null; public List<@CheckForeignKey(target = Artist.class) @NotNull ObjectId> artists = null;
@Override @Override
public String toString() { public String toString() {
return "Track [id=" + this.id + ", deleted=" + this.deleted + ", createdAt=" + this.createdAt + ", updatedAt=" + this.updatedAt + ", name=" + this.name + ", description=" + this.description return "Track [oid=" + this.oid + ", deleted=" + this.deleted + ", createdAt=" + this.createdAt + ", updatedAt=" + this.updatedAt + ", name=" + this.name + ", description=" + this.description
+ ", covers=" + this.covers + ", genderId=" + this.genderId + ", albumId=" + this.albumId + ", track=" + this.track + ", dataId=" + this.dataId + ", artists=" + this.artists + "]"; + ", covers=" + this.covers + ", genderId=" + this.genderId + ", albumId=" + this.albumId + ", track=" + this.track + ", dataId=" + this.dataId + ", artists=" + this.artists + "]";
} }
} }

View File

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

View File

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

View File

@ -0,0 +1,53 @@
package org.atriasoft.karusic.modelOld;
/*
CREATE TABLE `node` (
`id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY,
`deleted` BOOLEAN NOT NULL DEFAULT false,
`create_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been created',
`modify_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been update',
`type` enum("TYPE", "UNIVERS", "SERIE", "SAISON", "MEDIA") NOT NULL DEFAULT 'TYPE',
`name` TEXT COLLATE 'utf8_general_ci' NOT NULL,
`description` TEXT COLLATE 'utf8_general_ci',
`parent_id` bigint
) AUTO_INCREMENT=10;
*/
import java.util.List;
import org.atriasoft.archidata.annotation.DataJson;
import org.atriasoft.archidata.annotation.checker.CheckForeignKey;
import org.atriasoft.archidata.model.Data;
import org.atriasoft.archidata.model.GenericDataSoftDelete;
import org.bson.types.ObjectId;
import jakarta.persistence.Column;
import jakarta.persistence.Table;
import jakarta.validation.constraints.NotNull;
@Table(name = "gender")
public class GenderOld extends GenericDataSoftDelete {
@Column(length = 256)
public String name = null;
@Column(length = 0)
public String description = null;
@DataJson()
public List<@CheckForeignKey(target = Data.class) @NotNull ObjectId> covers = null;
public GenderOld() {}
public GenderOld(final String name) {
this.name = name;
}
public GenderOld(final Long id, final String name) {
this.id = id;
this.name = name;
}
@Column(nullable = true)
private final ObjectId oid = new ObjectId();
public ObjectId getOid() {
return this.oid;
}
}

View File

@ -0,0 +1,48 @@
package org.atriasoft.karusic.modelOld;
/*
CREATE TABLE `node` (
`id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY,
`deleted` BOOLEAN NOT NULL DEFAULT false,
`create_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been created',
`modify_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been update',
`type` enum("TYPE", "UNIVERS", "SERIE", "SAISON", "MEDIA") NOT NULL DEFAULT 'TYPE',
`name` TEXT COLLATE 'utf8_general_ci' NOT NULL,
`description` TEXT COLLATE 'utf8_general_ci',
`parent_id` bigint
) AUTO_INCREMENT=10;
*/
import java.util.List;
import org.atriasoft.archidata.annotation.DataJson;
import org.atriasoft.archidata.annotation.checker.CheckForeignKey;
import org.atriasoft.archidata.model.Data;
import org.atriasoft.archidata.model.GenericDataSoftDelete;
import org.bson.types.ObjectId;
import jakarta.persistence.Column;
import jakarta.persistence.Table;
import jakarta.validation.constraints.NotNull;
@Table(name = "track")
public class TrackOld extends GenericDataSoftDelete {
@Column(length = 256)
public String name = null;
@Column(length = 0)
public String description = null;
@DataJson()
public List<@CheckForeignKey(target = Data.class) @NotNull ObjectId> covers = null;
public Long genderId = null;
public Long albumId = null;
public Long track = null;
public ObjectId dataId = null;
@DataJson
public List<Long> artists = null;
@Column(nullable = true)
private final ObjectId oid = new ObjectId();
public ObjectId getOid() {
return this.oid;
}
}

View File

@ -1,19 +1,12 @@
package test.atriasoft.karusic; package test.atriasoft.karusic;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import org.atriasoft.archidata.dataAccess.DBAccess; import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.db.DbConfig; import org.atriasoft.archidata.db.DbConfig;
import org.atriasoft.archidata.db.DbIoFactory; import org.atriasoft.archidata.db.DbIoFactory;
import org.atriasoft.archidata.exception.DataAccessException; import org.atriasoft.archidata.exception.DataAccessException;
import org.atriasoft.archidata.tools.ConfigBaseVariable; 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.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -39,14 +32,6 @@ public class ConfigureDb {
ConfigBaseVariable.apiAdress = "http://127.0.0.1:12342/test/api/"; ConfigBaseVariable.apiAdress = "http://127.0.0.1:12342/test/api/";
// Enable the test mode permit to access to the test token (never use it in production). // Enable the test mode permit to access to the test token (never use it in production).
ConfigBaseVariable.testMode = "true"; ConfigBaseVariable.testMode = "true";
final List<Class<?>> listObject = List.of( //
Album.class, //
Artist.class, //
Gender.class, //
Playlist.class, //
Track.class, //
UserKarusic.class //
);
if ("SQLITE-MEMORY".equalsIgnoreCase(modeTest)) { if ("SQLITE-MEMORY".equalsIgnoreCase(modeTest)) {
ConfigBaseVariable.dbType = "sqlite"; ConfigBaseVariable.dbType = "sqlite";
ConfigBaseVariable.bdDatabase = null; ConfigBaseVariable.bdDatabase = null;

View File

@ -1,5 +1,9 @@
package test.atriasoft.karusic; package test.atriasoft.karusic;
import org.atriasoft.archidata.exception.RESTErrorResponseException;
import org.atriasoft.archidata.tools.ConfigBaseVariable;
import org.atriasoft.archidata.tools.RESTApi;
import org.atriasoft.karusic.api.HealthCheck.HealthResult;
import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
@ -8,10 +12,6 @@ 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.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.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -46,14 +46,14 @@ public class TestHealthCheck {
@Order(1) @Order(1)
@Test @Test
public void checkHealthCheck() throws Exception { public void checkHealthCheck() throws Exception {
final HealthResult result = api.get(HealthResult.class, "health_check"); final HealthResult result = api.request("health_check").get().fetch(HealthResult.class);
Assertions.assertEquals(result.value(), "alive and kicking"); Assertions.assertEquals(result.value(), "alive and kicking");
} }
@Order(2) @Order(2)
@Test @Test
public void checkHealthCheckWrongAPI() throws Exception { public void checkHealthCheckWrongAPI() throws Exception {
Assertions.assertThrows(RESTErrorResponseException.class, () -> api.get(HealthResult.class, "health_checks")); Assertions.assertThrows(RESTErrorResponseException.class, () -> api.request("health_check_kaboom").get().fetch());
} }
} }

View File

@ -7,6 +7,9 @@ import java.nio.file.Files;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.atriasoft.archidata.tools.ConfigBaseVariable;
import org.atriasoft.archidata.tools.RESTApi;
import org.atriasoft.karusic.model.Track;
import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
@ -15,9 +18,6 @@ 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.atriasoft.archidata.tools.ConfigBaseVariable;
import org.atriasoft.archidata.tools.RESTApi;
import org.atriasoft.karusic.model.Track;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -25,8 +25,8 @@ import org.slf4j.LoggerFactory;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class TestTrack { public class TestTrack {
private final static Logger LOGGER = LoggerFactory.getLogger(TestTrack.class); private final static Logger LOGGER = LoggerFactory.getLogger(TestTrack.class);
public final static String ENDPOINT_NAME = "track/"; public final static String ENDPOINT_NAME = "track";
public final static String ENDPOINT_DATA_NAME = "data/"; public final static String ENDPOINT_DATA_NAME = "data";
static WebLauncherTest webInterface = null; static WebLauncherTest webInterface = null;
static RESTApi api = null; static RESTApi api = null;
@ -89,11 +89,11 @@ public class TestTrack {
multipart.put("trackId", 9); multipart.put("trackId", 9);
multipart.put("file", dataToUpload); multipart.put("file", dataToUpload);
final Track inserted = api.postMultipart(Track.class, TestTrack.ENDPOINT_NAME + "upload", multipart); final Track inserted = api.request(TestTrack.ENDPOINT_NAME, "upload").post().bodyMultipart(multipart).fetch(Track.class);
Assertions.assertNotNull(inserted); Assertions.assertNotNull(inserted);
Assertions.assertNotNull(inserted.id); Assertions.assertNotNull(inserted.oid);
Assertions.assertTrue(inserted.id >= 0); // Assertions.assertTrue(inserted.oid >= 0);
Assertions.assertNull(inserted.updatedAt); Assertions.assertNull(inserted.updatedAt);
Assertions.assertNull(inserted.createdAt); Assertions.assertNull(inserted.createdAt);
Assertions.assertNull(inserted.deleted); Assertions.assertNull(inserted.deleted);
@ -102,8 +102,7 @@ public class TestTrack {
Assertions.assertNotNull(inserted.dataId); Assertions.assertNotNull(inserted.dataId);
// Retrieve Data: // Retrieve Data:
final HttpResponse<byte[]> retreiveData = api.getRaw(TestTrack.ENDPOINT_DATA_NAME + inserted.dataId); final HttpResponse<byte[]> retreiveData = api.request(TestTrack.ENDPOINT_DATA_NAME, inserted.dataId.toString()).get().fetchByte();
Assertions.assertNotNull(retreiveData); Assertions.assertNotNull(retreiveData);
Assertions.assertEquals(200, retreiveData.statusCode()); Assertions.assertEquals(200, retreiveData.statusCode());
Assertions.assertEquals("11999", retreiveData.headers().firstValue("content-length").orElse(null)); Assertions.assertEquals("11999", retreiveData.headers().firstValue("content-length").orElse(null));

1
front/.env Normal file
View File

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

10637
front/config sample.yaml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -29,11 +29,11 @@
"*.{ts,tsx,js,jsx,json}": "prettier --write" "*.{ts,tsx,js,jsx,json}": "prettier --write"
}, },
"dependencies": { "dependencies": {
"react-speech-recognition": "4.0.0", "react-speech-recognition": "4.0.1",
"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.16.0", "@chakra-ui/cli": "3.17.0",
"@chakra-ui/react": "3.16.0", "@chakra-ui/react": "3.17.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",
@ -44,15 +44,15 @@
"react-dom": "19.1.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.5.0", "react-router-dom": "7.5.3",
"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.3",
"zustand": "5.0.3" "zustand": "5.0.3"
}, },
"devDependencies": { "devDependencies": {
"@chakra-ui/styled-system": "^2.12.0", "@chakra-ui/styled-system": "^2.12.0",
"@playwright/test": "1.51.1", "@playwright/test": "1.52.0",
"@storybook/addon-actions": "8.6.12", "@storybook/addon-actions": "8.6.12",
"@storybook/addon-essentials": "8.6.12", "@storybook/addon-essentials": "8.6.12",
"@storybook/addon-links": "8.6.12", "@storybook/addon-links": "8.6.12",
@ -65,29 +65,29 @@
"@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.14.1", "@types/node": "22.15.3",
"@types/react": "19.1.1", "@types/react": "19.1.2",
"@types/react-dom": "19.1.2", "@types/react-dom": "19.1.3",
"@typescript-eslint/eslint-plugin": "8.30.0", "@typescript-eslint/eslint-plugin": "8.31.1",
"@typescript-eslint/parser": "8.30.0", "@typescript-eslint/parser": "8.31.1",
"@vitejs/plugin-react": "4.3.4", "@vitejs/plugin-react": "4.4.1",
"eslint": "9.24.0", "eslint": "9.25.1",
"eslint-plugin-import": "2.31.0", "eslint-plugin-import": "2.31.0",
"eslint-plugin-react": "7.37.5", "eslint-plugin-react": "7.37.5",
"eslint-plugin-react-hooks": "5.2.0", "eslint-plugin-react-hooks": "5.2.0",
"eslint-plugin-storybook": "0.12.0", "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.50.3", "knip": "5.52.0",
"lint-staged": "15.5.1", "lint-staged": "15.5.1",
"npm-check-updates": "^17.1.18", "npm-check-updates": "^18.0.1",
"prettier": "3.5.3", "prettier": "3.5.3",
"puppeteer": "24.6.1", "puppeteer": "24.7.2",
"react-is": "19.1.0", "react-is": "19.1.0",
"storybook": "8.6.12", "storybook": "8.6.12",
"ts-node": "10.9.2", "ts-node": "10.9.2",
"typescript": "5.8.3", "typescript": "5.8.3",
"vite": "6.2.6", "vite": "6.3.4",
"vitest": "3.1.1" "vitest": "3.1.2"
} }
} }

2247
front/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -15,7 +15,6 @@ import {
Album, Album,
AlbumCreate, AlbumCreate,
AlbumUpdate, AlbumUpdate,
Long,
ObjectId, ObjectId,
ZodAlbum, ZodAlbum,
isAlbum, isAlbum,
@ -32,12 +31,12 @@ export namespace AlbumResource {
}: { }: {
restConfig: RESTConfig, restConfig: RESTConfig,
params: { params: {
id: Long, oid: ObjectId,
}, },
}): Promise<Album> { }): Promise<Album> {
return RESTRequestJson({ return RESTRequestJson({
restModel: { restModel: {
endPoint: "/album/{id}", endPoint: "/album/{oid}",
requestType: HTTPRequestModel.GET, requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON, accept: HTTPMimeType.JSON,
}, },
@ -107,13 +106,13 @@ export namespace AlbumResource {
}: { }: {
restConfig: RESTConfig, restConfig: RESTConfig,
params: { params: {
id: Long, oid: ObjectId,
}, },
data: AlbumUpdate, data: AlbumUpdate,
}): Promise<Album> { }): Promise<Album> {
return RESTRequestJson({ return RESTRequestJson({
restModel: { restModel: {
endPoint: "/album/{id}", endPoint: "/album/{oid}",
requestType: HTTPRequestModel.PUT, requestType: HTTPRequestModel.PUT,
contentType: HTTPMimeType.JSON, contentType: HTTPMimeType.JSON,
accept: HTTPMimeType.JSON, accept: HTTPMimeType.JSON,
@ -132,12 +131,12 @@ export namespace AlbumResource {
}: { }: {
restConfig: RESTConfig, restConfig: RESTConfig,
params: { params: {
id: Long, oid: ObjectId,
}, },
}): Promise<void> { }): Promise<void> {
return RESTRequestVoid({ return RESTRequestVoid({
restModel: { restModel: {
endPoint: "/album/{id}", endPoint: "/album/{oid}",
requestType: HTTPRequestModel.DELETE, requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN, contentType: HTTPMimeType.TEXT_PLAIN,
}, },
@ -155,12 +154,12 @@ export namespace AlbumResource {
restConfig: RESTConfig, restConfig: RESTConfig,
params: { params: {
coverId: ObjectId, coverId: ObjectId,
id: Long, oid: ObjectId,
}, },
}): Promise<Album> { }): Promise<Album> {
return RESTRequestJson({ return RESTRequestJson({
restModel: { restModel: {
endPoint: "/album/{id}/cover/{coverId}", endPoint: "/album/{oid}/cover/{coverId}",
requestType: HTTPRequestModel.DELETE, requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN, contentType: HTTPMimeType.TEXT_PLAIN,
accept: HTTPMimeType.JSON, accept: HTTPMimeType.JSON,
@ -180,7 +179,7 @@ export namespace AlbumResource {
}: { }: {
restConfig: RESTConfig, restConfig: RESTConfig,
params: { params: {
id: Long, oid: ObjectId,
}, },
data: { data: {
file?: File, file?: File,
@ -190,7 +189,7 @@ export namespace AlbumResource {
}): Promise<Album> { }): Promise<Album> {
return RESTRequestJson({ return RESTRequestJson({
restModel: { restModel: {
endPoint: "/album/{id}/cover", endPoint: "/album/{oid}/cover",
requestType: HTTPRequestModel.POST, requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART, contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON, accept: HTTPMimeType.JSON,

View File

@ -15,7 +15,6 @@ import {
Artist, Artist,
ArtistCreate, ArtistCreate,
ArtistUpdate, ArtistUpdate,
Long,
ObjectId, ObjectId,
ZodArtist, ZodArtist,
isArtist, isArtist,
@ -29,12 +28,12 @@ export namespace ArtistResource {
}: { }: {
restConfig: RESTConfig, restConfig: RESTConfig,
params: { params: {
id: Long, oid: ObjectId,
}, },
}): Promise<Artist> { }): Promise<Artist> {
return RESTRequestJson({ return RESTRequestJson({
restModel: { restModel: {
endPoint: "/artist/{id}", endPoint: "/artist/{oid}",
requestType: HTTPRequestModel.GET, requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON, accept: HTTPMimeType.JSON,
}, },
@ -95,13 +94,13 @@ export namespace ArtistResource {
}: { }: {
restConfig: RESTConfig, restConfig: RESTConfig,
params: { params: {
id: Long, oid: ObjectId,
}, },
data: ArtistUpdate, data: ArtistUpdate,
}): Promise<Artist> { }): Promise<Artist> {
return RESTRequestJson({ return RESTRequestJson({
restModel: { restModel: {
endPoint: "/artist/{id}", endPoint: "/artist/{oid}",
requestType: HTTPRequestModel.PUT, requestType: HTTPRequestModel.PUT,
contentType: HTTPMimeType.JSON, contentType: HTTPMimeType.JSON,
accept: HTTPMimeType.JSON, accept: HTTPMimeType.JSON,
@ -117,12 +116,12 @@ export namespace ArtistResource {
}: { }: {
restConfig: RESTConfig, restConfig: RESTConfig,
params: { params: {
id: Long, oid: ObjectId,
}, },
}): Promise<void> { }): Promise<void> {
return RESTRequestVoid({ return RESTRequestVoid({
restModel: { restModel: {
endPoint: "/artist/{id}", endPoint: "/artist/{oid}",
requestType: HTTPRequestModel.DELETE, requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN, contentType: HTTPMimeType.TEXT_PLAIN,
}, },
@ -137,12 +136,12 @@ export namespace ArtistResource {
restConfig: RESTConfig, restConfig: RESTConfig,
params: { params: {
coverId: ObjectId, coverId: ObjectId,
id: Long, oid: ObjectId,
}, },
}): Promise<Artist> { }): Promise<Artist> {
return RESTRequestJson({ return RESTRequestJson({
restModel: { restModel: {
endPoint: "/artist/{id}/cover/{coverId}", endPoint: "/artist/{oid}/cover/{coverId}",
requestType: HTTPRequestModel.DELETE, requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN, contentType: HTTPMimeType.TEXT_PLAIN,
accept: HTTPMimeType.JSON, accept: HTTPMimeType.JSON,
@ -159,7 +158,7 @@ export namespace ArtistResource {
}: { }: {
restConfig: RESTConfig, restConfig: RESTConfig,
params: { params: {
id: Long, oid: ObjectId,
}, },
data: { data: {
file?: File, file?: File,
@ -169,7 +168,7 @@ export namespace ArtistResource {
}): Promise<Artist> { }): Promise<Artist> {
return RESTRequestJson({ return RESTRequestJson({
restModel: { restModel: {
endPoint: "/artist/{id}/cover", endPoint: "/artist/{oid}/cover",
requestType: HTTPRequestModel.POST, requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART, contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON, accept: HTTPMimeType.JSON,

View File

@ -15,7 +15,6 @@ import {
Gender, Gender,
GenderCreate, GenderCreate,
GenderUpdate, GenderUpdate,
Long,
ObjectId, ObjectId,
ZodGender, ZodGender,
isGender, isGender,
@ -29,12 +28,12 @@ export namespace GenderResource {
}: { }: {
restConfig: RESTConfig, restConfig: RESTConfig,
params: { params: {
id: Long, oid: ObjectId,
}, },
}): Promise<Gender> { }): Promise<Gender> {
return RESTRequestJson({ return RESTRequestJson({
restModel: { restModel: {
endPoint: "/gender/{id}", endPoint: "/gender/{oid}",
requestType: HTTPRequestModel.GET, requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON, accept: HTTPMimeType.JSON,
}, },
@ -77,13 +76,13 @@ export namespace GenderResource {
}: { }: {
restConfig: RESTConfig, restConfig: RESTConfig,
params: { params: {
id: Long, oid: ObjectId,
}, },
data: GenderUpdate, data: GenderUpdate,
}): Promise<Gender> { }): Promise<Gender> {
return RESTRequestJson({ return RESTRequestJson({
restModel: { restModel: {
endPoint: "/gender/{id}", endPoint: "/gender/{oid}",
requestType: HTTPRequestModel.PUT, requestType: HTTPRequestModel.PUT,
contentType: HTTPMimeType.JSON, contentType: HTTPMimeType.JSON,
accept: HTTPMimeType.JSON, accept: HTTPMimeType.JSON,
@ -117,12 +116,12 @@ export namespace GenderResource {
}: { }: {
restConfig: RESTConfig, restConfig: RESTConfig,
params: { params: {
id: Long, oid: ObjectId,
}, },
}): Promise<void> { }): Promise<void> {
return RESTRequestVoid({ return RESTRequestVoid({
restModel: { restModel: {
endPoint: "/gender/{id}", endPoint: "/gender/{oid}",
requestType: HTTPRequestModel.DELETE, requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN, contentType: HTTPMimeType.TEXT_PLAIN,
}, },
@ -137,12 +136,12 @@ export namespace GenderResource {
restConfig: RESTConfig, restConfig: RESTConfig,
params: { params: {
coverId: ObjectId, coverId: ObjectId,
id: Long, oid: ObjectId,
}, },
}): Promise<Gender> { }): Promise<Gender> {
return RESTRequestJson({ return RESTRequestJson({
restModel: { restModel: {
endPoint: "/gender/{id}/cover/{coverId}", endPoint: "/gender/{oid}/cover/{coverId}",
requestType: HTTPRequestModel.DELETE, requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN, contentType: HTTPMimeType.TEXT_PLAIN,
accept: HTTPMimeType.JSON, accept: HTTPMimeType.JSON,
@ -159,7 +158,7 @@ export namespace GenderResource {
}: { }: {
restConfig: RESTConfig, restConfig: RESTConfig,
params: { params: {
id: Long, oid: ObjectId,
}, },
data: { data: {
file?: File, file?: File,
@ -169,7 +168,7 @@ export namespace GenderResource {
}): Promise<Gender> { }): Promise<Gender> {
return RESTRequestJson({ return RESTRequestJson({
restModel: { restModel: {
endPoint: "/gender/{id}/cover", endPoint: "/gender/{oid}/cover",
requestType: HTTPRequestModel.POST, requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART, contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON, accept: HTTPMimeType.JSON,

View File

@ -11,7 +11,6 @@ import {
import { z as zod } from "zod" import { z as zod } from "zod"
import { import {
Long,
ObjectId, ObjectId,
Playlist, Playlist,
PlaylistCreate, PlaylistCreate,
@ -28,7 +27,7 @@ export namespace PlaylistResource {
}: { }: {
restConfig: RESTConfig, restConfig: RESTConfig,
params: { params: {
id: Long, id: ObjectId,
}, },
}): Promise<Playlist> { }): Promise<Playlist> {
return RESTRequestJson({ return RESTRequestJson({
@ -94,13 +93,13 @@ export namespace PlaylistResource {
}: { }: {
restConfig: RESTConfig, restConfig: RESTConfig,
params: { params: {
id: Long, oid: ObjectId,
}, },
data: PlaylistUpdate, data: PlaylistUpdate,
}): Promise<Playlist> { }): Promise<Playlist> {
return RESTRequestJson({ return RESTRequestJson({
restModel: { restModel: {
endPoint: "/playlist/{id}", endPoint: "/playlist/{oid}",
requestType: HTTPRequestModel.PUT, requestType: HTTPRequestModel.PUT,
contentType: HTTPMimeType.JSON, contentType: HTTPMimeType.JSON,
accept: HTTPMimeType.JSON, accept: HTTPMimeType.JSON,
@ -116,12 +115,12 @@ export namespace PlaylistResource {
}: { }: {
restConfig: RESTConfig, restConfig: RESTConfig,
params: { params: {
id: Long, oid: ObjectId,
}, },
}): Promise<void> { }): Promise<void> {
return RESTRequestVoid({ return RESTRequestVoid({
restModel: { restModel: {
endPoint: "/playlist/{id}", endPoint: "/playlist/{oid}",
requestType: HTTPRequestModel.DELETE, requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN, contentType: HTTPMimeType.TEXT_PLAIN,
}, },
@ -136,12 +135,12 @@ export namespace PlaylistResource {
restConfig: RESTConfig, restConfig: RESTConfig,
params: { params: {
coverId: ObjectId, coverId: ObjectId,
id: Long, oid: ObjectId,
}, },
}): Promise<Playlist> { }): Promise<Playlist> {
return RESTRequestJson({ return RESTRequestJson({
restModel: { restModel: {
endPoint: "/playlist/{id}/cover/{coverId}", endPoint: "/playlist/{oid}/cover/{coverId}",
requestType: HTTPRequestModel.DELETE, requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN, contentType: HTTPMimeType.TEXT_PLAIN,
accept: HTTPMimeType.JSON, accept: HTTPMimeType.JSON,
@ -157,7 +156,7 @@ export namespace PlaylistResource {
}: { }: {
restConfig: RESTConfig, restConfig: RESTConfig,
params: { params: {
id: Long, oid: ObjectId,
}, },
data: { data: {
file: File, file: File,
@ -165,7 +164,7 @@ export namespace PlaylistResource {
}): Promise<Playlist> { }): Promise<Playlist> {
return RESTRequestJson({ return RESTRequestJson({
restModel: { restModel: {
endPoint: "/playlist/{id}/cover", endPoint: "/playlist/{oid}/cover",
requestType: HTTPRequestModel.POST, requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART, contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON, accept: HTTPMimeType.JSON,

View File

@ -29,12 +29,12 @@ export namespace TrackResource {
}: { }: {
restConfig: RESTConfig, restConfig: RESTConfig,
params: { params: {
id: Long, oid: ObjectId,
}, },
}): Promise<Track> { }): Promise<Track> {
return RESTRequestJson({ return RESTRequestJson({
restModel: { restModel: {
endPoint: "/track/{id}", endPoint: "/track/{oid}",
requestType: HTTPRequestModel.GET, requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON, accept: HTTPMimeType.JSON,
}, },
@ -95,13 +95,13 @@ export namespace TrackResource {
}: { }: {
restConfig: RESTConfig, restConfig: RESTConfig,
params: { params: {
id: Long, oid: ObjectId,
}, },
data: TrackUpdate, data: TrackUpdate,
}): Promise<Track> { }): Promise<Track> {
return RESTRequestJson({ return RESTRequestJson({
restModel: { restModel: {
endPoint: "/track/{id}", endPoint: "/track/{oid}",
requestType: HTTPRequestModel.PUT, requestType: HTTPRequestModel.PUT,
contentType: HTTPMimeType.JSON, contentType: HTTPMimeType.JSON,
accept: HTTPMimeType.JSON, accept: HTTPMimeType.JSON,
@ -117,12 +117,12 @@ export namespace TrackResource {
}: { }: {
restConfig: RESTConfig, restConfig: RESTConfig,
params: { params: {
id: Long, oid: ObjectId,
}, },
}): Promise<void> { }): Promise<void> {
return RESTRequestVoid({ return RESTRequestVoid({
restModel: { restModel: {
endPoint: "/track/{id}", endPoint: "/track/{oid}",
requestType: HTTPRequestModel.DELETE, requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN, contentType: HTTPMimeType.TEXT_PLAIN,
}, },
@ -137,12 +137,12 @@ export namespace TrackResource {
restConfig: RESTConfig, restConfig: RESTConfig,
params: { params: {
coverId: ObjectId, coverId: ObjectId,
id: Long, oid: ObjectId,
}, },
}): Promise<Track> { }): Promise<Track> {
return RESTRequestJson({ return RESTRequestJson({
restModel: { restModel: {
endPoint: "/track/{id}/cover/{coverId}", endPoint: "/track/{oid}/cover/{coverId}",
requestType: HTTPRequestModel.DELETE, requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN, contentType: HTTPMimeType.TEXT_PLAIN,
accept: HTTPMimeType.JSON, accept: HTTPMimeType.JSON,
@ -159,7 +159,7 @@ export namespace TrackResource {
}: { }: {
restConfig: RESTConfig, restConfig: RESTConfig,
params: { params: {
id: Long, oid: ObjectId,
}, },
data: { data: {
file: File, file: File,
@ -169,7 +169,7 @@ export namespace TrackResource {
}): Promise<Track> { }): Promise<Track> {
return RESTRequestJson({ return RESTRequestJson({
restModel: { restModel: {
endPoint: "/track/{id}/cover", endPoint: "/track/{oid}/cover",
requestType: HTTPRequestModel.POST, requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART, contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON, accept: HTTPMimeType.JSON,
@ -189,9 +189,9 @@ export namespace TrackResource {
data: { data: {
file: File, file: File,
trackId?: Long, trackId?: Long,
genderId?: Long, genderId?: ObjectId,
albumId?: Long, albumId?: ObjectId,
artistId?: Long, artistId?: ObjectId,
title: string, title: string,
}, },
callbacks?: RESTCallbacks, callbacks?: RESTCallbacks,

View File

@ -5,9 +5,9 @@ import { z as zod } from "zod";
import {ZodIsoDate} from "./iso-date"; import {ZodIsoDate} from "./iso-date";
import {ZodObjectId} from "./object-id"; import {ZodObjectId} from "./object-id";
import {ZodGenericDataSoftDelete, ZodGenericDataSoftDeleteUpdate , ZodGenericDataSoftDeleteCreate } from "./generic-data-soft-delete"; import {ZodOIDGenericDataSoftDelete, ZodOIDGenericDataSoftDeleteUpdate , ZodOIDGenericDataSoftDeleteCreate } from "./oid-generic-data-soft-delete";
export const ZodAlbum = ZodGenericDataSoftDelete.extend({ export const ZodAlbum = ZodOIDGenericDataSoftDelete.extend({
name: zod.string().min(1).max(256).optional(), name: zod.string().min(1).max(256).optional(),
description: zod.string().max(8192).optional(), description: zod.string().max(8192).optional(),
/** /**
@ -29,7 +29,7 @@ export function isAlbum(data: any): data is Album {
return false; return false;
} }
} }
export const ZodAlbumUpdate = ZodGenericDataSoftDeleteUpdate.extend({ export const ZodAlbumUpdate = ZodOIDGenericDataSoftDeleteUpdate.extend({
name: zod.string().min(1).max(256).nullable().optional(), name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().max(8192).nullable().optional(), description: zod.string().max(8192).nullable().optional(),
publication: ZodIsoDate.nullable().optional(), publication: ZodIsoDate.nullable().optional(),
@ -47,7 +47,7 @@ export function isAlbumUpdate(data: any): data is AlbumUpdate {
return false; return false;
} }
} }
export const ZodAlbumCreate = ZodGenericDataSoftDeleteCreate.extend({ export const ZodAlbumCreate = ZodOIDGenericDataSoftDeleteCreate.extend({
name: zod.string().min(1).max(256).nullable().optional(), name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().max(8192).nullable().optional(), description: zod.string().max(8192).nullable().optional(),
publication: ZodIsoDate.nullable().optional(), publication: ZodIsoDate.nullable().optional(),

View File

@ -5,9 +5,9 @@ import { z as zod } from "zod";
import {ZodIsoDate} from "./iso-date"; import {ZodIsoDate} from "./iso-date";
import {ZodObjectId} from "./object-id"; import {ZodObjectId} from "./object-id";
import {ZodGenericDataSoftDelete, ZodGenericDataSoftDeleteUpdate , ZodGenericDataSoftDeleteCreate } from "./generic-data-soft-delete"; import {ZodOIDGenericDataSoftDelete, ZodOIDGenericDataSoftDeleteUpdate , ZodOIDGenericDataSoftDeleteCreate } from "./oid-generic-data-soft-delete";
export const ZodArtist = ZodGenericDataSoftDelete.extend({ export const ZodArtist = ZodOIDGenericDataSoftDelete.extend({
name: zod.string().min(1).max(256).optional(), name: zod.string().min(1).max(256).optional(),
description: zod.string().max(8192).optional(), description: zod.string().max(8192).optional(),
/** /**
@ -32,7 +32,7 @@ export function isArtist(data: any): data is Artist {
return false; return false;
} }
} }
export const ZodArtistUpdate = ZodGenericDataSoftDeleteUpdate.extend({ export const ZodArtistUpdate = ZodOIDGenericDataSoftDeleteUpdate.extend({
name: zod.string().min(1).max(256).nullable().optional(), name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().max(8192).nullable().optional(), description: zod.string().max(8192).nullable().optional(),
firstName: zod.string().min(1).max(256).nullable().optional(), firstName: zod.string().min(1).max(256).nullable().optional(),
@ -53,7 +53,7 @@ export function isArtistUpdate(data: any): data is ArtistUpdate {
return false; return false;
} }
} }
export const ZodArtistCreate = ZodGenericDataSoftDeleteCreate.extend({ export const ZodArtistCreate = ZodOIDGenericDataSoftDeleteCreate.extend({
name: zod.string().min(1).max(256).nullable().optional(), name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().max(8192).nullable().optional(), description: zod.string().max(8192).nullable().optional(),
firstName: zod.string().min(1).max(256).nullable().optional(), firstName: zod.string().min(1).max(256).nullable().optional(),

View File

@ -4,9 +4,9 @@
import { z as zod } from "zod"; import { z as zod } from "zod";
import {ZodObjectId} from "./object-id"; import {ZodObjectId} from "./object-id";
import {ZodGenericDataSoftDelete, ZodGenericDataSoftDeleteUpdate , ZodGenericDataSoftDeleteCreate } from "./generic-data-soft-delete"; import {ZodOIDGenericDataSoftDelete, ZodOIDGenericDataSoftDeleteUpdate , ZodOIDGenericDataSoftDeleteCreate } from "./oid-generic-data-soft-delete";
export const ZodGender = ZodGenericDataSoftDelete.extend({ export const ZodGender = ZodOIDGenericDataSoftDelete.extend({
name: zod.string().min(1).max(256).optional(), name: zod.string().min(1).max(256).optional(),
description: zod.string().max(8192).optional(), description: zod.string().max(8192).optional(),
/** /**
@ -27,7 +27,7 @@ export function isGender(data: any): data is Gender {
return false; return false;
} }
} }
export const ZodGenderUpdate = ZodGenericDataSoftDeleteUpdate.extend({ export const ZodGenderUpdate = ZodOIDGenericDataSoftDeleteUpdate.extend({
name: zod.string().min(1).max(256).nullable().optional(), name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().max(8192).nullable().optional(), description: zod.string().max(8192).nullable().optional(),
@ -44,7 +44,7 @@ export function isGenderUpdate(data: any): data is GenderUpdate {
return false; return false;
} }
} }
export const ZodGenderCreate = ZodGenericDataSoftDeleteCreate.extend({ export const ZodGenderCreate = ZodOIDGenericDataSoftDeleteCreate.extend({
name: zod.string().min(1).max(256).nullable().optional(), name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().max(8192).nullable().optional(), description: zod.string().max(8192).nullable().optional(),

View File

@ -15,6 +15,8 @@ export * from "./jwt-payload"
export * from "./jwt-token" export * from "./jwt-token"
export * from "./long" export * from "./long"
export * from "./object-id" export * from "./object-id"
export * from "./oid-generic-data"
export * from "./oid-generic-data-soft-delete"
export * from "./part-right" export * from "./part-right"
export * from "./part-right" export * from "./part-right"
export * from "./playlist" export * from "./playlist"
@ -25,4 +27,3 @@ export * from "./track"
export * from "./user" export * from "./user"
export * from "./user-karusic" export * from "./user-karusic"
export * from "./user-me" export * from "./user-me"
export * from "./uuid"

View File

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

View File

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

View File

@ -0,0 +1,53 @@
/**
* Interface of the server (auto-generated code)
*/
import { z as zod } from "zod";
import {ZodGenericTiming, ZodGenericTimingUpdate , ZodGenericTimingCreate } from "./generic-timing";
import {ZodObjectId} from "./object-id";
export const ZodOIDGenericData = ZodGenericTiming.extend({
/**
* Unique ObjectID of the object
*/
oid: ZodObjectId.readonly(),
});
export type OIDGenericData = zod.infer<typeof ZodOIDGenericData>;
export function isOIDGenericData(data: any): data is OIDGenericData {
try {
ZodOIDGenericData.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodOIDGenericData' error=${e}`);
return false;
}
}
export const ZodOIDGenericDataUpdate = ZodGenericTimingUpdate;
export type OIDGenericDataUpdate = zod.infer<typeof ZodOIDGenericDataUpdate>;
export function isOIDGenericDataUpdate(data: any): data is OIDGenericDataUpdate {
try {
ZodOIDGenericDataUpdate.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodOIDGenericDataUpdate' error=${e}`);
return false;
}
}
export const ZodOIDGenericDataCreate = ZodGenericTimingCreate;
export type OIDGenericDataCreate = zod.infer<typeof ZodOIDGenericDataCreate>;
export function isOIDGenericDataCreate(data: any): data is OIDGenericDataCreate {
try {
ZodOIDGenericDataCreate.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodOIDGenericDataCreate' error=${e}`);
return false;
}
}

View File

@ -3,18 +3,17 @@
*/ */
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 {ZodOIDGenericDataSoftDelete, ZodOIDGenericDataSoftDeleteUpdate , ZodOIDGenericDataSoftDeleteCreate } from "./oid-generic-data-soft-delete";
export const ZodPlaylist = ZodGenericDataSoftDelete.extend({ export const ZodPlaylist = ZodOIDGenericDataSoftDelete.extend({
name: zod.string().min(1).max(256).optional(), name: zod.string().min(1).max(256).optional(),
description: zod.string().max(8192).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).readonly().optional(), covers: zod.array(ZodObjectId).readonly().optional(),
tracks: zod.array(ZodLong), tracks: zod.array(ZodObjectId).optional(),
}); });
@ -29,10 +28,10 @@ export function isPlaylist(data: any): data is Playlist {
return false; return false;
} }
} }
export const ZodPlaylistUpdate = ZodGenericDataSoftDeleteUpdate.extend({ export const ZodPlaylistUpdate = ZodOIDGenericDataSoftDeleteUpdate.extend({
name: zod.string().min(1).max(256).nullable().optional(), name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().max(8192).nullable().optional(), description: zod.string().max(8192).nullable().optional(),
tracks: zod.array(ZodLong), tracks: zod.array(ZodObjectId).nullable().optional(),
}); });
@ -47,10 +46,10 @@ export function isPlaylistUpdate(data: any): data is PlaylistUpdate {
return false; return false;
} }
} }
export const ZodPlaylistCreate = ZodGenericDataSoftDeleteCreate.extend({ export const ZodPlaylistCreate = ZodOIDGenericDataSoftDeleteCreate.extend({
name: zod.string().min(1).max(256).nullable().optional(), name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().max(8192).nullable().optional(), description: zod.string().max(8192).nullable().optional(),
tracks: zod.array(ZodLong), tracks: zod.array(ZodObjectId).nullable().optional(),
}); });

View File

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

View File

@ -5,20 +5,20 @@ import { z as zod } from "zod";
import {ZodLong} from "./long"; import {ZodLong} from "./long";
import {ZodObjectId} from "./object-id"; import {ZodObjectId} from "./object-id";
import {ZodGenericDataSoftDelete, ZodGenericDataSoftDeleteUpdate , ZodGenericDataSoftDeleteCreate } from "./generic-data-soft-delete"; import {ZodOIDGenericDataSoftDelete, ZodOIDGenericDataSoftDeleteUpdate , ZodOIDGenericDataSoftDeleteCreate } from "./oid-generic-data-soft-delete";
export const ZodTrack = ZodGenericDataSoftDelete.extend({ export const ZodTrack = ZodOIDGenericDataSoftDelete.extend({
name: zod.string().min(1).max(256).optional(), name: zod.string().min(1).max(256).optional(),
description: zod.string().max(8192).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).readonly().optional(), covers: zod.array(ZodObjectId).readonly().optional(),
genderId: ZodLong.optional(), genderId: ZodObjectId.optional(),
albumId: ZodLong.optional(), albumId: ZodObjectId.optional(),
track: ZodLong.optional(), track: ZodLong.optional(),
dataId: ZodObjectId.optional(), dataId: ZodObjectId.optional(),
artists: zod.array(ZodLong), artists: zod.array(ZodObjectId).optional(),
}); });
@ -33,14 +33,14 @@ export function isTrack(data: any): data is Track {
return false; return false;
} }
} }
export const ZodTrackUpdate = ZodGenericDataSoftDeleteUpdate.extend({ export const ZodTrackUpdate = ZodOIDGenericDataSoftDeleteUpdate.extend({
name: zod.string().min(1).max(256).nullable().optional(), name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().max(8192).nullable().optional(), description: zod.string().max(8192).nullable().optional(),
genderId: ZodLong.nullable().optional(), genderId: ZodObjectId.nullable().optional(),
albumId: ZodLong.nullable().optional(), albumId: ZodObjectId.nullable().optional(),
track: ZodLong.nullable().optional(), track: ZodLong.nullable().optional(),
dataId: ZodObjectId.nullable().optional(), dataId: ZodObjectId.nullable().optional(),
artists: zod.array(ZodLong), artists: zod.array(ZodObjectId).nullable().optional(),
}); });
@ -55,14 +55,14 @@ export function isTrackUpdate(data: any): data is TrackUpdate {
return false; return false;
} }
} }
export const ZodTrackCreate = ZodGenericDataSoftDeleteCreate.extend({ export const ZodTrackCreate = ZodOIDGenericDataSoftDeleteCreate.extend({
name: zod.string().min(1).max(256).nullable().optional(), name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().max(8192).nullable().optional(), description: zod.string().max(8192).nullable().optional(),
genderId: ZodLong.nullable().optional(), genderId: ZodObjectId.nullable().optional(),
albumId: ZodLong.nullable().optional(), albumId: ZodObjectId.nullable().optional(),
track: ZodLong.nullable().optional(), track: ZodLong.nullable().optional(),
dataId: ZodObjectId.nullable().optional(), dataId: ZodObjectId.nullable().optional(),
artists: zod.array(ZodLong), artists: zod.array(ZodObjectId).nullable().optional(),
}); });

View File

@ -12,7 +12,7 @@ export const ZodUserMe = zod.object({
/** /**
* Map<EntityName, Map<PartName, Right>> * Map<EntityName, Map<PartName, Right>>
*/ */
rights: zod.record(zod.string(), zod.record(zod.string(), ZodPartRight)), rights: zod.record(zod.string(), zod.record(zod.string(), ZodPartRight)).optional(),
}); });

View File

@ -3,9 +3,9 @@
*/ */
import { z as zod } from "zod"; import { z as zod } from "zod";
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";
import {ZodObjectId} from "./object-id";
import {ZodTimestamp} from "./timestamp";
export const ZodUser = ZodGenericDataSoftDelete.extend({ export const ZodUser = ZodGenericDataSoftDelete.extend({
login: zod.string().min(3).max(128), login: zod.string().min(3).max(128),
@ -15,7 +15,7 @@ export const ZodUser = ZodGenericDataSoftDelete.extend({
/** /**
* List of Id of the specific covers * List of Id of the specific covers
*/ */
covers: zod.array(ZodUUID).optional(), covers: zod.array(ZodObjectId).optional(),
}); });
@ -38,7 +38,7 @@ export const ZodUserUpdate = ZodGenericDataSoftDeleteUpdate.extend({
/** /**
* List of Id of the specific covers * List of Id of the specific covers
*/ */
covers: zod.array(ZodUUID).nullable().optional(), covers: zod.array(ZodObjectId).nullable().optional(),
}); });
@ -61,7 +61,7 @@ export const ZodUserCreate = ZodGenericDataSoftDeleteCreate.extend({
/** /**
* List of Id of the specific covers * List of Id of the specific covers
*/ */
covers: zod.array(ZodUUID).nullable().optional(), covers: zod.array(ZodObjectId).nullable().optional(),
}); });

View File

@ -10,7 +10,7 @@ export type DisplayAlbumProps = {
dataAlbum?: Album; dataAlbum?: Album;
}; };
export const DisplayAlbum = ({ dataAlbum }: DisplayAlbumProps) => { export const DisplayAlbum = ({ dataAlbum }: DisplayAlbumProps) => {
const { countTracksOfAnAlbum } = useCountTracksWithAlbumId(dataAlbum?.id); const { countTracksOfAnAlbum } = useCountTracksWithAlbumId(dataAlbum?.oid);
if (!dataAlbum) { if (!dataAlbum) {
return ( return (
<Flex direction="row" width="full" height="full"> <Flex direction="row" width="full" height="full">

View File

@ -1,10 +1,11 @@
import { ObjectId } from '@/back-api';
import { DisplayAlbum } from '@/components/album/DisplayAlbum'; import { DisplayAlbum } from '@/components/album/DisplayAlbum';
import { useSpecificAlbum } from '@/service/Album'; import { useSpecificAlbum } from '@/service/Album';
export type DisplayAlbumIdProps = { export type DisplayAlbumIdProps = {
id: number; oid: ObjectId;
}; };
export const DisplayAlbumId = ({ id }: DisplayAlbumIdProps) => { export const DisplayAlbumId = ({ oid }: DisplayAlbumIdProps) => {
const { dataAlbum } = useSpecificAlbum(id); const { dataAlbum } = useSpecificAlbum(oid);
return <DisplayAlbum dataAlbum={dataAlbum} data-testid="display-album-id" />; return <DisplayAlbum dataAlbum={dataAlbum} data-testid="display-album-id" />;
}; };

View File

@ -9,7 +9,7 @@ export type DisplayGenderProps = {
dataGender?: Gender; dataGender?: Gender;
}; };
export const DisplayGender = ({ dataGender }: DisplayGenderProps) => { export const DisplayGender = ({ dataGender }: DisplayGenderProps) => {
const { countTracksOnAGender } = useCountTracksOfAGender(dataGender?.id); const { countTracksOnAGender } = useCountTracksOfAGender(dataGender?.oid);
if (!dataGender) { if (!dataGender) {
return ( return (
<Flex direction="row" width="full" height="full"> <Flex direction="row" width="full" height="full">

View File

@ -1,8 +1,9 @@
import { ObjectId } from '@/back-api';
import { DisplayGender } from '@/components/gender/DisplayGender'; import { DisplayGender } from '@/components/gender/DisplayGender';
import { useSpecificGender } from '@/service/Gender'; import { useSpecificGender } from '@/service/Gender';
export type DisplayGenderIdProps = { export type DisplayGenderIdProps = {
id: number; id: ObjectId;
}; };
export const DisplayGenderId = ({ id }: DisplayGenderIdProps) => { export const DisplayGenderId = ({ id }: DisplayGenderIdProps) => {
const { dataGender } = useSpecificGender(id); const { dataGender } = useSpecificGender(id);

View File

@ -34,13 +34,10 @@ export type AlbumEditPopUpProps = {};
export const AlbumEditPopUp = ({}: AlbumEditPopUpProps) => { export const AlbumEditPopUp = ({}: AlbumEditPopUpProps) => {
const { albumId } = useParams(); const { albumId } = useParams();
const albumIdInt = isNullOrUndefined(albumId)
? undefined
: parseInt(albumId, 10);
const { session } = useServiceContext(); const { session } = useServiceContext();
const { countTracksOfAnAlbum } = useCountTracksWithAlbumId(albumIdInt); const { countTracksOfAnAlbum } = useCountTracksWithAlbumId(albumId);
const { store } = useAlbumService(); const { store } = useAlbumService();
const { dataAlbum } = useSpecificAlbum(albumIdInt); const { dataAlbum } = useSpecificAlbum(albumId);
const [admin, setAdmin] = useState(false); const [admin, setAdmin] = useState(false);
const navigate = useNavigate(); const navigate = useNavigate();
const disclosure = useDisclosure(); const disclosure = useDisclosure();
@ -48,15 +45,15 @@ export const AlbumEditPopUp = ({}: AlbumEditPopUpProps) => {
navigate('../../', { relative: 'path' }); navigate('../../', { relative: 'path' });
}; };
const onRemove = () => { const onRemove = () => {
if (isNullOrUndefined(albumIdInt)) { if (isNullOrUndefined(albumId)) {
return; return;
} }
store.remove( store.remove(
albumIdInt, albumId,
AlbumResource.remove({ AlbumResource.remove({
restConfig: session.getRestConfig(), restConfig: session.getRestConfig(),
params: { params: {
id: albumIdInt, oid: albumId,
}, },
}) })
); );
@ -69,7 +66,7 @@ export const AlbumEditPopUp = ({}: AlbumEditPopUpProps) => {
deltaConfig: { omit: ['covers'] }, deltaConfig: { omit: ['covers'] },
}); });
const onSave = async (delta: AlbumUpdate) => { const onSave = async (delta: AlbumUpdate) => {
if (isNullOrUndefined(albumIdInt)) { if (isNullOrUndefined(albumId)) {
return; return;
} }
console.log(`onSave = ${JSON.stringify(delta, null, 2)}`); console.log(`onSave = ${JSON.stringify(delta, null, 2)}`);
@ -78,14 +75,14 @@ export const AlbumEditPopUp = ({}: AlbumEditPopUpProps) => {
restConfig: session.getRestConfig(), restConfig: session.getRestConfig(),
data: ZodAlbumUpdate.parse(delta), data: ZodAlbumUpdate.parse(delta),
params: { params: {
id: albumIdInt, oid: albumId,
}, },
}) })
); );
}; };
const onUriSelected = (uri: string) => { const onUriSelected = (uri: string) => {
if (isNullOrUndefined(albumIdInt)) { if (isNullOrUndefined(albumId)) {
return; return;
} }
store.update( store.update(
@ -95,7 +92,7 @@ export const AlbumEditPopUp = ({}: AlbumEditPopUpProps) => {
uri: uri, uri: uri,
}, },
params: { params: {
id: albumIdInt, oid: albumId,
}, },
}) })
); );
@ -105,7 +102,7 @@ export const AlbumEditPopUp = ({}: AlbumEditPopUpProps) => {
files.forEach((element) => { files.forEach((element) => {
console.log(`Select file: '${element.name}'`); console.log(`Select file: '${element.name}'`);
}); });
if (isNullOrUndefined(albumIdInt)) { if (isNullOrUndefined(albumId)) {
return; return;
} }
store.update( store.update(
@ -115,7 +112,7 @@ export const AlbumEditPopUp = ({}: AlbumEditPopUpProps) => {
file: files[0], file: files[0],
}, },
params: { params: {
id: albumIdInt, oid: albumId,
}, },
}) })
); );
@ -124,14 +121,14 @@ export const AlbumEditPopUp = ({}: AlbumEditPopUpProps) => {
if (isNullOrUndefined(dataAlbum?.covers)) { if (isNullOrUndefined(dataAlbum?.covers)) {
return; return;
} }
if (isNullOrUndefined(albumIdInt)) { if (isNullOrUndefined(albumId)) {
return; return;
} }
store.update( store.update(
AlbumResource.removeCover({ AlbumResource.removeCover({
restConfig: session.getRestConfig(), restConfig: session.getRestConfig(),
params: { params: {
id: albumIdInt, oid: albumId,
coverId: dataAlbum.covers[index], coverId: dataAlbum.covers[index],
}, },
}) })
@ -155,7 +152,7 @@ export const AlbumEditPopUp = ({}: AlbumEditPopUpProps) => {
{admin && ( {admin && (
<> <>
<FormGroupShow isRequired label="Id"> <FormGroupShow isRequired label="Id">
<Text>{dataAlbum?.id}</Text> <Text>{dataAlbum?.oid}</Text>
</FormGroupShow> </FormGroupShow>
{countTracksOfAnAlbum !== 0 && ( {countTracksOfAnAlbum !== 0 && (
<Flex paddingLeft="14px"> <Flex paddingLeft="14px">
@ -179,7 +176,7 @@ export const AlbumEditPopUp = ({}: AlbumEditPopUpProps) => {
<ConfirmPopUp <ConfirmPopUp
disclosure={disclosure} disclosure={disclosure}
title="Remove album" title="Remove album"
body={`Remove Album [${dataAlbum?.id}] ${dataAlbum?.name}`} body={`Remove Album [${dataAlbum?.oid}] ${dataAlbum?.name}`}
confirmTitle="Remove" confirmTitle="Remove"
onConfirm={onRemove} onConfirm={onRemove}
/> />

View File

@ -33,13 +33,10 @@ export type ArtistEditPopUpProps = {};
export const ArtistEditPopUp = ({}: ArtistEditPopUpProps) => { export const ArtistEditPopUp = ({}: ArtistEditPopUpProps) => {
const { artistId } = useParams(); const { artistId } = useParams();
const artistIdInt = isNullOrUndefined(artistId)
? undefined
: parseInt(artistId, 10);
const { session } = useServiceContext(); const { session } = useServiceContext();
const { countTracksOnAnArtist } = useCountTracksOfAnArtist(artistIdInt); const { countTracksOnAnArtist } = useCountTracksOfAnArtist(artistId);
const { store } = useArtistService(); const { store } = useArtistService();
const { dataArtist } = useSpecificArtist(artistIdInt); const { dataArtist } = useSpecificArtist(artistId);
const [admin, setAdmin] = useState(false); const [admin, setAdmin] = useState(false);
const navigate = useNavigate(); const navigate = useNavigate();
const disclosure = useDisclosure(); const disclosure = useDisclosure();
@ -47,15 +44,15 @@ export const ArtistEditPopUp = ({}: ArtistEditPopUpProps) => {
navigate('../../', { relative: 'path' }); navigate('../../', { relative: 'path' });
}; };
const onRemove = () => { const onRemove = () => {
if (isNullOrUndefined(artistIdInt)) { if (isNullOrUndefined(artistId)) {
return; return;
} }
store.remove( store.remove(
artistIdInt, artistId,
ArtistResource.remove({ ArtistResource.remove({
restConfig: session.getRestConfig(), restConfig: session.getRestConfig(),
params: { params: {
id: artistIdInt, oid: artistId,
}, },
}) })
); );
@ -68,7 +65,7 @@ export const ArtistEditPopUp = ({}: ArtistEditPopUpProps) => {
deltaConfig: { omit: ['covers'] }, deltaConfig: { omit: ['covers'] },
}); });
const onSave = async (data: ArtistUpdate) => { const onSave = async (data: ArtistUpdate) => {
if (isNullOrUndefined(artistIdInt)) { if (isNullOrUndefined(artistId)) {
return; return;
} }
console.log(`onSave = ${JSON.stringify(data, null, 2)}`); console.log(`onSave = ${JSON.stringify(data, null, 2)}`);
@ -77,14 +74,14 @@ export const ArtistEditPopUp = ({}: ArtistEditPopUpProps) => {
restConfig: session.getRestConfig(), restConfig: session.getRestConfig(),
data: ZodArtistUpdate.parse(data), data: ZodArtistUpdate.parse(data),
params: { params: {
id: artistIdInt, oid: artistId,
}, },
}) })
); );
}; };
const onUriSelected = (uri: string) => { const onUriSelected = (uri: string) => {
if (isNullOrUndefined(artistIdInt)) { if (isNullOrUndefined(artistId)) {
return; return;
} }
store.update( store.update(
@ -94,7 +91,7 @@ export const ArtistEditPopUp = ({}: ArtistEditPopUpProps) => {
uri: uri, uri: uri,
}, },
params: { params: {
id: artistIdInt, oid: artistId,
}, },
}) })
); );
@ -103,7 +100,7 @@ export const ArtistEditPopUp = ({}: ArtistEditPopUpProps) => {
files.forEach((element) => { files.forEach((element) => {
console.log(`Select file: '${element.name}'`); console.log(`Select file: '${element.name}'`);
}); });
if (isNullOrUndefined(artistIdInt)) { if (isNullOrUndefined(artistId)) {
return; return;
} }
store.update( store.update(
@ -113,7 +110,7 @@ export const ArtistEditPopUp = ({}: ArtistEditPopUpProps) => {
file: files[0], file: files[0],
}, },
params: { params: {
id: artistIdInt, oid: artistId,
}, },
}) })
); );
@ -122,14 +119,14 @@ export const ArtistEditPopUp = ({}: ArtistEditPopUpProps) => {
if (isNullOrUndefined(dataArtist?.covers)) { if (isNullOrUndefined(dataArtist?.covers)) {
return; return;
} }
if (isNullOrUndefined(artistIdInt)) { if (isNullOrUndefined(artistId)) {
return; return;
} }
store.update( store.update(
ArtistResource.removeCover({ ArtistResource.removeCover({
restConfig: session.getRestConfig(), restConfig: session.getRestConfig(),
params: { params: {
id: artistIdInt, oid: artistId,
coverId: dataArtist.covers[index], coverId: dataArtist.covers[index],
}, },
}) })
@ -154,7 +151,7 @@ export const ArtistEditPopUp = ({}: ArtistEditPopUpProps) => {
{admin && ( {admin && (
<> <>
<FormGroupShow isRequired label="Id"> <FormGroupShow isRequired label="Id">
<Text>{dataArtist?.id}</Text> <Text>{dataArtist?.oid}</Text>
</FormGroupShow> </FormGroupShow>
{countTracksOnAnArtist !== 0 && ( {countTracksOnAnArtist !== 0 && (
<Flex paddingLeft="14px"> <Flex paddingLeft="14px">
@ -178,7 +175,7 @@ export const ArtistEditPopUp = ({}: ArtistEditPopUpProps) => {
<ConfirmPopUp <ConfirmPopUp
disclosure={disclosure} disclosure={disclosure}
title="Remove artist" title="Remove artist"
body={`Remove Artist [${dataArtist?.id}] ${dataArtist?.name}`} body={`Remove Artist [${dataArtist?.oid}] ${dataArtist?.name}`}
confirmTitle="Remove" confirmTitle="Remove"
onConfirm={onRemove} onConfirm={onRemove}
/> />

View File

@ -33,13 +33,10 @@ export type GenderEditPopUpProps = {};
export const GenderEditPopUp = ({}: GenderEditPopUpProps) => { export const GenderEditPopUp = ({}: GenderEditPopUpProps) => {
const { genderId } = useParams(); const { genderId } = useParams();
const genderIdInt = isNullOrUndefined(genderId)
? undefined
: parseInt(genderId, 10);
const { session } = useServiceContext(); const { session } = useServiceContext();
const { countTracksOnAGender } = useCountTracksOfAGender(genderIdInt); const { countTracksOnAGender } = useCountTracksOfAGender(genderId);
const { store } = useGenderService(); const { store } = useGenderService();
const { dataGender } = useSpecificGender(genderIdInt); const { dataGender } = useSpecificGender(genderId);
const [admin, setAdmin] = useState(false); const [admin, setAdmin] = useState(false);
const navigate = useNavigate(); const navigate = useNavigate();
const disclosure = useDisclosure(); const disclosure = useDisclosure();
@ -47,15 +44,15 @@ export const GenderEditPopUp = ({}: GenderEditPopUpProps) => {
navigate('../../', { relative: 'path' }); navigate('../../', { relative: 'path' });
}; };
const onRemove = () => { const onRemove = () => {
if (isNullOrUndefined(genderIdInt)) { if (isNullOrUndefined(genderId)) {
return; return;
} }
store.remove( store.remove(
genderIdInt, genderId,
GenderResource.remove({ GenderResource.remove({
restConfig: session.getRestConfig(), restConfig: session.getRestConfig(),
params: { params: {
id: genderIdInt, oid: genderId,
}, },
}) })
); );
@ -68,7 +65,7 @@ export const GenderEditPopUp = ({}: GenderEditPopUpProps) => {
deltaConfig: { omit: ['covers'] }, deltaConfig: { omit: ['covers'] },
}); });
const onSave = async (data: GenderUpdate) => { const onSave = async (data: GenderUpdate) => {
if (isNullOrUndefined(genderIdInt)) { if (isNullOrUndefined(genderId)) {
return; return;
} }
console.log(`onSave = ${JSON.stringify(data, null, 2)}`); console.log(`onSave = ${JSON.stringify(data, null, 2)}`);
@ -77,13 +74,13 @@ export const GenderEditPopUp = ({}: GenderEditPopUpProps) => {
restConfig: session.getRestConfig(), restConfig: session.getRestConfig(),
data: ZodGenderUpdate.parse(data), data: ZodGenderUpdate.parse(data),
params: { params: {
id: genderIdInt, oid: genderId,
}, },
}) })
); );
}; };
const onUriSelected = (uri: string) => { const onUriSelected = (uri: string) => {
if (isNullOrUndefined(genderIdInt)) { if (isNullOrUndefined(genderId)) {
return; return;
} }
store.update( store.update(
@ -93,7 +90,7 @@ export const GenderEditPopUp = ({}: GenderEditPopUpProps) => {
uri: uri, uri: uri,
}, },
params: { params: {
id: genderIdInt, oid: genderId,
}, },
}) })
); );
@ -102,7 +99,7 @@ export const GenderEditPopUp = ({}: GenderEditPopUpProps) => {
files.forEach((element) => { files.forEach((element) => {
console.log(`Select file: '${element.name}'`); console.log(`Select file: '${element.name}'`);
}); });
if (isNullOrUndefined(genderIdInt)) { if (isNullOrUndefined(genderId)) {
return; return;
} }
store.update( store.update(
@ -112,7 +109,7 @@ export const GenderEditPopUp = ({}: GenderEditPopUpProps) => {
file: files[0], file: files[0],
}, },
params: { params: {
id: genderIdInt, oid: genderId,
}, },
}) })
); );
@ -121,14 +118,14 @@ export const GenderEditPopUp = ({}: GenderEditPopUpProps) => {
if (isNullOrUndefined(dataGender?.covers)) { if (isNullOrUndefined(dataGender?.covers)) {
return; return;
} }
if (isNullOrUndefined(genderIdInt)) { if (isNullOrUndefined(genderId)) {
return; return;
} }
store.update( store.update(
GenderResource.removeCover({ GenderResource.removeCover({
restConfig: session.getRestConfig(), restConfig: session.getRestConfig(),
params: { params: {
id: genderIdInt, oid: genderId,
coverId: dataGender.covers[index], coverId: dataGender.covers[index],
}, },
}) })
@ -153,7 +150,7 @@ export const GenderEditPopUp = ({}: GenderEditPopUpProps) => {
{admin && ( {admin && (
<> <>
<FormGroupShow isRequired label="Id"> <FormGroupShow isRequired label="Id">
<Text>{dataGender?.id}</Text> <Text>{dataGender?.oid}</Text>
</FormGroupShow> </FormGroupShow>
{countTracksOnAGender !== 0 && ( {countTracksOnAGender !== 0 && (
<Flex paddingLeft="14px"> <Flex paddingLeft="14px">
@ -177,7 +174,7 @@ export const GenderEditPopUp = ({}: GenderEditPopUpProps) => {
<ConfirmPopUp <ConfirmPopUp
disclosure={disclosure} disclosure={disclosure}
title="Remove gender" title="Remove gender"
body={`Remove gender [${dataGender?.id}] ${dataGender?.name}`} body={`Remove gender [${dataGender?.oid}] ${dataGender?.name}`}
confirmTitle="Remove" confirmTitle="Remove"
onConfirm={onRemove} onConfirm={onRemove}
/> />

View File

@ -32,15 +32,12 @@ export type TrackEditPopUpProps = {};
export const TrackEditPopUp = ({}: TrackEditPopUpProps) => { export const TrackEditPopUp = ({}: TrackEditPopUpProps) => {
const { trackId } = useParams(); const { trackId } = useParams();
const trackIdInt = isNullOrUndefined(trackId)
? undefined
: parseInt(trackId, 10);
const { session } = useServiceContext(); const { session } = useServiceContext();
const { dataGenders } = useOrderedGenders(undefined); const { dataGenders } = useOrderedGenders(undefined);
const { dataArtist } = useOrderedArtists(undefined); const { dataArtist } = useOrderedArtists(undefined);
const { dataAlbums } = useOrderedAlbums(undefined); const { dataAlbums } = useOrderedAlbums(undefined);
const { store } = useTrackService(); const { store } = useTrackService();
const { dataTrack } = useSpecificTrack(trackIdInt); const { dataTrack } = useSpecificTrack(trackId);
const [admin, setAdmin] = useState(false); const [admin, setAdmin] = useState(false);
const navigate = useNavigate(); const navigate = useNavigate();
const disclosure = useDisclosure(); const disclosure = useDisclosure();
@ -48,15 +45,15 @@ export const TrackEditPopUp = ({}: TrackEditPopUpProps) => {
navigate('../../', { relative: 'path' }); navigate('../../', { relative: 'path' });
}; };
const onRemove = () => { const onRemove = () => {
if (isNullOrUndefined(trackIdInt)) { if (isNullOrUndefined(trackId)) {
return; return;
} }
store.remove( store.remove(
trackIdInt, trackId,
TrackResource.remove({ TrackResource.remove({
restConfig: session.getRestConfig(), restConfig: session.getRestConfig(),
params: { params: {
id: trackIdInt, oid: trackId,
}, },
}) })
); );
@ -69,7 +66,7 @@ export const TrackEditPopUp = ({}: TrackEditPopUpProps) => {
deltaConfig: { omit: ['covers'] }, deltaConfig: { omit: ['covers'] },
}); });
const onSave = async (data: TrackUpdate) => { const onSave = async (data: TrackUpdate) => {
if (isNullOrUndefined(trackIdInt)) { if (isNullOrUndefined(trackId)) {
return; return;
} }
console.log(`onSave = ${JSON.stringify(data, null, 2)}`); console.log(`onSave = ${JSON.stringify(data, null, 2)}`);
@ -83,7 +80,7 @@ export const TrackEditPopUp = ({}: TrackEditPopUpProps) => {
restConfig: session.getRestConfig(), restConfig: session.getRestConfig(),
data: ZodTrackUpdate.parse({ track: trackNumber, ...rest }), data: ZodTrackUpdate.parse({ track: trackNumber, ...rest }),
params: { params: {
id: trackIdInt, oid: trackId,
}, },
}) })
); );
@ -107,7 +104,7 @@ export const TrackEditPopUp = ({}: TrackEditPopUpProps) => {
{admin && ( {admin && (
<> <>
<FormGroupShow isRequired label="Id"> <FormGroupShow isRequired label="Id">
<Text>{dataTrack?.id}</Text> <Text>{dataTrack?.oid}</Text>
</FormGroupShow> </FormGroupShow>
<FormGroupShow label="Data Id"> <FormGroupShow label="Data Id">
<Text>{dataTrack?.dataId}</Text> <Text>{dataTrack?.dataId}</Text>
@ -124,7 +121,7 @@ export const TrackEditPopUp = ({}: TrackEditPopUpProps) => {
<ConfirmPopUp <ConfirmPopUp
disclosure={disclosure} disclosure={disclosure}
title="Remove track" title="Remove track"
body={`Remove Media [${dataTrack?.id}] ${dataTrack?.name}`} body={`Remove Media [${dataTrack?.oid}] ${dataTrack?.name}`}
confirmTitle="Remove" confirmTitle="Remove"
onConfirm={onRemove} onConfirm={onRemove}
/> />

View File

@ -23,7 +23,7 @@ export const DisplayTrack = ({
data={track?.covers} data={track?.covers}
size="50" size="50"
height="full" height="full"
iconEmpty={trackActive?.id === track.id ? <LuPlay /> : <LuMusic2 />} iconEmpty={trackActive?.oid === track.oid ? <LuPlay /> : <LuMusic2 />}
onClick={onClick} onClick={onClick}
/> />
<Flex <Flex
@ -44,7 +44,7 @@ export const DisplayTrack = ({
overflow="hidden" overflow="hidden"
// TODO: noOfLines={[1, 2]} // TODO: noOfLines={[1, 2]}
marginY="auto" marginY="auto"
color={trackActive?.id === track.id ? 'green.700' : undefined} color={trackActive?.oid === track.oid ? 'green.700' : undefined}
> >
[{track.track}] {track.name} [{track.track}] {track.name}
</Text> </Text>

View File

@ -34,7 +34,7 @@ export const DisplayTrackFull = ({
data={track?.covers} data={track?.covers}
size="60px" size="60px"
marginY="auto" marginY="auto"
iconEmpty={trackActive?.id === track.id ? <LuPlay /> : <LuMusic2 />} iconEmpty={trackActive?.oid === track.oid ? <LuPlay /> : <LuMusic2 />}
onClick={onClick} onClick={onClick}
/> />
<Flex <Flex
@ -54,7 +54,7 @@ export const DisplayTrackFull = ({
marginRight="auto" marginRight="auto"
overflow="hidden" overflow="hidden"
// TODO: noOfLines={1} // TODO: noOfLines={1}
color={trackActive?.id === track.id ? 'green.700' : undefined} color={trackActive?.oid === track.oid ? 'green.700' : undefined}
> >
{track.name} {track.track && ` [${track.track}]`} {track.name} {track.track && ` [${track.track}]`}
</Text> </Text>
@ -69,7 +69,7 @@ export const DisplayTrackFull = ({
overflow="hidden" overflow="hidden"
//noOfLines={1} //noOfLines={1}
marginY="auto" marginY="auto"
color={trackActive?.id === track.id ? 'green.700' : undefined} color={trackActive?.oid === track.oid ? 'green.700' : undefined}
> >
<Text as="span" fontWeight="normal"> <Text as="span" fontWeight="normal">
Album: Album:
@ -88,7 +88,7 @@ export const DisplayTrackFull = ({
overflow="hidden" overflow="hidden"
//noOfLines={1} //noOfLines={1}
marginY="auto" marginY="auto"
color={trackActive?.id === track.id ? 'green.700' : undefined} color={trackActive?.oid === track.oid ? 'green.700' : undefined}
> >
<Text as="span" fontWeight="normal"> <Text as="span" fontWeight="normal">
Artist(s): Artist(s):
@ -107,7 +107,7 @@ export const DisplayTrackFull = ({
overflow="hidden" overflow="hidden"
//noOfLines={1} //noOfLines={1}
marginY="auto" marginY="auto"
color={trackActive?.id === track.id ? 'green.700' : undefined} color={trackActive?.oid === track.oid ? 'green.700' : undefined}
> >
<Text as="span" fontWeight="normal"> <Text as="span" fontWeight="normal">
Gender: Gender:

View File

@ -6,7 +6,7 @@ import { DisplayTrackFull } from './DisplayTrackFull';
import { DisplayTrackSkeleton } from './DisplayTrackSkeleton'; import { DisplayTrackSkeleton } from './DisplayTrackSkeleton';
export type DisplayTrackProps = { export type DisplayTrackProps = {
trackId: Track['id']; trackId: Track['oid'];
onClick?: () => void; onClick?: () => void;
contextMenu?: MenuElement[]; contextMenu?: MenuElement[];
}; };

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,
}; };
/** /**

View File

@ -3,6 +3,7 @@ import { LuDisc3 } from 'react-icons/lu';
import { MdAdd, MdEdit } from 'react-icons/md'; import { MdAdd, MdEdit } from 'react-icons/md';
import { Route, Routes, useNavigate, useParams } from 'react-router-dom'; import { Route, Routes, useNavigate, useParams } from 'react-router-dom';
import { ObjectId } from '@/back-api';
import { Covers } from '@/components/Cover'; import { Covers } from '@/components/Cover';
import { EmptyEnd } from '@/components/EmptyEnd'; import { EmptyEnd } from '@/components/EmptyEnd';
import { PageLayout } from '@/components/Layout/PageLayout'; import { PageLayout } from '@/components/Layout/PageLayout';
@ -19,22 +20,21 @@ import { useTracksOfAnAlbum } from '@/service/Track';
export const AlbumDetailPage = () => { export const AlbumDetailPage = () => {
const { albumId } = useParams(); const { albumId } = useParams();
const albumIdInt = albumId ? parseInt(albumId, 10) : undefined;
const { playInList } = useActivePlaylistService(); const { playInList } = useActivePlaylistService();
const { dataAlbum } = useSpecificAlbum(albumIdInt); const { dataAlbum } = useSpecificAlbum(albumId);
const { tracksOnAnAlbum } = useTracksOfAnAlbum(albumIdInt); const { tracksOnAnAlbum } = useTracksOfAnAlbum(albumId);
const navigate = useNavigate(); const navigate = useNavigate();
const onSelectItem = (trackId: number) => { const onSelectItem = (trackId: ObjectId) => {
//navigate(`/artist/${artistIdInt}/album/${albumId}`); //navigate(`/artist/${artistIdInt}/album/${albumId}`);
let currentPlay = 0; let currentPlay = 0;
const listTrackId: number[] = []; const listTrackId: ObjectId[] = [];
if (!tracksOnAnAlbum) { if (!tracksOnAnAlbum) {
console.log('Fail to get album...'); console.log('Fail to get album...');
return; return;
} }
for (let iii = 0; iii < tracksOnAnAlbum.length; iii++) { for (let iii = 0; iii < tracksOnAnAlbum.length; iii++) {
listTrackId.push(tracksOnAnAlbum[iii].id); listTrackId.push(tracksOnAnAlbum[iii].oid);
if (tracksOnAnAlbum[iii].id === trackId) { if (tracksOnAnAlbum[iii].oid === trackId) {
currentPlay = iii; currentPlay = iii;
} }
} }
@ -58,7 +58,7 @@ export const AlbumDetailPage = () => {
<Button <Button
{...BUTTON_TOP_BAR_PROPERTY} {...BUTTON_TOP_BAR_PROPERTY}
onClick={() => onClick={() =>
navigate(`/album/${albumId}/edit-album/${dataAlbum.id}`) navigate(`/album/${albumId}/edit-album/${dataAlbum.oid}`)
} }
> >
<MdEdit /> <MdEdit />
@ -101,7 +101,7 @@ export const AlbumDetailPage = () => {
border="1px" border="1px"
borderColor="brand.900" borderColor="brand.900"
backgroundColor={useColorModeValue('#FFFFFF88', '#00000088')} backgroundColor={useColorModeValue('#FFFFFF88', '#00000088')}
key={data.id} key={data.oid}
padding="5px" padding="5px"
as="button" as="button"
_hover={{ _hover={{
@ -111,13 +111,13 @@ export const AlbumDetailPage = () => {
> >
<DisplayTrackFull <DisplayTrackFull
track={data} track={data}
onClick={() => onSelectItem(data.id)} onClick={() => onSelectItem(data.oid)}
contextMenu={[ contextMenu={[
{ {
name: 'Edit', name: 'Edit',
icon: <MdEdit />, icon: <MdEdit />,
onClick: () => { onClick: () => {
navigate(`/album/${albumId}/edit-track/${data.id}`); navigate(`/album/${albumId}/edit-track/${data.oid}`);
}, },
}, },
{ {

View File

@ -3,6 +3,7 @@ import { useState } from 'react';
import { Flex, HStack } from '@chakra-ui/react'; import { Flex, HStack } from '@chakra-ui/react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { ObjectId } from '@/back-api';
import { EmptyEnd } from '@/components/EmptyEnd'; import { EmptyEnd } from '@/components/EmptyEnd';
import { PageLayout } from '@/components/Layout/PageLayout'; import { PageLayout } from '@/components/Layout/PageLayout';
import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter'; import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';
@ -21,7 +22,7 @@ export const AlbumsPage = () => {
const [filterTitle, setFilterTitle] = useState<string | undefined>(undefined); const [filterTitle, setFilterTitle] = useState<string | undefined>(undefined);
const { isLoading, dataAlbums } = useOrderedAlbums(filterTitle); const { isLoading, dataAlbums } = useOrderedAlbums(filterTitle);
const navigate = useNavigate(); const navigate = useNavigate();
const onSelectItem = (albumId: number) => { const onSelectItem = (albumId: ObjectId) => {
navigate(`/album/${albumId}`); navigate(`/album/${albumId}`);
}; };
@ -55,14 +56,14 @@ export const AlbumsPage = () => {
border="1px" border="1px"
borderColor="brand.900" borderColor="brand.900"
backgroundColor={useColorModeValue('#FFFFFF88', '#00000088')} backgroundColor={useColorModeValue('#FFFFFF88', '#00000088')}
key={data.id} key={data.oid}
padding="5px" padding="5px"
as="button" as="button"
_hover={{ _hover={{
boxShadow: 'outline-over', boxShadow: 'outline-over',
bgColor: useColorModeValue('#FFFFFFF7', '#000000F7'), bgColor: useColorModeValue('#FFFFFFF7', '#000000F7'),
}} }}
onClick={() => onSelectItem(data.id)} onClick={() => onSelectItem(data.oid)}
> >
<DisplayAlbum dataAlbum={data} /> <DisplayAlbum dataAlbum={data} />
</Flex> </Flex>

View File

@ -3,6 +3,7 @@ import { LuDisc3 } from 'react-icons/lu';
import { MdAdd, MdEdit, MdPerson } from 'react-icons/md'; import { MdAdd, MdEdit, MdPerson } from 'react-icons/md';
import { Route, Routes, useNavigate, useParams } from 'react-router-dom'; import { Route, Routes, useNavigate, useParams } from 'react-router-dom';
import { ObjectId } from '@/back-api';
import { Covers } from '@/components/Cover'; import { Covers } from '@/components/Cover';
import { EmptyEnd } from '@/components/EmptyEnd'; import { EmptyEnd } from '@/components/EmptyEnd';
import { PageLayout } from '@/components/Layout/PageLayout'; import { PageLayout } from '@/components/Layout/PageLayout';
@ -19,23 +20,21 @@ import { useTracksOfAnAlbum } from '@/service/Track';
export const ArtistAlbumDetailPage = () => { export const ArtistAlbumDetailPage = () => {
const { artistId, albumId } = useParams(); const { artistId, albumId } = useParams();
const artistIdInt = artistId ? parseInt(artistId, 10) : undefined;
const albumIdInt = albumId ? parseInt(albumId, 10) : undefined;
const { playInList } = useActivePlaylistService(); const { playInList } = useActivePlaylistService();
const { dataArtist } = useSpecificArtist(artistIdInt); const { dataArtist } = useSpecificArtist(artistId);
const { dataAlbum } = useSpecificAlbum(albumIdInt); const { dataAlbum } = useSpecificAlbum(albumId);
const { tracksOnAnAlbum } = useTracksOfAnAlbum(albumIdInt); const { tracksOnAnAlbum } = useTracksOfAnAlbum(albumId);
const navigate = useNavigate(); const navigate = useNavigate();
const onSelectItem = (trackId: number) => { const onSelectItem = (trackId: ObjectId) => {
let currentPlay = 0; let currentPlay = 0;
const listTrackId: number[] = []; const listTrackId: ObjectId[] = [];
if (!tracksOnAnAlbum) { if (!tracksOnAnAlbum) {
console.error('Fail to get the album ...'); console.error('Fail to get the album ...');
return; return;
} }
for (let iii = 0; iii < tracksOnAnAlbum.length; iii++) { for (let iii = 0; iii < tracksOnAnAlbum.length; iii++) {
listTrackId.push(tracksOnAnAlbum[iii].id); listTrackId.push(tracksOnAnAlbum[iii].oid);
if (tracksOnAnAlbum[iii].id === trackId) { if (tracksOnAnAlbum[iii].oid === trackId) {
currentPlay = iii; currentPlay = iii;
} }
} }
@ -57,7 +56,7 @@ export const ArtistAlbumDetailPage = () => {
<> <>
<TopBar <TopBar
title={dataArtist ? dataArtist?.name : 'Album detail'} title={dataArtist ? dataArtist?.name : 'Album detail'}
titleLink={dataArtist ? `/artist/${dataArtist.id}` : undefined} titleLink={dataArtist ? `/artist/${dataArtist.oid}` : undefined}
titleIcon={ titleIcon={
<Covers <Covers
data={dataArtist?.covers} data={dataArtist?.covers}
@ -71,7 +70,7 @@ export const ArtistAlbumDetailPage = () => {
<Button <Button
{...BUTTON_TOP_BAR_PROPERTY} {...BUTTON_TOP_BAR_PROPERTY}
onClick={() => onClick={() =>
navigate(`/album/${albumId}/edit-album/${dataAlbum.id}`) navigate(`/album/${albumId}/edit-album/${dataAlbum.oid}`)
} }
> >
<MdEdit /> <MdEdit />
@ -114,7 +113,7 @@ export const ArtistAlbumDetailPage = () => {
border="1px" border="1px"
borderColor="brand.900" borderColor="brand.900"
backgroundColor={useColorModeValue('#FFFFFF88', '#00000088')} backgroundColor={useColorModeValue('#FFFFFF88', '#00000088')}
key={data.id} key={data.oid}
padding="5px" padding="5px"
_hover={{ _hover={{
boxShadow: 'outline-over', boxShadow: 'outline-over',
@ -123,14 +122,14 @@ export const ArtistAlbumDetailPage = () => {
> >
<DisplayTrack <DisplayTrack
track={data} track={data}
onClick={() => onSelectItem(data.id)} onClick={() => onSelectItem(data.oid)}
contextMenu={[ contextMenu={[
{ {
name: 'Edit', name: 'Edit',
icon: <MdEdit />, icon: <MdEdit />,
onClick: () => { onClick: () => {
navigate( navigate(
`/artist/${artistIdInt}/album/${albumId}/edit-track/${data.id}` `/artist/${artistId}/album/${albumId}/edit-track/${data.oid}`
); );
}, },
}, },

View File

@ -3,6 +3,7 @@ import { LuUser } from 'react-icons/lu';
import { MdEdit, MdGroup } from 'react-icons/md'; import { MdEdit, MdGroup } from 'react-icons/md';
import { Route, Routes, useNavigate, useParams } from 'react-router-dom'; import { Route, Routes, useNavigate, useParams } from 'react-router-dom';
import { ObjectId } from '@/back-api';
import { Covers } from '@/components/Cover'; import { Covers } from '@/components/Cover';
import { EmptyEnd } from '@/components/EmptyEnd'; import { EmptyEnd } from '@/components/EmptyEnd';
import { PageLayout } from '@/components/Layout/PageLayout'; import { PageLayout } from '@/components/Layout/PageLayout';
@ -21,13 +22,12 @@ import { useAlbumIdsOfAnArtist } from '@/service/Track';
export const ArtistDetailPage = () => { export const ArtistDetailPage = () => {
const { artistId } = useParams(); const { artistId } = useParams();
const artistIdInt = artistId ? parseInt(artistId, 10) : undefined;
const navigate = useNavigate(); const navigate = useNavigate();
const onSelectItem = (albumId: number) => { const onSelectItem = (albumId: ObjectId) => {
navigate(`/artist/${artistIdInt}/album/${albumId}`); navigate(`/artist/${artistId}/album/${albumId}`);
}; };
const { dataArtist } = useSpecificArtist(artistIdInt); const { dataArtist } = useSpecificArtist(artistId);
const { albumIdsOfAnArtist } = useAlbumIdsOfAnArtist(artistIdInt); const { albumIdsOfAnArtist } = useAlbumIdsOfAnArtist(artistId);
if (!dataArtist) { if (!dataArtist) {
return ( return (
@ -105,7 +105,7 @@ export const ArtistDetailPage = () => {
}} }}
onClick={() => onSelectItem(data)} onClick={() => onSelectItem(data)}
> >
<DisplayAlbumId id={data} key={data} /> <DisplayAlbumId oid={data} key={data} />
</Flex> </Flex>
))} ))}
</HStack> </HStack>

View File

@ -5,7 +5,7 @@ import { LuUser } from 'react-icons/lu';
import { MdOutlineForkRight } from 'react-icons/md'; import { MdOutlineForkRight } from 'react-icons/md';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { Artist, Track } from '@/back-api'; import { Artist, ObjectId, Track } from '@/back-api';
import { Covers } from '@/components/Cover'; import { Covers } from '@/components/Cover';
import { EmptyEnd } from '@/components/EmptyEnd'; import { EmptyEnd } from '@/components/EmptyEnd';
import { PageLayout } from '@/components/Layout/PageLayout'; import { PageLayout } from '@/components/Layout/PageLayout';
@ -31,13 +31,13 @@ export const ArtistsPage = () => {
const navigate = useNavigate(); const navigate = useNavigate();
const { playInList } = useActivePlaylistService(); const { playInList } = useActivePlaylistService();
const onSelectItem = (data: Artist) => { const onSelectItem = (data: Artist) => {
navigate(`/artist/${data.id}/`); navigate(`/artist/${data.oid}/`);
}; };
const { dataArtist } = useOrderedArtists(filterName); const { dataArtist } = useOrderedArtists(filterName);
const { store: trackStore } = useTrackService(); const { store: trackStore } = useTrackService();
const onRandomPlay = () => { const onRandomPlay = () => {
const data = shuffleArray(dataArtist); const data = shuffleArray(dataArtist);
const playingList: number[] = []; const playingList: ObjectId[] = [];
for (let i = 0; i < Math.min(data.length, LIMIT_RANDOM_VALUES); i++) { for (let i = 0; i < Math.min(data.length, LIMIT_RANDOM_VALUES); i++) {
const selectedArtist: Artist = data[i]; const selectedArtist: Artist = data[i];
const listArtistTracks: Track[] = DataTools.getsWhere( const listArtistTracks: Track[] = DataTools.getsWhere(
@ -46,7 +46,7 @@ export const ArtistsPage = () => {
{ {
check: TypeCheck.CONTAINS, check: TypeCheck.CONTAINS,
key: 'artists', key: 'artists',
value: selectedArtist.id, value: selectedArtist.oid,
}, },
], ],
[] []
@ -55,7 +55,8 @@ export const ArtistsPage = () => {
continue; continue;
} }
playingList.push( playingList.push(
listArtistTracks[Math.floor(Math.random() * listArtistTracks.length)].id listArtistTracks[Math.floor(Math.random() * listArtistTracks.length)]
.oid
); );
} }
playInList(0, playingList); playInList(0, playingList);
@ -87,7 +88,7 @@ export const ArtistsPage = () => {
border="1px" border="1px"
borderColor="brand.900" borderColor="brand.900"
backgroundColor={useColorModeValue('#FFFFFF88', '#00000088')} backgroundColor={useColorModeValue('#FFFFFF88', '#00000088')}
key={data.id} key={data.oid}
padding="5px" padding="5px"
as="button" as="button"
_hover={{ _hover={{

View File

@ -3,6 +3,8 @@ import { LuDisc3 } from 'react-icons/lu';
import { MdEdit } from 'react-icons/md'; import { MdEdit } from 'react-icons/md';
import { Route, Routes, useNavigate, useParams } from 'react-router-dom'; import { Route, Routes, useNavigate, useParams } from 'react-router-dom';
//import { useTracksOfAGender } from '@/service/Track';
import { ObjectId } from '@/back-api';
import { Covers } from '@/components/Cover'; import { Covers } from '@/components/Cover';
import { EmptyEnd } from '@/components/EmptyEnd'; import { EmptyEnd } from '@/components/EmptyEnd';
import { PageLayout } from '@/components/Layout/PageLayout'; import { PageLayout } from '@/components/Layout/PageLayout';
@ -11,7 +13,6 @@ import { BUTTON_TOP_BAR_PROPERTY, TopBar } from '@/components/TopBar/TopBar';
import { GenderEditPopUp } from '@/components/popup/GenderEditPopUp'; import { GenderEditPopUp } from '@/components/popup/GenderEditPopUp';
import { TrackEditPopUp } from '@/components/popup/TrackEditPopUp'; import { TrackEditPopUp } from '@/components/popup/TrackEditPopUp';
import { DisplayTrackFull } from '@/components/track/DisplayTrackFull'; import { DisplayTrackFull } from '@/components/track/DisplayTrackFull';
//import { useTracksOfAGender } from '@/service/Track';
import { useColorModeValue } from '@/components/ui/color-mode'; import { useColorModeValue } from '@/components/ui/color-mode';
import { useActivePlaylistService } from '@/service/ActivePlaylist'; import { useActivePlaylistService } from '@/service/ActivePlaylist';
import { useSpecificGender } from '@/service/Gender'; import { useSpecificGender } from '@/service/Gender';
@ -19,22 +20,21 @@ import { useTracksOfAGender } from '@/service/Track';
export const GenderDetailPage = () => { export const GenderDetailPage = () => {
const { genderId } = useParams(); const { genderId } = useParams();
const genderIdInt = genderId ? parseInt(genderId, 10) : undefined;
const { playInList } = useActivePlaylistService(); const { playInList } = useActivePlaylistService();
const { dataGender } = useSpecificGender(genderIdInt); const { dataGender } = useSpecificGender(genderId);
const { tracksOnAGender } = useTracksOfAGender(genderIdInt); const { tracksOnAGender } = useTracksOfAGender(genderId);
const navigate = useNavigate(); const navigate = useNavigate();
const onSelectItem = (trackId: number) => { const onSelectItem = (trackId: ObjectId) => {
//navigate(`/artist/${artistIdInt}/gender/${genderId}`); //navigate(`/artist/${artistId}/gender/${genderId}`);
let currentPlay = 0; let currentPlay = 0;
const listTrackId: number[] = []; const listTrackId: ObjectId[] = [];
if (!tracksOnAGender) { if (!tracksOnAGender) {
console.log('Fail to get gender...'); console.log('Fail to get gender...');
return; return;
} }
for (let iii = 0; iii < tracksOnAGender.length; iii++) { for (let iii = 0; iii < tracksOnAGender.length; iii++) {
listTrackId.push(tracksOnAGender[iii].id); listTrackId.push(tracksOnAGender[iii].oid);
if (tracksOnAGender[iii].id === trackId) { if (tracksOnAGender[iii].oid === trackId) {
currentPlay = iii; currentPlay = iii;
} }
} }
@ -97,7 +97,7 @@ export const GenderDetailPage = () => {
border="1px" border="1px"
borderColor="brand.900" borderColor="brand.900"
backgroundColor={useColorModeValue('#FFFFFF88', '#00000088')} backgroundColor={useColorModeValue('#FFFFFF88', '#00000088')}
key={data.id} key={data.oid}
padding="5px" padding="5px"
as="button" as="button"
_hover={{ _hover={{
@ -107,12 +107,12 @@ export const GenderDetailPage = () => {
> >
<DisplayTrackFull <DisplayTrackFull
track={data} track={data}
onClick={() => onSelectItem(data.id)} onClick={() => onSelectItem(data.oid)}
contextMenu={[ contextMenu={[
{ {
name: 'Edit', name: 'Edit',
onClick: () => { onClick: () => {
navigate(`/gender/${genderId}/edit-track/${data.id}`); navigate(`/gender/${genderId}/edit-track/${data.oid}`);
}, },
}, },
{ name: 'Add Playlist', onClick: () => {} }, { name: 'Add Playlist', onClick: () => {} },

View File

@ -3,6 +3,7 @@ import { useState } from 'react';
import { Flex, HStack } from '@chakra-ui/react'; import { Flex, HStack } from '@chakra-ui/react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { ObjectId } from '@/back-api';
import { EmptyEnd } from '@/components/EmptyEnd'; import { EmptyEnd } from '@/components/EmptyEnd';
import { PageLayout } from '@/components/Layout/PageLayout'; import { PageLayout } from '@/components/Layout/PageLayout';
import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter'; import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';
@ -16,7 +17,7 @@ export const GendersPage = () => {
const [filterTitle, setFilterTitle] = useState<string | undefined>(undefined); const [filterTitle, setFilterTitle] = useState<string | undefined>(undefined);
const { isLoading, dataGenders } = useOrderedGenders(filterTitle); const { isLoading, dataGenders } = useOrderedGenders(filterTitle);
const navigate = useNavigate(); const navigate = useNavigate();
const onSelectItem = (genderId: number) => { const onSelectItem = (genderId: ObjectId) => {
navigate(`/gender/${genderId}`); navigate(`/gender/${genderId}`);
}; };
@ -50,14 +51,14 @@ export const GendersPage = () => {
border="1px" border="1px"
borderColor="brand.900" borderColor="brand.900"
backgroundColor={useColorModeValue('#FFFFFF88', '#00000088')} backgroundColor={useColorModeValue('#FFFFFF88', '#00000088')}
key={data.id} key={data.oid}
padding="5px" padding="5px"
as="button" as="button"
_hover={{ _hover={{
boxShadow: 'outline-over', boxShadow: 'outline-over',
bgColor: useColorModeValue('#FFFFFFF7', '#000000F7'), bgColor: useColorModeValue('#FFFFFFF7', '#000000F7'),
}} }}
onClick={() => onSelectItem(data.id)} onClick={() => onSelectItem(data.oid)}
> >
<DisplayGender dataGender={data} /> <DisplayGender dataGender={data} />
</Flex> </Flex>

View File

@ -11,6 +11,7 @@ import {
ArtistResource, ArtistResource,
Gender, Gender,
GenderResource, GenderResource,
ObjectId,
RestErrorResponse, RestErrorResponse,
Track, Track,
TrackResource, TrackResource,
@ -67,8 +68,8 @@ export class FileFailParsedElement {
} }
type FormInsertData = { type FormInsertData = {
genderId?: number; genderId?: ObjectId;
artistId?: number; artistId?: ObjectId;
titleAlbum?: string; titleAlbum?: string;
}; };
@ -283,8 +284,8 @@ export const AddPage = () => {
if ( if (
data.name?.toLowerCase() === parsedElementTmp[0].artist?.toLowerCase() data.name?.toLowerCase() === parsedElementTmp[0].artist?.toLowerCase()
) { ) {
console.log(` find artist : ${data.id}`); console.log(` find artist : ${data.oid}`);
form.setValues({ artistId: data.id }); form.setValues({ artistId: data.oid });
artistFound = true; artistFound = true;
} }
}); });
@ -301,8 +302,8 @@ export const AddPage = () => {
if ( if (
data.name?.toLowerCase() === parsedElementTmp[0].album?.toLowerCase() data.name?.toLowerCase() === parsedElementTmp[0].album?.toLowerCase()
) { ) {
console.log(` find album : ${data.id}`); console.log(` find album : ${data.oid}`);
form.setValues({ albumId: data.id }); form.setValues({ albumId: data.oid });
albumFound = true; albumFound = true;
} }
}); });

View File

@ -8,6 +8,7 @@ import {
} from 'react-icons/md'; } from 'react-icons/md';
import { Route, Routes, useNavigate } from 'react-router-dom'; import { Route, Routes, useNavigate } from 'react-router-dom';
import { ObjectId } from '@/back-api';
import { EmptyEnd } from '@/components/EmptyEnd'; import { EmptyEnd } from '@/components/EmptyEnd';
import { PageLayout } from '@/components/Layout/PageLayout'; import { PageLayout } from '@/components/Layout/PageLayout';
import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter'; import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';
@ -25,7 +26,7 @@ export const OnAirPage = () => {
const { playTrackList, trackOffset, setNewPlaylist } = const { playTrackList, trackOffset, setNewPlaylist } =
useActivePlaylistService(); useActivePlaylistService();
const navigate = useNavigate(); const navigate = useNavigate();
const onSelectItem = (trackId: number) => { const onSelectItem = (trackId: ObjectId) => {
let currentPlay = 0; let currentPlay = 0;
if (!playTrackList) { if (!playTrackList) {
console.log('Fail to get list of on air...'); console.log('Fail to get list of on air...');
@ -38,13 +39,13 @@ export const OnAirPage = () => {
} }
playInList(currentPlay, playTrackList); playInList(currentPlay, playTrackList);
}; };
const removeTrack = (trackId: number) => { const removeTrack = (trackId: ObjectId) => {
let elementToRemoveOffset = 0; let elementToRemoveOffset = 0;
if (!playTrackList) { if (!playTrackList) {
console.log('Fail to remove element of on air...'); console.log('Fail to remove element of on air...');
return; return;
} }
const newList: number[] = []; const newList: ObjectId[] = [];
for (let iii = 0; iii < playTrackList.length; iii++) { for (let iii = 0; iii < playTrackList.length; iii++) {
if (playTrackList[iii] === trackId) { if (playTrackList[iii] === trackId) {
elementToRemoveOffset = iii; elementToRemoveOffset = iii;

View File

@ -1,6 +1,7 @@
import { Box, Flex } from '@chakra-ui/react'; import { Box, Flex } from '@chakra-ui/react';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import { ObjectId } from '@/back-api';
import { EmptyEnd } from '@/components/EmptyEnd'; import { EmptyEnd } from '@/components/EmptyEnd';
import { PageLayout } from '@/components/Layout/PageLayout'; import { PageLayout } from '@/components/Layout/PageLayout';
import { TopBar } from '@/components/TopBar/TopBar'; import { TopBar } from '@/components/TopBar/TopBar';
@ -22,17 +23,17 @@ export const TracksStartLetterDetailPage = () => {
startLetter === '^^' startLetter === '^^'
); );
const { playInList } = useActivePlaylistService(); const { playInList } = useActivePlaylistService();
const onSelectItem = (trackId: number) => { const onSelectItem = (trackId: ObjectId) => {
//navigate(`/artist/${artistIdInt}/gender/${genderId}`); //navigate(`/artist/${artistIdInt}/gender/${genderId}`);
let currentPlay = 0; let currentPlay = 0;
const listTrackId: number[] = []; const listTrackId: ObjectId[] = [];
if (!tracksStartsWith) { if (!tracksStartsWith) {
console.log('Fail to get tracks...'); console.log('Fail to get tracks...');
return; return;
} }
for (let iii = 0; iii < tracksStartsWith.length; iii++) { for (let iii = 0; iii < tracksStartsWith.length; iii++) {
listTrackId.push(tracksStartsWith[iii].id); listTrackId.push(tracksStartsWith[iii].oid);
if (tracksStartsWith[iii].id === trackId) { if (tracksStartsWith[iii].oid === trackId) {
currentPlay = iii; currentPlay = iii;
} }
} }
@ -79,7 +80,7 @@ export const TracksStartLetterDetailPage = () => {
border="1px" border="1px"
borderColor="brand.900" borderColor="brand.900"
backgroundColor={useColorModeValue('#FFFFFF88', '#00000088')} backgroundColor={useColorModeValue('#FFFFFF88', '#00000088')}
key={data.id} key={data.oid}
padding="5px" padding="5px"
as="button" as="button"
_hover={{ _hover={{
@ -89,7 +90,7 @@ export const TracksStartLetterDetailPage = () => {
> >
<DisplayTrackFull <DisplayTrackFull
track={data} track={data}
onClick={() => onSelectItem(data.id)} onClick={() => onSelectItem(data.oid)}
/> />
</Box> </Box>
))} ))}

View File

@ -1,21 +1,22 @@
import { useCallback, useMemo, useState } from 'react'; import { useCallback, useMemo, useState } from 'react';
import { ObjectId, Track } from '@/back-api';
import { useServiceContext } from '@/service/ServiceContext'; import { useServiceContext } from '@/service/ServiceContext';
import { TrackServiceProps } from './Track'; import { TrackServiceProps } from './Track';
import { Track } from '@/back-api';
export type PlaylistElement = { export type PlaylistElement = {
trackId: number; trackId: ObjectId;
}; };
export type ActivePlaylistServiceProps = { export type ActivePlaylistServiceProps = {
playTrackList: number[]; playTrackList: ObjectId[];
trackOffset?: number; trackOffset?: number;
trackActive?: Track; trackActive?: Track;
setNewPlaylist: (listIds: number[]) => void; setNewPlaylist: (listIds: ObjectId[]) => void;
setNewPlaylistShuffle: (listIds: number[]) => void; setNewPlaylistShuffle: (listIds: ObjectId[]) => void;
playInList: (id: number | undefined, listIds: number[]) => void; playInList: (id: number | undefined, listIds: ObjectId[]) => void;
play: (id: number) => void; play: (id: ObjectId) => void;
previous: () => void; previous: () => void;
next: () => void; next: () => void;
first: () => void; first: () => void;
@ -46,10 +47,12 @@ export function localShuffle<T>(array: T[]): T[] {
export const useActivePlaylistServiceWrapped = ( export const useActivePlaylistServiceWrapped = (
track: TrackServiceProps track: TrackServiceProps
): ActivePlaylistServiceProps => { ): ActivePlaylistServiceProps => {
const [playTrackList, setPlayTrackList] = useState<number[]>([]); const [playTrackList, setPlayTrackList] = useState<ObjectId[]>([]);
const [trackOffset, setTrackOffset] = useState<number | undefined>(); const [trackOffset, setTrackOffset] = useState<number | undefined>();
const trackActive = useMemo(() => { const trackActive = useMemo(() => {
return track.store.get(trackOffset !== undefined ? playTrackList[trackOffset] : undefined); return track.store.get(
trackOffset !== undefined ? playTrackList[trackOffset] : undefined
);
}, [track.store.data, playTrackList, trackOffset]); }, [track.store.data, playTrackList, trackOffset]);
const clear = useCallback(() => { const clear = useCallback(() => {
@ -58,15 +61,15 @@ export const useActivePlaylistServiceWrapped = (
}, [setPlayTrackList, setTrackOffset]); }, [setPlayTrackList, setTrackOffset]);
const play = useCallback( const play = useCallback(
(id: number) => { (id: ObjectId) => {
setPlayTrackList([id]); setPlayTrackList([id]);
setTrackOffset(0); setTrackOffset(0);
}, },
[setPlayTrackList, setTrackOffset] [setPlayTrackList, setTrackOffset]
); );
const playInList = useCallback( const playInList = useCallback(
(id: number | undefined, listIds: number[]) => { (id: number | undefined, listIds: ObjectId[]) => {
console.log(`Request paly in list: ${id} in ${listIds}`); console.log(`Request play in list: ${id} in ${listIds?.length}`);
setPlayTrackList(listIds); setPlayTrackList(listIds);
setTrackOffset(id); setTrackOffset(id);
}, },
@ -74,7 +77,7 @@ export const useActivePlaylistServiceWrapped = (
); );
const setNewPlaylist = useCallback( const setNewPlaylist = useCallback(
(listIds: number[]) => { (listIds: ObjectId[]) => {
if (listIds.length == 0) { if (listIds.length == 0) {
clear(); clear();
return; return;
@ -86,7 +89,7 @@ export const useActivePlaylistServiceWrapped = (
); );
const setNewPlaylistShuffle = useCallback( const setNewPlaylistShuffle = useCallback(
(listIds: number[]) => { (listIds: ObjectId[]) => {
if (listIds.length == 0) { if (listIds.length == 0) {
clear(); clear();
return; return;
@ -128,7 +131,6 @@ export const useActivePlaylistServiceWrapped = (
}); });
}, [playTrackList, setTrackOffset]); }, [playTrackList, setTrackOffset]);
return { return {
playTrackList, playTrackList,
trackOffset, trackOffset,

View File

@ -1,6 +1,6 @@
import { useMemo } from 'react'; import { useMemo } from 'react';
import { Album, AlbumResource } from '@/back-api'; import { Album, AlbumResource, ObjectId } from '@/back-api';
import { useServiceContext } from '@/service/ServiceContext'; import { useServiceContext } from '@/service/ServiceContext';
import { SessionServiceProps } from '@/service/session'; import { SessionServiceProps } from '@/service/session';
import { DataStoreType, useDataStore } from '@/utils/data-store'; import { DataStoreType, useDataStore } from '@/utils/data-store';
@ -22,7 +22,7 @@ export const useAlbumServiceWrapped = (
const store = useDataStore<Album>( const store = useDataStore<Album>(
{ {
restApiName: 'ALBUM', restApiName: 'ALBUM',
primaryKey: 'id', primaryKey: 'oid',
available: session.isConnected, available: session.isConnected,
getsCall: () => { getsCall: () => {
return AlbumResource.gets({ return AlbumResource.gets({
@ -48,16 +48,16 @@ export const useOrderedAlbums = (titleFilter?: string) => {
[ [
{ {
check: TypeCheck.NOT_EQUAL, check: TypeCheck.NOT_EQUAL,
key: 'id', key: 'oid',
value: [undefined, null], value: [undefined, null],
}, },
], ],
['name', 'id'] ['name', 'oid']
); );
}, [store.data, titleFilter]); }, [store.data, titleFilter]);
return { isLoading: store.isLoading, dataAlbums }; return { isLoading: store.isLoading, dataAlbums };
}; };
export const useSpecificAlbum = (id: number | undefined) => { export const useSpecificAlbum = (id: ObjectId | undefined) => {
const { store } = useAlbumService(); const { store } = useAlbumService();
const dataAlbum = useMemo(() => { const dataAlbum = useMemo(() => {
return store.get(id); return store.get(id);
@ -65,7 +65,7 @@ export const useSpecificAlbum = (id: number | undefined) => {
return { dataAlbum }; return { dataAlbum };
}; };
export const useAlbumOfAnArtist = (idArtist: number | undefined) => { export const useAlbumOfAnArtist = (idArtist: ObjectId | undefined) => {
const { store } = useAlbumService(); const { store } = useAlbumService();
const dataAlbum = useMemo(() => { const dataAlbum = useMemo(() => {
return store.get(idArtist); return store.get(idArtist);

View File

@ -1,6 +1,6 @@
import { useMemo } from 'react'; import { useMemo } from 'react';
import { Artist, ArtistResource } from '@/back-api'; import { Artist, ArtistResource, ObjectId } from '@/back-api';
import { useServiceContext } from '@/service/ServiceContext'; import { useServiceContext } from '@/service/ServiceContext';
import { SessionServiceProps } from '@/service/session'; import { SessionServiceProps } from '@/service/session';
import { DataStoreType, useDataStore } from '@/utils/data-store'; import { DataStoreType, useDataStore } from '@/utils/data-store';
@ -22,7 +22,7 @@ export const useArtistServiceWrapped = (
const store = useDataStore<Artist>( const store = useDataStore<Artist>(
{ {
restApiName: 'ARTIST', restApiName: 'ARTIST',
primaryKey: 'id', primaryKey: 'oid',
available: session.isConnected, available: session.isConnected,
getsCall: () => { getsCall: () => {
return ArtistResource.gets({ return ArtistResource.gets({
@ -48,17 +48,17 @@ export const useOrderedArtists = (nameFilter?: string) => {
[ [
{ {
check: TypeCheck.NOT_EQUAL, check: TypeCheck.NOT_EQUAL,
key: 'id', key: 'oid',
value: [undefined, null], value: [undefined, null],
}, },
], ],
['name', 'id'] ['name', 'oid']
); );
}, [store.data, nameFilter]); }, [store.data, nameFilter]);
return { isLoading: store.isLoading, dataArtist }; return { isLoading: store.isLoading, dataArtist };
}; };
export const useSpecificArtist = (id: number | undefined) => { export const useSpecificArtist = (id: ObjectId | undefined) => {
const { store } = useArtistService(); const { store } = useArtistService();
const dataArtist = useMemo(() => { const dataArtist = useMemo(() => {
return store.get(id); return store.get(id);
@ -66,7 +66,7 @@ export const useSpecificArtist = (id: number | undefined) => {
return { dataArtist }; return { dataArtist };
}; };
export const useSpecificArtists = (ids: number[] | undefined) => { export const useSpecificArtists = (ids: ObjectId[] | undefined) => {
const { store } = useArtistService(); const { store } = useArtistService();
const dataArtists = useMemo(() => { const dataArtists = useMemo(() => {
return store.gets(ids); return store.gets(ids);

View File

@ -1,6 +1,6 @@
import { useMemo } from 'react'; import { useMemo } from 'react';
import { Gender, GenderResource } from '@/back-api'; import { Gender, GenderResource, ObjectId } from '@/back-api';
import { useServiceContext } from '@/service/ServiceContext'; import { useServiceContext } from '@/service/ServiceContext';
import { SessionServiceProps } from '@/service/session'; import { SessionServiceProps } from '@/service/session';
import { DataStoreType, useDataStore } from '@/utils/data-store'; import { DataStoreType, useDataStore } from '@/utils/data-store';
@ -22,7 +22,7 @@ export const useGenderServiceWrapped = (
const store = useDataStore<Gender>( const store = useDataStore<Gender>(
{ {
restApiName: 'GENDER', restApiName: 'GENDER',
primaryKey: 'id', primaryKey: 'oid',
available: session.isConnected, available: session.isConnected,
getsCall: () => { getsCall: () => {
return GenderResource.gets({ return GenderResource.gets({
@ -48,16 +48,16 @@ export const useOrderedGenders = (titleFilter?: string) => {
[ [
{ {
check: TypeCheck.NOT_EQUAL, check: TypeCheck.NOT_EQUAL,
key: 'id', key: 'oid',
value: [undefined, null], value: [undefined, null],
}, },
], ],
['name', 'id'] ['name', 'oid']
); );
}, [store.data, titleFilter]); }, [store.data, titleFilter]);
return { isLoading: store.isLoading, dataGenders }; return { isLoading: store.isLoading, dataGenders };
}; };
export const useSpecificGender = (id: number | undefined) => { export const useSpecificGender = (id: ObjectId | undefined) => {
const { store } = useGenderService(); const { store } = useGenderService();
const dataGender = useMemo(() => { const dataGender = useMemo(() => {
return store.get(id); return store.get(id);
@ -65,7 +65,7 @@ export const useSpecificGender = (id: number | undefined) => {
return { dataGender }; return { dataGender };
}; };
export const useGenderOfAnArtist = (idArtist: number | undefined) => { export const useGenderOfAnArtist = (idArtist: ObjectId | undefined) => {
const { store } = useGenderService(); const { store } = useGenderService();
const dataGender = useMemo(() => { const dataGender = useMemo(() => {
return store.get(idArtist); return store.get(idArtist);

View File

@ -1,6 +1,6 @@
import { ReactNode, createContext, useContext, useMemo } from 'react'; import { ReactNode, createContext, useContext, useMemo } from 'react';
import { Album, Artist, Gender, Track } from '@/back-api'; import { Album, Artist, Gender, ObjectId, Track } from '@/back-api';
import { import {
ActivePlaylistServiceProps, ActivePlaylistServiceProps,
useActivePlaylistServiceWrapped, useActivePlaylistServiceWrapped,
@ -82,16 +82,16 @@ export const ServiceContext = createContext<ServiceContextType>({
playTrackList: [], playTrackList: [],
trackOffset: undefined, trackOffset: undefined,
trackActive: undefined, trackActive: undefined,
setNewPlaylist: (_listIds: number[]) => { setNewPlaylist: (_listIds: ObjectId[]) => {
console.error('!!! WTF !!!'); console.error('!!! WTF !!!');
}, },
setNewPlaylistShuffle: (_listIds: number[]) => { setNewPlaylistShuffle: (_listIds: ObjectId[]) => {
console.error('!!! WTF !!!'); console.error('!!! WTF !!!');
}, },
playInList: (_id: number, _listIds: number[]) => { playInList: (_id: number, _listIds: ObjectId[]) => {
console.error('!!! WTF !!!'); console.error('!!! WTF !!!');
}, },
play: (_id: number) => { play: (_id: ObjectId) => {
console.error('!!! WTF !!!'); console.error('!!! WTF !!!');
}, },
previous: () => { previous: () => {

View File

@ -1,11 +1,11 @@
import { useMemo } from 'react'; import { useMemo } from 'react';
import { Track, TrackResource } from '@/back-api'; import { ObjectId, Track, TrackResource } from '@/back-api';
import { useServiceContext } from '@/service/ServiceContext'; import { useServiceContext } from '@/service/ServiceContext';
import { SessionServiceProps } from '@/service/session'; import { SessionServiceProps } from '@/service/session';
import { DataStoreType, useDataStore } from '@/utils/data-store'; import { DataStoreType, useDataStore } from '@/utils/data-store';
import { DataTools, TypeCheck } from '@/utils/data-tools'; import { DataTools, TypeCheck } from '@/utils/data-tools';
import { isArrayOf, isNumber } from '@/utils/validator'; import { isArrayOf, isString } from '@/utils/validator';
export type TrackServiceProps = { export type TrackServiceProps = {
store: DataStoreType<Track>; store: DataStoreType<Track>;
@ -22,7 +22,7 @@ export const useTrackServiceWrapped = (
const store = useDataStore<Track>( const store = useDataStore<Track>(
{ {
restApiName: 'TRACK', restApiName: 'TRACK',
primaryKey: 'id', primaryKey: 'oid',
available: session.isConnected, available: session.isConnected,
getsCall: () => { getsCall: () => {
return TrackResource.gets({ return TrackResource.gets({
@ -36,7 +36,7 @@ export const useTrackServiceWrapped = (
return { store }; return { store };
}; };
export const useSpecificTrack = (id: number | undefined) => { export const useSpecificTrack = (id?: ObjectId) => {
const { store } = useTrackService(); const { store } = useTrackService();
const dataTrack = useMemo(() => { const dataTrack = useMemo(() => {
return store.get(id); return store.get(id);
@ -48,7 +48,7 @@ export const useSpecificTrack = (id: number | undefined) => {
* @param idArtist - Id of the artist. * @param idArtist - Id of the artist.
* @returns a promise on the list of track elements * @returns a promise on the list of track elements
*/ */
export const useTracksOfAnArtist = (idArtist?: number) => { export const useTracksOfAnArtist = (idArtist?: ObjectId) => {
const { store } = useTrackService(); const { store } = useTrackService();
const tracksOnAnArtist = useMemo(() => { const tracksOnAnArtist = useMemo(() => {
if (idArtist) { if (idArtist) {
@ -74,7 +74,7 @@ export const useTracksOfAnArtist = (idArtist?: number) => {
* @param id - Id of the artist. * @param id - Id of the artist.
* @returns The number of track present in this artist * @returns The number of track present in this artist
*/ */
export const useCountTracksOfAnArtist = (idArtist?: number) => { export const useCountTracksOfAnArtist = (idArtist?: ObjectId) => {
const { isLoading, tracksOnAnAlbum } = useTracksOfAnAlbum(idArtist); const { isLoading, tracksOnAnAlbum } = useTracksOfAnAlbum(idArtist);
const countTracksOnAnArtist = useMemo( const countTracksOnAnArtist = useMemo(
() => tracksOnAnAlbum?.length ?? 0, () => tracksOnAnAlbum?.length ?? 0,
@ -88,7 +88,7 @@ export const useCountTracksOfAnArtist = (idArtist?: number) => {
* @param idGender - Id of the artist. * @param idGender - Id of the artist.
* @returns a promise on the list of track elements * @returns a promise on the list of track elements
*/ */
export const useTracksOfAGender = (idGender?: number) => { export const useTracksOfAGender = (idGender?: ObjectId) => {
const { store } = useTrackService(); const { store } = useTrackService();
const tracksOnAGender = useMemo(() => { const tracksOnAGender = useMemo(() => {
if (idGender) { if (idGender) {
@ -114,7 +114,7 @@ export const useTracksOfAGender = (idGender?: number) => {
* @param id - Id of the gender. * @param id - Id of the gender.
* @returns The number of track present in this artist * @returns The number of track present in this artist
*/ */
export const useCountTracksOfAGender = (idGender?: number) => { export const useCountTracksOfAGender = (idGender?: ObjectId) => {
const { isLoading, tracksOnAGender } = useTracksOfAGender(idGender); const { isLoading, tracksOnAGender } = useTracksOfAGender(idGender);
const countTracksOnAGender = useMemo( const countTracksOnAGender = useMemo(
() => tracksOnAGender?.length ?? 0, () => tracksOnAGender?.length ?? 0,
@ -128,12 +128,12 @@ export const useCountTracksOfAGender = (idGender?: number) => {
* @param artistId - ID of the artist * @param artistId - ID of the artist
* @returns the required List. * @returns the required List.
*/ */
export const useAlbumIdsOfAnArtist = (idArtist?: number) => { export const useAlbumIdsOfAnArtist = (idArtist?: ObjectId) => {
const { isLoading, tracksOnAnArtist } = useTracksOfAnArtist(idArtist); const { isLoading, tracksOnAnArtist } = useTracksOfAnArtist(idArtist);
const albumIdsOfAnArtist = useMemo(() => { const albumIdsOfAnArtist = useMemo(() => {
// extract a single time all value "id" in an array // extract a single time all value "id" in an array
const listAlbumId = DataTools.extractLimitOne(tracksOnAnArtist, 'albumId'); const listAlbumId = DataTools.extractLimitOne(tracksOnAnArtist, 'albumId');
if (isArrayOf(listAlbumId, isNumber)) { if (isArrayOf(listAlbumId, isString)) {
return listAlbumId; return listAlbumId;
} else { } else {
console.log( console.log(
@ -145,7 +145,7 @@ export const useAlbumIdsOfAnArtist = (idArtist?: number) => {
return { isLoading, albumIdsOfAnArtist }; return { isLoading, albumIdsOfAnArtist };
}; };
export const useTracksOfAnAlbum = (idAlbum?: number) => { export const useTracksOfAnAlbum = (idAlbum?: ObjectId) => {
const { store } = useTrackService(); const { store } = useTrackService();
const tracksOnAnAlbum = useMemo(() => { const tracksOnAnAlbum = useMemo(() => {
if (idAlbum) { if (idAlbum) {
@ -158,7 +158,7 @@ export const useTracksOfAnAlbum = (idAlbum?: number) => {
value: idAlbum, value: idAlbum,
}, },
], ],
['track', 'name', 'id'] ['track', 'name', 'iid']
); );
} }
}, [store.data, idAlbum]); }, [store.data, idAlbum]);
@ -170,7 +170,7 @@ export const useTracksOfAnAlbum = (idAlbum?: number) => {
* @param AlbumId - Id of the album. * @param AlbumId - Id of the album.
* @returns The number of element present in this season * @returns The number of element present in this season
*/ */
export const useCountTracksWithAlbumId = (albumId?: number) => { export const useCountTracksWithAlbumId = (albumId?: ObjectId) => {
const { isLoading, tracksOnAnAlbum } = useTracksOfAnAlbum(albumId); const { isLoading, tracksOnAnAlbum } = useTracksOfAnAlbum(albumId);
const countTracksOfAnAlbum = useMemo( const countTracksOfAnAlbum = useMemo(
() => tracksOnAnAlbum?.length ?? 0, () => tracksOnAnAlbum?.length ?? 0,