diff --git a/back/.checkstyle b/back/.checkstyle new file mode 100644 index 0000000..5783bc0 --- /dev/null +++ b/back/.checkstyle @@ -0,0 +1,7 @@ + + + + + + + diff --git a/back/Dockerfile b/back/Dockerfile index 8fc1c69..6571dab 100644 --- a/back/Dockerfile +++ b/back/Dockerfile @@ -1,15 +1,15 @@ -FROM maven:3.6.3-openjdk-16 AS build +FROM maven:3-openjdk-18 AS build COPY pom.xml /tmp/ COPY src /tmp/src/ 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 diff --git a/back/README.md b/back/README.md index b91b705..b3e5090 100644 --- a/back/README.md +++ b/back/README.md @@ -2,16 +2,24 @@ Generic backend for karusic in java =================================== - - mvn install +mvn compile + +mvn package + +// download all dependency in out/maven/dependency +mvn dependency:copy-dependencies + +java -cp out/maven/kar-karusic-0.1.0.jar org.kar.karusic.WebLauncher + + // create a single package jar mvn clean compile assembly:single -java -cp out/maven/karusic-0.1.0-jar-with-dependencies.jar org.kar.karideo.WebLauncher +java -cp out/maven/karusic-0.1.0-jar-with-dependencies.jar org.kar.karusic.WebLauncher diff --git a/back/karusic-back.iml b/back/karusic-back.iml deleted file mode 100644 index c56ba78..0000000 --- a/back/karusic-back.iml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/back/pom.xml b/back/pom.xml index 5cf9696..45a79ab 100644 --- a/back/pom.xml +++ b/back/pom.xml @@ -8,7 +8,6 @@ 3.1 17 17 - 3.1.1 @@ -17,7 +16,6 @@ https://gitea.atria-soft.org/api/packages/kangaroo-and-rabbit/maven - kangaroo-and-rabbit @@ -28,19 +26,39 @@ org.slf4j slf4j-simple 2.0.7 - - - + + + org.junit.jupiter + junit-jupiter-api + 5.10.0 + test + + + org.junit.jupiter + junit-jupiter-engine + 5.10.0 + test + + src test/src - ${project.basedir}/out/maven/ + ${project.basedir}/out/maven/ src/resources + + + ${basedir}/test/resources + + org.apache.maven.plugins @@ -49,16 +67,15 @@ ${maven.compiler.source} ${maven.compiler.target} - - org.codehaus.mojo - exec-maven-plugin - 1.4.0 - - org.kar.karusic.WebLauncher - + org.codehaus.mojo + exec-maven-plugin + 1.4.0 + + org.kar.karusic.WebLauncher + @@ -80,27 +97,28 @@ maven-surefire-plugin 3.0.0-M5 - - maven-assembly-plugin - - - - fully.qualified.MainClass - - - - jar-with-dependencies - - - + + maven-assembly-plugin + + + + fully.qualified.MainClass + + + + jar-with-dependencies + + + @@ -125,6 +163,23 @@ true + + org.codehaus.mojo + exec-maven-plugin + 3.1.0 + + + exec-application + package + + java + + + + + org.kar.karusic.WebLauncher + + - - - - org.codehaus.mojo - exec-maven-plugin - 1.4.0 - - io.scenarium.oauth.WebLauncher - - - - - org.apache.maven.plugins - maven-source-plugin - - - attach-sources - - jar - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - 3.0.0-M5 - - - maven-assembly-plugin - - - - fully.qualified.MainClass - - - - jar-with-dependencies - - - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 3.2.0 - - private - true - - - - - - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 3.2.0 - - public - - - - - - \ No newline at end of file diff --git a/back/src/org/kar/karusic/WebLauncher.java b/back/src/org/kar/karusic/WebLauncher.java index 0a2190b..97a792d 100755 --- a/back/src/org/kar/karusic/WebLauncher.java +++ b/back/src/org/kar/karusic/WebLauncher.java @@ -2,23 +2,11 @@ package org.kar.karusic; import java.net.URI; -import jakarta.ws.rs.core.UriBuilder; - import org.glassfish.grizzly.http.server.HttpServer; import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory; import org.glassfish.jersey.jackson.JacksonFeature; import org.glassfish.jersey.media.multipart.MultiPartFeature; import org.glassfish.jersey.server.ResourceConfig; -import org.kar.karusic.api.AlbumResource; -import org.kar.karusic.api.ArtistResource; -import org.kar.karusic.api.Front; -import org.kar.karusic.api.GenderResource; -import org.kar.karusic.api.HealthCheck; -import org.kar.karusic.api.PlaylistResource; -import org.kar.karusic.api.TrackResource; -import org.kar.karusic.api.UserResource; -import org.kar.karusic.filter.KarusicAuthenticationFilter; -import org.kar.karusic.migration.Initialization; import org.kar.archidata.GlobalConfiguration; import org.kar.archidata.UpdateJwtPublicKey; import org.kar.archidata.api.DataResource; @@ -30,23 +18,37 @@ import org.kar.archidata.filter.CORSFilter; import org.kar.archidata.filter.OptionFilter; import org.kar.archidata.migration.MigrationEngine; import org.kar.archidata.util.ConfigBaseVariable; -import org.slf4j.LoggerFactory; +import org.kar.karusic.api.AlbumResource; +import org.kar.karusic.api.ArtistResource; +import org.kar.karusic.api.Front; +import org.kar.karusic.api.GenderResource; +import org.kar.karusic.api.HealthCheck; +import org.kar.karusic.api.PlaylistResource; +import org.kar.karusic.api.TrackResource; +import org.kar.karusic.api.UserResource; +import org.kar.karusic.filter.KarusicAuthenticationFilter; +import org.kar.karusic.migration.Initialization; import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jakarta.ws.rs.core.UriBuilder; public class WebLauncher { final static Logger LOGGER = LoggerFactory.getLogger(WebLauncher.class); - protected UpdateJwtPublicKey keyUpdater = null; + protected UpdateJwtPublicKey keyUpdater = null; + protected HttpServer server = null; + public WebLauncher() { ConfigBaseVariable.bdDatabase = "karusic"; } - private static URI getBaseURI() { - return UriBuilder.fromUri(ConfigBaseVariable.getlocalAddress()).build(); - } + private static URI getBaseURI() { + return UriBuilder.fromUri(ConfigBaseVariable.getlocalAddress()).build(); + } public void migrateDB() throws Exception { WebLauncher.LOGGER.info("Create migration engine"); - MigrationEngine migrationEngine = new MigrationEngine(); + final MigrationEngine migrationEngine = new MigrationEngine(); WebLauncher.LOGGER.info("Add initialization"); migrationEngine.setInit(new Initialization()); WebLauncher.LOGGER.info("Add migration since last version"); @@ -56,9 +58,9 @@ public class WebLauncher { WebLauncher.LOGGER.info("Migrate the DB [STOP]"); } - public static void main(String[] args) throws Exception { + public static void main(final String[] args) throws Exception { WebLauncher.LOGGER.info("[START] application wake UP"); - WebLauncher launcher = new WebLauncher(); + final WebLauncher launcher = new WebLauncher(); launcher.migrateDB(); launcher.process(); @@ -68,43 +70,42 @@ public class WebLauncher { launcher.stopOther(); WebLauncher.LOGGER.info("STOP the REST server:"); } - - public void process() throws InterruptedException { + public void process() throws InterruptedException { // =================================================================== // Configure resources // =================================================================== - ResourceConfig rc = new ResourceConfig(); - - // add multipart models .. - rc.register(MultiPartFeature.class); - // global authentication system - rc.register(OptionFilter.class); - // remove cors ==> all time called by an other system... - rc.register(CORSFilter.class); - // global authentication system - rc.register(KarusicAuthenticationFilter.class); - // register exception catcher - rc.register(InputExceptionCatcher.class); - rc.register(SystemExceptionCatcher.class); - rc.register(FailExceptionCatcher.class); - rc.register(ExceptionCatcher.class); - // add default resource: - rc.register(UserResource.class); - rc.register(AlbumResource.class); - rc.register(ArtistResource.class); - rc.register(GenderResource.class); - rc.register(PlaylistResource.class); - rc.register(TrackResource.class); - rc.register(DataResource.class); - - rc.register(HealthCheck.class); - rc.register(Front.class); - - // add jackson to be discover when we are ins standalone server - rc.register(JacksonFeature.class); - // enable this to show low level request - //rc.property(LoggingFeature.LOGGING_FEATURE_LOGGER_LEVEL_SERVER, Level.WARNING.getName()); + final ResourceConfig rc = new ResourceConfig(); + + // add multipart models .. + rc.register(MultiPartFeature.class); + // global authentication system + rc.register(OptionFilter.class); + // remove cors ==> all time called by an other system... + rc.register(CORSFilter.class); + // global authentication system + rc.register(KarusicAuthenticationFilter.class); + // register exception catcher + rc.register(InputExceptionCatcher.class); + rc.register(SystemExceptionCatcher.class); + rc.register(FailExceptionCatcher.class); + rc.register(ExceptionCatcher.class); + // add default resource: + rc.register(UserResource.class); + rc.register(AlbumResource.class); + rc.register(ArtistResource.class); + rc.register(GenderResource.class); + rc.register(PlaylistResource.class); + rc.register(TrackResource.class); + rc.register(DataResource.class); + + rc.register(HealthCheck.class); + rc.register(Front.class); + + // add jackson to be discover when we are ins standalone server + rc.register(JacksonFeature.class); + // enable this to show low level request + //rc.property(LoggingFeature.LOGGING_FEATURE_LOGGER_LEVEL_SERVER, Level.WARNING.getName()); //System.out.println("Connect on the BDD:"); //System.out.println(" getDBHost: '" + ConfigVariable.getDBHost() + "'"); @@ -114,12 +115,13 @@ public class WebLauncher { //System.out.println(" getDBName: '" + ConfigVariable.getDBName() + "'"); System.out.println(" ==> " + GlobalConfiguration.dbConfig); System.out.println("OAuth service " + getBaseURI()); - HttpServer server = GrizzlyHttpServerFactory.createHttpServer(getBaseURI(), rc); + this.server = GrizzlyHttpServerFactory.createHttpServer(getBaseURI(), rc); + final HttpServer serverLink = this.server; Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { @Override public void run() { System.out.println("Stopping server.."); - server.shutdownNow(); + serverLink.shutdownNow(); } }, "shutdownHook")); @@ -129,25 +131,32 @@ public class WebLauncher { this.keyUpdater = new UpdateJwtPublicKey(); this.keyUpdater.start(); - // =================================================================== + // =================================================================== // run JERSEY - // =================================================================== + // =================================================================== try { - server.start(); + this.server.start(); LOGGER.info("Jersey app started at {}", getBaseURI()); - } catch (Exception e) { + } catch (final Exception e) { LOGGER.error("There was an error while starting Grizzly HTTP server."); e.printStackTrace(); } - } - - public void stopOther() { - keyUpdater.kill(); + } + + public void stop() { + if (this.server != null) { + this.server.shutdownNow(); + this.server = null; + } + } + + public void stopOther() { + this.keyUpdater.kill(); try { - keyUpdater.join(4000, 0); - } catch (InterruptedException e) { + this.keyUpdater.join(4000, 0); + } catch (final InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } - } + } } diff --git a/back/src/org/kar/karusic/api/AlbumResource.java b/back/src/org/kar/karusic/api/AlbumResource.java index 3aa5b06..6f8a5e8 100644 --- a/back/src/org/kar/karusic/api/AlbumResource.java +++ b/back/src/org/kar/karusic/api/AlbumResource.java @@ -5,12 +5,12 @@ import java.util.List; import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.glassfish.jersey.media.multipart.FormDataParam; -import org.kar.archidata.annotation.security.RolesAllowed; -import org.kar.archidata.sqlWrapper.SqlWrapper; -import org.kar.archidata.sqlWrapper.addOn.AddOnManyToMany; +import org.kar.archidata.dataAccess.DataAccess; +import org.kar.archidata.dataAccess.addOn.AddOnManyToMany; import org.kar.archidata.util.DataTools; import org.kar.karusic.model.Album; +import jakarta.annotation.security.RolesAllowed; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; @@ -25,75 +25,75 @@ import jakarta.ws.rs.core.Response; @Path("/album") @Produces({ MediaType.APPLICATION_JSON }) public class AlbumResource { - + @GET @Path("{id}") @RolesAllowed("USER") - public static Album getWithId(@PathParam("id") Long id) throws Exception { - return SqlWrapper.get(Album.class, id); + public static Album getWithId(@PathParam("id") final Long id) throws Exception { + return DataAccess.get(Album.class, id); } - + @GET @RolesAllowed("USER") public List get() throws Exception { - return SqlWrapper.gets(Album.class); + return DataAccess.gets(Album.class); } @POST @RolesAllowed("ADMIN") @Consumes(MediaType.APPLICATION_JSON) - public Album post(String jsonRequest) throws Exception { - return SqlWrapper.insertWithJson(Album.class, jsonRequest); + public Album post(final String jsonRequest) throws Exception { + return DataAccess.insertWithJson(Album.class, jsonRequest); } - + @PUT @Path("{id}") @RolesAllowed("ADMIN") @Consumes(MediaType.APPLICATION_JSON) - public Album put(@PathParam("id") Long id, String jsonRequest) throws Exception { - SqlWrapper.update(Album.class, id, jsonRequest); - return SqlWrapper.get(Album.class, id); + public Album put(@PathParam("id") final Long id, final String jsonRequest) throws Exception { + DataAccess.updateWithJson(Album.class, id, jsonRequest); + return DataAccess.get(Album.class, id); } - + @DELETE @Path("{id}") @RolesAllowed("ADMIN") - public Response delete(@PathParam("id") Long id) throws Exception { - SqlWrapper.delete(Album.class, id); + public Response delete(@PathParam("id") final Long id) throws Exception { + DataAccess.delete(Album.class, id); return Response.ok().build(); } - + @POST @Path("{id}/add_track/{trackId}") @RolesAllowed("ADMIN") @Consumes({ MediaType.MULTIPART_FORM_DATA }) - public Album addTrack(@PathParam("id") Long id, @PathParam("trackId") Long trackId) throws Exception { + public Album addTrack(@PathParam("id") final Long id, @PathParam("trackId") final Long trackId) throws Exception { AddOnManyToMany.removeLink(Album.class, id, "track", trackId); - return SqlWrapper.get(Album.class, id); + return DataAccess.get(Album.class, id); } - + @GET @Path("{id}/rm_track/{trackId}") @RolesAllowed("ADMIN") - public Album removeTrack(@PathParam("id") Long id, @PathParam("trackId") Long trackId) throws Exception { + public Album removeTrack(@PathParam("id") final Long id, @PathParam("trackId") final Long trackId) throws Exception { AddOnManyToMany.removeLink(Album.class, id, "track", trackId); - return SqlWrapper.get(Album.class, id); + return DataAccess.get(Album.class, id); } - + @POST @Path("{id}/add_cover") @RolesAllowed("ADMIN") @Consumes({ MediaType.MULTIPART_FORM_DATA }) - public Response uploadCover(@PathParam("id") Long id, @FormDataParam("fileName") String fileName, @FormDataParam("file") InputStream fileInputStream, - @FormDataParam("file") FormDataContentDisposition fileMetaData) { + public Response uploadCover(@PathParam("id") final Long id, @FormDataParam("fileName") final String fileName, @FormDataParam("file") final InputStream fileInputStream, + @FormDataParam("file") final FormDataContentDisposition fileMetaData) { return DataTools.uploadCover(Album.class, id, fileName, fileInputStream, fileMetaData); } - + @GET @Path("{id}/rm_cover/{coverId}") @RolesAllowed("ADMIN") - public Response removeCover(@PathParam("id") Long id, @PathParam("coverId") Long coverId) throws Exception { + public Response removeCover(@PathParam("id") final Long id, @PathParam("coverId") final Long coverId) throws Exception { AddOnManyToMany.removeLink(Album.class, id, "cover", coverId); - return Response.ok(SqlWrapper.get(Album.class, id)).build(); + return Response.ok(DataAccess.get(Album.class, id)).build(); } } diff --git a/back/src/org/kar/karusic/api/ArtistResource.java b/back/src/org/kar/karusic/api/ArtistResource.java index 2e9dc4f..650d647 100644 --- a/back/src/org/kar/karusic/api/ArtistResource.java +++ b/back/src/org/kar/karusic/api/ArtistResource.java @@ -5,12 +5,12 @@ import java.util.List; import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.glassfish.jersey.media.multipart.FormDataParam; -import org.kar.archidata.annotation.security.RolesAllowed; -import org.kar.archidata.sqlWrapper.SqlWrapper; -import org.kar.archidata.sqlWrapper.addOn.AddOnManyToMany; +import org.kar.archidata.dataAccess.DataAccess; +import org.kar.archidata.dataAccess.addOn.AddOnManyToMany; import org.kar.archidata.util.DataTools; import org.kar.karusic.model.Artist; +import jakarta.annotation.security.RolesAllowed; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; @@ -25,58 +25,58 @@ import jakarta.ws.rs.core.Response; @Path("/artist") @Produces({ MediaType.APPLICATION_JSON }) public class ArtistResource { - + @GET @Path("{id}") @RolesAllowed("USER") - public static Artist getWithId(@PathParam("id") Long id) throws Exception { - return SqlWrapper.get(Artist.class, id); + public static Artist getWithId(@PathParam("id") final Long id) throws Exception { + return DataAccess.get(Artist.class, id); } - + @GET @RolesAllowed("USER") public List get() throws Exception { - return SqlWrapper.gets(Artist.class); + return DataAccess.gets(Artist.class); } @POST @RolesAllowed("ADMIN") @Consumes(MediaType.APPLICATION_JSON) - public Artist put(String jsonRequest) throws Exception { - return SqlWrapper.insertWithJson(Artist.class, jsonRequest); + public Artist put(final String jsonRequest) throws Exception { + return DataAccess.insertWithJson(Artist.class, jsonRequest); } - + @PUT @Path("{id}") @RolesAllowed("ADMIN") @Consumes(MediaType.APPLICATION_JSON) - public Artist put(@PathParam("id") Long id, String jsonRequest) throws Exception { - SqlWrapper.update(Artist.class, id, jsonRequest); - return SqlWrapper.get(Artist.class, id); + public Artist put(@PathParam("id") final Long id, final String jsonRequest) throws Exception { + DataAccess.updateWithJson(Artist.class, id, jsonRequest); + return DataAccess.get(Artist.class, id); } - + @DELETE @Path("{id}") @RolesAllowed("ADMIN") - public Response delete(@PathParam("id") Long id) throws Exception { - SqlWrapper.delete(Artist.class, id); + public Response delete(@PathParam("id") final Long id) throws Exception { + DataAccess.delete(Artist.class, id); return Response.ok().build(); } - + @POST @Path("{id}/add_cover") @RolesAllowed("ADMIN") @Consumes({ MediaType.MULTIPART_FORM_DATA }) - public Response uploadCover(@PathParam("id") Long id, @FormDataParam("fileName") String fileName, @FormDataParam("file") InputStream fileInputStream, - @FormDataParam("file") FormDataContentDisposition fileMetaData) { + public Response uploadCover(@PathParam("id") final Long id, @FormDataParam("fileName") final String fileName, @FormDataParam("file") final InputStream fileInputStream, + @FormDataParam("file") final FormDataContentDisposition fileMetaData) { return DataTools.uploadCover(Artist.class, id, fileName, fileInputStream, fileMetaData); } - + @GET @Path("{id}/rm_cover/{coverId}") @RolesAllowed("ADMIN") - public Response removeCover(@PathParam("id") Long id, @PathParam("coverId") Long coverId) throws Exception { + public Response removeCover(@PathParam("id") final Long id, @PathParam("coverId") final Long coverId) throws Exception { AddOnManyToMany.removeLink(Artist.class, id, "cover", coverId); - return Response.ok(SqlWrapper.get(Artist.class, id)).build(); + return Response.ok(DataAccess.get(Artist.class, id)).build(); } } diff --git a/back/src/org/kar/karusic/api/Front.java b/back/src/org/kar/karusic/api/Front.java index 0d972e1..ed978c7 100644 --- a/back/src/org/kar/karusic/api/Front.java +++ b/back/src/org/kar/karusic/api/Front.java @@ -1,22 +1,14 @@ package org.kar.karusic.api; -import java.io.File; -import java.util.List; - -import org.kar.archidata.annotation.security.PermitAll; -import jakarta.ws.rs.*; -import jakarta.ws.rs.core.CacheControl; -import jakarta.ws.rs.core.PathSegment; -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.core.Response.ResponseBuilder; - import org.kar.archidata.api.FrontGeneric; import org.kar.karusic.util.ConfigVariable; +import jakarta.ws.rs.Path; + @Path("/front") public class Front extends FrontGeneric { public Front() { this.baseFrontFolder = ConfigVariable.getFrontFolder(); - + } } diff --git a/back/src/org/kar/karusic/api/GenderResource.java b/back/src/org/kar/karusic/api/GenderResource.java index 6255804..2957b65 100644 --- a/back/src/org/kar/karusic/api/GenderResource.java +++ b/back/src/org/kar/karusic/api/GenderResource.java @@ -5,12 +5,12 @@ import java.util.List; import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.glassfish.jersey.media.multipart.FormDataParam; -import org.kar.archidata.annotation.security.RolesAllowed; -import org.kar.archidata.sqlWrapper.SqlWrapper; -import org.kar.archidata.sqlWrapper.addOn.AddOnManyToMany; +import org.kar.archidata.dataAccess.DataAccess; +import org.kar.archidata.dataAccess.addOn.AddOnManyToMany; import org.kar.archidata.util.DataTools; import org.kar.karusic.model.Gender; +import jakarta.annotation.security.RolesAllowed; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; @@ -25,58 +25,58 @@ import jakarta.ws.rs.core.Response; @Path("/gender") @Produces({ MediaType.APPLICATION_JSON }) public class GenderResource { - + @GET @Path("{id}") @RolesAllowed("USER") - public static Gender getWithId(@PathParam("id") Long id) throws Exception { - return SqlWrapper.get(Gender.class, id); + public static Gender getWithId(@PathParam("id") final Long id) throws Exception { + return DataAccess.get(Gender.class, id); } - + @GET @RolesAllowed("USER") public List get() throws Exception { - return SqlWrapper.gets(Gender.class); + return DataAccess.gets(Gender.class); } @POST @RolesAllowed("ADMIN") @Consumes(MediaType.APPLICATION_JSON) - public Gender put(String jsonRequest) throws Exception { - return SqlWrapper.insertWithJson(Gender.class, jsonRequest); + public Gender put(final String jsonRequest) throws Exception { + return DataAccess.insertWithJson(Gender.class, jsonRequest); } - + @PUT @Path("{id}") @RolesAllowed("ADMIN") @Consumes(MediaType.APPLICATION_JSON) - public Gender put(@PathParam("id") Long id, String jsonRequest) throws Exception { - SqlWrapper.update(Gender.class, id, jsonRequest); - return SqlWrapper.get(Gender.class, id); + public Gender put(@PathParam("id") final Long id, final String jsonRequest) throws Exception { + DataAccess.updateWithJson(Gender.class, id, jsonRequest); + return DataAccess.get(Gender.class, id); } - + @DELETE @Path("{id}") @RolesAllowed("ADMIN") - public Response delete(@PathParam("id") Long id) throws Exception { - SqlWrapper.delete(Gender.class, id); + public Response delete(@PathParam("id") final Long id) throws Exception { + DataAccess.delete(Gender.class, id); return Response.ok().build(); } - + @POST @Path("{id}/add_cover") @RolesAllowed("ADMIN") @Consumes({ MediaType.MULTIPART_FORM_DATA }) - public Response uploadCover(@PathParam("id") Long id, @FormDataParam("fileName") String fileName, @FormDataParam("file") InputStream fileInputStream, - @FormDataParam("file") FormDataContentDisposition fileMetaData) { + public Response uploadCover(@PathParam("id") final Long id, @FormDataParam("fileName") final String fileName, @FormDataParam("file") final InputStream fileInputStream, + @FormDataParam("file") final FormDataContentDisposition fileMetaData) { return DataTools.uploadCover(Gender.class, id, fileName, fileInputStream, fileMetaData); } - + @GET @Path("{id}/rm_cover/{coverId}") @RolesAllowed("ADMIN") - public Response removeCover(@PathParam("id") Long id, @PathParam("coverId") Long coverId) throws Exception { + public Response removeCover(@PathParam("id") final Long id, @PathParam("coverId") final Long coverId) throws Exception { AddOnManyToMany.removeLink(Gender.class, id, "cover", coverId); - return Response.ok(SqlWrapper.get(Gender.class, id)).build(); + return Response.ok(DataAccess.get(Gender.class, id)).build(); } } diff --git a/back/src/org/kar/karusic/api/HealthCheck.java b/back/src/org/kar/karusic/api/HealthCheck.java index a088855..5a1ec09 100644 --- a/back/src/org/kar/karusic/api/HealthCheck.java +++ b/back/src/org/kar/karusic/api/HealthCheck.java @@ -1,28 +1,29 @@ package org.kar.karusic.api; -import org.kar.archidata.annotation.security.PermitAll; -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.*; -import jakarta.ws.rs.core.MediaType; - +import org.kar.archidata.exception.FailException; +import org.kar.archidata.util.ConfigBaseVariable; import org.kar.archidata.util.JWTWrapper; +import jakarta.annotation.security.PermitAll; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; + @Path("/health_check") @Produces(MediaType.APPLICATION_JSON) public class HealthCheck { - public class HealthResult { - public String value; - public HealthResult(String value) { - this.value = value; + + public record HealthResult( + String value) {}; + + @GET + @PermitAll + public HealthResult getHealth() throws FailException { + if (JWTWrapper.getPublicKeyJson() == null && !ConfigBaseVariable.getTestMode()) { + throw new FailException(Response.Status.INTERNAL_SERVER_ERROR, "Missing Jwt public token"); } + return new HealthResult("alive and kicking"); } - // todo : do it better... - @GET - @PermitAll - public Response getHealth() { - if (JWTWrapper.getPublicKeyJson() == null) { - return Response.status(500).entity(new HealthResult("Missing Jwt public token")).build(); - } - return Response.status(200).entity(new HealthResult("alive and kicking")).build(); - } } diff --git a/back/src/org/kar/karusic/api/PlaylistResource.java b/back/src/org/kar/karusic/api/PlaylistResource.java index afdf32f..995e05f 100644 --- a/back/src/org/kar/karusic/api/PlaylistResource.java +++ b/back/src/org/kar/karusic/api/PlaylistResource.java @@ -5,12 +5,12 @@ import java.util.List; import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.glassfish.jersey.media.multipart.FormDataParam; -import org.kar.archidata.annotation.security.RolesAllowed; -import org.kar.archidata.sqlWrapper.SqlWrapper; -import org.kar.archidata.sqlWrapper.addOn.AddOnManyToMany; +import org.kar.archidata.dataAccess.DataAccess; +import org.kar.archidata.dataAccess.addOn.AddOnManyToMany; import org.kar.archidata.util.DataTools; import org.kar.karusic.model.Playlist; +import jakarta.annotation.security.RolesAllowed; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; @@ -25,75 +25,75 @@ import jakarta.ws.rs.core.Response; @Path("/playlist") @Produces({ MediaType.APPLICATION_JSON }) public class PlaylistResource { - + @GET @Path("{id}") @RolesAllowed("USER") - public static Playlist getWithId(@PathParam("id") Long id) throws Exception { - return SqlWrapper.get(Playlist.class, id); + public static Playlist getWithId(@PathParam("id") final Long id) throws Exception { + return DataAccess.get(Playlist.class, id); } - + @GET @RolesAllowed("USER") public List get() throws Exception { - return SqlWrapper.gets(Playlist.class); + return DataAccess.gets(Playlist.class); } @POST @RolesAllowed("ADMIN") @Consumes(MediaType.APPLICATION_JSON) - public Playlist put(String jsonRequest) throws Exception { - return SqlWrapper.insertWithJson(Playlist.class, jsonRequest); + public Playlist put(final String jsonRequest) throws Exception { + return DataAccess.insertWithJson(Playlist.class, jsonRequest); } - + @PUT @Path("{id}") @RolesAllowed("ADMIN") @Consumes(MediaType.APPLICATION_JSON) - public Playlist put(@PathParam("id") Long id, String jsonRequest) throws Exception { - SqlWrapper.update(Playlist.class, id, jsonRequest); - return SqlWrapper.get(Playlist.class, id); + public Playlist put(@PathParam("id") final Long id, final String jsonRequest) throws Exception { + DataAccess.updateWithJson(Playlist.class, id, jsonRequest); + return DataAccess.get(Playlist.class, id); } - + @DELETE @Path("{id}") @RolesAllowed("ADMIN") - public Response delete(@PathParam("id") Long id) throws Exception { - SqlWrapper.delete(Playlist.class, id); + public Response delete(@PathParam("id") final Long id) throws Exception { + DataAccess.delete(Playlist.class, id); return Response.ok().build(); } - + @POST @Path("{id}/add_track/{trackId}") @RolesAllowed("ADMIN") @Consumes({ MediaType.MULTIPART_FORM_DATA }) - public Playlist addTrack(@PathParam("id") Long id, @PathParam("trackId") Long trackId) throws Exception { + public Playlist addTrack(@PathParam("id") final Long id, @PathParam("trackId") final Long trackId) throws Exception { AddOnManyToMany.removeLink(Playlist.class, id, "track", trackId); - return SqlWrapper.get(Playlist.class, id); + return DataAccess.get(Playlist.class, id); } - + @GET @Path("{id}/rm_track/{trackId}") @RolesAllowed("ADMIN") - public Playlist removeTrack(@PathParam("id") Long id, @PathParam("trackId") Long trackId) throws Exception { + public Playlist removeTrack(@PathParam("id") final Long id, @PathParam("trackId") final Long trackId) throws Exception { AddOnManyToMany.removeLink(Playlist.class, id, "track", trackId); - return SqlWrapper.get(Playlist.class, id); + return DataAccess.get(Playlist.class, id); } - + @POST @Path("{id}/add_cover") @RolesAllowed("ADMIN") @Consumes({ MediaType.MULTIPART_FORM_DATA }) - public Response uploadCover(@PathParam("id") Long id, @FormDataParam("fileName") String fileName, @FormDataParam("file") InputStream fileInputStream, - @FormDataParam("file") FormDataContentDisposition fileMetaData) { + public Response uploadCover(@PathParam("id") final Long id, @FormDataParam("fileName") final String fileName, @FormDataParam("file") final InputStream fileInputStream, + @FormDataParam("file") final FormDataContentDisposition fileMetaData) { return DataTools.uploadCover(Playlist.class, id, fileName, fileInputStream, fileMetaData); } - + @GET @Path("{id}/rm_cover/{coverId}") @RolesAllowed("ADMIN") - public Response removeCover(@PathParam("id") Long id, @PathParam("coverId") Long coverId) throws Exception { + public Response removeCover(@PathParam("id") final Long id, @PathParam("coverId") final Long coverId) throws Exception { AddOnManyToMany.removeLink(Playlist.class, id, "cover", coverId); - return Response.ok(SqlWrapper.get(Playlist.class, id)).build(); + return Response.ok(DataAccess.get(Playlist.class, id)).build(); } } diff --git a/back/src/org/kar/karusic/api/TrackResource.java b/back/src/org/kar/karusic/api/TrackResource.java index 5444ace..3432a6f 100644 --- a/back/src/org/kar/karusic/api/TrackResource.java +++ b/back/src/org/kar/karusic/api/TrackResource.java @@ -8,17 +8,17 @@ import java.util.List; import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.glassfish.jersey.media.multipart.FormDataParam; -import org.kar.archidata.annotation.security.RolesAllowed; +import org.kar.archidata.dataAccess.DataAccess; +import org.kar.archidata.dataAccess.QueryCondition; +import org.kar.archidata.dataAccess.addOn.AddOnManyToMany; import org.kar.archidata.model.Data; -import org.kar.archidata.sqlWrapper.QuerryCondition; -import org.kar.archidata.sqlWrapper.SqlWrapper; -import org.kar.archidata.sqlWrapper.addOn.AddOnManyToMany; import org.kar.archidata.util.DataTools; import org.kar.karusic.model.Album; import org.kar.karusic.model.Artist; import org.kar.karusic.model.Gender; import org.kar.karusic.model.Track; +import jakarta.annotation.security.RolesAllowed; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; @@ -37,37 +37,37 @@ public class TrackResource { @GET @Path("{id}") @RolesAllowed("USER") - public static Track getWithId(@PathParam("id") Long id) throws Exception { - return SqlWrapper.get(Track.class, id); + public static Track getWithId(@PathParam("id") final Long id) throws Exception { + return DataAccess.get(Track.class, id); } @GET @RolesAllowed("USER") public List get() throws Exception { - return SqlWrapper.gets(Track.class); + return DataAccess.gets(Track.class); } - + @POST @RolesAllowed("ADMIN") @Consumes(MediaType.APPLICATION_JSON) - public Track create(String jsonRequest) throws Exception { - return SqlWrapper.insertWithJson(Track.class, jsonRequest); + public Track create(final String jsonRequest) throws Exception { + return DataAccess.insertWithJson(Track.class, jsonRequest); } @PUT @Path("{id}") @RolesAllowed("ADMIN") @Consumes(MediaType.APPLICATION_JSON) - public Track put(@PathParam("id") Long id, String jsonRequest) throws Exception { - SqlWrapper.update(Track.class, id, jsonRequest); - return SqlWrapper.get(Track.class, id); + public Track put(@PathParam("id") final Long id, final String jsonRequest) throws Exception { + DataAccess.updateWithJson(Track.class, id, jsonRequest); + return DataAccess.get(Track.class, id); } @DELETE @Path("{id}") @RolesAllowed("ADMIN") - public Response delete(@PathParam("id") Long id) throws Exception { - SqlWrapper.delete(Track.class, id); + public Response delete(@PathParam("id") final Long id) throws Exception { + DataAccess.delete(Track.class, id); return Response.ok().build(); } @@ -75,34 +75,34 @@ public class TrackResource { @Path("{id}/add_artist/{artistId}") @RolesAllowed("ADMIN") @Consumes({ MediaType.MULTIPART_FORM_DATA }) - public Track addTrack(@PathParam("id") Long id, @PathParam("artistId") Long artistId) throws Exception { + public Track addTrack(@PathParam("id") final Long id, @PathParam("artistId") final Long artistId) throws Exception { AddOnManyToMany.removeLink(Track.class, id, "artist", artistId); - return SqlWrapper.get(Track.class, id); + return DataAccess.get(Track.class, id); } @GET @Path("{id}/rm_artist/{trackId}") @RolesAllowed("ADMIN") - public Track removeTrack(@PathParam("id") Long id, @PathParam("artistId") Long artistId) throws Exception { + public Track removeTrack(@PathParam("id") final Long id, @PathParam("artistId") final Long artistId) throws Exception { AddOnManyToMany.removeLink(Track.class, id, "artist", artistId); - return SqlWrapper.get(Track.class, id); + return DataAccess.get(Track.class, id); } @POST @Path("{id}/add_cover") @RolesAllowed("ADMIN") @Consumes({ MediaType.MULTIPART_FORM_DATA }) - public Response uploadCover(@PathParam("id") Long id, @FormDataParam("fileName") String fileName, @FormDataParam("file") InputStream fileInputStream, - @FormDataParam("file") FormDataContentDisposition fileMetaData) { + public Response uploadCover(@PathParam("id") final Long id, @FormDataParam("fileName") final String fileName, @FormDataParam("file") final InputStream fileInputStream, + @FormDataParam("file") final FormDataContentDisposition fileMetaData) { return DataTools.uploadCover(Track.class, id, fileName, fileInputStream, fileMetaData); } @GET @Path("{id}/rm_cover/{coverId}") @RolesAllowed("ADMIN") - public Response removeCover(@PathParam("id") Long id, @PathParam("coverId") Long coverId) throws Exception { + public Response removeCover(@PathParam("id") final Long id, @PathParam("coverId") final Long coverId) throws Exception { AddOnManyToMany.removeLink(Track.class, id, "cover", coverId); - return Response.ok(SqlWrapper.get(Track.class, id)).build(); + return Response.ok(DataAccess.get(Track.class, id)).build(); } @POST @@ -111,8 +111,8 @@ public class TrackResource { @Consumes({ MediaType.MULTIPART_FORM_DATA }) public Response uploadFile(@FormDataParam("fileName") String fileName, @FormDataParam("gender") String gender, @FormDataParam("artist") String artist, //@FormDataParam("seriesId") String seriesId, Not used ... - @FormDataParam("album") String album, @FormDataParam("trackId") String trackId, @FormDataParam("title") String title, @FormDataParam("file") InputStream fileInputStream, - @FormDataParam("file") FormDataContentDisposition fileMetaData) { + @FormDataParam("album") String album, @FormDataParam("trackId") String trackId, @FormDataParam("title") String title, @FormDataParam("file") final InputStream fileInputStream, + @FormDataParam("file") final FormDataContentDisposition fileMetaData) { try { // correct input string stream : fileName = DataTools.multipartCorrection(fileName); @@ -142,24 +142,24 @@ public class TrackResource { } */ - long tmpUID = DataTools.getTmpDataId(); - String sha512 = DataTools.saveTemporaryFile(fileInputStream, tmpUID); + final long tmpUID = DataTools.getTmpDataId(); + final String sha512 = DataTools.saveTemporaryFile(fileInputStream, tmpUID); Data data = DataTools.getWithSha512(sha512); if (data == null) { System.out.println("Need to add the data in the BDD ... "); System.out.flush(); try { data = DataTools.createNewData(tmpUID, fileName, sha512); - } catch (IOException ex) { + } catch (final IOException ex) { DataTools.removeTemporaryFile(tmpUID); ex.printStackTrace(); return Response.notModified("can not create input media").build(); - } catch (SQLException ex) { + } catch (final SQLException ex) { ex.printStackTrace(); DataTools.removeTemporaryFile(tmpUID); return Response.notModified("Error in SQL insertion ...").build(); } - } else if (data.deleted == true) { + } else if (data.deleted) { System.out.println("Data already exist but deleted"); System.out.flush(); DataTools.undelete(data.id); @@ -172,11 +172,11 @@ public class TrackResource { System.out.println("Find typeNode"); Gender genderElem = null; if (gender != null) { - genderElem = SqlWrapper.getWhere(Gender.class, new QuerryCondition("name", "=", gender)); + genderElem = DataAccess.getWhere(Gender.class, new QueryCondition("name", "=", gender)); if (genderElem == null) { genderElem = new Gender(); genderElem.name = gender; - genderElem = SqlWrapper.insert(genderElem); + genderElem = DataAccess.insert(genderElem); } } // NodeSmall typeNode = TypeResource.getWithId(Long.parseLong(typeId)); @@ -188,22 +188,22 @@ public class TrackResource { Artist artistElem = null; if (artist != null) { - artistElem = SqlWrapper.getWhere(Artist.class, new QuerryCondition("name", "=", artist)); + artistElem = DataAccess.getWhere(Artist.class, new QueryCondition("name", "=", artist)); if (artistElem == null) { artistElem = new Artist(); artistElem.name = artist; - artistElem = SqlWrapper.insert(artistElem); + artistElem = DataAccess.insert(artistElem); } } System.out.println(" ==> " + artistElem); Album albumElem = null; if (album != null) { - albumElem = SqlWrapper.getWhere(Album.class, new QuerryCondition("name", "=", album)); + albumElem = DataAccess.getWhere(Album.class, new QueryCondition("name", "=", album)); if (albumElem == null) { albumElem = new Album(); albumElem.name = album; - albumElem = SqlWrapper.insert(albumElem); + albumElem = DataAccess.insert(albumElem); } } System.out.println(" ==> " + album); @@ -221,15 +221,15 @@ public class TrackResource { trackElem.artists = new ArrayList<>(); trackElem.artists.add(artistElem.id); } - trackElem = SqlWrapper.insert(trackElem); + trackElem = DataAccess.insert(trackElem); /* Old mode of artist insertion (removed due to the slowlest request of getting value if (artistElem != null) { - SqlWrapper.addLink(Track.class, trackElem.id, "artist", artistElem.id); + DataAccess.addLink(Track.class, trackElem.id, "artist", artistElem.id); } */ return Response.ok(trackElem).build(); - } catch (Exception ex) { + } catch (final Exception ex) { System.out.println("Catch an unexpected error ... " + ex.getMessage()); ex.printStackTrace(); return Response.status(417).entity("Back-end error : " + ex.getMessage()).type("text/plain").build(); diff --git a/back/src/org/kar/karusic/api/UserResource.java b/back/src/org/kar/karusic/api/UserResource.java index 3564556..9c2b896 100755 --- a/back/src/org/kar/karusic/api/UserResource.java +++ b/back/src/org/kar/karusic/api/UserResource.java @@ -2,15 +2,15 @@ package org.kar.karusic.api; import java.util.List; -import org.kar.archidata.annotation.security.RolesAllowed; +import org.kar.archidata.dataAccess.DataAccess; import org.kar.archidata.filter.GenericContext; -import org.kar.archidata.sqlWrapper.SqlWrapper; import org.kar.karusic.model.UserKarusic; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.fasterxml.jackson.annotation.JsonInclude; +import jakarta.annotation.security.RolesAllowed; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; @@ -29,14 +29,13 @@ public class UserResource { public long id; public String login; - public UserOut(long id, String login) { - super(); + public UserOut(final long id, final String login) { this.id = id; this.login = login; } } - + public UserResource() {} // curl http://localhost:9993/api/users @@ -45,8 +44,8 @@ public class UserResource { public List getUsers() { System.out.println("getUsers"); try { - return SqlWrapper.gets(UserKarusic.class); - } catch (Exception e) { + return DataAccess.gets(UserKarusic.class); + } catch (final Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } @@ -57,15 +56,15 @@ public class UserResource { @GET @Path("{id}") @RolesAllowed("ADMIN") - public UserKarusic getUsers(@Context SecurityContext sc, @PathParam("id") long userId) { + public UserKarusic getUsers(@Context final SecurityContext sc, @PathParam("id") final long userId) { System.out.println("getUser " + userId); - GenericContext gc = (GenericContext) sc.getUserPrincipal(); + final GenericContext gc = (GenericContext) sc.getUserPrincipal(); System.out.println("==================================================="); System.out.println("== USER ? " + gc.userByToken.name); System.out.println("==================================================="); try { - return SqlWrapper.get(UserKarusic.class, userId); - } catch (Exception e) { + return DataAccess.get(UserKarusic.class, userId); + } catch (final Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } @@ -75,10 +74,10 @@ public class UserResource { @GET @Path("me") @RolesAllowed("USER") - public UserOut getMe(@Context SecurityContext sc) { - logger.debug("getMe()"); - GenericContext gc = (GenericContext) sc.getUserPrincipal(); - logger.debug("== USER ? {}", gc.userByToken); + public UserOut getMe(@Context final SecurityContext sc) { + this.logger.debug("getMe()"); + final GenericContext gc = (GenericContext) sc.getUserPrincipal(); + this.logger.debug("== USER ? {}", gc.userByToken); return new UserOut(gc.userByToken.id, gc.userByToken.name); } } diff --git a/back/src/org/kar/karusic/migration/Initialization.java b/back/src/org/kar/karusic/migration/Initialization.java index 7798b92..305b712 100644 --- a/back/src/org/kar/karusic/migration/Initialization.java +++ b/back/src/org/kar/karusic/migration/Initialization.java @@ -10,14 +10,14 @@ import org.kar.karusic.model.Playlist; import org.kar.karusic.model.Track; public class Initialization extends MigrationSqlStep { - - public static final int KARSO_INITIALISATION_ID = 1; + + public static final int KARSO_INITIALISATION_ID = 1; @Override public String getName() { return "Initialization"; } - + public Initialization() throws Exception { addClass(Album.class); addClass(Artist.class); @@ -26,7 +26,7 @@ public class Initialization extends MigrationSqlStep { addClass(Playlist.class); addClass(Track.class); addClass(User.class); - + addAction(""" INSERT INTO `gender` (`id`, `name`, `description`) VALUES (1, 'Variété française', NULL), @@ -59,25 +59,25 @@ public class Initialization extends MigrationSqlStep { // set start increment element to permit to add after default elements addAction(""" ALTER TABLE `album` AUTO_INCREMENT = 1000; - """); + """, "mysql"); addAction(""" ALTER TABLE `artist` AUTO_INCREMENT = 1000; - """); + """, "mysql"); addAction(""" ALTER TABLE `data` AUTO_INCREMENT = 1000; - """); + """, "mysql"); addAction(""" ALTER TABLE `gender` AUTO_INCREMENT = 1000; - """); + """, "mysql"); addAction(""" ALTER TABLE `playlist` AUTO_INCREMENT = 1000; - """); + """, "mysql"); addAction(""" ALTER TABLE `track` AUTO_INCREMENT = 1000; - """); + """, "mysql"); addAction(""" ALTER TABLE `user` AUTO_INCREMENT = 1000; - """); + """, "mysql"); } - + } diff --git a/back/src/org/kar/karusic/model/Album.java b/back/src/org/kar/karusic/model/Album.java index 37dc726..f5ac1b4 100644 --- a/back/src/org/kar/karusic/model/Album.java +++ b/back/src/org/kar/karusic/model/Album.java @@ -14,14 +14,14 @@ CREATE TABLE `node` ( */ import java.sql.Date; -import org.kar.archidata.annotation.SQLIfNotExists; +import org.kar.archidata.annotation.DataIfNotExists; import com.fasterxml.jackson.annotation.JsonInclude; import jakarta.persistence.Table; @Table(name = "album") -@SQLIfNotExists +@DataIfNotExists @JsonInclude(JsonInclude.Include.NON_NULL) public class Album extends NodeSmall { public Date publication = null; diff --git a/back/src/org/kar/karusic/model/Artist.java b/back/src/org/kar/karusic/model/Artist.java index 26daa44..4e9df83 100644 --- a/back/src/org/kar/karusic/model/Artist.java +++ b/back/src/org/kar/karusic/model/Artist.java @@ -14,7 +14,7 @@ CREATE TABLE `node` ( import java.sql.Date; -import org.kar.archidata.annotation.SQLIfNotExists; +import org.kar.archidata.annotation.DataIfNotExists; import com.fasterxml.jackson.annotation.JsonInclude; @@ -22,7 +22,7 @@ import jakarta.persistence.Column; import jakarta.persistence.Table; @Table(name = "artist") -@SQLIfNotExists +@DataIfNotExists @JsonInclude(JsonInclude.Include.NON_NULL) public class Artist extends NodeSmall { @Column(length = 256) @@ -31,10 +31,10 @@ public class Artist extends NodeSmall { public String surname = null; public Date birth = null; public Date death = null; - + @Override public String toString() { - return "Artist [id=" + id + ", name=" + name + ", description=" + description + ", covers=" + covers + ", firstName=" + firstName + ", surname=" + surname + ", birth=" + birth + ", death=" - + death + "]"; + return "Artist [id=" + this.id + ", name=" + this.name + ", description=" + this.description + ", covers=" + this.covers + ", firstName=" + this.firstName + ", surname=" + this.surname + + ", birth=" + this.birth + ", death=" + this.death + "]"; } } diff --git a/back/src/org/kar/karusic/model/Gender.java b/back/src/org/kar/karusic/model/Gender.java index d46833a..3328327 100644 --- a/back/src/org/kar/karusic/model/Gender.java +++ b/back/src/org/kar/karusic/model/Gender.java @@ -12,15 +12,15 @@ CREATE TABLE `node` ( ) AUTO_INCREMENT=10; */ -import org.kar.archidata.annotation.SQLIfNotExists; +import org.kar.archidata.annotation.DataIfNotExists; import com.fasterxml.jackson.annotation.JsonInclude; import jakarta.persistence.Table; @Table(name = "gender") -@SQLIfNotExists +@DataIfNotExists @JsonInclude(JsonInclude.Include.NON_NULL) public class Gender extends NodeSmall { - + } diff --git a/back/src/org/kar/karusic/model/NodeSmall.java b/back/src/org/kar/karusic/model/NodeSmall.java index 570038f..ccf3828 100644 --- a/back/src/org/kar/karusic/model/NodeSmall.java +++ b/back/src/org/kar/karusic/model/NodeSmall.java @@ -15,7 +15,7 @@ CREATE TABLE `node` ( import java.util.List; import org.kar.archidata.model.Data; -import org.kar.archidata.model.GenericTable; +import org.kar.archidata.model.GenericDataSoftDelete; import com.fasterxml.jackson.annotation.JsonInclude; @@ -24,7 +24,7 @@ import jakarta.persistence.FetchType; import jakarta.persistence.ManyToMany; @JsonInclude(JsonInclude.Include.NON_NULL) -public class NodeSmall extends GenericTable { +public class NodeSmall extends GenericDataSoftDelete { @Column(length = 256) public String name = null; public String description = null; diff --git a/back/src/org/kar/karusic/model/Playlist.java b/back/src/org/kar/karusic/model/Playlist.java index 4c087b0..38984f4 100644 --- a/back/src/org/kar/karusic/model/Playlist.java +++ b/back/src/org/kar/karusic/model/Playlist.java @@ -14,7 +14,7 @@ CREATE TABLE `node` ( import java.util.List; -import org.kar.archidata.annotation.SQLIfNotExists; +import org.kar.archidata.annotation.DataIfNotExists; import com.fasterxml.jackson.annotation.JsonInclude; @@ -23,7 +23,7 @@ import jakarta.persistence.ManyToMany; import jakarta.persistence.Table; @Table(name = "playlist") -@SQLIfNotExists +@DataIfNotExists @JsonInclude(JsonInclude.Include.NON_NULL) public class Playlist extends NodeSmall { @ManyToMany(fetch = FetchType.LAZY, targetEntity = Track.class) diff --git a/back/src/org/kar/karusic/model/Track.java b/back/src/org/kar/karusic/model/Track.java index bae5eb3..b8a77bc 100644 --- a/back/src/org/kar/karusic/model/Track.java +++ b/back/src/org/kar/karusic/model/Track.java @@ -14,7 +14,7 @@ CREATE TABLE `node` ( import java.util.List; -import org.kar.archidata.annotation.SQLIfNotExists; +import org.kar.archidata.annotation.DataIfNotExists; import com.fasterxml.jackson.annotation.JsonInclude; @@ -23,7 +23,7 @@ import jakarta.persistence.ManyToMany; import jakarta.persistence.Table; @Table(name = "track") -@SQLIfNotExists +@DataIfNotExists @JsonInclude(JsonInclude.Include.NON_NULL) public class Track extends NodeSmall { public Long genderId = null; @@ -32,10 +32,10 @@ public class Track extends NodeSmall { public Long dataId = null; @ManyToMany(fetch = FetchType.LAZY, targetEntity = Artist.class) public List artists = null; - + @Override public String toString() { - return "Track [id=" + id + ", deleted=" + deleted + ", createdAt=" + createdAt + ", updatedAt=" + updatedAt + ", name=" + name + ", description=" + description + ", covers=" + covers - + ", genderId=" + genderId + ", albumId=" + albumId + ", track=" + track + ", dataId=" + dataId + ", artists=" + artists + "]"; + return "Track [id=" + this.id + ", deleted=" + this.deleted + ", createdAt=" + this.createdAt + ", updatedAt=" + this.updatedAt + ", name=" + this.name + ", description=" + this.description + + ", covers=" + this.covers + ", genderId=" + this.genderId + ", albumId=" + this.albumId + ", track=" + this.track + ", dataId=" + this.dataId + ", artists=" + this.artists + "]"; } } diff --git a/back/src/org/kar/karusic/model/UserKarusic.java b/back/src/org/kar/karusic/model/UserKarusic.java index fb7a81f..43da152 100644 --- a/back/src/org/kar/karusic/model/UserKarusic.java +++ b/back/src/org/kar/karusic/model/UserKarusic.java @@ -1,6 +1,6 @@ package org.kar.karusic.model; -import org.kar.archidata.annotation.SQLIfNotExists; +import org.kar.archidata.annotation.DataIfNotExists; import org.kar.archidata.model.User; import com.fasterxml.jackson.annotation.JsonInclude; @@ -8,8 +8,8 @@ import com.fasterxml.jackson.annotation.JsonInclude; import jakarta.persistence.Table; @Table(name = "user") -@SQLIfNotExists +@DataIfNotExists @JsonInclude(JsonInclude.Include.NON_NULL) public class UserKarusic extends User { - + } diff --git a/back/test/resources/simplelogger.properties b/back/test/resources/simplelogger.properties new file mode 100644 index 0000000..54b58f4 --- /dev/null +++ b/back/test/resources/simplelogger.properties @@ -0,0 +1,35 @@ +# SLF4J's SimpleLogger configuration file +# Simple implementation of Logger that sends all enabled log messages, for all defined loggers, to System.err. +# Default logging detail level for all instances of SimpleLogger. +# Must be one of ("trace", "debug", "info", "warn", or "error"). +# If not specified, defaults to "info". +org.slf4j.simpleLogger.defaultLogLevel=debug + +# Logging detail level for a SimpleLogger instance named "xxxxx". +# Must be one of ("trace", "debug", "info", "warn", or "error"). +# If not specified, the default logging detail level is used. +#org.slf4j.simpleLogger.log.xxxxx= + +# Set to true if you want the current date and time to be included in output messages. +# Default is false, and will output the number of milliseconds elapsed since startup. +#org.slf4j.simpleLogger.showDateTime=false + +# The date and time format to be used in the output messages. +# The pattern describing the date and time format is the same that is used in java.text.SimpleDateFormat. +# If the format is not specified or is invalid, the default format is used. +# The default format is yyyy-MM-dd HH:mm:ss:SSS Z. +#org.slf4j.simpleLogger.dateTimeFormat=yyyy-MM-dd HH:mm:ss:SSS Z + +# Set to true if you want to output the current thread name. +# Defaults to true. +org.slf4j.simpleLogger.showThreadName=true + +# Set to true if you want the Logger instance name to be included in output messages. +# Defaults to true. +#org.slf4j.simpleLogger.showLogName=true + +# Set to true if you want the last component of the name to be included in output messages. +# Defaults to false. +#org.slf4j.simpleLogger.showShortLogName=false + + diff --git a/back/test/src/test/kar/karusic/StepwiseExtension.java b/back/test/src/test/kar/karusic/StepwiseExtension.java new file mode 100644 index 0000000..fb0c9a4 --- /dev/null +++ b/back/test/src/test/kar/karusic/StepwiseExtension.java @@ -0,0 +1,33 @@ +package test.kar.karusic; + +import org.junit.jupiter.api.extension.ConditionEvaluationResult; +import org.junit.jupiter.api.extension.ExecutionCondition; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.TestExecutionExceptionHandler; + +class StepwiseExtension implements ExecutionCondition, TestExecutionExceptionHandler { + @Override + public ConditionEvaluationResult evaluateExecutionCondition(final ExtensionContext extensionContext) { + final ExtensionContext.Namespace namespace = namespaceFor(extensionContext); + final ExtensionContext.Store store = storeFor(extensionContext, namespace); + final String value = store.get(StepwiseExtension.class, String.class); + return value == null ? ConditionEvaluationResult.enabled("No test failures in stepwise tests") + : ConditionEvaluationResult.disabled(String.format("Stepwise test disabled due to previous failure in '%s'", value)); + } + + @Override + public void handleTestExecutionException(final ExtensionContext extensionContext, final Throwable throwable) throws Throwable { + final ExtensionContext.Namespace namespace = namespaceFor(extensionContext); + final ExtensionContext.Store store = storeFor(extensionContext, namespace); + store.put(StepwiseExtension.class, extensionContext.getDisplayName()); + throw throwable; + } + + private ExtensionContext.Namespace namespaceFor(final ExtensionContext extensionContext) { + return ExtensionContext.Namespace.create(StepwiseExtension.class, extensionContext.getParent()); + } + + private ExtensionContext.Store storeFor(final ExtensionContext extensionContext, final ExtensionContext.Namespace namespace) { + return extensionContext.getParent().get().getStore(namespace); + } +} \ No newline at end of file diff --git a/back/test/src/test/kar/karusic/TestBase.java b/back/test/src/test/kar/karusic/TestBase.java new file mode 100644 index 0000000..0d9d78f --- /dev/null +++ b/back/test/src/test/kar/karusic/TestBase.java @@ -0,0 +1,250 @@ +package test.kar.karusic; + +import java.util.Map; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.ExtendWith; +import org.kar.archidata.exception.RESTErrorResponseExeption; +import org.kar.archidata.model.GetToken; +import org.kar.archidata.util.ConfigBaseVariable; +import org.kar.archidata.util.JWTWrapper; +import org.kar.archidata.util.RESTApi; +import org.kar.karusic.api.HealthCheck.HealthResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.nimbusds.jwt.JWTClaimsSet; + +@ExtendWith(StepwiseExtension.class) +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class TestBase { + private final static Logger LOGGER = LoggerFactory.getLogger(TestBase.class); + + static WebLauncherTest webInterface = null; + static RESTApi api = null; + + public void login(final String login, final String password) { + try { + final GetToken token = api.post(GetToken.class, "users/get_token", DataGetToken.generate(login, "v1", "202515252", password)); + api.setToken(token.jwt()); + } catch (final Exception ex) { + Assertions.fail("Can not get Authentication for '" + login + "' ==> " + ex.getMessage()); + } + } + + public void loginAdmin() { + login("karadmin", "adminA@666"); + } + + @BeforeAll + public static void configureWebServer() throws Exception { + LOGGER.info("configure server ..."); + webInterface = new WebLauncherTest(); + LOGGER.info("Create DB"); + try { + webInterface.migrateDB(); + } catch (final Exception ex) { + ex.printStackTrace(); + LOGGER.error("Detect an error: {}", ex.getMessage()); + } + LOGGER.info("Start REST (BEGIN)"); + webInterface.process(); + LOGGER.info("Start REST (DONE)"); + api = new RESTApi(ConfigBaseVariable.apiAdress); + } + + @AfterAll + public static void stopWebServer() throws InterruptedException { + LOGGER.info("Kill the web server"); + webInterface = null; + // TODO: do it better... + } + + @Order(1) + @Test + //@RepeatedTest(10) + public void checkHealthCheck() throws Exception { + final HealthResult result = api.get(HealthResult.class, "health_check"); + Assertions.assertEquals(result.value(), "alive and kicking"); + } + + @Order(2) + @Test + public void checkHealthCheckWrongAPI() throws Exception { + Assertions.assertThrows(RESTErrorResponseExeption.class, () -> api.get(HealthResult.class, "health_checks")); + } + + @Order(3) + @Test + public void firstUserConnect() throws Exception { + final GetToken result = api.post(GetToken.class, "users/get_token", DataGetToken.generate("karadmin", "v1", "202515252", "adminA@666")); + final String[] splitted = result.jwt().split("\\."); + Assertions.assertEquals(3, splitted.length); + final String authorization = result.jwt(); + LOGGER.debug(" validate token : " + authorization); + // Note with local access we get the internal key of the system. + final JWTClaimsSet ret = JWTWrapper.validateToken(authorization, "KarAuth", null); + // check the token is valid !!! (signed and coherent issuer... + Assertions.assertNotNull(ret); + // check userID + final String userUID = ret.getSubject(); + final long id = Long.parseLong(userUID); + Assertions.assertEquals(1, id); + final String name = (String) ret.getClaim("login"); + Assertions.assertEquals("karadmin", name); + + final Object rowRight = ret.getClaim("right"); + Assertions.assertNotNull(rowRight); + final Map> rights = (Map>) ret.getClaim("right"); + // Check if the element contain the basic keys: + Assertions.assertEquals(rights.size(), 1); + Assertions.assertTrue(rights.containsKey("karusic")); + final Map applRight = rights.get("karusic"); + //logger.error("full right: {}", applRight); + Assertions.assertEquals(applRight.size(), 2); + Assertions.assertTrue(applRight.containsKey("ADMIN")); + Assertions.assertEquals(true, applRight.get("ADMIN")); + Assertions.assertTrue(applRight.containsKey("USER")); + Assertions.assertEquals(true, applRight.get("USER")); + + //logger.debug("request user: '{}' right: '{}' row='{}'", userUID, applRight, rowRight); + + //Assertions.assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9", splitted[0]); + //Assertions.assertEquals("eyJzdWIiOiIwIiwiYXBwbGljYXRpb24iOiJrYXJzbyIsImlzcyI6IkthckF1dGgiLCJyaWdodCI6eyJrYXJzbyI6eyJBRE1JTiI6dHJ1ZSwiVVNFUiI6dHJ1ZX19LCJsb2dpbiI6ImthcmFkbWluIiwiZXhwIjoxNjg0MTk5MTkzLCJpYXQiOjE2ODI3NTU0MjV9", splitted[1]); + // TODO ... Assertions.assertEquals("????", splitted[2]); + } + + public void checkFail(final String type, final String urlOffset, final int errorStatus) { + checkFail(type, urlOffset, errorStatus, null); + } + + public void checkFail(final String type, final String urlOffset, final int errorStatus, final String data) { + LOGGER.info("Test API: url={} urlOffset={}", type, urlOffset); + try { + if ("GET".equals(type)) { + api.get(String.class, urlOffset); + } else if ("POST".equals(type)) { + api.post(String.class, urlOffset, data); + } else if ("PUT".equals(type)) { + api.put(String.class, urlOffset, data); + } else if ("DELETE".equals(type)) { + api.delete(String.class, urlOffset); + } + Assertions.fail("Request on URL does not fail as expected: '" + type + "' url='" + urlOffset + "'"); + } catch (final RESTErrorResponseExeption ex) { + if (errorStatus != ex.status) { + LOGGER.error("Fail in test with the wrong return errors: {}", ex.toString()); + } + Assertions.assertEquals(errorStatus, ex.status); + } catch (final Exception ex) { + LOGGER.error("Unexpected throw error: {}", ex); + Assertions.fail("Unexpected throws..."); + } + + } + + public void checkWork(final String type, final String urlOffset) { + checkWork(type, urlOffset, null); + } + + public void checkWork(final String type, final String urlOffset, final String data) { + LOGGER.info("Test API: url={} urlOffset={}", type, urlOffset); + try { + if ("GET".equals(type)) { + api.get(String.class, urlOffset); + } else if ("POST".equals(type)) { + api.post(String.class, urlOffset, data); + } else if ("PUT".equals(type)) { + api.put(String.class, urlOffset, data); + } else if ("DELETE".equals(type)) { + api.delete(String.class, urlOffset); + } + //Assertions.fail("Request on URL does not fail as expected: '" + type + "' url='" + urlOffset + "'"); + } catch (final RESTErrorResponseExeption ex) { + Assertions.fail("Must not fail ... " + ex.toString()); + } catch (final Exception ex) { + LOGGER.error("Unexpected throw error: {}", ex); + Assertions.fail("Unexpected throws..."); + } + + } + + @Order(4) + @Test + public void checkUnAuthorizedAPI() throws Exception { + // /application/ + checkFail("GET", "application/", 401); + checkFail("POST", "application/", 401, "{}"); + checkFail("PUT", "application/", 405, "{}"); // does not exist + checkFail("DELETE", "application/", 405); // does not exist + // /application/{id} + checkFail("GET", "application/0", 401); + checkFail("PUT", "application/0", 401, "{}"); + checkFail("POST", "application/0", 405, "{}"); + checkFail("DELETE", "application/0", 401); + // /application/{id}/* + checkFail("GET", "application/0/users", 401); + // /application/* + checkFail("GET", "application/small", 401); + checkFail("GET", "application/get_token", 401); + checkFail("GET", "application/return", 401); + + // /application_token/ section: + checkFail("GET", "application_token/0", 401); + checkFail("DELETE", "application_token/0/5", 401); + checkFail("DELETE", "application_token/0/create", 401); + + // /front/* + checkFail("GET", "front", 404); // no index in test section + // health check + checkWork("GET", "health_check"); + + // public_key (only application) + checkFail("GET", "public_key", 401); + checkFail("GET", "public_key/pem", 401); + + // /right + checkFail("GET", "right", 401); + checkFail("POST", "right", 401, "{}"); + checkFail("GET", "right/0", 401); + checkFail("PUT", "right/0", 401, "{}"); + checkFail("DELETE", "right/0", 401); + + // /system_config + checkWork("GET", "system_config/is_sign_up_availlable"); + checkFail("GET", "system_config/key/skjdfhkjsdhfkjsh", 401); + checkFail("PUT", "system_config/key/skjdfhkjsdhfkjsh", 401, "{}"); + + // /users + checkFail("GET", "users", 401); + checkFail("GET", "users/0", 401); + checkFail("POST", "users/0/application/0/link", 401, "{}"); + checkFail("POST", "users/0/set_admin", 401, "{}"); + checkFail("POST", "users/0/set_blocked", 401, "{}"); + checkFail("POST", "users/create_new_user", 401, "{}"); + checkFail("GET", "users/me", 401, "{}"); + checkFail("POST", "users/password", 401, "{}"); + checkWork("GET", "users/check_login?login=karadmin"); + checkFail("GET", "users/check_login?login=jhkjhkjh", 404); + checkWork("GET", "users/check_email?email=admin@admin.ZZZ"); + checkFail("GET", "users/check_email?email=ksjhdkjfhskjdh", 404); + // not testable : get_token + + } + + @Order(5) + @Test + public void testMeWithToken() throws Exception { + loginAdmin(); + final String result = api.get(String.class, "users/me"); + Assertions.assertEquals("{\"id\":1,\"login\":\"karadmin\"}", result); + + } + +} diff --git a/back/test/src/test/kar/karusic/WebLauncherTest.java b/back/test/src/test/kar/karusic/WebLauncherTest.java new file mode 100755 index 0000000..53f21d0 --- /dev/null +++ b/back/test/src/test/kar/karusic/WebLauncherTest.java @@ -0,0 +1,28 @@ + +package test.kar.karusic; + +import org.kar.archidata.util.ConfigBaseVariable; +import org.kar.karusic.WebLauncher; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class WebLauncherTest extends WebLauncher { + final private static Logger LOGGER = LoggerFactory.getLogger(WebLauncherTest.class); + + public WebLauncherTest() { + LOGGER.debug("Configure REST system"); + // for local test: + ConfigBaseVariable.apiAdress = "http://127.0.0.1:12345/test/api/"; + + ConfigBaseVariable.dbPort = "3306"; + // for the test we a in memory sqlite.. + ConfigBaseVariable.dbType = "sqlite"; + ConfigBaseVariable.dbHost = "memory"; + // for test we need to connect all time the DB + ConfigBaseVariable.dbKeepConnected = "true"; + + ConfigBaseVariable.dbHost = "localhost"; + ConfigBaseVariable.dbUser = "root"; + ConfigBaseVariable.dbPassword = "ZERTYSDGFVHSDFGHJYZSDFGSQxfgsqdfgsqdrf4564654"; + } +}