aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2021-10-20 09:05:43 +0200
committerChocobozzz <me@florianbigard.com>2021-10-20 09:25:44 +0200
commit978c87e7f58b6673fe60f04f1767bc9e02ea4936 (patch)
treee7d48735d4099fec8c7732f33e7dadb09c0eac80
parent7e76cc380040e40a2292a9dc825f037c9b538030 (diff)
downloadPeerTube-978c87e7f58b6673fe60f04f1767bc9e02ea4936.tar.gz
PeerTube-978c87e7f58b6673fe60f04f1767bc9e02ea4936.tar.zst
PeerTube-978c87e7f58b6673fe60f04f1767bc9e02ea4936.zip
Add channel filters for my videos/followers
-rw-r--r--client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts17
-rw-r--r--client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.ts17
-rw-r--r--client/src/app/+admin/users/user-list/user-list.component.ts9
-rw-r--r--client/src/app/+my-library/my-follows/my-followers.component.ts11
-rw-r--r--client/src/app/+my-library/my-videos/my-videos.component.ts46
-rw-r--r--client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts41
-rw-r--r--client/src/app/shared/shared-forms/advanced-input-filter.component.html10
-rw-r--r--client/src/app/shared/shared-forms/advanced-input-filter.component.ts8
-rw-r--r--client/src/app/shared/shared-main/video/video.service.ts20
-rw-r--r--server/controllers/api/users/me.ts4
-rw-r--r--server/middlewares/validators/users.ts27
-rw-r--r--server/models/video/video.ts9
-rw-r--r--server/tests/api/check-params/videos.ts14
-rw-r--r--server/tests/api/users/users.ts25
-rw-r--r--shared/extra-utils/videos/videos-command.ts3
15 files changed, 207 insertions, 54 deletions
diff --git a/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts
index 3edcb1c63..7baf34ca2 100644
--- a/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts
+++ b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts
@@ -28,12 +28,17 @@ export class VideoBlockListComponent extends RestTable implements OnInit {
28 28
29 inputFilters: AdvancedInputFilter[] = [ 29 inputFilters: AdvancedInputFilter[] = [
30 { 30 {
31 queryParams: { search: 'type:auto' }, 31 title: $localize`Advanced filters`,
32 label: $localize`Automatic blocks` 32 children: [
33 }, 33 {
34 { 34 queryParams: { search: 'type:auto' },
35 queryParams: { search: 'type:manual' }, 35 label: $localize`Automatic blocks`
36 label: $localize`Manual blocks` 36 },
37 {
38 queryParams: { search: 'type:manual' },
39 label: $localize`Manual blocks`
40 }
41 ]
37 } 42 }
38 ] 43 ]
39 44
diff --git a/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.ts b/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.ts
index c09ce7293..a60b228af 100644
--- a/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.ts
+++ b/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.ts
@@ -44,12 +44,17 @@ export class VideoCommentListComponent extends RestTable implements OnInit {
44 44
45 inputFilters: AdvancedInputFilter[] = [ 45 inputFilters: AdvancedInputFilter[] = [
46 { 46 {
47 queryParams: { search: 'local:true' }, 47 title: $localize`Advanced filters`,
48 label: $localize`Local comments` 48 children: [
49 }, 49 {
50 { 50 queryParams: { search: 'local:true' },
51 queryParams: { search: 'local:false' }, 51 label: $localize`Local comments`
52 label: $localize`Remote comments` 52 },
53 {
54 queryParams: { search: 'local:false' },
55 label: $localize`Remote comments`
56 }
57 ]
53 } 58 }
54 ] 59 ]
55 60
diff --git a/client/src/app/+admin/users/user-list/user-list.component.ts b/client/src/app/+admin/users/user-list/user-list.component.ts
index 1030759df..548e6e80f 100644
--- a/client/src/app/+admin/users/user-list/user-list.component.ts
+++ b/client/src/app/+admin/users/user-list/user-list.component.ts
@@ -36,8 +36,13 @@ export class UserListComponent extends RestTable implements OnInit {
36 36
37 inputFilters: AdvancedInputFilter[] = [ 37 inputFilters: AdvancedInputFilter[] = [
38 { 38 {
39 queryParams: { search: 'banned:true' }, 39 title: $localize`Advanced filters`,
40 label: $localize`Banned users` 40 children: [
41 {
42 queryParams: { search: 'banned:true' },
43 label: $localize`Banned users`
44 }
45 ]
41 } 46 }
42 ] 47 ]
43 48
diff --git a/client/src/app/+my-library/my-follows/my-followers.component.ts b/client/src/app/+my-library/my-follows/my-followers.component.ts
index 413d524df..4a72b983f 100644
--- a/client/src/app/+my-library/my-follows/my-followers.component.ts
+++ b/client/src/app/+my-library/my-follows/my-followers.component.ts
@@ -37,12 +37,19 @@ export class MyFollowersComponent implements OnInit {
37 } 37 }
38 38
39 this.auth.userInformationLoaded.subscribe(() => { 39 this.auth.userInformationLoaded.subscribe(() => {
40 this.inputFilters = this.auth.getUser().videoChannels.map(c => { 40 const channelFilters = this.auth.getUser().videoChannels.map(c => {
41 return { 41 return {
42 queryParams: { search: 'channel:' + c.name }, 42 queryParams: { search: 'channel:' + c.name },
43 label: $localize`Followers of ${c.name}` 43 label: c.name
44 } 44 }
45 }) 45 })
46
47 this.inputFilters = [
48 {
49 title: $localize`Channel filters`,
50 children: channelFilters
51 }
52 ]
46 }) 53 })
47 } 54 }
48 55
diff --git a/client/src/app/+my-library/my-videos/my-videos.component.ts b/client/src/app/+my-library/my-videos/my-videos.component.ts
index b1f3baf80..a117d0915 100644
--- a/client/src/app/+my-library/my-videos/my-videos.component.ts
+++ b/client/src/app/+my-library/my-videos/my-videos.component.ts
@@ -9,7 +9,7 @@ import { AdvancedInputFilter } from '@app/shared/shared-forms'
9import { DropdownAction, Video, VideoService } from '@app/shared/shared-main' 9import { DropdownAction, Video, VideoService } from '@app/shared/shared-main'
10import { LiveStreamInformationComponent } from '@app/shared/shared-video-live' 10import { LiveStreamInformationComponent } from '@app/shared/shared-video-live'
11import { MiniatureDisplayOptions, SelectionType, VideosSelectionComponent } from '@app/shared/shared-video-miniature' 11import { MiniatureDisplayOptions, SelectionType, VideosSelectionComponent } from '@app/shared/shared-video-miniature'
12import { VideoSortField } from '@shared/models' 12import { VideoChannel, VideoSortField } from '@shared/models'
13import { VideoChangeOwnershipComponent } from './modals/video-change-ownership.component' 13import { VideoChangeOwnershipComponent } from './modals/video-change-ownership.component'
14 14
15@Component({ 15@Component({
@@ -47,16 +47,12 @@ export class MyVideosComponent implements OnInit, DisableForReuseHook {
47 47
48 user: User 48 user: User
49 49
50 inputFilters: AdvancedInputFilter[] = [ 50 inputFilters: AdvancedInputFilter[]
51 {
52 queryParams: { search: 'isLive:true' },
53 label: $localize`Only live videos`
54 }
55 ]
56 51
57 disabled = false 52 disabled = false
58 53
59 private search: string 54 private search: string
55 private userChannels: VideoChannel[] = []
60 56
61 constructor ( 57 constructor (
62 protected router: Router, 58 protected router: Router,
@@ -79,6 +75,35 @@ export class MyVideosComponent implements OnInit, DisableForReuseHook {
79 if (this.route.snapshot.queryParams['search']) { 75 if (this.route.snapshot.queryParams['search']) {
80 this.search = this.route.snapshot.queryParams['search'] 76 this.search = this.route.snapshot.queryParams['search']
81 } 77 }
78
79 this.authService.userInformationLoaded.subscribe(() => {
80 this.user = this.authService.getUser()
81 this.userChannels = this.user.videoChannels
82
83 const channelFilters = this.userChannels.map(c => {
84 return {
85 queryParams: { search: 'channel:' + c.name },
86 label: c.name
87 }
88 })
89
90 this.inputFilters = [
91 {
92 title: $localize`Advanced filters`,
93 children: [
94 {
95 queryParams: { search: 'isLive:true' },
96 label: $localize`Only live videos`
97 }
98 ]
99 },
100
101 {
102 title: $localize`Channel filters`,
103 children: channelFilters
104 }
105 ]
106 })
82 } 107 }
83 108
84 onSearch (search: string) { 109 onSearch (search: string) {
@@ -105,7 +130,12 @@ export class MyVideosComponent implements OnInit, DisableForReuseHook {
105 getVideosObservable (page: number) { 130 getVideosObservable (page: number) {
106 const newPagination = immutableAssign(this.pagination, { currentPage: page }) 131 const newPagination = immutableAssign(this.pagination, { currentPage: page })
107 132
108 return this.videoService.getMyVideos(newPagination, this.sort, this.search) 133 return this.videoService.getMyVideos({
134 videoPagination: newPagination,
135 sort: this.sort,
136 userChannels: this.userChannels,
137 search: this.search
138 })
109 .pipe( 139 .pipe(
110 tap(res => this.pagination.totalItems = res.total) 140 tap(res => this.pagination.totalItems = res.total)
111 ) 141 )
diff --git a/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts b/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts
index 33e9fd8de..297993e39 100644
--- a/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts
+++ b/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts
@@ -39,24 +39,29 @@ export class AbuseListTableComponent extends RestTable implements OnInit {
39 39
40 inputFilters: AdvancedInputFilter[] = [ 40 inputFilters: AdvancedInputFilter[] = [
41 { 41 {
42 queryParams: { search: 'state:pending' }, 42 title: $localize`Advanced filters`,
43 label: $localize`Unsolved reports` 43 children: [
44 }, 44 {
45 { 45 queryParams: { search: 'state:pending' },
46 queryParams: { search: 'state:accepted' }, 46 label: $localize`Unsolved reports`
47 label: $localize`Accepted reports` 47 },
48 }, 48 {
49 { 49 queryParams: { search: 'state:accepted' },
50 queryParams: { search: 'state:rejected' }, 50 label: $localize`Accepted reports`
51 label: $localize`Refused reports` 51 },
52 }, 52 {
53 { 53 queryParams: { search: 'state:rejected' },
54 queryParams: { search: 'videoIs:blacklisted' }, 54 label: $localize`Refused reports`
55 label: $localize`Reports with blocked videos` 55 },
56 }, 56 {
57 { 57 queryParams: { search: 'videoIs:blacklisted' },
58 queryParams: { search: 'videoIs:deleted' }, 58 label: $localize`Reports with blocked videos`
59 label: $localize`Reports with deleted videos` 59 },
60 {
61 queryParams: { search: 'videoIs:deleted' },
62 label: $localize`Reports with deleted videos`
63 }
64 ]
60 } 65 }
61 ] 66 ]
62 67
diff --git a/client/src/app/shared/shared-forms/advanced-input-filter.component.html b/client/src/app/shared/shared-forms/advanced-input-filter.component.html
index 10d1296cf..c662b9bb6 100644
--- a/client/src/app/shared/shared-forms/advanced-input-filter.component.html
+++ b/client/src/app/shared/shared-forms/advanced-input-filter.component.html
@@ -5,11 +5,13 @@
5 </div> 5 </div>
6 6
7 <div role="menu" ngbDropdownMenu> 7 <div role="menu" ngbDropdownMenu>
8 <h6 class="dropdown-header" i18n>Advanced filters</h6> 8 <ng-container *ngFor="let group of filters">
9 <h6 class="dropdown-header">{{ group.title }}</h6>
9 10
10 <a *ngFor="let filter of filters" [routerLink]="[ '.' ]" [queryParams]="filter.queryParams" class="dropdown-item"> 11 <a *ngFor="let filter of group.children" [routerLink]="[ '.' ]" [queryParams]="filter.queryParams" class="dropdown-item">
11 {{ filter.label }} 12 {{ filter.label }}
12 </a> 13 </a>
14 </ng-container>
13 </div> 15 </div>
14 </div> 16 </div>
15 17
diff --git a/client/src/app/shared/shared-forms/advanced-input-filter.component.ts b/client/src/app/shared/shared-forms/advanced-input-filter.component.ts
index 8315662b4..a12dddf7a 100644
--- a/client/src/app/shared/shared-forms/advanced-input-filter.component.ts
+++ b/client/src/app/shared/shared-forms/advanced-input-filter.component.ts
@@ -5,8 +5,12 @@ import { AfterViewInit, Component, EventEmitter, Input, OnInit, Output } from '@
5import { ActivatedRoute, Params, Router } from '@angular/router' 5import { ActivatedRoute, Params, Router } from '@angular/router'
6 6
7export type AdvancedInputFilter = { 7export type AdvancedInputFilter = {
8 label: string 8 title: string
9 queryParams: Params 9
10 children: {
11 label: string
12 queryParams: Params
13 }[]
10} 14}
11 15
12const logger = debug('peertube:AdvancedInputFilterComponent') 16const logger = debug('peertube:AdvancedInputFilterComponent')
diff --git a/client/src/app/shared/shared-main/video/video.service.ts b/client/src/app/shared/shared-main/video/video.service.ts
index 2f43f1b9d..7935569e7 100644
--- a/client/src/app/shared/shared-main/video/video.service.ts
+++ b/client/src/app/shared/shared-main/video/video.service.ts
@@ -13,6 +13,7 @@ import {
13 UserVideoRateType, 13 UserVideoRateType,
14 UserVideoRateUpdate, 14 UserVideoRateUpdate,
15 Video as VideoServerModel, 15 Video as VideoServerModel,
16 VideoChannel as VideoChannelServerModel,
16 VideoConstant, 17 VideoConstant,
17 VideoDetails as VideoDetailsServerModel, 18 VideoDetails as VideoDetailsServerModel,
18 VideoFileMetadata, 19 VideoFileMetadata,
@@ -122,7 +123,14 @@ export class VideoService {
122 .pipe(catchError(err => this.restExtractor.handleError(err))) 123 .pipe(catchError(err => this.restExtractor.handleError(err)))
123 } 124 }
124 125
125 getMyVideos (videoPagination: ComponentPaginationLight, sort: VideoSortField, search?: string): Observable<ResultList<Video>> { 126 getMyVideos (options: {
127 videoPagination: ComponentPaginationLight
128 sort: VideoSortField
129 userChannels?: VideoChannelServerModel[]
130 search?: string
131 }): Observable<ResultList<Video>> {
132 const { videoPagination, sort, userChannels = [], search } = options
133
126 const pagination = this.restService.componentToRestPagination(videoPagination) 134 const pagination = this.restService.componentToRestPagination(videoPagination)
127 135
128 let params = new HttpParams() 136 let params = new HttpParams()
@@ -133,6 +141,16 @@ export class VideoService {
133 isLive: { 141 isLive: {
134 prefix: 'isLive:', 142 prefix: 'isLive:',
135 isBoolean: true 143 isBoolean: true
144 },
145 channelId: {
146 prefix: 'channel:',
147 handler: (name: string) => {
148 const channel = userChannels.find(c => c.name === name)
149
150 if (channel) return channel.id
151
152 return undefined
153 }
136 } 154 }
137 }) 155 })
138 156
diff --git a/server/controllers/api/users/me.ts b/server/controllers/api/users/me.ts
index 83b774d3c..6bacdbbb6 100644
--- a/server/controllers/api/users/me.ts
+++ b/server/controllers/api/users/me.ts
@@ -25,7 +25,7 @@ import {
25 usersUpdateMeValidator, 25 usersUpdateMeValidator,
26 usersVideoRatingValidator 26 usersVideoRatingValidator
27} from '../../../middlewares' 27} from '../../../middlewares'
28import { deleteMeValidator, videoImportsSortValidator, videosSortValidator } from '../../../middlewares/validators' 28import { deleteMeValidator, usersVideosValidator, videoImportsSortValidator, videosSortValidator } from '../../../middlewares/validators'
29import { updateAvatarValidator } from '../../../middlewares/validators/actor-image' 29import { updateAvatarValidator } from '../../../middlewares/validators/actor-image'
30import { AccountModel } from '../../../models/account/account' 30import { AccountModel } from '../../../models/account/account'
31import { AccountVideoRateModel } from '../../../models/account/account-video-rate' 31import { AccountVideoRateModel } from '../../../models/account/account-video-rate'
@@ -69,6 +69,7 @@ meRouter.get('/me/videos',
69 videosSortValidator, 69 videosSortValidator,
70 setDefaultVideosSort, 70 setDefaultVideosSort,
71 setDefaultPagination, 71 setDefaultPagination,
72 asyncMiddleware(usersVideosValidator),
72 asyncMiddleware(getUserVideos) 73 asyncMiddleware(getUserVideos)
73) 74)
74 75
@@ -113,6 +114,7 @@ async function getUserVideos (req: express.Request, res: express.Response) {
113 count: req.query.count, 114 count: req.query.count,
114 sort: req.query.sort, 115 sort: req.query.sort,
115 search: req.query.search, 116 search: req.query.search,
117 channelId: res.locals.videoChannel?.id,
116 isLive: req.query.isLive 118 isLive: req.query.isLive
117 }, 'filter:api.user.me.videos.list.params') 119 }, 'filter:api.user.me.videos.list.params')
118 120
diff --git a/server/middlewares/validators/users.ts b/server/middlewares/validators/users.ts
index c6eeeaf18..8f1a7801f 100644
--- a/server/middlewares/validators/users.ts
+++ b/server/middlewares/validators/users.ts
@@ -4,7 +4,7 @@ import { omit } from 'lodash'
4import { Hooks } from '@server/lib/plugins/hooks' 4import { Hooks } from '@server/lib/plugins/hooks'
5import { MUserDefault } from '@server/types/models' 5import { MUserDefault } from '@server/types/models'
6import { HttpStatusCode, UserRegister, UserRole } from '@shared/models' 6import { HttpStatusCode, UserRegister, UserRole } from '@shared/models'
7import { toBooleanOrNull, toIntOrNull } from '../../helpers/custom-validators/misc' 7import { isBooleanValid, isIdValid, toBooleanOrNull, toIntOrNull } from '../../helpers/custom-validators/misc'
8import { isThemeNameValid } from '../../helpers/custom-validators/plugins' 8import { isThemeNameValid } from '../../helpers/custom-validators/plugins'
9import { 9import {
10 isUserAdminFlagsValid, 10 isUserAdminFlagsValid,
@@ -31,7 +31,7 @@ import { Redis } from '../../lib/redis'
31import { isSignupAllowed, isSignupAllowedForCurrentIP } from '../../lib/signup' 31import { isSignupAllowed, isSignupAllowedForCurrentIP } from '../../lib/signup'
32import { ActorModel } from '../../models/actor/actor' 32import { ActorModel } from '../../models/actor/actor'
33import { UserModel } from '../../models/user/user' 33import { UserModel } from '../../models/user/user'
34import { areValidationErrors, doesVideoExist, isValidVideoIdParam } from './shared' 34import { areValidationErrors, doesVideoChannelIdExist, doesVideoExist, isValidVideoIdParam } from './shared'
35 35
36const usersListValidator = [ 36const usersListValidator = [
37 query('blocked') 37 query('blocked')
@@ -318,6 +318,28 @@ const usersVideoRatingValidator = [
318 } 318 }
319] 319]
320 320
321const usersVideosValidator = [
322 query('isLive')
323 .optional()
324 .customSanitizer(toBooleanOrNull)
325 .custom(isBooleanValid).withMessage('Should have a valid live boolean'),
326
327 query('channelId')
328 .optional()
329 .customSanitizer(toIntOrNull)
330 .custom(isIdValid).withMessage('Should have a valid channel id'),
331
332 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
333 logger.debug('Checking usersVideosValidator parameters', { parameters: req.params })
334
335 if (areValidationErrors(req, res)) return
336
337 if (req.query.channelId && !await doesVideoChannelIdExist(req.query.channelId, res)) return
338
339 return next()
340 }
341]
342
321const ensureUserRegistrationAllowed = [ 343const ensureUserRegistrationAllowed = [
322 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 344 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
323 const allowedParams = { 345 const allowedParams = {
@@ -513,6 +535,7 @@ export {
513 ensureUserRegistrationAllowed, 535 ensureUserRegistrationAllowed,
514 ensureUserRegistrationAllowedForIP, 536 ensureUserRegistrationAllowedForIP,
515 usersGetValidator, 537 usersGetValidator,
538 usersVideosValidator,
516 usersAskResetPasswordValidator, 539 usersAskResetPasswordValidator,
517 usersResetPasswordValidator, 540 usersResetPasswordValidator,
518 usersAskSendVerifyEmailValidator, 541 usersAskSendVerifyEmailValidator,
diff --git a/server/models/video/video.ts b/server/models/video/video.ts
index d2daf18ee..4044287ee 100644
--- a/server/models/video/video.ts
+++ b/server/models/video/video.ts
@@ -978,10 +978,12 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> {
978 start: number 978 start: number
979 count: number 979 count: number
980 sort: string 980 sort: string
981
982 channelId?: number
981 isLive?: boolean 983 isLive?: boolean
982 search?: string 984 search?: string
983 }) { 985 }) {
984 const { accountId, start, count, sort, search, isLive } = options 986 const { accountId, channelId, start, count, sort, search, isLive } = options
985 987
986 function buildBaseQuery (): FindOptions { 988 function buildBaseQuery (): FindOptions {
987 const where: WhereOptions = {} 989 const where: WhereOptions = {}
@@ -996,6 +998,10 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> {
996 where.isLive = isLive 998 where.isLive = isLive
997 } 999 }
998 1000
1001 const channelWhere = channelId
1002 ? { id: channelId }
1003 : {}
1004
999 const baseQuery = { 1005 const baseQuery = {
1000 offset: start, 1006 offset: start,
1001 limit: count, 1007 limit: count,
@@ -1005,6 +1011,7 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> {
1005 { 1011 {
1006 model: VideoChannelModel, 1012 model: VideoChannelModel,
1007 required: true, 1013 required: true,
1014 where: channelWhere,
1008 include: [ 1015 include: [
1009 { 1016 {
1010 model: AccountModel, 1017 model: AccountModel,
diff --git a/server/tests/api/check-params/videos.ts b/server/tests/api/check-params/videos.ts
index e11ca0c82..d02b6e156 100644
--- a/server/tests/api/check-params/videos.ts
+++ b/server/tests/api/check-params/videos.ts
@@ -119,6 +119,20 @@ describe('Test videos API validator', function () {
119 await checkBadSortPagination(server.url, path, server.accessToken) 119 await checkBadSortPagination(server.url, path, server.accessToken)
120 }) 120 })
121 121
122 it('Should fail with an invalid channel', async function () {
123 await makeGetRequest({ url: server.url, token: server.accessToken, path, query: { channelId: 'toto' } })
124 })
125
126 it('Should fail with an unknown channel', async function () {
127 await makeGetRequest({
128 url: server.url,
129 token: server.accessToken,
130 path,
131 query: { channelId: 89898 },
132 expectedStatus: HttpStatusCode.NOT_FOUND_404
133 })
134 })
135
122 it('Should success with the correct parameters', async function () { 136 it('Should success with the correct parameters', async function () {
123 await makeGetRequest({ url: server.url, token: server.accessToken, path, expectedStatus: HttpStatusCode.OK_200 }) 137 await makeGetRequest({ url: server.url, token: server.accessToken, path, expectedStatus: HttpStatusCode.OK_200 })
124 }) 138 })
diff --git a/server/tests/api/users/users.ts b/server/tests/api/users/users.ts
index 085d9d870..6c41e7d56 100644
--- a/server/tests/api/users/users.ts
+++ b/server/tests/api/users/users.ts
@@ -318,6 +318,8 @@ describe('Test users', function () {
318 fixture: 'video_short.webm' 318 fixture: 'video_short.webm'
319 } 319 }
320 await server.videos.upload({ token: userToken, attributes }) 320 await server.videos.upload({ token: userToken, attributes })
321
322 await server.channels.create({ token: userToken, attributes: { name: 'other_channel' } })
321 }) 323 })
322 324
323 it('Should have video quota updated', async function () { 325 it('Should have video quota updated', async function () {
@@ -340,6 +342,29 @@ describe('Test users', function () {
340 expect(video.previewPath).to.not.be.null 342 expect(video.previewPath).to.not.be.null
341 }) 343 })
342 344
345 it('Should be able to filter by channel in my videos', async function () {
346 const myInfo = await server.users.getMyInfo({ token: userToken })
347 const mainChannel = myInfo.videoChannels.find(c => c.name !== 'other_channel')
348 const otherChannel = myInfo.videoChannels.find(c => c.name === 'other_channel')
349
350 {
351 const { total, data } = await server.videos.listMyVideos({ token: userToken, channelId: mainChannel.id })
352 expect(total).to.equal(1)
353 expect(data).to.have.lengthOf(1)
354
355 const video: Video = data[0]
356 expect(video.name).to.equal('super user video')
357 expect(video.thumbnailPath).to.not.be.null
358 expect(video.previewPath).to.not.be.null
359 }
360
361 {
362 const { total, data } = await server.videos.listMyVideos({ token: userToken, channelId: otherChannel.id })
363 expect(total).to.equal(0)
364 expect(data).to.have.lengthOf(0)
365 }
366 })
367
343 it('Should be able to search in my videos', async function () { 368 it('Should be able to search in my videos', async function () {
344 { 369 {
345 const { total, data } = await server.videos.listMyVideos({ token: userToken, sort: '-createdAt', search: 'user video' }) 370 const { total, data } = await server.videos.listMyVideos({ token: userToken, sort: '-createdAt', search: 'user video' })
diff --git a/shared/extra-utils/videos/videos-command.ts b/shared/extra-utils/videos/videos-command.ts
index 99f56a34c..c1a9ec806 100644
--- a/shared/extra-utils/videos/videos-command.ts
+++ b/shared/extra-utils/videos/videos-command.ts
@@ -207,6 +207,7 @@ export class VideosCommand extends AbstractCommand {
207 sort?: string 207 sort?: string
208 search?: string 208 search?: string
209 isLive?: boolean 209 isLive?: boolean
210 channelId?: number
210 } = {}) { 211 } = {}) {
211 const path = '/api/v1/users/me/videos' 212 const path = '/api/v1/users/me/videos'
212 213
@@ -214,7 +215,7 @@ export class VideosCommand extends AbstractCommand {
214 ...options, 215 ...options,
215 216
216 path, 217 path,
217 query: pick(options, [ 'start', 'count', 'sort', 'search', 'isLive' ]), 218 query: pick(options, [ 'start', 'count', 'sort', 'search', 'isLive', 'channelId' ]),
218 implicitToken: true, 219 implicitToken: true,
219 defaultExpectedStatus: HttpStatusCode.OK_200 220 defaultExpectedStatus: HttpStatusCode.OK_200
220 }) 221 })