[FEAT] update to new API of archidata

This commit is contained in:
Edouard DUPIN 2025-01-05 20:08:56 +01:00
parent f03a18c34c
commit 0260b4d408
49 changed files with 982 additions and 568 deletions

View File

@ -20,12 +20,12 @@
<dependency>
<groupId>kangaroo-and-rabbit</groupId>
<artifactId>archidata</artifactId>
<version>0.15.0</version>
<version>0.19.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.1.0-alpha1</version>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.11</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>

258
back/pom.xml.versionsBackup Normal file
View File

@ -0,0 +1,258 @@
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.kar</groupId>
<artifactId>karusic</artifactId>
<version>0.1.0</version>
<properties>
<maven.compiler.version>3.1</maven.compiler.version>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<maven.dependency.version>3.1.1</maven.dependency.version>
</properties>
<repositories>
<repository>
<id>gitea</id>
<url>https://gitea.atria-soft.org/api/packages/kangaroo-and-rabbit/maven</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>kangaroo-and-rabbit</groupId>
<artifactId>archidata</artifactId>
<version>0.14.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.1.0-alpha1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.18.0-rc1</version>
</dependency>
<!--
************************************************************
** TEST dependency **
************************************************************
-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.11.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.11.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.revelc.code.formatter</groupId>
<artifactId>formatter-maven-plugin</artifactId>
<version>2.24.1</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.5.0</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>src</sourceDirectory>
<testSourceDirectory>test/src</testSourceDirectory>
<directory>${project.basedir}/out/maven/</directory>
<resources>
<resource>
<directory>src/resources</directory>
</resource>
</resources>
<testResources>
<testResource>
<directory>${basedir}/test/resources</directory>
</testResource>
</testResources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.version}</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.4.0</version>
<configuration>
<mainClass>org.kar.karusic.WebLauncher</mainClass>
</configuration>
</plugin>
<!-- Create the source bundle -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- junit results -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>fully.qualified.MainClass</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
<!-- Create coverage -->
<!--
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.10</version>
<executions>
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
<execution>
<id>jacoco-check</id>
<goals>
<goal>check</goal>
</goals>
<configuration>
<rules>
<rule>
<element>PACKAGE</element>
<limits>
<limit>
<counter>LINE</counter>
<value>COVEREDRATIO</value>
<minimum>0.50</minimum>
</limit>
</limits>
</rule>
</rules>
</configuration>
</execution>
</executions>
</plugin>
-->
<!-- Java-doc generation for stand-alone site -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<show>private</show>
<nohelp>true</nohelp>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>exec-application</id>
<phase>package</phase>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>org.kar.karusic.WebLauncher</mainClass>
</configuration>
</plugin>
<!-- Check the style of the code -->
<plugin>
<groupId>net.revelc.code.formatter</groupId>
<artifactId>formatter-maven-plugin</artifactId>
<version>2.23.0</version>
<configuration>
<encoding>UTF-8</encoding>
<lineEnding>LF</lineEnding>
<configFile>Formatter.xml</configFile>
<directories>
<directory>src/</directory>
<directory>test/src</directory>
</directories>
<includes>
<include>**/*.java</include>
</includes>
<excludes>
<exclude>module-info.java</exclude>
</excludes>
</configuration>
<executions>
<execution>
<goals>
<goal>validate</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<version>4.8.5.0</version>
<configuration>
<includeFilterFile>spotbugs-security-include.xml</includeFilterFile>
<excludeFilterFile>spotbugs-security-exclude.xml</excludeFilterFile>
<!--<plugins>
<plugin>
<groupId>com.h3xstream.findsecbugs</groupId>
<artifactId>findsecbugs-plugin</artifactId>
<version>1.12.0</version>
</plugin>
</plugins>
-->
</configuration>
</plugin>
</plugins>
</build>
<!-- Generate Java-docs As Part Of Project Reports -->
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<show>public</show>
</configuration>
</plugin>
</plugins>
</reporting>
</project>

View File

@ -0,0 +1,27 @@
package org.kar.karusic.CodecBson;
import java.util.UUID;
import org.bson.BsonReader;
import org.bson.BsonWriter;
import org.bson.codecs.Codec;
import org.bson.codecs.DecoderContext;
import org.bson.codecs.EncoderContext;
public class UUIDCodec implements Codec<UUID> {
@Override
public UUID decode(final BsonReader reader, final DecoderContext decoderContext) {
return UUID.fromString(reader.readString());
}
@Override
public void encode(final BsonWriter writer, final UUID value, final EncoderContext encoderContext) {
writer.writeString(value.toString());
}
@Override
public Class<UUID> getEncoderClass() {
return UUID.class;
}
}

View File

@ -12,15 +12,17 @@ import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.kar.archidata.GlobalConfiguration;
import org.kar.archidata.UpdateJwtPublicKey;
import org.kar.archidata.api.DataResource;
import org.kar.archidata.api.ProxyResource;
import org.kar.archidata.catcher.GenericCatcher;
import org.kar.archidata.db.DbConfig;
import org.kar.archidata.exception.DataAccessException;
import org.kar.archidata.filter.CORSFilter;
import org.kar.archidata.filter.OptionFilter;
import org.kar.archidata.migration.MigrationEngine;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.kar.archidata.tools.ContextGenericTools;
import org.kar.karusic.api.AlbumResource;
import org.kar.karusic.api.ArtistResource;
import org.kar.karusic.api.Front;
@ -35,6 +37,8 @@ import org.kar.karusic.migration.Migration20231126;
import org.kar.karusic.migration.Migration20240225;
import org.kar.karusic.migration.Migration20240226;
import org.kar.karusic.migration.Migration20240907;
import org.kar.karusic.migration.Migration20250104;
import org.kar.karusic.migration.Migration20250105;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -63,8 +67,10 @@ public class WebLauncher {
migrationEngine.add(new Migration20240225());
migrationEngine.add(new Migration20240226());
migrationEngine.add(new Migration20240907());
migrationEngine.add(new Migration20250104());
migrationEngine.add(new Migration20250105());
WebLauncher.LOGGER.info("Migrate the DB [START]");
migrationEngine.migrateWaitAdmin(GlobalConfiguration.dbConfig);
migrationEngine.migrateWaitAdmin(new DbConfig());
WebLauncher.LOGGER.info("Migrate the DB [STOP]");
}
@ -83,26 +89,26 @@ public class WebLauncher {
public void plop(final String aaa) {
// List available Image Readers
System.out.println("Available Image Readers:");
WebLauncher.LOGGER.trace("Available Image Readers:");
final Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName(aaa);
while (readers.hasNext()) {
final ImageReader reader = readers.next();
System.out.println("Reader: " + reader.getOriginatingProvider().getDescription(null));
System.out.println("Reader CN: " + reader.getOriginatingProvider().getPluginClassName());
WebLauncher.LOGGER.trace("Reader: " + reader.getOriginatingProvider().getDescription(null));
WebLauncher.LOGGER.trace("Reader CN: " + reader.getOriginatingProvider().getPluginClassName());
// ImageIO.deregisterServiceProvider(reader.getOriginatingProvider());
}
// List available Image Writers
System.out.println("\nAvailable Image Writers:");
WebLauncher.LOGGER.trace("\nAvailable Image Writers:");
final Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(aaa);
while (writers.hasNext()) {
final ImageWriter writer = writers.next();
System.out.println("Writer: " + writer.getOriginatingProvider().getDescription(null));
System.out.println("Writer CN: " + writer.getOriginatingProvider().getPluginClassName());
WebLauncher.LOGGER.trace("Writer: " + writer.getOriginatingProvider().getDescription(null));
WebLauncher.LOGGER.trace("Writer CN: " + writer.getOriginatingProvider().getPluginClassName());
}
}
public void process() throws InterruptedException {
public void process() throws InterruptedException, DataAccessException {
ImageIO.scanForPlugins();
plop("jpeg");
@ -137,6 +143,8 @@ public class WebLauncher {
rc.register(HealthCheck.class);
rc.register(Front.class);
ContextGenericTools.addJsr310(rc);
// add jackson to be discover when we are ins standalone server
rc.register(JacksonFeature.class);
// enable this to show low level request
@ -148,7 +156,7 @@ public class WebLauncher {
// System.out.println(" getDBLogin: '" + ConfigVariable.getDBLogin() + "'");
// System.out.println(" getDBPassword: '" + ConfigVariable.getDBPassword() + "'");
// System.out.println(" getDBName: '" + ConfigVariable.getDBName() + "'");
System.out.println(" ==> " + GlobalConfiguration.dbConfig);
System.out.println(" ==> " + new DbConfig());
System.out.println("OAuth service " + getBaseURI());
this.server = GrizzlyHttpServerFactory.createHttpServer(getBaseURI(), rc);
final HttpServer serverLink = this.server;

View File

@ -4,6 +4,7 @@ import java.util.List;
import org.kar.archidata.api.DataResource;
import org.kar.archidata.api.ProxyResource;
import org.kar.archidata.exception.DataAccessException;
import org.kar.archidata.externalRestApi.AnalyzeApi;
import org.kar.archidata.externalRestApi.TsGenerateApi;
import org.kar.archidata.tools.ConfigBaseVariable;
@ -43,7 +44,7 @@ public class WebLauncherLocal extends WebLauncher {
}
@Override
public void process() throws InterruptedException {
public void process() throws InterruptedException, DataAccessException {
if (true) {
// for local test:
ConfigBaseVariable.apiAdress = "http://0.0.0.0:19080/karusic/api/";

View File

@ -9,9 +9,9 @@ import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.annotation.AsyncType;
import org.kar.archidata.annotation.FormDataOptional;
import org.kar.archidata.annotation.TypeScriptProgress;
import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.addOn.AddOnDataJson;
import org.kar.archidata.dataAccess.addOn.AddOnManyToMany;
import org.kar.archidata.dataAccess.addOnSQL.AddOnDataJson;
import org.kar.archidata.dataAccess.options.CheckFunction;
import org.kar.archidata.tools.DataTools;
import org.kar.karusic.model.Album;
@ -41,8 +41,9 @@ public class AlbumResource {
@Path("{id}")
@RolesAllowed("USER")
@Operation(description = "Get a specific Album with his ID")
public static Album get(@PathParam("id") final Long id) throws Exception {
public Album get(@PathParam("id") final Long id) throws Exception {
return DataAccess.get(Album.class, id);
// return this.morphiaService.getDatastore().find(Album.class).filter(Filters.eq("id", id)).first();
}
@GET
@ -50,6 +51,8 @@ public class AlbumResource {
@Operation(description = "Get all the available Albums")
public List<Album> gets() throws Exception {
return DataAccess.gets(Album.class);
// final Query<Album> query = this.morphiaService.getDatastore().find(Album.class);
// return query.stream().toList();
}
@POST
@ -57,6 +60,12 @@ public class AlbumResource {
@Consumes(MediaType.APPLICATION_JSON)
@Operation(description = "Add an album (when all the data already exist)")
public Album post(final Album data) throws Exception {
// TODO: how to manage the checker ???
// final Album ret = this.morphiaService.getDatastore().save(data);
// return ret;
/* final MongoCollection<Track> trackCollection = db.getCollection("TTRACLK", Track.class); final InsertOneResult res = trackCollection.insertOne(plop); LOGGER.warn("plpop {}", res); final
* ObjectId ploppppp = res.getInsertedId().asObjectId().getValue(); LOGGER.warn("plpop 2522 {}", res.getInsertedId().asObjectId().getValue()); final Track ret =
* trackCollection.find(Filters.eq("_id", res.getInsertedId().asObjectId().getValue())) .first(); System.out.println("Grade found:\t" + ret); */
return DataAccess.insert(data, new CheckFunction(CHECKER));
}
@ -66,37 +75,45 @@ public class AlbumResource {
@Consumes(MediaType.APPLICATION_JSON)
@Operation(description = "Update a specific album")
public Album patch(@PathParam("id") final Long id, @AsyncType(Album.class) final String jsonRequest) throws Exception {
// final Query<Album> query = this.morphiaService.getDatastore().find(Album.class).filter(Filters.eq("id", id));
// final UpdateOperations<Album> ops = this.morphiaService.getDatastore().createUpdateOperations(Album.class)
// .set("name", master.getName());
// this.morphiaService.getDatastore().update(query, ops);
// return Response.ok(master).build();
DataAccess.updateWithJson(Album.class, id, jsonRequest, new CheckFunction(CHECKER));
return DataAccess.get(Album.class, id);
}
// @PUT
// @Path("{id}")
// @RolesAllowed("ADMIN")
// @Consumes(MediaType.APPLICATION_JSON)
// @Operation(description = "Update a specific album")
// public Album put(@PathParam("id") final Long id, final Album album)
// throws Exception {
// final Query<Album> query = this.morphiaService.getDatastore().find(Album.class).filter(Filters.eq("id", id));
// final UpdateOperations<Album> ops = this.morphiaService.getDatastore().createUpdateOperations(Album.class)
// .set("name", album.getName());
// this.morphiaService.getDatastore().update(query, ops);
// return Response.ok(album).build();
// }
@DELETE
@Path("{id}")
@RolesAllowed("ADMIN")
@Operation(description = "Remove a specific album")
public void remove(@PathParam("id") final Long id) throws Exception {
DataAccess.delete(Album.class, id);
// this.morphiaService.getDatastore().find(Album.class).filter(Filters.eq("id", id)).delete();
}
@POST
@Path("{id}/track/{trackId}")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
@Operation(description = "Add a Track on a specific album")
public Album addTrack(@PathParam("id") final Long id, @PathParam("trackId") final Long trackId) throws Exception {
AddOnManyToMany.removeLink(Album.class, id, "track", trackId);
return DataAccess.get(Album.class, id);
}
@DELETE
@Path("{id}/track/{trackId}")
@RolesAllowed("ADMIN")
@Operation(description = "Remove a Track on a specific album")
public Album removeTrack(@PathParam("id") final Long id, @PathParam("trackId") final Long trackId) throws Exception {
AddOnManyToMany.removeLink(Album.class, id, "track", trackId);
return DataAccess.get(Album.class, id);
}
/* @POST
* @Path("{id}/track/{trackId}")
* @RolesAllowed("ADMIN")
* @Consumes({ MediaType.MULTIPART_FORM_DATA })
* @Operation(description = "Add a Track on a specific album") public Album addTrack(@PathParam("id") final Long id, @PathParam("trackId") final Long trackId) throws Exception {
* AddOnManyToMany.removeLink(this.dam, Album.class, id, "track", trackId); return this.dam.get(Album.class, id); } */
@POST
@Path("{id}/cover")
@RolesAllowed("ADMIN")
@ -105,12 +122,14 @@ public class AlbumResource {
@TypeScriptProgress
public Album uploadCover(@PathParam("id") final Long id, @FormDataOptional @FormDataParam("uri") final String uri, @FormDataOptional @FormDataParam("file") final InputStream fileInputStream,
@FormDataOptional @FormDataParam("file") final FormDataContentDisposition fileMetaData) throws Exception {
if (uri != null) {
DataTools.uploadCoverFromUri(Album.class, id, uri);
} else {
DataTools.uploadCover(Album.class, id, fileInputStream, fileMetaData);
try (DBAccess db = DBAccess.createInterface()) {
if (uri != null) {
DataTools.uploadCoverFromUri(db, Album.class, id, uri);
} else {
DataTools.uploadCover(db, Album.class, id, fileInputStream, fileMetaData);
}
return db.get(Album.class, id);
}
return DataAccess.get(Album.class, id);
}
@DELETE
@ -118,7 +137,9 @@ public class AlbumResource {
@RolesAllowed("ADMIN")
@Operation(description = "Remove a cover on a specific album")
public Album removeCover(@PathParam("id") final Long id, @PathParam("coverId") final UUID coverId) throws Exception {
AddOnDataJson.removeLink(Album.class, id, "covers", coverId);
return DataAccess.get(Album.class, id);
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Album.class, "id", id, "covers", coverId);
return db.get(Album.class, id);
}
}
}

View File

@ -2,15 +2,16 @@ package org.kar.karusic.api;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;
import org.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.annotation.AsyncType;
import org.kar.archidata.annotation.FormDataOptional;
import org.kar.archidata.annotation.TypeScriptProgress;
import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.addOn.AddOnDataJson;
import org.kar.archidata.dataAccess.addOnSQL.AddOnDataJson;
import org.kar.archidata.dataAccess.options.CheckFunction;
import org.kar.archidata.tools.DataTools;
import org.kar.karusic.model.Artist;
@ -38,7 +39,7 @@ public class ArtistResource {
@GET
@Path("{id}")
@RolesAllowed("USER")
public static Artist get(@PathParam("id") final Long id) throws Exception {
public Artist get(@PathParam("id") final Long id) throws Exception {
return DataAccess.get(Artist.class, id);
}
@ -78,20 +79,23 @@ public class ArtistResource {
@TypeScriptProgress
public Artist uploadCover(@PathParam("id") final Long id, @FormDataOptional @FormDataParam("uri") final String uri, @FormDataOptional @FormDataParam("file") final InputStream fileInputStream,
@FormDataOptional @FormDataParam("file") final FormDataContentDisposition fileMetaData) throws Exception {
if (uri != null) {
DataTools.uploadCoverFromUri(Artist.class, id, uri);
} else {
DataTools.uploadCover(Artist.class, id, fileInputStream, fileMetaData);
try (DBAccess db = DBAccess.createInterface()) {
if (uri != null) {
DataTools.uploadCoverFromUri(db, Artist.class, id, uri);
} else {
DataTools.uploadCover(db, Artist.class, id, fileInputStream, fileMetaData);
}
return db.get(Artist.class, id);
}
return DataAccess.get(Artist.class, id);
}
@DELETE
@Path("{id}/cover/{coverId}")
@RolesAllowed("ADMIN")
public Artist removeCover(@PathParam("id") final Long id, @PathParam("coverId") final UUID coverId) throws Exception {
LOGGER.error("klmlmkmlkmlklmklmk");
AddOnDataJson.removeLink(Artist.class, id, "covers", coverId);
return DataAccess.get(Artist.class, id);
public Artist removeCover(@PathParam("id") final Long id, @PathParam("coverId") final ObjectId coverId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Artist.class, "id", id, "covers", coverId);
return db.get(Artist.class, id);
}
}
}

View File

@ -2,15 +2,16 @@ package org.kar.karusic.api;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;
import org.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.annotation.AsyncType;
import org.kar.archidata.annotation.FormDataOptional;
import org.kar.archidata.annotation.TypeScriptProgress;
import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.addOn.AddOnDataJson;
import org.kar.archidata.dataAccess.addOnSQL.AddOnDataJson;
import org.kar.archidata.dataAccess.options.CheckFunction;
import org.kar.archidata.tools.DataTools;
import org.kar.karusic.model.Gender;
@ -38,7 +39,7 @@ public class GenderResource {
@GET
@Path("{id}")
@RolesAllowed("USER")
public static Gender get(@PathParam("id") final Long id) throws Exception {
public Gender get(@PathParam("id") final Long id) throws Exception {
return DataAccess.get(Gender.class, id);
}
@ -78,19 +79,23 @@ public class GenderResource {
@TypeScriptProgress
public Gender uploadCover(@PathParam("id") final Long id, @FormDataOptional @FormDataParam("uri") final String uri, @FormDataOptional @FormDataParam("file") final InputStream fileInputStream,
@FormDataOptional @FormDataParam("file") final FormDataContentDisposition fileMetaData) throws Exception {
if (uri != null) {
DataTools.uploadCoverFromUri(Gender.class, id, uri);
} else {
DataTools.uploadCover(Gender.class, id, fileInputStream, fileMetaData);
try (DBAccess db = DBAccess.createInterface()) {
if (uri != null) {
DataTools.uploadCoverFromUri(db, Gender.class, id, uri);
} else {
DataTools.uploadCover(db, Gender.class, id, fileInputStream, fileMetaData);
}
return db.get(Gender.class, id);
}
return DataAccess.get(Gender.class, id);
}
@DELETE
@Path("{id}/cover/{coverId}")
@RolesAllowed("ADMIN")
public Gender removeCover(@PathParam("id") final Long id, @PathParam("coverId") final UUID coverId) throws Exception {
AddOnDataJson.removeLink(Gender.class, id, "covers", coverId);
return DataAccess.get(Gender.class, id);
public Gender removeCover(@PathParam("id") final Long id, @PathParam("coverId") final ObjectId coverId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Gender.class, "id", id, "covers", coverId);
return db.get(Gender.class, id);
}
}
}

View File

@ -2,14 +2,14 @@ package org.kar.karusic.api;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;
import org.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.annotation.AsyncType;
import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.addOn.AddOnDataJson;
import org.kar.archidata.dataAccess.addOn.AddOnManyToMany;
import org.kar.archidata.dataAccess.addOnSQL.AddOnDataJson;
import org.kar.archidata.dataAccess.options.CheckFunction;
import org.kar.archidata.tools.DataTools;
import org.kar.karusic.model.Playlist;
@ -37,7 +37,7 @@ public class PlaylistResource {
@GET
@Path("{id}")
@RolesAllowed("USER")
public static Playlist get(@PathParam("id") final Long id) throws Exception {
public Playlist get(@PathParam("id") final Long id) throws Exception {
return DataAccess.get(Playlist.class, id);
}
@ -75,16 +75,20 @@ public class PlaylistResource {
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
public Playlist addTrack(@PathParam("id") final Long id, @PathParam("trackId") final Long trackId) throws Exception {
AddOnManyToMany.removeLink(Playlist.class, id, "track", trackId);
return DataAccess.get(Playlist.class, id);
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Playlist.class, "id", id, "track", trackId);
return db.get(Playlist.class, id);
}
}
@DELETE
@Path("{id}/track/{trackId}")
@RolesAllowed("ADMIN")
public Playlist removeTrack(@PathParam("id") final Long id, @PathParam("trackId") final Long trackId) throws Exception {
AddOnManyToMany.removeLink(Playlist.class, id, "track", trackId);
return DataAccess.get(Playlist.class, id);
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Playlist.class, "id", id, "track", trackId);
return db.get(Playlist.class, id);
}
}
@POST
@ -94,14 +98,18 @@ public class PlaylistResource {
@AsyncType(Playlist.class)
public void uploadCover(@PathParam("id") final Long id, @FormDataParam("file") final InputStream fileInputStream, @FormDataParam("file") final FormDataContentDisposition fileMetaData)
throws Exception {
DataTools.uploadCover(Playlist.class, id, fileInputStream, fileMetaData);
try (DBAccess db = DBAccess.createInterface()) {
DataTools.uploadCover(db, Playlist.class, id, fileInputStream, fileMetaData);
}
}
@DELETE
@Path("{id}/cover/{coverId}")
@RolesAllowed("ADMIN")
public Playlist removeCover(@PathParam("id") final Long id, @PathParam("coverId") final UUID coverId) throws Exception {
AddOnDataJson.removeLink(Playlist.class, id, "covers", coverId);
return DataAccess.get(Playlist.class, id);
public Playlist removeCover(@PathParam("id") final Long id, @PathParam("coverId") final ObjectId coverId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Playlist.class, "id", id, "covers", coverId);
return DataAccess.get(Playlist.class, id);
}
}
}

View File

@ -5,16 +5,16 @@ import java.io.InputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.annotation.AsyncType;
import org.kar.archidata.annotation.FormDataOptional;
import org.kar.archidata.annotation.TypeScriptProgress;
import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.addOn.AddOnDataJson;
import org.kar.archidata.dataAccess.addOn.AddOnManyToMany;
import org.kar.archidata.dataAccess.addOnSQL.AddOnDataJson;
import org.kar.archidata.dataAccess.options.CheckFunction;
import org.kar.archidata.model.Data;
import org.kar.archidata.tools.DataTools;
@ -44,7 +44,7 @@ public class TrackResource {
@GET
@Path("{id}")
@RolesAllowed("USER")
public static Track get(@PathParam("id") final Long id) throws Exception {
public Track get(@PathParam("id") final Long id) throws Exception {
return DataAccess.get(Track.class, id);
}
@ -82,16 +82,20 @@ public class TrackResource {
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
public Track addTrack(@PathParam("id") final Long id, @PathParam("artistId") final Long artistId) throws Exception {
AddOnManyToMany.removeLink(Track.class, id, "artist", artistId);
return DataAccess.get(Track.class, id);
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Track.class, "id", id, "artist", artistId);
return DataAccess.get(Track.class, id);
}
}
@DELETE
@Path("{id}/artist/{trackId}")
@RolesAllowed("ADMIN")
public Track removeTrack(@PathParam("id") final Long id, @PathParam("artistId") final Long artistId) throws Exception {
AddOnManyToMany.removeLink(Track.class, id, "artist", artistId);
return DataAccess.get(Track.class, id);
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Track.class, "id", id, "artist", artistId);
return DataAccess.get(Track.class, id);
}
}
@POST
@ -101,20 +105,24 @@ public class TrackResource {
@TypeScriptProgress
public Track uploadCover(@PathParam("id") final Long id, @FormDataParam("uri") final String uri, @FormDataParam("file") final InputStream fileInputStream,
@FormDataParam("file") final FormDataContentDisposition fileMetaData) throws Exception {
if (uri != null) {
DataTools.uploadCoverFromUri(Track.class, id, uri);
} else {
DataTools.uploadCover(Track.class, id, fileInputStream, fileMetaData);
try (DBAccess db = DBAccess.createInterface()) {
if (uri != null) {
DataTools.uploadCoverFromUri(db, Track.class, id, uri);
} else {
DataTools.uploadCover(db, Track.class, id, fileInputStream, fileMetaData);
}
return DataAccess.get(Track.class, id);
}
return DataAccess.get(Track.class, id);
}
@DELETE
@Path("{id}/cover/{coverId}")
@RolesAllowed("ADMIN")
public Track removeCover(@PathParam("id") final Long id, @PathParam("coverId") final UUID coverId) throws Exception {
AddOnDataJson.removeLink(Track.class, id, "covers", coverId);
return DataAccess.get(Track.class, id);
public Track removeCover(@PathParam("id") final Long id, @PathParam("coverId") final ObjectId coverId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Track.class, "id", id, "covers", coverId);
return db.get(Track.class, id);
}
}
@POST
@ -132,7 +140,7 @@ public class TrackResource {
@FormDataParam("file") final InputStream fileInputStream, //
@FormDataParam("file") final FormDataContentDisposition fileMetaData //
) {
try {
try (DBAccess db = DBAccess.createInterface()) {
// correct input string stream :
trackId = DataTools.multipartCorrection(trackId);
albumId = DataTools.multipartCorrection(albumId);
@ -153,12 +161,12 @@ public class TrackResource {
final long tmpUID = DataTools.getTmpDataId();
final String sha512 = DataTools.saveTemporaryFile(fileInputStream, tmpUID);
Data data = DataTools.getWithSha512(sha512);
Data data = DataTools.getWithSha512(db, sha512);
if (data == null) {
LOGGER.info("Need to add the data in the BDD ... ");
try {
data = DataTools.createNewData(tmpUID, fileMetaData.getFileName(), sha512);
data = DataTools.createNewData(db, tmpUID, fileMetaData.getFileName(), sha512);
} catch (final IOException ex) {
DataTools.removeTemporaryFile(tmpUID);
ex.printStackTrace();
@ -170,7 +178,7 @@ public class TrackResource {
}
} else if (data.deleted) {
LOGGER.info("Data already exist but deleted");
DataTools.undelete(data.uuid);
DataTools.undelete(db, data.oid);
data.deleted = false;
} else {
LOGGER.info("Data already exist ... all good");
@ -182,14 +190,14 @@ public class TrackResource {
trackElem.track = trackId != null ? Long.parseLong(trackId) : null;
trackElem.albumId = albumId != null ? Long.parseLong(albumId) : null;
trackElem.genderId = genderId != null ? Long.parseLong(genderId) : null;
trackElem.dataId = data.uuid;
trackElem.dataId = data.oid;
// Now list of artist has an internal management:
if (artistId != null) {
trackElem.artists = new ArrayList<>();
trackElem.artists.add(artistId != null ? Long.parseLong(artistId) : null);
}
trackElem = DataAccess.insert(trackElem, new CheckFunction(CHECKER));
/* Old mode of artist insertion (removed due to the slowlest request of getting value if (artistElem != null) { DataAccess.addLink(Track.class, trackElem.id, "artist", artistElem.id); } */
/* Old mode of artist insertion (removed due to the slowlest request of getting value if (artistElem != null) { this.dam.addLink(Track.class, trackElem.id, "artist", artistElem.id); } */
return Response.ok(trackElem).build();
} catch (final Exception ex) {
LOGGER.info("Catch an unexpected error ... {}", ex.getMessage());

View File

@ -2,7 +2,7 @@ package org.kar.karusic.migration;
import java.util.List;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.migration.MigrationSqlStep;
import org.kar.archidata.model.Data;
import org.kar.archidata.model.User;
@ -35,35 +35,35 @@ public class Initialization extends MigrationSqlStep {
addClass(elem);
}
addAction("""
INSERT INTO `gender` (`id`, `name`, `description`) VALUES
(1, 'Variété française', NULL),
(2, 'Pop', NULL),
(3, 'inconnue', NULL),
(4, 'Disco', NULL),
(5, 'Enfants', NULL),
(6, 'Portugaise', NULL),
(7, 'Apprentissage', NULL),
(8, 'Blues', NULL),
(9, 'Jazz', NULL),
(10, 'Chanson Noël', NULL),
(11, 'DubStep', NULL),
(12, 'Rap français', NULL),
(13, 'Classique', NULL),
(14, 'Rock', NULL),
(15, 'Electro', NULL),
(16, 'Celtique', NULL),
(17, 'Country', NULL),
(18, 'Variété Québéquoise', NULL),
(19, 'Médiéval', NULL),
(20, 'Variété Italienne', NULL),
(21, 'Comédie Musicale', NULL),
(22, 'Vianney', NULL),
(23, 'Bande Original', NULL),
(24, 'Bande Originale', NULL),
(25, 'Variété Belge', NULL),
(26, 'Gospel', NULL);
""");
addAction((final DBAccess da) -> {
final List<Gender> data = List.of(//
new Gender(1L, "Variété française"), //
new Gender(2L, "Pop"), //
new Gender(3L, "inconnue"), //
new Gender(4L, "Disco"), //
new Gender(5L, "Enfants"), //
new Gender(6L, "Portugaise"), //
new Gender(7L, "Apprentissage"), //
new Gender(8L, "Blues"), //
new Gender(9L, "Jazz"), //
new Gender(10L, "Chanson Noël"), //
new Gender(11L, "DubStep"), //
new Gender(12L, "Rap français"), //
new Gender(13L, "Classique"), //
new Gender(14L, "Rock"), //
new Gender(15L, "Electro"), //
new Gender(16L, "Celtique"), //
new Gender(17L, "Country"), //
new Gender(18L, "Variété Québéquoise"), //
new Gender(19L, "Médiéval"), //
new Gender(20L, "Variété Italienne"), //
new Gender(21L, "Comédie Musicale"), //
new Gender(22L, "Vianney"), //
new Gender(23L, "Bande Original"), //
new Gender(24L, "Bande Originale"), //
new Gender(25L, "Variété Belge"), //
new Gender(26L, "Gospel"));
});
// set start increment element to permit to add after default elements
addAction("""
ALTER TABLE `album` AUTO_INCREMENT = 1000;
@ -85,10 +85,10 @@ public class Initialization extends MigrationSqlStep {
""", "mysql");
}
public static void dropAll() {
public static void dropAll(final DBAccess da) {
for (final Class<?> element : CLASSES_BASE) {
try {
DataAccess.drop(element);
da.drop(element);
} catch (final Exception ex) {
LOGGER.error("Fail to drop table !!!!!!");
ex.printStackTrace();
@ -96,10 +96,10 @@ public class Initialization extends MigrationSqlStep {
}
}
public static void cleanAll() {
public static void cleanAll(final DBAccess da) {
for (final Class<?> element : CLASSES_BASE) {
try {
DataAccess.cleanAll(element);
da.cleanAll(element);
} catch (final Exception ex) {
LOGGER.error("Fail to clean table !!!!!!");
ex.printStackTrace();

View File

@ -11,159 +11,4 @@ public class Migration20231126 extends MigrationSqlStep {
return "migration-2023-11-26: reorder the migration for the new API of archidata";
}
public Migration20231126() {
}
@Override
public void generateStep() throws Exception {
// update migration update (last one)
addAction("""
ALTER TABLE `KAR_migration`
CHANGE `id` `id` bigint NOT NULL COMMENT 'Primary key of the base' AUTO_INCREMENT FIRST,
CHANGE `create_date` `createdAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'Create time of the object' AFTER `id`,
CHANGE `modify_date` `updatedAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'When update the object' AFTER `createdAt`,
CHANGE `deleted` `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'When delete, they are not removed, they are just set in a deleted state' AFTER `updatedAt`,
ADD `version` int NOT NULL DEFAULT '2' AFTER `deleted`,
CHANGE `name` `name` varchar(256) COLLATE 'utf8mb4_0900_ai_ci' NULL COMMENT 'Name of the migration' AFTER `version`,
CHANGE `terminated` `terminated` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'if the migration is well terminated or not' AFTER `name`,
CHANGE `stepId` `stepId` int NULL COMMENT 'index in the migration progression' AFTER `terminated`,
CHANGE `count` `count` int NULL COMMENT 'number of element in the migration' AFTER `stepId`,
CHANGE `log` `log` text COLLATE 'utf8mb3_general_ci' NULL COMMENT 'Log generate by the migration' AFTER `count`;
""");
addAction("""
ALTER TABLE `album`
CHANGE `id` `id` bigint NOT NULL COMMENT 'Primary key of the base' AUTO_INCREMENT FIRST,
CHANGE `create_date` `createdAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'Create time of the object' AFTER `id`,
CHANGE `modify_date` `updatedAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'When update the object' AFTER `createdAt`,
CHANGE `deleted` `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'When delete, they are not removed, they are just set in a deleted state' AFTER `updatedAt`,
CHANGE `name` `name` varchar(256) COLLATE 'utf8mb4_0900_ai_ci' NULL AFTER `deleted`,
CHANGE `description` `description` text COLLATE 'utf8mb3_general_ci' NULL AFTER `name`,
CHANGE `publication` `publication` date NULL AFTER `description`;
""");
addAction("""
ALTER TABLE `album_link_cover`
CHANGE `create_date` `createdAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) AFTER `id`,
CHANGE `modify_date` `updatedAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) AFTER `createdAt`,
CHANGE `deleted` `deleted` tinyint(1) NOT NULL DEFAULT '0' AFTER `updatedAt`,
CHANGE `album_id` `object1id` bigint NOT NULL AFTER `deleted`,
CHANGE `cover_id` `object2id` bigint NOT NULL AFTER `object1id`;
""");
addAction("""
ALTER TABLE `artist`
CHANGE `id` `id` bigint NOT NULL COMMENT 'Primary key of the base' AUTO_INCREMENT FIRST,
CHANGE `create_date` `createdAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'Create time of the object' AFTER `id`,
CHANGE `modify_date` `updatedAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'When update the object' AFTER `createdAt`,
CHANGE `deleted` `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'When delete, they are not removed, they are just set in a deleted state' AFTER `updatedAt`,
CHANGE `firstName` `firstName` varchar(256) COLLATE 'utf8mb4_0900_ai_ci' NULL AFTER `description`,
CHANGE `surname` `surname` varchar(256) COLLATE 'utf8mb4_0900_ai_ci' NULL AFTER `firstName`,
CHANGE `birth` `birth` date NULL AFTER `surname`,
CHANGE `death` `death` date NULL AFTER `birth`;
""");
addAction("""
ALTER TABLE `artist_link_cover`
CHANGE `create_date` `createdAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) AFTER `id`,
CHANGE `modify_date` `updatedAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) AFTER `createdAt`,
CHANGE `deleted` `deleted` tinyint(1) NOT NULL DEFAULT '0' AFTER `updatedAt`,
CHANGE `artist_id` `object1id` bigint NOT NULL AFTER `deleted`,
CHANGE `cover_id` `object2id` bigint NOT NULL AFTER `object1id`;
""");
addAction("""
ALTER TABLE `data`
CHANGE `id` `id` bigint NOT NULL COMMENT 'Primary key of the base' AUTO_INCREMENT FIRST,
CHANGE `create_date` `createdAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'Create time of the object' AFTER `id`,
CHANGE `modify_date` `updatedAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'When update the object' AFTER `createdAt`,
CHANGE `deleted` `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'When delete, they are not removed, they are just set in a deleted state' AFTER `updatedAt`,
CHANGE `sha512` `sha512` varchar(128) COLLATE 'utf8mb4_0900_ai_ci' NOT NULL COMMENT 'Sha512 of the data' AFTER `deleted`,
CHANGE `mimeType` `mimeType` varchar(128) COLLATE 'utf8mb4_0900_ai_ci' NOT NULL COMMENT 'Mime -type of the media' AFTER `sha512`,
CHANGE `size` `size` bigint NOT NULL COMMENT 'Size in Byte of the data' AFTER `mimeType`;
""");
addAction("""
ALTER TABLE `gender`
CHANGE `id` `id` bigint NOT NULL COMMENT 'Primary key of the base' AUTO_INCREMENT FIRST,
CHANGE `create_date` `createdAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'Create time of the object' AFTER `id`,
CHANGE `modify_date` `updatedAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'When update the object' AFTER `createdAt`,
CHANGE `name` `name` varchar(256) COLLATE 'utf8mb4_0900_ai_ci' NULL AFTER `deleted`,
CHANGE `description` `description` text COLLATE 'utf8mb3_general_ci' NULL AFTER `name`;
""");
addAction("""
ALTER TABLE `gender_link_cover`
CHANGE `create_date` `createdAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) AFTER `id`,
CHANGE `modify_date` `updatedAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) AFTER `createdAt`,
CHANGE `deleted` `deleted` tinyint(1) NOT NULL DEFAULT '0' AFTER `updatedAt`,
CHANGE `gender_id` `object1id` bigint NOT NULL AFTER `deleted`,
CHANGE `cover_id` `object2id` bigint NOT NULL AFTER `object1id`;
""");
addAction("""
ALTER TABLE `playlist`
CHANGE `id` `id` bigint NOT NULL COMMENT 'Primary key of the base' AUTO_INCREMENT FIRST,
CHANGE `create_date` `createdAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'Create time of the object' AFTER `id`,
CHANGE `modify_date` `updatedAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'When update the object' AFTER `createdAt`,
CHANGE `name` `name` varchar(256) COLLATE 'utf8mb4_0900_ai_ci' NULL AFTER `deleted`,
CHANGE `description` `description` text COLLATE 'utf8mb3_general_ci' NULL AFTER `name`;
""");
addAction("""
ALTER TABLE `playlist_link_cover`
CHANGE `create_date` `createdAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) AFTER `id`,
CHANGE `modify_date` `updatedAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) AFTER `createdAt`,
CHANGE `deleted` `deleted` tinyint(1) NOT NULL DEFAULT '0' AFTER `updatedAt`,
CHANGE `playlist_id` `object1id` bigint NOT NULL AFTER `deleted`,
CHANGE `cover_id` `object2id` bigint NOT NULL AFTER `object1id`;
""");
addAction("""
ALTER TABLE `playlist_link_track`
CHANGE `create_date` `createdAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) AFTER `id`,
CHANGE `modify_date` `updatedAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) AFTER `createdAt`,
CHANGE `deleted` `deleted` tinyint(1) NOT NULL DEFAULT '0' AFTER `updatedAt`,
CHANGE `playlist_id` `object1id` bigint NOT NULL AFTER `deleted`,
CHANGE `track_id` `object2id` bigint NOT NULL AFTER `object1id`;
""");
addAction("""
ALTER TABLE `track`
CHANGE `id` `id` bigint NOT NULL COMMENT 'Primary key of the base' AUTO_INCREMENT FIRST,
CHANGE `create_date` `createdAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'Create time of the object' AFTER `id`,
CHANGE `modify_date` `updatedAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'When update the object' AFTER `createdAt`,
CHANGE `deleted` `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'When delete, they are not removed, they are just set in a deleted state' AFTER `updatedAt`,
CHANGE `name` `name` varchar(256) COLLATE 'utf8mb4_0900_ai_ci' NULL AFTER `deleted`,
CHANGE `description` `description` text COLLATE 'utf8mb3_general_ci' NULL AFTER `name`,
CHANGE `genderId` `genderId` bigint NULL AFTER `description`,
CHANGE `albumId` `albumId` bigint NULL AFTER `genderId`,
CHANGE `track` `track` bigint NULL AFTER `albumId`,
CHANGE `dataId` `dataId` bigint NULL AFTER `track`,
CHANGE `artists` `artists` text COLLATE 'utf8mb4_0900_ai_ci' NULL AFTER `dataId`;
""");
addAction("""
ALTER TABLE `track_link_cover`
CHANGE `create_date` `createdAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) AFTER `id`,
CHANGE `modify_date` `updatedAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) AFTER `createdAt`,
CHANGE `deleted` `deleted` tinyint(1) NOT NULL DEFAULT '0' AFTER `updatedAt`,
CHANGE `track_id` `object1id` bigint NOT NULL AFTER `deleted`,
CHANGE `cover_id` `object2id` bigint NOT NULL AFTER `object1id`;
""");
addAction("""
ALTER TABLE `user`
CHANGE `id` `id` bigint NOT NULL COMMENT 'Primary key of the base' AUTO_INCREMENT FIRST,
CHANGE `create_date` `createdAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'Create time of the object' AFTER `id`,
CHANGE `modify_date` `updatedAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'When update the object' AFTER `createdAt`,
CHANGE `deleted` `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'When delete, they are not removed, they are just set in a deleted state' AFTER `updatedAt`,
CHANGE `login` `login` varchar(128) COLLATE 'utf8mb4_0900_ai_ci' NULL AFTER `deleted`,
CHANGE `lastConnection` `lastConnection` timestamp(3) NULL AFTER `login`,
CHANGE `admin` `admin` tinyint(1) NOT NULL DEFAULT '0' AFTER `lastConnection`,
CHANGE `blocked` `blocked` tinyint(1) NOT NULL DEFAULT '0' AFTER `admin`,
CHANGE `removed` `removed` tinyint(1) NOT NULL DEFAULT '0' AFTER `blocked`;
""");
addAction("""
CREATE TABLE `user_link_cover` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT 'Primary key of the base' ,
`createdAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'Create time of the object' ,
`updatedAt` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT 'When update the object' ,
`deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'When delete, they are not removed, they are just set in a deleted state' ,
`object1Id` bigint NOT NULL COMMENT 'Object reference 1' ,
`object2Id` bigint NOT NULL COMMENT 'Object reference 2' ,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
""");
}
}

View File

@ -11,16 +11,4 @@ public class Migration20240225 extends MigrationSqlStep {
return "migration-2024-02-25: change model of thrack to use real json";
}
public Migration20240225() {
}
@Override
public void generateStep() throws Exception {
// update migration update (last one)
addAction("""
UPDATE `track` SET artists = CONCAT('[', artists, ']') WHERE artists IS NOT NULL
""");
}
}

View File

@ -1,22 +1,6 @@
package org.kar.karusic.migration;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.kar.archidata.api.DataResource;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.addOn.model.LinkTableLongLong;
import org.kar.archidata.dataAccess.options.AccessDeletedItems;
import org.kar.archidata.dataAccess.options.OverrideTableName;
import org.kar.archidata.migration.MigrationSqlStep;
import org.kar.archidata.tools.UuidUtils;
import org.kar.karusic.migration.model.CoverConversion;
import org.kar.karusic.migration.model.MediaConversion;
import org.kar.karusic.migration.model.UUIDConversion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -30,106 +14,4 @@ public class Migration20240226 extends MigrationSqlStep {
return "migration-2024-02-26: convert base with UUID";
}
public Migration20240226() {
}
@Override
public void generateStep() throws Exception {
addAction("""
ALTER TABLE `data` ADD `uuid` binary(16) AFTER `id`;
""");
addAction(() -> {
final List<UUIDConversion> datas = DataAccess.gets(UUIDConversion.class, new AccessDeletedItems(), new OverrideTableName("data"));
for (final UUIDConversion elem : datas) {
elem.uuid = UuidUtils.nextUUID();
}
for (final UUIDConversion elem : datas) {
DataAccess.update(elem, elem.id, List.of("uuid"), new OverrideTableName("data"));
}
});
addAction("""
ALTER TABLE `data` CHANGE `uuid` `uuid` binary(16) DEFAULT (UUID_TO_BIN(UUID(), TRUE));
""");
final List<String> tableToTransform = List.of("album", "artist", "gender", "playlist", "track", "user");
for (final String tableName : tableToTransform) {
addAction("ALTER TABLE `" + tableName + "` ADD `covers` text NULL;");
addAction(() -> {
final List<UUIDConversion> datas = DataAccess.gets(UUIDConversion.class, new AccessDeletedItems(), new OverrideTableName("data"));
final List<CoverConversion> medias = DataAccess.gets(CoverConversion.class, new AccessDeletedItems(), new OverrideTableName(tableName));
final List<LinkTableLongLong> links = DataAccess.gets(LinkTableLongLong.class, new OverrideTableName(tableName + "_link_cover"));
LOGGER.info("Get somes data: {} {} {}", datas.size(), medias.size(), links.size());
for (final CoverConversion media : medias) {
final List<UUID> values = new ArrayList<>();
for (final LinkTableLongLong link : links) {
if (link.object1Id.equals(media.id)) {
for (final UUIDConversion data : datas) {
if (data.id.equals(link.object2Id)) {
values.add(data.uuid);
break;
}
}
break;
}
}
if (values.size() != 0) {
media.covers = values;
LOGGER.info(" update: {} => {}", media.id, media.covers);
DataAccess.update(media, media.id, List.of("covers"), new OverrideTableName(tableName));
}
}
});
addAction("DROP TABLE `" + tableName + "_link_cover`;");
}
addAction("""
ALTER TABLE `track` ADD `dataUUID` binary(16) AFTER dataId;
""");
addAction(() -> {
final List<UUIDConversion> datas = DataAccess.gets(UUIDConversion.class, new AccessDeletedItems(), new OverrideTableName("data"));
final List<MediaConversion> medias = DataAccess.gets(MediaConversion.class, new AccessDeletedItems(), new OverrideTableName("track"));
for (final MediaConversion media : medias) {
for (final UUIDConversion data : datas) {
if (data.id.equals(media.dataId)) {
media.dataUUID = data.uuid;
DataAccess.update(media, media.id, List.of("dataUUID"), new OverrideTableName("track"));
break;
}
}
}
});
addAction("""
DROP TABLE `playlist`;
""");
addAction("""
DROP TABLE `playlist_link_track`;
""");
addAction("""
ALTER TABLE `track` DROP `dataId`;
""");
addAction("""
ALTER TABLE `track` CHANGE `dataUUID` `dataId` binary(16) NOT NULL;
""");
// Move the files...
addAction(() -> {
final List<UUIDConversion> datas = DataAccess.gets(UUIDConversion.class, new AccessDeletedItems(), new OverrideTableName("data"));
for (final UUIDConversion data : datas) {
final String origin = DataResource.getFileDataOld(data.id);
final String destination = DataResource.getFileData(data.uuid);
LOGGER.info("move file = {}", origin);
LOGGER.info(" ==> {}", destination);
Files.move(Paths.get(origin), Paths.get(destination), StandardCopyOption.ATOMIC_MOVE);
}
});
addAction("""
ALTER TABLE `data` DROP `id`;
""");
addAction("""
ALTER TABLE `data` CHANGE `uuid` `id` binary(16) DEFAULT (UUID_TO_BIN(UUID(), TRUE));
""");
addAction("""
ALTER TABLE `data` ADD PRIMARY KEY `id` (`id`);
""");
}
}

View File

@ -0,0 +1,144 @@
package org.kar.karusic.migration;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.bson.types.ObjectId;
import org.kar.archidata.api.DataResource;
import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.dataAccess.options.AccessDeletedItems;
import org.kar.archidata.dataAccess.options.OverrideTableName;
import org.kar.archidata.migration.MigrationSqlStep;
import org.kar.karusic.migration.model.CoverConversion;
import org.kar.karusic.migration.model.MediaConversion;
import org.kar.karusic.migration.model.OIDConversion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Migration20250104 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-01-04: convert base from UUID to OID";
}
@Override
public void generateStep() throws Exception {
// Create a simple function to create objectId in the DB (for manual insertion ...)
// addAction("""
// DELIMITER //
//
// CREATE FUNCTION generate_objectid()
// RETURNS BINARY(12)
// DETERMINISTIC
// BEGIN
// DECLARE ts BINARY(4);
// DECLARE random_part BINARY(5);
// DECLARE counter BINARY(3);
// SET ts = UNHEX(HEX(UNIX_TIMESTAMP()));
// SET random_part = UNHEX(HEX(FLOOR(RAND() * POW(2, 40))));
// SET counter = UNHEX(HEX(FLOOR(RAND() * POW(2, 24))));
// RETURN CONCAT(ts, random_part, counter);
// END //
//
// DELIMITER ;
// """);
addAction("""
ALTER TABLE `data` ADD `_id` binary(12) AFTER `uuid`;
""");
addAction((final DBAccess da) -> {
final List<OIDConversion> datas = da.gets(OIDConversion.class, new AccessDeletedItems(), new OverrideTableName("data"));
for (final OIDConversion elem : datas) {
elem._id = new ObjectId();
}
for (final OIDConversion elem : datas) {
da.update(elem, elem.uuid, List.of("_id"), new OverrideTableName("data"));
}
});
final List<String> tableToTransform = List.of("album", "artist", "gender", "track", "user");
for (final String tableName : tableToTransform) {
addAction("ALTER TABLE `" + tableName + "` ADD `covers_oid` text NULL;");
addAction((final DBAccess da) -> {
final List<OIDConversion> datas = da.gets(OIDConversion.class, new AccessDeletedItems(), new OverrideTableName("data"));
final List<CoverConversion> tableCoverTransforms = da.gets(CoverConversion.class, new AccessDeletedItems(), new OverrideTableName(tableName));
LOGGER.info("Get somes data: {} {}", datas.size(), tableCoverTransforms.size());
for (final CoverConversion tableTransform : tableCoverTransforms) {
final List<ObjectId> values = new ArrayList<>();
if (tableTransform.covers == null) {
continue;
}
for (final UUID link : tableTransform.covers) {
for (final OIDConversion data : datas) {
if (data.uuid.equals(link)) {
values.add(data._id);
break;
}
}
}
if (values.size() != 0) {
tableTransform.covers_oid = values;
LOGGER.info(" update: {}: {} => {}", tableTransform.id, tableTransform.covers, tableTransform.covers_oid);
da.update(tableTransform, tableTransform.id, List.of("covers_oid"), new OverrideTableName(tableName));
}
}
});
addAction("ALTER TABLE `" + tableName + "` DROP `covers`;");
addAction("ALTER TABLE `" + tableName + "` CHANGE `covers_oid` `covers` text NULL;");
}
addAction("""
ALTER TABLE `track` ADD `dataOid` binary(12) AFTER dataId;
""");
addAction((final DBAccess da) -> {
final List<OIDConversion> datas = da.gets(OIDConversion.class, new AccessDeletedItems(), new OverrideTableName("data"));
final List<MediaConversion> medias = da.gets(MediaConversion.class, new AccessDeletedItems(), new OverrideTableName("track"));
for (final MediaConversion media : medias) {
for (final OIDConversion data : datas) {
if (data.uuid.equals(media.dataId)) {
media.dataOid = data._id;
da.update(media, media.id, List.of("dataOid"), new OverrideTableName("track"));
break;
}
}
}
});
addAction("""
ALTER TABLE `track` DROP `dataId`;
""");
addAction("""
ALTER TABLE `track` CHANGE `dataOid` `dataId` binary(12) NOT NULL;
""");
// Move the files...
addAction((final DBAccess da) -> {
final List<OIDConversion> datas = da.gets(OIDConversion.class, new AccessDeletedItems(), new OverrideTableName("data"));
for (final OIDConversion data : datas) {
final String origin = DataResource.getFileDataOld(data.uuid);
final String destination = DataResource.getFileData(data._id);
LOGGER.info("move file = {}", origin);
LOGGER.info(" ==> {}", destination);
try {
Files.move(Paths.get(origin), Paths.get(destination), StandardCopyOption.ATOMIC_MOVE);
} catch (final NoSuchFileException ex) {
LOGGER.warn("Fail to move file : {}", ex.getMessage());
}
}
});
addAction("""
ALTER TABLE `data` DROP `uuid`;
""");
// addAction("""
// ALTER TABLE `data` CHANGE `_id` `_id` BINARY(12) DEFAULT (generate_objectid());
// """);
addAction("""
ALTER TABLE `data` ADD PRIMARY KEY `_id` (`_id`);
""");
}
}

View File

@ -0,0 +1,31 @@
package org.kar.karusic.migration;
import org.kar.archidata.migration.MigrationSqlStep;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Migration20250105 extends MigrationSqlStep {
private static final Logger LOGGER = LoggerFactory.getLogger(Migration20240907.class);
public static final int KARSO_INITIALISATION_ID = 1;
@Override
public String getName() {
return "migration-2025-01-05: remove old UUID";
}
@Override
public void generateStep() throws Exception {
// addAction("""
// ALTER TABLE `data` DROP INDEX `PRIMARY`;
// """);
// addAction("""
// ALTER TABLE `data` CHANGE `id` `uuid` binary(16) DEFAULT (UUID_TO_BIN(UUID(), TRUE));
// """);
// addAction("""
// ALTER TABLE `data` ADD PRIMARY KEY `uuid` (`uuid`);
// """);
}
}

View File

@ -3,6 +3,7 @@ package org.kar.karusic.migration.model;
import java.util.List;
import java.util.UUID;
import org.bson.types.ObjectId;
import org.kar.archidata.annotation.DataJson;
import jakarta.persistence.Id;
@ -12,4 +13,6 @@ public class CoverConversion {
public Long id = null;
@DataJson
public List<UUID> covers = null;
@DataJson
public List<ObjectId> covers_oid = null;
}

View File

@ -2,11 +2,13 @@ package org.kar.karusic.migration.model;
import java.util.UUID;
import org.bson.types.ObjectId;
import jakarta.persistence.Id;
public class MediaConversion {
@Id
public Long id = null;
public Long dataId = null;
public UUID dataUUID = null;
public UUID dataId = null;
public ObjectId dataOid = null;
}

View File

@ -2,10 +2,12 @@ package org.kar.karusic.migration.model;
import java.util.UUID;
import org.bson.types.ObjectId;
import jakarta.persistence.Id;
public class UUIDConversion {
public class OIDConversion {
@Id
public Long id = null;
public UUID uuid = null;
public ObjectId _id = null;
}

View File

@ -2,8 +2,8 @@ package org.kar.karusic.model;
import java.time.LocalDate;
import java.util.List;
import java.util.UUID;
import org.bson.types.ObjectId;
import org.kar.archidata.annotation.DataIfNotExists;
import org.kar.archidata.annotation.DataJson;
import org.kar.archidata.dataAccess.options.CheckJPA;
@ -12,11 +12,13 @@ import org.kar.archidata.model.GenericDataSoftDelete;
import com.fasterxml.jackson.annotation.JsonInclude;
import dev.morphia.annotations.Entity;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable;
import jakarta.persistence.Column;
import jakarta.persistence.Table;
@Entity("Album")
@Table(name = "album")
@DataIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
@ -34,6 +36,6 @@ public class Album extends GenericDataSoftDelete {
@Schema(description = "List of Id of the specific covers")
@DataJson(targetEntity = Data.class)
@Nullable
public List<UUID> covers = null;
public List<ObjectId> covers = null;
public LocalDate publication = null;
}

View File

@ -2,8 +2,8 @@ package org.kar.karusic.model;
import java.time.LocalDate;
import java.util.List;
import java.util.UUID;
import org.bson.types.ObjectId;
import org.kar.archidata.annotation.DataIfNotExists;
import org.kar.archidata.annotation.DataJson;
import org.kar.archidata.dataAccess.options.CheckJPA;
@ -12,11 +12,13 @@ import org.kar.archidata.model.GenericDataSoftDelete;
import com.fasterxml.jackson.annotation.JsonInclude;
import dev.morphia.annotations.Entity;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable;
import jakarta.persistence.Column;
import jakarta.persistence.Table;
@Entity("Artist")
@Table(name = "artist")
@DataIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
@ -34,7 +36,7 @@ public class Artist extends GenericDataSoftDelete {
@Schema(description = "List of Id of the specific covers")
@DataJson(targetEntity = Data.class)
@Nullable
public List<UUID> covers = null;
public List<ObjectId> covers = null;
@Column(length = 256)
public String firstName = null;
@Column(length = 256)

View File

@ -13,8 +13,8 @@ CREATE TABLE `node` (
*/
import java.util.List;
import java.util.UUID;
import org.bson.types.ObjectId;
import org.kar.archidata.annotation.DataIfNotExists;
import org.kar.archidata.annotation.DataJson;
import org.kar.archidata.dataAccess.options.CheckJPA;
@ -23,11 +23,13 @@ import org.kar.archidata.model.GenericDataSoftDelete;
import com.fasterxml.jackson.annotation.JsonInclude;
import dev.morphia.annotations.Entity;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable;
import jakarta.persistence.Column;
import jakarta.persistence.Table;
@Entity("Gender")
@Table(name = "gender")
@DataIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
@ -45,6 +47,13 @@ public class Gender extends GenericDataSoftDelete {
@Schema(description = "List of Id of the specific covers")
@DataJson(targetEntity = Data.class)
@Nullable
public List<UUID> covers = null;
public List<ObjectId> covers = null;
public Gender() {}
public Gender(final Long id, final String name) {
this.id = id;
this.name = name;
}
}

View File

@ -13,8 +13,8 @@ CREATE TABLE `node` (
*/
import java.util.List;
import java.util.UUID;
import org.bson.types.ObjectId;
import org.kar.archidata.annotation.DataIfNotExists;
import org.kar.archidata.annotation.DataJson;
import org.kar.archidata.dataAccess.options.CheckJPA;
@ -23,6 +23,7 @@ import org.kar.archidata.model.GenericDataSoftDelete;
import com.fasterxml.jackson.annotation.JsonInclude;
import dev.morphia.annotations.Entity;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable;
import jakarta.persistence.Column;
@ -30,6 +31,7 @@ import jakarta.persistence.FetchType;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.Table;
@Entity("Playlist")
@Table(name = "playlist")
@DataIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
@ -47,7 +49,7 @@ public class Playlist extends GenericDataSoftDelete {
@Schema(description = "List of Id of the specific covers")
@DataJson(targetEntity = Data.class)
@Nullable
public List<UUID> covers = null;
public List<ObjectId> covers = null;
@ManyToMany(fetch = FetchType.LAZY, targetEntity = Track.class)
public List<Long> tracks = null;
public List<ObjectId> tracks = null;
}

View File

@ -13,8 +13,8 @@ CREATE TABLE `node` (
*/
import java.util.List;
import java.util.UUID;
import org.bson.types.ObjectId;
import org.kar.archidata.annotation.DataIfNotExists;
import org.kar.archidata.annotation.DataJson;
import org.kar.archidata.dataAccess.options.CheckJPA;
@ -23,11 +23,13 @@ import org.kar.archidata.model.GenericDataSoftDelete;
import com.fasterxml.jackson.annotation.JsonInclude;
import dev.morphia.annotations.Entity;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable;
import jakarta.persistence.Column;
import jakarta.persistence.Table;
@Entity("Track")
@Table(name = "track")
@DataIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
@ -46,11 +48,11 @@ public class Track extends GenericDataSoftDelete {
@Schema(description = "List of Id of the specific covers")
@DataJson(targetEntity = Data.class)
@Nullable
public List<UUID> covers = null;
public List<ObjectId> covers = null;
public Long genderId = null;
public Long albumId = null;
public Long track = null;
public UUID dataId = null;
public ObjectId dataId = null;
// @ManyToMany(fetch = FetchType.LAZY, targetEntity = Artist.class)
@DataJson
@Column(length = 0)

View File

@ -0,0 +1,18 @@
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>
%d{HH:mm:ss.SSS} [%thread] %highlight(%-5level) %logger - %msg%n
</pattern>
<!--
<pattern>
%d{HH:mm:ss.SSS} | %thread | %highlight(%-5level) | %logger - %msg%n
</pattern>
-->
</encoder>
</appender>
<root level="info">
<appender-ref ref="CONSOLE" />
</root>
</configuration>

View File

@ -3,12 +3,14 @@
# Default logging detail level for all instances of SimpleLogger.
# Must be one of ("trace", "debug", "info", "warn", or "error").
# If not specified, defaults to "info".
org.slf4j.simpleLogger.defaultLogLevel=trace
org.slf4j.simpleLogger.defaultLogLevel=INFO
# Logging detail level for a SimpleLogger instance named "xxxxx".
# Must be one of ("trace", "debug", "info", "warn", or "error").
# If not specified, the default logging detail level is used.
#org.slf4j.simpleLogger.log.xxxxx=
org.slf4j.simpleLogger.log.org.kar.archidata=TRACE
org.slf4j.simpleLogger.log.org.kar.karusic=TRACE
# Set to true if you want the current date and time to be included in output messages.
# Default is false, and will output the number of milliseconds elapsed since startup.
@ -32,4 +34,9 @@ org.slf4j.simpleLogger.showThreadName=true
# Defaults to false.
#org.slf4j.simpleLogger.showShortLogName=false
# Utilise les codes ANSI pour la couleur
org.slf4j.simpleLogger.warnColor=\u001B[33m
org.slf4j.simpleLogger.errorColor=\u001B[31m
org.slf4j.simpleLogger.infoColor=\u001B[32m
org.slf4j.simpleLogger.debugColor=\u001B[34m

View File

@ -0,0 +1,126 @@
package test.kar.karusic;
import java.io.IOException;
import java.util.List;
import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.db.DbConfig;
import org.kar.archidata.db.DbIoFactory;
import org.kar.archidata.exception.DataAccessException;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.kar.karusic.model.Album;
import org.kar.karusic.model.Artist;
import org.kar.karusic.model.Gender;
import org.kar.karusic.model.Playlist;
import org.kar.karusic.model.Track;
import org.kar.karusic.model.UserKarusic;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.InternalServerErrorException;
public class ConfigureDb {
final static private Logger LOGGER = LoggerFactory.getLogger(ConfigureDb.class);
final static private String modeTestForced = null;// "MONGO";
public static DBAccess da = null;
public static void configure() throws IOException, InternalServerErrorException, DataAccessException {
String modeTest = System.getenv("TEST_E2E_MODE");
if (modeTest == null || modeTest.isEmpty() || "false".equalsIgnoreCase(modeTest)) {
modeTest = "SQLITE-MEMORY";
} else if ("true".equalsIgnoreCase(modeTest)) {
modeTest = "MY-SQL";
}
// override the local test:
if (modeTestForced != null) {
modeTest = modeTestForced;
}
final List<Class<?>> listObject = List.of( //
Album.class, //
Artist.class, //
Gender.class, //
Playlist.class, //
Track.class, //
UserKarusic.class //
);
if ("SQLITE-MEMORY".equalsIgnoreCase(modeTest)) {
ConfigBaseVariable.dbType = "sqlite";
ConfigBaseVariable.bdDatabase = null;
ConfigBaseVariable.dbHost = "memory";
// for test we need to connect all time the DB
ConfigBaseVariable.dbKeepConnected = "true";
} else if ("SQLITE".equalsIgnoreCase(modeTest)) {
ConfigBaseVariable.dbType = "sqlite";
ConfigBaseVariable.bdDatabase = null;
ConfigBaseVariable.dbKeepConnected = "true";
} else if ("MY-SQL".equalsIgnoreCase(modeTest)) {
ConfigBaseVariable.dbType = "mysql";
ConfigBaseVariable.bdDatabase = "test_karusic_db";
ConfigBaseVariable.dbPort = "3906";
ConfigBaseVariable.dbUser = "root";
} else if ("MONGO".equalsIgnoreCase(modeTest)) {
ConfigBaseVariable.dbType = "mongo";
ConfigBaseVariable.bdDatabase = "test_karusic_db";
} else {
// User local modification ...
ConfigBaseVariable.bdDatabase = "test_karusic_db";
ConfigBaseVariable.dbPort = "3906";
ConfigBaseVariable.dbUser = "root";
}
removeDB();
// Connect the dataBase...
da = DBAccess.createInterface();
}
public static void removeDB() {
String modeTest = System.getenv("TEST_E2E_MODE");
if (modeTest == null || modeTest.isEmpty() || "false".equalsIgnoreCase(modeTest)) {
modeTest = "SQLITE-MEMORY";
} else if ("true".equalsIgnoreCase(modeTest)) {
modeTest = "MY-SQL";
}
// override the local test:
if (modeTestForced != null) {
modeTest = modeTestForced;
}
DbConfig config = null;
try {
config = new DbConfig();
} catch (final DataAccessException e) {
e.printStackTrace();
LOGGER.error("Fail to clean the DB");
return;
}
config.setDbName(null);
LOGGER.info("Remove the DB and create a new one '{}'", config.getDbName());
try (final DBAccess daRoot = DBAccess.createInterface(config)) {
if ("SQLITE-MEMORY".equalsIgnoreCase(modeTest)) {
// nothing to do ...
} else if ("SQLITE".equalsIgnoreCase(modeTest)) {
daRoot.deleteDB(ConfigBaseVariable.bdDatabase);
} else if ("MY-SQL".equalsIgnoreCase(modeTest)) {
daRoot.deleteDB(ConfigBaseVariable.bdDatabase);
} else if ("MONGO".equalsIgnoreCase(modeTest)) {
daRoot.deleteDB(ConfigBaseVariable.bdDatabase);
}
daRoot.createDB(ConfigBaseVariable.bdDatabase);
} catch (final InternalServerErrorException e) {
e.printStackTrace();
LOGGER.error("Fail to clean the DB");
return;
} catch (final IOException e) {
e.printStackTrace();
LOGGER.error("Fail to clean the DB");
return;
}
}
public static void clear() throws IOException {
LOGGER.info("Remove the test db");
removeDB();
// The connection is by default open ==> close it at the end of test:
da.close();
DbIoFactory.closeAllForceMode();
ConfigBaseVariable.clearAllValue();
}
}

View File

@ -7,10 +7,8 @@ import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith;
import org.kar.archidata.db.DBEntry;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.kar.archidata.tools.RESTApi;
import org.kar.karusic.migration.Initialization;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -27,31 +25,16 @@ public class TestBase {
@BeforeAll
public static void configureWebServer() throws Exception {
ConfigureDb.configure();
LOGGER.info("configure server ...");
webInterface = new WebLauncherTest();
LOGGER.info("Clean previous table");
try {
Initialization.dropAll();
} catch (final Exception ex) {
ex.printStackTrace();
LOGGER.error("plop: {}", ex.getLocalizedMessage());
throw ex;
}
LOGGER.info("Create DB");
try {
webInterface.migrateDB();
} catch (final Exception ex) {
ex.printStackTrace();
LOGGER.error("Detect an error: {}", ex.getMessage());
}
LOGGER.info("Start REST (BEGIN)");
webInterface.process();
LOGGER.info("Start REST (DONE)");
api = new RESTApi(ConfigBaseVariable.apiAdress);
api.setToken(Common.USER_TOKEN);
api.setToken(Common.ADMIN_TOKEN);
}
@AfterAll
@ -59,9 +42,7 @@ public class TestBase {
LOGGER.info("Kill the web server");
webInterface.stop();
webInterface = null;
LOGGER.info("Remove the test db");
DBEntry.closeAllForceMode();
ConfigBaseVariable.clearAllValue();
ConfigureDb.clear();
}
}

View File

@ -0,0 +1,61 @@
package test.kar.karusic;
import static org.bson.codecs.configuration.CodecRegistries.fromProviders;
import static org.bson.codecs.configuration.CodecRegistries.fromRegistries;
import java.io.IOException;
import org.bson.codecs.configuration.CodecRegistry;
import org.bson.codecs.pojo.PojoCodecProvider;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith;
import org.kar.karusic.model.Track;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.mongodb.ConnectionString;
import com.mongodb.MongoClientSettings;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
@ExtendWith(StepwiseExtension.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class TestMongoDb {
final static private Logger LOGGER = LoggerFactory.getLogger(TestMongoDb.class);
@BeforeAll
public static void configureWebServer() throws Exception {}
@AfterAll
public static void removeDataBase() throws IOException {
}
@Order(1)
@Test
public void testCreateTable() throws Exception {
final ConnectionString connectionString = new ConnectionString("mongodb://localhost:27017");// System.getProperty("mongodb.uri"));
// Configure the CodecRegistry to include a codec to handle the translation to and from BSON for our POJOs.
final CodecRegistry pojoCodecRegistry = fromProviders(PojoCodecProvider.builder().automatic(true).build());
// Add the default codec registry, which contains all the default codecs. They can handle all the major types in
// Java-like Boolean, Double, String, BigDecimal, etc.
final CodecRegistry codecRegistry = fromRegistries(MongoClientSettings.getDefaultCodecRegistry(), pojoCodecRegistry);
// Wrap all my settings together using MongoClientSettings.
final MongoClientSettings clientSettings = MongoClientSettings.builder().applyConnectionString(connectionString).codecRegistry(codecRegistry).build();
// Initiate the connection with MongoDB.
try (MongoClient mongoClient = MongoClients.create(clientSettings)) {
final MongoDatabase db = mongoClient.getDatabase("sample_training");
final MongoCollection<Track> grades = db.getCollection("Track", Track.class);
}
}
}

View File

@ -19,6 +19,7 @@ services:
kar_mongodb_service:
image: mongo:latest
restart: always
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: base_db_password
@ -27,19 +28,6 @@ services:
volumes:
- ./dataMongo:/data/db
mongo_express_service:
image: mongo-express
restart: always
ports:
- 8081:8081
links:
- kar_mongodb_service:db
environment:
ME_CONFIG_MONGODB_ADMINUSERNAME: root
ME_CONFIG_MONGODB_ADMINPASSWORD: base_db_password
ME_CONFIG_MONGODB_URL: mongodb://root:base_db_password@db:27017/
ME_CONFIG_BASICAUTH: false
kar_adminer_service:
image: adminer:latest
restart: always
@ -52,3 +40,17 @@ services:
ports:
- 4079:8080
mem_limit: 50m
mongo_express_service:
image: mongo-express
restart: always
ports:
- 4077:8081
links:
- kar_mongodb_service:db
environment:
ME_CONFIG_MONGODB_ADMINUSERNAME: root
ME_CONFIG_MONGODB_ADMINPASSWORD: base_db_password
ME_CONFIG_MONGODB_URL: mongodb://root:base_db_password@db:27017/
ME_CONFIG_BASICAUTH: false

View File

@ -22,30 +22,6 @@ import {
export namespace AlbumResource {
/**
* Add a Track on a specific album
*/
export function addTrack({
restConfig,
params,
}: {
restConfig: RESTConfig,
params: {
trackId: Long,
id: Long,
},
}): Promise<Album> {
return RESTRequestJson({
restModel: {
endPoint: "/album/{id}/track/{trackId}",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isAlbum);
};
/**
* Get a specific Album with his ID
*/
@ -192,30 +168,6 @@ export namespace AlbumResource {
params,
}, isAlbum);
};
/**
* Remove a Track on a specific album
*/
export function removeTrack({
restConfig,
params,
}: {
restConfig: RESTConfig,
params: {
trackId: Long,
id: Long,
},
}): Promise<Album> {
return RESTRequestJson({
restModel: {
endPoint: "/album/{id}/track/{trackId}",
requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isAlbum);
};
/**
* Add a cover on a specific album
*/

View File

@ -15,7 +15,7 @@ import {
Artist,
ArtistWrite,
Long,
UUID,
ObjectId,
ZodArtist,
isArtist,
} from "../model";
@ -135,7 +135,7 @@ export namespace ArtistResource {
}: {
restConfig: RESTConfig,
params: {
coverId: UUID,
coverId: ObjectId,
id: Long,
},
}): Promise<Artist> {

View File

@ -10,7 +10,7 @@ import {
} from "../rest-tools";
import {
UUID,
ObjectId,
} from "../model";
export namespace DataResource {
@ -30,13 +30,13 @@ export namespace DataResource {
},
params: {
name: string,
uuid: UUID,
oid: ObjectId,
},
data: string,
}): Promise<object> {
return RESTRequestJson({
restModel: {
endPoint: "/data/{uuid}/{name}",
endPoint: "/data/{oid}/{name}",
requestType: HTTPRequestModel.GET,
},
restConfig,
@ -59,13 +59,13 @@ export namespace DataResource {
Authorization?: string,
},
params: {
uuid: UUID,
oid: ObjectId,
},
data: string,
}): Promise<object> {
return RESTRequestJson({
restModel: {
endPoint: "/data/{uuid}",
endPoint: "/data/{oid}",
requestType: HTTPRequestModel.GET,
},
restConfig,
@ -88,13 +88,13 @@ export namespace DataResource {
Authorization?: string,
},
params: {
uuid: UUID,
oid: ObjectId,
},
data: string,
}): Promise<object> {
return RESTRequestJson({
restModel: {
endPoint: "/data/thumbnail/{uuid}",
endPoint: "/data/thumbnail/{oid}",
requestType: HTTPRequestModel.GET,
},
restConfig,

View File

@ -15,7 +15,7 @@ import {
Gender,
GenderWrite,
Long,
UUID,
ObjectId,
ZodGender,
isGender,
} from "../model";
@ -135,7 +135,7 @@ export namespace GenderResource {
}: {
restConfig: RESTConfig,
params: {
coverId: UUID,
coverId: ObjectId,
id: Long,
},
}): Promise<Gender> {

View File

@ -12,9 +12,9 @@ import {
import { z as zod } from "zod"
import {
Long,
ObjectId,
Playlist,
PlaylistWrite,
UUID,
ZodPlaylist,
isPlaylist,
} from "../model";
@ -155,7 +155,7 @@ export namespace PlaylistResource {
}: {
restConfig: RESTConfig,
params: {
coverId: UUID,
coverId: ObjectId,
id: Long,
},
}): Promise<Playlist> {

View File

@ -13,9 +13,9 @@ import {
import { z as zod } from "zod"
import {
Long,
ObjectId,
Track,
TrackWrite,
UUID,
ZodTrack,
isTrack,
} from "../model";
@ -156,7 +156,7 @@ export namespace TrackResource {
}: {
restConfig: RESTConfig,
params: {
coverId: UUID,
coverId: ObjectId,
id: Long,
},
}): Promise<Track> {

View File

@ -3,7 +3,7 @@
*/
import { z as zod } from "zod";
import {ZodUUID} from "./uuid";
import {ZodObjectId} from "./object-id";
import {ZodLocalDate} from "./local-date";
import {ZodGenericDataSoftDelete, ZodGenericDataSoftDeleteWrite } from "./generic-data-soft-delete";
@ -13,7 +13,7 @@ export const ZodAlbum = ZodGenericDataSoftDelete.extend({
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodUUID).optional(),
covers: zod.array(ZodObjectId).optional(),
publication: ZodLocalDate.optional(),
});
@ -35,7 +35,7 @@ export const ZodAlbumWrite = ZodGenericDataSoftDeleteWrite.extend({
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodUUID).nullable().optional(),
covers: zod.array(ZodObjectId).nullable().optional(),
publication: ZodLocalDate.nullable().optional(),
});

View File

@ -3,7 +3,7 @@
*/
import { z as zod } from "zod";
import {ZodUUID} from "./uuid";
import {ZodObjectId} from "./object-id";
import {ZodLocalDate} from "./local-date";
import {ZodGenericDataSoftDelete, ZodGenericDataSoftDeleteWrite } from "./generic-data-soft-delete";
@ -13,7 +13,7 @@ export const ZodArtist = ZodGenericDataSoftDelete.extend({
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodUUID).optional(),
covers: zod.array(ZodObjectId).optional(),
firstName: zod.string().max(256).optional(),
surname: zod.string().max(256).optional(),
birth: ZodLocalDate.optional(),
@ -38,7 +38,7 @@ export const ZodArtistWrite = ZodGenericDataSoftDeleteWrite.extend({
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodUUID).nullable().optional(),
covers: zod.array(ZodObjectId).nullable().optional(),
firstName: zod.string().max(256).nullable().optional(),
surname: zod.string().max(256).nullable().optional(),
birth: ZodLocalDate.nullable().optional(),

View File

@ -3,7 +3,7 @@
*/
import { z as zod } from "zod";
import {ZodUUID} from "./uuid";
import {ZodObjectId} from "./object-id";
import {ZodGenericDataSoftDelete, ZodGenericDataSoftDeleteWrite } from "./generic-data-soft-delete";
export const ZodGender = ZodGenericDataSoftDelete.extend({
@ -12,7 +12,7 @@ export const ZodGender = ZodGenericDataSoftDelete.extend({
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodUUID).optional(),
covers: zod.array(ZodObjectId).optional(),
});
@ -33,7 +33,7 @@ export const ZodGenderWrite = ZodGenericDataSoftDeleteWrite.extend({
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodUUID).nullable().optional(),
covers: zod.array(ZodObjectId).nullable().optional(),
});

View File

@ -12,6 +12,7 @@ export * from "./integer"
export * from "./iso-date"
export * from "./local-date"
export * from "./long"
export * from "./object-id"
export * from "./part-right"
export * from "./playlist"
export * from "./rest-error-response"

View File

@ -0,0 +1,8 @@
/**
* Interface of the server (auto-generated code)
*/
import { z as zod } from "zod";
export const ZodObjectId = zod.string().length(24, "Invalid ObjectId length").regex(/^[a-fA-F0-9]{24}$/, "Invalid ObjectId format");
export type ObjectId = zod.infer<typeof ZodObjectId>;

View File

@ -3,8 +3,7 @@
*/
import { z as zod } from "zod";
import {ZodUUID} from "./uuid";
import {ZodLong} from "./long";
import {ZodObjectId} from "./object-id";
import {ZodGenericDataSoftDelete, ZodGenericDataSoftDeleteWrite } from "./generic-data-soft-delete";
export const ZodPlaylist = ZodGenericDataSoftDelete.extend({
@ -13,8 +12,8 @@ export const ZodPlaylist = ZodGenericDataSoftDelete.extend({
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodUUID).optional(),
tracks: zod.array(ZodLong),
covers: zod.array(ZodObjectId).optional(),
tracks: zod.array(ZodObjectId),
});
@ -35,8 +34,8 @@ export const ZodPlaylistWrite = ZodGenericDataSoftDeleteWrite.extend({
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodUUID).nullable().optional(),
tracks: zod.array(ZodLong).optional(),
covers: zod.array(ZodObjectId).nullable().optional(),
tracks: zod.array(ZodObjectId).optional(),
});

View File

@ -3,7 +3,7 @@
*/
import { z as zod } from "zod";
import {ZodUUID} from "./uuid";
import {ZodObjectId} from "./object-id";
import {ZodLong} from "./long";
import {ZodGenericDataSoftDelete, ZodGenericDataSoftDeleteWrite } from "./generic-data-soft-delete";
@ -13,11 +13,11 @@ export const ZodTrack = ZodGenericDataSoftDelete.extend({
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodUUID).optional(),
covers: zod.array(ZodObjectId).optional(),
genderId: ZodLong.optional(),
albumId: ZodLong.optional(),
track: ZodLong.optional(),
dataId: ZodUUID.optional(),
dataId: ZodObjectId.optional(),
artists: zod.array(ZodLong),
});
@ -39,11 +39,11 @@ export const ZodTrackWrite = ZodGenericDataSoftDeleteWrite.extend({
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodUUID).nullable().optional(),
covers: zod.array(ZodObjectId).nullable().optional(),
genderId: ZodLong.nullable().optional(),
albumId: ZodLong.nullable().optional(),
track: ZodLong.nullable().optional(),
dataId: ZodUUID.nullable().optional(),
dataId: ZodObjectId.nullable().optional(),
artists: zod.array(ZodLong).optional(),
});

View File

@ -8,11 +8,10 @@ import {ZodUUID} from "./uuid";
import {ZodGenericDataSoftDelete, ZodGenericDataSoftDeleteWrite } from "./generic-data-soft-delete";
export const ZodUser = ZodGenericDataSoftDelete.extend({
login: zod.string().max(128).optional(),
login: zod.string().min(3).max(128),
lastConnection: ZodTimestamp.optional(),
admin: zod.boolean(),
blocked: zod.boolean(),
removed: zod.boolean(),
blockedReason: zod.string().max(512).optional(),
/**
* List of Id of the specific covers
*/
@ -32,11 +31,10 @@ export function isUser(data: any): data is User {
}
}
export const ZodUserWrite = ZodGenericDataSoftDeleteWrite.extend({
login: zod.string().max(128).nullable().optional(),
login: zod.string().min(3).max(128).optional(),
lastConnection: ZodTimestamp.nullable().optional(),
admin: zod.boolean(),
blocked: zod.boolean(),
removed: zod.boolean(),
blockedReason: zod.string().max(512).nullable().optional(),
/**
* List of Id of the specific covers
*/

View File

@ -7,11 +7,15 @@
import { RestErrorResponse, isRestErrorResponse } from "./model";
export enum HTTPRequestModel {
ARCHIVE = "ARCHIVE",
DELETE = "DELETE",
HEAD = "HEAD",
GET = "GET",
OPTION = "OPTION",
PATCH = "PATCH",
POST = "POST",
PUT = "PUT",
RESTORE = "RESTORE",
}
export enum HTTPMimeType {
ALL = "*/*",
@ -248,9 +252,14 @@ export function RESTRequest({
if (restModel.accept !== undefined) {
headers["Accept"] = restModel.accept;
}
if (restModel.requestType !== HTTPRequestModel.GET) {
if (restModel.requestType !== HTTPRequestModel.GET &&
restModel.requestType !== HTTPRequestModel.ARCHIVE &&
restModel.requestType !== HTTPRequestModel.RESTORE
) {
// if Get we have not a content type, the body is empty
if (restModel.contentType !== HTTPMimeType.MULTIPART) {
if (restModel.contentType !== HTTPMimeType.MULTIPART &&
restModel.contentType !== undefined
) {
// special case of multi-part ==> no content type otherwise the browser does not set the ";bundary=--****"
headers["Content-Type"] = restModel.contentType;
}

View File

@ -5,9 +5,10 @@ import { Image } from '@chakra-ui/react';
import { DataUrlAccess } from '@/utils/data-url-access';
import { Icon } from './Icon';
import { ObjectId } from '@/back-api';
export type CoversProps = BoxProps & {
data?: string[];
data?: ObjectId[];
size?: StyleProps["width"];
iconEmpty?: As;
slideshow?: boolean;

View File

@ -1,11 +1,9 @@
import { useState } from 'react';
import React from 'react';
import {
Input,
InputGroup,
InputLeftElement,
useOutsideClick,
} from '@chakra-ui/react';
import { MdSearch } from 'react-icons/md';

View File

@ -1,7 +1,7 @@
import { ReactElement } from 'react';
import { Center, Flex, Text, Wrap, WrapItem } from '@chakra-ui/react';
import { LuCrown, LuDisc3, LuEar, LuFileAudio, LuUser } from 'react-icons/lu';
import { LuCrown, LuDisc3, LuEar, LuFileAudio } from 'react-icons/lu';
import { MdGroup } from 'react-icons/md';
import { useNavigate } from 'react-router-dom';

View File

@ -1,7 +1,6 @@
import { Navigate, Route, Routes } from 'react-router-dom';
import { Error404 } from '@/errors';
import { ArtistAlbumDetailPage } from '@/scene/artist/ArtistAlbumDetailPage';
import { TrackSelectionPage } from '@/scene/track/TrackSelectionPage';
import { TracksStartLetterDetailPage } from '@/scene/track/TracksStartLetterDetailPage';