Add search by original publication date
authorAndrés Maldonado <amaldona@etu.utc.fr>
Tue, 27 Nov 2018 17:57:02 +0000 (18:57 +0100)
committerChocobozzz <me@florianbigard.com>
Tue, 12 Feb 2019 10:14:37 +0000 (11:14 +0100)
client/src/app/search/advanced-search.model.ts
client/src/app/search/search-filters.component.html
client/src/app/search/search-filters.component.ts
server/models/video/video.ts
server/tests/api/check-params/search.ts
server/tests/api/search/search-videos.ts
shared/models/search/videos-search-query.model.ts

index 033fa9bba86530ba58f7c75154e6dc2ef60ad562..5b713e14550120785bff6dca2ee3604883d25eb9 100644 (file)
@@ -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),
index 74bb781f4f52bc99f9561e7a1777294b9fe11e40..8220a990be23c6e0dd1ac6db33eab1a6f2619ef3 100644 (file)
         </div>
       </div>
 
+      <div class="form-group">
+        <label i18n for="original-publication-after">Original publication year</label>
+
+        <div class="row">
+          <div class="col-sm-6">
+            <input
+              type="text" id="original-publication-after" name="original-publication-after"
+              i18n-placeholder placeholder="After..."
+              [(ngModel)]="originallyPublishedStartYear"
+            >
+          </div>
+          <div class="col-sm-6">
+            <input
+              type="text" id="original-publication-before" name="original-publication-before"
+              i18n-placeholder placeholder="Before..."
+              [(ngModel)]="originallyPublishedEndYear"
+            >
+          </div>
+        </div>
+      </div>
+
       <div class="form-group">
         <div i18n class="radio-label">Duration</div>
 
   <div class="submit-button">
     <input type="submit" i18n-value value="Filter">
   </div>
-</form>
\ No newline at end of file
+</form>
index 3fdc6df35c9d8cdab0e7aba2c5ddf4c9802d68b2..762a6b7f2833264677df9de6c5d631598f5fb74b 100644 (file)
@@ -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()
   }
+
 }
index 215e26d7dd2cec92bffe285473ce81826a87b550..fe81fab1ae4a7e9626527423894734840f4d4fd8 100644 (file)
@@ -1174,6 +1174,8 @@ export class VideoModel extends Model<VideoModel> {
     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<VideoModel> {
       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 = {}
 
index aa81965f33362e32d29890e8c0b2c226185fec4e..7b7e07784f96d965f075faa834b86fbb0146c48a 100644 (file)
@@ -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 })
     })
   })
 
index 50da837da8c974325c4186d67479bdca8050b799..fa4078b99ff6ac41c9a95b3cb8eb9dd9eaac2aa3 100644 (file)
@@ -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 ])
 
index 0db220758286d7a9f1d1da6eecabcaad81ccfa7b..838063095dfabf7b55134fcff4ec12ca3fa99fce 100644 (file)
@@ -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[]