From a37e9e74ff07b057370d1ed6c0b391a02be8a6d2 Mon Sep 17 00:00:00 2001 From: kontrollanten <6680299+kontrollanten@users.noreply.github.com> Date: Mon, 13 Dec 2021 15:29:13 +0100 Subject: Give moderators access to edit channels (#4608) * give admins access to edit all channels closes #4598 * test(channels): +admin update another users channel * Fix tests * fix(server): delete another users channel Since the channel owner isn't necessary the auth user we need to check the right account whether it's the last video or not. * REMOVE_ANY_VIDEO_CHANNEL > MANAGE_ANY_VIDEO_CHANNEL Merge REMOVE_ANY_VIDEO_CHANNEL and MANY_VIDEO_CHANNELS to MANAGE_ANY_VIDEO_CHANNEL. * user-right: moderator can't manage admins channel * client: MyVideoChannelCreateComponent > VideoChannelCreateComponent * client: MyVideoChannelEdit > VideoChannelEdit * Revert "user-right: moderator can't manage admins channel" This reverts commit 2c627c154e2bfe6af2e0f45efb27faf4117572f3. * server: clean dupl validator functionality * fix ensureUserCanManageChannel usage It's not async anymore. * server: merge channel validator middleares ensureAuthUserOwnsChannelValidator & ensureUserCanManageChannel gets merged into one middleware. * client(VideoChannelEdit): redirect to prev route * fix(VideoChannels): handle anon users * client: new routes for create/update channel * Refactor channel validators Co-authored-by: Chocobozzz --- client/src/app/+manage/manage-routing.module.ts | 31 ++++ client/src/app/+manage/manage.module.ts | 31 ++++ .../video-channel-create.component.ts | 120 +++++++++++++ .../video-channel-edit.component.html | 96 +++++++++++ .../video-channel-edit.component.scss | 77 +++++++++ .../video-channel-edit/video-channel-edit.ts | 18 ++ .../video-channel-update.component.ts | 189 +++++++++++++++++++++ .../my-video-channel-create.component.ts | 120 ------------- .../my-video-channel-edit.component.html | 112 ------------ .../my-video-channel-edit.component.scss | 73 -------- .../+my-video-channels/my-video-channel-edit.ts | 18 -- .../my-video-channel-update.component.ts | 188 -------------------- .../my-video-channels-routing.module.ts | 18 +- .../my-video-channels.component.html | 4 +- .../+my-video-channels/my-video-channels.module.ts | 8 +- .../+video-channels/video-channels.component.html | 4 +- .../+video-channels/video-channels.component.ts | 10 +- .../app/+video-channels/video-channels.module.ts | 2 + client/src/app/app-routing.module.ts | 6 +- client/src/app/core/routing/redirect.service.ts | 6 +- 20 files changed, 590 insertions(+), 541 deletions(-) create mode 100644 client/src/app/+manage/manage-routing.module.ts create mode 100644 client/src/app/+manage/manage.module.ts create mode 100644 client/src/app/+manage/video-channel-edit/video-channel-create.component.ts create mode 100644 client/src/app/+manage/video-channel-edit/video-channel-edit.component.html create mode 100644 client/src/app/+manage/video-channel-edit/video-channel-edit.component.scss create mode 100644 client/src/app/+manage/video-channel-edit/video-channel-edit.ts create mode 100644 client/src/app/+manage/video-channel-edit/video-channel-update.component.ts delete mode 100644 client/src/app/+my-library/+my-video-channels/my-video-channel-create.component.ts delete mode 100644 client/src/app/+my-library/+my-video-channels/my-video-channel-edit.component.html delete mode 100644 client/src/app/+my-library/+my-video-channels/my-video-channel-edit.component.scss delete mode 100644 client/src/app/+my-library/+my-video-channels/my-video-channel-edit.ts delete mode 100644 client/src/app/+my-library/+my-video-channels/my-video-channel-update.component.ts (limited to 'client/src/app') diff --git a/client/src/app/+manage/manage-routing.module.ts b/client/src/app/+manage/manage-routing.module.ts new file mode 100644 index 000000000..14ae4f1e0 --- /dev/null +++ b/client/src/app/+manage/manage-routing.module.ts @@ -0,0 +1,31 @@ +import { NgModule } from '@angular/core' +import { RouterModule, Routes } from '@angular/router' +import { VideoChannelCreateComponent } from './video-channel-edit/video-channel-create.component' +import { VideoChannelUpdateComponent } from './video-channel-edit/video-channel-update.component' + +const manageRoutes: Routes = [ + { + path: 'create', + component: VideoChannelCreateComponent, + data: { + meta: { + title: $localize`Create a new video channel` + } + } + }, + { + path: 'update/:videoChannelName', + component: VideoChannelUpdateComponent, + data: { + meta: { + title: $localize`Update video channel` + } + } + } +] + +@NgModule({ + imports: [ RouterModule.forChild(manageRoutes) ], + exports: [ RouterModule ] +}) +export class ManageRoutingModule {} diff --git a/client/src/app/+manage/manage.module.ts b/client/src/app/+manage/manage.module.ts new file mode 100644 index 000000000..28939ec5a --- /dev/null +++ b/client/src/app/+manage/manage.module.ts @@ -0,0 +1,31 @@ +import { NgModule } from '@angular/core' +import { SharedFormModule } from '@app/shared/shared-forms' +import { SharedGlobalIconModule } from '@app/shared/shared-icons' +import { SharedMainModule } from '@app/shared/shared-main' +import { SharedActorImageModule } from '../shared/shared-actor-image/shared-actor-image.module' +import { SharedActorImageEditModule } from '@app/shared/shared-actor-image-edit' +import { VideoChannelCreateComponent } from './video-channel-edit/video-channel-create.component' +import { VideoChannelUpdateComponent } from './video-channel-edit/video-channel-update.component' +import { ManageRoutingModule } from './manage-routing.module' + +@NgModule({ + imports: [ + ManageRoutingModule, + SharedMainModule, + SharedFormModule, + SharedGlobalIconModule, + SharedActorImageModule, + SharedActorImageEditModule + ], + + declarations: [ + VideoChannelCreateComponent, + VideoChannelUpdateComponent + ], + + exports: [ + ], + + providers: [] +}) +export class ManageModule { } diff --git a/client/src/app/+manage/video-channel-edit/video-channel-create.component.ts b/client/src/app/+manage/video-channel-edit/video-channel-create.component.ts new file mode 100644 index 000000000..5f8e0278e --- /dev/null +++ b/client/src/app/+manage/video-channel-edit/video-channel-create.component.ts @@ -0,0 +1,120 @@ +import { of } from 'rxjs' +import { switchMap } from 'rxjs/operators' +import { Component, OnInit } from '@angular/core' +import { Router } from '@angular/router' +import { AuthService, Notifier } from '@app/core' +import { + VIDEO_CHANNEL_DESCRIPTION_VALIDATOR, + VIDEO_CHANNEL_DISPLAY_NAME_VALIDATOR, + VIDEO_CHANNEL_NAME_VALIDATOR, + VIDEO_CHANNEL_SUPPORT_VALIDATOR +} from '@app/shared/form-validators/video-channel-validators' +import { FormValidatorService } from '@app/shared/shared-forms' +import { VideoChannel, VideoChannelService } from '@app/shared/shared-main' +import { HttpStatusCode, VideoChannelCreate } from '@shared/models' +import { VideoChannelEdit } from './video-channel-edit' + +@Component({ + templateUrl: './video-channel-edit.component.html', + styleUrls: [ './video-channel-edit.component.scss' ] +}) +export class VideoChannelCreateComponent extends VideoChannelEdit implements OnInit { + error: string + videoChannel = new VideoChannel({}) + + private avatar: FormData + private banner: FormData + + constructor ( + protected formValidatorService: FormValidatorService, + private authService: AuthService, + private notifier: Notifier, + private router: Router, + private videoChannelService: VideoChannelService + ) { + super() + } + + ngOnInit () { + this.buildForm({ + name: VIDEO_CHANNEL_NAME_VALIDATOR, + 'display-name': VIDEO_CHANNEL_DISPLAY_NAME_VALIDATOR, + description: VIDEO_CHANNEL_DESCRIPTION_VALIDATOR, + support: VIDEO_CHANNEL_SUPPORT_VALIDATOR + }) + } + + formValidated () { + this.error = undefined + + const body = this.form.value + const videoChannelCreate: VideoChannelCreate = { + name: body.name, + displayName: body['display-name'], + description: body.description || null, + support: body.support || null + } + + this.videoChannelService.createVideoChannel(videoChannelCreate) + .pipe( + switchMap(() => this.uploadAvatar()), + switchMap(() => this.uploadBanner()) + ).subscribe({ + next: () => { + this.authService.refreshUserInformation() + + this.notifier.success($localize`Video channel ${videoChannelCreate.displayName} created.`) + this.router.navigate([ '/my-library', 'video-channels' ]) + }, + + error: err => { + if (err.status === HttpStatusCode.CONFLICT_409) { + this.error = $localize`This name already exists on this instance.` + return + } + + this.error = err.message + } + }) + } + + onAvatarChange (formData: FormData) { + this.avatar = formData + } + + onAvatarDelete () { + this.avatar = null + } + + onBannerChange (formData: FormData) { + this.banner = formData + } + + onBannerDelete () { + this.banner = null + } + + isCreation () { + return true + } + + getFormButtonTitle () { + return $localize`Create` + } + + getUsername () { + return this.form.value.name + } + + private uploadAvatar () { + if (!this.avatar) return of(undefined) + + return this.videoChannelService.changeVideoChannelImage(this.getUsername(), this.avatar, 'avatar') + } + + private uploadBanner () { + if (!this.banner) return of(undefined) + + return this.videoChannelService.changeVideoChannelImage(this.getUsername(), this.banner, 'banner') + } +} diff --git a/client/src/app/+manage/video-channel-edit/video-channel-edit.component.html b/client/src/app/+manage/video-channel-edit/video-channel-edit.component.html new file mode 100644 index 000000000..3751747a9 --- /dev/null +++ b/client/src/app/+manage/video-channel-edit/video-channel-edit.component.html @@ -0,0 +1,96 @@ +
{{ error }}
+ +
+
+ +
+
+
NEW CHANNEL
+
CHANNEL
+
+ +
+
Banner image of the channel
+ + + + + +
+ +
+ +
+ @{{ instanceHost }} +
+
+
+ {{ formErrors['name'] }} +
+
+ +
+ + +
+ {{ formErrors['display-name'] }} +
+
+ +
+ + +
+ {{ formErrors.description }} +
+
+ +
+ + + +
+ {{ formErrors.support }} +
+
+ +
+ +
+ +
+
+ +
+
+
+ +
+
+
+
\ No newline at end of file diff --git a/client/src/app/+manage/video-channel-edit/video-channel-edit.component.scss b/client/src/app/+manage/video-channel-edit/video-channel-edit.component.scss new file mode 100644 index 000000000..d010d6277 --- /dev/null +++ b/client/src/app/+manage/video-channel-edit/video-channel-edit.component.scss @@ -0,0 +1,77 @@ +@use '_variables' as *; +@use '_mixins' as *; + +.margin-content { + padding-top: 20px; +} + +label { + font-weight: $font-regular; + font-size: 100%; +} + +.video-channel-title { + @include settings-big-title; +} + +my-actor-avatar-edit, +my-actor-banner-edit { + display: block; + margin-bottom: 20px; +} + +my-actor-banner-edit { + max-width: 500px; +} + +.input-group { + @include peertube-input-group(fit-content); +} + +.input-group-append { + height: 30px; +} + +input { + &[type=text] { + @include peertube-input-text(340px); + + display: block; + + &#name { + width: auto; + flex-grow: 1; + } + } + + &[type=submit] { + @include peertube-button; + @include orange-button; + @include margin-left(auto); + } +} + +textarea { + @include peertube-textarea(500px, 150px); + + display: block; +} + +.peertube-select-container { + @include peertube-select-container(340px); +} + +.breadcrumb { + @include breadcrumb; +} + +@media screen and (max-width: $small-view) { + input[type=text]#name { + width: auto !important; + } + + label[for=name] + div, + textarea { + width: 100%; + } +} diff --git a/client/src/app/+manage/video-channel-edit/video-channel-edit.ts b/client/src/app/+manage/video-channel-edit/video-channel-edit.ts new file mode 100644 index 000000000..963b4cbbe --- /dev/null +++ b/client/src/app/+manage/video-channel-edit/video-channel-edit.ts @@ -0,0 +1,18 @@ +import { FormReactive } from '@app/shared/shared-forms' +import { VideoChannel } from '@app/shared/shared-main' + +export abstract class VideoChannelEdit extends FormReactive { + videoChannel: VideoChannel + + abstract isCreation (): boolean + abstract getFormButtonTitle (): string + + get instanceHost () { + return window.location.host + } + + // Should be implemented by the child + isBulkUpdateVideosDisplayed () { + return false + } +} diff --git a/client/src/app/+manage/video-channel-edit/video-channel-update.component.ts b/client/src/app/+manage/video-channel-edit/video-channel-update.component.ts new file mode 100644 index 000000000..21b6167b2 --- /dev/null +++ b/client/src/app/+manage/video-channel-edit/video-channel-update.component.ts @@ -0,0 +1,189 @@ +import { Subscription } from 'rxjs' +import { HttpErrorResponse } from '@angular/common/http' +import { Component, OnDestroy, OnInit } from '@angular/core' +import { ActivatedRoute, Router } from '@angular/router' +import { AuthService, Notifier, RedirectService, ServerService } from '@app/core' +import { genericUploadErrorHandler } from '@app/helpers' +import { + VIDEO_CHANNEL_DESCRIPTION_VALIDATOR, + VIDEO_CHANNEL_DISPLAY_NAME_VALIDATOR, + VIDEO_CHANNEL_SUPPORT_VALIDATOR +} from '@app/shared/form-validators/video-channel-validators' +import { FormValidatorService } from '@app/shared/shared-forms' +import { VideoChannel, VideoChannelService } from '@app/shared/shared-main' +import { HTMLServerConfig, VideoChannelUpdate } from '@shared/models' +import { VideoChannelEdit } from './video-channel-edit' + +@Component({ + selector: 'my-video-channel-update', + templateUrl: './video-channel-edit.component.html', + styleUrls: [ './video-channel-edit.component.scss' ] +}) +export class VideoChannelUpdateComponent extends VideoChannelEdit implements OnInit, OnDestroy { + error: string + videoChannel: VideoChannel + + private paramsSub: Subscription + private oldSupportField: string + private serverConfig: HTMLServerConfig + + constructor ( + protected formValidatorService: FormValidatorService, + private authService: AuthService, + private notifier: Notifier, + private router: Router, + private route: ActivatedRoute, + private videoChannelService: VideoChannelService, + private serverService: ServerService, + private redirectService: RedirectService + ) { + super() + } + + ngOnInit () { + this.serverConfig = this.serverService.getHTMLConfig() + + this.buildForm({ + 'display-name': VIDEO_CHANNEL_DISPLAY_NAME_VALIDATOR, + description: VIDEO_CHANNEL_DESCRIPTION_VALIDATOR, + support: VIDEO_CHANNEL_SUPPORT_VALIDATOR, + bulkVideosSupportUpdate: null + }) + + this.paramsSub = this.route.params.subscribe(routeParams => { + const videoChannelName = routeParams['videoChannelName'] + + this.videoChannelService.getVideoChannel(videoChannelName) + .subscribe({ + next: videoChannelToUpdate => { + this.videoChannel = videoChannelToUpdate + + this.oldSupportField = videoChannelToUpdate.support + + this.form.patchValue({ + 'display-name': videoChannelToUpdate.displayName, + description: videoChannelToUpdate.description, + support: videoChannelToUpdate.support + }) + }, + + error: err => { + this.error = err.message + } + }) + }) + } + + ngOnDestroy () { + if (this.paramsSub) this.paramsSub.unsubscribe() + } + + formValidated () { + this.error = undefined + + const body = this.form.value + const videoChannelUpdate: VideoChannelUpdate = { + displayName: body['display-name'], + description: body.description || null, + support: body.support || null, + bulkVideosSupportUpdate: body.bulkVideosSupportUpdate || false + } + + this.videoChannelService.updateVideoChannel(this.videoChannel.name, videoChannelUpdate) + .subscribe({ + next: () => { + this.authService.refreshUserInformation() + + this.notifier.success($localize`Video channel ${videoChannelUpdate.displayName} updated.`) + + this.redirectService.redirectToPreviousRoute([ '/c', this.videoChannel.name ]) + }, + + error: err => { + this.error = err.message + } + }) + } + + onAvatarChange (formData: FormData) { + this.videoChannelService.changeVideoChannelImage(this.videoChannel.name, formData, 'avatar') + .subscribe({ + next: data => { + this.notifier.success($localize`Avatar changed.`) + + this.videoChannel.updateAvatar(data.avatar) + }, + + error: (err: HttpErrorResponse) => genericUploadErrorHandler({ + err, + name: $localize`avatar`, + notifier: this.notifier + }) + }) + } + + onAvatarDelete () { + this.videoChannelService.deleteVideoChannelImage(this.videoChannel.name, 'avatar') + .subscribe({ + next: () => { + this.notifier.success($localize`Avatar deleted.`) + + this.videoChannel.resetAvatar() + }, + + error: err => this.notifier.error(err.message) + }) + } + + onBannerChange (formData: FormData) { + this.videoChannelService.changeVideoChannelImage(this.videoChannel.name, formData, 'banner') + .subscribe({ + next: data => { + this.notifier.success($localize`Banner changed.`) + + this.videoChannel.updateBanner(data.banner) + }, + + error: (err: HttpErrorResponse) => genericUploadErrorHandler({ + err, + name: $localize`banner`, + notifier: this.notifier + }) + }) + } + + onBannerDelete () { + this.videoChannelService.deleteVideoChannelImage(this.videoChannel.name, 'banner') + .subscribe({ + next: () => { + this.notifier.success($localize`Banner deleted.`) + + this.videoChannel.resetBanner() + }, + + error: err => this.notifier.error(err.message) + }) + } + + get maxAvatarSize () { + return this.serverConfig.avatar.file.size.max + } + + get avatarExtensions () { + return this.serverConfig.avatar.file.extensions.join(',') + } + + isCreation () { + return false + } + + getFormButtonTitle () { + return $localize`Update` + } + + isBulkUpdateVideosDisplayed () { + if (this.oldSupportField === undefined) return false + + return this.oldSupportField !== this.form.value['support'] + } +} diff --git a/client/src/app/+my-library/+my-video-channels/my-video-channel-create.component.ts b/client/src/app/+my-library/+my-video-channels/my-video-channel-create.component.ts deleted file mode 100644 index fd00720d8..000000000 --- a/client/src/app/+my-library/+my-video-channels/my-video-channel-create.component.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { of } from 'rxjs' -import { switchMap } from 'rxjs/operators' -import { Component, OnInit } from '@angular/core' -import { Router } from '@angular/router' -import { AuthService, Notifier } from '@app/core' -import { - VIDEO_CHANNEL_DESCRIPTION_VALIDATOR, - VIDEO_CHANNEL_DISPLAY_NAME_VALIDATOR, - VIDEO_CHANNEL_NAME_VALIDATOR, - VIDEO_CHANNEL_SUPPORT_VALIDATOR -} from '@app/shared/form-validators/video-channel-validators' -import { FormValidatorService } from '@app/shared/shared-forms' -import { VideoChannel, VideoChannelService } from '@app/shared/shared-main' -import { HttpStatusCode, VideoChannelCreate } from '@shared/models' -import { MyVideoChannelEdit } from './my-video-channel-edit' - -@Component({ - templateUrl: './my-video-channel-edit.component.html', - styleUrls: [ './my-video-channel-edit.component.scss' ] -}) -export class MyVideoChannelCreateComponent extends MyVideoChannelEdit implements OnInit { - error: string - videoChannel = new VideoChannel({}) - - private avatar: FormData - private banner: FormData - - constructor ( - protected formValidatorService: FormValidatorService, - private authService: AuthService, - private notifier: Notifier, - private router: Router, - private videoChannelService: VideoChannelService - ) { - super() - } - - ngOnInit () { - this.buildForm({ - name: VIDEO_CHANNEL_NAME_VALIDATOR, - 'display-name': VIDEO_CHANNEL_DISPLAY_NAME_VALIDATOR, - description: VIDEO_CHANNEL_DESCRIPTION_VALIDATOR, - support: VIDEO_CHANNEL_SUPPORT_VALIDATOR - }) - } - - formValidated () { - this.error = undefined - - const body = this.form.value - const videoChannelCreate: VideoChannelCreate = { - name: body.name, - displayName: body['display-name'], - description: body.description || null, - support: body.support || null - } - - this.videoChannelService.createVideoChannel(videoChannelCreate) - .pipe( - switchMap(() => this.uploadAvatar()), - switchMap(() => this.uploadBanner()) - ).subscribe({ - next: () => { - this.authService.refreshUserInformation() - - this.notifier.success($localize`Video channel ${videoChannelCreate.displayName} created.`) - this.router.navigate([ '/my-library', 'video-channels' ]) - }, - - error: err => { - if (err.status === HttpStatusCode.CONFLICT_409) { - this.error = $localize`This name already exists on this instance.` - return - } - - this.error = err.message - } - }) - } - - onAvatarChange (formData: FormData) { - this.avatar = formData - } - - onAvatarDelete () { - this.avatar = null - } - - onBannerChange (formData: FormData) { - this.banner = formData - } - - onBannerDelete () { - this.banner = null - } - - isCreation () { - return true - } - - getFormButtonTitle () { - return $localize`Create` - } - - getUsername () { - return this.form.value.name - } - - private uploadAvatar () { - if (!this.avatar) return of(undefined) - - return this.videoChannelService.changeVideoChannelImage(this.getUsername(), this.avatar, 'avatar') - } - - private uploadBanner () { - if (!this.banner) return of(undefined) - - return this.videoChannelService.changeVideoChannelImage(this.getUsername(), this.banner, 'banner') - } -} diff --git a/client/src/app/+my-library/+my-video-channels/my-video-channel-edit.component.html b/client/src/app/+my-library/+my-video-channels/my-video-channel-edit.component.html deleted file mode 100644 index 2910dffad..000000000 --- a/client/src/app/+my-library/+my-video-channels/my-video-channel-edit.component.html +++ /dev/null @@ -1,112 +0,0 @@ - - -
{{ error }}
- -
- -
-
-
NEW CHANNEL
-
CHANNEL
-
- -
-
Banner image of your channel
- - - - - -
- -
- -
- @{{ instanceHost }} -
-
-
- {{ formErrors['name'] }} -
-
- -
- - -
- {{ formErrors['display-name'] }} -
-
- -
- - -
- {{ formErrors.description }} -
-
- -
- - - -
- {{ formErrors.support }} -
-
- -
- -
- -
-
- -
-
-
- -
-
-
diff --git a/client/src/app/+my-library/+my-video-channels/my-video-channel-edit.component.scss b/client/src/app/+my-library/+my-video-channels/my-video-channel-edit.component.scss deleted file mode 100644 index d8bfe71b6..000000000 --- a/client/src/app/+my-library/+my-video-channels/my-video-channel-edit.component.scss +++ /dev/null @@ -1,73 +0,0 @@ -@use '_variables' as *; -@use '_mixins' as *; - -label { - font-weight: $font-regular; - font-size: 100%; -} - -.video-channel-title { - @include settings-big-title; -} - -my-actor-avatar-edit, -my-actor-banner-edit { - display: block; - margin-bottom: 20px; -} - -my-actor-banner-edit { - max-width: 500px; -} - -.input-group { - @include peertube-input-group(fit-content); -} - -.input-group-append { - height: 30px; -} - -input { - &[type=text] { - @include peertube-input-text(340px); - - display: block; - - &#name { - width: auto; - flex-grow: 1; - } - } - - &[type=submit] { - @include peertube-button; - @include orange-button; - @include margin-left(auto); - } -} - -textarea { - @include peertube-textarea(500px, 150px); - - display: block; -} - -.peertube-select-container { - @include peertube-select-container(340px); -} - -.breadcrumb { - @include breadcrumb; -} - -@media screen and (max-width: $small-view) { - input[type=text]#name { - width: auto !important; - } - - label[for=name] + div, - textarea { - width: 100%; - } -} diff --git a/client/src/app/+my-library/+my-video-channels/my-video-channel-edit.ts b/client/src/app/+my-library/+my-video-channels/my-video-channel-edit.ts deleted file mode 100644 index 33bb90f14..000000000 --- a/client/src/app/+my-library/+my-video-channels/my-video-channel-edit.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { FormReactive } from '@app/shared/shared-forms' -import { VideoChannel } from '@app/shared/shared-main' - -export abstract class MyVideoChannelEdit extends FormReactive { - videoChannel: VideoChannel - - abstract isCreation (): boolean - abstract getFormButtonTitle (): string - - get instanceHost () { - return window.location.host - } - - // Should be implemented by the child - isBulkUpdateVideosDisplayed () { - return false - } -} diff --git a/client/src/app/+my-library/+my-video-channels/my-video-channel-update.component.ts b/client/src/app/+my-library/+my-video-channels/my-video-channel-update.component.ts deleted file mode 100644 index f9521b8b5..000000000 --- a/client/src/app/+my-library/+my-video-channels/my-video-channel-update.component.ts +++ /dev/null @@ -1,188 +0,0 @@ -import { Subscription } from 'rxjs' -import { HttpErrorResponse } from '@angular/common/http' -import { Component, OnDestroy, OnInit } from '@angular/core' -import { ActivatedRoute, Router } from '@angular/router' -import { AuthService, Notifier, ServerService } from '@app/core' -import { genericUploadErrorHandler } from '@app/helpers' -import { - VIDEO_CHANNEL_DESCRIPTION_VALIDATOR, - VIDEO_CHANNEL_DISPLAY_NAME_VALIDATOR, - VIDEO_CHANNEL_SUPPORT_VALIDATOR -} from '@app/shared/form-validators/video-channel-validators' -import { FormValidatorService } from '@app/shared/shared-forms' -import { VideoChannel, VideoChannelService } from '@app/shared/shared-main' -import { HTMLServerConfig, VideoChannelUpdate } from '@shared/models' -import { MyVideoChannelEdit } from './my-video-channel-edit' - -@Component({ - selector: 'my-video-channel-update', - templateUrl: './my-video-channel-edit.component.html', - styleUrls: [ './my-video-channel-edit.component.scss' ] -}) -export class MyVideoChannelUpdateComponent extends MyVideoChannelEdit implements OnInit, OnDestroy { - error: string - videoChannel: VideoChannel - - private paramsSub: Subscription - private oldSupportField: string - private serverConfig: HTMLServerConfig - - constructor ( - protected formValidatorService: FormValidatorService, - private authService: AuthService, - private notifier: Notifier, - private router: Router, - private route: ActivatedRoute, - private videoChannelService: VideoChannelService, - private serverService: ServerService - ) { - super() - } - - ngOnInit () { - this.serverConfig = this.serverService.getHTMLConfig() - - this.buildForm({ - 'display-name': VIDEO_CHANNEL_DISPLAY_NAME_VALIDATOR, - description: VIDEO_CHANNEL_DESCRIPTION_VALIDATOR, - support: VIDEO_CHANNEL_SUPPORT_VALIDATOR, - bulkVideosSupportUpdate: null - }) - - this.paramsSub = this.route.params.subscribe(routeParams => { - const videoChannelId = routeParams['videoChannelId'] - - this.videoChannelService.getVideoChannel(videoChannelId) - .subscribe({ - next: videoChannelToUpdate => { - this.videoChannel = videoChannelToUpdate - - this.oldSupportField = videoChannelToUpdate.support - - this.form.patchValue({ - 'display-name': videoChannelToUpdate.displayName, - description: videoChannelToUpdate.description, - support: videoChannelToUpdate.support - }) - }, - - error: err => { - this.error = err.message - } - }) - }) - } - - ngOnDestroy () { - if (this.paramsSub) this.paramsSub.unsubscribe() - } - - formValidated () { - this.error = undefined - - const body = this.form.value - const videoChannelUpdate: VideoChannelUpdate = { - displayName: body['display-name'], - description: body.description || null, - support: body.support || null, - bulkVideosSupportUpdate: body.bulkVideosSupportUpdate || false - } - - this.videoChannelService.updateVideoChannel(this.videoChannel.name, videoChannelUpdate) - .subscribe({ - next: () => { - this.authService.refreshUserInformation() - - this.notifier.success($localize`Video channel ${videoChannelUpdate.displayName} updated.`) - - this.router.navigate([ '/my-library', 'video-channels' ]) - }, - - error: err => { - this.error = err.message - } - }) - } - - onAvatarChange (formData: FormData) { - this.videoChannelService.changeVideoChannelImage(this.videoChannel.name, formData, 'avatar') - .subscribe({ - next: data => { - this.notifier.success($localize`Avatar changed.`) - - this.videoChannel.updateAvatar(data.avatar) - }, - - error: (err: HttpErrorResponse) => genericUploadErrorHandler({ - err, - name: $localize`avatar`, - notifier: this.notifier - }) - }) - } - - onAvatarDelete () { - this.videoChannelService.deleteVideoChannelImage(this.videoChannel.name, 'avatar') - .subscribe({ - next: () => { - this.notifier.success($localize`Avatar deleted.`) - - this.videoChannel.resetAvatar() - }, - - error: err => this.notifier.error(err.message) - }) - } - - onBannerChange (formData: FormData) { - this.videoChannelService.changeVideoChannelImage(this.videoChannel.name, formData, 'banner') - .subscribe({ - next: data => { - this.notifier.success($localize`Banner changed.`) - - this.videoChannel.updateBanner(data.banner) - }, - - error: (err: HttpErrorResponse) => genericUploadErrorHandler({ - err, - name: $localize`banner`, - notifier: this.notifier - }) - }) - } - - onBannerDelete () { - this.videoChannelService.deleteVideoChannelImage(this.videoChannel.name, 'banner') - .subscribe({ - next: () => { - this.notifier.success($localize`Banner deleted.`) - - this.videoChannel.resetBanner() - }, - - error: err => this.notifier.error(err.message) - }) - } - - get maxAvatarSize () { - return this.serverConfig.avatar.file.size.max - } - - get avatarExtensions () { - return this.serverConfig.avatar.file.extensions.join(',') - } - - isCreation () { - return false - } - - getFormButtonTitle () { - return $localize`Update` - } - - isBulkUpdateVideosDisplayed () { - if (this.oldSupportField === undefined) return false - - return this.oldSupportField !== this.form.value['support'] - } -} diff --git a/client/src/app/+my-library/+my-video-channels/my-video-channels-routing.module.ts b/client/src/app/+my-library/+my-video-channels/my-video-channels-routing.module.ts index 6b8efad0b..b4962ed35 100644 --- a/client/src/app/+my-library/+my-video-channels/my-video-channels-routing.module.ts +++ b/client/src/app/+my-library/+my-video-channels/my-video-channels-routing.module.ts @@ -1,7 +1,5 @@ import { NgModule } from '@angular/core' import { RouterModule, Routes } from '@angular/router' -import { MyVideoChannelUpdateComponent } from './my-video-channel-update.component' -import { MyVideoChannelCreateComponent } from './my-video-channel-create.component' import { MyVideoChannelsComponent } from './my-video-channels.component' const myVideoChannelsRoutes: Routes = [ @@ -16,21 +14,11 @@ const myVideoChannelsRoutes: Routes = [ }, { path: 'create', - component: MyVideoChannelCreateComponent, - data: { - meta: { - title: $localize`Create a new video channel` - } - } + redirectTo: '/manage/create' }, { - path: 'update/:videoChannelId', - component: MyVideoChannelUpdateComponent, - data: { - meta: { - title: $localize`Update video channel` - } - } + path: 'update/:videoChannelName', + redirectTo: '/manage/update/:videoChannelName' } ] diff --git a/client/src/app/+my-library/+my-video-channels/my-video-channels.component.html b/client/src/app/+my-library/+my-video-channels/my-video-channels.component.html index bbe583971..77947315b 100644 --- a/client/src/app/+my-library/+my-video-channels/my-video-channels.component.html +++ b/client/src/app/+my-library/+my-video-channels/my-video-channels.component.html @@ -9,7 +9,7 @@
- + Create video channel @@ -37,7 +37,7 @@
{videoChannel.videosCount, plural, =0 {No videos} =1 {1 video} other {{{ videoChannel.videosCount }} videos}}
- +
diff --git a/client/src/app/+my-library/+my-video-channels/my-video-channels.module.ts b/client/src/app/+my-library/+my-video-channels/my-video-channels.module.ts index c775bfdee..a17eb9f10 100644 --- a/client/src/app/+my-library/+my-video-channels/my-video-channels.module.ts +++ b/client/src/app/+my-library/+my-video-channels/my-video-channels.module.ts @@ -1,11 +1,8 @@ import { ChartModule } from 'primeng/chart' import { NgModule } from '@angular/core' -import { SharedActorImageEditModule } from '@app/shared/shared-actor-image-edit' import { SharedFormModule } from '@app/shared/shared-forms' import { SharedGlobalIconModule } from '@app/shared/shared-icons' import { SharedMainModule } from '@app/shared/shared-main' -import { MyVideoChannelCreateComponent } from './my-video-channel-create.component' -import { MyVideoChannelUpdateComponent } from './my-video-channel-update.component' import { MyVideoChannelsRoutingModule } from './my-video-channels-routing.module' import { MyVideoChannelsComponent } from './my-video-channels.component' import { SharedActorImageModule } from '@app/shared/shared-actor-image/shared-actor-image.module' @@ -19,14 +16,11 @@ import { SharedActorImageModule } from '@app/shared/shared-actor-image/shared-ac SharedMainModule, SharedFormModule, SharedGlobalIconModule, - SharedActorImageEditModule, SharedActorImageModule ], declarations: [ - MyVideoChannelsComponent, - MyVideoChannelCreateComponent, - MyVideoChannelUpdateComponent + MyVideoChannelsComponent ], exports: [], diff --git a/client/src/app/+video-channels/video-channels.component.html b/client/src/app/+video-channels/video-channels.component.html index aec2e373c..212e2f867 100644 --- a/client/src/app/+video-channels/video-channels.component.html +++ b/client/src/app/+video-channels/video-channels.component.html @@ -6,11 +6,11 @@
- + Manage channel - +