Fix video files duplicated when fps is null
authorChocobozzz <me@florianbigard.com>
Wed, 26 Sep 2018 12:08:35 +0000 (14:08 +0200)
committerChocobozzz <me@florianbigard.com>
Wed, 26 Sep 2018 12:08:35 +0000 (14:08 +0200)
Null values are not considered equal in a UNIQUE index

server/initializers/constants.ts
server/initializers/migrations/0260-upload-quota-daily.ts [new file with mode: 0644]
server/initializers/migrations/0260-upload_quota_daily.ts [deleted file]
server/initializers/migrations/0275-video-file-unique.ts [new file with mode: 0644]
server/lib/activitypub/videos.ts
server/models/account/account.ts
server/models/video/video-file.ts

index de426c16e0ad35d731d8ac8d7f3c3945d2e17f1c..09ecedfa5bb5208bd40d90cfae8f49d37ae2269c 100644 (file)
@@ -16,7 +16,7 @@ let config: IConfig = require('config')
 
 // ---------------------------------------------------------------------------
 
-const LAST_MIGRATION_VERSION = 270
+const LAST_MIGRATION_VERSION = 275
 
 // ---------------------------------------------------------------------------
 
diff --git a/server/initializers/migrations/0260-upload-quota-daily.ts b/server/initializers/migrations/0260-upload-quota-daily.ts
new file mode 100644 (file)
index 0000000..d25154b
--- /dev/null
@@ -0,0 +1,23 @@
+import * as Sequelize from 'sequelize'
+import { CONSTRAINTS_FIELDS } from '../constants'
+
+async function up (utils: {
+  transaction: Sequelize.Transaction
+  queryInterface: Sequelize.QueryInterface
+  sequelize: Sequelize.Sequelize
+}): Promise<any> {
+  {
+    const data = {
+      type: Sequelize.BIGINT,
+      allowNull: false,
+      defaultValue: -1
+    }
+    await utils.queryInterface.addColumn('user', 'videoQuotaDaily', data)
+  }
+}
+
+function down (options) {
+  throw new Error('Not implemented.')
+}
+
+export { up, down }
diff --git a/server/initializers/migrations/0260-upload_quota_daily.ts b/server/initializers/migrations/0260-upload_quota_daily.ts
deleted file mode 100644 (file)
index d25154b..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-import * as Sequelize from 'sequelize'
-import { CONSTRAINTS_FIELDS } from '../constants'
-
-async function up (utils: {
-  transaction: Sequelize.Transaction
-  queryInterface: Sequelize.QueryInterface
-  sequelize: Sequelize.Sequelize
-}): Promise<any> {
-  {
-    const data = {
-      type: Sequelize.BIGINT,
-      allowNull: false,
-      defaultValue: -1
-    }
-    await utils.queryInterface.addColumn('user', 'videoQuotaDaily', data)
-  }
-}
-
-function down (options) {
-  throw new Error('Not implemented.')
-}
-
-export { up, down }
diff --git a/server/initializers/migrations/0275-video-file-unique.ts b/server/initializers/migrations/0275-video-file-unique.ts
new file mode 100644 (file)
index 0000000..fd89188
--- /dev/null
@@ -0,0 +1,34 @@
+import * as Sequelize from 'sequelize'
+
+async function up (utils: {
+  transaction: Sequelize.Transaction
+  queryInterface: Sequelize.QueryInterface
+  sequelize: Sequelize.Sequelize
+}): Promise<any> {
+  {
+    const query = 'DELETE FROM "videoFile" vf1 USING "videoFile" vf2 WHERE vf1.id < vf2.id ' +
+      'AND vf1."videoId" = vf2."videoId" AND vf1.resolution = vf2.resolution AND vf1.fps IS NULL'
+    await utils.sequelize.query(query)
+  }
+
+  {
+    const query = 'UPDATE "videoFile" SET fps = -1 WHERE fps IS NULL;'
+    await utils.sequelize.query(query)
+  }
+
+  {
+    const data = {
+      type: Sequelize.INTEGER,
+      allowNull: false,
+      defaultValue: -1
+    }
+    await utils.queryInterface.changeColumn('videoFile', 'fps', data)
+  }
+
+}
+
+function down (options) {
+  throw new Error('Not implemented.')
+}
+
+export { up, down }
index db72ef23c54e09a563d0b33b4ddab662b652592c..3dccabe120387670e2dd5b67738026ef30a06a2b 100644 (file)
@@ -478,7 +478,7 @@ function videoFileActivityUrlToDBAttributes (videoCreated: VideoModel, videoObje
       resolution: fileUrl.height,
       size: fileUrl.size,
       videoId: videoCreated.id,
-      fps: fileUrl.fps
+      fps: fileUrl.fps || -1
     } as VideoFileModel
     attributes.push(attribute)
   }
index 580d920ceddad9cd23db6eeb01740eec26822611..27c75d8861203c3be8c6e8e27b9d134e3dbb334c 100644 (file)
@@ -19,7 +19,6 @@ import { isAccountDescriptionValid } from '../../helpers/custom-validators/accou
 import { sendDeleteActor } from '../../lib/activitypub/send'
 import { ActorModel } from '../activitypub/actor'
 import { ApplicationModel } from '../application/application'
-import { AvatarModel } from '../avatar/avatar'
 import { ServerModel } from '../server/server'
 import { getSort, throwIfNotValid } from '../utils'
 import { VideoChannelModel } from '../video/video-channel'
index 0887a37384fa8f846bc799a42706a115587801be..f040803b9a0240d2156df0dc073e0609f237b3fe 100644 (file)
@@ -66,8 +66,8 @@ export class VideoFileModel extends Model<VideoFileModel> {
   @Column
   infoHash: string
 
-  @AllowNull(true)
-  @Default(null)
+  @AllowNull(false)
+  @Default(-1)
   @Is('VideoFileFPS', value => throwIfNotValid(value, isVideoFPSResolutionValid, 'fps'))
   @Column
   fps: number