Add ability to display all channel/account videos
This commit is contained in:
parent
ff2cac9fa3
commit
0aa52e1707
|
@ -3,7 +3,7 @@ import { concatMap, map, switchMap, tap } from 'rxjs/operators'
|
||||||
import { Component, OnDestroy, OnInit } from '@angular/core'
|
import { Component, OnDestroy, OnInit } from '@angular/core'
|
||||||
import { ComponentPagination, hasMoreItems, ScreenService, User, UserService } from '@app/core'
|
import { ComponentPagination, hasMoreItems, ScreenService, User, UserService } from '@app/core'
|
||||||
import { Account, AccountService, Video, VideoChannel, VideoChannelService, VideoService } from '@app/shared/shared-main'
|
import { Account, AccountService, Video, VideoChannel, VideoChannelService, VideoService } from '@app/shared/shared-main'
|
||||||
import { VideoSortField } from '@shared/models'
|
import { NSFWPolicyType, VideoSortField } from '@shared/models'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-account-video-channels',
|
selector: 'my-account-video-channels',
|
||||||
|
@ -31,6 +31,7 @@ export class AccountVideoChannelsComponent implements OnInit, OnDestroy {
|
||||||
onChannelDataSubject = new Subject<any>()
|
onChannelDataSubject = new Subject<any>()
|
||||||
|
|
||||||
userMiniature: User
|
userMiniature: User
|
||||||
|
nsfwPolicy: NSFWPolicyType
|
||||||
|
|
||||||
private accountSub: Subscription
|
private accountSub: Subscription
|
||||||
|
|
||||||
|
@ -52,7 +53,11 @@ export class AccountVideoChannelsComponent implements OnInit, OnDestroy {
|
||||||
})
|
})
|
||||||
|
|
||||||
this.userService.getAnonymousOrLoggedUser()
|
this.userService.getAnonymousOrLoggedUser()
|
||||||
.subscribe(user => this.userMiniature = user)
|
.subscribe(user => {
|
||||||
|
this.userMiniature = user
|
||||||
|
|
||||||
|
this.nsfwPolicy = user.nsfwPolicy
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy () {
|
ngOnDestroy () {
|
||||||
|
@ -65,7 +70,14 @@ export class AccountVideoChannelsComponent implements OnInit, OnDestroy {
|
||||||
tap(res => this.channelPagination.totalItems = res.total),
|
tap(res => this.channelPagination.totalItems = res.total),
|
||||||
switchMap(res => from(res.data)),
|
switchMap(res => from(res.data)),
|
||||||
concatMap(videoChannel => {
|
concatMap(videoChannel => {
|
||||||
return this.videoService.getVideoChannelVideos(videoChannel, this.videosPagination, this.videosSort)
|
const options = {
|
||||||
|
videoChannel,
|
||||||
|
videoPagination: this.videosPagination,
|
||||||
|
sort: this.videosSort,
|
||||||
|
nsfwPolicy: this.nsfwPolicy
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.videoService.getVideoChannelVideos(options)
|
||||||
.pipe(map(data => ({ videoChannel, videos: data.data })))
|
.pipe(map(data => ({ videoChannel, videos: data.data })))
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { AuthService, ConfirmService, LocalStorageService, Notifier, ScreenServi
|
||||||
import { immutableAssign } from '@app/helpers'
|
import { immutableAssign } from '@app/helpers'
|
||||||
import { Account, AccountService, VideoService } from '@app/shared/shared-main'
|
import { Account, AccountService, VideoService } from '@app/shared/shared-main'
|
||||||
import { AbstractVideoList } from '@app/shared/shared-video-miniature'
|
import { AbstractVideoList } from '@app/shared/shared-video-miniature'
|
||||||
|
import { VideoFilter } from '@shared/models'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-account-videos',
|
selector: 'my-account-videos',
|
||||||
|
@ -18,6 +19,8 @@ export class AccountVideosComponent extends AbstractVideoList implements OnInit,
|
||||||
titlePage: string
|
titlePage: string
|
||||||
loadOnInit = false
|
loadOnInit = false
|
||||||
|
|
||||||
|
filter: VideoFilter = null
|
||||||
|
|
||||||
private account: Account
|
private account: Account
|
||||||
private accountSub: Subscription
|
private accountSub: Subscription
|
||||||
|
|
||||||
|
@ -40,6 +43,8 @@ export class AccountVideosComponent extends AbstractVideoList implements OnInit,
|
||||||
ngOnInit () {
|
ngOnInit () {
|
||||||
super.ngOnInit()
|
super.ngOnInit()
|
||||||
|
|
||||||
|
this.enableAllFilterIfPossible()
|
||||||
|
|
||||||
// Parent get the account for us
|
// Parent get the account for us
|
||||||
this.accountSub = this.accountService.accountLoaded
|
this.accountSub = this.accountService.accountLoaded
|
||||||
.pipe(first())
|
.pipe(first())
|
||||||
|
@ -59,9 +64,16 @@ export class AccountVideosComponent extends AbstractVideoList implements OnInit,
|
||||||
|
|
||||||
getVideosObservable (page: number) {
|
getVideosObservable (page: number) {
|
||||||
const newPagination = immutableAssign(this.pagination, { currentPage: page })
|
const newPagination = immutableAssign(this.pagination, { currentPage: page })
|
||||||
|
const options = {
|
||||||
|
account: this.account,
|
||||||
|
videoPagination: newPagination,
|
||||||
|
sort: this.sort,
|
||||||
|
nsfwPolicy: this.nsfwPolicy,
|
||||||
|
videoFilter: this.filter
|
||||||
|
}
|
||||||
|
|
||||||
return this.videoService
|
return this.videoService
|
||||||
.getAccountVideos(this.account, newPagination, this.sort)
|
.getAccountVideos(options)
|
||||||
.pipe(
|
.pipe(
|
||||||
tap(({ total }) => {
|
tap(({ total }) => {
|
||||||
this.titlePage = $localize`Published ${total} videos`
|
this.titlePage = $localize`Published ${total} videos`
|
||||||
|
@ -69,6 +81,12 @@ export class AccountVideosComponent extends AbstractVideoList implements OnInit,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleModerationDisplay () {
|
||||||
|
this.filter = this.buildLocalFilter(this.filter, null)
|
||||||
|
|
||||||
|
this.reloadVideos()
|
||||||
|
}
|
||||||
|
|
||||||
generateSyndicationList () {
|
generateSyndicationList () {
|
||||||
this.syndicationItems = this.videoService.getAccountFeedUrls(this.account.id)
|
this.syndicationItems = this.videoService.getAccountFeedUrls(this.account.id)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { AuthService, ConfirmService, LocalStorageService, Notifier, ScreenServi
|
||||||
import { immutableAssign } from '@app/helpers'
|
import { immutableAssign } from '@app/helpers'
|
||||||
import { VideoChannel, VideoChannelService, VideoService } from '@app/shared/shared-main'
|
import { VideoChannel, VideoChannelService, VideoService } from '@app/shared/shared-main'
|
||||||
import { AbstractVideoList } from '@app/shared/shared-video-miniature'
|
import { AbstractVideoList } from '@app/shared/shared-video-miniature'
|
||||||
|
import { VideoFilter } from '@shared/models'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-video-channel-videos',
|
selector: 'my-video-channel-videos',
|
||||||
|
@ -18,6 +19,8 @@ export class VideoChannelVideosComponent extends AbstractVideoList implements On
|
||||||
titlePage: string
|
titlePage: string
|
||||||
loadOnInit = false
|
loadOnInit = false
|
||||||
|
|
||||||
|
filter: VideoFilter = null
|
||||||
|
|
||||||
private videoChannel: VideoChannel
|
private videoChannel: VideoChannel
|
||||||
private videoChannelSub: Subscription
|
private videoChannelSub: Subscription
|
||||||
|
|
||||||
|
@ -46,6 +49,8 @@ export class VideoChannelVideosComponent extends AbstractVideoList implements On
|
||||||
ngOnInit () {
|
ngOnInit () {
|
||||||
super.ngOnInit()
|
super.ngOnInit()
|
||||||
|
|
||||||
|
this.enableAllFilterIfPossible()
|
||||||
|
|
||||||
// Parent get the video channel for us
|
// Parent get the video channel for us
|
||||||
this.videoChannelSub = this.videoChannelService.videoChannelLoaded
|
this.videoChannelSub = this.videoChannelService.videoChannelLoaded
|
||||||
.pipe(first())
|
.pipe(first())
|
||||||
|
@ -65,9 +70,16 @@ export class VideoChannelVideosComponent extends AbstractVideoList implements On
|
||||||
|
|
||||||
getVideosObservable (page: number) {
|
getVideosObservable (page: number) {
|
||||||
const newPagination = immutableAssign(this.pagination, { currentPage: page })
|
const newPagination = immutableAssign(this.pagination, { currentPage: page })
|
||||||
|
const options = {
|
||||||
|
videoChannel: this.videoChannel,
|
||||||
|
videoPagination: newPagination,
|
||||||
|
sort: this.sort,
|
||||||
|
nsfwPolicy: this.nsfwPolicy,
|
||||||
|
videoFilter: this.filter
|
||||||
|
}
|
||||||
|
|
||||||
return this.videoService
|
return this.videoService
|
||||||
.getVideoChannelVideos(this.videoChannel, newPagination, this.sort, this.nsfwPolicy)
|
.getVideoChannelVideos(options)
|
||||||
.pipe(
|
.pipe(
|
||||||
tap(({ total }) => {
|
tap(({ total }) => {
|
||||||
this.titlePage = total === 1
|
this.titlePage = total === 1
|
||||||
|
@ -80,4 +92,10 @@ export class VideoChannelVideosComponent extends AbstractVideoList implements On
|
||||||
generateSyndicationList () {
|
generateSyndicationList () {
|
||||||
this.syndicationItems = this.videoService.getVideoChannelFeedUrls(this.videoChannel.id)
|
this.syndicationItems = this.videoService.getVideoChannelFeedUrls(this.videoChannel.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleModerationDisplay () {
|
||||||
|
this.filter = this.buildLocalFilter(this.filter, null)
|
||||||
|
|
||||||
|
this.reloadVideos()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,11 +39,7 @@ export class VideoLocalComponent extends AbstractVideoList implements OnInit, On
|
||||||
ngOnInit () {
|
ngOnInit () {
|
||||||
super.ngOnInit()
|
super.ngOnInit()
|
||||||
|
|
||||||
if (this.authService.isLoggedIn()) {
|
this.enableAllFilterIfPossible()
|
||||||
const user = this.authService.getUser()
|
|
||||||
this.displayModerationBlock = user.hasRight(UserRight.SEE_ALL_VIDEOS)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.generateSyndicationList()
|
this.generateSyndicationList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +73,7 @@ export class VideoLocalComponent extends AbstractVideoList implements OnInit, On
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleModerationDisplay () {
|
toggleModerationDisplay () {
|
||||||
this.filter = this.filter === 'local' ? 'all-local' as 'all-local' : 'local' as 'local'
|
this.filter = this.buildLocalFilter(this.filter, 'local')
|
||||||
|
|
||||||
this.reloadVideos()
|
this.reloadVideos()
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,16 +134,28 @@ export class VideoService implements VideosProvider {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
getAccountVideos (
|
getAccountVideos (parameters: {
|
||||||
account: Account,
|
account: Account,
|
||||||
videoPagination: ComponentPaginationLight,
|
videoPagination: ComponentPaginationLight,
|
||||||
sort: VideoSortField
|
sort: VideoSortField
|
||||||
): Observable<ResultList<Video>> {
|
nsfwPolicy?: NSFWPolicyType
|
||||||
|
videoFilter?: VideoFilter
|
||||||
|
}): Observable<ResultList<Video>> {
|
||||||
|
const { account, videoPagination, sort, videoFilter, nsfwPolicy } = parameters
|
||||||
|
|
||||||
const pagination = this.restService.componentPaginationToRestPagination(videoPagination)
|
const pagination = this.restService.componentPaginationToRestPagination(videoPagination)
|
||||||
|
|
||||||
let params = new HttpParams()
|
let params = new HttpParams()
|
||||||
params = this.restService.addRestGetParams(params, pagination, sort)
|
params = this.restService.addRestGetParams(params, pagination, sort)
|
||||||
|
|
||||||
|
if (nsfwPolicy) {
|
||||||
|
params = params.set('nsfw', this.nsfwPolicyToParam(nsfwPolicy))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (videoFilter) {
|
||||||
|
params = params.set('filter', videoFilter)
|
||||||
|
}
|
||||||
|
|
||||||
return this.authHttp
|
return this.authHttp
|
||||||
.get<ResultList<Video>>(AccountService.BASE_ACCOUNT_URL + account.nameWithHost + '/videos', { params })
|
.get<ResultList<Video>>(AccountService.BASE_ACCOUNT_URL + account.nameWithHost + '/videos', { params })
|
||||||
.pipe(
|
.pipe(
|
||||||
|
@ -152,12 +164,15 @@ export class VideoService implements VideosProvider {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
getVideoChannelVideos (
|
getVideoChannelVideos (parameters: {
|
||||||
videoChannel: VideoChannel,
|
videoChannel: VideoChannel,
|
||||||
videoPagination: ComponentPaginationLight,
|
videoPagination: ComponentPaginationLight,
|
||||||
sort: VideoSortField,
|
sort: VideoSortField,
|
||||||
nsfwPolicy?: NSFWPolicyType
|
nsfwPolicy?: NSFWPolicyType
|
||||||
): Observable<ResultList<Video>> {
|
videoFilter?: VideoFilter
|
||||||
|
}): Observable<ResultList<Video>> {
|
||||||
|
const { videoChannel, videoPagination, sort, nsfwPolicy, videoFilter } = parameters
|
||||||
|
|
||||||
const pagination = this.restService.componentPaginationToRestPagination(videoPagination)
|
const pagination = this.restService.componentPaginationToRestPagination(videoPagination)
|
||||||
|
|
||||||
let params = new HttpParams()
|
let params = new HttpParams()
|
||||||
|
@ -167,6 +182,10 @@ export class VideoService implements VideosProvider {
|
||||||
params = params.set('nsfw', this.nsfwPolicyToParam(nsfwPolicy))
|
params = params.set('nsfw', this.nsfwPolicyToParam(nsfwPolicy))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (videoFilter) {
|
||||||
|
params = params.set('filter', videoFilter)
|
||||||
|
}
|
||||||
|
|
||||||
return this.authHttp
|
return this.authHttp
|
||||||
.get<ResultList<Video>>(VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannel.nameWithHost + '/videos', { params })
|
.get<ResultList<Video>>(VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannel.nameWithHost + '/videos', { params })
|
||||||
.pipe(
|
.pipe(
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
<div class="dropdown-item">
|
<div class="dropdown-item">
|
||||||
<my-peertube-checkbox
|
<my-peertube-checkbox
|
||||||
(change)="toggleModerationDisplay()"
|
(change)="toggleModerationDisplay()"
|
||||||
inputName="display-unlisted-private" i18n-labelText labelText="Display unlisted and private videos"
|
inputName="display-unlisted-private" i18n-labelText labelText="Display all videos (private, unlisted or not yet published)"
|
||||||
></my-peertube-checkbox>
|
></my-peertube-checkbox>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -31,13 +31,21 @@ $iconSize: 16px;
|
||||||
|
|
||||||
.moderation-block {
|
.moderation-block {
|
||||||
div {
|
div {
|
||||||
@include button-with-icon($iconSize, 3px, -1px);
|
@include button-with-icon($iconSize, 3px, -2px);
|
||||||
}
|
}
|
||||||
|
|
||||||
margin-left: .2rem;
|
margin-left: .4rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
|
.dropdown-item {
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
::ng-deep my-peertube-checkbox label {
|
||||||
|
padding: 3px 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ import {
|
||||||
import { DisableForReuseHook } from '@app/core/routing/disable-for-reuse-hook'
|
import { DisableForReuseHook } from '@app/core/routing/disable-for-reuse-hook'
|
||||||
import { GlobalIconName } from '@app/shared/shared-icons'
|
import { GlobalIconName } from '@app/shared/shared-icons'
|
||||||
import { isLastMonth, isLastWeek, isThisMonth, isToday, isYesterday } from '@shared/core-utils/miscs/date'
|
import { isLastMonth, isLastWeek, isThisMonth, isToday, isYesterday } from '@shared/core-utils/miscs/date'
|
||||||
import { ServerConfig, VideoSortField } from '@shared/models'
|
import { ServerConfig, UserRight, VideoFilter, VideoSortField } from '@shared/models'
|
||||||
import { NSFWPolicyType } from '@shared/models/videos/nsfw-policy.type'
|
import { NSFWPolicyType } from '@shared/models/videos/nsfw-policy.type'
|
||||||
import { Syndication, Video } from '../shared-main'
|
import { Syndication, Video } from '../shared-main'
|
||||||
import { MiniatureDisplayOptions, OwnerDisplayType } from './video-miniature.component'
|
import { MiniatureDisplayOptions, OwnerDisplayType } from './video-miniature.component'
|
||||||
|
@ -205,10 +205,6 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor
|
||||||
this.loadMoreVideos(true)
|
this.loadMoreVideos(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleModerationDisplay () {
|
|
||||||
throw new Error('toggleModerationDisplay is not implemented')
|
|
||||||
}
|
|
||||||
|
|
||||||
removeVideoFromArray (video: Video) {
|
removeVideoFromArray (video: Video) {
|
||||||
this.videos = this.videos.filter(v => v.id !== video.id)
|
this.videos = this.videos.filter(v => v.id !== video.id)
|
||||||
}
|
}
|
||||||
|
@ -268,6 +264,10 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor
|
||||||
return this.groupedDateLabels[this.groupedDates[video.id]]
|
return this.groupedDateLabels[this.groupedDates[video.id]]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleModerationDisplay () {
|
||||||
|
throw new Error('toggleModerationDisplay is not implemented')
|
||||||
|
}
|
||||||
|
|
||||||
// On videos hook for children that want to do something
|
// On videos hook for children that want to do something
|
||||||
protected onMoreVideos () { /* empty */ }
|
protected onMoreVideos () { /* empty */ }
|
||||||
|
|
||||||
|
@ -277,6 +277,28 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor
|
||||||
this.angularState = routeParams[ 'a-state' ]
|
this.angularState = routeParams[ 'a-state' ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected buildLocalFilter (existing: VideoFilter, base: VideoFilter) {
|
||||||
|
if (base === 'local') {
|
||||||
|
return existing === 'local'
|
||||||
|
? 'all-local' as 'all-local'
|
||||||
|
: 'local' as 'local'
|
||||||
|
}
|
||||||
|
|
||||||
|
return existing === 'all'
|
||||||
|
? null
|
||||||
|
: 'all'
|
||||||
|
}
|
||||||
|
|
||||||
|
protected enableAllFilterIfPossible () {
|
||||||
|
if (!this.authService.isLoggedIn()) return
|
||||||
|
|
||||||
|
this.authService.userInformationLoaded
|
||||||
|
.subscribe(() => {
|
||||||
|
const user = this.authService.getUser()
|
||||||
|
this.displayModerationBlock = user.hasRight(UserRight.SEE_ALL_VIDEOS)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
private calcPageSizes () {
|
private calcPageSizes () {
|
||||||
if (this.screenService.isInMobileView()) {
|
if (this.screenService.isInMobileView()) {
|
||||||
this.pagination.itemsPerPage = 5
|
this.pagination.itemsPerPage = 5
|
||||||
|
|
|
@ -65,6 +65,10 @@ $icon-font-path: '~@neos21/bootstrap3-glyphicons/assets/fonts/';
|
||||||
opacity: .9;
|
opacity: .9;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
color: pvar(--mainForegroundColor) !important;
|
||||||
|
}
|
||||||
|
|
||||||
&::after {
|
&::after {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ import * as magnetUtil from 'magnet-uri'
|
||||||
const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS
|
const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS
|
||||||
|
|
||||||
function isVideoFilterValid (filter: VideoFilter) {
|
function isVideoFilterValid (filter: VideoFilter) {
|
||||||
return filter === 'local' || filter === 'all-local'
|
return filter === 'local' || filter === 'all-local' || filter === 'all'
|
||||||
}
|
}
|
||||||
|
|
||||||
function isVideoCategoryValid (value: any) {
|
function isVideoCategoryValid (value: any) {
|
||||||
|
|
|
@ -429,7 +429,10 @@ const commonVideosFiltersValidator = [
|
||||||
if (areValidationErrors(req, res)) return
|
if (areValidationErrors(req, res)) return
|
||||||
|
|
||||||
const user = res.locals.oauth ? res.locals.oauth.token.User : undefined
|
const user = res.locals.oauth ? res.locals.oauth.token.User : undefined
|
||||||
if (req.query.filter === 'all-local' && (!user || user.hasRight(UserRight.SEE_ALL_VIDEOS) === false)) {
|
if (
|
||||||
|
(req.query.filter === 'all-local' || req.query.filter === 'all') &&
|
||||||
|
(!user || user.hasRight(UserRight.SEE_ALL_VIDEOS) === false)
|
||||||
|
) {
|
||||||
res.status(401)
|
res.status(401)
|
||||||
.json({ error: 'You are not allowed to see all local videos.' })
|
.json({ error: 'You are not allowed to see all local videos.' })
|
||||||
|
|
||||||
|
|
|
@ -89,7 +89,7 @@ function buildListQuery (model: typeof Model, options: BuildVideosQueryOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only list public/published videos
|
// Only list public/published videos
|
||||||
if (!options.filter || options.filter !== 'all-local') {
|
if (!options.filter || (options.filter !== 'all-local' && options.filter !== 'all')) {
|
||||||
and.push(
|
and.push(
|
||||||
`("video"."state" = ${VideoState.PUBLISHED} OR ` +
|
`("video"."state" = ${VideoState.PUBLISHED} OR ` +
|
||||||
`("video"."state" = ${VideoState.TO_TRANSCODE} AND "video"."waitTranscoding" IS false))`
|
`("video"."state" = ${VideoState.TO_TRANSCODE} AND "video"."waitTranscoding" IS false))`
|
||||||
|
|
|
@ -1085,7 +1085,7 @@ export class VideoModel extends Model<VideoModel> {
|
||||||
historyOfUser?: MUserId
|
historyOfUser?: MUserId
|
||||||
countVideos?: boolean
|
countVideos?: boolean
|
||||||
}) {
|
}) {
|
||||||
if (options.filter && options.filter === 'all-local' && !options.user.hasRight(UserRight.SEE_ALL_VIDEOS)) {
|
if ((options.filter === 'all-local' || options.filter === 'all') && !options.user.hasRight(UserRight.SEE_ALL_VIDEOS)) {
|
||||||
throw new Error('Try to filter all-local but no user has not the see all videos right')
|
throw new Error('Try to filter all-local but no user has not the see all videos right')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -78,28 +78,33 @@ describe('Test videos filters', function () {
|
||||||
await testEndpoints(server, server.accessToken, 'local', 200)
|
await testEndpoints(server, server.accessToken, 'local', 200)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should fail to list all-local with a simple user', async function () {
|
it('Should fail to list all-local/all with a simple user', async function () {
|
||||||
await testEndpoints(server, userAccessToken, 'all-local', 401)
|
await testEndpoints(server, userAccessToken, 'all-local', 401)
|
||||||
|
await testEndpoints(server, userAccessToken, 'all', 401)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should succeed to list all-local with a moderator', async function () {
|
it('Should succeed to list all-local/all with a moderator', async function () {
|
||||||
await testEndpoints(server, moderatorAccessToken, 'all-local', 200)
|
await testEndpoints(server, moderatorAccessToken, 'all-local', 200)
|
||||||
|
await testEndpoints(server, moderatorAccessToken, 'all', 200)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should succeed to list all-local with an admin', async function () {
|
it('Should succeed to list all-local/all with an admin', async function () {
|
||||||
await testEndpoints(server, server.accessToken, 'all-local', 200)
|
await testEndpoints(server, server.accessToken, 'all-local', 200)
|
||||||
|
await testEndpoints(server, server.accessToken, 'all', 200)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Because we cannot authenticate the user on the RSS endpoint
|
// Because we cannot authenticate the user on the RSS endpoint
|
||||||
it('Should fail on the feeds endpoint with the all-local filter', async function () {
|
it('Should fail on the feeds endpoint with the all-local/all filter', async function () {
|
||||||
await makeGetRequest({
|
for (const filter of [ 'all', 'all-local' ]) {
|
||||||
url: server.url,
|
await makeGetRequest({
|
||||||
path: '/feeds/videos.json',
|
url: server.url,
|
||||||
statusCodeExpected: 401,
|
path: '/feeds/videos.json',
|
||||||
query: {
|
statusCodeExpected: 401,
|
||||||
filter: 'all-local'
|
query: {
|
||||||
}
|
filter
|
||||||
})
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should succeed on the feeds endpoint with the local filter', async function () {
|
it('Should succeed on the feeds endpoint with the local filter', async function () {
|
||||||
|
|
|
@ -116,6 +116,20 @@ describe('Test videos filter validator', function () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('Should display all videos by the admin or the moderator', async function () {
|
||||||
|
for (const server of servers) {
|
||||||
|
for (const token of [ server.accessToken, server['moderatorAccessToken'] ]) {
|
||||||
|
|
||||||
|
const [ channelVideos, accountVideos, videos, searchVideos ] = await getVideosNames(server, token, 'all')
|
||||||
|
expect(channelVideos).to.have.lengthOf(3)
|
||||||
|
expect(accountVideos).to.have.lengthOf(3)
|
||||||
|
|
||||||
|
expect(videos).to.have.lengthOf(5)
|
||||||
|
expect(searchVideos).to.have.lengthOf(5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
after(async function () {
|
after(async function () {
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
export type VideoFilter = 'local' | 'all-local'
|
export type VideoFilter = 'local' | 'all-local' | 'all'
|
||||||
|
|
|
@ -3681,9 +3681,10 @@ components:
|
||||||
in: query
|
in: query
|
||||||
required: false
|
required: false
|
||||||
description: >
|
description: >
|
||||||
Special filters (local for instance) which might require special rights:
|
Special filters which might require special rights:
|
||||||
* `local` - only videos local to the instance
|
* `local` - only videos local to the instance
|
||||||
* `all-local` - only videos local to the instance, but showing private and unlisted videos (requires Admin privileges)
|
* `all-local` - only videos local to the instance, but showing private and unlisted videos (requires Admin privileges)
|
||||||
|
* `all` - all videos, showing private and unlisted videos (requires Admin privileges)
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
enum:
|
enum:
|
||||||
|
|
Loading…
Reference in New Issue