aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorChocobozzz <florian.bigard@gmail.com>2017-12-05 17:46:33 +0100
committerChocobozzz <florian.bigard@gmail.com>2017-12-05 18:25:29 +0100
commitf3aaa9a95cc2b61f1f255472d7014d08faa66561 (patch)
tree95e70c8d0ed5b6f1c71c32a77cb7d6cf8478c9d4
parentd235f6b0d1054a2a3451dacade927caefce8f30c (diff)
downloadPeerTube-f3aaa9a95cc2b61f1f255472d7014d08faa66561.tar.gz
PeerTube-f3aaa9a95cc2b61f1f255472d7014d08faa66561.tar.zst
PeerTube-f3aaa9a95cc2b61f1f255472d7014d08faa66561.zip
Fix client search
-rw-r--r--client/src/app/account/account-videos/account-videos.component.ts8
-rw-r--r--client/src/app/app.component.html2
-rw-r--r--client/src/app/app.module.ts4
-rw-r--r--client/src/app/header/header.component.html (renamed from client/src/app/shared/search/search.component.html)2
-rw-r--r--client/src/app/header/header.component.scss (renamed from client/src/app/shared/search/search.component.scss)0
-rw-r--r--client/src/app/header/header.component.ts28
-rw-r--r--client/src/app/header/index.ts1
-rw-r--r--client/src/app/shared/index.ts1
-rw-r--r--client/src/app/shared/misc/utils.ts18
-rw-r--r--client/src/app/shared/search/index.ts4
-rw-r--r--client/src/app/shared/search/search-field.type.ts1
-rw-r--r--client/src/app/shared/search/search.component.ts42
-rw-r--r--client/src/app/shared/search/search.model.ts6
-rw-r--r--client/src/app/shared/search/search.service.ts18
-rw-r--r--client/src/app/shared/shared.module.ts4
-rw-r--r--client/src/app/shared/video/abstract-video-list.ts24
-rw-r--r--client/src/app/shared/video/video.service.ts9
-rw-r--r--client/src/app/signup/signup.component.html2
-rw-r--r--client/src/app/videos/video-list/index.ts1
-rw-r--r--client/src/app/videos/video-list/video-recently-added.component.ts12
-rw-r--r--client/src/app/videos/video-list/video-search.component.ts51
-rw-r--r--client/src/app/videos/video-list/video-trending.component.ts12
-rw-r--r--client/src/app/videos/videos-routing.module.ts11
-rw-r--r--client/src/app/videos/videos.module.ts5
-rw-r--r--server/controllers/api/videos/index.ts22
-rw-r--r--server/initializers/constants.ts6
-rw-r--r--server/middlewares/index.ts1
-rw-r--r--server/middlewares/search.ts14
-rw-r--r--server/middlewares/validators/videos.ts5
-rw-r--r--server/models/video/video-interface.ts1
-rw-r--r--server/models/video/video.ts47
-rw-r--r--server/tests/api/single-server.ts112
-rw-r--r--server/tests/utils/videos.ts20
33 files changed, 245 insertions, 249 deletions
diff --git a/client/src/app/account/account-videos/account-videos.component.ts b/client/src/app/account/account-videos/account-videos.component.ts
index cc28f511a..1bc6c0a35 100644
--- a/client/src/app/account/account-videos/account-videos.component.ts
+++ b/client/src/app/account/account-videos/account-videos.component.ts
@@ -1,4 +1,4 @@
1import { Component, OnDestroy, OnInit } from '@angular/core' 1import { Component, OnInit } from '@angular/core'
2import { ActivatedRoute, Router } from '@angular/router' 2import { ActivatedRoute, Router } from '@angular/router'
3import { NotificationsService } from 'angular2-notifications' 3import { NotificationsService } from 'angular2-notifications'
4import { AbstractVideoList } from '../../shared/video/abstract-video-list' 4import { AbstractVideoList } from '../../shared/video/abstract-video-list'
@@ -9,7 +9,7 @@ import { VideoService } from '../../shared/video/video.service'
9 templateUrl: './account-videos.component.html', 9 templateUrl: './account-videos.component.html',
10 styleUrls: [ './account-videos.component.scss' ] 10 styleUrls: [ './account-videos.component.scss' ]
11}) 11})
12export class AccountVideosComponent extends AbstractVideoList implements OnInit, OnDestroy { 12export class AccountVideosComponent extends AbstractVideoList implements OnInit {
13 titlePage = 'My videos' 13 titlePage = 'My videos'
14 currentRoute = '/account/videos' 14 currentRoute = '/account/videos'
15 15
@@ -24,10 +24,6 @@ export class AccountVideosComponent extends AbstractVideoList implements OnInit,
24 super.ngOnInit() 24 super.ngOnInit()
25 } 25 }
26 26
27 ngOnDestroy () {
28 super.ngOnDestroy()
29 }
30
31 getVideosObservable () { 27 getVideosObservable () {
32 return this.videoService.getMyVideos(this.pagination, this.sort) 28 return this.videoService.getMyVideos(this.pagination, this.sort)
33 } 29 }
diff --git a/client/src/app/app.component.html b/client/src/app/app.component.html
index 640524e23..b095e44d6 100644
--- a/client/src/app/app.component.html
+++ b/client/src/app/app.component.html
@@ -11,7 +11,7 @@
11 </div> 11 </div>
12 12
13 <div class="header-right"> 13 <div class="header-right">
14 <my-search></my-search> 14 <my-header></my-header>
15 </div> 15 </div>
16 </div> 16 </div>
17 17
diff --git a/client/src/app/app.module.ts b/client/src/app/app.module.ts
index 342589003..ee7cb0c8a 100644
--- a/client/src/app/app.module.ts
+++ b/client/src/app/app.module.ts
@@ -21,6 +21,7 @@ import { SignupModule } from './signup'
21import { SharedModule } from './shared' 21import { SharedModule } from './shared'
22import { VideosModule } from './videos' 22import { VideosModule } from './videos'
23import { MenuComponent, MenuAdminComponent } from './menu' 23import { MenuComponent, MenuAdminComponent } from './menu'
24import { HeaderComponent } from './header'
24 25
25export function metaFactory (): MetaLoader { 26export function metaFactory (): MetaLoader {
26 return new MetaStaticLoader({ 27 return new MetaStaticLoader({
@@ -51,7 +52,8 @@ const APP_PROVIDERS = [
51 AppComponent, 52 AppComponent,
52 53
53 MenuComponent, 54 MenuComponent,
54 MenuAdminComponent 55 MenuAdminComponent,
56 HeaderComponent
55 ], 57 ],
56 imports: [ 58 imports: [
57 BrowserModule, 59 BrowserModule,
diff --git a/client/src/app/shared/search/search.component.html b/client/src/app/header/header.component.html
index 9bc9bafe4..aa72fb68a 100644
--- a/client/src/app/shared/search/search.component.html
+++ b/client/src/app/header/header.component.html
@@ -1,6 +1,6 @@
1<input 1<input
2 type="text" id="search-video" name="search-video" placeholder="Search..." 2 type="text" id="search-video" name="search-video" placeholder="Search..."
3 [(ngModel)]="searchCriteria.value" (keyup.enter)="doSearch()" 3 [(ngModel)]="searchValue" (keyup.enter)="doSearch()"
4> 4>
5<span (click)="doSearch()" class="icon icon-search"></span> 5<span (click)="doSearch()" class="icon icon-search"></span>
6 6
diff --git a/client/src/app/shared/search/search.component.scss b/client/src/app/header/header.component.scss
index 7ba8ef26c..7ba8ef26c 100644
--- a/client/src/app/shared/search/search.component.scss
+++ b/client/src/app/header/header.component.scss
diff --git a/client/src/app/header/header.component.ts b/client/src/app/header/header.component.ts
new file mode 100644
index 000000000..a903048f2
--- /dev/null
+++ b/client/src/app/header/header.component.ts
@@ -0,0 +1,28 @@
1import { Component, OnInit } from '@angular/core'
2import { Router } from '@angular/router'
3import { getParameterByName } from '../shared/misc/utils'
4
5@Component({
6 selector: 'my-header',
7 templateUrl: './header.component.html',
8 styleUrls: [ './header.component.scss' ]
9})
10
11export class HeaderComponent implements OnInit {
12 searchValue = ''
13
14 constructor (private router: Router) {}
15
16 ngOnInit () {
17 const searchQuery = getParameterByName('search', window.location.href)
18 if (searchQuery) this.searchValue = searchQuery
19 }
20
21 doSearch () {
22 if (!this.searchValue) return
23
24 this.router.navigate([ '/videos', 'search' ], {
25 queryParams: { search: this.searchValue }
26 })
27 }
28}
diff --git a/client/src/app/header/index.ts b/client/src/app/header/index.ts
new file mode 100644
index 000000000..d98d2d00a
--- /dev/null
+++ b/client/src/app/header/index.ts
@@ -0,0 +1 @@
export * from './header.component'
diff --git a/client/src/app/shared/index.ts b/client/src/app/shared/index.ts
index 79bf5ef43..413dda16a 100644
--- a/client/src/app/shared/index.ts
+++ b/client/src/app/shared/index.ts
@@ -1,7 +1,6 @@
1export * from './auth' 1export * from './auth'
2export * from './forms' 2export * from './forms'
3export * from './rest' 3export * from './rest'
4export * from './search'
5export * from './users' 4export * from './users'
6export * from './video-abuse' 5export * from './video-abuse'
7export * from './video-blacklist' 6export * from './video-blacklist'
diff --git a/client/src/app/shared/misc/utils.ts b/client/src/app/shared/misc/utils.ts
new file mode 100644
index 000000000..2b5c3686e
--- /dev/null
+++ b/client/src/app/shared/misc/utils.ts
@@ -0,0 +1,18 @@
1// Thanks: https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript
2
3function getParameterByName (name: string, url: string) {
4 if (!url) url = window.location.href
5 name = name.replace(/[\[\]]/g, '\\$&')
6
7 const regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)')
8 const results = regex.exec(url)
9
10 if (!results) return null
11 if (!results[2]) return ''
12
13 return decodeURIComponent(results[2].replace(/\+/g, ' '))
14}
15
16export {
17 getParameterByName
18}
diff --git a/client/src/app/shared/search/index.ts b/client/src/app/shared/search/index.ts
deleted file mode 100644
index d4016cf89..000000000
--- a/client/src/app/shared/search/index.ts
+++ /dev/null
@@ -1,4 +0,0 @@
1export * from './search-field.type'
2export * from './search.component'
3export * from './search.model'
4export * from './search.service'
diff --git a/client/src/app/shared/search/search-field.type.ts b/client/src/app/shared/search/search-field.type.ts
deleted file mode 100644
index 7323d6cc3..000000000
--- a/client/src/app/shared/search/search-field.type.ts
+++ /dev/null
@@ -1 +0,0 @@
1export type SearchField = 'name' | 'account' | 'host' | 'tags'
diff --git a/client/src/app/shared/search/search.component.ts b/client/src/app/shared/search/search.component.ts
deleted file mode 100644
index f49ecc8ad..000000000
--- a/client/src/app/shared/search/search.component.ts
+++ /dev/null
@@ -1,42 +0,0 @@
1import { Component, OnInit } from '@angular/core'
2import { Router } from '@angular/router'
3import { Search } from './search.model'
4import { SearchService } from './search.service'
5
6@Component({
7 selector: 'my-search',
8 templateUrl: './search.component.html',
9 styleUrls: [ './search.component.scss' ]
10})
11
12export class SearchComponent implements OnInit {
13 searchCriteria: Search = {
14 field: 'name',
15 value: ''
16 }
17
18 constructor (private searchService: SearchService, private router: Router) {}
19
20 ngOnInit () {
21 // Subscribe if the search changed
22 // Usually changed by videos list component
23 this.searchService.updateSearch.subscribe(
24 newSearchCriteria => {
25 // Put a field by default
26 if (!newSearchCriteria.field) {
27 newSearchCriteria.field = 'name'
28 }
29
30 this.searchCriteria = newSearchCriteria
31 }
32 )
33 }
34
35 doSearch () {
36 // if (this.router.url.indexOf('/videos/list') === -1) {
37 // this.router.navigate([ '/videos/list' ])
38 // }
39
40 this.searchService.searchUpdated.next(this.searchCriteria)
41 }
42}
diff --git a/client/src/app/shared/search/search.model.ts b/client/src/app/shared/search/search.model.ts
deleted file mode 100644
index 174adf2c6..000000000
--- a/client/src/app/shared/search/search.model.ts
+++ /dev/null
@@ -1,6 +0,0 @@
1import { SearchField } from './search-field.type'
2
3export interface Search {
4 field: SearchField
5 value: string
6}
diff --git a/client/src/app/shared/search/search.service.ts b/client/src/app/shared/search/search.service.ts
deleted file mode 100644
index 0480b46bd..000000000
--- a/client/src/app/shared/search/search.service.ts
+++ /dev/null
@@ -1,18 +0,0 @@
1import { Injectable } from '@angular/core'
2import { Subject } from 'rxjs/Subject'
3import { ReplaySubject } from 'rxjs/ReplaySubject'
4
5import { Search } from './search.model'
6
7// This class is needed to communicate between videos/ and search component
8// Remove it when we'll be able to subscribe to router changes
9@Injectable()
10export class SearchService {
11 searchUpdated: Subject<Search>
12 updateSearch: Subject<Search>
13
14 constructor () {
15 this.updateSearch = new Subject<Search>()
16 this.searchUpdated = new ReplaySubject<Search>(1)
17 }
18}
diff --git a/client/src/app/shared/shared.module.ts b/client/src/app/shared/shared.module.ts
index f7ced040d..86e1a380e 100644
--- a/client/src/app/shared/shared.module.ts
+++ b/client/src/app/shared/shared.module.ts
@@ -17,7 +17,6 @@ import { FromNowPipe } from './misc/from-now.pipe'
17import { LoaderComponent } from './misc/loader.component' 17import { LoaderComponent } from './misc/loader.component'
18import { NumberFormatterPipe } from './misc/number-formatter.pipe' 18import { NumberFormatterPipe } from './misc/number-formatter.pipe'
19import { RestExtractor, RestService } from './rest' 19import { RestExtractor, RestService } from './rest'
20import { SearchComponent, SearchService } from './search'
21import { UserService } from './users' 20import { UserService } from './users'
22import { VideoAbuseService } from './video-abuse' 21import { VideoAbuseService } from './video-abuse'
23import { VideoBlacklistService } from './video-blacklist' 22import { VideoBlacklistService } from './video-blacklist'
@@ -43,7 +42,6 @@ import { VideoService } from './video/video.service'
43 ], 42 ],
44 43
45 declarations: [ 44 declarations: [
46 SearchComponent,
47 LoaderComponent, 45 LoaderComponent,
48 VideoThumbnailComponent, 46 VideoThumbnailComponent,
49 NumberFormatterPipe, 47 NumberFormatterPipe,
@@ -66,7 +64,6 @@ import { VideoService } from './video/video.service'
66 BytesPipe, 64 BytesPipe,
67 KeysPipe, 65 KeysPipe,
68 66
69 SearchComponent,
70 LoaderComponent, 67 LoaderComponent,
71 VideoThumbnailComponent, 68 VideoThumbnailComponent,
72 69
@@ -78,7 +75,6 @@ import { VideoService } from './video/video.service'
78 AUTH_INTERCEPTOR_PROVIDER, 75 AUTH_INTERCEPTOR_PROVIDER,
79 RestExtractor, 76 RestExtractor,
80 RestService, 77 RestService,
81 SearchService,
82 VideoAbuseService, 78 VideoAbuseService,
83 VideoBlacklistService, 79 VideoBlacklistService,
84 UserService, 80 UserService,
diff --git a/client/src/app/shared/video/abstract-video-list.ts b/client/src/app/shared/video/abstract-video-list.ts
index cf717cf4c..84ca5cbe4 100644
--- a/client/src/app/shared/video/abstract-video-list.ts
+++ b/client/src/app/shared/video/abstract-video-list.ts
@@ -1,25 +1,25 @@
1import { OnDestroy, OnInit } from '@angular/core' 1import { OnInit } from '@angular/core'
2import { ActivatedRoute, Router } from '@angular/router' 2import { ActivatedRoute, Router } from '@angular/router'
3import { NotificationsService } from 'angular2-notifications' 3import { NotificationsService } from 'angular2-notifications'
4import { Observable } from 'rxjs/Observable' 4import { Observable } from 'rxjs/Observable'
5import { Subscription } from 'rxjs/Subscription'
6import { SortField } from './sort-field.type' 5import { SortField } from './sort-field.type'
7import { VideoPagination } from './video-pagination.model' 6import { VideoPagination } from './video-pagination.model'
8import { Video } from './video.model' 7import { Video } from './video.model'
9 8
10export abstract class AbstractVideoList implements OnInit, OnDestroy { 9export abstract class AbstractVideoList implements OnInit {
11 pagination: VideoPagination = { 10 pagination: VideoPagination = {
12 currentPage: 1, 11 currentPage: 1,
13 itemsPerPage: 25, 12 itemsPerPage: 25,
14 totalItems: null 13 totalItems: null
15 } 14 }
16 sort: SortField = '-createdAt' 15 sort: SortField = '-createdAt'
16 defaultSort: SortField = '-createdAt'
17 videos: Video[] = [] 17 videos: Video[] = []
18 loadOnInit = true
18 19
19 protected notificationsService: NotificationsService 20 protected notificationsService: NotificationsService
20 protected router: Router 21 protected router: Router
21 protected route: ActivatedRoute 22 protected route: ActivatedRoute
22 protected subActivatedRoute: Subscription
23 23
24 protected abstract currentRoute: string 24 protected abstract currentRoute: string
25 25
@@ -32,13 +32,7 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy {
32 // Subscribe to route changes 32 // Subscribe to route changes
33 const routeParams = this.route.snapshot.params 33 const routeParams = this.route.snapshot.params
34 this.loadRouteParams(routeParams) 34 this.loadRouteParams(routeParams)
35 this.loadMoreVideos('after') 35 if (this.loadOnInit === true) this.loadMoreVideos('after')
36 }
37
38 ngOnDestroy () {
39 if (this.subActivatedRoute) {
40 this.subActivatedRoute.unsubscribe()
41 }
42 } 36 }
43 37
44 onNearOfTop () { 38 onNearOfTop () {
@@ -53,6 +47,12 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy {
53 } 47 }
54 } 48 }
55 49
50 reloadVideos () {
51 this.videos = []
52 this.loadedPages = {}
53 this.loadMoreVideos('before')
54 }
55
56 loadMoreVideos (where: 'before' | 'after') { 56 loadMoreVideos (where: 'before' | 'after') {
57 if (this.loadedPages[this.pagination.currentPage] === true) return 57 if (this.loadedPages[this.pagination.currentPage] === true) return
58 58
@@ -105,7 +105,7 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy {
105 } 105 }
106 106
107 protected loadRouteParams (routeParams: { [ key: string ]: any }) { 107 protected loadRouteParams (routeParams: { [ key: string ]: any }) {
108 this.sort = routeParams['sort'] as SortField || '-createdAt' 108 this.sort = routeParams['sort'] as SortField || this.defaultSort
109 109
110 if (routeParams['page'] !== undefined) { 110 if (routeParams['page'] !== undefined) {
111 this.pagination.currentPage = parseInt(routeParams['page'], 10) 111 this.pagination.currentPage = parseInt(routeParams['page'], 10)
diff --git a/client/src/app/shared/video/video.service.ts b/client/src/app/shared/video/video.service.ts
index b2a26417c..3f35b67c4 100644
--- a/client/src/app/shared/video/video.service.ts
+++ b/client/src/app/shared/video/video.service.ts
@@ -11,7 +11,7 @@ import { VideoRateType } from '../../../../../shared/models/videos/video-rate.ty
11import { VideoUpdate } from '../../../../../shared/models/videos/video-update.model' 11import { VideoUpdate } from '../../../../../shared/models/videos/video-update.model'
12import { RestExtractor } from '../rest/rest-extractor.service' 12import { RestExtractor } from '../rest/rest-extractor.service'
13import { RestService } from '../rest/rest.service' 13import { RestService } from '../rest/rest.service'
14import { Search } from '../search/search.model' 14import { Search } from '../header/search.model'
15import { UserService } from '../users/user.service' 15import { UserService } from '../users/user.service'
16import { SortField } from './sort-field.type' 16import { SortField } from './sort-field.type'
17import { VideoDetails } from './video-details.model' 17import { VideoDetails } from './video-details.model'
@@ -91,15 +91,14 @@ export class VideoService {
91 .catch((res) => this.restExtractor.handleError(res)) 91 .catch((res) => this.restExtractor.handleError(res))
92 } 92 }
93 93
94 searchVideos (search: Search, videoPagination: VideoPagination, sort: SortField): Observable<{ videos: Video[], totalVideos: number}> { 94 searchVideos (search: string, videoPagination: VideoPagination, sort: SortField): Observable<{ videos: Video[], totalVideos: number}> {
95 const url = VideoService.BASE_VIDEO_URL + 'search/' + encodeURIComponent(search.value) 95 const url = VideoService.BASE_VIDEO_URL + 'search'
96 96
97 const pagination = this.videoPaginationToRestPagination(videoPagination) 97 const pagination = this.videoPaginationToRestPagination(videoPagination)
98 98
99 let params = new HttpParams() 99 let params = new HttpParams()
100 params = this.restService.addRestGetParams(params, pagination, sort) 100 params = this.restService.addRestGetParams(params, pagination, sort)
101 101 params = params.append('search', search)
102 if (search.field) params.set('field', search.field)
103 102
104 return this.authHttp 103 return this.authHttp
105 .get<ResultList<VideoServerModel>>(url, { params }) 104 .get<ResultList<VideoServerModel>>(url, { params })
diff --git a/client/src/app/signup/signup.component.html b/client/src/app/signup/signup.component.html
index 1e9f7f949..8a30ab512 100644
--- a/client/src/app/signup/signup.component.html
+++ b/client/src/app/signup/signup.component.html
@@ -1,7 +1,7 @@
1<div class="margin-content"> 1<div class="margin-content">
2 2
3 <div class="title-page title-page-single"> 3 <div class="title-page title-page-single">
4 Signup 4 Create an account
5 </div> 5 </div>
6 6
7 <div *ngIf="error" class="alert alert-danger">{{ error }}</div> 7 <div *ngIf="error" class="alert alert-danger">{{ error }}</div>
diff --git a/client/src/app/videos/video-list/index.ts b/client/src/app/videos/video-list/index.ts
index 594e31984..13024294e 100644
--- a/client/src/app/videos/video-list/index.ts
+++ b/client/src/app/videos/video-list/index.ts
@@ -1,3 +1,4 @@
1export * from './video-recently-added.component' 1export * from './video-recently-added.component'
2export * from './video-trending.component' 2export * from './video-trending.component'
3export * from './video-search.component'
3export * from './shared' 4export * from './shared'
diff --git a/client/src/app/videos/video-list/video-recently-added.component.ts b/client/src/app/videos/video-list/video-recently-added.component.ts
index d48804414..6168fac95 100644
--- a/client/src/app/videos/video-list/video-recently-added.component.ts
+++ b/client/src/app/videos/video-list/video-recently-added.component.ts
@@ -1,17 +1,19 @@
1import { Component, OnDestroy, OnInit } from '@angular/core' 1import { Component, OnInit } from '@angular/core'
2import { ActivatedRoute, Router } from '@angular/router' 2import { ActivatedRoute, Router } from '@angular/router'
3import { NotificationsService } from 'angular2-notifications' 3import { NotificationsService } from 'angular2-notifications'
4import { VideoService } from '../../shared/video/video.service'
5import { AbstractVideoList } from '../../shared/video/abstract-video-list' 4import { AbstractVideoList } from '../../shared/video/abstract-video-list'
5import { SortField } from '../../shared/video/sort-field.type'
6import { VideoService } from '../../shared/video/video.service'
6 7
7@Component({ 8@Component({
8 selector: 'my-videos-recently-added', 9 selector: 'my-videos-recently-added',
9 styleUrls: [ '../../shared/video/abstract-video-list.scss' ], 10 styleUrls: [ '../../shared/video/abstract-video-list.scss' ],
10 templateUrl: '../../shared/video/abstract-video-list.html' 11 templateUrl: '../../shared/video/abstract-video-list.html'
11}) 12})
12export class VideoRecentlyAddedComponent extends AbstractVideoList implements OnInit, OnDestroy { 13export class VideoRecentlyAddedComponent extends AbstractVideoList implements OnInit {
13 titlePage = 'Recently added' 14 titlePage = 'Recently added'
14 currentRoute = '/videos/recently-added' 15 currentRoute = '/videos/recently-added'
16 sort: SortField = '-createdAt'
15 17
16 constructor (protected router: Router, 18 constructor (protected router: Router,
17 protected route: ActivatedRoute, 19 protected route: ActivatedRoute,
@@ -24,10 +26,6 @@ export class VideoRecentlyAddedComponent extends AbstractVideoList implements On
24 super.ngOnInit() 26 super.ngOnInit()
25 } 27 }
26 28
27 ngOnDestroy () {
28 super.ngOnDestroy()
29 }
30
31 getVideosObservable () { 29 getVideosObservable () {
32 return this.videoService.getVideos(this.pagination, this.sort) 30 return this.videoService.getVideos(this.pagination, this.sort)
33 } 31 }
diff --git a/client/src/app/videos/video-list/video-search.component.ts b/client/src/app/videos/video-list/video-search.component.ts
new file mode 100644
index 000000000..ba851d27e
--- /dev/null
+++ b/client/src/app/videos/video-list/video-search.component.ts
@@ -0,0 +1,51 @@
1import { Component, OnDestroy, OnInit } from '@angular/core'
2import { ActivatedRoute, Router } from '@angular/router'
3import { NotificationsService } from 'angular2-notifications'
4import { AbstractVideoList } from 'app/shared/video/abstract-video-list'
5import { Subscription } from 'rxjs/Subscription'
6import { SortField } from '../../shared/video/sort-field.type'
7import { VideoService } from '../../shared/video/video.service'
8
9@Component({
10 selector: 'my-videos-search',
11 styleUrls: [ '../../shared/video/abstract-video-list.scss' ],
12 templateUrl: '../../shared/video/abstract-video-list.html'
13})
14export class VideoSearchComponent extends AbstractVideoList implements OnInit, OnDestroy {
15 titlePage = 'Search'
16 currentRoute = '/videos/search'
17 loadOnInit = false
18
19 private search = ''
20 private subActivatedRoute: Subscription
21
22 constructor (protected router: Router,
23 protected route: ActivatedRoute,
24 protected notificationsService: NotificationsService,
25 private videoService: VideoService) {
26 super()
27 }
28
29 ngOnInit () {
30 super.ngOnInit()
31
32 this.subActivatedRoute = this.route.queryParams.subscribe(
33 queryParams => {
34 this.search = queryParams['search']
35 this.reloadVideos()
36 },
37
38 err => this.notificationsService.error('Error', err.text)
39 )
40 }
41
42 ngOnDestroy () {
43 if (this.subActivatedRoute) {
44 this.subActivatedRoute.unsubscribe()
45 }
46 }
47
48 getVideosObservable () {
49 return this.videoService.searchVideos(this.search, this.pagination, this.sort)
50 }
51}
diff --git a/client/src/app/videos/video-list/video-trending.component.ts b/client/src/app/videos/video-list/video-trending.component.ts
index 9108289c9..e80fd7f2c 100644
--- a/client/src/app/videos/video-list/video-trending.component.ts
+++ b/client/src/app/videos/video-list/video-trending.component.ts
@@ -1,17 +1,19 @@
1import { Component, OnDestroy, OnInit } from '@angular/core' 1import { Component, OnInit } from '@angular/core'
2import { ActivatedRoute, Router } from '@angular/router' 2import { ActivatedRoute, Router } from '@angular/router'
3import { NotificationsService } from 'angular2-notifications' 3import { NotificationsService } from 'angular2-notifications'
4import { VideoService } from '../../shared/video/video.service'
5import { AbstractVideoList } from 'app/shared/video/abstract-video-list' 4import { AbstractVideoList } from 'app/shared/video/abstract-video-list'
5import { SortField } from '../../shared/video/sort-field.type'
6import { VideoService } from '../../shared/video/video.service'
6 7
7@Component({ 8@Component({
8 selector: 'my-videos-trending', 9 selector: 'my-videos-trending',
9 styleUrls: [ '../../shared/video/abstract-video-list.scss' ], 10 styleUrls: [ '../../shared/video/abstract-video-list.scss' ],
10 templateUrl: '../../shared/video/abstract-video-list.html' 11 templateUrl: '../../shared/video/abstract-video-list.html'
11}) 12})
12export class VideoTrendingComponent extends AbstractVideoList implements OnInit, OnDestroy { 13export class VideoTrendingComponent extends AbstractVideoList implements OnInit {
13 titlePage = 'Trending' 14 titlePage = 'Trending'
14 currentRoute = '/videos/trending' 15 currentRoute = '/videos/trending'
16 defaultSort: SortField = '-views'
15 17
16 constructor (protected router: Router, 18 constructor (protected router: Router,
17 protected route: ActivatedRoute, 19 protected route: ActivatedRoute,
@@ -24,10 +26,6 @@ export class VideoTrendingComponent extends AbstractVideoList implements OnInit,
24 super.ngOnInit() 26 super.ngOnInit()
25 } 27 }
26 28
27 ngOnDestroy () {
28 super.ngOnDestroy()
29 }
30
31 getVideosObservable () { 29 getVideosObservable () {
32 return this.videoService.getVideos(this.pagination, this.sort) 30 return this.videoService.getVideos(this.pagination, this.sort)
33 } 31 }
diff --git a/client/src/app/videos/videos-routing.module.ts b/client/src/app/videos/videos-routing.module.ts
index 204851c81..6910421b7 100644
--- a/client/src/app/videos/videos-routing.module.ts
+++ b/client/src/app/videos/videos-routing.module.ts
@@ -1,6 +1,7 @@
1import { NgModule } from '@angular/core' 1import { NgModule } from '@angular/core'
2import { RouterModule, Routes } from '@angular/router' 2import { RouterModule, Routes } from '@angular/router'
3import { MetaGuard } from '@ngx-meta/core' 3import { MetaGuard } from '@ngx-meta/core'
4import { VideoSearchComponent } from './video-list'
4import { VideoRecentlyAddedComponent } from './video-list/video-recently-added.component' 5import { VideoRecentlyAddedComponent } from './video-list/video-recently-added.component'
5import { VideoTrendingComponent } from './video-list/video-trending.component' 6import { VideoTrendingComponent } from './video-list/video-trending.component'
6import { VideosComponent } from './videos.component' 7import { VideosComponent } from './videos.component'
@@ -35,6 +36,15 @@ const videosRoutes: Routes = [
35 } 36 }
36 }, 37 },
37 { 38 {
39 path: 'search',
40 component: VideoSearchComponent,
41 data: {
42 meta: {
43 title: 'Search videos'
44 }
45 }
46 },
47 {
38 path: 'upload', 48 path: 'upload',
39 loadChildren: 'app/videos/+video-edit#VideoAddModule', 49 loadChildren: 'app/videos/+video-edit#VideoAddModule',
40 data: { 50 data: {
@@ -54,6 +64,7 @@ const videosRoutes: Routes = [
54 }, 64 },
55 { 65 {
56 path: ':uuid', 66 path: ':uuid',
67 pathMatch: 'full',
57 redirectTo: 'watch/:uuid' 68 redirectTo: 'watch/:uuid'
58 }, 69 },
59 { 70 {
diff --git a/client/src/app/videos/videos.module.ts b/client/src/app/videos/videos.module.ts
index 6d846fd3b..8c8d52ad9 100644
--- a/client/src/app/videos/videos.module.ts
+++ b/client/src/app/videos/videos.module.ts
@@ -1,6 +1,6 @@
1import { NgModule } from '@angular/core' 1import { NgModule } from '@angular/core'
2import { SharedModule } from '../shared' 2import { SharedModule } from '../shared'
3import { VideoMiniatureComponent } from './video-list' 3import { VideoMiniatureComponent, VideoSearchComponent } from './video-list'
4import { VideoRecentlyAddedComponent } from './video-list/video-recently-added.component' 4import { VideoRecentlyAddedComponent } from './video-list/video-recently-added.component'
5import { VideoTrendingComponent } from './video-list/video-trending.component' 5import { VideoTrendingComponent } from './video-list/video-trending.component'
6import { VideosRoutingModule } from './videos-routing.module' 6import { VideosRoutingModule } from './videos-routing.module'
@@ -17,7 +17,8 @@ import { VideosComponent } from './videos.component'
17 17
18 VideoTrendingComponent, 18 VideoTrendingComponent,
19 VideoRecentlyAddedComponent, 19 VideoRecentlyAddedComponent,
20 VideoMiniatureComponent 20 VideoMiniatureComponent,
21 VideoSearchComponent
21 ], 22 ],
22 23
23 exports: [ 24 exports: [
diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts
index e2798830e..2b70d535e 100644
--- a/server/controllers/api/videos/index.ts
+++ b/server/controllers/api/videos/index.ts
@@ -26,7 +26,6 @@ import {
26 authenticate, 26 authenticate,
27 paginationValidator, 27 paginationValidator,
28 setPagination, 28 setPagination,
29 setVideosSearch,
30 setVideosSort, 29 setVideosSort,
31 videosAddValidator, 30 videosAddValidator,
32 videosGetValidator, 31 videosGetValidator,
@@ -84,6 +83,14 @@ videosRouter.get('/',
84 setPagination, 83 setPagination,
85 asyncMiddleware(listVideos) 84 asyncMiddleware(listVideos)
86) 85)
86videosRouter.get('/search',
87 videosSearchValidator,
88 paginationValidator,
89 videosSortValidator,
90 setVideosSort,
91 setPagination,
92 asyncMiddleware(searchVideos)
93)
87videosRouter.put('/:id', 94videosRouter.put('/:id',
88 authenticate, 95 authenticate,
89 asyncMiddleware(videosUpdateValidator), 96 asyncMiddleware(videosUpdateValidator),
@@ -115,16 +122,6 @@ videosRouter.delete('/:id',
115 asyncMiddleware(removeVideoRetryWrapper) 122 asyncMiddleware(removeVideoRetryWrapper)
116) 123)
117 124
118videosRouter.get('/search/:value',
119 videosSearchValidator,
120 paginationValidator,
121 videosSortValidator,
122 setVideosSort,
123 setPagination,
124 setVideosSearch,
125 asyncMiddleware(searchVideos)
126)
127
128// --------------------------------------------------------------------------- 125// ---------------------------------------------------------------------------
129 126
130export { 127export {
@@ -378,8 +375,7 @@ async function removeVideo (req: express.Request, res: express.Response) {
378 375
379async function searchVideos (req: express.Request, res: express.Response, next: express.NextFunction) { 376async function searchVideos (req: express.Request, res: express.Response, next: express.NextFunction) {
380 const resultList = await db.Video.searchAndPopulateAccountAndServerAndTags( 377 const resultList = await db.Video.searchAndPopulateAccountAndServerAndTags(
381 req.params.value, 378 req.query.search,
382 req.query.field,
383 req.query.start, 379 req.query.start,
384 req.query.count, 380 req.query.count,
385 req.query.sort 381 req.query.sort
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts
index 144a4edbf..3e083fd92 100644
--- a/server/initializers/constants.ts
+++ b/server/initializers/constants.ts
@@ -25,11 +25,6 @@ const API_VERSION = 'v1'
25const PAGINATION_COUNT_DEFAULT = 15 25const PAGINATION_COUNT_DEFAULT = 15
26 26
27// Sortable columns per schema 27// Sortable columns per schema
28const SEARCHABLE_COLUMNS = {
29 VIDEOS: [ 'name', 'magnetUri', 'host', 'account', 'tags' ]
30}
31
32// Sortable columns per schema
33const SORTABLE_COLUMNS = { 28const SORTABLE_COLUMNS = {
34 USERS: [ 'id', 'username', 'createdAt' ], 29 USERS: [ 'id', 'username', 'createdAt' ],
35 JOBS: [ 'id', 'createdAt' ], 30 JOBS: [ 'id', 'createdAt' ],
@@ -361,7 +356,6 @@ export {
361 REMOTE_SCHEME, 356 REMOTE_SCHEME,
362 FOLLOW_STATES, 357 FOLLOW_STATES,
363 AVATARS_DIR, 358 AVATARS_DIR,
364 SEARCHABLE_COLUMNS,
365 SERVER_ACCOUNT_NAME, 359 SERVER_ACCOUNT_NAME,
366 PRIVATE_RSA_KEY_SIZE, 360 PRIVATE_RSA_KEY_SIZE,
367 SORTABLE_COLUMNS, 361 SORTABLE_COLUMNS,
diff --git a/server/middlewares/index.ts b/server/middlewares/index.ts
index aafcad2d9..0cef26953 100644
--- a/server/middlewares/index.ts
+++ b/server/middlewares/index.ts
@@ -4,6 +4,5 @@ export * from './async'
4export * from './oauth' 4export * from './oauth'
5export * from './pagination' 5export * from './pagination'
6export * from './servers' 6export * from './servers'
7export * from './search'
8export * from './sort' 7export * from './sort'
9export * from './user-right' 8export * from './user-right'
diff --git a/server/middlewares/search.ts b/server/middlewares/search.ts
deleted file mode 100644
index 6fe83d25b..000000000
--- a/server/middlewares/search.ts
+++ /dev/null
@@ -1,14 +0,0 @@
1import 'express-validator'
2import * as express from 'express'
3
4function setVideosSearch (req: express.Request, res: express.Response, next: express.NextFunction) {
5 if (!req.query.field) req.query.field = 'name'
6
7 return next()
8}
9
10// ---------------------------------------------------------------------------
11
12export {
13 setVideosSearch
14}
diff --git a/server/middlewares/validators/videos.ts b/server/middlewares/validators/videos.ts
index f21680aa0..ee2ac50c8 100644
--- a/server/middlewares/validators/videos.ts
+++ b/server/middlewares/validators/videos.ts
@@ -18,7 +18,7 @@ import {
18} from '../../helpers/custom-validators/videos' 18} from '../../helpers/custom-validators/videos'
19import { getDurationFromVideoFile } from '../../helpers/ffmpeg-utils' 19import { getDurationFromVideoFile } from '../../helpers/ffmpeg-utils'
20import { logger } from '../../helpers/logger' 20import { logger } from '../../helpers/logger'
21import { CONSTRAINTS_FIELDS, SEARCHABLE_COLUMNS } from '../../initializers' 21import { CONSTRAINTS_FIELDS } from '../../initializers'
22import { database as db } from '../../initializers/database' 22import { database as db } from '../../initializers/database'
23import { UserInstance } from '../../models/account/user-interface' 23import { UserInstance } from '../../models/account/user-interface'
24import { VideoInstance } from '../../models/video/video-interface' 24import { VideoInstance } from '../../models/video/video-interface'
@@ -172,8 +172,7 @@ const videosRemoveValidator = [
172] 172]
173 173
174const videosSearchValidator = [ 174const videosSearchValidator = [
175 param('value').not().isEmpty().withMessage('Should have a valid search'), 175 query('search').not().isEmpty().withMessage('Should have a valid search'),
176 query('field').optional().isIn(SEARCHABLE_COLUMNS.VIDEOS).withMessage('Should have correct searchable column'),
177 176
178 (req: express.Request, res: express.Response, next: express.NextFunction) => { 177 (req: express.Request, res: express.Response, next: express.NextFunction) => {
179 logger.debug('Checking videosSearch parameters', { parameters: req.params }) 178 logger.debug('Checking videosSearch parameters', { parameters: req.params })
diff --git a/server/models/video/video-interface.ts b/server/models/video/video-interface.ts
index be140de86..2a63350af 100644
--- a/server/models/video/video-interface.ts
+++ b/server/models/video/video-interface.ts
@@ -50,7 +50,6 @@ export namespace VideoMethods {
50 export type ListUserVideosForApi = (userId: number, start: number, count: number, sort: string) => Bluebird< ResultList<VideoInstance> > 50 export type ListUserVideosForApi = (userId: number, start: number, count: number, sort: string) => Bluebird< ResultList<VideoInstance> >
51 export type SearchAndPopulateAccountAndServerAndTags = ( 51 export type SearchAndPopulateAccountAndServerAndTags = (
52 value: string, 52 value: string,
53 field: string,
54 start: number, 53 start: number,
55 count: number, 54 count: number,
56 sort: string 55 sort: string
diff --git a/server/models/video/video.ts b/server/models/video/video.ts
index f3469c1de..4dce8e2fc 100644
--- a/server/models/video/video.ts
+++ b/server/models/video/video.ts
@@ -1070,7 +1070,7 @@ loadByUUIDAndPopulateAccountAndServerAndTags = function (uuid: string) {
1070 return Video.findOne(options) 1070 return Video.findOne(options)
1071} 1071}
1072 1072
1073searchAndPopulateAccountAndServerAndTags = function (value: string, field: string, start: number, count: number, sort: string) { 1073searchAndPopulateAccountAndServerAndTags = function (value: string, start: number, count: number, sort: string) {
1074 const serverInclude: Sequelize.IncludeOptions = { 1074 const serverInclude: Sequelize.IncludeOptions = {
1075 model: Video['sequelize'].models.Server, 1075 model: Video['sequelize'].models.Server,
1076 required: false 1076 required: false
@@ -1099,33 +1099,24 @@ searchAndPopulateAccountAndServerAndTags = function (value: string, field: strin
1099 order: [ getSort(sort), [ Video['sequelize'].models.Tag, 'name', 'ASC' ] ] 1099 order: [ getSort(sort), [ Video['sequelize'].models.Tag, 'name', 'ASC' ] ]
1100 } 1100 }
1101 1101
1102 if (field === 'tags') { 1102 // TODO: search on tags too
1103 const escapedValue = Video['sequelize'].escape('%' + value + '%') 1103 // const escapedValue = Video['sequelize'].escape('%' + value + '%')
1104 query.where['id'][Sequelize.Op.in] = Video['sequelize'].literal( 1104 // query.where['id'][Sequelize.Op.in] = Video['sequelize'].literal(
1105 `(SELECT "VideoTags"."videoId" 1105 // `(SELECT "VideoTags"."videoId"
1106 FROM "Tags" 1106 // FROM "Tags"
1107 INNER JOIN "VideoTags" ON "Tags"."id" = "VideoTags"."tagId" 1107 // INNER JOIN "VideoTags" ON "Tags"."id" = "VideoTags"."tagId"
1108 WHERE name ILIKE ${escapedValue} 1108 // WHERE name ILIKE ${escapedValue}
1109 )` 1109 // )`
1110 ) 1110 // )
1111 } else if (field === 'host') { 1111
1112 // FIXME: Include our server? (not stored in the database) 1112 // TODO: search on account too
1113 serverInclude.where = { 1113 // accountInclude.where = {
1114 host: { 1114 // name: {
1115 [Sequelize.Op.iLike]: '%' + value + '%' 1115 // [Sequelize.Op.iLike]: '%' + value + '%'
1116 } 1116 // }
1117 } 1117 // }
1118 serverInclude.required = true 1118 query.where['name'] = {
1119 } else if (field === 'account') { 1119 [Sequelize.Op.iLike]: '%' + value + '%'
1120 accountInclude.where = {
1121 name: {
1122 [Sequelize.Op.iLike]: '%' + value + '%'
1123 }
1124 }
1125 } else {
1126 query.where[field] = {
1127 [Sequelize.Op.iLike]: '%' + value + '%'
1128 }
1129 } 1120 }
1130 1121
1131 query.include = [ 1122 query.include = [
diff --git a/server/tests/api/single-server.ts b/server/tests/api/single-server.ts
index 041d13225..fe192d391 100644
--- a/server/tests/api/single-server.ts
+++ b/server/tests/api/single-server.ts
@@ -225,7 +225,7 @@ describe('Test a single server', function () {
225 expect(video.views).to.equal(3) 225 expect(video.views).to.equal(3)
226 }) 226 })
227 227
228 it('Should search the video by name by default', async function () { 228 it('Should search the video by name', async function () {
229 const res = await searchVideo(server.url, 'my') 229 const res = await searchVideo(server.url, 'my')
230 230
231 expect(res.body.total).to.equal(1) 231 expect(res.body.total).to.equal(1)
@@ -279,35 +279,36 @@ describe('Test a single server', function () {
279 // }) 279 // })
280 // }) 280 // })
281 281
282 it('Should search the video by tag', async function () { 282 // Not implemented yet
283 const res = await searchVideo(server.url, 'tag1', 'tags') 283 // it('Should search the video by tag', async function () {
284 284 // const res = await searchVideo(server.url, 'tag1')
285 expect(res.body.total).to.equal(1) 285 //
286 expect(res.body.data).to.be.an('array') 286 // expect(res.body.total).to.equal(1)
287 expect(res.body.data.length).to.equal(1) 287 // expect(res.body.data).to.be.an('array')
288 288 // expect(res.body.data.length).to.equal(1)
289 const video = res.body.data[0] 289 //
290 expect(video.name).to.equal('my super name') 290 // const video = res.body.data[0]
291 expect(video.category).to.equal(2) 291 // expect(video.name).to.equal('my super name')
292 expect(video.categoryLabel).to.equal('Films') 292 // expect(video.category).to.equal(2)
293 expect(video.licence).to.equal(6) 293 // expect(video.categoryLabel).to.equal('Films')
294 expect(video.licenceLabel).to.equal('Attribution - Non Commercial - No Derivatives') 294 // expect(video.licence).to.equal(6)
295 expect(video.language).to.equal(3) 295 // expect(video.licenceLabel).to.equal('Attribution - Non Commercial - No Derivatives')
296 expect(video.languageLabel).to.equal('Mandarin') 296 // expect(video.language).to.equal(3)
297 expect(video.nsfw).to.be.ok 297 // expect(video.languageLabel).to.equal('Mandarin')
298 expect(video.description).to.equal('my super description') 298 // expect(video.nsfw).to.be.ok
299 expect(video.serverHost).to.equal('localhost:9001') 299 // expect(video.description).to.equal('my super description')
300 expect(video.account).to.equal('root') 300 // expect(video.serverHost).to.equal('localhost:9001')
301 expect(video.isLocal).to.be.true 301 // expect(video.account).to.equal('root')
302 expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ]) 302 // expect(video.isLocal).to.be.true
303 expect(dateIsValid(video.createdAt)).to.be.true 303 // expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ])
304 expect(dateIsValid(video.updatedAt)).to.be.true 304 // expect(dateIsValid(video.createdAt)).to.be.true
305 305 // expect(dateIsValid(video.updatedAt)).to.be.true
306 const test = await testVideoImage(server.url, 'video_short.webm', video.thumbnailPath) 306 //
307 expect(test).to.equal(true) 307 // const test = await testVideoImage(server.url, 'video_short.webm', video.thumbnailPath)
308 }) 308 // expect(test).to.equal(true)
309 // })
309 310
310 it('Should not find a search by name by default', async function () { 311 it('Should not find a search by name', async function () {
311 const res = await searchVideo(server.url, 'hello') 312 const res = await searchVideo(server.url, 'hello')
312 313
313 expect(res.body.total).to.equal(0) 314 expect(res.body.total).to.equal(0)
@@ -315,21 +316,23 @@ describe('Test a single server', function () {
315 expect(res.body.data.length).to.equal(0) 316 expect(res.body.data.length).to.equal(0)
316 }) 317 })
317 318
318 it('Should not find a search by author', async function () { 319 // Not implemented yet
319 const res = await searchVideo(server.url, 'hello', 'account') 320 // it('Should not find a search by author', async function () {
320 321 // const res = await searchVideo(server.url, 'hello')
321 expect(res.body.total).to.equal(0) 322 //
322 expect(res.body.data).to.be.an('array') 323 // expect(res.body.total).to.equal(0)
323 expect(res.body.data.length).to.equal(0) 324 // expect(res.body.data).to.be.an('array')
324 }) 325 // expect(res.body.data.length).to.equal(0)
325 326 // })
326 it('Should not find a search by tag', async function () { 327 //
327 const res = await searchVideo(server.url, 'hello', 'tags') 328 // Not implemented yet
328 329 // it('Should not find a search by tag', async function () {
329 expect(res.body.total).to.equal(0) 330 // const res = await searchVideo(server.url, 'hello')
330 expect(res.body.data).to.be.an('array') 331 //
331 expect(res.body.data.length).to.equal(0) 332 // expect(res.body.total).to.equal(0)
332 }) 333 // expect(res.body.data).to.be.an('array')
334 // expect(res.body.data.length).to.equal(0)
335 // })
333 336
334 it('Should remove the video', async function () { 337 it('Should remove the video', async function () {
335 await removeVideo(server.url, server.accessToken, videoId) 338 await removeVideo(server.url, server.accessToken, videoId)
@@ -443,7 +446,7 @@ describe('Test a single server', function () {
443 }) 446 })
444 447
445 it('Should search the first video', async function () { 448 it('Should search the first video', async function () {
446 const res = await searchVideoWithPagination(server.url, 'webm', 'name', 0, 1, 'name') 449 const res = await searchVideoWithPagination(server.url, 'webm', 0, 1, 'name')
447 450
448 const videos = res.body.data 451 const videos = res.body.data
449 expect(res.body.total).to.equal(4) 452 expect(res.body.total).to.equal(4)
@@ -452,7 +455,7 @@ describe('Test a single server', function () {
452 }) 455 })
453 456
454 it('Should search the last two videos', async function () { 457 it('Should search the last two videos', async function () {
455 const res = await searchVideoWithPagination(server.url, 'webm', 'name', 2, 2, 'name') 458 const res = await searchVideoWithPagination(server.url, 'webm', 2, 2, 'name')
456 459
457 const videos = res.body.data 460 const videos = res.body.data
458 expect(res.body.total).to.equal(4) 461 expect(res.body.total).to.equal(4)
@@ -462,20 +465,21 @@ describe('Test a single server', function () {
462 }) 465 })
463 466
464 it('Should search all the webm videos', async function () { 467 it('Should search all the webm videos', async function () {
465 const res = await searchVideoWithPagination(server.url, 'webm', 'name', 0, 15) 468 const res = await searchVideoWithPagination(server.url, 'webm', 0, 15)
466 469
467 const videos = res.body.data 470 const videos = res.body.data
468 expect(res.body.total).to.equal(4) 471 expect(res.body.total).to.equal(4)
469 expect(videos.length).to.equal(4) 472 expect(videos.length).to.equal(4)
470 }) 473 })
471 474
472 it('Should search all the root author videos', async function () { 475 // Not implemented yet
473 const res = await searchVideoWithPagination(server.url, 'root', 'account', 0, 15) 476 // it('Should search all the root author videos', async function () {
474 477 // const res = await searchVideoWithPagination(server.url, 'root', 0, 15)
475 const videos = res.body.data 478 //
476 expect(res.body.total).to.equal(6) 479 // const videos = res.body.data
477 expect(videos.length).to.equal(6) 480 // expect(res.body.total).to.equal(6)
478 }) 481 // expect(videos.length).to.equal(6)
482 // })
479 483
480 // Not implemented yet 484 // Not implemented yet
481 // it('Should search all the 9001 port videos', async function () { 485 // it('Should search all the 9001 port videos', async function () {
diff --git a/server/tests/utils/videos.ts b/server/tests/utils/videos.ts
index 73a9f1a0a..ff7da9bb2 100644
--- a/server/tests/utils/videos.ts
+++ b/server/tests/utils/videos.ts
@@ -145,26 +145,25 @@ function removeVideo (url: string, token: string, id: number, expectedStatus = 2
145 .expect(expectedStatus) 145 .expect(expectedStatus)
146} 146}
147 147
148function searchVideo (url: string, search: string, field?: string) { 148function searchVideo (url: string, search: string) {
149 const path = '/api/v1/videos' 149 const path = '/api/v1/videos'
150 const req = request(url) 150 const req = request(url)
151 .get(path + '/search/' + search) 151 .get(path + '/search')
152 .set('Accept', 'application/json') 152 .query({ search })
153 153 .set('Accept', 'application/json')
154 if (field) req.query({ field })
155 154
156 return req.expect(200) 155 return req.expect(200)
157 .expect('Content-Type', /json/) 156 .expect('Content-Type', /json/)
158} 157}
159 158
160function searchVideoWithPagination (url: string, search: string, field: string, start: number, count: number, sort?: string) { 159function searchVideoWithPagination (url: string, search: string, start: number, count: number, sort?: string) {
161 const path = '/api/v1/videos' 160 const path = '/api/v1/videos'
162 161
163 const req = request(url) 162 const req = request(url)
164 .get(path + '/search/' + search) 163 .get(path + '/search')
165 .query({ start }) 164 .query({ start })
165 .query({ search })
166 .query({ count }) 166 .query({ count })
167 .query({ field })
168 167
169 if (sort) req.query({ sort }) 168 if (sort) req.query({ sort })
170 169
@@ -177,7 +176,8 @@ function searchVideoWithSort (url: string, search: string, sort: string) {
177 const path = '/api/v1/videos' 176 const path = '/api/v1/videos'
178 177
179 return request(url) 178 return request(url)
180 .get(path + '/search/' + search) 179 .get(path + '/search')
180 .query({ search })
181 .query({ sort }) 181 .query({ sort })
182 .set('Accept', 'application/json') 182 .set('Accept', 'application/json')
183 .expect(200) 183 .expect(200)