From 263a4ae4c031fc5536c4a6c2b7180b759875338c Mon Sep 17 00:00:00 2001 From: Edouard DUPIN Date: Wed, 26 Feb 2025 00:09:58 +0100 Subject: [PATCH] [FEAT] update upload of data --- .../org/kar/karideo/api/MediaResource.java | 64 ++-- .../org/kar/karideo/api/SeriesResource.java | 3 + back/src/org/kar/karideo/model/Media.java | 1 + front/src/back-api/api/media-resource.ts | 9 +- front/src/back-api/model/media.ts | 4 +- front/src/components/Cover.tsx | 3 +- front/src/components/form/FormSelect.tsx | 4 + .../components/popup/PopUpUploadProgress.tsx | 10 +- front/src/components/select/SelectSingle.tsx | 5 + front/src/scene/AppRoutes.tsx | 2 +- front/src/scene/home/AddPage.tsx | 279 ++++++++---------- .../{ => sso}/series/SeriesDetailPage.tsx | 0 .../src/scene/{ => sso}/series/SeriesPage.tsx | 0 .../scene/{ => sso}/series/SeriesRoutes.tsx | 0 .../series/SeriesSeasonDetailPage.tsx | 0 front/src/scene/type/TypesPage.tsx | 4 +- front/src/service/Series.ts | 31 +- front/src/service/ServiceContext.tsx | 3 + 18 files changed, 237 insertions(+), 185 deletions(-) rename front/src/scene/{ => sso}/series/SeriesDetailPage.tsx (100%) rename front/src/scene/{ => sso}/series/SeriesPage.tsx (100%) rename front/src/scene/{ => sso}/series/SeriesRoutes.tsx (100%) rename front/src/scene/{ => sso}/series/SeriesSeasonDetailPage.tsx (100%) diff --git a/back/src/org/kar/karideo/api/MediaResource.java b/back/src/org/kar/karideo/api/MediaResource.java index 8a4b866..15ea728 100644 --- a/back/src/org/kar/karideo/api/MediaResource.java +++ b/back/src/org/kar/karideo/api/MediaResource.java @@ -78,6 +78,9 @@ public class MediaResource { if (data.contentEquals("null")) { return null; } + if (data.contentEquals("undefined")) { + return null; + } return data; } @@ -86,34 +89,43 @@ public class MediaResource { @Consumes({ MediaType.MULTIPART_FORM_DATA }) @Operation(description = "Create a new Media", tags = "GLOBAL") @TypeScriptProgress - public Media uploadFile( // - @FormDataParam("fileName") String fileName, // - @FormDataParam("universe") String universe, // - @FormDataParam("series") String series, // - // @FormDataParam("seriesId") String seriesId, // Not used ... - @FormDataParam("season") String season, // - @FormDataParam("episode") String episode, // - @FormDataParam("title") String title, // + public Media uploadMedia( // + // @AsyncType(Long.class) @FormDataParam("universeId") String universeId, // + // @AsyncType(Long.class) @FormDataParam("typeId") String typeId, // + // @AsyncType(Long.class) @FormDataParam("seriesId") String seriesId, // + // @AsyncType(Long.class) @FormDataParam("season") String season, // value of the season ==> local add if needed + // @AsyncType(Long.class) @FormDataParam("episode") String episode, // value of the season ==> local add if needed + @FormDataParam("universeId") String universeId, // @FormDataParam("typeId") String typeId, // + @FormDataParam("seriesId") String seriesId, // + @FormDataParam("season") String season, // value of the season ==> local add if needed + @FormDataParam("episode") String episode, // value of the season ==> local add if needed + @FormDataParam("title") String title, // @FormDataParam("file") final InputStream fileInputStream, // @FormDataParam("file") final FormDataContentDisposition fileMetaData // ) throws FailException { try (DBAccess db = DBAccess.createInterface()) { // correct input string stream : - fileName = multipartCorrection(fileName); - universe = multipartCorrection(universe); - series = multipartCorrection(series); + final String fileName = multipartCorrection(fileMetaData.getFileName()); + universeId = multipartCorrection(universeId); + final Long universeIdLong = universeId != null ? Long.parseLong(universeId) : null; + typeId = multipartCorrection(typeId); + final Long typeIdLong = typeId != null ? Long.parseLong(typeId) : null; + seriesId = multipartCorrection(seriesId); + final Long seriesIdLong = seriesId != null ? Long.parseLong(seriesId) : null; season = multipartCorrection(season); + final Long seasonLong = season != null ? Long.parseLong(season) : null; episode = multipartCorrection(episode); title = multipartCorrection(title); - typeId = multipartCorrection(typeId); + + // todo: check if all remotes Id exist ... // public NodeSmall uploadFile(final FormDataMultiPart form) { LOGGER.info("Upload media file: {}", fileMetaData); LOGGER.info(" - fileName: {}", fileName); - LOGGER.info(" - universe: {}", universe); - LOGGER.info(" - series: {}", series); - LOGGER.info(" - season: {}", season); + LOGGER.info(" - universe: {}", universeIdLong); + LOGGER.info(" - series: {}", seriesIdLong); + LOGGER.info(" - season: {}", seasonLong); LOGGER.info(" - episode: {}", episode); LOGGER.info(" - title: {}", title); LOGGER.info(" - type: {}", typeId); @@ -149,26 +161,32 @@ public class MediaResource { // Fist step: retieve all the Id of each parents:... LOGGER.info("Find typeNode"); // check if id of type exist: - final Type typeNode = TypeResource.getId(Long.parseLong(typeId)); + final Type typeNode = TypeResource.getId(typeIdLong); if (typeNode == null) { DataResource.removeTemporaryFile(tmpUID); throw new InputException("typeId", "TypeId does not exist ..."); } - LOGGER.info(" ==> {}", typeNode); - LOGGER.info("Find seriesNode"); - // get uid of group: + // check if id of type exist: Series seriesNode = null; - if (series != null) { - seriesNode = SeriesResource.getOrCreate(series, typeNode.id); + if (seriesIdLong != null) { + seriesNode = SeriesResource.getId(seriesIdLong); + if (seriesNode == null) { + DataResource.removeTemporaryFile(tmpUID); + throw new InputException("seriesId", "seriesId does not exist ..."); + } + if (seriesNode.parentId != typeNode.id) { + DataResource.removeTemporaryFile(tmpUID); + throw new InputException("seriesId", "seriesId object have not the correct parent..."); + } } LOGGER.info(" ==> {}", seriesNode); LOGGER.info("Find seasonNode"); // get uid of season: Season seasonNode = null; - if (seriesNode == null && season != null) { + if (seriesNode == null && seasonLong != null) { DataResource.removeTemporaryFile(tmpUID); - throw new InputException("season", "Season is set but no seraies is set !!"); + throw new InputException("season", "Season is set but no series is set !!"); } if (season != null) { seasonNode = SeasonResource.getOrCreate(season, seriesNode.id); diff --git a/back/src/org/kar/karideo/api/SeriesResource.java b/back/src/org/kar/karideo/api/SeriesResource.java index e592dde..53ee895 100644 --- a/back/src/org/kar/karideo/api/SeriesResource.java +++ b/back/src/org/kar/karideo/api/SeriesResource.java @@ -52,6 +52,9 @@ public class SeriesResource { return DataAccess.get(Series.class, id); } + public static Series getId(final Long id) throws Exception { + return DataAccess.get(Series.class, id); + } /* ============================================================================= ADMIN SECTION: ============================================================================= */ @POST diff --git a/back/src/org/kar/karideo/model/Media.java b/back/src/org/kar/karideo/model/Media.java index 60acf75..c821a6a 100644 --- a/back/src/org/kar/karideo/model/Media.java +++ b/back/src/org/kar/karideo/model/Media.java @@ -34,6 +34,7 @@ public class Media extends GenericDataSoftDelete { public ObjectId dataId; @ManyToOne(fetch = FetchType.LAZY, targetEntity = Data.class) @Column(nullable = false) + @Nullable public UUID dataIdOld; @Schema(description = "Type of the media") @ManyToOne(fetch = FetchType.LAZY, targetEntity = Type.class) diff --git a/front/src/back-api/api/media-resource.ts b/front/src/back-api/api/media-resource.ts index fd0e9b2..a4dbcc5 100644 --- a/front/src/back-api/api/media-resource.ts +++ b/front/src/back-api/api/media-resource.ts @@ -181,21 +181,20 @@ export namespace MediaResource { /** * Create a new Media */ - export function uploadFile({ + export function uploadMedia({ restConfig, data, callbacks, }: { restConfig: RESTConfig, data: { - fileName: string, file: File, - series: string, - universe: string, + universeId: string, season: string, - episode: string, typeId: string, + episode: string, title: string, + seriesId: string, }, callbacks?: RESTCallbacks, }): Promise { diff --git a/front/src/back-api/model/media.ts b/front/src/back-api/model/media.ts index c511180..6bacd0b 100644 --- a/front/src/back-api/model/media.ts +++ b/front/src/back-api/model/media.ts @@ -22,7 +22,7 @@ export const ZodMedia = ZodGenericDataSoftDelete.extend({ * Foreign Key Id of the data */ dataId: ZodObjectId, - dataIdOld: ZodUUID, + dataIdOld: ZodUUID.optional(), /** * Type of the media */ @@ -79,7 +79,7 @@ export const ZodMediaWrite = ZodGenericDataSoftDeleteWrite.extend({ * Foreign Key Id of the data */ dataId: ZodObjectId.optional(), - dataIdOld: ZodUUID.optional(), + dataIdOld: ZodUUID.nullable().optional(), /** * Type of the media */ diff --git a/front/src/components/Cover.tsx b/front/src/components/Cover.tsx index 93dcb41..3ac4b88 100644 --- a/front/src/components/Cover.tsx +++ b/front/src/components/Cover.tsx @@ -69,7 +69,8 @@ export const Covers = ({ loading="lazy" src={url} maxWidth={size} - boxSize={size} /*{...rest}*/ + maxHeight={size} + boxSize={size} onClick={onClick} /> ); diff --git a/front/src/components/form/FormSelect.tsx b/front/src/components/form/FormSelect.tsx index 818ee08..e5f97ef 100644 --- a/front/src/components/form/FormSelect.tsx +++ b/front/src/components/form/FormSelect.tsx @@ -16,6 +16,8 @@ export type FormSelectProps = { placeholder?: string; // Form: Specify if the element is required or not isRequired?: boolean; + // is locked for edition + disabled?: boolean; // List of object options options: object[]; // in the option specify the value Key @@ -35,6 +37,7 @@ export const FormSelect = ({ options, keyInputKey = 'id', keyInputValue = 'name', + disabled = false, suggestion, addNewItem, ...rest @@ -60,6 +63,7 @@ export const FormSelect = ({ keyValue={keyInputValue} onCreate={onCreate} suggestion={suggestion} + disabled={disabled} /> ); diff --git a/front/src/components/popup/PopUpUploadProgress.tsx b/front/src/components/popup/PopUpUploadProgress.tsx index 004a5eb..619997b 100644 --- a/front/src/components/popup/PopUpUploadProgress.tsx +++ b/front/src/components/popup/PopUpUploadProgress.tsx @@ -73,7 +73,13 @@ export const PopUpUploadProgress = ({ animated max={totalSize} height="24px" - /> + width="full" + colorPalette="blue" + > + + + + {currentSize.toLocaleString('fr-FR')} Bytes @@ -81,7 +87,7 @@ export const PopUpUploadProgress = ({ {error && ( - + {error} )} diff --git a/front/src/components/select/SelectSingle.tsx b/front/src/components/select/SelectSingle.tsx index 24bbed6..31c6efb 100644 --- a/front/src/components/select/SelectSingle.tsx +++ b/front/src/components/select/SelectSingle.tsx @@ -17,6 +17,8 @@ export type SelectSingleProps = { onChange?: (value: number | string | undefined) => void; keyKey?: string; keyValue?: string; + // is locked for edition + disabled?: boolean; ref?: RefObject; // if set add capability to add the search item onCreate?: (data: string) => void; @@ -31,6 +33,7 @@ export const SelectSingle = ({ ref, keyKey = 'id', keyValue = keyKey, + disabled = false, suggestion, onCreate, }: SelectSingleProps) => { @@ -107,6 +110,7 @@ export const SelectSingle = ({ onChangeInput(e.target.value)} onFocus={() => setShowList(true)} @@ -124,6 +128,7 @@ export const SelectSingle = ({ />