From b86851444a8e6bd4c47229b25ac896b1672bd73d Mon Sep 17 00:00:00 2001 From: stefano-lacorazza <112132737+stefano-lacorazza@users.noreply.github.com> Date: Mon, 23 Sep 2024 06:02:25 -0500 Subject: [PATCH 01/20] OV-377: + add preview page with video player --- .../bundles/common/enums/app-route.enum.ts | 1 + .../src/bundles/preview/pages/preview.tsx | 21 +++++++++++++++++++ .../bundles/preview/pages/styles.module.css | 6 ++++++ frontend/src/routes/routes.tsx | 7 +++++++ 4 files changed, 35 insertions(+) create mode 100644 frontend/src/bundles/preview/pages/preview.tsx create mode 100644 frontend/src/bundles/preview/pages/styles.module.css diff --git a/frontend/src/bundles/common/enums/app-route.enum.ts b/frontend/src/bundles/common/enums/app-route.enum.ts index d6526128a..158df0e85 100644 --- a/frontend/src/bundles/common/enums/app-route.enum.ts +++ b/frontend/src/bundles/common/enums/app-route.enum.ts @@ -6,6 +6,7 @@ const AppRoute = { MY_AVATAR: '/my-avatar', ANY: '*', CREATE_AVATAR: '/create-avatar', + PREVIEW: '/preview', } as const; export { AppRoute }; diff --git a/frontend/src/bundles/preview/pages/preview.tsx b/frontend/src/bundles/preview/pages/preview.tsx new file mode 100644 index 000000000..2384865a6 --- /dev/null +++ b/frontend/src/bundles/preview/pages/preview.tsx @@ -0,0 +1,21 @@ +import { Box, Header , VideoPlayer } from '~/bundles/common/components/components.js'; + +import styles from './styles.module.css'; + +const Preview: React.FC = () => { + + return ( + +
+ + + ); +}; + +export { Preview }; diff --git a/frontend/src/bundles/preview/pages/styles.module.css b/frontend/src/bundles/preview/pages/styles.module.css new file mode 100644 index 000000000..7317d0311 --- /dev/null +++ b/frontend/src/bundles/preview/pages/styles.module.css @@ -0,0 +1,6 @@ +.video-player { + height: 1000px; + width: 1000px; + position: relative; + background-color: var(--chakra-colors-gray-200); +} diff --git a/frontend/src/routes/routes.tsx b/frontend/src/routes/routes.tsx index 1a6e2e18d..32e823ea9 100644 --- a/frontend/src/routes/routes.tsx +++ b/frontend/src/routes/routes.tsx @@ -6,6 +6,7 @@ import { NotFound } from '~/bundles/common/pages/not-found/not-found.js'; import { CreateAvatar } from '~/bundles/create-avatar/pages/create-avatar.js'; import { Home } from '~/bundles/home/pages/home.js'; import { MyAvatar } from '~/bundles/my-avatar/pages/my-avatar.js'; +import { Preview } from '~/bundles/preview/pages/preview.js'; import { Studio } from '~/bundles/studio/pages/studio.js'; const routes = [ @@ -57,6 +58,12 @@ const routes = [ path: AppRoute.ANY, element: , }, + { + path: AppRoute.PREVIEW, + element: ( + + ), + } ], }, ]; From 49af338d7e8206c4f3d4948e7b8fecde40e51c17 Mon Sep 17 00:00:00 2001 From: stefano-lacorazza <112132737+stefano-lacorazza@users.noreply.github.com> Date: Mon, 23 Sep 2024 08:30:02 -0500 Subject: [PATCH 02/20] OV-377: + add copy url button to homepage --- .../src/bundles/common/api/video-api/videos-api.ts | 14 ++++++++++++++ .../common/icons/helper/icon-conversion.helper.ts | 3 +++ frontend/src/bundles/common/icons/icon-name.ts | 2 ++ .../home/components/video-card/video-card.tsx | 11 +++++++++++ frontend/src/bundles/home/store/actions.ts | 11 ++++++++++- frontend/src/bundles/home/store/home.ts | 3 ++- 6 files changed, 42 insertions(+), 2 deletions(-) diff --git a/frontend/src/bundles/common/api/video-api/videos-api.ts b/frontend/src/bundles/common/api/video-api/videos-api.ts index 3c8448a44..94d485e1c 100644 --- a/frontend/src/bundles/common/api/video-api/videos-api.ts +++ b/frontend/src/bundles/common/api/video-api/videos-api.ts @@ -81,6 +81,20 @@ class VideosApi extends BaseHttpApi { await response.json(); } + + public async createVideoUrl(id: string): Promise { + const response = await this.load( + this.getFullEndpoint(`${VideosApiPath.ROOT}${id}`, {}), + { + method: HTTPMethod.GET, + contentType: ContentType.JSON, + payload: JSON.stringify({}), + hasAuth: true, + }, + ); + //TODO: Response type should be changed + await response.json(); + } } export { VideosApi }; diff --git a/frontend/src/bundles/common/icons/helper/icon-conversion.helper.ts b/frontend/src/bundles/common/icons/helper/icon-conversion.helper.ts index 8b24d8759..a7442f954 100644 --- a/frontend/src/bundles/common/icons/helper/icon-conversion.helper.ts +++ b/frontend/src/bundles/common/icons/helper/icon-conversion.helper.ts @@ -3,6 +3,7 @@ import { faCircleUser, faCloudArrowDown, faCloudArrowUp, + faCopy, faEllipsisVertical, faFileLines, faFont, @@ -41,12 +42,14 @@ const CloudArrowDown = convertIcon(faCloudArrowDown); const VolumeHigh = convertIcon(faVolumeHigh); const VolumeOff = convertIcon(faVolumeOff); const Stop = convertIcon(faStop); +const Copy = convertIcon(faCopy); export { BackwardStep, CircleUser, CloudArrowDown, CloudArrowUp, + Copy, EllipsisVertical, FileLines, Font, diff --git a/frontend/src/bundles/common/icons/icon-name.ts b/frontend/src/bundles/common/icons/icon-name.ts index 953788739..3a047ee89 100644 --- a/frontend/src/bundles/common/icons/icon-name.ts +++ b/frontend/src/bundles/common/icons/icon-name.ts @@ -18,6 +18,7 @@ import { CircleUser, CloudArrowDown, CloudArrowUp, + Copy, EllipsisVertical, FileLines, Font, @@ -69,6 +70,7 @@ const IconName = { LOGO_TEXT: LogoText, DELETE: DeleteIcon, WARNING: WarningIcon, + COPY: Copy, } as const; export { IconName }; diff --git a/frontend/src/bundles/home/components/video-card/video-card.tsx b/frontend/src/bundles/home/components/video-card/video-card.tsx index 5e23438de..2d3de7d3c 100644 --- a/frontend/src/bundles/home/components/video-card/video-card.tsx +++ b/frontend/src/bundles/home/components/video-card/video-card.tsx @@ -94,6 +94,9 @@ const VideoCard: React.FC = ({ handleWarningModalClose(); }, [dispatch, handleWarningModalClose, id]); + const handleCopyButtonClick = useCallback(() => { + void dispatch(homeActions.createVideoUrl(id)); + }, []); return ( = ({ Delete + } + onClick={handleCopyButtonClick} + > + + Copy video URL + + diff --git a/frontend/src/bundles/home/store/actions.ts b/frontend/src/bundles/home/store/actions.ts index 56bd864c7..430921232 100644 --- a/frontend/src/bundles/home/store/actions.ts +++ b/frontend/src/bundles/home/store/actions.ts @@ -24,4 +24,13 @@ const deleteVideo = createAsyncThunk, string, AsyncThunkConfig>( }, ); -export { deleteVideo, loadUserVideos }; +const createVideoUrl = createAsyncThunk, string, AsyncThunkConfig>( + `${sliceName}/create-video-url`, + (payload, { extra }) => { + const { videosApi } = extra; + + return videosApi.deleteVideo(payload); + }, +); + +export { createVideoUrl, deleteVideo, loadUserVideos }; diff --git a/frontend/src/bundles/home/store/home.ts b/frontend/src/bundles/home/store/home.ts index 9b26c21f9..c4b6247ee 100644 --- a/frontend/src/bundles/home/store/home.ts +++ b/frontend/src/bundles/home/store/home.ts @@ -1,10 +1,11 @@ -import { deleteVideo, loadUserVideos } from './actions.js'; +import { createVideoUrl, deleteVideo, loadUserVideos, } from './actions.js'; import { actions } from './slice.js'; const allActions = { ...actions, deleteVideo, loadUserVideos, + createVideoUrl, }; export { reducer } from './slice.js'; From 06e0c10274289185100908b386c6f15898e1e61c Mon Sep 17 00:00:00 2001 From: stefano-lacorazza <112132737+stefano-lacorazza@users.noreply.github.com> Date: Mon, 23 Sep 2024 21:29:03 -0500 Subject: [PATCH 03/20] OV-377: + create JWT with video id and return it to frontend --- .../src/bundles/videos/video.controller.ts | 22 +++++++++++++++ backend/src/bundles/videos/video.service.ts | 6 ++++- .../common/services/token/token.services.ts | 12 +++++++++ .../common/api/video-api/videos-api.ts | 27 ++++++++++--------- .../home/components/video-card/video-card.tsx | 14 ++++++++-- .../bundles/home/helpers/create-url-token.ts | 7 +++++ frontend/src/bundles/home/helpers/helpers.ts | 1 + frontend/src/bundles/home/store/actions.ts | 5 ++-- .../videos/enums/videos-api-path.enum.ts | 1 + 9 files changed, 77 insertions(+), 18 deletions(-) create mode 100644 frontend/src/bundles/home/helpers/create-url-token.ts create mode 100644 frontend/src/bundles/home/helpers/helpers.ts diff --git a/backend/src/bundles/videos/video.controller.ts b/backend/src/bundles/videos/video.controller.ts index 2ec2314d8..93cb6f5d8 100644 --- a/backend/src/bundles/videos/video.controller.ts +++ b/backend/src/bundles/videos/video.controller.ts @@ -109,6 +109,17 @@ class VideoController extends BaseController { }>, ), }); + this.addRoute({ + path: `${VideosApiPath.ID}/share`, + method: HTTPMethod.GET, + handler: (options) => { + return this.createVideoIdJWT( + options as ApiHandlerOptions<{ + params: VideoGetOneRequestDto; + }>, + ); + }, + }); } /** @@ -186,6 +197,17 @@ class VideoController extends BaseController { }; } + private async createVideoIdJWT( + options: ApiHandlerOptions<{ + params: VideoGetOneRequestDto; + }>, + ): Promise { + return { + status: HTTPCode.OK, + payload: await this.videoService.getVideoIdToken(options.params.id), + }; + } + /** * @swagger * /videos/: diff --git a/backend/src/bundles/videos/video.service.ts b/backend/src/bundles/videos/video.service.ts index fad0bacb5..8b17eeab6 100644 --- a/backend/src/bundles/videos/video.service.ts +++ b/backend/src/bundles/videos/video.service.ts @@ -2,6 +2,7 @@ import { VideoEntity } from '~/bundles/videos/video.entity.js'; import { type VideoRepository } from '~/bundles/videos/video.repository.js'; import { HTTPCode, HttpError } from '~/common/http/http.js'; import { type FileService } from '~/common/services/file/file.service.js'; +import { tokenService } from '~/common/services/services.js'; import { type Service } from '~/common/types/types.js'; import { VideoValidationMessage } from './enums/enums.js'; @@ -15,7 +16,6 @@ import { class VideoService implements Service { private videoRepository: VideoRepository; private fileService: FileService; - public constructor( videoRepository: VideoRepository, fileService: FileService, @@ -100,6 +100,10 @@ class VideoService implements Service { return isVideoDeleted; } + + public async getVideoIdToken(id: string): Promise { + return await tokenService.createVideoIdToken(id); + } } export { VideoService }; diff --git a/backend/src/common/services/token/token.services.ts b/backend/src/common/services/token/token.services.ts index 3bef998a0..b0df2bb4c 100644 --- a/backend/src/common/services/token/token.services.ts +++ b/backend/src/common/services/token/token.services.ts @@ -17,6 +17,13 @@ class TokenService { .sign(this.secretKey); } + public async createVideoIdToken(videoId: string): Promise { + const jwt = await new SignJWT({ videoId }) + .setProtectedHeader({ alg: 'HS256' }) + .sign(this.secretKey); + return jwt.replaceAll('.', '-'); + } + public async verifyToken(token: string): Promise { try { const { payload } = await jwtVerify(token, this.secretKey); @@ -30,6 +37,11 @@ class TokenService { const payload = await this.verifyToken(token); return (payload?.['userId'] as string) || null; } + + public async getVideoIdFromToken(token: string): Promise { + const payload = await this.verifyToken(token); + return (payload?.['videoId'] as string) || null; + } } export { TokenService }; diff --git a/frontend/src/bundles/common/api/video-api/videos-api.ts b/frontend/src/bundles/common/api/video-api/videos-api.ts index 94d485e1c..966eaafc4 100644 --- a/frontend/src/bundles/common/api/video-api/videos-api.ts +++ b/frontend/src/bundles/common/api/video-api/videos-api.ts @@ -82,18 +82,21 @@ class VideosApi extends BaseHttpApi { await response.json(); } - public async createVideoUrl(id: string): Promise { - const response = await this.load( - this.getFullEndpoint(`${VideosApiPath.ROOT}${id}`, {}), - { - method: HTTPMethod.GET, - contentType: ContentType.JSON, - payload: JSON.stringify({}), - hasAuth: true, - }, - ); - //TODO: Response type should be changed - await response.json(); + public async getVideoIdJWT(id: string): Promise { + + const response = await this.load( + this.getFullEndpoint(`${VideosApiPath.ROOT}${id}/share`, {}), + { + method: HTTPMethod.GET, + contentType: ContentType.JSON, + hasAuth: true, + }, + ); + + if (!response.ok) { + throw new Error(`Failed to get video ID JWT: ${response.statusText}`); + } + return await response.text(); } } diff --git a/frontend/src/bundles/home/components/video-card/video-card.tsx b/frontend/src/bundles/home/components/video-card/video-card.tsx index 2d3de7d3c..d9a02052b 100644 --- a/frontend/src/bundles/home/components/video-card/video-card.tsx +++ b/frontend/src/bundles/home/components/video-card/video-card.tsx @@ -24,6 +24,7 @@ import { useState, } from '~/bundles/common/hooks/hooks.js'; import { IconName, IconSize } from '~/bundles/common/icons/icons.js'; +import { createVideoUrl } from '~/bundles/home/helpers/helpers.js'; import { actions as homeActions } from '~/bundles/home/store/home.js'; import { PlayerModal } from '../player-modal/player-modal.js'; @@ -95,8 +96,17 @@ const VideoCard: React.FC = ({ }, [dispatch, handleWarningModalClose, id]); const handleCopyButtonClick = useCallback(() => { - void dispatch(homeActions.createVideoUrl(id)); - }, []); + dispatch(homeActions.createVideoUrl(id)) + .unwrap() + .then(async (jwt) => { + const token = await jwt; + createVideoUrl(token); + }) + .catch((error) => { + alert(error.message); + }); + }, [dispatch, id]); + return ( { + const baseUrl = 'http://localhost:3000'; + return `${baseUrl}/preview/${jwtToken}`; +}; + +export { createVideoUrl }; \ No newline at end of file diff --git a/frontend/src/bundles/home/helpers/helpers.ts b/frontend/src/bundles/home/helpers/helpers.ts new file mode 100644 index 000000000..51239f491 --- /dev/null +++ b/frontend/src/bundles/home/helpers/helpers.ts @@ -0,0 +1 @@ +export { createVideoUrl } from './create-url-token.js'; \ No newline at end of file diff --git a/frontend/src/bundles/home/store/actions.ts b/frontend/src/bundles/home/store/actions.ts index 430921232..05797904d 100644 --- a/frontend/src/bundles/home/store/actions.ts +++ b/frontend/src/bundles/home/store/actions.ts @@ -24,12 +24,11 @@ const deleteVideo = createAsyncThunk, string, AsyncThunkConfig>( }, ); -const createVideoUrl = createAsyncThunk, string, AsyncThunkConfig>( +const createVideoUrl = createAsyncThunk, string, AsyncThunkConfig>( `${sliceName}/create-video-url`, (payload, { extra }) => { const { videosApi } = extra; - - return videosApi.deleteVideo(payload); + return videosApi.getVideoIdJWT(payload); }, ); diff --git a/shared/src/bundles/videos/enums/videos-api-path.enum.ts b/shared/src/bundles/videos/enums/videos-api-path.enum.ts index 82abbdcfa..0832c0367 100644 --- a/shared/src/bundles/videos/enums/videos-api-path.enum.ts +++ b/shared/src/bundles/videos/enums/videos-api-path.enum.ts @@ -1,6 +1,7 @@ const VideosApiPath = { ROOT: '/', ID: '/:id', + SHARE: '/share', } as const; export { VideosApiPath }; From 945fac9d0e6c14de9a07becbb91443a8b54faaf9 Mon Sep 17 00:00:00 2001 From: stefano-lacorazza <112132737+stefano-lacorazza@users.noreply.github.com> Date: Tue, 24 Sep 2024 03:39:47 -0500 Subject: [PATCH 04/20] OV-377: + copy url to clipboard --- .../src/bundles/home/components/video-card/video-card.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/frontend/src/bundles/home/components/video-card/video-card.tsx b/frontend/src/bundles/home/components/video-card/video-card.tsx index d9a02052b..6c5860d6f 100644 --- a/frontend/src/bundles/home/components/video-card/video-card.tsx +++ b/frontend/src/bundles/home/components/video-card/video-card.tsx @@ -30,6 +30,7 @@ import { actions as homeActions } from '~/bundles/home/store/home.js'; import { PlayerModal } from '../player-modal/player-modal.js'; import { DeleteWarning } from './components/delete-warning.js'; import styles from './styles.module.css'; +import { notificationService } from '~/bundles/common/services/services.js'; type Properties = { id: string; @@ -100,11 +101,14 @@ const VideoCard: React.FC = ({ .unwrap() .then(async (jwt) => { const token = await jwt; - createVideoUrl(token); + const url = createVideoUrl(token); + await navigator.clipboard.writeText(createVideoUrl(url)); + }) .catch((error) => { - alert(error.message); + throw new Error(`Failed to get video ID JWT: ${error}`); }); + }, [dispatch, id]); return ( From c19a3fafcd860899205b06f68d16a1682cd1fe8c Mon Sep 17 00:00:00 2001 From: stefano-lacorazza <112132737+stefano-lacorazza@users.noreply.github.com> Date: Tue, 24 Sep 2024 04:55:42 -0500 Subject: [PATCH 05/20] OV-377: + create dynamic preview url --- .../src/bundles/videos/video.controller.ts | 26 +++++++++++++++++++ .../common/api/video-api/videos-api.ts | 16 ++++++++++++ .../home/components/video-card/video-card.tsx | 8 +++--- frontend/src/bundles/home/store/actions.ts | 4 +-- frontend/src/bundles/home/store/home.ts | 4 +-- .../preview/components/preview-wrapper.tsx | 10 +++++++ .../src/bundles/preview/pages/preview.tsx | 7 ++++- frontend/src/routes/routes.tsx | 6 ++--- 8 files changed, 69 insertions(+), 12 deletions(-) create mode 100644 frontend/src/bundles/preview/components/preview-wrapper.tsx diff --git a/backend/src/bundles/videos/video.controller.ts b/backend/src/bundles/videos/video.controller.ts index 93cb6f5d8..0aaa10dd5 100644 --- a/backend/src/bundles/videos/video.controller.ts +++ b/backend/src/bundles/videos/video.controller.ts @@ -197,6 +197,32 @@ class VideoController extends BaseController { }; } + /** + * @swagger + * /videos/{id}/share: + * get: + * parameters: + * - in: path + * name: id + * required: true + * schema: + * type: string + * format: uuid + * description: The video id + * description: Create a JWT for the video id + * security: + * - bearerAuth: [] + * responses: + * 200: + * description: Successful operation + * content: + * application/json: + * schema: + * type: object + * properties: + * token: + * type: string + */ private async createVideoIdJWT( options: ApiHandlerOptions<{ params: VideoGetOneRequestDto; diff --git a/frontend/src/bundles/common/api/video-api/videos-api.ts b/frontend/src/bundles/common/api/video-api/videos-api.ts index 966eaafc4..74d7f8892 100644 --- a/frontend/src/bundles/common/api/video-api/videos-api.ts +++ b/frontend/src/bundles/common/api/video-api/videos-api.ts @@ -68,6 +68,22 @@ class VideosApi extends BaseHttpApi { return await response.json(); } + public async getVideo( + payload: UpdateVideoRequestDto, + id: string, + ): Promise { + const response = await this.load( + this.getFullEndpoint(VideosApiPath.ID, { id }), + { + method: HTTPMethod.GET, + contentType: ContentType.JSON, + hasAuth: true, + }, + ); + + return await response.json(); + } + public async deleteVideo(id: string): Promise { const response = await this.load( this.getFullEndpoint(`${VideosApiPath.ROOT}${id}`, {}), diff --git a/frontend/src/bundles/home/components/video-card/video-card.tsx b/frontend/src/bundles/home/components/video-card/video-card.tsx index 6c5860d6f..41a094e88 100644 --- a/frontend/src/bundles/home/components/video-card/video-card.tsx +++ b/frontend/src/bundles/home/components/video-card/video-card.tsx @@ -24,13 +24,13 @@ import { useState, } from '~/bundles/common/hooks/hooks.js'; import { IconName, IconSize } from '~/bundles/common/icons/icons.js'; +import { notificationService } from '~/bundles/common/services/services.js'; import { createVideoUrl } from '~/bundles/home/helpers/helpers.js'; import { actions as homeActions } from '~/bundles/home/store/home.js'; import { PlayerModal } from '../player-modal/player-modal.js'; import { DeleteWarning } from './components/delete-warning.js'; import styles from './styles.module.css'; -import { notificationService } from '~/bundles/common/services/services.js'; type Properties = { id: string; @@ -97,13 +97,13 @@ const VideoCard: React.FC = ({ }, [dispatch, handleWarningModalClose, id]); const handleCopyButtonClick = useCallback(() => { - dispatch(homeActions.createVideoUrl(id)) + dispatch(homeActions.getJwt(id)) .unwrap() .then(async (jwt) => { const token = await jwt; const url = createVideoUrl(token); - await navigator.clipboard.writeText(createVideoUrl(url)); - + await navigator.clipboard.writeText(url); + notificationService.success({ message: 'Url copied to clipboard', id : 'url-copied', title : 'Success' }); }) .catch((error) => { throw new Error(`Failed to get video ID JWT: ${error}`); diff --git a/frontend/src/bundles/home/store/actions.ts b/frontend/src/bundles/home/store/actions.ts index 05797904d..3312e2cd5 100644 --- a/frontend/src/bundles/home/store/actions.ts +++ b/frontend/src/bundles/home/store/actions.ts @@ -24,7 +24,7 @@ const deleteVideo = createAsyncThunk, string, AsyncThunkConfig>( }, ); -const createVideoUrl = createAsyncThunk, string, AsyncThunkConfig>( +const getJwt = createAsyncThunk, string, AsyncThunkConfig>( `${sliceName}/create-video-url`, (payload, { extra }) => { const { videosApi } = extra; @@ -32,4 +32,4 @@ const createVideoUrl = createAsyncThunk, string, AsyncThunkConfi }, ); -export { createVideoUrl, deleteVideo, loadUserVideos }; +export { deleteVideo, getJwt, loadUserVideos }; diff --git a/frontend/src/bundles/home/store/home.ts b/frontend/src/bundles/home/store/home.ts index c4b6247ee..f97fc0dbb 100644 --- a/frontend/src/bundles/home/store/home.ts +++ b/frontend/src/bundles/home/store/home.ts @@ -1,11 +1,11 @@ -import { createVideoUrl, deleteVideo, loadUserVideos, } from './actions.js'; +import { deleteVideo, getJwt, loadUserVideos, } from './actions.js'; import { actions } from './slice.js'; const allActions = { ...actions, deleteVideo, loadUserVideos, - createVideoUrl, + getJwt, }; export { reducer } from './slice.js'; diff --git a/frontend/src/bundles/preview/components/preview-wrapper.tsx b/frontend/src/bundles/preview/components/preview-wrapper.tsx new file mode 100644 index 000000000..631934df9 --- /dev/null +++ b/frontend/src/bundles/preview/components/preview-wrapper.tsx @@ -0,0 +1,10 @@ +import { useParams } from 'react-router-dom'; + +import { Preview } from '~/bundles/preview/pages/preview.js'; + +const PreviewWrapper: React.FC = () => { + const { id } = useParams<{ id: string }>(); + return ; +}; + +export { PreviewWrapper }; \ No newline at end of file diff --git a/frontend/src/bundles/preview/pages/preview.tsx b/frontend/src/bundles/preview/pages/preview.tsx index 2384865a6..6a361d3c9 100644 --- a/frontend/src/bundles/preview/pages/preview.tsx +++ b/frontend/src/bundles/preview/pages/preview.tsx @@ -2,12 +2,17 @@ import { Box, Header , VideoPlayer } from '~/bundles/common/components/component import styles from './styles.module.css'; -const Preview: React.FC = () => { +type Properties = { + id: string; +}; + +const Preview: React.FC = ({ id }) => { return (
+ {id} , }, { - path: AppRoute.PREVIEW, + path: `${AppRoute.PREVIEW}/:id`, element: ( - + ), } ], From 01bf93f9c48d0c8ce00eb87e4a625dfd45a4289c Mon Sep 17 00:00:00 2001 From: stefano-lacorazza <112132737+stefano-lacorazza@users.noreply.github.com> Date: Wed, 25 Sep 2024 06:50:39 -0500 Subject: [PATCH 06/20] OV-377: + create public-video controller and service --- .../src/bundles/public-video/enums/enums.ts | 1 + .../enums/public-videos-api-path.enum.ts | 5 +++ .../public-video/public-video.controller.ts | 40 +++++++++++++++++ .../public-video/public-video.service.ts | 43 +++++++++++++++++++ .../src/bundles/public-video/public-videos.ts | 12 ++++++ .../controller/base-controller.package.ts | 3 +- .../types/api-handler-options.type.ts | 2 + .../server-application/server-application.ts | 3 ++ .../common/services/token/token.services.ts | 2 +- frontend/src/bundles/common/api/api.ts | 9 +++- .../api/public-video-api/enums/enums.ts | 1 + .../api/public-video-api/public-videos-api.ts | 43 +++++++++++++++++++ .../preview/components/preview-wrapper.tsx | 4 +- .../src/bundles/preview/pages/preview.tsx | 40 ++++++++++++----- frontend/src/bundles/preview/store/actions.ts | 13 ++++++ .../http-api/base-http-api.package.ts | 8 +++- .../http-api/types/http-api-options.type.ts | 1 + frontend/src/framework/store/store.package.ts | 4 +- frontend/src/routes/routes.tsx | 2 +- shared/src/enums/api-path.enum.ts | 1 + 20 files changed, 219 insertions(+), 18 deletions(-) create mode 100644 backend/src/bundles/public-video/enums/enums.ts create mode 100644 backend/src/bundles/public-video/enums/public-videos-api-path.enum.ts create mode 100644 backend/src/bundles/public-video/public-video.controller.ts create mode 100644 backend/src/bundles/public-video/public-video.service.ts create mode 100644 backend/src/bundles/public-video/public-videos.ts create mode 100644 frontend/src/bundles/common/api/public-video-api/enums/enums.ts create mode 100644 frontend/src/bundles/common/api/public-video-api/public-videos-api.ts create mode 100644 frontend/src/bundles/preview/store/actions.ts diff --git a/backend/src/bundles/public-video/enums/enums.ts b/backend/src/bundles/public-video/enums/enums.ts new file mode 100644 index 000000000..2f314a44f --- /dev/null +++ b/backend/src/bundles/public-video/enums/enums.ts @@ -0,0 +1 @@ +export { VideosApiPath, VideoValidationMessage } from 'shared'; diff --git a/backend/src/bundles/public-video/enums/public-videos-api-path.enum.ts b/backend/src/bundles/public-video/enums/public-videos-api-path.enum.ts new file mode 100644 index 000000000..d41af0187 --- /dev/null +++ b/backend/src/bundles/public-video/enums/public-videos-api-path.enum.ts @@ -0,0 +1,5 @@ +const PublicVideosApiPath = { + ROOT: '/', +} as const; + +export { PublicVideosApiPath }; diff --git a/backend/src/bundles/public-video/public-video.controller.ts b/backend/src/bundles/public-video/public-video.controller.ts new file mode 100644 index 000000000..bbf999f77 --- /dev/null +++ b/backend/src/bundles/public-video/public-video.controller.ts @@ -0,0 +1,40 @@ +import { type PublicVideoService } from '~/bundles/public-video/public-video.service.js'; +import { + type ApiHandlerOptions, + type ApiHandlerResponse, + BaseController, +} from '~/common/controller/controller.js'; +import { HTTPCode, HTTPMethod } from '~/common/http/http.js'; +import { type Logger } from '~/common/logger/logger.js'; + +import { PublicVideosApiPath } from './enums/public-videos-api-path.enum.js'; + +class PublicVideoController extends BaseController { + private publicVideoService: PublicVideoService; + + public constructor(logger: Logger, publicVideoService: PublicVideoService) { + super(logger, '/public-video'); + + this.publicVideoService = publicVideoService; + + this.addRoute({ + path: PublicVideosApiPath.ROOT, + method: HTTPMethod.GET, + handler: (options) => this.findUrlByToken(options), + }); + } + + private async findUrlByToken( + options: ApiHandlerOptions, + ): Promise { + const headers = options.headers as Record; + const videoTokenHeader = headers['video_token']?.toString() ?? ''; + + return { + status: HTTPCode.OK, + payload: await this.publicVideoService.findUrlByToken(videoTokenHeader ?? ''), + }; + } +} + +export { PublicVideoController }; diff --git a/backend/src/bundles/public-video/public-video.service.ts b/backend/src/bundles/public-video/public-video.service.ts new file mode 100644 index 000000000..f95cccd1d --- /dev/null +++ b/backend/src/bundles/public-video/public-video.service.ts @@ -0,0 +1,43 @@ +import { type VideoRepository } from '~/bundles/videos/video.repository.js'; +import { HTTPCode, HttpError } from '~/common/http/http.js'; +import { tokenService } from '~/common/services/services.js'; + +import { VideoValidationMessage } from './enums/enums.js'; + +class PublicVideoService { + private videoRepository: VideoRepository; + public constructor( + videoRepository: VideoRepository, + ) { + this.videoRepository = videoRepository; + } + + public async findUrlByToken(token: string): Promise { + const id = await tokenService.getVideoIdFromToken(token); + + if (!id) { + this.throwVideoNotFoundError(); + } + + const video = await this.videoRepository.findById(id); + + if (!video) { + this.throwVideoNotFoundError(); + } + + const url = video.toObject().url; + if (!url) { + this.throwVideoNotFoundError(); + } + return url; + } + + private throwVideoNotFoundError(): never { + throw new HttpError({ + message: VideoValidationMessage.VIDEO_DOESNT_EXIST, + status: HTTPCode.NOT_FOUND, + }); + } +} + +export { PublicVideoService }; diff --git a/backend/src/bundles/public-video/public-videos.ts b/backend/src/bundles/public-video/public-videos.ts new file mode 100644 index 000000000..0018fc4b1 --- /dev/null +++ b/backend/src/bundles/public-video/public-videos.ts @@ -0,0 +1,12 @@ +import { VideoModel } from '~/bundles/videos/video.model.js'; +import { VideoRepository } from '~/bundles/videos/video.repository.js'; +import { logger } from '~/common/logger/logger.js'; + +import { PublicVideoController } from './public-video.controller.js'; +import { PublicVideoService } from './public-video.service.js'; + +const videoRepository = new VideoRepository(VideoModel); +const videoService = new PublicVideoService(videoRepository); +const publicVideoController = new PublicVideoController(logger, videoService); + +export { publicVideoController }; diff --git a/backend/src/common/controller/base-controller.package.ts b/backend/src/common/controller/base-controller.package.ts index 3ec714afd..eb3bcfd70 100644 --- a/backend/src/common/controller/base-controller.package.ts +++ b/backend/src/common/controller/base-controller.package.ts @@ -49,7 +49,7 @@ class BaseController implements Controller { private mapRequest( request: Parameters[0], ): ApiHandlerOptions { - const { body, query, params, session, user } = request; + const { body, query, params, session, user, headers } = request; return { body, @@ -57,6 +57,7 @@ class BaseController implements Controller { params, session, user, + headers, }; } } diff --git a/backend/src/common/controller/types/api-handler-options.type.ts b/backend/src/common/controller/types/api-handler-options.type.ts index 0aee24e31..07838befe 100644 --- a/backend/src/common/controller/types/api-handler-options.type.ts +++ b/backend/src/common/controller/types/api-handler-options.type.ts @@ -4,6 +4,7 @@ type DefaultApiHandlerOptions = { params?: unknown; session?: unknown; user?: unknown; + headers?: unknown; }; type ApiHandlerOptions< @@ -14,6 +15,7 @@ type ApiHandlerOptions< params: T['params']; session: T['session']; user: T['user']; + headers: T['headers']; }; export { type ApiHandlerOptions }; diff --git a/backend/src/common/server-application/server-application.ts b/backend/src/common/server-application/server-application.ts index f940b4b54..67e8701fd 100644 --- a/backend/src/common/server-application/server-application.ts +++ b/backend/src/common/server-application/server-application.ts @@ -3,6 +3,7 @@ import { avatarVideoController } from '~/bundles/avatar-videos/avatar-videos.js' import { avatarController } from '~/bundles/avatars/avatars.js'; import { chatController } from '~/bundles/chat/chat.js'; import { notificationController } from '~/bundles/notifications/notifications.js'; +import { publicVideoController } from '~/bundles/public-video/public-videos.js'; import { speechController } from '~/bundles/speech/speech.js'; import { userController } from '~/bundles/users/users.js'; import { videoController } from '~/bundles/videos/videos.js'; @@ -24,6 +25,8 @@ const apiV1 = new BaseServerAppApi( ...chatController.routes, ...speechController.routes, ...avatarVideoController.routes, + ...publicVideoController.routes, + ); const serverApp = new BaseServerApp({ diff --git a/backend/src/common/services/token/token.services.ts b/backend/src/common/services/token/token.services.ts index b0df2bb4c..cd06b720a 100644 --- a/backend/src/common/services/token/token.services.ts +++ b/backend/src/common/services/token/token.services.ts @@ -21,7 +21,7 @@ class TokenService { const jwt = await new SignJWT({ videoId }) .setProtectedHeader({ alg: 'HS256' }) .sign(this.secretKey); - return jwt.replaceAll('.', '-'); + return jwt.replaceAll('.', '~'); } public async verifyToken(token: string): Promise { diff --git a/frontend/src/bundles/common/api/api.ts b/frontend/src/bundles/common/api/api.ts index b492f9ff0..2a2663498 100644 --- a/frontend/src/bundles/common/api/api.ts +++ b/frontend/src/bundles/common/api/api.ts @@ -2,6 +2,7 @@ import { config } from '~/framework/config/config.js'; import { http } from '~/framework/http/http.js'; import { storage } from '~/framework/storage/storage.js'; +import { PublicVideosApi } from './public-video-api/public-videos-api.js'; import { VideosApi } from './video-api/videos-api.js'; const videosApi = new VideosApi({ @@ -10,4 +11,10 @@ const videosApi = new VideosApi({ http, }); -export { videosApi }; +const publicVideosApi = new PublicVideosApi({ + baseUrl: config.ENV.API.ORIGIN_URL, + storage, + http, +}); + +export { publicVideosApi,videosApi }; diff --git a/frontend/src/bundles/common/api/public-video-api/enums/enums.ts b/frontend/src/bundles/common/api/public-video-api/enums/enums.ts new file mode 100644 index 000000000..7e0da47c3 --- /dev/null +++ b/frontend/src/bundles/common/api/public-video-api/enums/enums.ts @@ -0,0 +1 @@ +export { VideosApiPath } from 'shared'; diff --git a/frontend/src/bundles/common/api/public-video-api/public-videos-api.ts b/frontend/src/bundles/common/api/public-video-api/public-videos-api.ts new file mode 100644 index 000000000..c6851b3a7 --- /dev/null +++ b/frontend/src/bundles/common/api/public-video-api/public-videos-api.ts @@ -0,0 +1,43 @@ +import { ApiPath, ContentType } from '~/bundles/common/enums/enums.js'; +import { type Http, HTTPMethod } from '~/framework/http/http.js'; +import { BaseHttpApi } from '~/framework/http-api/http-api.js'; +import { type Storage } from '~/framework/storage/storage.js'; + +import { VideosApiPath } from './enums/enums.js'; + +type Constructor = { + baseUrl: string; + http: Http; + storage: Storage; +}; + +class PublicVideosApi extends BaseHttpApi { + public constructor({ baseUrl, http, storage }: Constructor) { + super({ path: ApiPath.PUBLIC_VIDEO, baseUrl, http, storage }); + } + + public async getVideoUrlFromJWT(jwt: string): Promise { + + const headers = new Headers(); + headers.append('video_token', jwt.replaceAll('~', '.')); + + const options = { + method: HTTPMethod.GET, + contentType: ContentType.JSON, + hasAuth: true, + customHeaders: headers, + }; + + const response = await this.load( + this.getFullEndpoint(`/public-video${VideosApiPath.ROOT}`, {}), + options, + ); + + if (!response.ok) { + throw new Error(`Failed to get video ID JWT: ${response.statusText}`); + } + return await response.text(); +} +} + +export { PublicVideosApi }; diff --git a/frontend/src/bundles/preview/components/preview-wrapper.tsx b/frontend/src/bundles/preview/components/preview-wrapper.tsx index 631934df9..4d70848f8 100644 --- a/frontend/src/bundles/preview/components/preview-wrapper.tsx +++ b/frontend/src/bundles/preview/components/preview-wrapper.tsx @@ -3,8 +3,8 @@ import { useParams } from 'react-router-dom'; import { Preview } from '~/bundles/preview/pages/preview.js'; const PreviewWrapper: React.FC = () => { - const { id } = useParams<{ id: string }>(); - return ; + const { jwt } = useParams<{ jwt: string }>(); + return ; }; export { PreviewWrapper }; \ No newline at end of file diff --git a/frontend/src/bundles/preview/pages/preview.tsx b/frontend/src/bundles/preview/pages/preview.tsx index 6a361d3c9..8407d32e1 100644 --- a/frontend/src/bundles/preview/pages/preview.tsx +++ b/frontend/src/bundles/preview/pages/preview.tsx @@ -1,20 +1,40 @@ -import { Box, Header , VideoPlayer } from '~/bundles/common/components/components.js'; +import { Box, Header, Loader, VideoPlayer } from '~/bundles/common/components/components.js'; +import { useAppDispatch, useEffect, useState } from '~/bundles/common/hooks/hooks.js'; +import { getUrl } from '../store/actions.js'; import styles from './styles.module.css'; type Properties = { - id: string; + jwt: string; }; -const Preview: React.FC = ({ id }) => { - +const Preview: React.FC = ({ jwt }) => { + const dispatch = useAppDispatch(); + const [url, setUrl] = useState(''); + const [loading, setLoading] = useState(true); + + useEffect(() => { + const fetchUrl = async (): Promise => { + try { + const result = await dispatch(getUrl(jwt)).unwrap(); + setUrl(result); + } finally { + setLoading(false); + } + }; + + fetchUrl().catch(error => {throw new Error(error); }); + }, [dispatch, jwt]); + + if (loading) { + return ; + } + return ( - -
- {id} + +
= ({ id }) => { ); }; -export { Preview }; +export { Preview }; \ No newline at end of file diff --git a/frontend/src/bundles/preview/store/actions.ts b/frontend/src/bundles/preview/store/actions.ts new file mode 100644 index 000000000..57baeb9e0 --- /dev/null +++ b/frontend/src/bundles/preview/store/actions.ts @@ -0,0 +1,13 @@ +import { createAsyncThunk } from '@reduxjs/toolkit'; + +import { type AsyncThunkConfig } from '~/bundles/common/types/types.js'; + +const getUrl = createAsyncThunk, string, AsyncThunkConfig>( + 'preview/create-video-url', + (payload, { extra }) => { + const { publicVideosApi } = extra; + return publicVideosApi.getVideoUrlFromJWT(payload); + }, +); + +export { getUrl }; diff --git a/frontend/src/framework/http-api/base-http-api.package.ts b/frontend/src/framework/http-api/base-http-api.package.ts index 48fadbd2d..90d86c912 100644 --- a/frontend/src/framework/http-api/base-http-api.package.ts +++ b/frontend/src/framework/http-api/base-http-api.package.ts @@ -51,9 +51,15 @@ class BaseHttpApi implements HttpApi { hasAuth, credentials = 'same-origin', keepAlive = false, + customHeaders, } = options; - + const headers = await this.getHeaders(contentType, hasAuth); + if (customHeaders) { + for (const [key, value] of customHeaders) { + headers.append(key, value); + } + } const response = await this.http.load(path, { method, diff --git a/frontend/src/framework/http-api/types/http-api-options.type.ts b/frontend/src/framework/http-api/types/http-api-options.type.ts index 2a635c599..4c44b70b7 100644 --- a/frontend/src/framework/http-api/types/http-api-options.type.ts +++ b/frontend/src/framework/http-api/types/http-api-options.type.ts @@ -11,6 +11,7 @@ type HTTPApiOptions = Omit< payload?: HttpOptions['payload']; credentials?: HttpOptions['credentials']; keepAlive?: HttpOptions['keepAlive']; + customHeaders?: HttpOptions['headers']; }; export { type HTTPApiOptions }; diff --git a/frontend/src/framework/store/store.package.ts b/frontend/src/framework/store/store.package.ts index 33e2f8f29..15ec62bec 100644 --- a/frontend/src/framework/store/store.package.ts +++ b/frontend/src/framework/store/store.package.ts @@ -9,7 +9,7 @@ import { authApi } from '~/bundles/auth/auth.js'; import { reducer as authReducer } from '~/bundles/auth/store/auth.js'; import { chatApi } from '~/bundles/chat/chat.js'; import { reducer as chatReducer } from '~/bundles/chat/store/chat.js'; -import { videosApi } from '~/bundles/common/api/api.js'; +import { publicVideosApi, videosApi } from '~/bundles/common/api/api.js'; import { AppEnvironment } from '~/bundles/common/enums/enums.js'; import { draftMiddleware, @@ -42,6 +42,7 @@ type ExtraArguments = { avatarVideosApi: typeof avatarVideosApi; chatApi: typeof chatApi; storage: typeof storage; + publicVideosApi: typeof publicVideosApi; }; class Store { @@ -87,6 +88,7 @@ class Store { avatarVideosApi, chatApi, storage, + publicVideosApi, }; } } diff --git a/frontend/src/routes/routes.tsx b/frontend/src/routes/routes.tsx index b5a58fc6d..08e6cdf6c 100644 --- a/frontend/src/routes/routes.tsx +++ b/frontend/src/routes/routes.tsx @@ -59,7 +59,7 @@ const routes = [ element: , }, { - path: `${AppRoute.PREVIEW}/:id`, + path: `${AppRoute.PREVIEW}/:jwt`, element: ( ), diff --git a/shared/src/enums/api-path.enum.ts b/shared/src/enums/api-path.enum.ts index a3429e663..b2d8fe95a 100644 --- a/shared/src/enums/api-path.enum.ts +++ b/shared/src/enums/api-path.enum.ts @@ -8,6 +8,7 @@ const ApiPath = { CHAT: '/chat', SPEECH: '/speech', AVATAR_VIDEO: '/avatar-video', + PUBLIC_VIDEO: '/public-video', } as const; export { ApiPath }; From 5e9044d7b2af4a3c24ddff6e0862f1f05550b274 Mon Sep 17 00:00:00 2001 From: stefano-lacorazza <112132737+stefano-lacorazza@users.noreply.github.com> Date: Wed, 25 Sep 2024 08:14:49 -0500 Subject: [PATCH 07/20] OV-377: + white route public-video --- backend/src/bundles/public-video/public-video.controller.ts | 5 +++-- backend/src/common/constants/white-routes.constants.ts | 4 ++++ .../common/api/public-video-api/public-videos-api.ts | 6 +++--- frontend/src/bundles/preview/pages/preview.tsx | 1 + frontend/src/bundles/preview/store/actions.ts | 1 + 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/backend/src/bundles/public-video/public-video.controller.ts b/backend/src/bundles/public-video/public-video.controller.ts index bbf999f77..7c813113f 100644 --- a/backend/src/bundles/public-video/public-video.controller.ts +++ b/backend/src/bundles/public-video/public-video.controller.ts @@ -4,6 +4,7 @@ import { type ApiHandlerResponse, BaseController, } from '~/common/controller/controller.js'; +import { ApiPath } from '~/common/enums/enums.js'; import { HTTPCode, HTTPMethod } from '~/common/http/http.js'; import { type Logger } from '~/common/logger/logger.js'; @@ -13,7 +14,7 @@ class PublicVideoController extends BaseController { private publicVideoService: PublicVideoService; public constructor(logger: Logger, publicVideoService: PublicVideoService) { - super(logger, '/public-video'); + super(logger, ApiPath.PUBLIC_VIDEO); this.publicVideoService = publicVideoService; @@ -29,7 +30,7 @@ class PublicVideoController extends BaseController { ): Promise { const headers = options.headers as Record; const videoTokenHeader = headers['video_token']?.toString() ?? ''; - + return { status: HTTPCode.OK, payload: await this.publicVideoService.findUrlByToken(videoTokenHeader ?? ''), diff --git a/backend/src/common/constants/white-routes.constants.ts b/backend/src/common/constants/white-routes.constants.ts index 4af3ddb56..5a592caa2 100644 --- a/backend/src/common/constants/white-routes.constants.ts +++ b/backend/src/common/constants/white-routes.constants.ts @@ -11,6 +11,10 @@ const WHITE_ROUTES = [ path: `/api/v1${ApiPath.AUTH}${AuthApiPath.SIGN_UP}`, method: HTTPMethod.POST, }, + { + path: `/api/v1${ApiPath.PUBLIC_VIDEO}/`, + method: HTTPMethod.GET, + }, { path: /\/v1\/documentation\/.*/, method: HTTPMethod.GET, diff --git a/frontend/src/bundles/common/api/public-video-api/public-videos-api.ts b/frontend/src/bundles/common/api/public-video-api/public-videos-api.ts index c6851b3a7..6793bdffb 100644 --- a/frontend/src/bundles/common/api/public-video-api/public-videos-api.ts +++ b/frontend/src/bundles/common/api/public-video-api/public-videos-api.ts @@ -20,7 +20,7 @@ class PublicVideosApi extends BaseHttpApi { const headers = new Headers(); headers.append('video_token', jwt.replaceAll('~', '.')); - + const options = { method: HTTPMethod.GET, contentType: ContentType.JSON, @@ -29,10 +29,10 @@ class PublicVideosApi extends BaseHttpApi { }; const response = await this.load( - this.getFullEndpoint(`/public-video${VideosApiPath.ROOT}`, {}), + this.getFullEndpoint(`${VideosApiPath.ROOT}`, {}), options, ); - + if (!response.ok) { throw new Error(`Failed to get video ID JWT: ${response.statusText}`); } diff --git a/frontend/src/bundles/preview/pages/preview.tsx b/frontend/src/bundles/preview/pages/preview.tsx index 8407d32e1..8e0ca76e5 100644 --- a/frontend/src/bundles/preview/pages/preview.tsx +++ b/frontend/src/bundles/preview/pages/preview.tsx @@ -17,6 +17,7 @@ const Preview: React.FC = ({ jwt }) => { const fetchUrl = async (): Promise => { try { const result = await dispatch(getUrl(jwt)).unwrap(); + setUrl(result); } finally { setLoading(false); diff --git a/frontend/src/bundles/preview/store/actions.ts b/frontend/src/bundles/preview/store/actions.ts index 57baeb9e0..7a72985bf 100644 --- a/frontend/src/bundles/preview/store/actions.ts +++ b/frontend/src/bundles/preview/store/actions.ts @@ -6,6 +6,7 @@ const getUrl = createAsyncThunk, string, AsyncThunkConfig>( 'preview/create-video-url', (payload, { extra }) => { const { publicVideosApi } = extra; + return publicVideosApi.getVideoUrlFromJWT(payload); }, ); From ba2031e5e4a33b601e46b6a608ef59359f8d7448 Mon Sep 17 00:00:00 2001 From: stefano-lacorazza <112132737+stefano-lacorazza@users.noreply.github.com> Date: Wed, 25 Sep 2024 09:01:37 -0500 Subject: [PATCH 08/20] OV-377: + style preview page --- .../src/bundles/preview/pages/preview.tsx | 19 ++++++++++++---- .../bundles/preview/pages/styles.module.css | 22 ++++++++++++++++--- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/frontend/src/bundles/preview/pages/preview.tsx b/frontend/src/bundles/preview/pages/preview.tsx index 8e0ca76e5..33181410c 100644 --- a/frontend/src/bundles/preview/pages/preview.tsx +++ b/frontend/src/bundles/preview/pages/preview.tsx @@ -1,5 +1,8 @@ -import { Box, Header, Loader, VideoPlayer } from '~/bundles/common/components/components.js'; -import { useAppDispatch, useEffect, useState } from '~/bundles/common/hooks/hooks.js'; +import { useNavigate } from 'react-router-dom'; + +import { Box, Button,Header, Loader, VideoPlayer, } from '~/bundles/common/components/components.js'; +import { AppRoute } from '~/bundles/common/enums/enums.js'; +import { useAppDispatch, useCallback,useEffect, useState } from '~/bundles/common/hooks/hooks.js'; import { getUrl } from '../store/actions.js'; import styles from './styles.module.css'; @@ -27,19 +30,27 @@ const Preview: React.FC = ({ jwt }) => { fetchUrl().catch(error => {throw new Error(error); }); }, [dispatch, jwt]); + const navigate = useNavigate(); + + const handleClick = useCallback(() => { + navigate(AppRoute.ROOT); + }, [navigate]); + if (loading) { - return ; + return ; } return ( -
+
}/> + + ); }; diff --git a/frontend/src/bundles/preview/pages/styles.module.css b/frontend/src/bundles/preview/pages/styles.module.css index 7317d0311..420dc5bd5 100644 --- a/frontend/src/bundles/preview/pages/styles.module.css +++ b/frontend/src/bundles/preview/pages/styles.module.css @@ -1,6 +1,22 @@ .video-player { - height: 1000px; - width: 1000px; + height:50vh; + width: 90vh; position: relative; - background-color: var(--chakra-colors-gray-200); + background-color: var(--chakra-colors-background-600); } +.loader-box { + background-color: var(--chakra-colors-background-900); + display: flex; + justify-content: center; + align-items: center; + height: 100vh; +} +.back-box { + background-color: var(--chakra-colors-background-600); + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + position: relative; + z-index: 0; +} \ No newline at end of file From 423cabcb1da86e101255284afd7f79265a45c4c8 Mon Sep 17 00:00:00 2001 From: stefano-lacorazza <112132737+stefano-lacorazza@users.noreply.github.com> Date: Wed, 25 Sep 2024 09:24:22 -0500 Subject: [PATCH 09/20] OV-377: * prettier --- .../public-video/public-video.controller.ts | 8 +-- .../public-video/public-video.service.ts | 4 +- .../src/bundles/videos/video.controller.ts | 2 +- backend/src/bundles/videos/video.service.ts | 2 +- .../server-application/server-application.ts | 1 - .../common/services/token/token.services.ts | 2 +- frontend/src/bundles/common/api/api.ts | 2 +- .../api/public-video-api/public-videos-api.ts | 9 ++-- .../common/api/video-api/videos-api.ts | 25 +++++----- .../home/components/video-card/video-card.tsx | 9 ++-- .../bundles/home/helpers/create-url-token.ts | 3 +- frontend/src/bundles/home/helpers/helpers.ts | 2 +- frontend/src/bundles/home/store/home.ts | 2 +- .../preview/components/preview-wrapper.tsx | 2 +- .../src/bundles/preview/pages/preview.tsx | 49 ++++++++++++++----- .../bundles/preview/pages/styles.module.css | 4 +- .../http-api/base-http-api.package.ts | 2 +- frontend/src/routes/routes.tsx | 6 +-- 18 files changed, 80 insertions(+), 54 deletions(-) diff --git a/backend/src/bundles/public-video/public-video.controller.ts b/backend/src/bundles/public-video/public-video.controller.ts index 7c813113f..8c60f4271 100644 --- a/backend/src/bundles/public-video/public-video.controller.ts +++ b/backend/src/bundles/public-video/public-video.controller.ts @@ -24,7 +24,7 @@ class PublicVideoController extends BaseController { handler: (options) => this.findUrlByToken(options), }); } - + private async findUrlByToken( options: ApiHandlerOptions, ): Promise { @@ -33,9 +33,11 @@ class PublicVideoController extends BaseController { return { status: HTTPCode.OK, - payload: await this.publicVideoService.findUrlByToken(videoTokenHeader ?? ''), + payload: await this.publicVideoService.findUrlByToken( + videoTokenHeader ?? '', + ), }; } -} +} export { PublicVideoController }; diff --git a/backend/src/bundles/public-video/public-video.service.ts b/backend/src/bundles/public-video/public-video.service.ts index f95cccd1d..8b57a7740 100644 --- a/backend/src/bundles/public-video/public-video.service.ts +++ b/backend/src/bundles/public-video/public-video.service.ts @@ -6,9 +6,7 @@ import { VideoValidationMessage } from './enums/enums.js'; class PublicVideoService { private videoRepository: VideoRepository; - public constructor( - videoRepository: VideoRepository, - ) { + public constructor(videoRepository: VideoRepository) { this.videoRepository = videoRepository; } diff --git a/backend/src/bundles/videos/video.controller.ts b/backend/src/bundles/videos/video.controller.ts index 0aaa10dd5..5e89f2374 100644 --- a/backend/src/bundles/videos/video.controller.ts +++ b/backend/src/bundles/videos/video.controller.ts @@ -197,7 +197,7 @@ class VideoController extends BaseController { }; } - /** + /** * @swagger * /videos/{id}/share: * get: diff --git a/backend/src/bundles/videos/video.service.ts b/backend/src/bundles/videos/video.service.ts index 8b17eeab6..6fec6a96a 100644 --- a/backend/src/bundles/videos/video.service.ts +++ b/backend/src/bundles/videos/video.service.ts @@ -102,7 +102,7 @@ class VideoService implements Service { } public async getVideoIdToken(id: string): Promise { - return await tokenService.createVideoIdToken(id); + return await tokenService.createVideoIdToken(id); } } diff --git a/backend/src/common/server-application/server-application.ts b/backend/src/common/server-application/server-application.ts index 67e8701fd..ea5f73ecf 100644 --- a/backend/src/common/server-application/server-application.ts +++ b/backend/src/common/server-application/server-application.ts @@ -26,7 +26,6 @@ const apiV1 = new BaseServerAppApi( ...speechController.routes, ...avatarVideoController.routes, ...publicVideoController.routes, - ); const serverApp = new BaseServerApp({ diff --git a/backend/src/common/services/token/token.services.ts b/backend/src/common/services/token/token.services.ts index cd06b720a..f1f6c85ba 100644 --- a/backend/src/common/services/token/token.services.ts +++ b/backend/src/common/services/token/token.services.ts @@ -18,7 +18,7 @@ class TokenService { } public async createVideoIdToken(videoId: string): Promise { - const jwt = await new SignJWT({ videoId }) + const jwt = await new SignJWT({ videoId }) .setProtectedHeader({ alg: 'HS256' }) .sign(this.secretKey); return jwt.replaceAll('.', '~'); diff --git a/frontend/src/bundles/common/api/api.ts b/frontend/src/bundles/common/api/api.ts index 2a2663498..70fd2a12c 100644 --- a/frontend/src/bundles/common/api/api.ts +++ b/frontend/src/bundles/common/api/api.ts @@ -17,4 +17,4 @@ const publicVideosApi = new PublicVideosApi({ http, }); -export { publicVideosApi,videosApi }; +export { publicVideosApi, videosApi }; diff --git a/frontend/src/bundles/common/api/public-video-api/public-videos-api.ts b/frontend/src/bundles/common/api/public-video-api/public-videos-api.ts index 6793bdffb..096bfb43d 100644 --- a/frontend/src/bundles/common/api/public-video-api/public-videos-api.ts +++ b/frontend/src/bundles/common/api/public-video-api/public-videos-api.ts @@ -17,7 +17,6 @@ class PublicVideosApi extends BaseHttpApi { } public async getVideoUrlFromJWT(jwt: string): Promise { - const headers = new Headers(); headers.append('video_token', jwt.replaceAll('~', '.')); @@ -34,10 +33,12 @@ class PublicVideosApi extends BaseHttpApi { ); if (!response.ok) { - throw new Error(`Failed to get video ID JWT: ${response.statusText}`); - } + throw new Error( + `Failed to get video ID JWT: ${response.statusText}`, + ); + } return await response.text(); -} + } } export { PublicVideosApi }; diff --git a/frontend/src/bundles/common/api/video-api/videos-api.ts b/frontend/src/bundles/common/api/video-api/videos-api.ts index 74d7f8892..491ae298c 100644 --- a/frontend/src/bundles/common/api/video-api/videos-api.ts +++ b/frontend/src/bundles/common/api/video-api/videos-api.ts @@ -99,20 +99,21 @@ class VideosApi extends BaseHttpApi { } public async getVideoIdJWT(id: string): Promise { + const response = await this.load( + this.getFullEndpoint(`${VideosApiPath.ROOT}${id}/share`, {}), + { + method: HTTPMethod.GET, + contentType: ContentType.JSON, + hasAuth: true, + }, + ); - const response = await this.load( - this.getFullEndpoint(`${VideosApiPath.ROOT}${id}/share`, {}), - { - method: HTTPMethod.GET, - contentType: ContentType.JSON, - hasAuth: true, - }, + if (!response.ok) { + throw new Error( + `Failed to get video ID JWT: ${response.statusText}`, ); - - if (!response.ok) { - throw new Error(`Failed to get video ID JWT: ${response.statusText}`); - } - return await response.text(); + } + return await response.text(); } } diff --git a/frontend/src/bundles/home/components/video-card/video-card.tsx b/frontend/src/bundles/home/components/video-card/video-card.tsx index 41a094e88..5558dfb63 100644 --- a/frontend/src/bundles/home/components/video-card/video-card.tsx +++ b/frontend/src/bundles/home/components/video-card/video-card.tsx @@ -103,14 +103,17 @@ const VideoCard: React.FC = ({ const token = await jwt; const url = createVideoUrl(token); await navigator.clipboard.writeText(url); - notificationService.success({ message: 'Url copied to clipboard', id : 'url-copied', title : 'Success' }); + notificationService.success({ + message: 'Url copied to clipboard', + id: 'url-copied', + title: 'Success', + }); }) .catch((error) => { throw new Error(`Failed to get video ID JWT: ${error}`); }); - }, [dispatch, id]); - + return ( { const baseUrl = 'http://localhost:3000'; return `${baseUrl}/preview/${jwtToken}`; }; -export { createVideoUrl }; \ No newline at end of file +export { createVideoUrl }; diff --git a/frontend/src/bundles/home/helpers/helpers.ts b/frontend/src/bundles/home/helpers/helpers.ts index 51239f491..2a9c6a4b1 100644 --- a/frontend/src/bundles/home/helpers/helpers.ts +++ b/frontend/src/bundles/home/helpers/helpers.ts @@ -1 +1 @@ -export { createVideoUrl } from './create-url-token.js'; \ No newline at end of file +export { createVideoUrl } from './create-url-token.js'; diff --git a/frontend/src/bundles/home/store/home.ts b/frontend/src/bundles/home/store/home.ts index f97fc0dbb..f682b3b1d 100644 --- a/frontend/src/bundles/home/store/home.ts +++ b/frontend/src/bundles/home/store/home.ts @@ -1,4 +1,4 @@ -import { deleteVideo, getJwt, loadUserVideos, } from './actions.js'; +import { deleteVideo, getJwt, loadUserVideos } from './actions.js'; import { actions } from './slice.js'; const allActions = { diff --git a/frontend/src/bundles/preview/components/preview-wrapper.tsx b/frontend/src/bundles/preview/components/preview-wrapper.tsx index 4d70848f8..bfa744f70 100644 --- a/frontend/src/bundles/preview/components/preview-wrapper.tsx +++ b/frontend/src/bundles/preview/components/preview-wrapper.tsx @@ -7,4 +7,4 @@ const PreviewWrapper: React.FC = () => { return ; }; -export { PreviewWrapper }; \ No newline at end of file +export { PreviewWrapper }; diff --git a/frontend/src/bundles/preview/pages/preview.tsx b/frontend/src/bundles/preview/pages/preview.tsx index 33181410c..83f39d489 100644 --- a/frontend/src/bundles/preview/pages/preview.tsx +++ b/frontend/src/bundles/preview/pages/preview.tsx @@ -1,8 +1,19 @@ import { useNavigate } from 'react-router-dom'; -import { Box, Button,Header, Loader, VideoPlayer, } from '~/bundles/common/components/components.js'; +import { + Box, + Button, + Header, + Loader, + VideoPlayer, +} from '~/bundles/common/components/components.js'; import { AppRoute } from '~/bundles/common/enums/enums.js'; -import { useAppDispatch, useCallback,useEffect, useState } from '~/bundles/common/hooks/hooks.js'; +import { + useAppDispatch, + useCallback, + useEffect, + useState, +} from '~/bundles/common/hooks/hooks.js'; import { getUrl } from '../store/actions.js'; import styles from './styles.module.css'; @@ -27,7 +38,9 @@ const Preview: React.FC = ({ jwt }) => { } }; - fetchUrl().catch(error => {throw new Error(error); }); + fetchUrl().catch((error) => { + throw new Error(error); + }); }, [dispatch, jwt]); const navigate = useNavigate(); @@ -37,22 +50,34 @@ const Preview: React.FC = ({ jwt }) => { }, [navigate]); if (loading) { - return ; + return ( + + + + ); } return ( -
}/> - - + } /> + + ); }; -export { Preview }; \ No newline at end of file +export { Preview }; diff --git a/frontend/src/bundles/preview/pages/styles.module.css b/frontend/src/bundles/preview/pages/styles.module.css index 420dc5bd5..21d73a329 100644 --- a/frontend/src/bundles/preview/pages/styles.module.css +++ b/frontend/src/bundles/preview/pages/styles.module.css @@ -1,5 +1,5 @@ .video-player { - height:50vh; + height: 50vh; width: 90vh; position: relative; background-color: var(--chakra-colors-background-600); @@ -19,4 +19,4 @@ height: 100vh; position: relative; z-index: 0; -} \ No newline at end of file +} diff --git a/frontend/src/framework/http-api/base-http-api.package.ts b/frontend/src/framework/http-api/base-http-api.package.ts index 90d86c912..f64d71e5d 100644 --- a/frontend/src/framework/http-api/base-http-api.package.ts +++ b/frontend/src/framework/http-api/base-http-api.package.ts @@ -53,7 +53,7 @@ class BaseHttpApi implements HttpApi { keepAlive = false, customHeaders, } = options; - + const headers = await this.getHeaders(contentType, hasAuth); if (customHeaders) { for (const [key, value] of customHeaders) { diff --git a/frontend/src/routes/routes.tsx b/frontend/src/routes/routes.tsx index 08e6cdf6c..1a527e48d 100644 --- a/frontend/src/routes/routes.tsx +++ b/frontend/src/routes/routes.tsx @@ -60,10 +60,8 @@ const routes = [ }, { path: `${AppRoute.PREVIEW}/:jwt`, - element: ( - - ), - } + element: , + }, ], }, ]; From 5c7e932f7a20c678948a9886582db054f2de8eb8 Mon Sep 17 00:00:00 2001 From: stefano-lacorazza <112132737+stefano-lacorazza@users.noreply.github.com> Date: Thu, 26 Sep 2024 08:19:57 -0500 Subject: [PATCH 10/20] OV-377: * Refactor token service to use a unified method for creating and decoding tokens --- .../public-video/public-video.service.ts | 2 +- backend/src/bundles/videos/video.service.ts | 3 +- .../common/plugins/auth/auth-jwt.plugin.ts | 2 +- .../common/services/token/token.services.ts | 30 ++++++++----------- .../src/bundles/preview/pages/preview.tsx | 6 ++-- 5 files changed, 19 insertions(+), 24 deletions(-) diff --git a/backend/src/bundles/public-video/public-video.service.ts b/backend/src/bundles/public-video/public-video.service.ts index 8b57a7740..91b73c42c 100644 --- a/backend/src/bundles/public-video/public-video.service.ts +++ b/backend/src/bundles/public-video/public-video.service.ts @@ -11,7 +11,7 @@ class PublicVideoService { } public async findUrlByToken(token: string): Promise { - const id = await tokenService.getVideoIdFromToken(token); + const id = await tokenService.getIdFromToken(token); if (!id) { this.throwVideoNotFoundError(); diff --git a/backend/src/bundles/videos/video.service.ts b/backend/src/bundles/videos/video.service.ts index 6fec6a96a..e4e457508 100644 --- a/backend/src/bundles/videos/video.service.ts +++ b/backend/src/bundles/videos/video.service.ts @@ -102,7 +102,8 @@ class VideoService implements Service { } public async getVideoIdToken(id: string): Promise { - return await tokenService.createVideoIdToken(id); + const token = await tokenService.createToken(id, false); + return token.replaceAll('.', '~'); } } diff --git a/backend/src/common/plugins/auth/auth-jwt.plugin.ts b/backend/src/common/plugins/auth/auth-jwt.plugin.ts index f5d41bc6d..01e7cc3bc 100644 --- a/backend/src/common/plugins/auth/auth-jwt.plugin.ts +++ b/backend/src/common/plugins/auth/auth-jwt.plugin.ts @@ -31,7 +31,7 @@ const authenticateJWT = fp((fastify, { routesWhiteList }, done) => { const [, token] = authHeader.split(' '); - const userId = await tokenService.getUserIdFromToken(token as string); + const userId = await tokenService.getIdFromToken(token as string); if (!userId) { throw new HttpError({ diff --git a/backend/src/common/services/token/token.services.ts b/backend/src/common/services/token/token.services.ts index f1f6c85ba..fe69dc4ce 100644 --- a/backend/src/common/services/token/token.services.ts +++ b/backend/src/common/services/token/token.services.ts @@ -10,18 +10,17 @@ class TokenService { this.expirationTime = expirationTime; } - public async createToken(userId: string): Promise { - return await new SignJWT({ userId }) - .setProtectedHeader({ alg: 'HS256' }) - .setExpirationTime(this.expirationTime) - .sign(this.secretKey); - } + public async createToken( + id: string, + expires: boolean = true, + ): Promise { + const jwt = new SignJWT({ id }).setProtectedHeader({ alg: 'HS256' }); + + if (expires) { + jwt.setExpirationTime(this.expirationTime); + } - public async createVideoIdToken(videoId: string): Promise { - const jwt = await new SignJWT({ videoId }) - .setProtectedHeader({ alg: 'HS256' }) - .sign(this.secretKey); - return jwt.replaceAll('.', '~'); + return await jwt.sign(this.secretKey); } public async verifyToken(token: string): Promise { @@ -33,14 +32,9 @@ class TokenService { } } - public async getUserIdFromToken(token: string): Promise { - const payload = await this.verifyToken(token); - return (payload?.['userId'] as string) || null; - } - - public async getVideoIdFromToken(token: string): Promise { + public async getIdFromToken(token: string): Promise { const payload = await this.verifyToken(token); - return (payload?.['videoId'] as string) || null; + return (payload?.['id'] as string) ?? null; } } diff --git a/frontend/src/bundles/preview/pages/preview.tsx b/frontend/src/bundles/preview/pages/preview.tsx index 83f39d489..afad3b54a 100644 --- a/frontend/src/bundles/preview/pages/preview.tsx +++ b/frontend/src/bundles/preview/pages/preview.tsx @@ -25,7 +25,7 @@ type Properties = { const Preview: React.FC = ({ jwt }) => { const dispatch = useAppDispatch(); const [url, setUrl] = useState(''); - const [loading, setLoading] = useState(true); + const [isLoading, setIsLoading] = useState(true); useEffect(() => { const fetchUrl = async (): Promise => { @@ -34,7 +34,7 @@ const Preview: React.FC = ({ jwt }) => { setUrl(result); } finally { - setLoading(false); + setIsLoading(false); } }; @@ -49,7 +49,7 @@ const Preview: React.FC = ({ jwt }) => { navigate(AppRoute.ROOT); }, [navigate]); - if (loading) { + if (isLoading) { return ( From 480e38f75dd1450008aa0754be904c08f5733ab3 Mon Sep 17 00:00:00 2001 From: stefano-lacorazza <112132737+stefano-lacorazza@users.noreply.github.com> Date: Thu, 26 Sep 2024 08:40:45 -0500 Subject: [PATCH 11/20] OV-377: + added dynamically created sharing URL --- frontend/src/bundles/home/helpers/create-url-token.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/src/bundles/home/helpers/create-url-token.ts b/frontend/src/bundles/home/helpers/create-url-token.ts index 9f617e0a6..b9b5bd0bb 100644 --- a/frontend/src/bundles/home/helpers/create-url-token.ts +++ b/frontend/src/bundles/home/helpers/create-url-token.ts @@ -1,5 +1,9 @@ const createVideoUrl = (jwtToken: string): string => { - const baseUrl = 'http://localhost:3000'; + const baseUrl = + import.meta.env['VITE_APP_NODE_ENV'] === 'production' + ? 'http://bsa-2024-outreachvids-dev.eu-north-1.elasticbeanstalk.com/' + : 'http://localhost:3000'; + return `${baseUrl}/preview/${jwtToken}`; }; From 556ed1d693149729abb2f8511bbc251a20bff0ac Mon Sep 17 00:00:00 2001 From: stefano-lacorazza <112132737+stefano-lacorazza@users.noreply.github.com> Date: Thu, 26 Sep 2024 09:01:15 -0500 Subject: [PATCH 12/20] OV-377: - use config to create video url --- frontend/src/bundles/home/helpers/create-url-token.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/frontend/src/bundles/home/helpers/create-url-token.ts b/frontend/src/bundles/home/helpers/create-url-token.ts index b9b5bd0bb..a39c76c60 100644 --- a/frontend/src/bundles/home/helpers/create-url-token.ts +++ b/frontend/src/bundles/home/helpers/create-url-token.ts @@ -1,7 +1,10 @@ +import { AppEnvironment } from '~/bundles/common/enums/enums.js'; +import { config } from '~/framework/config/config.js'; + const createVideoUrl = (jwtToken: string): string => { const baseUrl = - import.meta.env['VITE_APP_NODE_ENV'] === 'production' - ? 'http://bsa-2024-outreachvids-dev.eu-north-1.elasticbeanstalk.com/' + config.ENV.APP.ENVIRONMENT === AppEnvironment.PRODUCTION + ? 'http://bsa-2024-outreachvids-dev.eu-north-1.elasticbeanstalk.com' : 'http://localhost:3000'; return `${baseUrl}/preview/${jwtToken}`; From c2ebd64ed00905a4e8a9dc26422bbd4cae2bc2e8 Mon Sep 17 00:00:00 2001 From: stefano-lacorazza <112132737+stefano-lacorazza@users.noreply.github.com> Date: Thu, 26 Sep 2024 09:16:06 -0500 Subject: [PATCH 13/20] Merge branch 'next' into task/OV-377-create-preview-page From 32b55b7c413640c36b6442193516259f6d42d92d Mon Sep 17 00:00:00 2001 From: stefano-lacorazza <112132737+stefano-lacorazza@users.noreply.github.com> Date: Thu, 26 Sep 2024 10:09:43 -0500 Subject: [PATCH 14/20] OV-377: + create env variable for deployment URL andfix magic numbers --- backend/src/bundles/public-video/public-video.controller.ts | 2 +- backend/src/bundles/public-video/public-video.service.ts | 2 +- backend/src/bundles/videos/video.controller.ts | 2 +- frontend/.env.example | 6 ++++++ frontend/src/bundles/common/api/video-api/videos-api.ts | 2 +- frontend/src/bundles/home/helpers/create-url-token.ts | 2 +- frontend/src/framework/config/base-config.package.ts | 3 +++ .../src/framework/config/types/environment-schema.type.ts | 3 +++ 8 files changed, 17 insertions(+), 5 deletions(-) diff --git a/backend/src/bundles/public-video/public-video.controller.ts b/backend/src/bundles/public-video/public-video.controller.ts index 8c60f4271..b9ae03978 100644 --- a/backend/src/bundles/public-video/public-video.controller.ts +++ b/backend/src/bundles/public-video/public-video.controller.ts @@ -34,7 +34,7 @@ class PublicVideoController extends BaseController { return { status: HTTPCode.OK, payload: await this.publicVideoService.findUrlByToken( - videoTokenHeader ?? '', + videoTokenHeader, ), }; } diff --git a/backend/src/bundles/public-video/public-video.service.ts b/backend/src/bundles/public-video/public-video.service.ts index 91b73c42c..018cd2006 100644 --- a/backend/src/bundles/public-video/public-video.service.ts +++ b/backend/src/bundles/public-video/public-video.service.ts @@ -23,7 +23,7 @@ class PublicVideoService { this.throwVideoNotFoundError(); } - const url = video.toObject().url; + const { url } = video.toObject(); if (!url) { this.throwVideoNotFoundError(); } diff --git a/backend/src/bundles/videos/video.controller.ts b/backend/src/bundles/videos/video.controller.ts index 5e89f2374..45ce5db2f 100644 --- a/backend/src/bundles/videos/video.controller.ts +++ b/backend/src/bundles/videos/video.controller.ts @@ -110,7 +110,7 @@ class VideoController extends BaseController { ), }); this.addRoute({ - path: `${VideosApiPath.ID}/share`, + path: `${VideosApiPath.ID}${VideosApiPath.SHARE}`, method: HTTPMethod.GET, handler: (options) => { return this.createVideoIdJWT( diff --git a/frontend/.env.example b/frontend/.env.example index 9d1ec0623..6092178be 100644 --- a/frontend/.env.example +++ b/frontend/.env.example @@ -10,3 +10,9 @@ VITE_APP_API_ORIGIN_URL=/api/v1 # VITE_APP_PROXY_SERVER_URL=http://localhost:3001 VITE_APP_SOCKET_ORIGIN_URL=/socket.io + +# +# DEPLOYMENT +# +DEPLOYMENT_URL=http://bsa-2024-outreachvids-dev.eu-north-1.elasticbeanstalk.com + diff --git a/frontend/src/bundles/common/api/video-api/videos-api.ts b/frontend/src/bundles/common/api/video-api/videos-api.ts index 491ae298c..f40e8ed34 100644 --- a/frontend/src/bundles/common/api/video-api/videos-api.ts +++ b/frontend/src/bundles/common/api/video-api/videos-api.ts @@ -100,7 +100,7 @@ class VideosApi extends BaseHttpApi { public async getVideoIdJWT(id: string): Promise { const response = await this.load( - this.getFullEndpoint(`${VideosApiPath.ROOT}${id}/share`, {}), + this.getFullEndpoint(`${VideosApiPath.ROOT}${id}${VideosApiPath.SHARE}`, {}), { method: HTTPMethod.GET, contentType: ContentType.JSON, diff --git a/frontend/src/bundles/home/helpers/create-url-token.ts b/frontend/src/bundles/home/helpers/create-url-token.ts index a39c76c60..0a7eb46c1 100644 --- a/frontend/src/bundles/home/helpers/create-url-token.ts +++ b/frontend/src/bundles/home/helpers/create-url-token.ts @@ -4,7 +4,7 @@ import { config } from '~/framework/config/config.js'; const createVideoUrl = (jwtToken: string): string => { const baseUrl = config.ENV.APP.ENVIRONMENT === AppEnvironment.PRODUCTION - ? 'http://bsa-2024-outreachvids-dev.eu-north-1.elasticbeanstalk.com' + ? config.ENV.DEPLOYMENT.URL : 'http://localhost:3000'; return `${baseUrl}/preview/${jwtToken}`; diff --git a/frontend/src/framework/config/base-config.package.ts b/frontend/src/framework/config/base-config.package.ts index f58044b4b..8c16f79f0 100644 --- a/frontend/src/framework/config/base-config.package.ts +++ b/frontend/src/framework/config/base-config.package.ts @@ -20,6 +20,9 @@ class BaseConfig implements Config { 'VITE_APP_SOCKET_ORIGIN_URL' ] as string, }, + DEPLOYMENT: { + URL: import.meta.env['DEPLOYMENT_URL'] as string, + }, }; } } diff --git a/frontend/src/framework/config/types/environment-schema.type.ts b/frontend/src/framework/config/types/environment-schema.type.ts index 92adb2fd0..ac7921fe5 100644 --- a/frontend/src/framework/config/types/environment-schema.type.ts +++ b/frontend/src/framework/config/types/environment-schema.type.ts @@ -9,6 +9,9 @@ type EnvironmentSchema = { ORIGIN_URL: string; SOCKET_ORIGIN_URL: string; }; + DEPLOYMENT: { + URL: string; + }; }; export { type EnvironmentSchema }; From 7d1c53602e8a22d7b514a99a36634fc5b3a19a6e Mon Sep 17 00:00:00 2001 From: stefano-lacorazza <112132737+stefano-lacorazza@users.noreply.github.com> Date: Thu, 26 Sep 2024 10:12:24 -0500 Subject: [PATCH 15/20] OV-377: * prettier --- backend/src/bundles/public-video/public-video.controller.ts | 5 ++--- frontend/src/bundles/common/api/video-api/videos-api.ts | 5 ++++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/backend/src/bundles/public-video/public-video.controller.ts b/backend/src/bundles/public-video/public-video.controller.ts index b9ae03978..f864f9128 100644 --- a/backend/src/bundles/public-video/public-video.controller.ts +++ b/backend/src/bundles/public-video/public-video.controller.ts @@ -33,9 +33,8 @@ class PublicVideoController extends BaseController { return { status: HTTPCode.OK, - payload: await this.publicVideoService.findUrlByToken( - videoTokenHeader, - ), + payload: + await this.publicVideoService.findUrlByToken(videoTokenHeader), }; } } diff --git a/frontend/src/bundles/common/api/video-api/videos-api.ts b/frontend/src/bundles/common/api/video-api/videos-api.ts index f40e8ed34..22238dec9 100644 --- a/frontend/src/bundles/common/api/video-api/videos-api.ts +++ b/frontend/src/bundles/common/api/video-api/videos-api.ts @@ -100,7 +100,10 @@ class VideosApi extends BaseHttpApi { public async getVideoIdJWT(id: string): Promise { const response = await this.load( - this.getFullEndpoint(`${VideosApiPath.ROOT}${id}${VideosApiPath.SHARE}`, {}), + this.getFullEndpoint( + `${VideosApiPath.ROOT}${id}${VideosApiPath.SHARE}`, + {}, + ), { method: HTTPMethod.GET, contentType: ContentType.JSON, From 3ae5db17874f62ce361e00d87ddf601e8641824d Mon Sep 17 00:00:00 2001 From: stefano-lacorazza <112132737+stefano-lacorazza@users.noreply.github.com> Date: Thu, 26 Sep 2024 14:01:20 -0500 Subject: [PATCH 16/20] OV-377: * changed baseurl to access env PUBLIC_URL --- frontend/src/bundles/home/helpers/create-url-token.ts | 6 +----- frontend/src/framework/config/base-config.package.ts | 2 +- .../src/framework/config/types/environment-schema.type.ts | 2 +- frontend/vite.config.ts | 1 + 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/frontend/src/bundles/home/helpers/create-url-token.ts b/frontend/src/bundles/home/helpers/create-url-token.ts index 0a7eb46c1..fc31d5e07 100644 --- a/frontend/src/bundles/home/helpers/create-url-token.ts +++ b/frontend/src/bundles/home/helpers/create-url-token.ts @@ -1,11 +1,7 @@ -import { AppEnvironment } from '~/bundles/common/enums/enums.js'; import { config } from '~/framework/config/config.js'; const createVideoUrl = (jwtToken: string): string => { - const baseUrl = - config.ENV.APP.ENVIRONMENT === AppEnvironment.PRODUCTION - ? config.ENV.DEPLOYMENT.URL - : 'http://localhost:3000'; + const baseUrl = config.ENV.DEPLOYMENT.PUBLIC_URL; return `${baseUrl}/preview/${jwtToken}`; }; diff --git a/frontend/src/framework/config/base-config.package.ts b/frontend/src/framework/config/base-config.package.ts index 8c16f79f0..56ba31483 100644 --- a/frontend/src/framework/config/base-config.package.ts +++ b/frontend/src/framework/config/base-config.package.ts @@ -21,7 +21,7 @@ class BaseConfig implements Config { ] as string, }, DEPLOYMENT: { - URL: import.meta.env['DEPLOYMENT_URL'] as string, + PUBLIC_URL: import.meta.env['PUBLIC_URL'] as string, }, }; } diff --git a/frontend/src/framework/config/types/environment-schema.type.ts b/frontend/src/framework/config/types/environment-schema.type.ts index ac7921fe5..cdbe7675a 100644 --- a/frontend/src/framework/config/types/environment-schema.type.ts +++ b/frontend/src/framework/config/types/environment-schema.type.ts @@ -10,7 +10,7 @@ type EnvironmentSchema = { SOCKET_ORIGIN_URL: string; }; DEPLOYMENT: { - URL: string; + PUBLIC_URL: string; }; }; diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index bfd716c3f..1c1f488b7 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -10,6 +10,7 @@ const config = ({ mode }: ConfigEnv): ReturnType => { VITE_APP_API_ORIGIN_URL, VITE_APP_PROXY_SERVER_URL, VITE_APP_SOCKET_ORIGIN_URL, + } = loadEnv(mode, process.cwd()); return defineConfig({ From d932a5a36789ee4d3e4fdb4e2d0b891fa0276ecd Mon Sep 17 00:00:00 2001 From: stefano-lacorazza <112132737+stefano-lacorazza@users.noreply.github.com> Date: Thu, 26 Sep 2024 14:02:40 -0500 Subject: [PATCH 17/20] OV-377: * changed baseurl to access env PUBLIC_URL --- frontend/.env.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/.env.example b/frontend/.env.example index 6092178be..d79b56559 100644 --- a/frontend/.env.example +++ b/frontend/.env.example @@ -14,5 +14,5 @@ VITE_APP_SOCKET_ORIGIN_URL=/socket.io # # DEPLOYMENT # -DEPLOYMENT_URL=http://bsa-2024-outreachvids-dev.eu-north-1.elasticbeanstalk.com +PUBLIC_URL=http://bsa-2024-outreachvids-dev.eu-north-1.elasticbeanstalk.com From 89fd45db291b2b2f213302b8f60ac1511da2b154 Mon Sep 17 00:00:00 2001 From: stefano-lacorazza <112132737+stefano-lacorazza@users.noreply.github.com> Date: Thu, 26 Sep 2024 14:04:45 -0500 Subject: [PATCH 18/20] OV-377: * prettier --- frontend/vite.config.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 1c1f488b7..bfd716c3f 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -10,7 +10,6 @@ const config = ({ mode }: ConfigEnv): ReturnType => { VITE_APP_API_ORIGIN_URL, VITE_APP_PROXY_SERVER_URL, VITE_APP_SOCKET_ORIGIN_URL, - } = loadEnv(mode, process.cwd()); return defineConfig({ From b8e9f782ff5b8d5570d50e9f3b95c5d3416990b7 Mon Sep 17 00:00:00 2001 From: stefano-lacorazza <112132737+stefano-lacorazza@users.noreply.github.com> Date: Fri, 27 Sep 2024 04:29:24 -0500 Subject: [PATCH 19/20] OV-377: - prettier --- frontend/src/bundles/home/store/actions.ts | 8 +++++++- frontend/src/bundles/home/store/home.ts | 5 +++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/frontend/src/bundles/home/store/actions.ts b/frontend/src/bundles/home/store/actions.ts index 19a7e5e29..be65b7615 100644 --- a/frontend/src/bundles/home/store/actions.ts +++ b/frontend/src/bundles/home/store/actions.ts @@ -57,4 +57,10 @@ const generateScriptSpeechPreview = createAsyncThunk< return speechApi.generateScriptSpeech(payload); }); -export { deleteVideo, generateScriptSpeechPreview, getJwt, loadUserVideos, loadVoices }; +export { + deleteVideo, + generateScriptSpeechPreview, + getJwt, + loadUserVideos, + loadVoices, +}; diff --git a/frontend/src/bundles/home/store/home.ts b/frontend/src/bundles/home/store/home.ts index acf10b4cd..d6e5c96e2 100644 --- a/frontend/src/bundles/home/store/home.ts +++ b/frontend/src/bundles/home/store/home.ts @@ -1,6 +1,7 @@ import { - deleteVideo, generateScriptSpeechPreview, -getJwt, + deleteVideo, + generateScriptSpeechPreview, + getJwt, loadUserVideos, } from './actions.js'; import { actions } from './slice.js'; From 34e108446e16819e0bcc15e43729fa7175d4ba7b Mon Sep 17 00:00:00 2001 From: stefano-lacorazza <112132737+stefano-lacorazza@users.noreply.github.com> Date: Fri, 27 Sep 2024 04:57:51 -0500 Subject: [PATCH 20/20] OV-377: * change .env variable --- frontend/.env.example | 2 +- frontend/src/bundles/home/helpers/create-url-token.ts | 1 - frontend/src/framework/config/base-config.package.ts | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/frontend/.env.example b/frontend/.env.example index d79b56559..2303ec6c4 100644 --- a/frontend/.env.example +++ b/frontend/.env.example @@ -14,5 +14,5 @@ VITE_APP_SOCKET_ORIGIN_URL=/socket.io # # DEPLOYMENT # -PUBLIC_URL=http://bsa-2024-outreachvids-dev.eu-north-1.elasticbeanstalk.com +VITE_APP_PUBLIC_URL=http://localhost:3000 diff --git a/frontend/src/bundles/home/helpers/create-url-token.ts b/frontend/src/bundles/home/helpers/create-url-token.ts index fc31d5e07..a4d778936 100644 --- a/frontend/src/bundles/home/helpers/create-url-token.ts +++ b/frontend/src/bundles/home/helpers/create-url-token.ts @@ -2,7 +2,6 @@ import { config } from '~/framework/config/config.js'; const createVideoUrl = (jwtToken: string): string => { const baseUrl = config.ENV.DEPLOYMENT.PUBLIC_URL; - return `${baseUrl}/preview/${jwtToken}`; }; diff --git a/frontend/src/framework/config/base-config.package.ts b/frontend/src/framework/config/base-config.package.ts index 56ba31483..a4a408ea2 100644 --- a/frontend/src/framework/config/base-config.package.ts +++ b/frontend/src/framework/config/base-config.package.ts @@ -21,7 +21,7 @@ class BaseConfig implements Config { ] as string, }, DEPLOYMENT: { - PUBLIC_URL: import.meta.env['PUBLIC_URL'] as string, + PUBLIC_URL: import.meta.env['VITE_APP_PUBLIC_URL'] as string, }, }; }