diff options
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 @@ | |||
1 | import { Component, OnDestroy, OnInit } from '@angular/core' | 1 | import { Component, OnInit } from '@angular/core' |
2 | import { ActivatedRoute, Router } from '@angular/router' | 2 | import { ActivatedRoute, Router } from '@angular/router' |
3 | import { NotificationsService } from 'angular2-notifications' | 3 | import { NotificationsService } from 'angular2-notifications' |
4 | import { AbstractVideoList } from '../../shared/video/abstract-video-list' | 4 | import { 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 | }) |
12 | export class AccountVideosComponent extends AbstractVideoList implements OnInit, OnDestroy { | 12 | export 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' | |||
21 | import { SharedModule } from './shared' | 21 | import { SharedModule } from './shared' |
22 | import { VideosModule } from './videos' | 22 | import { VideosModule } from './videos' |
23 | import { MenuComponent, MenuAdminComponent } from './menu' | 23 | import { MenuComponent, MenuAdminComponent } from './menu' |
24 | import { HeaderComponent } from './header' | ||
24 | 25 | ||
25 | export function metaFactory (): MetaLoader { | 26 | export 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 @@ | |||
1 | import { Component, OnInit } from '@angular/core' | ||
2 | import { Router } from '@angular/router' | ||
3 | import { getParameterByName } from '../shared/misc/utils' | ||
4 | |||
5 | @Component({ | ||
6 | selector: 'my-header', | ||
7 | templateUrl: './header.component.html', | ||
8 | styleUrls: [ './header.component.scss' ] | ||
9 | }) | ||
10 | |||
11 | export 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 @@ | |||
1 | export * from './auth' | 1 | export * from './auth' |
2 | export * from './forms' | 2 | export * from './forms' |
3 | export * from './rest' | 3 | export * from './rest' |
4 | export * from './search' | ||
5 | export * from './users' | 4 | export * from './users' |
6 | export * from './video-abuse' | 5 | export * from './video-abuse' |
7 | export * from './video-blacklist' | 6 | export * 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 | |||
3 | function 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 | |||
16 | export { | ||
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 @@ | |||
1 | export * from './search-field.type' | ||
2 | export * from './search.component' | ||
3 | export * from './search.model' | ||
4 | export * 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 @@ | |||
1 | export 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 @@ | |||
1 | import { Component, OnInit } from '@angular/core' | ||
2 | import { Router } from '@angular/router' | ||
3 | import { Search } from './search.model' | ||
4 | import { SearchService } from './search.service' | ||
5 | |||
6 | @Component({ | ||
7 | selector: 'my-search', | ||
8 | templateUrl: './search.component.html', | ||
9 | styleUrls: [ './search.component.scss' ] | ||
10 | }) | ||
11 | |||
12 | export 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 @@ | |||
1 | import { SearchField } from './search-field.type' | ||
2 | |||
3 | export 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 @@ | |||
1 | import { Injectable } from '@angular/core' | ||
2 | import { Subject } from 'rxjs/Subject' | ||
3 | import { ReplaySubject } from 'rxjs/ReplaySubject' | ||
4 | |||
5 | import { 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() | ||
10 | export 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' | |||
17 | import { LoaderComponent } from './misc/loader.component' | 17 | import { LoaderComponent } from './misc/loader.component' |
18 | import { NumberFormatterPipe } from './misc/number-formatter.pipe' | 18 | import { NumberFormatterPipe } from './misc/number-formatter.pipe' |
19 | import { RestExtractor, RestService } from './rest' | 19 | import { RestExtractor, RestService } from './rest' |
20 | import { SearchComponent, SearchService } from './search' | ||
21 | import { UserService } from './users' | 20 | import { UserService } from './users' |
22 | import { VideoAbuseService } from './video-abuse' | 21 | import { VideoAbuseService } from './video-abuse' |
23 | import { VideoBlacklistService } from './video-blacklist' | 22 | import { 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 @@ | |||
1 | import { OnDestroy, OnInit } from '@angular/core' | 1 | import { OnInit } from '@angular/core' |
2 | import { ActivatedRoute, Router } from '@angular/router' | 2 | import { ActivatedRoute, Router } from '@angular/router' |
3 | import { NotificationsService } from 'angular2-notifications' | 3 | import { NotificationsService } from 'angular2-notifications' |
4 | import { Observable } from 'rxjs/Observable' | 4 | import { Observable } from 'rxjs/Observable' |
5 | import { Subscription } from 'rxjs/Subscription' | ||
6 | import { SortField } from './sort-field.type' | 5 | import { SortField } from './sort-field.type' |
7 | import { VideoPagination } from './video-pagination.model' | 6 | import { VideoPagination } from './video-pagination.model' |
8 | import { Video } from './video.model' | 7 | import { Video } from './video.model' |
9 | 8 | ||
10 | export abstract class AbstractVideoList implements OnInit, OnDestroy { | 9 | export 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 | |||
11 | import { VideoUpdate } from '../../../../../shared/models/videos/video-update.model' | 11 | import { VideoUpdate } from '../../../../../shared/models/videos/video-update.model' |
12 | import { RestExtractor } from '../rest/rest-extractor.service' | 12 | import { RestExtractor } from '../rest/rest-extractor.service' |
13 | import { RestService } from '../rest/rest.service' | 13 | import { RestService } from '../rest/rest.service' |
14 | import { Search } from '../search/search.model' | 14 | import { Search } from '../header/search.model' |
15 | import { UserService } from '../users/user.service' | 15 | import { UserService } from '../users/user.service' |
16 | import { SortField } from './sort-field.type' | 16 | import { SortField } from './sort-field.type' |
17 | import { VideoDetails } from './video-details.model' | 17 | import { 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 @@ | |||
1 | export * from './video-recently-added.component' | 1 | export * from './video-recently-added.component' |
2 | export * from './video-trending.component' | 2 | export * from './video-trending.component' |
3 | export * from './video-search.component' | ||
3 | export * from './shared' | 4 | export * 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 @@ | |||
1 | import { Component, OnDestroy, OnInit } from '@angular/core' | 1 | import { Component, OnInit } from '@angular/core' |
2 | import { ActivatedRoute, Router } from '@angular/router' | 2 | import { ActivatedRoute, Router } from '@angular/router' |
3 | import { NotificationsService } from 'angular2-notifications' | 3 | import { NotificationsService } from 'angular2-notifications' |
4 | import { VideoService } from '../../shared/video/video.service' | ||
5 | import { AbstractVideoList } from '../../shared/video/abstract-video-list' | 4 | import { AbstractVideoList } from '../../shared/video/abstract-video-list' |
5 | import { SortField } from '../../shared/video/sort-field.type' | ||
6 | import { 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 | }) |
12 | export class VideoRecentlyAddedComponent extends AbstractVideoList implements OnInit, OnDestroy { | 13 | export 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 @@ | |||
1 | import { Component, OnDestroy, OnInit } from '@angular/core' | ||
2 | import { ActivatedRoute, Router } from '@angular/router' | ||
3 | import { NotificationsService } from 'angular2-notifications' | ||
4 | import { AbstractVideoList } from 'app/shared/video/abstract-video-list' | ||
5 | import { Subscription } from 'rxjs/Subscription' | ||
6 | import { SortField } from '../../shared/video/sort-field.type' | ||
7 | import { 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 | }) | ||
14 | export 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 @@ | |||
1 | import { Component, OnDestroy, OnInit } from '@angular/core' | 1 | import { Component, OnInit } from '@angular/core' |
2 | import { ActivatedRoute, Router } from '@angular/router' | 2 | import { ActivatedRoute, Router } from '@angular/router' |
3 | import { NotificationsService } from 'angular2-notifications' | 3 | import { NotificationsService } from 'angular2-notifications' |
4 | import { VideoService } from '../../shared/video/video.service' | ||
5 | import { AbstractVideoList } from 'app/shared/video/abstract-video-list' | 4 | import { AbstractVideoList } from 'app/shared/video/abstract-video-list' |
5 | import { SortField } from '../../shared/video/sort-field.type' | ||
6 | import { 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 | }) |
12 | export class VideoTrendingComponent extends AbstractVideoList implements OnInit, OnDestroy { | 13 | export 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 @@ | |||
1 | import { NgModule } from '@angular/core' | 1 | import { NgModule } from '@angular/core' |
2 | import { RouterModule, Routes } from '@angular/router' | 2 | import { RouterModule, Routes } from '@angular/router' |
3 | import { MetaGuard } from '@ngx-meta/core' | 3 | import { MetaGuard } from '@ngx-meta/core' |
4 | import { VideoSearchComponent } from './video-list' | ||
4 | import { VideoRecentlyAddedComponent } from './video-list/video-recently-added.component' | 5 | import { VideoRecentlyAddedComponent } from './video-list/video-recently-added.component' |
5 | import { VideoTrendingComponent } from './video-list/video-trending.component' | 6 | import { VideoTrendingComponent } from './video-list/video-trending.component' |
6 | import { VideosComponent } from './videos.component' | 7 | import { 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 @@ | |||
1 | import { NgModule } from '@angular/core' | 1 | import { NgModule } from '@angular/core' |
2 | import { SharedModule } from '../shared' | 2 | import { SharedModule } from '../shared' |
3 | import { VideoMiniatureComponent } from './video-list' | 3 | import { VideoMiniatureComponent, VideoSearchComponent } from './video-list' |
4 | import { VideoRecentlyAddedComponent } from './video-list/video-recently-added.component' | 4 | import { VideoRecentlyAddedComponent } from './video-list/video-recently-added.component' |
5 | import { VideoTrendingComponent } from './video-list/video-trending.component' | 5 | import { VideoTrendingComponent } from './video-list/video-trending.component' |
6 | import { VideosRoutingModule } from './videos-routing.module' | 6 | import { 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 | ) |
86 | videosRouter.get('/search', | ||
87 | videosSearchValidator, | ||
88 | paginationValidator, | ||
89 | videosSortValidator, | ||
90 | setVideosSort, | ||
91 | setPagination, | ||
92 | asyncMiddleware(searchVideos) | ||
93 | ) | ||
87 | videosRouter.put('/:id', | 94 | videosRouter.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 | ||
118 | videosRouter.get('/search/:value', | ||
119 | videosSearchValidator, | ||
120 | paginationValidator, | ||
121 | videosSortValidator, | ||
122 | setVideosSort, | ||
123 | setPagination, | ||
124 | setVideosSearch, | ||
125 | asyncMiddleware(searchVideos) | ||
126 | ) | ||
127 | |||
128 | // --------------------------------------------------------------------------- | 125 | // --------------------------------------------------------------------------- |
129 | 126 | ||
130 | export { | 127 | export { |
@@ -378,8 +375,7 @@ async function removeVideo (req: express.Request, res: express.Response) { | |||
378 | 375 | ||
379 | async function searchVideos (req: express.Request, res: express.Response, next: express.NextFunction) { | 376 | async 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' | |||
25 | const PAGINATION_COUNT_DEFAULT = 15 | 25 | const PAGINATION_COUNT_DEFAULT = 15 |
26 | 26 | ||
27 | // Sortable columns per schema | 27 | // Sortable columns per schema |
28 | const SEARCHABLE_COLUMNS = { | ||
29 | VIDEOS: [ 'name', 'magnetUri', 'host', 'account', 'tags' ] | ||
30 | } | ||
31 | |||
32 | // Sortable columns per schema | ||
33 | const SORTABLE_COLUMNS = { | 28 | const 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' | |||
4 | export * from './oauth' | 4 | export * from './oauth' |
5 | export * from './pagination' | 5 | export * from './pagination' |
6 | export * from './servers' | 6 | export * from './servers' |
7 | export * from './search' | ||
8 | export * from './sort' | 7 | export * from './sort' |
9 | export * from './user-right' | 8 | export * 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 @@ | |||
1 | import 'express-validator' | ||
2 | import * as express from 'express' | ||
3 | |||
4 | function 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 | |||
12 | export { | ||
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' |
19 | import { getDurationFromVideoFile } from '../../helpers/ffmpeg-utils' | 19 | import { getDurationFromVideoFile } from '../../helpers/ffmpeg-utils' |
20 | import { logger } from '../../helpers/logger' | 20 | import { logger } from '../../helpers/logger' |
21 | import { CONSTRAINTS_FIELDS, SEARCHABLE_COLUMNS } from '../../initializers' | 21 | import { CONSTRAINTS_FIELDS } from '../../initializers' |
22 | import { database as db } from '../../initializers/database' | 22 | import { database as db } from '../../initializers/database' |
23 | import { UserInstance } from '../../models/account/user-interface' | 23 | import { UserInstance } from '../../models/account/user-interface' |
24 | import { VideoInstance } from '../../models/video/video-interface' | 24 | import { VideoInstance } from '../../models/video/video-interface' |
@@ -172,8 +172,7 @@ const videosRemoveValidator = [ | |||
172 | ] | 172 | ] |
173 | 173 | ||
174 | const videosSearchValidator = [ | 174 | const 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 | ||
1073 | searchAndPopulateAccountAndServerAndTags = function (value: string, field: string, start: number, count: number, sort: string) { | 1073 | searchAndPopulateAccountAndServerAndTags = 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 | ||
148 | function searchVideo (url: string, search: string, field?: string) { | 148 | function 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 | ||
160 | function searchVideoWithPagination (url: string, search: string, field: string, start: number, count: number, sort?: string) { | 159 | function 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) |