Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Framasoft
PeerTube
PeerTube
Commits
978c87e7
Verified
Commit
978c87e7
authored
Oct 20, 2021
by
Chocobozzz
Browse files
Add channel filters for my videos/followers
parent
7e76cc38
Changes
15
Hide whitespace changes
Inline
Side-by-side
client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts
View file @
978c87e7
...
...
@@ -28,12 +28,17 @@ export class VideoBlockListComponent extends RestTable implements OnInit {
inputFilters
:
AdvancedInputFilter
[]
=
[
{
queryParams
:
{
search
:
'
type:auto
'
},
label
:
$localize
`Automatic blocks`
},
{
queryParams
:
{
search
:
'
type:manual
'
},
label
:
$localize
`Manual blocks`
title
:
$localize
`Advanced filters`
,
children
:
[
{
queryParams
:
{
search
:
'
type:auto
'
},
label
:
$localize
`Automatic blocks`
},
{
queryParams
:
{
search
:
'
type:manual
'
},
label
:
$localize
`Manual blocks`
}
]
}
]
...
...
client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.ts
View file @
978c87e7
...
...
@@ -44,12 +44,17 @@ export class VideoCommentListComponent extends RestTable implements OnInit {
inputFilters
:
AdvancedInputFilter
[]
=
[
{
queryParams
:
{
search
:
'
local:true
'
},
label
:
$localize
`Local comments`
},
{
queryParams
:
{
search
:
'
local:false
'
},
label
:
$localize
`Remote comments`
title
:
$localize
`Advanced filters`
,
children
:
[
{
queryParams
:
{
search
:
'
local:true
'
},
label
:
$localize
`Local comments`
},
{
queryParams
:
{
search
:
'
local:false
'
},
label
:
$localize
`Remote comments`
}
]
}
]
...
...
client/src/app/+admin/users/user-list/user-list.component.ts
View file @
978c87e7
...
...
@@ -36,8 +36,13 @@ export class UserListComponent extends RestTable implements OnInit {
inputFilters
:
AdvancedInputFilter
[]
=
[
{
queryParams
:
{
search
:
'
banned:true
'
},
label
:
$localize
`Banned users`
title
:
$localize
`Advanced filters`
,
children
:
[
{
queryParams
:
{
search
:
'
banned:true
'
},
label
:
$localize
`Banned users`
}
]
}
]
...
...
client/src/app/+my-library/my-follows/my-followers.component.ts
View file @
978c87e7
...
...
@@ -37,12 +37,19 @@ export class MyFollowersComponent implements OnInit {
}
this
.
auth
.
userInformationLoaded
.
subscribe
(()
=>
{
this
.
input
Filters
=
this
.
auth
.
getUser
().
videoChannels
.
map
(
c
=>
{
const
channel
Filters
=
this
.
auth
.
getUser
().
videoChannels
.
map
(
c
=>
{
return
{
queryParams
:
{
search
:
'
channel:
'
+
c
.
name
},
label
:
$localize
`Followers of
${
c
.
name
}
`
label
:
c
.
name
}
})
this
.
inputFilters
=
[
{
title
:
$localize
`Channel filters`
,
children
:
channelFilters
}
]
})
}
...
...
client/src/app/+my-library/my-videos/my-videos.component.ts
View file @
978c87e7
...
...
@@ -9,7 +9,7 @@ import { AdvancedInputFilter } from '@app/shared/shared-forms'
import
{
DropdownAction
,
Video
,
VideoService
}
from
'
@app/shared/shared-main
'
import
{
LiveStreamInformationComponent
}
from
'
@app/shared/shared-video-live
'
import
{
MiniatureDisplayOptions
,
SelectionType
,
VideosSelectionComponent
}
from
'
@app/shared/shared-video-miniature
'
import
{
VideoSortField
}
from
'
@shared/models
'
import
{
VideoChannel
,
VideoSortField
}
from
'
@shared/models
'
import
{
VideoChangeOwnershipComponent
}
from
'
./modals/video-change-ownership.component
'
@
Component
({
...
...
@@ -47,16 +47,12 @@ export class MyVideosComponent implements OnInit, DisableForReuseHook {
user
:
User
inputFilters
:
AdvancedInputFilter
[]
=
[
{
queryParams
:
{
search
:
'
isLive:true
'
},
label
:
$localize
`Only live videos`
}
]
inputFilters
:
AdvancedInputFilter
[]
disabled
=
false
private
search
:
string
private
userChannels
:
VideoChannel
[]
=
[]
constructor
(
protected
router
:
Router
,
...
...
@@ -79,6 +75,35 @@ export class MyVideosComponent implements OnInit, DisableForReuseHook {
if
(
this
.
route
.
snapshot
.
queryParams
[
'
search
'
])
{
this
.
search
=
this
.
route
.
snapshot
.
queryParams
[
'
search
'
]
}
this
.
authService
.
userInformationLoaded
.
subscribe
(()
=>
{
this
.
user
=
this
.
authService
.
getUser
()
this
.
userChannels
=
this
.
user
.
videoChannels
const
channelFilters
=
this
.
userChannels
.
map
(
c
=>
{
return
{
queryParams
:
{
search
:
'
channel:
'
+
c
.
name
},
label
:
c
.
name
}
})
this
.
inputFilters
=
[
{
title
:
$localize
`Advanced filters`
,
children
:
[
{
queryParams
:
{
search
:
'
isLive:true
'
},
label
:
$localize
`Only live videos`
}
]
},
{
title
:
$localize
`Channel filters`
,
children
:
channelFilters
}
]
})
}
onSearch
(
search
:
string
)
{
...
...
@@ -105,7 +130,12 @@ export class MyVideosComponent implements OnInit, DisableForReuseHook {
getVideosObservable
(
page
:
number
)
{
const
newPagination
=
immutableAssign
(
this
.
pagination
,
{
currentPage
:
page
})
return
this
.
videoService
.
getMyVideos
(
newPagination
,
this
.
sort
,
this
.
search
)
return
this
.
videoService
.
getMyVideos
({
videoPagination
:
newPagination
,
sort
:
this
.
sort
,
userChannels
:
this
.
userChannels
,
search
:
this
.
search
})
.
pipe
(
tap
(
res
=>
this
.
pagination
.
totalItems
=
res
.
total
)
)
...
...
client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts
View file @
978c87e7
...
...
@@ -39,24 +39,29 @@ export class AbuseListTableComponent extends RestTable implements OnInit {
inputFilters
:
AdvancedInputFilter
[]
=
[
{
queryParams
:
{
search
:
'
state:pending
'
},
label
:
$localize
`Unsolved reports`
},
{
queryParams
:
{
search
:
'
state:accepted
'
},
label
:
$localize
`Accepted reports`
},
{
queryParams
:
{
search
:
'
state:rejected
'
},
label
:
$localize
`Refused reports`
},
{
queryParams
:
{
search
:
'
videoIs:blacklisted
'
},
label
:
$localize
`Reports with blocked videos`
},
{
queryParams
:
{
search
:
'
videoIs:deleted
'
},
label
:
$localize
`Reports with deleted videos`
title
:
$localize
`Advanced filters`
,
children
:
[
{
queryParams
:
{
search
:
'
state:pending
'
},
label
:
$localize
`Unsolved reports`
},
{
queryParams
:
{
search
:
'
state:accepted
'
},
label
:
$localize
`Accepted reports`
},
{
queryParams
:
{
search
:
'
state:rejected
'
},
label
:
$localize
`Refused reports`
},
{
queryParams
:
{
search
:
'
videoIs:blacklisted
'
},
label
:
$localize
`Reports with blocked videos`
},
{
queryParams
:
{
search
:
'
videoIs:deleted
'
},
label
:
$localize
`Reports with deleted videos`
}
]
}
]
...
...
client/src/app/shared/shared-forms/advanced-input-filter.component.html
View file @
978c87e7
...
...
@@ -5,11 +5,13 @@
</div>
<div
role=
"menu"
ngbDropdownMenu
>
<h6
class=
"dropdown-header"
i18n
>
Advanced filters
</h6>
<ng-container
*ngFor=
"let group of filters"
>
<h6
class=
"dropdown-header"
>
{{ group.title }}
</h6>
<a
*ngFor=
"let filter of filters"
[routerLink]=
"[ '.' ]"
[queryParams]=
"filter.queryParams"
class=
"dropdown-item"
>
{{ filter.label }}
</a>
<a
*ngFor=
"let filter of group.children"
[routerLink]=
"[ '.' ]"
[queryParams]=
"filter.queryParams"
class=
"dropdown-item"
>
{{ filter.label }}
</a>
</ng-container>
</div>
</div>
...
...
client/src/app/shared/shared-forms/advanced-input-filter.component.ts
View file @
978c87e7
...
...
@@ -5,8 +5,12 @@ import { AfterViewInit, Component, EventEmitter, Input, OnInit, Output } from '@
import
{
ActivatedRoute
,
Params
,
Router
}
from
'
@angular/router
'
export
type
AdvancedInputFilter
=
{
label
:
string
queryParams
:
Params
title
:
string
children
:
{
label
:
string
queryParams
:
Params
}[]
}
const
logger
=
debug
(
'
peertube:AdvancedInputFilterComponent
'
)
...
...
client/src/app/shared/shared-main/video/video.service.ts
View file @
978c87e7
...
...
@@ -13,6 +13,7 @@ import {
UserVideoRateType
,
UserVideoRateUpdate
,
Video
as
VideoServerModel
,
VideoChannel
as
VideoChannelServerModel
,
VideoConstant
,
VideoDetails
as
VideoDetailsServerModel
,
VideoFileMetadata
,
...
...
@@ -122,7 +123,14 @@ export class VideoService {
.
pipe
(
catchError
(
err
=>
this
.
restExtractor
.
handleError
(
err
)))
}
getMyVideos
(
videoPagination
:
ComponentPaginationLight
,
sort
:
VideoSortField
,
search
?:
string
):
Observable
<
ResultList
<
Video
>>
{
getMyVideos
(
options
:
{
videoPagination
:
ComponentPaginationLight
sort
:
VideoSortField
userChannels
?:
VideoChannelServerModel
[]
search
?:
string
}):
Observable
<
ResultList
<
Video
>>
{
const
{
videoPagination
,
sort
,
userChannels
=
[],
search
}
=
options
const
pagination
=
this
.
restService
.
componentToRestPagination
(
videoPagination
)
let
params
=
new
HttpParams
()
...
...
@@ -133,6 +141,16 @@ export class VideoService {
isLive
:
{
prefix
:
'
isLive:
'
,
isBoolean
:
true
},
channelId
:
{
prefix
:
'
channel:
'
,
handler
:
(
name
:
string
)
=>
{
const
channel
=
userChannels
.
find
(
c
=>
c
.
name
===
name
)
if
(
channel
)
return
channel
.
id
return
undefined
}
}
})
...
...
server/controllers/api/users/me.ts
View file @
978c87e7
...
...
@@ -25,7 +25,7 @@ import {
usersUpdateMeValidator
,
usersVideoRatingValidator
}
from
'
../../../middlewares
'
import
{
deleteMeValidator
,
videoImportsSortValidator
,
videosSortValidator
}
from
'
../../../middlewares/validators
'
import
{
deleteMeValidator
,
usersVideosValidator
,
videoImportsSortValidator
,
videosSortValidator
}
from
'
../../../middlewares/validators
'
import
{
updateAvatarValidator
}
from
'
../../../middlewares/validators/actor-image
'
import
{
AccountModel
}
from
'
../../../models/account/account
'
import
{
AccountVideoRateModel
}
from
'
../../../models/account/account-video-rate
'
...
...
@@ -69,6 +69,7 @@ meRouter.get('/me/videos',
videosSortValidator
,
setDefaultVideosSort
,
setDefaultPagination
,
asyncMiddleware
(
usersVideosValidator
),
asyncMiddleware
(
getUserVideos
)
)
...
...
@@ -113,6 +114,7 @@ async function getUserVideos (req: express.Request, res: express.Response) {
count
:
req
.
query
.
count
,
sort
:
req
.
query
.
sort
,
search
:
req
.
query
.
search
,
channelId
:
res
.
locals
.
videoChannel
?.
id
,
isLive
:
req
.
query
.
isLive
},
'
filter:api.user.me.videos.list.params
'
)
...
...
server/middlewares/validators/users.ts
View file @
978c87e7
...
...
@@ -4,7 +4,7 @@ import { omit } from 'lodash'
import
{
Hooks
}
from
'
@server/lib/plugins/hooks
'
import
{
MUserDefault
}
from
'
@server/types/models
'
import
{
HttpStatusCode
,
UserRegister
,
UserRole
}
from
'
@shared/models
'
import
{
toBooleanOrNull
,
toIntOrNull
}
from
'
../../helpers/custom-validators/misc
'
import
{
isBooleanValid
,
isIdValid
,
toBooleanOrNull
,
toIntOrNull
}
from
'
../../helpers/custom-validators/misc
'
import
{
isThemeNameValid
}
from
'
../../helpers/custom-validators/plugins
'
import
{
isUserAdminFlagsValid
,
...
...
@@ -31,7 +31,7 @@ import { Redis } from '../../lib/redis'
import
{
isSignupAllowed
,
isSignupAllowedForCurrentIP
}
from
'
../../lib/signup
'
import
{
ActorModel
}
from
'
../../models/actor/actor
'
import
{
UserModel
}
from
'
../../models/user/user
'
import
{
areValidationErrors
,
doesVideoExist
,
isValidVideoIdParam
}
from
'
./shared
'
import
{
areValidationErrors
,
doesVideoChannelIdExist
,
doesVideoExist
,
isValidVideoIdParam
}
from
'
./shared
'
const
usersListValidator
=
[
query
(
'
blocked
'
)
...
...
@@ -318,6 +318,28 @@ const usersVideoRatingValidator = [
}
]
const
usersVideosValidator
=
[
query
(
'
isLive
'
)
.
optional
()
.
customSanitizer
(
toBooleanOrNull
)
.
custom
(
isBooleanValid
).
withMessage
(
'
Should have a valid live boolean
'
),
query
(
'
channelId
'
)
.
optional
()
.
customSanitizer
(
toIntOrNull
)
.
custom
(
isIdValid
).
withMessage
(
'
Should have a valid channel id
'
),
async
(
req
:
express
.
Request
,
res
:
express
.
Response
,
next
:
express
.
NextFunction
)
=>
{
logger
.
debug
(
'
Checking usersVideosValidator parameters
'
,
{
parameters
:
req
.
params
})
if
(
areValidationErrors
(
req
,
res
))
return
if
(
req
.
query
.
channelId
&&
!
await
doesVideoChannelIdExist
(
req
.
query
.
channelId
,
res
))
return
return
next
()
}
]
const
ensureUserRegistrationAllowed
=
[
async
(
req
:
express
.
Request
,
res
:
express
.
Response
,
next
:
express
.
NextFunction
)
=>
{
const
allowedParams
=
{
...
...
@@ -513,6 +535,7 @@ export {
ensureUserRegistrationAllowed
,
ensureUserRegistrationAllowedForIP
,
usersGetValidator
,
usersVideosValidator
,
usersAskResetPasswordValidator
,
usersResetPasswordValidator
,
usersAskSendVerifyEmailValidator
,
...
...
server/models/video/video.ts
View file @
978c87e7
...
...
@@ -978,10 +978,12 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> {
start
:
number
count
:
number
sort
:
string
channelId
?:
number
isLive
?:
boolean
search
?:
string
})
{
const
{
accountId
,
start
,
count
,
sort
,
search
,
isLive
}
=
options
const
{
accountId
,
channelId
,
start
,
count
,
sort
,
search
,
isLive
}
=
options
function
buildBaseQuery
():
FindOptions
{
const
where
:
WhereOptions
=
{}
...
...
@@ -996,6 +998,10 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> {
where
.
isLive
=
isLive
}
const
channelWhere
=
channelId
?
{
id
:
channelId
}
:
{}
const
baseQuery
=
{
offset
:
start
,
limit
:
count
,
...
...
@@ -1005,6 +1011,7 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> {
{
model
:
VideoChannelModel
,
required
:
true
,
where
:
channelWhere
,
include
:
[
{
model
:
AccountModel
,
...
...
server/tests/api/check-params/videos.ts
View file @
978c87e7
...
...
@@ -119,6 +119,20 @@ describe('Test videos API validator', function () {
await
checkBadSortPagination
(
server
.
url
,
path
,
server
.
accessToken
)
})
it
(
'
Should fail with an invalid channel
'
,
async
function
()
{
await
makeGetRequest
({
url
:
server
.
url
,
token
:
server
.
accessToken
,
path
,
query
:
{
channelId
:
'
toto
'
}
})
})
it
(
'
Should fail with an unknown channel
'
,
async
function
()
{
await
makeGetRequest
({
url
:
server
.
url
,
token
:
server
.
accessToken
,
path
,
query
:
{
channelId
:
89898
},
expectedStatus
:
HttpStatusCode
.
NOT_FOUND_404
})
})
it
(
'
Should success with the correct parameters
'
,
async
function
()
{
await
makeGetRequest
({
url
:
server
.
url
,
token
:
server
.
accessToken
,
path
,
expectedStatus
:
HttpStatusCode
.
OK_200
})
})
...
...
server/tests/api/users/users.ts
View file @
978c87e7
...
...
@@ -318,6 +318,8 @@ describe('Test users', function () {
fixture
:
'
video_short.webm
'
}
await
server
.
videos
.
upload
({
token
:
userToken
,
attributes
})
await
server
.
channels
.
create
({
token
:
userToken
,
attributes
:
{
name
:
'
other_channel
'
}
})
})
it
(
'
Should have video quota updated
'
,
async
function
()
{
...
...
@@ -340,6 +342,29 @@ describe('Test users', function () {
expect
(
video
.
previewPath
).
to
.
not
.
be
.
null
})
it
(
'
Should be able to filter by channel in my videos
'
,
async
function
()
{
const
myInfo
=
await
server
.
users
.
getMyInfo
({
token
:
userToken
})
const
mainChannel
=
myInfo
.
videoChannels
.
find
(
c
=>
c
.
name
!==
'
other_channel
'
)
const
otherChannel
=
myInfo
.
videoChannels
.
find
(
c
=>
c
.
name
===
'
other_channel
'
)
{
const
{
total
,
data
}
=
await
server
.
videos
.
listMyVideos
({
token
:
userToken
,
channelId
:
mainChannel
.
id
})
expect
(
total
).
to
.
equal
(
1
)
expect
(
data
).
to
.
have
.
lengthOf
(
1
)
const
video
:
Video
=
data
[
0
]
expect
(
video
.
name
).
to
.
equal
(
'
super user video
'
)
expect
(
video
.
thumbnailPath
).
to
.
not
.
be
.
null
expect
(
video
.
previewPath
).
to
.
not
.
be
.
null
}
{
const
{
total
,
data
}
=
await
server
.
videos
.
listMyVideos
({
token
:
userToken
,
channelId
:
otherChannel
.
id
})
expect
(
total
).
to
.
equal
(
0
)
expect
(
data
).
to
.
have
.
lengthOf
(
0
)
}
})
it
(
'
Should be able to search in my videos
'
,
async
function
()
{
{
const
{
total
,
data
}
=
await
server
.
videos
.
listMyVideos
({
token
:
userToken
,
sort
:
'
-createdAt
'
,
search
:
'
user video
'
})
...
...
shared/extra-utils/videos/videos-command.ts
View file @
978c87e7
...
...
@@ -207,6 +207,7 @@ export class VideosCommand extends AbstractCommand {
sort
?:
string
search
?:
string
isLive
?:
boolean
channelId
?:
number
}
=
{})
{
const
path
=
'
/api/v1/users/me/videos
'
...
...
@@ -214,7 +215,7 @@ export class VideosCommand extends AbstractCommand {
...
options
,
path
,
query
:
pick
(
options
,
[
'
start
'
,
'
count
'
,
'
sort
'
,
'
search
'
,
'
isLive
'
]),
query
:
pick
(
options
,
[
'
start
'
,
'
count
'
,
'
sort
'
,
'
search
'
,
'
isLive
'
,
'
channelId
'
]),
implicitToken
:
true
,
defaultExpectedStatus
:
HttpStatusCode
.
OK_200
})
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment