[DEV] update all the model

This commit is contained in:
Edouard DUPIN 2024-03-17 23:45:38 +01:00
parent 5d8dab3742
commit cebf7d35fb
34 changed files with 349 additions and 315 deletions

View File

@ -27,6 +27,11 @@
<artifactId>slf4j-simple</artifactId>
<version>2.0.9</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.16.1</version>
</dependency>
<!--
************************************************************
** TEST dependency **

View File

@ -13,6 +13,7 @@ import org.kar.archidata.api.DataResource;
import org.kar.archidata.catcher.ExceptionCatcher;
import org.kar.archidata.catcher.FailExceptionCatcher;
import org.kar.archidata.catcher.InputExceptionCatcher;
import org.kar.archidata.catcher.JacksonCatcher;
import org.kar.archidata.catcher.SystemExceptionCatcher;
import org.kar.archidata.filter.CORSFilter;
import org.kar.archidata.filter.OptionFilter;
@ -91,6 +92,7 @@ public class WebLauncher {
// global authentication system
rc.register(KarusicAuthenticationFilter.class);
// register exception catcher
rc.register(JacksonCatcher.class);
rc.register(InputExceptionCatcher.class);
rc.register(SystemExceptionCatcher.class);
rc.register(FailExceptionCatcher.class);

View File

@ -8,6 +8,7 @@ import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.annotation.AsyncType;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.addOn.AddOnDataJson;
import org.kar.archidata.dataAccess.addOn.AddOnManyToMany;
import org.kar.archidata.tools.DataTools;
import org.kar.karusic.model.Album;
@ -108,7 +109,7 @@ public class AlbumResource {
@RolesAllowed("ADMIN")
@Operation(description = "Remove a cover on a specific album")
public Album removeCover(@PathParam("id") final Long id, @PathParam("coverId") final UUID coverId) throws Exception {
//AddOnManyToMany.removeLink(Album.class, id, "cover", coverId);
AddOnDataJson.removeLink(Album.class, id, "covers", coverId);
return DataAccess.get(Album.class, id);
}
}

View File

@ -8,6 +8,7 @@ import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.annotation.AsyncType;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.addOn.AddOnDataJson;
import org.kar.archidata.tools.DataTools;
import org.kar.karusic.model.Artist;
import org.slf4j.Logger;
@ -80,7 +81,8 @@ public class ArtistResource {
@Path("{id}/cover/{coverId}")
@RolesAllowed("ADMIN")
public Artist removeCover(@PathParam("id") final Long id, @PathParam("coverId") final UUID coverId) throws Exception {
//AddOnManyToMany.removeLink(Artist.class, id, "cover", coverId);
LOGGER.error("klmlmkmlkmlklmklmk");
AddOnDataJson.removeLink(Artist.class, id, "covers", coverId);
return DataAccess.get(Artist.class, id);
}
}

View File

@ -8,6 +8,7 @@ import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.annotation.AsyncType;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.addOn.AddOnDataJson;
import org.kar.archidata.tools.DataTools;
import org.kar.karusic.model.Gender;
import org.slf4j.Logger;
@ -54,7 +55,7 @@ public class GenderResource {
@Path("{id}")
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Gender patch(@PathParam("id") final Long id, final String jsonRequest) throws Exception {
public Gender patch(@PathParam("id") final Long id, @AsyncType(Gender.class) final String jsonRequest) throws Exception {
DataAccess.updateWithJson(Gender.class, id, jsonRequest);
return DataAccess.get(Gender.class, id);
}
@ -80,7 +81,7 @@ public class GenderResource {
@Path("{id}/cover/{coverId}")
@RolesAllowed("ADMIN")
public Gender removeCover(@PathParam("id") final Long id, @PathParam("coverId") final UUID coverId) throws Exception {
//AddOnManyToMany.removeLink(Gender.class, id, "cover", coverId);
AddOnDataJson.removeLink(Gender.class, id, "covers", coverId);
return DataAccess.get(Gender.class, id);
}
}

View File

@ -8,6 +8,7 @@ import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.annotation.AsyncType;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.addOn.AddOnDataJson;
import org.kar.archidata.dataAccess.addOn.AddOnManyToMany;
import org.kar.archidata.tools.DataTools;
import org.kar.karusic.model.Playlist;
@ -34,13 +35,13 @@ public class PlaylistResource {
@GET
@Path("{id}")
@RolesAllowed("USER")
public static Playlist getWithId(@PathParam("id") final Long id) throws Exception {
public static Playlist get(@PathParam("id") final Long id) throws Exception {
return DataAccess.get(Playlist.class, id);
}
@GET
@RolesAllowed("USER")
public List<Playlist> get() throws Exception {
public List<Playlist> gets() throws Exception {
return DataAccess.gets(Playlist.class);
}
@ -55,7 +56,7 @@ public class PlaylistResource {
@Path("{id}")
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Playlist put(@PathParam("id") final Long id, final String jsonRequest) throws Exception {
public Playlist patch(@PathParam("id") final Long id, @AsyncType(Playlist.class) final String jsonRequest) throws Exception {
DataAccess.updateWithJson(Playlist.class, id, jsonRequest);
return DataAccess.get(Playlist.class, id);
}
@ -71,7 +72,7 @@ public class PlaylistResource {
@Path("{id}/track/{trackId}")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
public Playlist uploadTrack(@PathParam("id") final Long id, @PathParam("trackId") final 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 DataAccess.get(Playlist.class, id);
}
@ -98,7 +99,7 @@ public class PlaylistResource {
@Path("{id}/cover/{coverId}")
@RolesAllowed("ADMIN")
public Playlist removeCover(@PathParam("id") final Long id, @PathParam("coverId") final UUID coverId) throws Exception {
//AddOnManyToMany.removeLink(Playlist.class, id, "cover", coverId);
AddOnDataJson.removeLink(Playlist.class, id, "covers", coverId);
return DataAccess.get(Playlist.class, id);
}
}

View File

@ -12,6 +12,7 @@ import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.annotation.AsyncType;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.QueryCondition;
import org.kar.archidata.dataAccess.addOn.AddOnDataJson;
import org.kar.archidata.dataAccess.addOn.AddOnManyToMany;
import org.kar.archidata.dataAccess.options.Condition;
import org.kar.archidata.model.Data;
@ -107,12 +108,12 @@ public class TrackResource {
@Path("{id}/cover/{coverId}")
@RolesAllowed("ADMIN")
public Track removeCover(@PathParam("id") final Long id, @PathParam("coverId") final UUID coverId) throws Exception {
//AddOnManyToMany.removeLink(Track.class, id, "cover", coverId);
AddOnDataJson.removeLink(Track.class, id, "covers", coverId);
return DataAccess.get(Track.class, id);
}
@POST
@Path("/upload/")
@Path("upload/")
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
// Formatter:off
@ -230,7 +231,7 @@ public class TrackResource {
trackElem.albumId = albumElem != null ? albumElem.id : null;
trackElem.genderId = genderElem != null ? genderElem.id : null;
trackElem.dataId = data.id;
// Now list of artis has an internal management:
// Now list of artist has an internal management:
if (artistElem != null) {
trackElem.artists = new ArrayList<>();
trackElem.artists.add(artistElem.id);

View File

@ -83,18 +83,28 @@ public class Migration20240226 extends MigrationSqlStep {
}
}
});
addAction("""
ALTER TABLE `track` CHANGE `dataUUID` `dataUUID` binary(16) NOT NULL;
DROP TABLE `playlist`;
""");
addAction("""
DROP TABLE `playlist_link_track`;
""");
addAction("""
ALTER TABLE `track` DROP `dataId`;
""");
*/
addAction("""
DROP TABLE `playlist`;
ALTER TABLE `track` CHANGE `dataUUID` `dataId` binary(16) NOT NULL;
""");
addAction("""
DROP TABLE `playlist_link_track`;
ALTER TABLE `data` DROP `id`;
""");
addAction("""
ALTER TABLE `data` CHANGE `uuid` `id` binary(16) DEFAULT (UUID_TO_BIN(UUID(), TRUE));
""");
addAction("""
ALTER TABLE `data` ADD PRIMARY KEY `id` (`id`);
""");
/*
// Move the files...

View File

@ -9,9 +9,11 @@ import { Routes, RouterModule } from '@angular/router'; // CLI imports router
import { ForbiddenScene, HomeOutScene, NotFound404Scene, SsoScene } from 'common/scene';
import { OnlyAdminGuard, OnlyUnregisteredGuardHome, OnlyUsersGuard, OnlyUsersGuardHome } from 'common/service';
import { HelpScene, HomeScene, AlbumEditScene, AlbumsScene, ArtistEditScene, ArtistScene, SettingsScene,
GenderScene, PlaylistScene, TrackEditScene, TrackScene, UploadScene, ArtistsScene, ArtistAlbumScene, AlbumScene } from './scene';
import {
HelpScene, HomeScene, AlbumEditScene, AlbumsScene, ArtistEditScene, ArtistScene, SettingsScene,
GenderScene, PlaylistScene, TrackEditScene, TrackScene, UploadScene, ArtistsScene, ArtistAlbumScene, AlbumScene
} from './scene';
// import { HelpComponent } from './help/help.component';
// see https://angular.io/guide/router
@ -21,13 +23,13 @@ const routes: Routes = [
{ path: '', redirectTo: '/home', pathMatch: 'full' },
{ path: 'forbidden', component: ForbiddenScene },
// ------------------------------------
// -- home global interface
// ------------------------------------
{
path: 'home',
component: HomeScene,
component: HomeScene,
canActivate: [OnlyUsersGuardHome], // this route to unregistered path when not logged ==> permit to simplify display
},
{
@ -72,7 +74,7 @@ const routes: Routes = [
canActivate: [OnlyUsersGuard],
},
//{ path: 'gender-edit/:genderId', component: GenderEditScene },
//{ path: 'gender/:genderId', component: GenderScene },
//{ path: 'gender/:genderId/:artistId/:albumId/:trackId', component: GenderScene },
@ -89,7 +91,7 @@ const routes: Routes = [
component: PlaylistScene,
canActivate: [OnlyUsersGuard],
},
//{ path: 'playlist-edit/:playlistId', component: PlaylistEditScene },
// ------------------------------------
@ -107,16 +109,16 @@ const routes: Routes = [
component: ArtistScene,
canActivate: [OnlyUsersGuard],
},
{
path: 'artist/:artistId/edit',
component: ArtistEditScene,
canActivate: [OnlyAdminGuard],
},
{
path: 'artist/:artistId/:albumId',
component: ArtistAlbumScene,
canActivate: [OnlyUsersGuard],
},
{
path: 'artist-edit/:artistId',
component: ArtistEditScene,
canActivate: [OnlyAdminGuard],
},
// ------------------------------------
// -- Album:

View File

@ -2,7 +2,7 @@
* API of the server (auto-generated code)
*/
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import {UUID, Long, Album, isAlbum, } from "./model"
import {Long, UUID, Album, isAlbum, } from "./model"
export namespace AlbumResource {
/**
@ -83,42 +83,6 @@ export namespace AlbumResource {
data,
}, isAlbum);
};
/**
* Get all the available Albums
*/
export function gets({ restConfig, }: {
restConfig: RESTConfig,
}): Promise<Album[]> {
return RESTRequestJsonArray({
restModel: {
endPoint: "/album",
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON,
},
restConfig,
}, isAlbum);
};
/**
* Add a Track on a specific album
*/
export function addTrack({ restConfig, params, }: {
restConfig: RESTConfig,
params: {
trackId: Long,
id: Long,
},
}): Promise<Album> {
return RESTRequestJson({
restModel: {
endPoint: "/album/{id}/track/{trackId}",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isAlbum);
};
/**
* Remove a Track on a specific album
*/
@ -184,4 +148,40 @@ export namespace AlbumResource {
params,
}, isAlbum);
};
/**
* Get all the available Albums
*/
export function gets({ restConfig, }: {
restConfig: RESTConfig,
}): Promise<Album[]> {
return RESTRequestJsonArray({
restModel: {
endPoint: "/album",
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON,
},
restConfig,
}, isAlbum);
};
/**
* Add a Track on a specific album
*/
export function addTrack({ restConfig, params, }: {
restConfig: RESTConfig,
params: {
trackId: Long,
id: Long,
},
}): Promise<Album> {
return RESTRequestJson({
restModel: {
endPoint: "/album/{id}/track/{trackId}",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isAlbum);
};
}

View File

@ -2,7 +2,7 @@
* API of the server (auto-generated code)
*/
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import {Artist, UUID, Long, isArtist, } from "./model"
import {Artist, Long, UUID, isArtist, } from "./model"
export namespace ArtistResource {
export function remove({ restConfig, params, }: {
@ -71,18 +71,6 @@ export namespace ArtistResource {
data,
}, isArtist);
};
export function gets({ restConfig, }: {
restConfig: RESTConfig,
}): Promise<Artist[]> {
return RESTRequestJsonArray({
restModel: {
endPoint: "/artist",
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON,
},
restConfig,
}, isArtist);
};
export function uploadCover({ restConfig, params, data, }: {
restConfig: RESTConfig,
params: {
@ -122,4 +110,16 @@ export namespace ArtistResource {
params,
}, isArtist);
};
export function gets({ restConfig, }: {
restConfig: RESTConfig,
}): Promise<Artist[]> {
return RESTRequestJsonArray({
restModel: {
endPoint: "/artist",
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON,
},
restConfig,
}, isArtist);
};
}

View File

@ -2,7 +2,7 @@
* API of the server (auto-generated code)
*/
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import {Long, } from "./model"
import {UUID, } from "./model"
export namespace DataResource {
/**
@ -35,7 +35,7 @@ export namespace DataResource {
Authorization: string,
},
params: {
id: Long,
id: UUID,
},
data: string,
}): Promise<void> {
@ -60,7 +60,7 @@ export namespace DataResource {
Authorization: string,
},
params: {
id: Long,
id: UUID,
},
data: string,
}): Promise<void> {
@ -86,7 +86,7 @@ export namespace DataResource {
},
params: {
name: string,
id: Long,
id: UUID,
},
data: string,
}): Promise<void> {

View File

@ -2,7 +2,7 @@
* API of the server (auto-generated code)
*/
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import {UUID, Long, Gender, isGender, } from "./model"
import {Long, Gender, UUID, isGender, } from "./model"
export namespace GenderResource {
export function remove({ restConfig, params, }: {
@ -42,7 +42,7 @@ export namespace GenderResource {
params: {
id: Long,
},
data: string,
data: Gender,
}): Promise<Gender> {
return RESTRequestJson({
restModel: {
@ -71,18 +71,6 @@ export namespace GenderResource {
data,
}, isGender);
};
export function gets({ restConfig, }: {
restConfig: RESTConfig,
}): Promise<Gender[]> {
return RESTRequestJsonArray({
restModel: {
endPoint: "/gender",
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON,
},
restConfig,
}, isGender);
};
export function uploadCover({ restConfig, params, data, }: {
restConfig: RESTConfig,
params: {
@ -122,4 +110,16 @@ export namespace GenderResource {
params,
}, isGender);
};
export function gets({ restConfig, }: {
restConfig: RESTConfig,
}): Promise<Gender[]> {
return RESTRequestJsonArray({
restModel: {
endPoint: "/gender",
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON,
},
restConfig,
}, isGender);
};
}

View File

@ -2,7 +2,7 @@
* API of the server (auto-generated code)
*/
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import {UUID, Long, Playlist, isPlaylist, } from "./model"
import {Long, UUID, Playlist, isPlaylist, } from "./model"
export namespace PlaylistResource {
export function remove({ restConfig, params, }: {
@ -21,24 +21,28 @@ export namespace PlaylistResource {
params,
});
};
export function get({ restConfig, }: {
restConfig: RESTConfig,
}): Promise<Playlist[]> {
return RESTRequestJsonArray({
restModel: {
endPoint: "/playlist",
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON,
},
restConfig,
}, isPlaylist);
};
export function put({ restConfig, params, data, }: {
export function get({ restConfig, params, }: {
restConfig: RESTConfig,
params: {
id: Long,
},
data: string,
}): Promise<Playlist> {
return RESTRequestJson({
restModel: {
endPoint: "/playlist/{id}",
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isPlaylist);
};
export function patch({ restConfig, params, data, }: {
restConfig: RESTConfig,
params: {
id: Long,
},
data: Playlist,
}): Promise<Playlist> {
return RESTRequestJson({
restModel: {
@ -123,23 +127,19 @@ export namespace PlaylistResource {
params,
}, isPlaylist);
};
export function getWithId({ restConfig, params, }: {
export function gets({ restConfig, }: {
restConfig: RESTConfig,
params: {
id: Long,
},
}): Promise<Playlist> {
return RESTRequestJson({
}): Promise<Playlist[]> {
return RESTRequestJsonArray({
restModel: {
endPoint: "/playlist/{id}",
endPoint: "/playlist",
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isPlaylist);
};
export function uploadTrack({ restConfig, params, }: {
export function addTrack({ restConfig, params, }: {
restConfig: RESTConfig,
params: {
trackId: Long,

View File

@ -74,19 +74,26 @@ export type RESTRequestType = {
queries?: object,
};
/**
* This service permit to add some data like token and authorization..
*/
export function RESTRequest({ restModel, restConfig, data, params, queries }: RESTRequestType): Promise<ModelResponseHttp> {
function removeTrailingSlashes(input: string): string {
return input.replace(/\/+$/, '');
}
function removeLeadingSlashes(input: string): string {
return input.replace(/^\/+/, '');
}
export function RESTUrl({ restModel, restConfig, data, params, queries }: RESTRequestType): string {
// Create the URL PATH:
let generateUrl = `${restConfig.server}/${restModel.endPoint}`;
let generateUrl = `${removeTrailingSlashes(restConfig.server)}/${removeLeadingSlashes(restModel.endPoint)}`;
if (params !== undefined) {
for (let key of Object.keys(params)) {
generateUrl = generateUrl.replaceAll(`{${key}}`, `${params[key]}`);
}
}
if (queries === undefined && (restConfig.token === undefined || restModel.tokenInUrl !== true)) {
return generateUrl;
}
const searchParams = new URLSearchParams();
if (queries !== undefined) {
const searchParams = new URLSearchParams();
for (let key of Object.keys(queries)) {
const value = queries[key];
if (Array.isArray(value)) {
@ -97,11 +104,16 @@ export function RESTRequest({ restModel, restConfig, data, params, queries }: RE
searchParams.append(`${key}`, `${value}`);
}
}
if (restConfig.token !== undefined && restModel.tokenInUrl === true) {
searchParams.append('Authorization', `Bearer ${restConfig.token}`);
}
generateUrl += "?" + searchParams.toString();
}
if (restConfig.token !== undefined && restModel.tokenInUrl === true) {
searchParams.append('Authorization', `Bearer ${restConfig.token}`);
}
return generateUrl + "?" + searchParams.toString();
}
export function RESTRequest({ restModel, restConfig, data, params, queries }: RESTRequestType): Promise<ModelResponseHttp> {
// Create the URL PATH:
let generateUrl = RESTUrl({ restModel, restConfig, data, params, queries });
let headers: any = {};
if (restConfig.token !== undefined && restModel.tokenInUrl !== true) {
headers['Authorization'] = `Bearer ${restConfig.token}`;
@ -111,7 +123,10 @@ export function RESTRequest({ restModel, restConfig, data, params, queries }: RE
}
if (restModel.requestType !== HTTPRequestModel.GET) {
// if Get we have not a content type, the body is empty
headers['Content-Type'] = restModel.contentType;
if (restModel.contentType !== HTTPMimeType.MULTIPART) {
// special case of multi-part ==> no content type otherwise the browser does not set the ";bundary=--****"
headers['Content-Type'] = restModel.contentType;
}
}
let body = data;
if (restModel.contentType === HTTPMimeType.JSON) {

View File

@ -2,7 +2,7 @@
* API of the server (auto-generated code)
*/
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import {UUID, Long, Track, isTrack, } from "./model"
import {Long, Track, UUID, isTrack, } from "./model"
export namespace TrackResource {
export function remove({ restConfig, params, }: {
@ -71,36 +71,6 @@ export namespace TrackResource {
data,
}, isTrack);
};
export function gets({ restConfig, }: {
restConfig: RESTConfig,
}): Promise<Track[]> {
return RESTRequestJsonArray({
restModel: {
endPoint: "/track",
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON,
},
restConfig,
}, isTrack);
};
export function addTrack({ restConfig, params, }: {
restConfig: RESTConfig,
params: {
artistId: Long,
id: Long,
},
}): Promise<Track> {
return RESTRequestJson({
restModel: {
endPoint: "/track/{id}/artist/{artistId}",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isTrack);
};
export function removeTrack({ restConfig, params, }: {
restConfig: RESTConfig,
params: {
@ -171,7 +141,7 @@ export namespace TrackResource {
}): Promise<Track> {
return RESTRequestJson({
restModel: {
endPoint: "/track//upload/",
endPoint: "/track/upload/",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
@ -180,4 +150,34 @@ export namespace TrackResource {
data,
}, isTrack);
};
export function gets({ restConfig, }: {
restConfig: RESTConfig,
}): Promise<Track[]> {
return RESTRequestJsonArray({
restModel: {
endPoint: "/track",
requestType: HTTPRequestModel.GET,
accept: HTTPMimeType.JSON,
},
restConfig,
}, isTrack);
};
export function addTrack({ restConfig, params, }: {
restConfig: RESTConfig,
params: {
artistId: Long,
id: Long,
},
}): Promise<Track> {
return RESTRequestJson({
restModel: {
endPoint: "/track/{id}/artist/{artistId}",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
}, isTrack);
};
}

View File

@ -22,19 +22,6 @@ export namespace UserResource {
params,
}, isUserKarusic);
};
export function gets({ restConfig, produce, }: {
restConfig: RESTConfig,
produce: HTTPMimeType.JSON,
}): Promise<UserKarusic[]> {
return RESTRequestJsonArray({
restModel: {
endPoint: "/users",
requestType: HTTPRequestModel.GET,
accept: produce,
},
restConfig,
}, isUserKarusic);
};
export function getMe({ restConfig, produce, }: {
restConfig: RESTConfig,
produce: HTTPMimeType.JSON,
@ -48,4 +35,17 @@ export namespace UserResource {
restConfig,
}, isUserOut);
};
export function gets({ restConfig, produce, }: {
restConfig: RESTConfig,
produce: HTTPMimeType.JSON,
}): Promise<UserKarusic[]> {
return RESTRequestJsonArray({
restModel: {
endPoint: "/users",
requestType: HTTPRequestModel.GET,
accept: produce,
},
restConfig,
}, isUserKarusic);
};
}

View File

@ -106,9 +106,10 @@ export class ElementPlayerAudioComponent implements OnInit {
this.haveNext = this.localIdStreaming >= this.localListStreaming.length - 1;
this.trackService.get(this.localListStreaming[this.localIdStreaming])
.then((response: Track) => {
//console.log(`get response of video : ${ JSON.stringify(response, null, 2)}`);
console.log(`get response of video : ${JSON.stringify(response, null, 2)}`);
self.currentLMedia = response;
self.dataTitle = response.name;
console.log("aaa");
if (!isNullOrUndefined(response.albumId)) {
this.albumService.get(response.albumId)
.then((response2: Album) => {
@ -117,24 +118,25 @@ export class ElementPlayerAudioComponent implements OnInit {
})
.catch(() => { });
}
console.log("aaa");
if (!isNullOrUndefined(response.artists) && isArray(response.artists) && response.artists.length > 0) {
this.artistService.get(response.artists[0])
.then((response2: Artist) => {
self.dataAuthor = response2.name;
})
.catch(() => { });
}
} console.log("aaa");
if (isNullOrUndefined(self.currentLMedia)) {
console.log("Can not retrieve the media ...")
return;
}
} console.log("aaa");
if (isNullOrUndefined(self.currentLMedia.dataId)) {
console.log("Can not retrieve the media ... null or undefined data ID")
return;
}
} console.log("aaa");
self.mediaSource = self.dataService.getUrl(self.currentLMedia.dataId, "unknownMediaName.webm");
}).catch(() => {
console.error("error not unmanaged in audio player ... 111");
}).catch((error) => {
console.error(`error not unmanaged in audio player ... 111 ${error}`);
})
}
updateTitle() {

View File

@ -10,7 +10,7 @@
<div class="noImage"></div>
}
</div>
@if(data) {
@if(element) {
<div class="title-small">
{{episodeDisplay}} {{name}}
</div>

View File

@ -187,7 +187,7 @@ export class AlbumEditScene implements OnInit {
this.deleteCoverId = id;
this.popInService.open('popin-delete-confirm');
}
removeCoverAfterConfirm(id: number) {
removeCoverAfterConfirm(id: string) {
console.log(`Request remove cover: ${id}`);
let self = this;
this.albumService.deleteCover(this.idAlbum, id)

View File

@ -46,7 +46,7 @@ export class AlbumScene implements OnInit {
self.albumName = response.name;
self.albumDescription = response.description;
self.albumCovers = this.dataService.getListUrl(response.covers);
}).catch((response) => {
}).catch((error) => {
self.albumDescription = undefined;
self.albumName = '???';
self.albumCovers = undefined;

View File

@ -5,10 +5,10 @@
*/
import { Component, OnInit } from '@angular/core';
import { Album, Track } from 'app/back-api';
import { Album, Artist, NodeSmall, Track } from 'app/back-api';
import { ArtistService, DataService, ArianeService, AlbumService, PlayerService, TrackService } from 'app/service';
import { NodeData } from 'common/model';
import { DataInterface } from 'common/utils';
import { filter } from 'rxjs';
@Component({
@ -43,8 +43,21 @@ export class AlbumsScene implements OnInit {
getArtistsStringCallback(albumId: number): Promise<String[]> {
//console.log(`request all artist for album: {albumId}`)
//return this.trackService.getAlbumIdsOfAnArtist(albumId);
return new Promise((resolve, reject) => { resolve(["a implementer pus tyar"]); });
let self = this;
return new Promise((resolve, reject) => {
self.trackService.getTracksWithAlbumId(albumId)
.then((response: Track[]) => {
const listArtists = DataInterface.extractLimitOneList(response, "artists");
self.artistService.getAll(listArtists)
.then((listArtists: Artist[]) => {
resolve(DataInterface.extractLimitOne(listArtists, "name"));
}).catch((error) => {
resolve([">> ERROR 1 <<"]);
})
}).catch((error) => {
resolve([">> ERROR 2 <<"]);
});
});
}
ngOnInit() {
const self = this;
@ -55,7 +68,7 @@ export class AlbumsScene implements OnInit {
//console.log(`get parameter id: ${ this.idArtist}`);
this.albumService.getOrder()
.then((response: NodeData[]) => {
.then((response: Album[]) => {
//console.log(`>>>> get album : ${JSON.stringify(response)}`)
self.albums = response;
self.albumsSave = [...response];

View File

@ -44,7 +44,6 @@ export class ArtistScene implements OnInit {
// this.idType = parseInt(this.route.snapshot.paramMap.get('typeId'));
this.idArtist = this.arianeService.getArtistId();
let self = this;
this.artistService.get(this.idArtist)
.then((response) => {
self.name = response.name;

View File

@ -63,9 +63,9 @@
<b>Album:</b> {{albumName}}
</div>
}
@if (episode!=null) {
@if (track!=null) {
<div class="episode">
<b>Episode:</b> {{episode}}
<b>Piste:</b> {{track}}
</div>
}
<div class="episode">

View File

@ -5,6 +5,7 @@
*/
import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
import { Track } from 'app/back-api';
import { DataService, TrackService, ArtistService, AlbumService, ArianeService } from 'app/service';
import { HttpWrapperService } from 'common/service';
import { isNullOrUndefined } from 'common/utils';
@ -47,13 +48,12 @@ export class TrackScene implements OnInit {
name: string = '';
description: string = '';
episode: number = undefined;
track: number = undefined;
artists: number[] = undefined;
artistName: string = undefined;
albumId: number = undefined;
albumName: string = undefined;
dataId: string = "";
time: number = undefined;
typeId: number = undefined;
generatedName: string = '';
trackSource: string = '';
@ -134,11 +134,11 @@ export class TrackScene implements OnInit {
this.generatedName = `${this.generatedName}s${this.albumName}-`;
}
}
if (this.episode !== undefined) {
if (this.episode < 10) {
this.generatedName = `${this.generatedName}e0${this.episode}-`;
if (this.track !== undefined) {
if (this.track < 10) {
this.generatedName = `${this.generatedName}e0${this.track}-`;
} else {
this.generatedName = `${this.generatedName}e${this.episode}-`;
this.generatedName = `${this.generatedName}e${this.track}-`;
}
}
this.generatedName = this.generatedName + this.name;
@ -201,7 +201,7 @@ export class TrackScene implements OnInit {
self.haveNext = null;
self.havePrevious = null;
this.trackService.get(this.idTrack)
.then((response) => {
.then((response: Track) => {
console.log(`get response of track : ${JSON.stringify(response, null, 2)}`);
self.error = '';
self.name = response.name;
@ -210,17 +210,13 @@ export class TrackScene implements OnInit {
self.artists = response.artists;
self.albumId = response.albumId;
self.dataId = response.dataId;
self.time = response.time;
self.generatedName = "????????? TODO: ???????" //response.generatedName;
if (self.dataId !== -1) {
self.trackSource = self.httpService.createRESTCall2({
api: `data/${self.dataId}/${self.generatedName}`,
addURLToken: true,
});
if (!isNullOrUndefined(self.dataId)) {
self.trackSource = this.dataService.getUrl(self.dataId);
} else {
self.trackSource = '';
}
self.covers = self.dataService.(response.covers);
self.covers = self.dataService.getListUrl(response.covers);
self.generateName();
if (!isNullOrUndefined(self.artists) && self.artists.length !== 0) {
@ -240,29 +236,28 @@ export class TrackScene implements OnInit {
}).catch((response5) => {
// nothing to do ...
});
self.albumService.getTrack(self.albumId)
.then((response6: any) => {
// console.log("saison property: " + JSON.stringify(response, null, 2));
self.trackService.getTracksWithAlbumId(self.albumId)
.then((response6: Track[]) => {
self.haveNext = null;
self.havePrevious = null;
for (let iii = 0; iii < response6.length; iii++) {
if (isNullOrUndefined(response6[iii].episode)) {
if (isNullOrUndefined(response6[iii].track)) {
continue;
}
if (response6[iii].episode < self.episode) {
if (response6[iii].track < self.track) {
if (self.havePrevious === null) {
self.havePrevious = response6[iii];
} else if (self.havePrevious.episode < response6[iii].episode) {
} else if (self.havePrevious.episode < response6[iii].track) {
self.havePrevious = response6[iii];
}
} else if (response6[iii].episode > self.episode) {
} else if (response6[iii].track > self.track) {
if (self.haveNext === null) {
self.haveNext = response6[iii];
} else if (self.haveNext.episode > response6[iii].episode) {
} else if (self.haveNext.episode > response6[iii].track) {
self.haveNext = response6[iii];
}
}
self.covers.push(self.dataService.getCoverUrl(response6[iii]));
//self.covers.push(self.dataService.getUrl(response6[iii].covers));
}
}).catch((response7: any) => {
@ -275,11 +270,10 @@ export class TrackScene implements OnInit {
self.error = 'Can not get the data';
self.name = '';
self.description = '';
self.episode = undefined;
self.track = undefined;
self.artists = undefined;
self.albumId = undefined;
self.dataId = -1;
self.time = undefined;
self.dataId = "";
self.generatedName = '';
self.trackSource = '';
self.covers = undefined;

View File

@ -5,9 +5,9 @@
*/
import { Component, OnInit } from '@angular/core';
import { Artist, Gender } from 'app/back-api';
import { GenderService, ArtistService, TrackService, AlbumService } from 'app/service';
import { NodeData } from 'common/model';
import { UploadProgress } from 'common/popin/upload-progress/upload-progress';
import { PopInService } from 'common/service';
import { isNullOrUndefined } from 'common/utils';
@ -132,7 +132,7 @@ export class UploadScene implements OnInit {
console.log(`get response22 : ${JSON.stringify(response2, null, 2)}`);
});
this.genderService.getOrder()
.then((response2: NodeData[]) => {
.then((response2: Gender[]) => {
//console.error(`Keep gender : ${ JSON.stringify(response2, null, 2)} ==> ${response2.length}`);
for (let iii = 0; iii < response2.length; iii++) {
self.listGender.push({ value: response2[iii].id, label: response2[iii].name });
@ -186,13 +186,16 @@ export class UploadScene implements OnInit {
return;
}
let self = this;
this.artistService.getAlbum(this.artistId)
.then((response2) => {
for (let iii = 0; iii < response2.length; iii++) {
self.listAlbum.push({ value: response2[iii].id, label: response2[iii].name });
}
}).catch((response2) => {
console.log(`get response22 : ${JSON.stringify(response2, null, 2)}`);
this.trackService.getAlbumIdsOfAnArtist(this.artistId)
.then((listAlbumIds: number[]) => {
this.albumService.getAll(listAlbumIds)
.then((response2) => {
for (let iii = 0; iii < response2.length; iii++) {
self.listAlbum.push({ value: response2[iii].id, label: response2[iii].name });
}
}).catch((response2) => {
console.log(`get response22 : ${JSON.stringify(response2, null, 2)}`);
});
});
}
onArtist(value: any): void {
@ -532,31 +535,33 @@ export class UploadScene implements OnInit {
self.albumId = undefined;
console.error(`ALBUM ==> check album values...`);
// set 1 find the ID of the album:
this.artistService.getAlbum(this.artistId)
.then((response: any[]) => {
console.log(`find album: ${JSON.stringify(response, null, 2)}`);
for (let iii = 0; iii < response.length; iii++) {
// console.log(" - " + JSON.stringify(response[iii]) + 'compare with : ' + JSON.stringify(self.globalAlbum));
if (response[iii].name === `${self.globalAlbum}`) {
self.albumId = response[iii].id;
break;
}
}
if (isNullOrUndefined(self.albumId)) {
return;
}
self.albumService.getTrack(self.albumId)
.then((response2: any[]) => {
self.listFileInBdd = response2;
console.log(`find album: ${JSON.stringify(response, null, 2)}`);
// console.log("find track: " + response2.length);
// for (let iii = 0; iii<response2.length; iii++) {
// console.log(" - " + JSON.stringify(response2[iii]));
// }
self.checkConcordance();
}).catch((response3) => {
self.listFileInBdd = undefined;
});
this.trackService.getAlbumIdsOfAnArtist(this.artistId)
.then((listAlbumIds: number[]) => {
this.artistService.getAll(listAlbumIds)
.then((response: Artist[]) => {
for (let iii = 0; iii < response.length; iii++) {
// console.log(" - " + JSON.stringify(response[iii]) + 'compare with : ' + JSON.stringify(self.globalAlbum));
if (response[iii].name === `${self.globalAlbum}`) {
self.albumId = response[iii].id;
break;
}
}
if (isNullOrUndefined(self.albumId)) {
return;
}
self.trackService.getTracksWithAlbumId(self.albumId)
.then((response2: any[]) => {
self.listFileInBdd = response2;
console.log(`find album: ${JSON.stringify(response, null, 2)}`);
// console.log("find track: " + response2.length);
// for (let iii = 0; iii<response2.length; iii++) {
// console.log(" - " + JSON.stringify(response2[iii]));
// }
self.checkConcordance();
}).catch((response3) => {
self.listFileInBdd = undefined;
});
})
}).catch((response4) => {
self.listFileInBdd = undefined;
});

View File

@ -5,7 +5,6 @@
*/
import { Injectable } from '@angular/core';
import { NodeData } from 'common/model';
import { SessionService } from 'common/service';
import { DataInterface, TypeCheck, isArrayOf, isNumber } from 'common/utils';
@ -26,12 +25,13 @@ export class AlbumService extends GenericDataService<Album> {
}
}
private lambdaGets(): Promise<Album[]> {
const self = this;
return AlbumResource.gets({ restConfig: this.getRestConfig() });
}
constructor(private session: SessionService) {
super();
this.setStore(new DataStore<Album>(this.lambdaGets, "id"));
this.setStore(new DataStore<Album>(() => this.lambdaGets()));
}
insert(data: Album): Promise<Album> {
@ -147,7 +147,7 @@ export class AlbumService extends GenericDataService<Album> {
if (isArrayOf(listArtistId, isNumber)) {
resolve(listArtistId);
} else {
reject("Fail to get the ids (impossible case)");
reject(`Fail to get the ids (impossible case) ${listArtistId}`);
}
}).catch((response) => {
reject(response);

View File

@ -14,8 +14,8 @@ import { ArtistService } from './artist';
import { AlbumService } from './album';
import { TrackService } from './track';
import { environment } from 'environments/environment';
import { NodeData } from 'common/model';
import { isNullOrUndefined, isStringNullOrUndefined, isUndefined } from 'common/utils';
import { NodeSmall } from 'app/back-api';
export class InputOrders {
public genderId: number = undefined;
@ -94,8 +94,7 @@ export class ArianeService {
if (isNullOrUndefined(valueStr) || isStringNullOrUndefined(valueStr)) {
return undefined;
}
return valueStr;
return parseInt(valueStr, 10);
}
updateProperties() {
@ -103,7 +102,6 @@ export class ArianeService {
while (!isNullOrUndefined(elem.firstChild)) {
elem = elem.firstChild;
}
//console.log(`!!!!!!!!!!!!!!!!!!!!!!!!!! ${JSON.stringify(elem.snapshot.paramMap)}`);
let params = elem.snapshot.paramMap;
let segment: string[] = location.pathname.split("/");
while (segment.length > 1 && (segment[0] === "" || segment[0] === environment.applName)) {
@ -197,7 +195,7 @@ export class ArianeService {
}
let self = this;
this.playlistService.get(id)
.then((response: NodeData) => {
.then((response: NodeSmall) => {
self.playlistName = response.name;
self.playlistChange.emit(self.playlistId);
}).catch((response) => {
@ -223,7 +221,7 @@ export class ArianeService {
}
let self = this;
this.artistService.get(id)
.then((response: NodeData) => {
.then((response: NodeSmall) => {
self.artistName = response.name;
self.artistChange.emit(self.artistId);
}).catch((response) => {
@ -249,7 +247,7 @@ export class ArianeService {
}
let self = this;
this.albumService.get(id)
.then((response: NodeData) => {
.then((response: NodeSmall) => {
// self.setArtist(response.artistId);
self.albumName = response.name;
self.albumChange.emit(self.albumId);

View File

@ -6,10 +6,7 @@
import { Injectable } from '@angular/core';
import { HttpWrapperService, BddService, SessionService } from 'common/service';
import { DataInterface, TypeCheck, isArrayOf } from 'common/utils';
import { isNodeData, NodeData } from 'common/model';
import { GenericInterfaceModelDB } from './GenericInterfaceModelDB';
import { SessionService } from 'common/service';
import { Artist, ArtistResource, UUID } from 'app/back-api';
import { RESTConfig } from 'app/back-api/rest-tools';
import { DataStore } from 'common/utils/data-store';
@ -33,7 +30,8 @@ export class ArtistService extends GenericDataService<Artist> {
constructor(private session: SessionService) {
super();
this.setStore(new DataStore<Artist>(this.lambdaGets, "id"));
const self = this;
this.setStore(new DataStore<Artist>(() => self.lambdaGets()));
}
insert(data: Artist): Promise<Artist> {
const self = this;

View File

@ -32,29 +32,32 @@ export class DataService {
*/
getUrl(dataId: string, optionalName?: string): string {
if (isNullOrUndefined(optionalName)) {
return RESTUrl({
const url = RESTUrl({
restModel: {
endPoint: "data/{dataId}",
tokenInUrl: true,
},
restConfig: this.getRestConfig(),
queries: {
params: {
dataId
}
}).replace("http://localhost:19080", "https://atria-soft.org");
});//.replace("http://localhost:19080", "https://atria-soft.org");
console.log(`get URL = ${url}`);
return url;
}
return RESTUrl({
const url = RESTUrl({
restModel: {
endPoint: "data/{dataId}/{optionalName}",
tokenInUrl: true,
},
restConfig: this.getRestConfig(),
queries: {
params: {
dataId,
optionalName
}
}).replace("http://localhost:19080", "https://atria-soft.org");
});//.replace("http://localhost:19080", "https://atria-soft.org");
console.log(`get URL = ${url}`);
return url;
}
/**
* Retrieve the list Cover URL of a specific data id
@ -83,10 +86,10 @@ export class DataService {
tokenInUrl: true,
},
restConfig: this.getRestConfig(),
queries: {
params: {
coverId
} +
}).replace("http://localhost:19080", "https://atria-soft.org");
}
});//.replace("http://localhost:19080", "https://atria-soft.org");
}
/**
* Retrieve the list thumbnail cover URL of a specific data id

View File

@ -6,10 +6,8 @@
import { Injectable } from '@angular/core';
import { HttpWrapperService, BddService, SessionService } from 'common/service';
import { DataInterface, isArrayOf, isNullOrUndefined, TypeCheck } from 'common/utils';
import { isNodeData, NodeData } from 'common/model';
import { GenderResource, Gender, GenderResource, UUID } from 'app/back-api';
import { SessionService } from 'common/service';
import { GenderResource, Gender, UUID } from 'app/back-api';
import { RESTConfig } from 'app/back-api/rest-tools';
import { DataStore } from 'common/utils/data-store';
import { environment } from 'environments/environment';
@ -36,7 +34,8 @@ export class GenderService extends GenericDataService<Gender> {
constructor(private session: SessionService) {
super();
this.setStore(new DataStore<Gender>(this.lambdaGets, "id"));
const self = this;
this.setStore(new DataStore<Gender>(() => this.lambdaGets()));
}
insert(data: Gender): Promise<Gender> {
const self = this;

View File

@ -5,12 +5,9 @@
*/
import { Injectable } from '@angular/core';
import { NodeData } from 'common/model';
import { HttpWrapperService, BddService, SessionService } from 'common/service';
import { DataInterface, TypeCheck } from 'common/utils';
import { GenericInterfaceModelDB } from './GenericInterfaceModelDB';
import { Playlist, PlaylistResource, Playlist, UUID } from 'app/back-api';
import { SessionService } from 'common/service';
import { Playlist, PlaylistResource, UUID } from 'app/back-api';
import { RESTConfig } from 'app/back-api/rest-tools';
import { DataStore } from 'common/utils/data-store';
import { environment } from 'environments/environment';
@ -31,7 +28,8 @@ export class PlaylistService extends GenericDataService<Playlist> {
constructor(private session: SessionService) {
super();
this.setStore(new DataStore<Playlist>(this.lambdaGets, "id"));
const self = this;
this.setStore(new DataStore<Playlist>(() => this.lambdaGets()));
}
getSubArtist(id: bigint, select: Array<string> = []): any {

View File

@ -30,7 +30,8 @@ export class TrackService extends GenericDataService<Track> {
constructor(private session: SessionService) {
super();
this.setStore(new DataStore<Track>(this.lambdaGets, "id"));
const self = this;
this.setStore(new DataStore<Track>(() => this.lambdaGets()));
}
/*
insert(data: Track): Promise<Track> {
@ -218,48 +219,32 @@ export class TrackService extends GenericDataService<Track> {
countTracksOfAnArtist(artistId: number): Promise<number> {
let self = this;
return new Promise((resolve, reject) => {
self.gets()
self.getTracksOfAnArtist(artistId)
.then((response: Track[]) => {
let data = DataTools.getsWhere(response, [
{
check: TypeCheck.CONTAINS,
key: 'artists',
value: artistId,
},
]);
resolve(data.length);
}).catch((response) => {
reject(response);
resolve(response.length);
}).catch((error) => {
reject(error);
});
});
}
/**
* Get all the album of a specific artist
* @param idArtist - ID of the artist
* @param artistId - ID of the artist
* @returns the required List.
*/
getAlbumIdsOfAnArtist(idArtist: number): Promise<number[]> {
getAlbumIdsOfAnArtist(artistId: number): Promise<number[]> {
let self = this;
return new Promise((resolve, reject) => {
self.gets()
self.getTracksOfAnArtist(artistId)
.then((response: Track[]) => {
//console.log(" <<<========================================>>> " + idArtist);
let data = DataTools.getsWhere(response,
[
{
check: TypeCheck.CONTAINS, //< this is for array containing
key: 'artists',
value: idArtist,
},
], ['id']);
//console.log("==> get all tracks of the artist: " + JSON.stringify(data, null, 2));
// extract a single time all value "id" in an array
const listAlbumId = DataInterface.extractLimitOne(data, "albumId");
const listAlbumId = DataInterface.extractLimitOne(response, "albumId");
if (isArrayOf(listAlbumId, isNumber)) {
resolve(listAlbumId);
} else {
reject("Fail to get the ids (impossible case)");
reject(`Fail to get the ids (impossible case) ${listAlbumId}`);
}
}).catch((response) => {
reject(response);

@ -1 +1 @@
Subproject commit 147a955b195eb7c90e445d404f043d9a363087ca
Subproject commit ae86abe8ca367b91d36c48683fda8cfd82f3ec48