From e7c89cc3f3e69776c6ad62e62a52f8d2f12a81c1 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 14 Apr 2023 09:57:37 +0200 Subject: [PATCH] Allow to update a live with untouched privacy --- .../+video-edit/video-update.component.ts | 5 ++-- .../middlewares/validators/videos/videos.ts | 2 +- server/tests/api/check-params/live.ts | 8 ++++++- shared/core-utils/common/object.ts | 24 ++++++++++++++++++- 4 files changed, 34 insertions(+), 5 deletions(-) diff --git a/client/src/app/+videos/+video-edit/video-update.component.ts b/client/src/app/+videos/+video-edit/video-update.component.ts index 412b43967..b70270261 100644 --- a/client/src/app/+videos/+video-edit/video-update.component.ts +++ b/client/src/app/+videos/+video-edit/video-update.component.ts @@ -9,6 +9,7 @@ import { Video, VideoCaptionEdit, VideoCaptionService, VideoDetails, VideoEdit, import { LiveVideoService } from '@app/shared/shared-video-live' import { LoadingBarService } from '@ngx-loading-bar/core' import { logger } from '@root-helpers/logger' +import { pick, simpleObjectsDeepEqual } from '@shared/core-utils' import { LiveVideo, LiveVideoUpdate, VideoPrivacy } from '@shared/models' import { VideoSource } from '@shared/models/videos/video-source' import { hydrateFormFromVideo } from './shared/video-edit-utils' @@ -134,8 +135,8 @@ export class VideoUpdateComponent extends FormReactive implements OnInit { } // Don't update live attributes if they did not change - const liveChanged = Object.keys(liveVideoUpdate) - .some(key => this.liveVideo[key] !== liveVideoUpdate[key]) + const baseVideo = pick(this.liveVideo, Object.keys(liveVideoUpdate) as (keyof LiveVideoUpdate)[]) + const liveChanged = !simpleObjectsDeepEqual(baseVideo, liveVideoUpdate) if (!liveChanged) return of(undefined) return this.liveVideoService.updateLive(this.videoEdit.id, liveVideoUpdate) diff --git a/server/middlewares/validators/videos/videos.ts b/server/middlewares/validators/videos/videos.ts index ea6bd0721..d3014e8e7 100644 --- a/server/middlewares/validators/videos/videos.ts +++ b/server/middlewares/validators/videos/videos.ts @@ -234,7 +234,7 @@ const videosUpdateValidator = getCommonVideoEditAttributes().concat([ if (!await doesVideoExist(req.params.id, res)) return cleanUpReqFiles(req) const video = getVideoWithAttributes(res) - if (req.body.privacy && video.isLive && video.state !== VideoState.WAITING_FOR_LIVE) { + if (video.isLive && video.privacy !== req.body.privacy && video.state !== VideoState.WAITING_FOR_LIVE) { return res.fail({ message: 'Cannot update privacy of a live that has already started' }) } diff --git a/server/tests/api/check-params/live.ts b/server/tests/api/check-params/live.ts index 81f10ed8e..2dc735c23 100644 --- a/server/tests/api/check-params/live.ts +++ b/server/tests/api/check-params/live.ts @@ -553,9 +553,15 @@ describe('Test video lives API validator', function () { const ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: live.rtmpUrl, streamKey: live.streamKey }) await command.waitUntilPublished({ videoId: video.id }) + await server.videos.update({ id: video.id, - attributes: { privacy: VideoPrivacy.PUBLIC }, + attributes: { privacy: VideoPrivacy.PUBLIC } // Same privacy, it's fine + }) + + await server.videos.update({ + id: video.id, + attributes: { privacy: VideoPrivacy.UNLISTED }, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) diff --git a/shared/core-utils/common/object.ts b/shared/core-utils/common/object.ts index 7f1f147f4..9780b2594 100644 --- a/shared/core-utils/common/object.ts +++ b/shared/core-utils/common/object.ts @@ -45,10 +45,32 @@ function shallowCopy (o: T): T { return Object.assign(Object.create(Object.getPrototypeOf(o)), o) } +function simpleObjectsDeepEqual (a: any, b: any) { + if (a === b) return true + + if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null) { + return false + } + + const keysA = Object.keys(a) + const keysB = Object.keys(b) + + if (keysA.length !== keysB.length) return false + + for (const key of keysA) { + if (!keysB.includes(key)) return false + + if (!simpleObjectsDeepEqual(a[key], b[key])) return false + } + + return true +} + export { pick, omit, getKeys, shallowCopy, - sortObjectComparator + sortObjectComparator, + simpleObjectsDeepEqual }