Allow users/visitors to search through an account's videos (#3589)
* WIP: account search * add search to account view * add tests for account search
This commit is contained in:
parent
2264c1ceed
commit
370240824e
|
@ -0,0 +1,104 @@
|
||||||
|
import { Subscription } from 'rxjs'
|
||||||
|
import { first, tap } from 'rxjs/operators'
|
||||||
|
import { Component, OnDestroy, OnInit } from '@angular/core'
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router'
|
||||||
|
import { AuthService, ConfirmService, LocalStorageService, Notifier, ScreenService, ServerService, UserService } from '@app/core'
|
||||||
|
import { immutableAssign } from '@app/helpers'
|
||||||
|
import { Account, AccountService, VideoService } from '@app/shared/shared-main'
|
||||||
|
import { AbstractVideoList } from '@app/shared/shared-video-miniature'
|
||||||
|
import { VideoFilter } from '@shared/models'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'my-account-search',
|
||||||
|
templateUrl: '../../shared/shared-video-miniature/abstract-video-list.html',
|
||||||
|
styleUrls: [
|
||||||
|
'../../shared/shared-video-miniature/abstract-video-list.scss'
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class AccountSearchComponent extends AbstractVideoList implements OnInit, OnDestroy {
|
||||||
|
titlePage: string
|
||||||
|
loadOnInit = false
|
||||||
|
|
||||||
|
search = ''
|
||||||
|
filter: VideoFilter = null
|
||||||
|
|
||||||
|
private account: Account
|
||||||
|
private accountSub: Subscription
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
protected router: Router,
|
||||||
|
protected serverService: ServerService,
|
||||||
|
protected route: ActivatedRoute,
|
||||||
|
protected authService: AuthService,
|
||||||
|
protected userService: UserService,
|
||||||
|
protected notifier: Notifier,
|
||||||
|
protected confirmService: ConfirmService,
|
||||||
|
protected screenService: ScreenService,
|
||||||
|
protected storageService: LocalStorageService,
|
||||||
|
private accountService: AccountService,
|
||||||
|
private videoService: VideoService
|
||||||
|
) {
|
||||||
|
super()
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit () {
|
||||||
|
super.ngOnInit()
|
||||||
|
|
||||||
|
this.enableAllFilterIfPossible()
|
||||||
|
|
||||||
|
// Parent get the account for us
|
||||||
|
this.accountSub = this.accountService.accountLoaded
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe(account => {
|
||||||
|
this.account = account
|
||||||
|
|
||||||
|
this.reloadVideos()
|
||||||
|
this.generateSyndicationList()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy () {
|
||||||
|
if (this.accountSub) this.accountSub.unsubscribe()
|
||||||
|
|
||||||
|
super.ngOnDestroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSearch (value: string) {
|
||||||
|
if (value === '') this.router.navigate(['../videos'], { relativeTo: this.route })
|
||||||
|
this.search = value
|
||||||
|
|
||||||
|
this.reloadVideos()
|
||||||
|
}
|
||||||
|
|
||||||
|
getVideosObservable (page: number) {
|
||||||
|
const newPagination = immutableAssign(this.pagination, { currentPage: page })
|
||||||
|
const options = {
|
||||||
|
account: this.account,
|
||||||
|
videoPagination: newPagination,
|
||||||
|
sort: this.sort,
|
||||||
|
nsfwPolicy: this.nsfwPolicy,
|
||||||
|
videoFilter: this.filter,
|
||||||
|
search: this.search
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.videoService
|
||||||
|
.getAccountVideos(options)
|
||||||
|
.pipe(
|
||||||
|
tap(({ total }) => {
|
||||||
|
this.titlePage = this.search
|
||||||
|
? $localize`Published ${total} videos matching "${this.search}"`
|
||||||
|
: $localize`Published ${total} videos`
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleModerationDisplay () {
|
||||||
|
this.filter = this.buildLocalFilter(this.filter, null)
|
||||||
|
|
||||||
|
this.reloadVideos()
|
||||||
|
}
|
||||||
|
|
||||||
|
generateSyndicationList () {
|
||||||
|
/* disable syndication */
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ import { AccountsComponent } from './accounts.component'
|
||||||
import { AccountVideosComponent } from './account-videos/account-videos.component'
|
import { AccountVideosComponent } from './account-videos/account-videos.component'
|
||||||
import { AccountAboutComponent } from './account-about/account-about.component'
|
import { AccountAboutComponent } from './account-about/account-about.component'
|
||||||
import { AccountVideoChannelsComponent } from './account-video-channels/account-video-channels.component'
|
import { AccountVideoChannelsComponent } from './account-video-channels/account-video-channels.component'
|
||||||
|
import { AccountSearchComponent } from './account-search/account-search.component'
|
||||||
|
|
||||||
const accountsRoutes: Routes = [
|
const accountsRoutes: Routes = [
|
||||||
{
|
{
|
||||||
|
@ -21,19 +22,6 @@ const accountsRoutes: Routes = [
|
||||||
redirectTo: 'video-channels',
|
redirectTo: 'video-channels',
|
||||||
pathMatch: 'full'
|
pathMatch: 'full'
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: 'videos',
|
|
||||||
component: AccountVideosComponent,
|
|
||||||
data: {
|
|
||||||
meta: {
|
|
||||||
title: $localize`Account videos`
|
|
||||||
},
|
|
||||||
reuse: {
|
|
||||||
enabled: true,
|
|
||||||
key: 'account-videos-list'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: 'video-channels',
|
path: 'video-channels',
|
||||||
component: AccountVideoChannelsComponent,
|
component: AccountVideoChannelsComponent,
|
||||||
|
@ -51,6 +39,28 @@ const accountsRoutes: Routes = [
|
||||||
title: $localize`About account`
|
title: $localize`About account`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'videos',
|
||||||
|
component: AccountVideosComponent,
|
||||||
|
data: {
|
||||||
|
meta: {
|
||||||
|
title: $localize`Account videos`
|
||||||
|
},
|
||||||
|
reuse: {
|
||||||
|
enabled: true,
|
||||||
|
key: 'account-videos-list'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'search',
|
||||||
|
component: AccountSearchComponent,
|
||||||
|
data: {
|
||||||
|
meta: {
|
||||||
|
title: $localize`Search videos within account`
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,11 +44,13 @@
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
<list-overflow [items]="links" [itemTemplate]="linkTemplate"></list-overflow>
|
<list-overflow [items]="links" [itemTemplate]="linkTemplate"></list-overflow>
|
||||||
|
|
||||||
|
<simple-search-input (searchChanged)="searchChanged($event)" name="search-videos" i18n-placeholder placeholder="Search videos"></simple-search-input>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="margin-content">
|
<div class="margin-content">
|
||||||
<router-outlet></router-outlet>
|
<router-outlet (activate)="onOutletLoaded($event)"></router-outlet>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { Account, AccountService, DropdownAction, ListOverflowItem, VideoChannel
|
||||||
import { AccountReportComponent } from '@app/shared/shared-moderation'
|
import { AccountReportComponent } from '@app/shared/shared-moderation'
|
||||||
import { User, UserRight } from '@shared/models'
|
import { User, UserRight } from '@shared/models'
|
||||||
import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
|
import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
|
||||||
|
import { AccountSearchComponent } from './account-search/account-search.component'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: './accounts.component.html',
|
templateUrl: './accounts.component.html',
|
||||||
|
@ -14,6 +15,7 @@ import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
|
||||||
})
|
})
|
||||||
export class AccountsComponent implements OnInit, OnDestroy {
|
export class AccountsComponent implements OnInit, OnDestroy {
|
||||||
@ViewChild('accountReportModal') accountReportModal: AccountReportComponent
|
@ViewChild('accountReportModal') accountReportModal: AccountReportComponent
|
||||||
|
accountSearch: AccountSearchComponent
|
||||||
|
|
||||||
account: Account
|
account: Account
|
||||||
accountUser: User
|
accountUser: User
|
||||||
|
@ -99,6 +101,18 @@ export class AccountsComponent implements OnInit, OnDestroy {
|
||||||
return $localize`${count} subscribers`
|
return $localize`${count} subscribers`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onOutletLoaded (component: Component) {
|
||||||
|
if (component instanceof AccountSearchComponent) {
|
||||||
|
this.accountSearch = component
|
||||||
|
} else {
|
||||||
|
this.accountSearch = undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
searchChanged (search: string) {
|
||||||
|
if (this.accountSearch) this.accountSearch.updateSearch(search)
|
||||||
|
}
|
||||||
|
|
||||||
private onAccount (account: Account) {
|
private onAccount (account: Account) {
|
||||||
this.prependModerationActions = undefined
|
this.prependModerationActions = undefined
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { SharedVideoMiniatureModule } from '@app/shared/shared-video-miniature'
|
||||||
import { AccountAboutComponent } from './account-about/account-about.component'
|
import { AccountAboutComponent } from './account-about/account-about.component'
|
||||||
import { AccountVideoChannelsComponent } from './account-video-channels/account-video-channels.component'
|
import { AccountVideoChannelsComponent } from './account-video-channels/account-video-channels.component'
|
||||||
import { AccountVideosComponent } from './account-videos/account-videos.component'
|
import { AccountVideosComponent } from './account-videos/account-videos.component'
|
||||||
|
import { AccountSearchComponent } from './account-search/account-search.component'
|
||||||
import { AccountsRoutingModule } from './accounts-routing.module'
|
import { AccountsRoutingModule } from './accounts-routing.module'
|
||||||
import { AccountsComponent } from './accounts.component'
|
import { AccountsComponent } from './accounts.component'
|
||||||
|
|
||||||
|
@ -27,7 +28,8 @@ import { AccountsComponent } from './accounts.component'
|
||||||
AccountsComponent,
|
AccountsComponent,
|
||||||
AccountVideosComponent,
|
AccountVideosComponent,
|
||||||
AccountVideoChannelsComponent,
|
AccountVideoChannelsComponent,
|
||||||
AccountAboutComponent
|
AccountAboutComponent,
|
||||||
|
AccountSearchComponent
|
||||||
],
|
],
|
||||||
|
|
||||||
exports: [
|
exports: [
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
export * from './help.component'
|
export * from './help.component'
|
||||||
export * from './list-overflow.component'
|
export * from './list-overflow.component'
|
||||||
export * from './top-menu-dropdown.component'
|
export * from './top-menu-dropdown.component'
|
||||||
|
export * from './simple-search-input.component'
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
<span>
|
||||||
|
<my-global-icon iconName="search" aria-label="Search" role="button" (click)="showInput()"></my-global-icon>
|
||||||
|
|
||||||
|
<input
|
||||||
|
#ref
|
||||||
|
type="text"
|
||||||
|
[(ngModel)]="value"
|
||||||
|
(focusout)="focusLost()"
|
||||||
|
(keyup.enter)="searchChange()"
|
||||||
|
[hidden]="!shown"
|
||||||
|
[name]="name"
|
||||||
|
[placeholder]="placeholder"
|
||||||
|
>
|
||||||
|
</span>
|
|
@ -0,0 +1,29 @@
|
||||||
|
@import '_variables';
|
||||||
|
@import '_mixins';
|
||||||
|
|
||||||
|
span {
|
||||||
|
opacity: .6;
|
||||||
|
|
||||||
|
&:focus-within {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
my-global-icon {
|
||||||
|
height: 18px;
|
||||||
|
position: relative;
|
||||||
|
top: -2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
@include peertube-input-text(150px);
|
||||||
|
|
||||||
|
height: 22px; // maximum height for the account/video-channels links
|
||||||
|
padding-left: 10px;
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
|
||||||
|
&::placeholder {
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
import { Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router'
|
||||||
|
import { Subject } from 'rxjs'
|
||||||
|
import { debounceTime, distinctUntilChanged } from 'rxjs/operators'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'simple-search-input',
|
||||||
|
templateUrl: './simple-search-input.component.html',
|
||||||
|
styleUrls: [ './simple-search-input.component.scss' ]
|
||||||
|
})
|
||||||
|
export class SimpleSearchInputComponent implements OnInit {
|
||||||
|
@ViewChild('ref') input: ElementRef
|
||||||
|
|
||||||
|
@Input() name = 'search'
|
||||||
|
@Input() placeholder = $localize`Search`
|
||||||
|
|
||||||
|
@Output() searchChanged = new EventEmitter<string>()
|
||||||
|
|
||||||
|
value = ''
|
||||||
|
shown: boolean
|
||||||
|
|
||||||
|
private searchSubject = new Subject<string>()
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
private router: Router,
|
||||||
|
private route: ActivatedRoute
|
||||||
|
) {}
|
||||||
|
|
||||||
|
ngOnInit () {
|
||||||
|
this.searchSubject
|
||||||
|
.pipe(
|
||||||
|
debounceTime(400),
|
||||||
|
distinctUntilChanged()
|
||||||
|
)
|
||||||
|
.subscribe(value => this.searchChanged.emit(value))
|
||||||
|
|
||||||
|
this.searchSubject.next(this.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
showInput () {
|
||||||
|
this.shown = true
|
||||||
|
setTimeout(() => this.input.nativeElement.focus())
|
||||||
|
}
|
||||||
|
|
||||||
|
focusLost () {
|
||||||
|
if (this.value !== '') return
|
||||||
|
this.shown = false
|
||||||
|
}
|
||||||
|
|
||||||
|
searchChange () {
|
||||||
|
this.router.navigate(['./search'], { relativeTo: this.route })
|
||||||
|
this.searchSubject.next(this.value)
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,7 +30,7 @@ import { ActionDropdownComponent, ButtonComponent, DeleteButtonComponent, EditBu
|
||||||
import { DateToggleComponent } from './date'
|
import { DateToggleComponent } from './date'
|
||||||
import { FeedComponent } from './feeds'
|
import { FeedComponent } from './feeds'
|
||||||
import { LoaderComponent, SmallLoaderComponent } from './loaders'
|
import { LoaderComponent, SmallLoaderComponent } from './loaders'
|
||||||
import { HelpComponent, ListOverflowComponent, TopMenuDropdownComponent } from './misc'
|
import { HelpComponent, ListOverflowComponent, TopMenuDropdownComponent, SimpleSearchInputComponent } from './misc'
|
||||||
import { UserHistoryService, UserNotificationsComponent, UserNotificationService, UserQuotaComponent } from './users'
|
import { UserHistoryService, UserNotificationsComponent, UserNotificationService, UserQuotaComponent } from './users'
|
||||||
import { RedundancyService, VideoImportService, VideoOwnershipService, VideoService } from './video'
|
import { RedundancyService, VideoImportService, VideoOwnershipService, VideoService } from './video'
|
||||||
import { VideoCaptionService } from './video-caption'
|
import { VideoCaptionService } from './video-caption'
|
||||||
|
@ -88,6 +88,7 @@ import { VideoChannelService } from './video-channel'
|
||||||
HelpComponent,
|
HelpComponent,
|
||||||
ListOverflowComponent,
|
ListOverflowComponent,
|
||||||
TopMenuDropdownComponent,
|
TopMenuDropdownComponent,
|
||||||
|
SimpleSearchInputComponent,
|
||||||
|
|
||||||
UserQuotaComponent,
|
UserQuotaComponent,
|
||||||
UserNotificationsComponent
|
UserNotificationsComponent
|
||||||
|
@ -140,6 +141,7 @@ import { VideoChannelService } from './video-channel'
|
||||||
HelpComponent,
|
HelpComponent,
|
||||||
ListOverflowComponent,
|
ListOverflowComponent,
|
||||||
TopMenuDropdownComponent,
|
TopMenuDropdownComponent,
|
||||||
|
SimpleSearchInputComponent,
|
||||||
|
|
||||||
UserQuotaComponent,
|
UserQuotaComponent,
|
||||||
UserNotificationsComponent
|
UserNotificationsComponent
|
||||||
|
|
|
@ -140,8 +140,9 @@ export class VideoService implements VideosProvider {
|
||||||
sort: VideoSortField
|
sort: VideoSortField
|
||||||
nsfwPolicy?: NSFWPolicyType
|
nsfwPolicy?: NSFWPolicyType
|
||||||
videoFilter?: VideoFilter
|
videoFilter?: VideoFilter
|
||||||
|
search?: string
|
||||||
}): Observable<ResultList<Video>> {
|
}): Observable<ResultList<Video>> {
|
||||||
const { account, videoPagination, sort, videoFilter, nsfwPolicy } = parameters
|
const { account, videoPagination, sort, videoFilter, nsfwPolicy, search } = parameters
|
||||||
|
|
||||||
const pagination = this.restService.componentPaginationToRestPagination(videoPagination)
|
const pagination = this.restService.componentPaginationToRestPagination(videoPagination)
|
||||||
|
|
||||||
|
@ -156,6 +157,10 @@ export class VideoService implements VideosProvider {
|
||||||
params = params.set('filter', videoFilter)
|
params = params.set('filter', videoFilter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (search) {
|
||||||
|
params = params.set('search', search)
|
||||||
|
}
|
||||||
|
|
||||||
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(
|
||||||
|
|
|
@ -665,6 +665,11 @@
|
||||||
font-size: 130%;
|
font-size: 130%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
list-overflow {
|
||||||
|
display: inline-block;
|
||||||
|
width: max-content;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -175,7 +175,8 @@ async function listAccountVideos (req: express.Request, res: express.Response) {
|
||||||
withFiles: false,
|
withFiles: false,
|
||||||
accountId: account.id,
|
accountId: account.id,
|
||||||
user: res.locals.oauth ? res.locals.oauth.token.User : undefined,
|
user: res.locals.oauth ? res.locals.oauth.token.User : undefined,
|
||||||
countVideos
|
countVideos,
|
||||||
|
search: req.query.search
|
||||||
}, 'filter:api.accounts.videos.list.params')
|
}, 'filter:api.accounts.videos.list.params')
|
||||||
|
|
||||||
const resultList = await Hooks.wrapPromiseFun(
|
const resultList = await Hooks.wrapPromiseFun(
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { MVideoFullLight } from '@server/types/models'
|
||||||
import { ServerErrorCode, UserRight, VideoChangeOwnershipStatus, VideoPrivacy } from '../../../../shared'
|
import { ServerErrorCode, UserRight, VideoChangeOwnershipStatus, VideoPrivacy } from '../../../../shared'
|
||||||
import { VideoChangeOwnershipAccept } from '../../../../shared/models/videos/video-change-ownership-accept.model'
|
import { VideoChangeOwnershipAccept } from '../../../../shared/models/videos/video-change-ownership-accept.model'
|
||||||
import {
|
import {
|
||||||
|
exists,
|
||||||
isBooleanValid,
|
isBooleanValid,
|
||||||
isDateValid,
|
isDateValid,
|
||||||
isFileFieldValid,
|
isFileFieldValid,
|
||||||
|
@ -444,6 +445,9 @@ const commonVideosFiltersValidator = [
|
||||||
.optional()
|
.optional()
|
||||||
.customSanitizer(toBooleanOrNull)
|
.customSanitizer(toBooleanOrNull)
|
||||||
.custom(isBooleanValid).withMessage('Should have a valid skip count boolean'),
|
.custom(isBooleanValid).withMessage('Should have a valid skip count boolean'),
|
||||||
|
query('search')
|
||||||
|
.optional()
|
||||||
|
.custom(exists).withMessage('Should have a valid search'),
|
||||||
|
|
||||||
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||||
logger.debug('Checking commons video filters query', { parameters: req.query })
|
logger.debug('Checking commons video filters query', { parameters: req.query })
|
||||||
|
|
|
@ -34,7 +34,7 @@ describe('Test users with multiple servers', function () {
|
||||||
let userAvatarFilename: string
|
let userAvatarFilename: string
|
||||||
|
|
||||||
before(async function () {
|
before(async function () {
|
||||||
this.timeout(120000)
|
this.timeout(120_000)
|
||||||
|
|
||||||
servers = await flushAndRunMultipleServers(3)
|
servers = await flushAndRunMultipleServers(3)
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ describe('Test users with multiple servers', function () {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should be able to update my description', async function () {
|
it('Should be able to update my description', async function () {
|
||||||
this.timeout(10000)
|
this.timeout(10_000)
|
||||||
|
|
||||||
await updateMyUser({
|
await updateMyUser({
|
||||||
url: servers[0].url,
|
url: servers[0].url,
|
||||||
|
@ -109,7 +109,7 @@ describe('Test users with multiple servers', function () {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should be able to update my avatar', async function () {
|
it('Should be able to update my avatar', async function () {
|
||||||
this.timeout(10000)
|
this.timeout(10_000)
|
||||||
|
|
||||||
const fixture = 'avatar2.png'
|
const fixture = 'avatar2.png'
|
||||||
|
|
||||||
|
@ -164,8 +164,27 @@ describe('Test users with multiple servers', function () {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('Should search through account videos', async function () {
|
||||||
|
this.timeout(10_000)
|
||||||
|
|
||||||
|
const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name: 'Kami no chikara' })
|
||||||
|
|
||||||
|
await waitJobs(servers)
|
||||||
|
|
||||||
|
for (const server of servers) {
|
||||||
|
const res = await getAccountVideos(server.url, server.accessToken, 'user1@localhost:' + servers[0].port, 0, 5, undefined, {
|
||||||
|
search: 'Kami'
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(res.body.total).to.equal(1)
|
||||||
|
expect(res.body.data).to.be.an('array')
|
||||||
|
expect(res.body.data).to.have.lengthOf(1)
|
||||||
|
expect(res.body.data[0].uuid).to.equal(resVideo.body.video.uuid)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
it('Should remove the user', async function () {
|
it('Should remove the user', async function () {
|
||||||
this.timeout(10000)
|
this.timeout(10_000)
|
||||||
|
|
||||||
for (const server of servers) {
|
for (const server of servers) {
|
||||||
const resAccounts = await getAccountsList(server.url, '-createdAt')
|
const resAccounts = await getAccountsList(server.url, '-createdAt')
|
||||||
|
|
|
@ -194,7 +194,10 @@ function getAccountVideos (
|
||||||
start: number,
|
start: number,
|
||||||
count: number,
|
count: number,
|
||||||
sort?: string,
|
sort?: string,
|
||||||
query: { nsfw?: boolean } = {}
|
query: {
|
||||||
|
nsfw?: boolean
|
||||||
|
search?: string
|
||||||
|
} = {}
|
||||||
) {
|
) {
|
||||||
const path = '/api/v1/accounts/' + accountName + '/videos'
|
const path = '/api/v1/accounts/' + accountName + '/videos'
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue