parent
37cb07eae2
commit
43df00a30d
|
@ -1,112 +0,0 @@
|
||||||
<nav aria-label="breadcrumb">
|
|
||||||
<ol class="breadcrumb">
|
|
||||||
<li class="breadcrumb-item">
|
|
||||||
<a routerLink="/my-library/video-channels" i18n>My Channels</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<ng-container *ngIf="isCreation()">
|
|
||||||
<li class="breadcrumb-item active" i18n>Create</li>
|
|
||||||
</ng-container>
|
|
||||||
<ng-container *ngIf="!isCreation()">
|
|
||||||
<li class="breadcrumb-item active" i18n>Edit</li>
|
|
||||||
<li class="breadcrumb-item active" aria-current="page">
|
|
||||||
<a *ngIf="videoChannel" [routerLink]="[ '/my-library/video-channels/update', videoChannel?.nameWithHost ]">{{ videoChannel?.displayName }}</a>
|
|
||||||
</li>
|
|
||||||
</ng-container>
|
|
||||||
</ol>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div *ngIf="error" class="alert alert-danger">{{ error }}</div>
|
|
||||||
|
|
||||||
<form role="form" (ngSubmit)="formValidated()" [formGroup]="form">
|
|
||||||
|
|
||||||
<div class="form-row"> <!-- channel grid -->
|
|
||||||
<div class="form-group col-12 col-lg-4 col-xl-3">
|
|
||||||
<div *ngIf="isCreation()" class="video-channel-title" i18n>NEW CHANNEL</div>
|
|
||||||
<div *ngIf="!isCreation() && videoChannel" class="video-channel-title" i18n>CHANNEL</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group col-12 col-lg-8 col-xl-9">
|
|
||||||
<h6 i18n>Banner image of your channel</h6>
|
|
||||||
|
|
||||||
<my-actor-banner-edit
|
|
||||||
*ngIf="videoChannel" [previewImage]="isCreation()"
|
|
||||||
[actor]="videoChannel" (bannerChange)="onBannerChange($event)" (bannerDelete)="onBannerDelete()"
|
|
||||||
></my-actor-banner-edit>
|
|
||||||
|
|
||||||
<my-actor-avatar-edit
|
|
||||||
*ngIf="videoChannel" [previewImage]="isCreation()"
|
|
||||||
[actor]="videoChannel" (avatarChange)="onAvatarChange($event)" (avatarDelete)="onAvatarDelete()"
|
|
||||||
[displayUsername]="!isCreation()" [displaySubscribers]="!isCreation()"
|
|
||||||
></my-actor-avatar-edit>
|
|
||||||
|
|
||||||
<div class="form-group" *ngIf="isCreation()">
|
|
||||||
<label i18n for="name">Name</label>
|
|
||||||
<div class="input-group">
|
|
||||||
<input
|
|
||||||
type="text" id="name" i18n-placeholder placeholder="Example: my_channel"
|
|
||||||
formControlName="name" [ngClass]="{ 'input-error': formErrors['name'] }" class="form-control"
|
|
||||||
>
|
|
||||||
<div class="input-group-append">
|
|
||||||
<span class="input-group-text">@{{ instanceHost }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div *ngIf="formErrors['name']" class="form-error">
|
|
||||||
{{ formErrors['name'] }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label i18n for="display-name">Display name</label>
|
|
||||||
<input
|
|
||||||
type="text" id="display-name" class="form-control"
|
|
||||||
formControlName="display-name" [ngClass]="{ 'input-error': formErrors['display-name'] }"
|
|
||||||
>
|
|
||||||
<div *ngIf="formErrors['display-name']" class="form-error">
|
|
||||||
{{ formErrors['display-name'] }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label i18n for="description">Description</label>
|
|
||||||
<textarea
|
|
||||||
id="description" formControlName="description" class="form-control"
|
|
||||||
[ngClass]="{ 'input-error': formErrors['description'] }"
|
|
||||||
></textarea>
|
|
||||||
<div *ngIf="formErrors.description" class="form-error">
|
|
||||||
{{ formErrors.description }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="support">Support</label>
|
|
||||||
<my-help
|
|
||||||
helpType="markdownEnhanced" i18n-preHtml preHtml="Short text to tell people how they can support your channel (membership platform...).<br /><br />
|
|
||||||
When you will upload a video in this channel, the video support field will be automatically filled by this text."
|
|
||||||
></my-help>
|
|
||||||
<my-markdown-textarea
|
|
||||||
id="support" formControlName="support" textareaMaxWidth="500px" markdownType="enhanced"
|
|
||||||
[classes]="{ 'input-error': formErrors['support'] }"
|
|
||||||
></my-markdown-textarea>
|
|
||||||
<div *ngIf="formErrors.support" class="form-error">
|
|
||||||
{{ formErrors.support }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group" *ngIf="isBulkUpdateVideosDisplayed()">
|
|
||||||
<my-peertube-checkbox
|
|
||||||
inputName="bulkVideosSupportUpdate" formControlName="bulkVideosSupportUpdate"
|
|
||||||
i18n-labelText labelText="Overwrite support field of all videos of this channel"
|
|
||||||
></my-peertube-checkbox>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-row"> <!-- submit placement block -->
|
|
||||||
<div class="col-md-7 col-xl-5"></div>
|
|
||||||
<div class="col-md-5 col-xl-5 d-inline-flex">
|
|
||||||
<input type="submit" value="{{ getFormButtonTitle() }}" [disabled]="!form.valid">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
|
@ -1,7 +1,5 @@
|
||||||
import { NgModule } from '@angular/core'
|
import { NgModule } from '@angular/core'
|
||||||
import { RouterModule, Routes } from '@angular/router'
|
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'
|
import { MyVideoChannelsComponent } from './my-video-channels.component'
|
||||||
|
|
||||||
const myVideoChannelsRoutes: Routes = [
|
const myVideoChannelsRoutes: Routes = [
|
||||||
|
@ -13,24 +11,6 @@ const myVideoChannelsRoutes: Routes = [
|
||||||
title: $localize`My video channels`
|
title: $localize`My video channels`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'create',
|
|
||||||
component: MyVideoChannelCreateComponent,
|
|
||||||
data: {
|
|
||||||
meta: {
|
|
||||||
title: $localize`Create a new video channel`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'update/:videoChannelId',
|
|
||||||
component: MyVideoChannelUpdateComponent,
|
|
||||||
data: {
|
|
||||||
meta: {
|
|
||||||
title: $localize`Update video channel`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
<div class="video-channels-header d-flex justify-content-between">
|
<div class="video-channels-header d-flex justify-content-between">
|
||||||
<my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter>
|
<my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter>
|
||||||
|
|
||||||
<a class="create-button" routerLink="create">
|
<a class="create-button" routerLink="/c/@create">
|
||||||
<my-global-icon iconName="add" aria-hidden="true"></my-global-icon>
|
<my-global-icon iconName="add" aria-hidden="true"></my-global-icon>
|
||||||
<ng-container i18n>Create video channel</ng-container>
|
<ng-container i18n>Create video channel</ng-container>
|
||||||
</a>
|
</a>
|
||||||
|
@ -37,7 +37,7 @@
|
||||||
<div i18n class="video-channel-videos">{videoChannel.videosCount, plural, =0 {No videos} =1 {1 video} other {{{ videoChannel.videosCount }} videos}}</div>
|
<div i18n class="video-channel-videos">{videoChannel.videosCount, plural, =0 {No videos} =1 {1 video} other {{{ videoChannel.videosCount }} videos}}</div>
|
||||||
|
|
||||||
<div class="video-channel-buttons">
|
<div class="video-channel-buttons">
|
||||||
<my-edit-button label [routerLink]="[ 'update', videoChannel.nameWithHost ]"></my-edit-button>
|
<my-edit-button label [routerLink]="[ '/c', videoChannel.nameWithHost, 'update' ]"></my-edit-button>
|
||||||
<my-delete-button label (click)="deleteVideoChannel(videoChannel)"></my-delete-button>
|
<my-delete-button label (click)="deleteVideoChannel(videoChannel)"></my-delete-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
import { ChartModule } from 'primeng/chart'
|
import { ChartModule } from 'primeng/chart'
|
||||||
import { NgModule } from '@angular/core'
|
import { NgModule } from '@angular/core'
|
||||||
import { SharedActorImageEditModule } from '@app/shared/shared-actor-image-edit'
|
|
||||||
import { SharedFormModule } from '@app/shared/shared-forms'
|
import { SharedFormModule } from '@app/shared/shared-forms'
|
||||||
import { SharedGlobalIconModule } from '@app/shared/shared-icons'
|
import { SharedGlobalIconModule } from '@app/shared/shared-icons'
|
||||||
import { SharedMainModule } from '@app/shared/shared-main'
|
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 { MyVideoChannelsRoutingModule } from './my-video-channels-routing.module'
|
||||||
import { MyVideoChannelsComponent } from './my-video-channels.component'
|
import { MyVideoChannelsComponent } from './my-video-channels.component'
|
||||||
import { SharedActorImageModule } from '@app/shared/shared-actor-image/shared-actor-image.module'
|
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,
|
SharedMainModule,
|
||||||
SharedFormModule,
|
SharedFormModule,
|
||||||
SharedGlobalIconModule,
|
SharedGlobalIconModule,
|
||||||
SharedActorImageEditModule,
|
|
||||||
SharedActorImageModule
|
SharedActorImageModule
|
||||||
],
|
],
|
||||||
|
|
||||||
declarations: [
|
declarations: [
|
||||||
MyVideoChannelsComponent,
|
MyVideoChannelsComponent
|
||||||
MyVideoChannelCreateComponent,
|
|
||||||
MyVideoChannelUpdateComponent
|
|
||||||
],
|
],
|
||||||
|
|
||||||
exports: [],
|
exports: [],
|
||||||
|
|
|
@ -12,11 +12,11 @@ import {
|
||||||
import { FormValidatorService } from '@app/shared/shared-forms'
|
import { FormValidatorService } from '@app/shared/shared-forms'
|
||||||
import { VideoChannel, VideoChannelService } from '@app/shared/shared-main'
|
import { VideoChannel, VideoChannelService } from '@app/shared/shared-main'
|
||||||
import { HttpStatusCode, VideoChannelCreate } from '@shared/models'
|
import { HttpStatusCode, VideoChannelCreate } from '@shared/models'
|
||||||
import { MyVideoChannelEdit } from './my-video-channel-edit'
|
import { MyVideoChannelEdit } from './video-channel-edit'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: './my-video-channel-edit.component.html',
|
templateUrl: './video-channel-edit.component.html',
|
||||||
styleUrls: [ './my-video-channel-edit.component.scss' ]
|
styleUrls: [ './video-channel-edit.component.scss' ]
|
||||||
})
|
})
|
||||||
export class MyVideoChannelCreateComponent extends MyVideoChannelEdit implements OnInit {
|
export class MyVideoChannelCreateComponent extends MyVideoChannelEdit implements OnInit {
|
||||||
error: string
|
error: string
|
|
@ -0,0 +1,96 @@
|
||||||
|
<div *ngIf="error" class="alert alert-danger">{{ error }}</div>
|
||||||
|
|
||||||
|
<div class="margin-content">
|
||||||
|
<form role="form" (ngSubmit)="formValidated()" [formGroup]="form">
|
||||||
|
|
||||||
|
<div class="form-row"> <!-- channel grid -->
|
||||||
|
<div class="form-group col-12 col-lg-4 col-xl-3">
|
||||||
|
<div *ngIf="isCreation()" class="video-channel-title" i18n>NEW CHANNEL</div>
|
||||||
|
<div *ngIf="!isCreation() && videoChannel" class="video-channel-title" i18n>CHANNEL</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group col-12 col-lg-8 col-xl-9">
|
||||||
|
<h6 i18n>Banner image of the channel</h6>
|
||||||
|
|
||||||
|
<my-actor-banner-edit
|
||||||
|
*ngIf="videoChannel" [previewImage]="isCreation()"
|
||||||
|
[actor]="videoChannel" (bannerChange)="onBannerChange($event)" (bannerDelete)="onBannerDelete()"
|
||||||
|
></my-actor-banner-edit>
|
||||||
|
|
||||||
|
<my-actor-avatar-edit
|
||||||
|
*ngIf="videoChannel" [previewImage]="isCreation()"
|
||||||
|
[actor]="videoChannel" (avatarChange)="onAvatarChange($event)" (avatarDelete)="onAvatarDelete()"
|
||||||
|
[displayUsername]="!isCreation()" [displaySubscribers]="!isCreation()"
|
||||||
|
></my-actor-avatar-edit>
|
||||||
|
|
||||||
|
<div class="form-group" *ngIf="isCreation()">
|
||||||
|
<label i18n for="name">Name</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input
|
||||||
|
type="text" id="name" i18n-placeholder placeholder="Example: my_channel"
|
||||||
|
formControlName="name" [ngClass]="{ 'input-error': formErrors['name'] }" class="form-control"
|
||||||
|
>
|
||||||
|
<div class="input-group-append">
|
||||||
|
<span class="input-group-text">@{{ instanceHost }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="formErrors['name']" class="form-error">
|
||||||
|
{{ formErrors['name'] }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label i18n for="display-name">Display name</label>
|
||||||
|
<input
|
||||||
|
type="text" id="display-name" class="form-control"
|
||||||
|
formControlName="display-name" [ngClass]="{ 'input-error': formErrors['display-name'] }"
|
||||||
|
>
|
||||||
|
<div *ngIf="formErrors['display-name']" class="form-error">
|
||||||
|
{{ formErrors['display-name'] }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label i18n for="description">Description</label>
|
||||||
|
<textarea
|
||||||
|
id="description" formControlName="description" class="form-control"
|
||||||
|
[ngClass]="{ 'input-error': formErrors['description'] }"
|
||||||
|
></textarea>
|
||||||
|
<div *ngIf="formErrors.description" class="form-error">
|
||||||
|
{{ formErrors.description }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="support">Support</label>
|
||||||
|
<my-help
|
||||||
|
helpType="markdownEnhanced" i18n-preHtml preHtml="Short text to tell people how they can support the channel (membership platform...).<br /><br />
|
||||||
|
When a video is uploaded in this channel, the video support field will be automatically filled by this text."
|
||||||
|
></my-help>
|
||||||
|
<my-markdown-textarea
|
||||||
|
id="support" formControlName="support" textareaMaxWidth="500px" markdownType="enhanced"
|
||||||
|
[classes]="{ 'input-error': formErrors['support'] }"
|
||||||
|
></my-markdown-textarea>
|
||||||
|
<div *ngIf="formErrors.support" class="form-error">
|
||||||
|
{{ formErrors.support }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" *ngIf="isBulkUpdateVideosDisplayed()">
|
||||||
|
<my-peertube-checkbox
|
||||||
|
inputName="bulkVideosSupportUpdate" formControlName="bulkVideosSupportUpdate"
|
||||||
|
i18n-labelText labelText="Overwrite support field of all videos of this channel"
|
||||||
|
></my-peertube-checkbox>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row"> <!-- submit placement block -->
|
||||||
|
<div class="col-md-7 col-xl-5"></div>
|
||||||
|
<div class="col-md-5 col-xl-5 d-inline-flex">
|
||||||
|
<input type="submit" value="{{ getFormButtonTitle() }}" [disabled]="!form.valid">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
|
@ -1,6 +1,10 @@
|
||||||
@use '_variables' as *;
|
@use '_variables' as *;
|
||||||
@use '_mixins' as *;
|
@use '_mixins' as *;
|
||||||
|
|
||||||
|
.margin-content {
|
||||||
|
padding-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
label {
|
label {
|
||||||
font-weight: $font-regular;
|
font-weight: $font-regular;
|
||||||
font-size: 100%;
|
font-size: 100%;
|
|
@ -12,14 +12,14 @@ import {
|
||||||
import { FormValidatorService } from '@app/shared/shared-forms'
|
import { FormValidatorService } from '@app/shared/shared-forms'
|
||||||
import { VideoChannel, VideoChannelService } from '@app/shared/shared-main'
|
import { VideoChannel, VideoChannelService } from '@app/shared/shared-main'
|
||||||
import { HTMLServerConfig, VideoChannelUpdate } from '@shared/models'
|
import { HTMLServerConfig, VideoChannelUpdate } from '@shared/models'
|
||||||
import { MyVideoChannelEdit } from './my-video-channel-edit'
|
import { MyVideoChannelEdit } from './video-channel-edit'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-video-channel-update',
|
selector: 'my-video-channel-update',
|
||||||
templateUrl: './my-video-channel-edit.component.html',
|
templateUrl: './video-channel-edit.component.html',
|
||||||
styleUrls: [ './my-video-channel-edit.component.scss' ]
|
styleUrls: [ './video-channel-edit.component.scss' ]
|
||||||
})
|
})
|
||||||
export class MyVideoChannelUpdateComponent extends MyVideoChannelEdit implements OnInit, OnDestroy {
|
export class VideoChannelUpdateComponent extends MyVideoChannelEdit implements OnInit, OnDestroy {
|
||||||
error: string
|
error: string
|
||||||
videoChannel: VideoChannel
|
videoChannel: VideoChannel
|
||||||
|
|
||||||
|
@ -50,9 +50,9 @@ export class MyVideoChannelUpdateComponent extends MyVideoChannelEdit implements
|
||||||
})
|
})
|
||||||
|
|
||||||
this.paramsSub = this.route.params.subscribe(routeParams => {
|
this.paramsSub = this.route.params.subscribe(routeParams => {
|
||||||
const videoChannelId = routeParams['videoChannelId']
|
const videoChannelName = routeParams['videoChannelName']
|
||||||
|
|
||||||
this.videoChannelService.getVideoChannel(videoChannelId)
|
this.videoChannelService.getVideoChannel(videoChannelName)
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: videoChannelToUpdate => {
|
next: videoChannelToUpdate => {
|
||||||
this.videoChannel = videoChannelToUpdate
|
this.videoChannel = videoChannelToUpdate
|
||||||
|
@ -95,7 +95,7 @@ export class MyVideoChannelUpdateComponent extends MyVideoChannelEdit implements
|
||||||
|
|
||||||
this.notifier.success($localize`Video channel ${videoChannelUpdate.displayName} updated.`)
|
this.notifier.success($localize`Video channel ${videoChannelUpdate.displayName} updated.`)
|
||||||
|
|
||||||
this.router.navigate([ '/my-library', 'video-channels' ])
|
this.router.navigate([ '/c', this.videoChannel.name ])
|
||||||
},
|
},
|
||||||
|
|
||||||
error: err => {
|
error: err => {
|
|
@ -1,10 +1,21 @@
|
||||||
import { NgModule } from '@angular/core'
|
import { NgModule } from '@angular/core'
|
||||||
import { RouterModule, Routes } from '@angular/router'
|
import { RouterModule, Routes } from '@angular/router'
|
||||||
|
import { MyVideoChannelCreateComponent } from './video-channel-edit/video-channel-create.component'
|
||||||
|
import { VideoChannelUpdateComponent } from './video-channel-edit/video-channel-update.component'
|
||||||
import { VideoChannelPlaylistsComponent } from './video-channel-playlists/video-channel-playlists.component'
|
import { VideoChannelPlaylistsComponent } from './video-channel-playlists/video-channel-playlists.component'
|
||||||
import { VideoChannelVideosComponent } from './video-channel-videos/video-channel-videos.component'
|
import { VideoChannelVideosComponent } from './video-channel-videos/video-channel-videos.component'
|
||||||
import { VideoChannelsComponent } from './video-channels.component'
|
import { VideoChannelsComponent } from './video-channels.component'
|
||||||
|
|
||||||
const videoChannelsRoutes: Routes = [
|
const videoChannelsRoutes: Routes = [
|
||||||
|
{
|
||||||
|
path: '@create',
|
||||||
|
component: MyVideoChannelCreateComponent,
|
||||||
|
data: {
|
||||||
|
meta: {
|
||||||
|
title: $localize`Create a new video channel`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: ':videoChannelName',
|
path: ':videoChannelName',
|
||||||
component: VideoChannelsComponent,
|
component: VideoChannelsComponent,
|
||||||
|
@ -37,6 +48,16 @@ const videoChannelsRoutes: Routes = [
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: ':videoChannelName/update',
|
||||||
|
component: VideoChannelUpdateComponent,
|
||||||
|
|
||||||
|
data: {
|
||||||
|
meta: {
|
||||||
|
title: $localize`Update video channel`
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -6,11 +6,11 @@
|
||||||
<div class="channel-info">
|
<div class="channel-info">
|
||||||
|
|
||||||
<ng-template #buttonsTemplate>
|
<ng-template #buttonsTemplate>
|
||||||
<a *ngIf="isManageable()" [routerLink]="[ '/my-library/video-channels/update', videoChannel.nameWithHost ]" class="peertube-button-link orange-button" i18n>
|
<a *ngIf="isManageable()" [routerLink]="[ 'update' ]" class="peertube-button-link orange-button" i18n>
|
||||||
Manage channel
|
Manage channel
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<my-subscribe-button *ngIf="!isManageable()" #subscribeButton [videoChannels]="[videoChannel]"></my-subscribe-button>
|
<my-subscribe-button *ngIf="!isOwner()" #subscribeButton [videoChannels]="[videoChannel]"></my-subscribe-button>
|
||||||
|
|
||||||
<button *ngIf="videoChannel.support" (click)="showSupportModal()" class="support-button peertube-button orange-button-inverted">
|
<button *ngIf="videoChannel.support" (click)="showSupportModal()" class="support-button peertube-button orange-button-inverted">
|
||||||
<my-global-icon iconName="support" aria-hidden="true"></my-global-icon>
|
<my-global-icon iconName="support" aria-hidden="true"></my-global-icon>
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { AuthService, MarkdownService, Notifier, RestExtractor, ScreenService }
|
||||||
import { ListOverflowItem, VideoChannel, VideoChannelService, VideoService } from '@app/shared/shared-main'
|
import { ListOverflowItem, VideoChannel, VideoChannelService, VideoService } from '@app/shared/shared-main'
|
||||||
import { SupportModalComponent } from '@app/shared/shared-support-modal'
|
import { SupportModalComponent } from '@app/shared/shared-support-modal'
|
||||||
import { SubscribeButtonComponent } from '@app/shared/shared-user-subscription'
|
import { SubscribeButtonComponent } from '@app/shared/shared-user-subscription'
|
||||||
import { HttpStatusCode } from '@shared/models'
|
import { HttpStatusCode, UserRight } from '@shared/models'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: './video-channels.component.html',
|
templateUrl: './video-channels.component.html',
|
||||||
|
@ -93,10 +93,14 @@ export class VideoChannelsComponent implements OnInit, OnDestroy {
|
||||||
return this.authService.isLoggedIn()
|
return this.authService.isLoggedIn()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isOwner () {
|
||||||
|
return this.videoChannel?.ownerAccount.userId === this.authService.getUser().id
|
||||||
|
}
|
||||||
|
|
||||||
isManageable () {
|
isManageable () {
|
||||||
if (!this.isUserLoggedIn()) return false
|
if (!this.isUserLoggedIn()) return false
|
||||||
|
|
||||||
return this.videoChannel?.ownerAccount.userId === this.authService.getUser().id
|
return this.isOwner() || this.authService.getUser().hasRight(UserRight.MANAGE_VIDEO_CHANNELS)
|
||||||
}
|
}
|
||||||
|
|
||||||
activateCopiedMessage () {
|
activateCopiedMessage () {
|
||||||
|
|
|
@ -11,6 +11,9 @@ import { VideoChannelVideosComponent } from './video-channel-videos/video-channe
|
||||||
import { VideoChannelsRoutingModule } from './video-channels-routing.module'
|
import { VideoChannelsRoutingModule } from './video-channels-routing.module'
|
||||||
import { VideoChannelsComponent } from './video-channels.component'
|
import { VideoChannelsComponent } from './video-channels.component'
|
||||||
import { SharedActorImageModule } from '../shared/shared-actor-image/shared-actor-image.module'
|
import { SharedActorImageModule } from '../shared/shared-actor-image/shared-actor-image.module'
|
||||||
|
import { MyVideoChannelCreateComponent } from './video-channel-edit/video-channel-create.component'
|
||||||
|
import { VideoChannelUpdateComponent } from './video-channel-edit/video-channel-update.component'
|
||||||
|
import { SharedActorImageEditModule } from '@app/shared/shared-actor-image-edit'
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -23,13 +26,16 @@ import { SharedActorImageModule } from '../shared/shared-actor-image/shared-acto
|
||||||
SharedUserSubscriptionModule,
|
SharedUserSubscriptionModule,
|
||||||
SharedGlobalIconModule,
|
SharedGlobalIconModule,
|
||||||
SharedSupportModal,
|
SharedSupportModal,
|
||||||
SharedActorImageModule
|
SharedActorImageModule,
|
||||||
|
SharedActorImageEditModule
|
||||||
],
|
],
|
||||||
|
|
||||||
declarations: [
|
declarations: [
|
||||||
VideoChannelsComponent,
|
VideoChannelsComponent,
|
||||||
VideoChannelVideosComponent,
|
VideoChannelVideosComponent,
|
||||||
VideoChannelPlaylistsComponent
|
VideoChannelPlaylistsComponent,
|
||||||
|
MyVideoChannelCreateComponent,
|
||||||
|
VideoChannelUpdateComponent
|
||||||
],
|
],
|
||||||
|
|
||||||
exports: [
|
exports: [
|
||||||
|
|
|
@ -24,6 +24,7 @@ import {
|
||||||
asyncRetryTransactionMiddleware,
|
asyncRetryTransactionMiddleware,
|
||||||
authenticate,
|
authenticate,
|
||||||
commonVideosFiltersValidator,
|
commonVideosFiltersValidator,
|
||||||
|
ensureUserCanManageChannel,
|
||||||
optionalAuthenticate,
|
optionalAuthenticate,
|
||||||
paginationValidator,
|
paginationValidator,
|
||||||
setDefaultPagination,
|
setDefaultPagination,
|
||||||
|
@ -74,7 +75,7 @@ videoChannelRouter.post('/:nameWithHost/avatar/pick',
|
||||||
authenticate,
|
authenticate,
|
||||||
reqAvatarFile,
|
reqAvatarFile,
|
||||||
asyncMiddleware(videoChannelsNameWithHostValidator),
|
asyncMiddleware(videoChannelsNameWithHostValidator),
|
||||||
ensureAuthUserOwnsChannelValidator,
|
ensureUserCanManageChannel,
|
||||||
updateAvatarValidator,
|
updateAvatarValidator,
|
||||||
asyncMiddleware(updateVideoChannelAvatar)
|
asyncMiddleware(updateVideoChannelAvatar)
|
||||||
)
|
)
|
||||||
|
@ -83,7 +84,7 @@ videoChannelRouter.post('/:nameWithHost/banner/pick',
|
||||||
authenticate,
|
authenticate,
|
||||||
reqBannerFile,
|
reqBannerFile,
|
||||||
asyncMiddleware(videoChannelsNameWithHostValidator),
|
asyncMiddleware(videoChannelsNameWithHostValidator),
|
||||||
ensureAuthUserOwnsChannelValidator,
|
ensureUserCanManageChannel,
|
||||||
updateBannerValidator,
|
updateBannerValidator,
|
||||||
asyncMiddleware(updateVideoChannelBanner)
|
asyncMiddleware(updateVideoChannelBanner)
|
||||||
)
|
)
|
||||||
|
@ -91,21 +92,21 @@ videoChannelRouter.post('/:nameWithHost/banner/pick',
|
||||||
videoChannelRouter.delete('/:nameWithHost/avatar',
|
videoChannelRouter.delete('/:nameWithHost/avatar',
|
||||||
authenticate,
|
authenticate,
|
||||||
asyncMiddleware(videoChannelsNameWithHostValidator),
|
asyncMiddleware(videoChannelsNameWithHostValidator),
|
||||||
ensureAuthUserOwnsChannelValidator,
|
ensureUserCanManageChannel,
|
||||||
asyncMiddleware(deleteVideoChannelAvatar)
|
asyncMiddleware(deleteVideoChannelAvatar)
|
||||||
)
|
)
|
||||||
|
|
||||||
videoChannelRouter.delete('/:nameWithHost/banner',
|
videoChannelRouter.delete('/:nameWithHost/banner',
|
||||||
authenticate,
|
authenticate,
|
||||||
asyncMiddleware(videoChannelsNameWithHostValidator),
|
asyncMiddleware(videoChannelsNameWithHostValidator),
|
||||||
ensureAuthUserOwnsChannelValidator,
|
ensureUserCanManageChannel,
|
||||||
asyncMiddleware(deleteVideoChannelBanner)
|
asyncMiddleware(deleteVideoChannelBanner)
|
||||||
)
|
)
|
||||||
|
|
||||||
videoChannelRouter.put('/:nameWithHost',
|
videoChannelRouter.put('/:nameWithHost',
|
||||||
authenticate,
|
authenticate,
|
||||||
asyncMiddleware(videoChannelsNameWithHostValidator),
|
asyncMiddleware(videoChannelsNameWithHostValidator),
|
||||||
ensureAuthUserOwnsChannelValidator,
|
ensureUserCanManageChannel,
|
||||||
videoChannelsUpdateValidator,
|
videoChannelsUpdateValidator,
|
||||||
asyncRetryTransactionMiddleware(updateVideoChannel)
|
asyncRetryTransactionMiddleware(updateVideoChannel)
|
||||||
)
|
)
|
||||||
|
|
|
@ -20,8 +20,26 @@ function ensureUserHasRight (userRight: UserRight) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ensureUserCanManageChannel (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||||
|
const user = res.locals.oauth.token.user
|
||||||
|
const isUserOwner = res.locals.videoChannel.Account.userId !== user.id
|
||||||
|
|
||||||
|
if (isUserOwner && user.hasRight(UserRight.MANAGE_VIDEO_CHANNELS) === false) {
|
||||||
|
const message = `User ${user.username} does not have right to manage channel ${req.params.nameWithHost}.`
|
||||||
|
logger.info(message)
|
||||||
|
|
||||||
|
return res.fail({
|
||||||
|
status: HttpStatusCode.FORBIDDEN_403,
|
||||||
|
message
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return next()
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
export {
|
export {
|
||||||
ensureUserHasRight
|
ensureUserHasRight,
|
||||||
|
ensureUserCanManageChannel
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,5 +41,7 @@ export const enum UserRight {
|
||||||
MANAGE_VIDEOS_REDUNDANCIES,
|
MANAGE_VIDEOS_REDUNDANCIES,
|
||||||
|
|
||||||
MANAGE_VIDEO_FILES,
|
MANAGE_VIDEO_FILES,
|
||||||
RUN_VIDEO_TRANSCODING
|
RUN_VIDEO_TRANSCODING,
|
||||||
|
|
||||||
|
MANAGE_VIDEO_CHANNELS
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user