diff --git a/client/src/app/search/advanced-search.model.ts b/client/src/app/search/advanced-search.model.ts index 033fa9bba..5b713e145 100644 --- a/client/src/app/search/advanced-search.model.ts +++ b/client/src/app/search/advanced-search.model.ts @@ -4,6 +4,9 @@ export class AdvancedSearch { startDate: string // ISO 8601 endDate: string // ISO 8601 + originallyPublishedStartDate: string // ISO 8601 + originallyPublishedEndDate: string // ISO 8601 + nsfw: NSFWQuery categoryOneOf: string @@ -23,6 +26,8 @@ export class AdvancedSearch { constructor (options?: { startDate?: string endDate?: string + originallyPublishedStartDate?: string + originallyPublishedEndDate?: string nsfw?: NSFWQuery categoryOneOf?: string licenceOneOf?: string @@ -37,6 +42,9 @@ export class AdvancedSearch { this.startDate = options.startDate || undefined this.endDate = options.endDate || undefined + this.originallyPublishedStartDate = options.originallyPublishedStartDate || undefined + this.originallyPublishedEndDate = options.originallyPublishedEndDate || undefined + this.nsfw = options.nsfw || undefined this.categoryOneOf = options.categoryOneOf || undefined this.licenceOneOf = options.licenceOneOf || undefined @@ -66,6 +74,8 @@ export class AdvancedSearch { reset () { this.startDate = undefined this.endDate = undefined + this.originallyPublishedStartDate = undefined + this.originallyPublishedEndDate = undefined this.nsfw = undefined this.categoryOneOf = undefined this.licenceOneOf = undefined @@ -82,6 +92,8 @@ export class AdvancedSearch { return { startDate: this.startDate, endDate: this.endDate, + originallyPublishedStartDate: this.originallyPublishedStartDate, + originallyPublishedEndDate: this.originallyPublishedEndDate, nsfw: this.nsfw, categoryOneOf: this.categoryOneOf, licenceOneOf: this.licenceOneOf, @@ -98,6 +110,8 @@ export class AdvancedSearch { return { startDate: this.startDate, endDate: this.endDate, + originallyPublishedStartDate: this.originallyPublishedStartDate, + originallyPublishedEndDate: this.originallyPublishedEndDate, nsfw: this.nsfw, categoryOneOf: this.intoArray(this.categoryOneOf), licenceOneOf: this.intoArray(this.licenceOneOf), diff --git a/client/src/app/search/search-filters.component.html b/client/src/app/search/search-filters.component.html index 74bb781f4..8220a990b 100644 --- a/client/src/app/search/search-filters.component.html +++ b/client/src/app/search/search-filters.component.html @@ -20,6 +20,27 @@ +
+ + +
+
+ +
+
+ +
+
+
+
Duration
@@ -93,4 +114,4 @@
- \ No newline at end of file + diff --git a/client/src/app/search/search-filters.component.ts b/client/src/app/search/search-filters.component.ts index 3fdc6df35..762a6b7f2 100644 --- a/client/src/app/search/search-filters.component.ts +++ b/client/src/app/search/search-filters.component.ts @@ -25,6 +25,9 @@ export class SearchFiltersComponent implements OnInit { publishedDateRange: string durationRange: string + originallyPublishedStartYear: string + originallyPublishedEndYear: string + constructor ( private i18n: I18n, private serverService: ServerService @@ -86,15 +89,27 @@ export class SearchFiltersComponent implements OnInit { this.loadFromDurationRange() this.loadFromPublishedRange() + this.loadOriginallyPublishedAtYears() } formUpdated () { this.updateModelFromDurationRange() this.updateModelFromPublishedRange() + this.updateModelFromOriginallyPublishedAtYears() this.filtered.emit(this.advancedSearch) } + private loadOriginallyPublishedAtYears () { + this.originallyPublishedStartYear = this.advancedSearch.originallyPublishedStartDate + ? new Date(this.advancedSearch.originallyPublishedStartDate).getFullYear().toString() + : null + + this.originallyPublishedEndYear = this.advancedSearch.originallyPublishedEndDate + ? new Date(this.advancedSearch.originallyPublishedEndDate).getFullYear().toString() + : null + } + private loadFromDurationRange () { if (this.advancedSearch.durationMin || this.advancedSearch.durationMax) { const fourMinutes = 60 * 4 @@ -127,6 +142,32 @@ export class SearchFiltersComponent implements OnInit { } } + private updateModelFromOriginallyPublishedAtYears () { + const baseDate = new Date() + baseDate.setHours(0, 0, 0, 0) + baseDate.setMonth(0, 1) + + if (this.originallyPublishedStartYear) { + const year = parseInt(this.originallyPublishedStartYear, 10) + const start = new Date(baseDate) + start.setFullYear(year) + + this.advancedSearch.originallyPublishedStartDate = start.toISOString() + } else { + this.advancedSearch.originallyPublishedStartDate = null + } + + if (this.originallyPublishedEndYear) { + const year = parseInt(this.originallyPublishedEndYear, 10) + const end = new Date(baseDate) + end.setFullYear(year) + + this.advancedSearch.originallyPublishedEndDate = end.toISOString() + } else { + this.advancedSearch.originallyPublishedEndDate = null + } + } + private updateModelFromDurationRange () { if (!this.durationRange) return @@ -174,4 +215,5 @@ export class SearchFiltersComponent implements OnInit { this.advancedSearch.startDate = date.toISOString() } + } diff --git a/server/models/video/video.ts b/server/models/video/video.ts index 215e26d7d..fe81fab1a 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts @@ -1174,6 +1174,8 @@ export class VideoModel extends Model { sort?: string startDate?: string // ISO 8601 endDate?: string // ISO 8601 + originallyPublishedStartDate?: string + originallyPublishedEndDate?: string nsfw?: boolean categoryOneOf?: number[] licenceOneOf?: number[] @@ -1196,6 +1198,15 @@ export class VideoModel extends Model { whereAnd.push({ publishedAt: publishedAtRange }) } + if (options.originallyPublishedStartDate || options.originallyPublishedEndDate) { + const originallyPublishedAtRange = {} + + if (options.originallyPublishedStartDate) originallyPublishedAtRange[ Sequelize.Op.gte ] = options.originallyPublishedStartDate + if (options.originallyPublishedEndDate) originallyPublishedAtRange[ Sequelize.Op.lte ] = options.originallyPublishedEndDate + + whereAnd.push({ originallyPublishedAt: originallyPublishedAtRange }) + } + if (options.durationMin || options.durationMax) { const durationRange = {} diff --git a/server/tests/api/check-params/search.ts b/server/tests/api/check-params/search.ts index aa81965f3..7b7e07784 100644 --- a/server/tests/api/check-params/search.ts +++ b/server/tests/api/check-params/search.ts @@ -113,6 +113,12 @@ describe('Test videos API validator', function () { const customQuery2 = immutableAssign(query, { endDate: 'hello' }) await makeGetRequest({ url: server.url, path, query: customQuery2, statusCodeExpected: 400 }) + + const customQuery3 = immutableAssign(query, { originallyPublishedStartDate: 'hello' }) + await makeGetRequest({ url: server.url, path, query: customQuery3, statusCodeExpected: 400 }) + + const customQuery4 = immutableAssign(query, { originallyPublishedEndDate: 'hello' }) + await makeGetRequest({ url: server.url, path, query: customQuery4, statusCodeExpected: 400 }) }) }) diff --git a/server/tests/api/search/search-videos.ts b/server/tests/api/search/search-videos.ts index 50da837da..fa4078b99 100644 --- a/server/tests/api/search/search-videos.ts +++ b/server/tests/api/search/search-videos.ts @@ -60,7 +60,10 @@ describe('Test a videos search', function () { const attributes6 = immutableAssign(attributes1, { name: attributes1.name + ' - 6', tags: [ 't1', 't2 '] }) await uploadVideo(server.url, server.accessToken, attributes6) - const attributes7 = immutableAssign(attributes1, { name: attributes1.name + ' - 7' }) + const attributes7 = immutableAssign(attributes1, { + name: attributes1.name + ' - 7', + originallyPublishedAt: '2019-02-12T09:58:08.286Z' + }) await uploadVideo(server.url, server.accessToken, attributes7) const attributes8 = immutableAssign(attributes1, { name: attributes1.name + ' - 8', licence: 4 }) @@ -343,6 +346,67 @@ describe('Test a videos search', function () { expect(videos[0].name).to.equal('1111 2222 3333') }) + it('Should search on originally published date', async function () { + const baseQuery = { + search: '1111 2222 3333', + languageOneOf: [ 'pl', 'fr' ], + durationMax: 4, + nsfw: 'false' as 'false', + licenceOneOf: [ 1, 4 ] + } + + { + const query = immutableAssign(baseQuery, { originallyPublishedStartDate: '2019-02-11T09:58:08.286Z' }) + const res = await advancedVideosSearch(server.url, query) + + expect(res.body.total).to.equal(1) + expect(res.body.data[0].name).to.equal('1111 2222 3333 - 7') + } + + { + const query = immutableAssign(baseQuery, { originallyPublishedEndDate: '2019-03-11T09:58:08.286Z' }) + const res = await advancedVideosSearch(server.url, query) + + expect(res.body.total).to.equal(1) + expect(res.body.data[0].name).to.equal('1111 2222 3333 - 7') + } + + { + const query = immutableAssign(baseQuery, { originallyPublishedEndDate: '2019-01-11T09:58:08.286Z' }) + const res = await advancedVideosSearch(server.url, query) + + expect(res.body.total).to.equal(0) + } + + { + const query = immutableAssign(baseQuery, { originallyPublishedStartDate: '2019-03-11T09:58:08.286Z' }) + const res = await advancedVideosSearch(server.url, query) + + expect(res.body.total).to.equal(0) + } + + { + const query = immutableAssign(baseQuery, { + originallyPublishedStartDate: '2019-01-11T09:58:08.286Z', + originallyPublishedEndDate: '2019-01-10T09:58:08.286Z' + }) + const res = await advancedVideosSearch(server.url, query) + + expect(res.body.total).to.equal(0) + } + + { + const query = immutableAssign(baseQuery, { + originallyPublishedStartDate: '2019-01-11T09:58:08.286Z', + originallyPublishedEndDate: '2019-04-11T09:58:08.286Z' + }) + const res = await advancedVideosSearch(server.url, query) + + expect(res.body.total).to.equal(1) + expect(res.body.data[0].name).to.equal('1111 2222 3333 - 7') + } + }) + after(async function () { killallServers([ server ]) diff --git a/shared/models/search/videos-search-query.model.ts b/shared/models/search/videos-search-query.model.ts index 0db220758..838063095 100644 --- a/shared/models/search/videos-search-query.model.ts +++ b/shared/models/search/videos-search-query.model.ts @@ -11,6 +11,9 @@ export interface VideosSearchQuery { startDate?: string // ISO 8601 endDate?: string // ISO 8601 + originallyPublishedStartDate?: string // ISO 8601 + originallyPublishedEndDate?: string // ISO 8601 + nsfw?: NSFWQuery categoryOneOf?: number[]