13 Commits

Author SHA1 Message Date
Edouard DUPIN
e4ff85f336 [FEAT] init from backup 2025-10-15 23:24:13 +02:00
Edouard DUPIN
ba2d6e25a9 [FEAT] update to archidata 2025-10-15 21:53:46 +02:00
Edouard DUPIN
688a57836d [FIX] bd name setting position to permit to have a test DB (remove other application test than Mongo) 2025-10-15 21:48:30 +02:00
Edouard DUPIN
7686ed845b [FIX] periodic backup (once a day) 2025-10-15 21:42:22 +02:00
Edouard DUPIN
aea5ebf43f [FEAT] remove old DockerFile 2025-10-15 21:41:37 +02:00
Edouard DUPIN
1dc9eed99d [FEAT] clean DockerFile 2025-10-15 21:41:24 +02:00
Edouard DUPIN
0c7bba3e42 [FIX] migrate Data to data end fic management of docker 2025-09-28 21:10:33 +02:00
Edouard DUPIN
ad270ce83b [FIX] covers 2025-09-28 10:16:40 +02:00
Edouard DUPIN
2777931a21 [FEAT] update new archidata ==> cover will fail 2025-09-27 16:50:00 +02:00
Edouard DUPIN
8ecfe57b96 qsdfqsdf 2025-09-27 16:49:57 +02:00
Edouard DUPIN
092239c225 [FEAT] update size of Image fomr 1.3GB to 186MB 2025-09-27 16:49:51 +02:00
Edouard DUPIN
0f3d2e18b3 [FEAT] remove old migration and midration to mongo is OK 2025-09-27 16:49:42 +02:00
Edouard DUPIN
5020454135 [VERSION] update dev tag version 2025-05-03 11:05:53 +02:00
77 changed files with 661 additions and 1448 deletions

View File

@@ -17,7 +17,7 @@ RUN pacman -Syu --noconfirm && pacman-db-upgrade \
&& pacman -S --noconfirm maven npm pnpm \
&& pacman -Scc --noconfirm
ENV PATH /tmp/node_modules/.bin:$PATH
ENV PATH=/tmp/node_modules/.bin:$PATH
######################################################################################
##
@@ -81,33 +81,24 @@ RUN pnpm static:build
##
######################################################################################
#FROM bellsoft/liberica-openjdk-alpine:latest
## add wget to manage the health check...
#RUN apk add --no-cache wget
FROM common
FROM bellsoft/liberica-openjdk-alpine-musl:latest
#FROM archlinux:base
#RUN pacman -Syu --noconfirm && pacman-db-upgrade
## install package
#RUN pacman -S --noconfirm jdk-openjdk wget
## intall npm
#RUN pacman -S --noconfirm npm
## clean all the caches Need only on the release environment
#RUN pacman -Scc --noconfirm
ENV LANG C.UTF-8
COPY --from=build_back /tmp/out/maven/*.jar /application/application.jar
COPY --from=build_front /tmp/dist /application/front/
# COPY front/public/icons /application/front/public/icons
# COPY front/public/icons /application/front/icons
WORKDIR /application/
RUN apk add --no-cache wget \
&& addgroup -g 1000 user \
&& adduser --system -u 1000 -G user user
ENV LANG=C.UTF-8
EXPOSE 80
WORKDIR /application/
RUN chown user:user -R /application
# To verify health-check: docker inspect --format "{{json .State.Health }}" YOUR_SERVICE_NAME | jq
HEALTHCHECK --start-period=10s --start-interval=2s --interval=30s --timeout=5s --retries=10 \
CMD wget --no-verbose --tries=1 --spider http://localhost:80/api/health_check || exit 1
CMD ["java", "-Xms64M", "-Xmx1G", "-cp", "/application/application.jar", "org.atriasoft.karusic.WebLauncher"]
COPY --chown=user:user --from=build_back /tmp/out/maven/*.jar /application/application.jar
COPY --chown=user:user --from=build_front /tmp/dist /application/front/
USER user

View File

@@ -1,22 +0,0 @@
FROM maven:3-openjdk-23 AS build
COPY pom.xml /tmp/
COPY src /tmp/src/
COPY Formatter.xml /tmp/
WORKDIR /tmp/
RUN mvn clean compile assembly:single
FROM bellsoft/liberica-openjdk-alpine:latest
ENV LANG=C.UTF-8
# add wget to manage the health check...
RUN apk add --no-cache wget
RUN mkdir /application/
COPY --from=build /tmp/out/maven/*.jar /application/application.jar
WORKDIR /application/
EXPOSE 18080
CMD ["java", "-Xms64M", "-Xmx1G", "-cp", "/application/application.jar", "org.atriasoft.karusic.WebLauncher"]

View File

@@ -3,12 +3,12 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.atriasoft</groupId>
<artifactId>karusic</artifactId>
<version>1.2.0</version>
<version>1.2.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.atria-soft</groupId>
<artifactId>archidata</artifactId>
<version>0.30.4</version>
<version>0.37.2</version>
</dependency>
<!-- Loopback of logger JDK logging API to SLF4J -->
<dependency>

View File

@@ -13,8 +13,8 @@ import org.atriasoft.archidata.UpdateJwtPublicKey;
import org.atriasoft.archidata.api.DataResource;
import org.atriasoft.archidata.api.ProxyResource;
import org.atriasoft.archidata.catcher.GenericCatcher;
import org.atriasoft.archidata.cron.CronScheduler;
import org.atriasoft.archidata.db.DbConfig;
import org.atriasoft.archidata.exception.DataAccessException;
import org.atriasoft.archidata.filter.CORSFilter;
import org.atriasoft.archidata.filter.OptionFilter;
import org.atriasoft.archidata.migration.MigrationEngine;
@@ -29,8 +29,10 @@ import org.atriasoft.karusic.api.PlaylistResource;
import org.atriasoft.karusic.api.TrackResource;
import org.atriasoft.karusic.api.UserResource;
import org.atriasoft.karusic.filter.KarusicAuthenticationFilter;
import org.atriasoft.karusic.job.BackupJob;
import org.atriasoft.karusic.migration.Initialization;
import org.atriasoft.karusic.migration.Migration20250427;
import org.atriasoft.karusic.migration.Migration20250928;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.jackson.JacksonFeature;
@@ -47,10 +49,12 @@ public class WebLauncher {
final static Logger LOGGER = LoggerFactory.getLogger(WebLauncher.class);
protected UpdateJwtPublicKey keyUpdater = null;
protected HttpServer server = null;
protected CronScheduler scheduler = null;
public WebLauncher() {
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
ConfigBaseVariable.bdDatabase = "karusic";
this.scheduler = new CronScheduler();
this.scheduler.setGracePeriodMinutes(1);
}
private static URI getBaseURI() {
@@ -64,6 +68,7 @@ public class WebLauncher {
migrationEngine.setInit(new Initialization());
WebLauncher.LOGGER.info("Add migration since last version");
migrationEngine.add(new Migration20250427());
migrationEngine.add(new Migration20250928());
WebLauncher.LOGGER.info("Migrate the DB [START]");
migrationEngine.migrateWaitAdmin(new DbConfig());
WebLauncher.LOGGER.info("Migrate the DB [STOP]");
@@ -75,6 +80,8 @@ public class WebLauncher {
SLF4JBridgeHandler.install();
WebLauncher.LOGGER.info("[START] application wake UP");
ConfigBaseVariable.bdDatabase = "karusic";
ConfigBaseVariable.dbType = "mongo";
final WebLauncher launcher = new WebLauncher();
launcher.migrateDB();
@@ -107,7 +114,7 @@ public class WebLauncher {
}
}
public void process() throws InterruptedException, DataAccessException {
public void process() throws Exception {
ImageIO.scanForPlugins();
plop("jpeg");
@@ -175,6 +182,12 @@ public class WebLauncher {
this.keyUpdater = new UpdateJwtPublicKey();
this.keyUpdater.start();
// ===================================================================
// start generic scheduler ...
// ===================================================================
this.scheduler.addTask("backup", "0 0 * * *", new BackupJob());
this.scheduler.start();
// ===================================================================
// run JERSEY
// ===================================================================
@@ -192,6 +205,10 @@ public class WebLauncher {
this.server.shutdownNow();
this.server = null;
}
if (this.scheduler != null) {
this.scheduler.stop();
this.scheduler = null;
}
}
public void stopOther() {

View File

@@ -2,9 +2,9 @@ package org.atriasoft.karusic;
import java.util.logging.LogManager;
import org.atriasoft.archidata.exception.DataAccessException;
import org.atriasoft.archidata.tools.ConfigBaseVariable;
import org.atriasoft.karusic.migration.Initialization;
import org.atriasoft.karusic.util.ConfigVariable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.bridge.SLF4JBridgeHandler;
@@ -15,6 +15,8 @@ public class WebLauncherLocal extends WebLauncher {
private WebLauncherLocal() {}
public static void main(final String[] args) throws Exception {
ConfigBaseVariable.bdDatabase = "karusic";
ConfigBaseVariable.dbType = "mongo";
// Loop-back of logger JDK logging API to SLF4J
LogManager.getLogManager().reset();
SLF4JBridgeHandler.install();
@@ -28,13 +30,16 @@ public class WebLauncherLocal extends WebLauncher {
}
@Override
public void process() throws InterruptedException, DataAccessException {
public void process() throws Exception {
if (true) {
// for local test:
ConfigBaseVariable.apiAdress = "http://0.0.0.0:19080/karusic/api/";
ConfigBaseVariable.testMode = "true";
ConfigBaseVariable.dbType = "mongo";
}
if (ConfigVariable.isInitWithBackup()) {
Initialization.initializeWithBackup();
}
// Test fail of SSO: ConfigBaseVariable.ssoAdress = null;
try {
super.migrateDB();

View File

@@ -1,18 +1,13 @@
package org.atriasoft.karusic.api;
import java.io.InputStream;
import java.util.List;
import org.atriasoft.archidata.annotation.apiGenerator.ApiInputOptional;
import org.atriasoft.archidata.annotation.apiGenerator.ApiTypeScriptProgress;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.annotation.checker.GroupCreate;
import org.atriasoft.archidata.annotation.checker.GroupUpdate;
import org.atriasoft.archidata.annotation.checker.ValidGroup;
import org.atriasoft.archidata.dataAccess.DataAccess;
import org.atriasoft.archidata.dataAccess.addOnSQL.AddOnDataJson;
import org.atriasoft.archidata.tools.DataTools;
import org.atriasoft.karusic.model.Album;
import org.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -56,7 +51,7 @@ public class AlbumResource {
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
@Operation(description = "Add an album (when all the data already exist)")
public Album post(@Valid final Album data) throws Exception {
public Album post(@Valid @ValidGroup(GroupCreate.class) final Album data) throws Exception {
// TODO: how to manage the checker ???
// final Album ret = this.morphiaService.getDatastore().save(data);
// return ret;
@@ -71,7 +66,7 @@ public class AlbumResource {
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
@Operation(description = "Update a specific album")
public Album put(@PathParam("oid") final ObjectId oid, @Valid final Album album) throws Exception {
public Album put(@PathParam("oid") final ObjectId oid, @Valid @ValidGroup(GroupUpdate.class) final Album album) throws Exception {
// final Query<Album> query = this.morphiaService.getDatastore().find(Album.class).filter(Filters.eq("id", id));
// final UpdateOperations<Album> ops = this.morphiaService.getDatastore().createUpdateOperations(Album.class)
// .set("name", master.getName());
@@ -105,38 +100,4 @@ public class AlbumResource {
// 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 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); } */
@POST
@Path("{oid}/cover")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
@Operation(description = "Add a cover on a specific album")
@ApiTypeScriptProgress
public Album uploadCover(@PathParam("oid") final ObjectId oid, @ApiInputOptional @FormDataParam("uri") final String uri, @ApiInputOptional @FormDataParam("file") final InputStream fileInputStream,
@ApiInputOptional @FormDataParam("file") final FormDataContentDisposition fileMetaData) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
if (uri != null) {
DataTools.uploadCoverFromUri(db, Album.class, oid, uri);
} else {
DataTools.uploadCover(db, Album.class, oid, fileInputStream, fileMetaData);
}
return db.get(Album.class, oid);
}
}
@DELETE
@Path("{oid}/cover/{coverId}")
@RolesAllowed("ADMIN")
@Operation(description = "Remove a cover on a specific album")
public Album removeCover(@PathParam("oid") final ObjectId oid, @PathParam("coverId") final ObjectId coverId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Album.class, "id", oid, "covers", coverId);
return db.get(Album.class, oid);
}
}
}

View File

@@ -1,18 +1,13 @@
package org.atriasoft.karusic.api;
import java.io.InputStream;
import java.util.List;
import org.atriasoft.archidata.annotation.apiGenerator.ApiInputOptional;
import org.atriasoft.archidata.annotation.apiGenerator.ApiTypeScriptProgress;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.annotation.checker.GroupCreate;
import org.atriasoft.archidata.annotation.checker.GroupUpdate;
import org.atriasoft.archidata.annotation.checker.ValidGroup;
import org.atriasoft.archidata.dataAccess.DataAccess;
import org.atriasoft.archidata.dataAccess.addOnSQL.AddOnDataJson;
import org.atriasoft.archidata.tools.DataTools;
import org.atriasoft.karusic.model.Artist;
import org.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -49,7 +44,7 @@ public class ArtistResource {
@POST
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Artist post(@Valid final Artist data) throws Exception {
public Artist post(@Valid @ValidGroup(GroupCreate.class) final Artist data) throws Exception {
return DataAccess.insert(data);
}
@@ -57,7 +52,7 @@ public class ArtistResource {
@Path("{oid}")
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Artist put(@PathParam("oid") final ObjectId oid, @Valid final Artist artist) throws Exception {
public Artist put(@PathParam("oid") final ObjectId oid, @Valid @ValidGroup(GroupUpdate.class) final Artist artist) throws Exception {
artist.oid = oid;
DataAccess.update(artist, oid);
return DataAccess.get(Artist.class, oid);
@@ -69,31 +64,4 @@ public class ArtistResource {
public void remove(@PathParam("oid") final ObjectId oid) throws Exception {
DataAccess.delete(Artist.class, oid);
}
@POST
@Path("{oid}/cover")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
@ApiTypeScriptProgress
public Artist uploadCover(@PathParam("oid") final ObjectId oid, @ApiInputOptional @FormDataParam("uri") final String uri,
@ApiInputOptional @FormDataParam("file") final InputStream fileInputStream, @ApiInputOptional @FormDataParam("file") final FormDataContentDisposition fileMetaData) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
if (uri != null) {
DataTools.uploadCoverFromUri(db, Artist.class, oid, uri);
} else {
DataTools.uploadCover(db, Artist.class, oid, fileInputStream, fileMetaData);
}
return db.get(Artist.class, oid);
}
}
@DELETE
@Path("{oid}/cover/{coverId}")
@RolesAllowed("ADMIN")
public Artist removeCover(@PathParam("oid") final ObjectId oid, @PathParam("coverId") final ObjectId coverId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Artist.class, "id", oid, "covers", coverId);
return db.get(Artist.class, oid);
}
}
}

View File

@@ -1,18 +1,13 @@
package org.atriasoft.karusic.api;
import java.io.InputStream;
import java.util.List;
import org.atriasoft.archidata.annotation.apiGenerator.ApiInputOptional;
import org.atriasoft.archidata.annotation.apiGenerator.ApiTypeScriptProgress;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.annotation.checker.GroupCreate;
import org.atriasoft.archidata.annotation.checker.GroupUpdate;
import org.atriasoft.archidata.annotation.checker.ValidGroup;
import org.atriasoft.archidata.dataAccess.DataAccess;
import org.atriasoft.archidata.dataAccess.addOnSQL.AddOnDataJson;
import org.atriasoft.archidata.tools.DataTools;
import org.atriasoft.karusic.model.Gender;
import org.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -49,7 +44,7 @@ public class GenderResource {
@POST
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Gender post(@Valid final Gender data) throws Exception {
public Gender post(@Valid @ValidGroup(GroupCreate.class) final Gender data) throws Exception {
return DataAccess.insert(data);
}
@@ -57,7 +52,7 @@ public class GenderResource {
@Path("{oid}")
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Gender patch(@PathParam("oid") final ObjectId oid, @Valid final Gender gender) throws Exception {
public Gender patch(@PathParam("oid") final ObjectId oid, @Valid @ValidGroup(GroupUpdate.class) final Gender gender) throws Exception {
gender.oid = oid;
DataAccess.update(gender, oid);
return DataAccess.get(Gender.class, oid);
@@ -70,30 +65,4 @@ public class GenderResource {
DataAccess.delete(Gender.class, oid);
}
@POST
@Path("{oid}/cover")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
@ApiTypeScriptProgress
public Gender uploadCover(@PathParam("oid") final ObjectId oid, @ApiInputOptional @FormDataParam("uri") final String uri,
@ApiInputOptional @FormDataParam("file") final InputStream fileInputStream, @ApiInputOptional @FormDataParam("file") final FormDataContentDisposition fileMetaData) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
if (uri != null) {
DataTools.uploadCoverFromUri(db, Gender.class, oid, uri);
} else {
DataTools.uploadCover(db, Gender.class, oid, fileInputStream, fileMetaData);
}
return db.get(Gender.class, oid);
}
}
@DELETE
@Path("{oid}/cover/{coverId}")
@RolesAllowed("ADMIN")
public Gender removeCover(@PathParam("oid") final ObjectId oid, @PathParam("coverId") final ObjectId coverId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Gender.class, "_id", oid, "covers", coverId);
return db.get(Gender.class, oid);
}
}
}

View File

@@ -1,17 +1,13 @@
package org.atriasoft.karusic.api;
import java.io.InputStream;
import java.util.List;
import org.atriasoft.archidata.annotation.apiGenerator.ApiAsyncType;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.annotation.checker.GroupCreate;
import org.atriasoft.archidata.annotation.checker.GroupUpdate;
import org.atriasoft.archidata.annotation.checker.ValidGroup;
import org.atriasoft.archidata.dataAccess.DataAccess;
import org.atriasoft.archidata.dataAccess.addOnSQL.AddOnDataJson;
import org.atriasoft.archidata.tools.DataTools;
import org.atriasoft.karusic.model.Playlist;
import org.bson.types.ObjectId;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -48,7 +44,7 @@ public class PlaylistResource {
@POST
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Playlist post(@Valid final Playlist data) throws Exception {
public Playlist post(@Valid @ValidGroup(GroupCreate.class) final Playlist data) throws Exception {
return DataAccess.insert(data);
}
@@ -56,7 +52,7 @@ public class PlaylistResource {
@Path("{oid}")
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Playlist put(@PathParam("oid") final ObjectId oid, @Valid final Playlist playlist) throws Exception {
public Playlist put(@PathParam("oid") final ObjectId oid, @Valid @ValidGroup(GroupUpdate.class) final Playlist playlist) throws Exception {
playlist.oid = oid;
DataAccess.update(playlist, oid);
return DataAccess.get(Playlist.class, oid);
@@ -69,25 +65,4 @@ public class PlaylistResource {
DataAccess.delete(Playlist.class, oid);
}
@POST
@Path("{oid}/cover")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
@ApiAsyncType(Playlist.class)
public void uploadCover(@PathParam("oid") final ObjectId oid, @FormDataParam("file") final InputStream fileInputStream, @FormDataParam("file") final FormDataContentDisposition fileMetaData)
throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
DataTools.uploadCover(db, Playlist.class, oid, fileInputStream, fileMetaData);
}
}
@DELETE
@Path("{oid}/cover/{coverId}")
@RolesAllowed("ADMIN")
public Playlist removeCover(@PathParam("oid") final ObjectId oid, @PathParam("coverId") final ObjectId coverId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Playlist.class, "id", oid, "covers", coverId);
return DataAccess.get(Playlist.class, oid);
}
}
}

View File

@@ -9,9 +9,11 @@ import java.util.List;
import org.atriasoft.archidata.annotation.apiGenerator.ApiAsyncType;
import org.atriasoft.archidata.annotation.apiGenerator.ApiInputOptional;
import org.atriasoft.archidata.annotation.apiGenerator.ApiTypeScriptProgress;
import org.atriasoft.archidata.annotation.checker.GroupCreate;
import org.atriasoft.archidata.annotation.checker.GroupUpdate;
import org.atriasoft.archidata.annotation.checker.ValidGroup;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.dataAccess.DataAccess;
import org.atriasoft.archidata.dataAccess.addOnSQL.AddOnDataJson;
import org.atriasoft.archidata.model.Data;
import org.atriasoft.archidata.tools.DataTools;
import org.atriasoft.karusic.model.Track;
@@ -55,7 +57,7 @@ public class TrackResource {
@POST
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Track post(@Valid final Track data) throws Exception {
public Track post(@Valid @ValidGroup(GroupCreate.class) final Track data) throws Exception {
return DataAccess.insert(data);
}
@@ -63,7 +65,7 @@ public class TrackResource {
@Path("{oid}")
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Track put(@PathParam("oid") final ObjectId oid, @Valid final Track track) throws Exception {
public Track put(@PathParam("oid") final ObjectId oid, @Valid @ValidGroup(GroupUpdate.class) final Track track) throws Exception {
track.oid = oid;
DataAccess.update(track, oid);
return DataAccess.get(Track.class, oid);
@@ -76,33 +78,6 @@ public class TrackResource {
DataAccess.delete(Track.class, oid);
}
@POST
@Path("{oid}/cover")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
@ApiTypeScriptProgress
public Track uploadCover(@PathParam("oid") final ObjectId oid, @FormDataParam("uri") final String uri, @FormDataParam("file") final InputStream fileInputStream,
@FormDataParam("file") final FormDataContentDisposition fileMetaData) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
if (uri != null) {
DataTools.uploadCoverFromUri(db, Track.class, oid, uri);
} else {
DataTools.uploadCover(db, Track.class, oid, fileInputStream, fileMetaData);
}
return DataAccess.get(Track.class, oid);
}
}
@DELETE
@Path("{oid}/cover/{coverId}")
@RolesAllowed("ADMIN")
public Track removeCover(@PathParam("oid") final ObjectId oid, @PathParam("coverId") final ObjectId coverId) throws Exception {
try (DBAccess db = DBAccess.createInterface()) {
AddOnDataJson.removeLink(db, Track.class, "_id", oid, "covers", coverId);
return db.get(Track.class, oid);
}
}
@POST
@Path("upload/")
@RolesAllowed("ADMIN")

View File

@@ -1,13 +1,12 @@
package org.atriasoft.karusic.api;
import java.util.List;
import java.util.Map;
import org.atriasoft.archidata.dataAccess.DataAccess;
import org.atriasoft.archidata.filter.GenericContext;
import org.atriasoft.karusic.api.UserResourceModel.PartRight;
import org.atriasoft.karusic.api.UserResourceModel.UserMe;
import org.atriasoft.karusic.model.UserKarusic;
import org.bson.types.ObjectId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -29,11 +28,11 @@ public class UserResource {
@JsonInclude(JsonInclude.Include.NON_NULL)
public class UserOut {
public long id;
public ObjectId oid;
public String login;
public UserOut(final long id, final String login) {
this.id = id;
public UserOut(final ObjectId oid, final String login) {
this.oid = oid;
this.login = login;
}
@@ -57,9 +56,9 @@ public class UserResource {
// curl http://localhost:9993/api/users/3
@GET
@Path("{id}")
@Path("{oid}")
@RolesAllowed("ADMIN")
public UserKarusic get(@Context final SecurityContext sc, @PathParam("id") final long userId) {
public UserKarusic get(@Context final SecurityContext sc, @PathParam("oid") final ObjectId userId) {
LOGGER.info("getUser {}", userId);
final GenericContext gc = (GenericContext) sc.getUserPrincipal();
LOGGER.info("===================================================");
@@ -81,11 +80,6 @@ public class UserResource {
LOGGER.debug("getMe()");
final GenericContext gc = (GenericContext) sc.getUserPrincipal();
LOGGER.debug("== USER ? {}", gc.userByToken);
return new UserMe(gc.userByToken.id, gc.userByToken.name, //
Map.of(gc.userByToken.name, //
Map.of("admin", PartRight.READ_WRITE, //
"user", PartRight.READ_WRITE), //
"karusic", //
Map.of("user", PartRight.READ)));
return new UserMe(gc.userByToken.oid, gc.userByToken.name);
}
}

View File

@@ -1,21 +1,16 @@
package org.atriasoft.karusic.api.UserResourceModel;
import java.util.Map;
import io.swagger.v3.oas.annotations.media.Schema;
import org.bson.types.ObjectId;
public class UserMe {
public long id;
public ObjectId oid;
public String login;
@Schema(description = "Map<EntityName, Map<PartName, Right>>")
public Map<String, Map<String, PartRight>> rights;
public UserMe() {}
public UserMe(final long id, final String login, final Map<String, Map<String, PartRight>> rights) {
this.id = id;
public UserMe(final ObjectId oid, final String login) {
this.oid = oid;
this.login = login;
this.rights = rights;
}
}

View File

@@ -0,0 +1,47 @@
package org.atriasoft.karusic.job;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import org.atriasoft.archidata.backup.BackupEngine;
import org.atriasoft.archidata.backup.BackupEngine.EngineBackupType;
import org.atriasoft.archidata.exception.DataAccessException;
import org.atriasoft.archidata.tools.ConfigBaseVariable;
import org.atriasoft.karusic.migration.Initialization;
import org.atriasoft.karusic.util.ConfigVariable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class BackupJob implements Runnable {
final static Logger LOGGER = LoggerFactory.getLogger(BackupJob.class);
BackupEngine engine;
public BackupJob() throws DataAccessException, IOException {
final Path path = Paths.get(ConfigVariable.getBackupFolder());
Files.createDirectories(path);
this.engine = new BackupEngine(path, ConfigBaseVariable.getDBName(), EngineBackupType.JSON_EXTENDED);
this.engine.setEnableStoreOrRestoreData(false);
for (final Class<?> clazz : Initialization.CLASSES_BASE) {
this.engine.addClass(clazz);
}
this.engine.addCollection("counters");
this.engine.addCollection("KAR_migration");
}
@Override
public void run() {
LOGGER.warn("Backup request");
try {
final String timestampUtc = ZonedDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd_HH:mm:ss.SSS"));
this.engine.store(timestampUtc + "_full");
} catch (final Exception ex) {
LOGGER.error("Fail in Backup: {}", ex.getMessage());
ex.printStackTrace();
}
}
}

View File

@@ -1,10 +1,19 @@
package org.atriasoft.karusic.migration;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import org.atriasoft.archidata.api.DataResource;
import org.atriasoft.archidata.api.ProxyResource;
import org.atriasoft.archidata.backup.BackupEngine;
import org.atriasoft.archidata.backup.BackupEngine.EngineBackupType;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.db.DbConfig;
import org.atriasoft.archidata.exception.DataAccessException;
import org.atriasoft.archidata.exception.FailException;
import org.atriasoft.archidata.externalRestApi.AnalyzeApi;
import org.atriasoft.archidata.externalRestApi.TsGenerateApi;
import org.atriasoft.archidata.filter.PartRight;
@@ -12,6 +21,7 @@ import org.atriasoft.archidata.migration.MigrationSqlStep;
import org.atriasoft.archidata.model.Data;
import org.atriasoft.archidata.model.User;
import org.atriasoft.archidata.model.token.JwtToken;
import org.atriasoft.archidata.tools.ConfigBaseVariable;
import org.atriasoft.karusic.api.AlbumResource;
import org.atriasoft.karusic.api.ArtistResource;
import org.atriasoft.karusic.api.Front;
@@ -28,6 +38,8 @@ import org.atriasoft.karusic.model.Track;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.InternalServerErrorException;
public class Initialization extends MigrationSqlStep {
private static final Logger LOGGER = LoggerFactory.getLogger(Initialization.class);
@@ -39,6 +51,27 @@ public class Initialization extends MigrationSqlStep {
return "Initialization";
}
public static void removeDB() throws DataAccessException, InternalServerErrorException, IOException {
final DbConfig config = new DbConfig();
LOGGER.info("Remove DB '{}'", config.getDbName());
try (DBAccess dba = DBAccess.createInterface(config)) {
dba.deleteDB(ConfigBaseVariable.bdDatabase);
}
}
/** Restore backup file (./init/backup.tar.gz). */
public static void initializeWithBackup() throws IOException, DataAccessException, FailException {
final Path path = Paths.get("./init/backup.tar.gz");
if (!Files.exists(path)) {
throw new FailException("file: ./init/backup.tar.gz does not exist");
}
removeDB();
final BackupEngine engine = new BackupEngine(Paths.get("."), ConfigBaseVariable.bdDatabase, EngineBackupType.JSON_EXTENDED);
if (!engine.restoreFile(path, null)) {
throw new FailException("Can not retrieve db from backup");
}
}
public static void generateObjects() throws Exception {
LOGGER.info("Generate APIs");
final List<Class<?>> listOfResources = List.of(AlbumResource.class, ArtistResource.class, Front.class, GenderResource.class, HealthCheck.class, PlaylistResource.class, UserResource.class,
@@ -47,7 +80,7 @@ public class Initialization extends MigrationSqlStep {
api.addAllApi(listOfResources);
api.addModel(JwtToken.class);
api.addModel(PartRight.class);
TsGenerateApi.generateApi(api, "../front/src/back-api/");
TsGenerateApi.generateApi(api, Paths.get("../front/src/back-api/"));
LOGGER.info("Generate APIs (DONE)");
}

View File

@@ -1,14 +0,0 @@
package org.atriasoft.karusic.migration;
import org.atriasoft.archidata.migration.MigrationSqlStep;
public class Migration20231126 extends MigrationSqlStep {
public static final int KARSO_INITIALISATION_ID = 1;
@Override
public String getName() {
return "migration-2023-11-26: reorder the migration for the new API of archidata";
}
}

View File

@@ -1,14 +0,0 @@
package org.atriasoft.karusic.migration;
import org.atriasoft.archidata.migration.MigrationSqlStep;
public class Migration20240225 extends MigrationSqlStep {
public static final int KARSO_INITIALISATION_ID = 1;
@Override
public String getName() {
return "migration-2024-02-25: change model of thrack to use real json";
}
}

View File

@@ -1,17 +0,0 @@
package org.atriasoft.karusic.migration;
import org.atriasoft.archidata.migration.MigrationSqlStep;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Migration20240226 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-2024-02-26: convert base with UUID";
}
}

View File

@@ -1,34 +0,0 @@
package org.atriasoft.karusic.migration;
import org.atriasoft.archidata.migration.MigrationSqlStep;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Migration20240907 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-2024-09-07: convert data id in uuid";
}
public Migration20240907() {
}
@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

@@ -1,144 +0,0 @@
package org.atriasoft.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.atriasoft.archidata.api.DataResource;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.dataAccess.options.AccessDeletedItems;
import org.atriasoft.archidata.dataAccess.options.OverrideTableName;
import org.atriasoft.archidata.migration.MigrationSqlStep;
import org.atriasoft.karusic.migration.model.CoverConversion;
import org.atriasoft.karusic.migration.model.MediaConversion;
import org.atriasoft.karusic.migration.model.OIDConversion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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

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

View File

@@ -24,7 +24,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Migration20250427 extends MigrationSqlStep {
private static final Logger LOGGER = LoggerFactory.getLogger(Migration20240226.class);
private static final Logger LOGGER = LoggerFactory.getLogger(Migration20250427.class);
public static final int KARSO_INITIALISATION_ID = 1;
@@ -73,10 +73,8 @@ public class Migration20250427 extends MigrationSqlStep {
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()));
final DbConfig configSQL = 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());

View File

@@ -0,0 +1,27 @@
package org.atriasoft.karusic.migration;
import org.atriasoft.archidata.dataAccess.DBAccess;
import org.atriasoft.archidata.dataAccess.DBAccessMongo;
import org.atriasoft.archidata.migration.MigrationSqlStep;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Migration20250928 extends MigrationSqlStep {
private static final Logger LOGGER = LoggerFactory.getLogger(Migration20250928.class);
public static final int KARSO_INITIALISATION_ID = 1;
@Override
public String getName() {
return "migration-2025-09-28: Renzme collection Data in Data";
}
@Override
public void generateStep() throws Exception {
addAction((final DBAccess da) -> {
if (da instanceof final DBAccessMongo daMongo) {
daMongo.renameCollection("Data", "data");
}
});
}
}

View File

@@ -4,7 +4,6 @@ import java.util.Date;
import java.util.List;
import org.atriasoft.archidata.annotation.DataIfNotExists;
import org.atriasoft.archidata.annotation.apiGenerator.ApiAccessLimitation;
import org.atriasoft.archidata.annotation.apiGenerator.ApiGenerationMode;
import org.atriasoft.archidata.annotation.checker.CheckForeignKey;
import org.atriasoft.archidata.annotation.checker.CollectionNotEmpty;
@@ -15,10 +14,10 @@ import org.hibernate.validator.constraints.UniqueElements;
import com.fasterxml.jackson.annotation.JsonInclude;
import dev.morphia.annotations.Entity;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
@@ -37,7 +36,6 @@ public class Album extends OIDGenericDataSoftDelete {
@Nullable
@CollectionNotEmpty
@UniqueElements
@ApiAccessLimitation(readable = true, creatable = false, updatable = false)
public List<@CheckForeignKey(target = Data.class) @NotNull ObjectId> covers = null;
public Date publication;

View File

@@ -4,7 +4,6 @@ import java.util.Date;
import java.util.List;
import org.atriasoft.archidata.annotation.DataIfNotExists;
import org.atriasoft.archidata.annotation.apiGenerator.ApiAccessLimitation;
import org.atriasoft.archidata.annotation.apiGenerator.ApiGenerationMode;
import org.atriasoft.archidata.annotation.checker.CheckForeignKey;
import org.atriasoft.archidata.annotation.checker.CollectionNotEmpty;
@@ -15,10 +14,10 @@ import org.hibernate.validator.constraints.UniqueElements;
import com.fasterxml.jackson.annotation.JsonInclude;
import dev.morphia.annotations.Entity;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
@@ -37,7 +36,6 @@ public class Artist extends OIDGenericDataSoftDelete {
@Nullable
@CollectionNotEmpty
@UniqueElements
@ApiAccessLimitation(readable = true, creatable = false, updatable = false)
public List<@CheckForeignKey(target = Data.class) @NotNull ObjectId> covers = null;
@Column(length = 256)
@Size(min = 1, max = 256)

View File

@@ -15,7 +15,6 @@ CREATE TABLE `node` (
import java.util.List;
import org.atriasoft.archidata.annotation.DataIfNotExists;
import org.atriasoft.archidata.annotation.apiGenerator.ApiAccessLimitation;
import org.atriasoft.archidata.annotation.apiGenerator.ApiGenerationMode;
import org.atriasoft.archidata.annotation.checker.CheckForeignKey;
import org.atriasoft.archidata.annotation.checker.CollectionNotEmpty;
@@ -26,10 +25,10 @@ import org.hibernate.validator.constraints.UniqueElements;
import com.fasterxml.jackson.annotation.JsonInclude;
import dev.morphia.annotations.Entity;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
@@ -48,7 +47,6 @@ public class Gender extends OIDGenericDataSoftDelete {
@Nullable
@CollectionNotEmpty
@UniqueElements
@ApiAccessLimitation(readable = true, creatable = false, updatable = false)
public List<@CheckForeignKey(target = Data.class) @NotNull ObjectId> covers = null;
public Gender() {}

View File

@@ -15,7 +15,6 @@ CREATE TABLE `node` (
import java.util.List;
import org.atriasoft.archidata.annotation.DataIfNotExists;
import org.atriasoft.archidata.annotation.apiGenerator.ApiAccessLimitation;
import org.atriasoft.archidata.annotation.apiGenerator.ApiGenerationMode;
import org.atriasoft.archidata.annotation.checker.CheckForeignKey;
import org.atriasoft.archidata.annotation.checker.CollectionNotEmpty;
@@ -26,10 +25,10 @@ import org.hibernate.validator.constraints.UniqueElements;
import com.fasterxml.jackson.annotation.JsonInclude;
import dev.morphia.annotations.Entity;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
@@ -48,7 +47,6 @@ public class Playlist extends OIDGenericDataSoftDelete {
@Nullable
@CollectionNotEmpty
@UniqueElements
@ApiAccessLimitation(readable = true, creatable = false, updatable = false)
public List<@CheckForeignKey(target = Data.class) @NotNull ObjectId> covers = null;
public List<@CheckForeignKey(target = Track.class) @NotNull ObjectId> tracks = null;
}

View File

@@ -1,21 +1,8 @@
package org.atriasoft.karusic.model;
/*
CREATE TABLE `node` (
`id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY,
`deleted` BOOLEAN NOT NULL DEFAULT false,
`create_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been created',
`modify_date` datetime NOT NULL DEFAULT now() COMMENT 'Time the element has been update',
`type` enum("TYPE", "UNIVERS", "SERIE", "SAISON", "MEDIA") NOT NULL DEFAULT 'TYPE',
`name` TEXT COLLATE 'utf8_general_ci' NOT NULL,
`description` TEXT COLLATE 'utf8_general_ci',
`parent_id` bigint
) AUTO_INCREMENT=10;
*/
import java.util.List;
import org.atriasoft.archidata.annotation.DataIfNotExists;
import org.atriasoft.archidata.annotation.apiGenerator.ApiAccessLimitation;
import org.atriasoft.archidata.annotation.apiGenerator.ApiGenerationMode;
import org.atriasoft.archidata.annotation.checker.CheckForeignKey;
import org.atriasoft.archidata.annotation.checker.CollectionNotEmpty;
@@ -26,10 +13,10 @@ import org.hibernate.validator.constraints.UniqueElements;
import com.fasterxml.jackson.annotation.JsonInclude;
import dev.morphia.annotations.Entity;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.PositiveOrZero;
import jakarta.validation.constraints.Size;
@@ -50,7 +37,6 @@ public class Track extends OIDGenericDataSoftDelete {
@Nullable
@CollectionNotEmpty
@UniqueElements
@ApiAccessLimitation(readable = true, creatable = false, updatable = false)
public List<@CheckForeignKey(target = Data.class) @NotNull ObjectId> covers = null;
@CheckForeignKey(target = Gender.class)
public ObjectId genderId = null;

View File

@@ -4,11 +4,26 @@ public class ConfigVariable {
public static final String BASE_NAME = "ORG_KARUSIC_";
public static String getFrontFolder() {
String out = System.getenv(BASE_NAME + "FRONT_FOLDER");
final String out = System.getenv(BASE_NAME + "FRONT_FOLDER");
if (out == null) {
return "/application/front";
}
return out;
}
public static String getBackupFolder() {
final String out = System.getenv(BASE_NAME + "BACKUP_FOLDER");
if (out == null) {
return "/application/backup";
}
return out;
}
public static boolean isInitWithBackup() {
final String out = System.getenv(BASE_NAME + "INIT_WITH_BACKUP");
if (out == null) {
return false;
}
return "true".equals(out);
}
}

View File

@@ -18,60 +18,15 @@ public class ConfigureDb {
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;
}
// for local test:
ConfigBaseVariable.apiAdress = "http://127.0.0.1:12342/test/api/";
// Enable the test mode permit to access to the test token (never use it in production).
ConfigBaseVariable.testMode = "true";
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.atriasoftusic_db";
ConfigBaseVariable.dbPort = "3906";
ConfigBaseVariable.dbUser = "root";
} else if ("MONGO".equalsIgnoreCase(modeTest)) {
ConfigBaseVariable.dbType = "mongo";
ConfigBaseVariable.bdDatabase = "test.atriasoftusic_db";
} else {
// User local modification ...
ConfigBaseVariable.bdDatabase = "test.atriasoftusic_db";
ConfigBaseVariable.dbPort = "3906";
ConfigBaseVariable.dbUser = "root";
}
ConfigBaseVariable.dbType = "mongo";
ConfigBaseVariable.bdDatabase = "test_karusic_db";
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();
@@ -80,18 +35,9 @@ public class ConfigureDb {
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.deleteDB(ConfigBaseVariable.bdDatabase);
daRoot.createDB(ConfigBaseVariable.bdDatabase);
} catch (final InternalServerErrorException e) {
e.printStackTrace();

View File

@@ -4,12 +4,10 @@
import {
HTTPMimeType,
HTTPRequestModel,
RESTCallbacks,
RESTConfig,
RESTRequestJson,
RESTRequestVoid,
} from "../rest-tools";
import { z as zod } from "zod"
import {
Album,
@@ -21,7 +19,6 @@ import {
} from "../model";
export namespace AlbumResource {
/**
* Get a specific Album with his ID
*/
@@ -144,60 +141,4 @@ export namespace AlbumResource {
params,
});
};
/**
* Remove a cover on a specific album
*/
export function removeCover({
restConfig,
params,
}: {
restConfig: RESTConfig,
params: {
coverId: ObjectId,
oid: ObjectId,
},
}): Promise<Album> {
return RESTRequestJson({
restModel: {
endPoint: "/album/{oid}/cover/{coverId}",
requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isAlbum);
};
/**
* Add a cover on a specific album
*/
export function uploadCover({
restConfig,
params,
data,
callbacks,
}: {
restConfig: RESTConfig,
params: {
oid: ObjectId,
},
data: {
file?: File,
uri?: string,
},
callbacks?: RESTCallbacks,
}): Promise<Album> {
return RESTRequestJson({
restModel: {
endPoint: "/album/{oid}/cover",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
callbacks,
}, isAlbum);
};
}

View File

@@ -4,12 +4,10 @@
import {
HTTPMimeType,
HTTPRequestModel,
RESTCallbacks,
RESTConfig,
RESTRequestJson,
RESTRequestVoid,
} from "../rest-tools";
import { z as zod } from "zod"
import {
Artist,
@@ -21,7 +19,6 @@ import {
} from "../model";
export namespace ArtistResource {
export function get({
restConfig,
params,
@@ -129,54 +126,4 @@ export namespace ArtistResource {
params,
});
};
export function removeCover({
restConfig,
params,
}: {
restConfig: RESTConfig,
params: {
coverId: ObjectId,
oid: ObjectId,
},
}): Promise<Artist> {
return RESTRequestJson({
restModel: {
endPoint: "/artist/{oid}/cover/{coverId}",
requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isArtist);
};
export function uploadCover({
restConfig,
params,
data,
callbacks,
}: {
restConfig: RESTConfig,
params: {
oid: ObjectId,
},
data: {
file?: File,
uri?: string,
},
callbacks?: RESTCallbacks,
}): Promise<Artist> {
return RESTRequestJson({
restModel: {
endPoint: "/artist/{oid}/cover",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
callbacks,
}, isArtist);
};
}

View File

@@ -4,17 +4,16 @@
import {
HTTPMimeType,
HTTPRequestModel,
RESTCallbacks,
RESTConfig,
RESTRequestJson,
RESTRequestVoid,
} from "../rest-tools";
import {
ObjectId,
isObjectId,
} from "../model";
export namespace DataResource {
/**
* Get back some data from the data environment (with a beautiful name (permit download with basic name)
*/
@@ -110,25 +109,55 @@ export namespace DataResource {
});
};
/**
* Insert a new data in the data environment
* Upload data in the system
*/
export function uploadFile({
export function uploadMedia({
restConfig,
data,
callbacks,
}: {
restConfig: RESTConfig,
data: {
file: File,
},
}): Promise<void> {
return RESTRequestVoid({
callbacks?: RESTCallbacks,
}): Promise<ObjectId> {
return RESTRequestJson({
restModel: {
endPoint: "/data//upload/",
endPoint: "/data/upload",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
},
restConfig,
data,
});
callbacks,
}, isObjectId);
};
/**
* Upload data in the system with an external URI
*/
export function uploadMediaFromUri({
restConfig,
queries,
callbacks,
}: {
restConfig: RESTConfig,
queries: {
uri?: string,
},
callbacks?: RESTCallbacks,
}): Promise<ObjectId> {
return RESTRequestJson({
restModel: {
endPoint: "/data/uploadUri",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.JSON,
accept: HTTPMimeType.JSON,
},
restConfig,
queries,
callbacks,
}, isObjectId);
};
}

View File

@@ -1,6 +1,6 @@
/**
* Interface of the server (auto-generated code)
*/
export namespace Front {
export namespace Front {
}

View File

@@ -4,12 +4,10 @@
import {
HTTPMimeType,
HTTPRequestModel,
RESTCallbacks,
RESTConfig,
RESTRequestJson,
RESTRequestVoid,
} from "../rest-tools";
import { z as zod } from "zod"
import {
Gender,
@@ -21,7 +19,6 @@ import {
} from "../model";
export namespace GenderResource {
export function get({
restConfig,
params,
@@ -129,54 +126,4 @@ export namespace GenderResource {
params,
});
};
export function removeCover({
restConfig,
params,
}: {
restConfig: RESTConfig,
params: {
coverId: ObjectId,
oid: ObjectId,
},
}): Promise<Gender> {
return RESTRequestJson({
restModel: {
endPoint: "/gender/{oid}/cover/{coverId}",
requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isGender);
};
export function uploadCover({
restConfig,
params,
data,
callbacks,
}: {
restConfig: RESTConfig,
params: {
oid: ObjectId,
},
data: {
file?: File,
uri?: string,
},
callbacks?: RESTCallbacks,
}): Promise<Gender> {
return RESTRequestJson({
restModel: {
endPoint: "/gender/{oid}/cover",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
callbacks,
}, isGender);
};
}

View File

@@ -7,14 +7,12 @@ import {
RESTConfig,
RESTRequestJson,
} from "../rest-tools";
import {
HealthResult,
isHealthResult,
} from "../model";
export namespace HealthCheck {
export function getHealth({
restConfig,
}: {

View File

@@ -8,7 +8,6 @@ import {
RESTRequestJson,
RESTRequestVoid,
} from "../rest-tools";
import { z as zod } from "zod"
import {
ObjectId,
@@ -20,7 +19,6 @@ import {
} from "../model";
export namespace PlaylistResource {
export function get({
restConfig,
params,
@@ -128,50 +126,4 @@ export namespace PlaylistResource {
params,
});
};
export function removeCover({
restConfig,
params,
}: {
restConfig: RESTConfig,
params: {
coverId: ObjectId,
oid: ObjectId,
},
}): Promise<Playlist> {
return RESTRequestJson({
restModel: {
endPoint: "/playlist/{oid}/cover/{coverId}",
requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isPlaylist);
};
export function uploadCover({
restConfig,
params,
data,
}: {
restConfig: RESTConfig,
params: {
oid: ObjectId,
},
data: {
file: File,
},
}): Promise<Playlist> {
return RESTRequestJson({
restModel: {
endPoint: "/playlist/{oid}/cover",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
}, isPlaylist);
};
}

View File

@@ -8,7 +8,6 @@ import {
} from "../rest-tools";
export namespace ProxyResource {
export function getImageFromUrl({
restConfig,
queries,

View File

@@ -9,7 +9,6 @@ import {
RESTRequestJson,
RESTRequestVoid,
} from "../rest-tools";
import { z as zod } from "zod"
import {
Long,
@@ -22,7 +21,6 @@ import {
} from "../model";
export namespace TrackResource {
export function get({
restConfig,
params,
@@ -130,56 +128,6 @@ export namespace TrackResource {
params,
});
};
export function removeCover({
restConfig,
params,
}: {
restConfig: RESTConfig,
params: {
coverId: ObjectId,
oid: ObjectId,
},
}): Promise<Track> {
return RESTRequestJson({
restModel: {
endPoint: "/track/{oid}/cover/{coverId}",
requestType: HTTPRequestModel.DELETE,
contentType: HTTPMimeType.TEXT_PLAIN,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isTrack);
};
export function uploadCover({
restConfig,
params,
data,
callbacks,
}: {
restConfig: RESTConfig,
params: {
oid: ObjectId,
},
data: {
file: File,
uri: string,
},
callbacks?: RESTCallbacks,
}): Promise<Track> {
return RESTRequestJson({
restModel: {
endPoint: "/track/{oid}/cover",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
callbacks,
}, isTrack);
};
export function uploadTrack({
restConfig,
data,

View File

@@ -7,10 +7,9 @@ import {
RESTConfig,
RESTRequestJson,
} from "../rest-tools";
import { z as zod } from "zod"
import {
Long,
ObjectId,
UserKarusic,
UserMe,
ZodUserKarusic,
@@ -19,19 +18,18 @@ import {
} from "../model";
export namespace UserResource {
export function get({
restConfig,
params,
}: {
restConfig: RESTConfig,
params: {
id: Long,
oid: ObjectId,
},
}): Promise<UserKarusic> {
return RESTRequestJson({
restModel: {
endPoint: "/users/{id}",
endPoint: "/users/{oid}",
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON,
},

View File

@@ -2,10 +2,13 @@
* Interface of the server (auto-generated code)
*/
import { z as zod } from "zod";
import {ZodIsoDate} from "./iso-date";
import {ZodObjectId} from "./object-id";
import {ZodOIDGenericDataSoftDelete, ZodOIDGenericDataSoftDeleteUpdate , ZodOIDGenericDataSoftDeleteCreate } from "./oid-generic-data-soft-delete";
import { ZodIsoDate } from "./iso-date";
import { ZodObjectId } from "./object-id";
import {
ZodOIDGenericDataSoftDelete,
ZodOIDGenericDataSoftDeleteCreate,
ZodOIDGenericDataSoftDeleteUpdate,
} from "./oid-generic-data-soft-delete";
export const ZodAlbum = ZodOIDGenericDataSoftDelete.extend({
name: zod.string().min(1).max(256).optional(),
@@ -13,9 +16,8 @@ export const ZodAlbum = ZodOIDGenericDataSoftDelete.extend({
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodObjectId).readonly().optional(),
covers: zod.array(ZodObjectId).optional(),
publication: ZodIsoDate.optional(),
});
export type Album = zod.infer<typeof ZodAlbum>;
@@ -29,29 +31,15 @@ export function isAlbum(data: any): data is Album {
return false;
}
}
export const ZodAlbumUpdate = ZodOIDGenericDataSoftDeleteUpdate.extend({
name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().max(8192).nullable().optional(),
publication: ZodIsoDate.nullable().optional(),
});
export type AlbumUpdate = zod.infer<typeof ZodAlbumUpdate>;
export function isAlbumUpdate(data: any): data is AlbumUpdate {
try {
ZodAlbumUpdate.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodAlbumUpdate' error=${e}`);
return false;
}
}
export const ZodAlbumCreate = ZodOIDGenericDataSoftDeleteCreate.extend({
name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().max(8192).nullable().optional(),
publication: ZodIsoDate.nullable().optional(),
name: zod.string().min(1).max(256).optional(),
description: zod.string().max(8192).optional(),
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodObjectId).optional(),
publication: ZodIsoDate.optional(),
});
export type AlbumCreate = zod.infer<typeof ZodAlbumCreate>;
@@ -65,3 +53,25 @@ export function isAlbumCreate(data: any): data is AlbumCreate {
return false;
}
}
export const ZodAlbumUpdate = ZodOIDGenericDataSoftDeleteUpdate.extend({
name: zod.string().min(1).max(256).optional(),
description: zod.string().max(8192).optional(),
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodObjectId).optional(),
publication: ZodIsoDate.optional(),
});
export type AlbumUpdate = zod.infer<typeof ZodAlbumUpdate>;
export function isAlbumUpdate(data: any): data is AlbumUpdate {
try {
ZodAlbumUpdate.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodAlbumUpdate' error=${e}`);
return false;
}
}

View File

@@ -2,10 +2,13 @@
* Interface of the server (auto-generated code)
*/
import { z as zod } from "zod";
import {ZodIsoDate} from "./iso-date";
import {ZodObjectId} from "./object-id";
import {ZodOIDGenericDataSoftDelete, ZodOIDGenericDataSoftDeleteUpdate , ZodOIDGenericDataSoftDeleteCreate } from "./oid-generic-data-soft-delete";
import { ZodIsoDate } from "./iso-date";
import { ZodObjectId } from "./object-id";
import {
ZodOIDGenericDataSoftDelete,
ZodOIDGenericDataSoftDeleteCreate,
ZodOIDGenericDataSoftDeleteUpdate,
} from "./oid-generic-data-soft-delete";
export const ZodArtist = ZodOIDGenericDataSoftDelete.extend({
name: zod.string().min(1).max(256).optional(),
@@ -13,12 +16,11 @@ export const ZodArtist = ZodOIDGenericDataSoftDelete.extend({
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodObjectId).readonly().optional(),
covers: zod.array(ZodObjectId).optional(),
firstName: zod.string().min(1).max(256).optional(),
surname: zod.string().min(1).max(256).optional(),
birth: ZodIsoDate.optional(),
death: ZodIsoDate.optional(),
});
export type Artist = zod.infer<typeof ZodArtist>;
@@ -32,35 +34,18 @@ export function isArtist(data: any): data is Artist {
return false;
}
}
export const ZodArtistUpdate = ZodOIDGenericDataSoftDeleteUpdate.extend({
name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().max(8192).nullable().optional(),
firstName: zod.string().min(1).max(256).nullable().optional(),
surname: zod.string().min(1).max(256).nullable().optional(),
birth: ZodIsoDate.nullable().optional(),
death: ZodIsoDate.nullable().optional(),
});
export type ArtistUpdate = zod.infer<typeof ZodArtistUpdate>;
export function isArtistUpdate(data: any): data is ArtistUpdate {
try {
ZodArtistUpdate.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodArtistUpdate' error=${e}`);
return false;
}
}
export const ZodArtistCreate = ZodOIDGenericDataSoftDeleteCreate.extend({
name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().max(8192).nullable().optional(),
firstName: zod.string().min(1).max(256).nullable().optional(),
surname: zod.string().min(1).max(256).nullable().optional(),
birth: ZodIsoDate.nullable().optional(),
death: ZodIsoDate.nullable().optional(),
name: zod.string().min(1).max(256).optional(),
description: zod.string().max(8192).optional(),
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodObjectId).optional(),
firstName: zod.string().min(1).max(256).optional(),
surname: zod.string().min(1).max(256).optional(),
birth: ZodIsoDate.optional(),
death: ZodIsoDate.optional(),
});
export type ArtistCreate = zod.infer<typeof ZodArtistCreate>;
@@ -74,3 +59,28 @@ export function isArtistCreate(data: any): data is ArtistCreate {
return false;
}
}
export const ZodArtistUpdate = ZodOIDGenericDataSoftDeleteUpdate.extend({
name: zod.string().min(1).max(256).optional(),
description: zod.string().max(8192).optional(),
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodObjectId).optional(),
firstName: zod.string().min(1).max(256).optional(),
surname: zod.string().min(1).max(256).optional(),
birth: ZodIsoDate.optional(),
death: ZodIsoDate.optional(),
});
export type ArtistUpdate = zod.infer<typeof ZodArtistUpdate>;
export function isArtistUpdate(data: any): data is ArtistUpdate {
try {
ZodArtistUpdate.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodArtistUpdate' error=${e}`);
return false;
}
}

View File

@@ -2,9 +2,12 @@
* Interface of the server (auto-generated code)
*/
import { z as zod } from "zod";
import {ZodObjectId} from "./object-id";
import {ZodOIDGenericDataSoftDelete, ZodOIDGenericDataSoftDeleteUpdate , ZodOIDGenericDataSoftDeleteCreate } from "./oid-generic-data-soft-delete";
import { ZodObjectId } from "./object-id";
import {
ZodOIDGenericDataSoftDelete,
ZodOIDGenericDataSoftDeleteCreate,
ZodOIDGenericDataSoftDeleteUpdate,
} from "./oid-generic-data-soft-delete";
export const ZodGender = ZodOIDGenericDataSoftDelete.extend({
name: zod.string().min(1).max(256).optional(),
@@ -12,8 +15,7 @@ export const ZodGender = ZodOIDGenericDataSoftDelete.extend({
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodObjectId).readonly().optional(),
covers: zod.array(ZodObjectId).optional(),
});
export type Gender = zod.infer<typeof ZodGender>;
@@ -27,27 +29,14 @@ export function isGender(data: any): data is Gender {
return false;
}
}
export const ZodGenderUpdate = ZodOIDGenericDataSoftDeleteUpdate.extend({
name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().max(8192).nullable().optional(),
});
export type GenderUpdate = zod.infer<typeof ZodGenderUpdate>;
export function isGenderUpdate(data: any): data is GenderUpdate {
try {
ZodGenderUpdate.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodGenderUpdate' error=${e}`);
return false;
}
}
export const ZodGenderCreate = ZodOIDGenericDataSoftDeleteCreate.extend({
name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().max(8192).nullable().optional(),
name: zod.string().min(1).max(256).optional(),
description: zod.string().max(8192).optional(),
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodObjectId).optional(),
});
export type GenderCreate = zod.infer<typeof ZodGenderCreate>;
@@ -61,3 +50,24 @@ export function isGenderCreate(data: any): data is GenderCreate {
return false;
}
}
export const ZodGenderUpdate = ZodOIDGenericDataSoftDeleteUpdate.extend({
name: zod.string().min(1).max(256).optional(),
description: zod.string().max(8192).optional(),
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodObjectId).optional(),
});
export type GenderUpdate = zod.infer<typeof ZodGenderUpdate>;
export function isGenderUpdate(data: any): data is GenderUpdate {
try {
ZodGenderUpdate.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodGenderUpdate' error=${e}`);
return false;
}
}

View File

@@ -2,15 +2,13 @@
* Interface of the server (auto-generated code)
*/
import { z as zod } from "zod";
import {ZodGenericData, ZodGenericDataUpdate , ZodGenericDataCreate } from "./generic-data";
import { ZodGenericData } from "./generic-data";
export const ZodGenericDataSoftDelete = ZodGenericData.extend({
/**
* Deleted state
*/
deleted: zod.boolean().readonly().optional(),
});
export type GenericDataSoftDelete = zod.infer<typeof ZodGenericDataSoftDelete>;
@@ -24,29 +22,3 @@ export function isGenericDataSoftDelete(data: any): data is GenericDataSoftDelet
return false;
}
}
export const ZodGenericDataSoftDeleteUpdate = ZodGenericDataUpdate;
export type GenericDataSoftDeleteUpdate = zod.infer<typeof ZodGenericDataSoftDeleteUpdate>;
export function isGenericDataSoftDeleteUpdate(data: any): data is GenericDataSoftDeleteUpdate {
try {
ZodGenericDataSoftDeleteUpdate.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodGenericDataSoftDeleteUpdate' error=${e}`);
return false;
}
}
export const ZodGenericDataSoftDeleteCreate = ZodGenericDataCreate;
export type GenericDataSoftDeleteCreate = zod.infer<typeof ZodGenericDataSoftDeleteCreate>;
export function isGenericDataSoftDeleteCreate(data: any): data is GenericDataSoftDeleteCreate {
try {
ZodGenericDataSoftDeleteCreate.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodGenericDataSoftDeleteCreate' error=${e}`);
return false;
}
}

View File

@@ -2,16 +2,14 @@
* Interface of the server (auto-generated code)
*/
import { z as zod } from "zod";
import {ZodGenericTiming, ZodGenericTimingUpdate , ZodGenericTimingCreate } from "./generic-timing";
import {ZodLong} from "./long";
import { ZodGenericTiming } from "./generic-timing";
import { ZodLong } from "./long";
export const ZodGenericData = ZodGenericTiming.extend({
/**
* Unique Id of the object
*/
id: ZodLong.readonly(),
});
export type GenericData = zod.infer<typeof ZodGenericData>;
@@ -25,29 +23,3 @@ export function isGenericData(data: any): data is GenericData {
return false;
}
}
export const ZodGenericDataUpdate = ZodGenericTimingUpdate;
export type GenericDataUpdate = zod.infer<typeof ZodGenericDataUpdate>;
export function isGenericDataUpdate(data: any): data is GenericDataUpdate {
try {
ZodGenericDataUpdate.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodGenericDataUpdate' error=${e}`);
return false;
}
}
export const ZodGenericDataCreate = ZodGenericTimingCreate;
export type GenericDataCreate = zod.infer<typeof ZodGenericDataCreate>;
export function isGenericDataCreate(data: any): data is GenericDataCreate {
try {
ZodGenericDataCreate.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodGenericDataCreate' error=${e}`);
return false;
}
}

View File

@@ -2,8 +2,7 @@
* Interface of the server (auto-generated code)
*/
import { z as zod } from "zod";
import {ZodIsoDate} from "./iso-date";
import { ZodIsoDate } from "./iso-date";
export const ZodGenericTiming = zod.object({
/**
@@ -28,21 +27,7 @@ export function isGenericTiming(data: any): data is GenericTiming {
return false;
}
}
export const ZodGenericTimingUpdate = zod.object({
});
export type GenericTimingUpdate = zod.infer<typeof ZodGenericTimingUpdate>;
export function isGenericTimingUpdate(data: any): data is GenericTimingUpdate {
try {
ZodGenericTimingUpdate.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodGenericTimingUpdate' error=${e}`);
return false;
}
}
export const ZodGenericTimingCreate = zod.object({
});
@@ -58,3 +43,19 @@ export function isGenericTimingCreate(data: any): data is GenericTimingCreate {
return false;
}
}
export const ZodGenericTimingUpdate = zod.object({
});
export type GenericTimingUpdate = zod.infer<typeof ZodGenericTimingUpdate>;
export function isGenericTimingUpdate(data: any): data is GenericTimingUpdate {
try {
ZodGenericTimingUpdate.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodGenericTimingUpdate' error=${e}`);
return false;
}
}

View File

@@ -3,7 +3,6 @@
*/
import { z as zod } from "zod";
export const ZodHealthResult = zod.object({
});

View File

@@ -4,8 +4,6 @@
export * from "./album"
export * from "./artist"
export * from "./gender"
export * from "./generic-data"
export * from "./generic-data-soft-delete"
export * from "./generic-timing"
export * from "./health-result"
export * from "./integer"
@@ -18,11 +16,9 @@ export * from "./object-id"
export * from "./oid-generic-data"
export * from "./oid-generic-data-soft-delete"
export * from "./part-right"
export * from "./part-right"
export * from "./playlist"
export * from "./rest-error-response"
export * from "./rest-input-error"
export * from "./timestamp"
export * from "./track"
export * from "./user"
export * from "./user-karusic"

View File

@@ -3,6 +3,15 @@
*/
import { z as zod } from "zod";
export const ZodInteger = zod.number().safe();
export type Integer = zod.infer<typeof ZodInteger>;
export function isInteger(data: any): data is Integer {
try {
ZodInteger.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodInteger' error=${e}`);
return false;
}
}

View File

@@ -3,6 +3,15 @@
*/
import { z as zod } from "zod";
export const ZodIsoDate = zod.string().datetime({ precision: 3 });
export type IsoDate = zod.infer<typeof ZodIsoDate>;
export function isIsoDate(data: any): data is IsoDate {
try {
ZodIsoDate.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodIsoDate' error=${e}`);
return false;
}
}

View File

@@ -3,7 +3,6 @@
*/
import { z as zod } from "zod";
export const ZodJwtHeader = zod.object({
typ: zod.string().max(128),
alg: zod.string().max(128),

View File

@@ -2,8 +2,7 @@
* Interface of the server (auto-generated code)
*/
import { z as zod } from "zod";
import {ZodLong} from "./long";
import { ZodLong } from "./long";
export const ZodJwtPayload = zod.object({
sub: zod.string(),

View File

@@ -2,10 +2,8 @@
* Interface of the server (auto-generated code)
*/
import { z as zod } from "zod";
import {ZodJwtHeader} from "./jwt-header";
import {ZodJwtPayload} from "./jwt-payload";
import { ZodJwtHeader } from "./jwt-header";
import { ZodJwtPayload } from "./jwt-payload";
export const ZodJwtToken = zod.object({
header: ZodJwtHeader,
payload: ZodJwtPayload,

View File

@@ -1,8 +0,0 @@
/**
* Interface of the server (auto-generated code)
*/
import { z as zod } from "zod";
export const ZodLocalDate = zod.string().date();
export type LocalDate = zod.infer<typeof ZodLocalDate>;

View File

@@ -3,6 +3,15 @@
*/
import { z as zod } from "zod";
export const ZodLong = zod.number();
export type Long = zod.infer<typeof ZodLong>;
export function isLong(data: any): data is Long {
try {
ZodLong.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodLong' error=${e}`);
return false;
}
}

View File

@@ -3,6 +3,15 @@
*/
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>;
export function isObjectId(data: any): data is ObjectId {
try {
ZodObjectId.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodObjectId' error=${e}`);
return false;
}
}

View File

@@ -2,15 +2,17 @@
* Interface of the server (auto-generated code)
*/
import { z as zod } from "zod";
import {ZodOIDGenericData, ZodOIDGenericDataUpdate , ZodOIDGenericDataCreate } from "./oid-generic-data";
import {
ZodOIDGenericData,
ZodOIDGenericDataCreate,
ZodOIDGenericDataUpdate,
} from "./oid-generic-data";
export const ZodOIDGenericDataSoftDelete = ZodOIDGenericData.extend({
/**
* Deleted state
*/
deleted: zod.boolean().readonly().optional(),
});
export type OIDGenericDataSoftDelete = zod.infer<typeof ZodOIDGenericDataSoftDelete>;
@@ -24,19 +26,7 @@ export function isOIDGenericDataSoftDelete(data: any): data is OIDGenericDataSof
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>;
@@ -50,3 +40,17 @@ export function isOIDGenericDataSoftDeleteCreate(data: any): data is OIDGenericD
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;
}
}

View File

@@ -2,16 +2,18 @@
* 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";
import {
ZodGenericTiming,
ZodGenericTimingCreate,
ZodGenericTimingUpdate,
} 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>;
@@ -25,19 +27,7 @@ export function isOIDGenericData(data: any): data is OIDGenericData {
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>;
@@ -51,3 +41,17 @@ export function isOIDGenericDataCreate(data: any): data is OIDGenericDataCreate
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;
}
}

View File

@@ -3,13 +3,12 @@
*/
import { z as zod } from "zod";
export enum PartRight {
READ = 1,
NONE = 0,
WRITE = 2,
READ = 1,
READ_WRITE = 3,
};
WRITE = 2,
};
export const ZodPartRight = zod.nativeEnum(PartRight);

View File

@@ -2,9 +2,12 @@
* Interface of the server (auto-generated code)
*/
import { z as zod } from "zod";
import {ZodObjectId} from "./object-id";
import {ZodOIDGenericDataSoftDelete, ZodOIDGenericDataSoftDeleteUpdate , ZodOIDGenericDataSoftDeleteCreate } from "./oid-generic-data-soft-delete";
import { ZodObjectId } from "./object-id";
import {
ZodOIDGenericDataSoftDelete,
ZodOIDGenericDataSoftDeleteCreate,
ZodOIDGenericDataSoftDeleteUpdate,
} from "./oid-generic-data-soft-delete";
export const ZodPlaylist = ZodOIDGenericDataSoftDelete.extend({
name: zod.string().min(1).max(256).optional(),
@@ -12,9 +15,8 @@ export const ZodPlaylist = ZodOIDGenericDataSoftDelete.extend({
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodObjectId).readonly().optional(),
covers: zod.array(ZodObjectId).optional(),
tracks: zod.array(ZodObjectId).optional(),
});
export type Playlist = zod.infer<typeof ZodPlaylist>;
@@ -28,29 +30,15 @@ export function isPlaylist(data: any): data is Playlist {
return false;
}
}
export const ZodPlaylistUpdate = ZodOIDGenericDataSoftDeleteUpdate.extend({
name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().max(8192).nullable().optional(),
tracks: zod.array(ZodObjectId).nullable().optional(),
});
export type PlaylistUpdate = zod.infer<typeof ZodPlaylistUpdate>;
export function isPlaylistUpdate(data: any): data is PlaylistUpdate {
try {
ZodPlaylistUpdate.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodPlaylistUpdate' error=${e}`);
return false;
}
}
export const ZodPlaylistCreate = ZodOIDGenericDataSoftDeleteCreate.extend({
name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().max(8192).nullable().optional(),
tracks: zod.array(ZodObjectId).nullable().optional(),
name: zod.string().min(1).max(256).optional(),
description: zod.string().max(8192).optional(),
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodObjectId).optional(),
tracks: zod.array(ZodObjectId).optional(),
});
export type PlaylistCreate = zod.infer<typeof ZodPlaylistCreate>;
@@ -64,3 +52,25 @@ export function isPlaylistCreate(data: any): data is PlaylistCreate {
return false;
}
}
export const ZodPlaylistUpdate = ZodOIDGenericDataSoftDeleteUpdate.extend({
name: zod.string().min(1).max(256).optional(),
description: zod.string().max(8192).optional(),
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodObjectId).optional(),
tracks: zod.array(ZodObjectId).optional(),
});
export type PlaylistUpdate = zod.infer<typeof ZodPlaylistUpdate>;
export function isPlaylistUpdate(data: any): data is PlaylistUpdate {
try {
ZodPlaylistUpdate.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodPlaylistUpdate' error=${e}`);
return false;
}
}

View File

@@ -2,11 +2,9 @@
* Interface of the server (auto-generated code)
*/
import { z as zod } from "zod";
import {ZodInteger} from "./integer";
import {ZodObjectId} from "./object-id";
import {ZodRestInputError} from "./rest-input-error";
import { ZodInteger } from "./integer";
import { ZodObjectId } from "./object-id";
import { ZodRestInputError } from "./rest-input-error";
export const ZodRestErrorResponse = zod.object({
oid: ZodObjectId.optional(),
name: zod.string(),

View File

@@ -3,7 +3,6 @@
*/
import { z as zod } from "zod";
export const ZodRestInputError = zod.object({
argument: zod.string().optional(),
path: zod.string().optional(),

View File

@@ -2,10 +2,13 @@
* Interface of the server (auto-generated code)
*/
import { z as zod } from "zod";
import {ZodLong} from "./long";
import {ZodObjectId} from "./object-id";
import {ZodOIDGenericDataSoftDelete, ZodOIDGenericDataSoftDeleteUpdate , ZodOIDGenericDataSoftDeleteCreate } from "./oid-generic-data-soft-delete";
import { ZodLong } from "./long";
import { ZodObjectId } from "./object-id";
import {
ZodOIDGenericDataSoftDelete,
ZodOIDGenericDataSoftDeleteCreate,
ZodOIDGenericDataSoftDeleteUpdate,
} from "./oid-generic-data-soft-delete";
export const ZodTrack = ZodOIDGenericDataSoftDelete.extend({
name: zod.string().min(1).max(256).optional(),
@@ -13,13 +16,12 @@ export const ZodTrack = ZodOIDGenericDataSoftDelete.extend({
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodObjectId).readonly().optional(),
covers: zod.array(ZodObjectId).optional(),
genderId: ZodObjectId.optional(),
albumId: ZodObjectId.optional(),
track: ZodLong.optional(),
dataId: ZodObjectId.optional(),
artists: zod.array(ZodObjectId).optional(),
});
export type Track = zod.infer<typeof ZodTrack>;
@@ -33,37 +35,19 @@ export function isTrack(data: any): data is Track {
return false;
}
}
export const ZodTrackUpdate = ZodOIDGenericDataSoftDeleteUpdate.extend({
name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().max(8192).nullable().optional(),
genderId: ZodObjectId.nullable().optional(),
albumId: ZodObjectId.nullable().optional(),
track: ZodLong.nullable().optional(),
dataId: ZodObjectId.nullable().optional(),
artists: zod.array(ZodObjectId).nullable().optional(),
});
export type TrackUpdate = zod.infer<typeof ZodTrackUpdate>;
export function isTrackUpdate(data: any): data is TrackUpdate {
try {
ZodTrackUpdate.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodTrackUpdate' error=${e}`);
return false;
}
}
export const ZodTrackCreate = ZodOIDGenericDataSoftDeleteCreate.extend({
name: zod.string().min(1).max(256).nullable().optional(),
description: zod.string().max(8192).nullable().optional(),
genderId: ZodObjectId.nullable().optional(),
albumId: ZodObjectId.nullable().optional(),
track: ZodLong.nullable().optional(),
dataId: ZodObjectId.nullable().optional(),
artists: zod.array(ZodObjectId).nullable().optional(),
name: zod.string().min(1).max(256).optional(),
description: zod.string().max(8192).optional(),
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodObjectId).optional(),
genderId: ZodObjectId.optional(),
albumId: ZodObjectId.optional(),
track: ZodLong.optional(),
dataId: ZodObjectId.optional(),
artists: zod.array(ZodObjectId).optional(),
});
export type TrackCreate = zod.infer<typeof ZodTrackCreate>;
@@ -77,3 +61,29 @@ export function isTrackCreate(data: any): data is TrackCreate {
return false;
}
}
export const ZodTrackUpdate = ZodOIDGenericDataSoftDeleteUpdate.extend({
name: zod.string().min(1).max(256).optional(),
description: zod.string().max(8192).optional(),
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodObjectId).optional(),
genderId: ZodObjectId.optional(),
albumId: ZodObjectId.optional(),
track: ZodLong.optional(),
dataId: ZodObjectId.optional(),
artists: zod.array(ZodObjectId).optional(),
});
export type TrackUpdate = zod.infer<typeof ZodTrackUpdate>;
export function isTrackUpdate(data: any): data is TrackUpdate {
try {
ZodTrackUpdate.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodTrackUpdate' error=${e}`);
return false;
}
}

View File

@@ -2,8 +2,7 @@
* Interface of the server (auto-generated code)
*/
import { z as zod } from "zod";
import {ZodUser, ZodUserUpdate , ZodUserCreate } from "./user";
import { ZodUser } from "./user";
export const ZodUserKarusic = ZodUser;

View File

@@ -2,17 +2,11 @@
* Interface of the server (auto-generated code)
*/
import { z as zod } from "zod";
import {ZodLong} from "./long";
import {ZodPartRight} from "./part-right";
import { ZodObjectId } from "./object-id";
export const ZodUserMe = zod.object({
id: ZodLong,
oid: ZodObjectId.optional(),
login: zod.string().optional(),
/**
* Map<EntityName, Map<PartName, Right>>
*/
rights: zod.record(zod.string(), zod.record(zod.string(), ZodPartRight)).optional(),
});

View File

@@ -2,21 +2,19 @@
* Interface of the server (auto-generated code)
*/
import { z as zod } from "zod";
import { ZodIsoDate } from "./iso-date";
import { ZodObjectId } from "./object-id";
import { ZodOIDGenericDataSoftDelete } from "./oid-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 = ZodOIDGenericDataSoftDelete.extend({
login: zod.string().min(3).max(128),
lastConnection: ZodTimestamp.optional(),
lastConnection: ZodIsoDate.optional(),
blocked: zod.boolean().optional(),
blockedReason: zod.string().max(512).optional(),
blockedReason: zod.string().max(512).readonly().optional(),
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodObjectId).optional(),
covers: zod.array(ZodObjectId).readonly().optional(),
});
export type User = zod.infer<typeof ZodUser>;
@@ -30,49 +28,3 @@ export function isUser(data: any): data is User {
return false;
}
}
export const ZodUserUpdate = ZodGenericDataSoftDeleteUpdate.extend({
login: zod.string().min(3).max(128),
lastConnection: ZodTimestamp.nullable().optional(),
blocked: zod.boolean().nullable().optional(),
blockedReason: zod.string().max(512).nullable().optional(),
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodObjectId).nullable().optional(),
});
export type UserUpdate = zod.infer<typeof ZodUserUpdate>;
export function isUserUpdate(data: any): data is UserUpdate {
try {
ZodUserUpdate.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodUserUpdate' error=${e}`);
return false;
}
}
export const ZodUserCreate = ZodGenericDataSoftDeleteCreate.extend({
login: zod.string().min(3).max(128),
lastConnection: ZodTimestamp.nullable().optional(),
blocked: zod.boolean().nullable().optional(),
blockedReason: zod.string().max(512).nullable().optional(),
/**
* List of Id of the specific covers
*/
covers: zod.array(ZodObjectId).nullable().optional(),
});
export type UserCreate = zod.infer<typeof ZodUserCreate>;
export function isUserCreate(data: any): data is UserCreate {
try {
ZodUserCreate.parse(data);
return true;
} catch (e: any) {
console.log(`Fail to parse data type='ZodUserCreate' error=${e}`);
return false;
}
}

View File

@@ -1,8 +0,0 @@
/**
* Interface of the server (auto-generated code)
*/
import { z as zod } from "zod";
export const ZodUUID = zod.string().uuid();
export type UUID = zod.infer<typeof ZodUUID>;

View File

@@ -7,6 +7,7 @@ import { RestErrorResponse, isRestErrorResponse } from './model';
export enum HTTPRequestModel {
ARCHIVE = 'ARCHIVE',
CALL = 'CALL',
DELETE = 'DELETE',
HEAD = 'HEAD',
GET = 'GET',
@@ -33,6 +34,8 @@ export interface RESTConfig {
server: string;
// Token to access of the data.
token?: string;
// api Token to access of the data.
tokenApi?: string;
}
export interface RESTModel {
@@ -123,7 +126,7 @@ export function RESTUrl({
}
if (
queries === undefined &&
(restConfig.token === undefined || restModel.tokenInUrl !== true)
((restConfig.token === undefined && restConfig.tokenApi === undefined) || restModel.tokenInUrl !== true)
) {
return generateUrl;
}
@@ -143,6 +146,9 @@ export function RESTUrl({
if (restConfig.token !== undefined && restModel.tokenInUrl === true) {
searchParams.append('Authorization', `Bearer ${restConfig.token}`);
}
if (restConfig.tokenApi !== undefined && restModel.tokenInUrl === true) {
searchParams.append('Authorization', `ApiKey ${restConfig.tokenApi}`);
}
return generateUrl + '?' + searchParams.toString();
}
@@ -257,6 +263,9 @@ export function RESTRequest({
if (restConfig.token !== undefined && restModel.tokenInUrl !== true) {
headers['Authorization'] = `Bearer ${restConfig.token}`;
}
if (restConfig.tokenApi !== undefined && restModel.tokenInUrl !== true) {
headers['Authorization'] = `ApiKey ${restConfig.tokenApi}`;
}
if (restModel.accept !== undefined) {
headers['Accept'] = restModel.accept;
}

View File

@@ -16,6 +16,7 @@ export type CoversProps = Omit<BoxProps, 'iconEmpty'> & {
export const Covers = ({
data,
onClick,
iconEmpty,
size = '100px',
slideshow = false,
@@ -44,7 +45,7 @@ export const Covers = ({
if (!data || data.length < 1) {
if (iconEmpty) {
return <Icon children={iconEmpty} sizeIcon={size} />;
return <Icon children={iconEmpty} sizeIcon={size} onClick={onClick} />;
} else {
return (
<Box
@@ -55,6 +56,7 @@ export const Covers = ({
borderColor="blue"
borderWidth="1px"
margin="auto"
onClick={onClick}
{...rest}
></Box>
);
@@ -67,7 +69,11 @@ export const Covers = ({
loading="lazy"
src={url}
maxWidth={size}
boxSize={size} /*{...rest}*/
maxHeight={size}
//boxSize={size}
width="100%"
height="100%"
onClick={onClick}
/>
);
}

View File

@@ -1,10 +1,13 @@
import { DragEventHandler, ReactNode, RefObject } from 'react';
import { ReactNode, RefObject } from 'react';
import { Box, BoxProps, Center, Flex, HStack, Image } from '@chakra-ui/react';
import { MdHighlightOff, MdUploadFile } from 'react-icons/md';
import { DataResource } from '@/back-api';
import { FormGroup } from '@/components/form/FormGroup';
import { useServiceContext } from '@/service/ServiceContext';
import { DataUrlAccess } from '@/utils/data-url-access';
import { isNullOrUndefined } from '@/utils/validator';
import { useFormidableContextElement } from '../formidable';
@@ -68,9 +71,8 @@ export const DragNdrop = ({
hidden
id="browse"
onChange={handleFileChange}
//accept=".pdf,.docx,.pptx,.txt,.xlsx"
multiple
/>
/>{' '}
Browse files
</Center>
</Box>
@@ -110,22 +112,53 @@ export type FormCoversProps = {
ref?: RefObject<any>;
label?: string;
isRequired?: boolean;
onFilesSelected?: (files: File[]) => void;
onUriSelected?: (uri: string) => void;
onRemove?: (index: number) => void;
};
/** This field component is a direct insertion component ==> not manage with formidable */
export const FormCovers = ({
name,
ref,
onFilesSelected = () => {},
onUriSelected = () => {},
onRemove = () => {},
...rest
}: FormCoversProps) => {
const { value } = useFormidableContextElement(name);
export const FormCovers = ({ name, ref, ...rest }: FormCoversProps) => {
const { value, onChange } = useFormidableContextElement(name);
const { session } = useServiceContext();
const urls = DataUrlAccess.getListThumbnailUrl(value) ?? [];
const onUriSelected = async (uri: string) => {
const res = await DataResource.uploadMediaFromUri({
restConfig: session.getRestConfig(),
queries: {
uri: uri,
},
});
if (isNullOrUndefined(value)) {
onChange([res]);
return;
}
onChange([...value, res]);
};
const onFilesSelected = async (files: File[]) => {
const res = await DataResource.uploadMedia({
restConfig: session.getRestConfig(),
data: {
file: files[0],
},
});
if (isNullOrUndefined(value)) {
onChange([res]);
return;
}
onChange([...value, res]);
};
const onRemove = (index: number) => {
if (isNullOrUndefined(value)) {
return;
}
const values = [...value];
values.splice(index, 1);
if (values.length === 0) {
onChange(undefined);
} else {
onChange(values);
}
};
return (
<FormGroup name={name} {...rest}>
<HStack wrap="wrap" width="full">
@@ -139,7 +172,7 @@ export const FormCovers = ({
zIndex="+1"
color="#00000020"
_hover={{ color: 'red' }}
onClick={() => onRemove && onRemove(index)}
onClick={() => onRemove(index)}
>
<MdHighlightOff />
</CenterIcon>
@@ -152,8 +185,8 @@ export const FormCovers = ({
<DragNdrop
height="125px"
width="125px"
onFilesSelected={onFilesSelected}
onUriSelected={onUriSelected}
onFilesSelected={(e) => onFilesSelected(e)}
onUriSelected={(e) => onUriSelected(e)}
/>
</Flex>
</HStack>

View File

@@ -16,6 +16,8 @@ export type FormSelectProps = {
placeholder?: string;
// Form: Specify if the element is required or not
isRequired?: boolean;
// is locked for edition
disabled?: boolean;
// List of object options
options: object[];
// in the option specify the value Key
@@ -33,8 +35,9 @@ export const FormSelect = ({
ref,
placeholder,
options,
keyInputKey = 'id',
keyInputKey = 'oid',
keyInputValue = 'name',
disabled = false,
suggestion,
addNewItem,
...rest
@@ -60,6 +63,7 @@ export const FormSelect = ({
keyValue={keyInputValue}
onCreate={onCreate}
suggestion={suggestion}
disabled={disabled}
/>
</FormGroup>
);

View File

@@ -3,10 +3,7 @@ import { RefObject } from 'react';
import { FormGroup } from '@/components/form/FormGroup';
import { SelectMultiple } from '@/components/select/SelectMultiple';
import {
useFormidableContext,
useFormidableContextElement,
} from '../formidable';
import { useFormidableContextElement } from '../formidable';
export type FormSelectMultipleProps = {
// Form: Name of the variable
@@ -34,13 +31,12 @@ export const FormSelectMultiple = ({
ref,
placeholder,
options,
keyInputKey = 'id',
keyInputKey = 'oid',
keyInputValue = 'name',
addNewItem,
...rest
}: FormSelectMultipleProps) => {
const { form, value, isModify, onChange, onRestore } =
useFormidableContextElement(name);
const { form, value, onChange } = useFormidableContextElement(name);
// if set add capability to add the search item
const onCreate = !addNewItem
? undefined

View File

@@ -81,59 +81,6 @@ export const AlbumEditPopUp = ({}: AlbumEditPopUpProps) => {
);
};
const onUriSelected = (uri: string) => {
if (isNullOrUndefined(albumId)) {
return;
}
store.update(
AlbumResource.uploadCover({
restConfig: session.getRestConfig(),
data: {
uri: uri,
},
params: {
oid: albumId,
},
})
);
};
const onFilesSelected = (files: File[]) => {
files.forEach((element) => {
console.log(`Select file: '${element.name}'`);
});
if (isNullOrUndefined(albumId)) {
return;
}
store.update(
AlbumResource.uploadCover({
restConfig: session.getRestConfig(),
data: {
file: files[0],
},
params: {
oid: albumId,
},
})
);
};
const onRemoveCover = (index: number) => {
if (isNullOrUndefined(dataAlbum?.covers)) {
return;
}
if (isNullOrUndefined(albumId)) {
return;
}
store.update(
AlbumResource.removeCover({
restConfig: session.getRestConfig(),
params: {
oid: albumId,
coverId: dataAlbum.covers[index],
},
})
);
};
return (
<DialogRoot
//initialFocusRef={initialRef}
@@ -192,12 +139,7 @@ export const AlbumEditPopUp = ({}: AlbumEditPopUpProps) => {
/>
<FormTextarea name="description" label="Description" />
<FormInput name="publication" label="Publication" />
<FormCovers
name="covers"
onFilesSelected={onFilesSelected}
onUriSelected={onUriSelected}
onRemove={onRemoveCover}
/>
<FormCovers name="covers" />
</>
)}
</DialogBody>

View File

@@ -79,59 +79,9 @@ export const ArtistEditPopUp = ({}: ArtistEditPopUpProps) => {
})
);
};
const onUriSelected = (uri: string) => {
if (isNullOrUndefined(artistId)) {
return;
}
store.update(
ArtistResource.uploadCover({
restConfig: session.getRestConfig(),
data: {
uri: uri,
},
params: {
oid: artistId,
},
})
);
};
const onFilesSelected = (files: File[]) => {
files.forEach((element) => {
console.log(`Select file: '${element.name}'`);
});
if (isNullOrUndefined(artistId)) {
return;
}
store.update(
ArtistResource.uploadCover({
restConfig: session.getRestConfig(),
data: {
file: files[0],
},
params: {
oid: artistId,
},
})
);
};
const onRemoveCover = (index: number) => {
if (isNullOrUndefined(dataArtist?.covers)) {
return;
}
if (isNullOrUndefined(artistId)) {
return;
}
store.update(
ArtistResource.removeCover({
restConfig: session.getRestConfig(),
params: {
oid: artistId,
coverId: dataArtist.covers[index],
},
})
);
};
if (isNullOrUndefined(artistId)) {
return;
}
return (
<DialogRoot
//initialFocusRef={initialRef}
@@ -194,12 +144,7 @@ export const ArtistEditPopUp = ({}: ArtistEditPopUpProps) => {
<FormInput name="surname" label="SurName" />
<FormInput name="birth" label="Birth date" />
<FormInput name="death" label="Death date" />
<FormCovers
name="covers"
onFilesSelected={onFilesSelected}
onUriSelected={onUriSelected}
onRemove={onRemoveCover}
/>
<FormCovers name="covers" label="Covers" />
</>
)}
</DialogBody>

View File

@@ -79,58 +79,6 @@ export const GenderEditPopUp = ({}: GenderEditPopUpProps) => {
})
);
};
const onUriSelected = (uri: string) => {
if (isNullOrUndefined(genderId)) {
return;
}
store.update(
GenderResource.uploadCover({
restConfig: session.getRestConfig(),
data: {
uri: uri,
},
params: {
oid: genderId,
},
})
);
};
const onFilesSelected = (files: File[]) => {
files.forEach((element) => {
console.log(`Select file: '${element.name}'`);
});
if (isNullOrUndefined(genderId)) {
return;
}
store.update(
GenderResource.uploadCover({
restConfig: session.getRestConfig(),
data: {
file: files[0],
},
params: {
oid: genderId,
},
})
);
};
const onRemoveCover = (index: number) => {
if (isNullOrUndefined(dataGender?.covers)) {
return;
}
if (isNullOrUndefined(genderId)) {
return;
}
store.update(
GenderResource.removeCover({
restConfig: session.getRestConfig(),
params: {
oid: genderId,
coverId: dataGender.covers[index],
},
})
);
};
return (
<DialogRoot
//initialFocusRef={initialRef}
@@ -189,12 +137,7 @@ export const GenderEditPopUp = ({}: GenderEditPopUpProps) => {
ref={initialRef}
/>
<FormTextarea name="description" label="Description" />
<FormCovers
name="covers"
onFilesSelected={onFilesSelected}
onUriSelected={onUriSelected}
onRemove={onRemoveCover}
/>
<FormCovers name="covers" />
</>
)}
</DialogBody>

View File

@@ -39,7 +39,7 @@ export const SelectMultiple = ({
});
}, [options, keyKey, keyValue]);
const [hasSuggestion, setHasSuggestion] = useState<boolean>(
onCreate && suggestion ? true : false
!!(onCreate && suggestion)
);
const [currentSearch, setCurrentSearch] = useState<string | undefined>(
onCreate ? suggestion : undefined
@@ -57,7 +57,7 @@ export const SelectMultiple = ({
return [];
}
return transformedOption.filter((element) => {
return values.includes(element[keyKey]);
return values?.includes(element[keyKey]);
});
}, [values, transformedOption]);
@@ -88,7 +88,6 @@ export const SelectMultiple = ({
const onOpenClose = () => {
if (!showList) {
refFocus?.current?.focus();
return;
}
};
const createNewItem = !onCreate

View File

@@ -17,6 +17,8 @@ export type SelectSingleProps = {
onChange?: (value: number | string | undefined) => void;
keyKey?: string;
keyValue?: string;
// is locked for edition
disabled?: boolean;
ref?: RefObject<any>;
// if set add capability to add the search item
onCreate?: (data: string) => void;
@@ -31,6 +33,7 @@ export const SelectSingle = ({
ref,
keyKey = 'id',
keyValue = keyKey,
disabled = false,
suggestion,
onCreate,
}: SelectSingleProps) => {
@@ -44,17 +47,17 @@ export const SelectSingle = ({
});
}, [options, keyKey, keyValue]);
const [hasSuggestion, setHasSuggestion] = useState<boolean>(
onCreate && suggestion ? true : false
!!(onCreate && suggestion)
);
const [currentSearch, setCurrentSearch] = useState<string | undefined>(
onCreate ? suggestion : undefined
);
useEffect(() => {
console.log(
`Update suggestion : ${onCreate} ${suggestion} ==> ${onCreate ? suggestion : undefined} .. ${onCreate && !isNullOrUndefined(suggestion) ? true : false}`
`Update suggestion : ${onCreate} ${suggestion} ==> ${onCreate ? suggestion : undefined} .. ${!!(onCreate && !isNullOrUndefined(suggestion))}`
);
setCurrentSearch(onCreate ? suggestion : undefined);
setHasSuggestion(onCreate && !isNullOrUndefined(suggestion) ? true : false);
setHasSuggestion(!!(onCreate && !isNullOrUndefined(suggestion)));
}, [suggestion]);
const refFocus = ref ?? useRef<HTMLInputElement | null>(null);
const selectedOptions = useMemo(() => {
@@ -65,7 +68,7 @@ export const SelectSingle = ({
}, [value, transformedOption]);
const selectValue = (data?: SelectListModel) => {
const tmpData = data?.id == selectedOptions?.id ? undefined : data;
const tmpData = data?.id === selectedOptions?.id ? undefined : data;
setShowList(false);
if (onChange) {
onChange(tmpData?.id);

View File

@@ -1 +1 @@
1.2.0
1.2.1-dev