Try to fix subscriptions inconsistencies
authorChocobozzz <me@florianbigard.com>
Wed, 8 Jan 2020 14:11:38 +0000 (15:11 +0100)
committerChocobozzz <me@florianbigard.com>
Wed, 8 Jan 2020 14:44:41 +0000 (15:44 +0100)
12 files changed:
client/src/app/shared/video/abstract-video-list.html
server/lib/activitypub/send/send-update.ts
server/lib/activitypub/videos.ts
server/lib/video-transcoding.ts
server/models/account/account.ts
server/models/activitypub/actor-follow.ts
server/models/activitypub/actor.ts
server/models/video/video-caption.ts
server/models/video/video-channel.ts
server/models/video/video.ts
server/tests/api/activitypub/helpers.ts
server/tests/api/server/follows.ts

index 3abc4312f43163dfbe09f60a34e29e6735d22981..c8bb4270bad62b18baf7d5f116e624c6ffc81fbb 100644 (file)
@@ -25,7 +25,7 @@
     </div>
   </div>
 
-  <div class="no-results" i18n *ngIf="pagination.totalItems === 0">No results.</div>
+  <div class="no-results" i18n *ngIf="hasDoneFirstQuery && videos.length === 0">No results.</div>
   <div
     myInfiniteScroller (nearOfBottom)="onNearOfBottom()" [autoInit]="true" [dataObservable]="onDataSubject.asObservable()"
     class="videos"
index cb14b8dbfeffb08076cf6701b18ea9eb8a6a882f..9c76671b5d8b931bdbbeef4fe14f7cbcd06bf9a2 100644 (file)
@@ -35,7 +35,7 @@ async function sendUpdateVideo (videoArg: MVideoAPWithoutCaption, t: Transaction
 
   // Needed to build the AP object
   if (!video.VideoCaptions) {
-    video.VideoCaptions = await video.$get('VideoCaptions', { transaction: t }) as VideoCaptionModel[]
+    video.VideoCaptions = await video.$get('VideoCaptions', { transaction: t })
   }
 
   const videoObject = video.toActivityPubObject()
index 2fb1f8d4982f8082257766ab5c198381420295a1..ade93150f39453837dcebde1cc269d7e86497a61 100644 (file)
@@ -86,7 +86,7 @@ async function federateVideoIfNeeded (videoArg: MVideoAPWithoutCaption, isNewVid
       video.VideoCaptions = await video.$get('VideoCaptions', {
         attributes: [ 'language' ],
         transaction
-      }) as VideoCaptionModel[]
+      })
     }
 
     if (isNewVideo) {
index 4fd1d62a9140f0655d976741ebbcdae83d0919ff..0d5b3ae39326ad7cf4c4e6887b2054f4a5fc28eb 100644 (file)
@@ -206,7 +206,7 @@ async function generateHlsPlaylist (video: MVideoWithFile, resolution: VideoReso
   await createTorrentAndSetInfoHash(videoStreamingPlaylist, newVideoFile)
 
   await newVideoFile.save()
-  videoStreamingPlaylist.VideoFiles = await videoStreamingPlaylist.$get('VideoFiles') as VideoFileModel[]
+  videoStreamingPlaylist.VideoFiles = await videoStreamingPlaylist.$get('VideoFiles')
 
   video.setHLSPlaylist(videoStreamingPlaylist)
 
index a757b7203a641d336420a90d9758130f04ee2bcc..8a0ffeb633d77795a82bda75188e649bb3948266 100644 (file)
@@ -223,7 +223,7 @@ export class AccountModel extends Model<AccountModel> {
   @BeforeDestroy
   static async sendDeleteIfOwned (instance: AccountModel, options) {
     if (!instance.Actor) {
-      instance.Actor = await instance.$get('Actor', { transaction: options.transaction }) as ActorModel
+      instance.Actor = await instance.$get('Actor', { transaction: options.transaction })
     }
 
     await ActorFollowModel.removeFollowsOf(instance.Actor.id, options.transaction)
index c65b975d23b8abce46c1663d7059e620b37940c0..f21d2b8a29894d50dedcfa6d143b407b1ce3df9f 100644 (file)
@@ -36,6 +36,7 @@ import {
   MActorFollowSubscriptions
 } from '@server/typings/models'
 import { ActivityPubActorType } from '@shared/models'
+import { afterCommitIfTransaction } from '@server/helpers/database-utils'
 
 @Table({
   tableName: 'actorFollow',
@@ -104,20 +105,20 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
 
   @AfterCreate
   @AfterUpdate
-  static incrementFollowerAndFollowingCount (instance: ActorFollowModel) {
+  static incrementFollowerAndFollowingCount (instance: ActorFollowModel, options: any) {
     if (instance.state !== 'accepted') return undefined
 
     return Promise.all([
-      ActorModel.incrementFollows(instance.actorId, 'followingCount', 1),
-      ActorModel.incrementFollows(instance.targetActorId, 'followersCount', 1)
+      ActorModel.rebuildFollowsCount(instance.actorId, 'following', options.transaction),
+      ActorModel.rebuildFollowsCount(instance.targetActorId, 'followers', options.transaction)
     ])
   }
 
   @AfterDestroy
-  static decrementFollowerAndFollowingCount (instance: ActorFollowModel) {
+  static decrementFollowerAndFollowingCount (instance: ActorFollowModel, options: any) {
     return Promise.all([
-      ActorModel.incrementFollows(instance.actorId, 'followingCount',-1),
-      ActorModel.incrementFollows(instance.targetActorId, 'followersCount', -1)
+      ActorModel.rebuildFollowsCount(instance.actorId, 'following', options.transaction),
+      ActorModel.rebuildFollowsCount(instance.targetActorId, 'followers', options.transaction)
     ])
   }
 
index 58b52ffb1cdab772a736efe3dae7a0f2d3566b7a..007647ced187f20c46ddf850543e684d1f7eb7d7 100644 (file)
@@ -47,7 +47,7 @@ import {
   MActorWithInboxes
 } from '../../typings/models'
 import * as Bluebird from 'bluebird'
-import { Op, Transaction } from 'sequelize'
+import { Op, Transaction, literal } from 'sequelize'
 
 enum ScopeNames {
   FULL = 'FULL'
@@ -421,13 +421,24 @@ export class ActorModel extends Model<ActorModel> {
     return ActorModel.scope(ScopeNames.FULL).findOne(query)
   }
 
-  static incrementFollows (id: number, column: 'followersCount' | 'followingCount', by: number) {
-    return ActorModel.increment(column, {
-      by,
-      where: {
-        id
-      }
-    })
+  static rebuildFollowsCount (ofId: number, type: 'followers' | 'following', transaction?: Transaction) {
+    const sanitizedOfId = parseInt(ofId + '', 10)
+    const where = { id: sanitizedOfId }
+
+    let columnToUpdate: string
+    let columnOfCount: string
+
+    if (type === 'followers') {
+      columnToUpdate = 'followersCount'
+      columnOfCount = 'targetActorId'
+    } else {
+      columnToUpdate = 'followingCount'
+      columnOfCount = 'actorId'
+    }
+
+    return ActorModel.update({
+      [columnToUpdate]: literal(`(SELECT COUNT(*) FROM "actorFollow" WHERE "${columnOfCount}" = ${sanitizedOfId})`)
+    }, { where, transaction })
   }
 
   getSharedInbox (this: MActorWithInboxes) {
index ad580176857b3727a0f1a00c0f81fe6a1db89d2c..eeb2a4afdc7cfcb351a759cef9b24cd486decaff 100644 (file)
@@ -79,7 +79,7 @@ export class VideoCaptionModel extends Model<VideoCaptionModel> {
   @BeforeDestroy
   static async removeFiles (instance: VideoCaptionModel) {
     if (!instance.Video) {
-      instance.Video = await instance.$get('Video') as VideoModel
+      instance.Video = await instance.$get('Video')
     }
 
     if (instance.isOwned()) {
index 05545bd9d6f9d6e925d0b4f7a1f78065a2a6d6f7..e10adcb3aca3817d78aa19cfcc0d584fff81b15d 100644 (file)
@@ -249,7 +249,7 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
   @BeforeDestroy
   static async sendDeleteIfOwned (instance: VideoChannelModel, options) {
     if (!instance.Actor) {
-      instance.Actor = await instance.$get('Actor', { transaction: options.transaction }) as ActorModel
+      instance.Actor = await instance.$get('Actor', { transaction: options.transaction })
     }
 
     if (instance.Actor.isOwned()) {
index cd3245ee400c45d8805c8dcdea1c13bdae017437..ac8c81ddf27024f23e9d467d7515aff7ce1e3a31 100644 (file)
@@ -1061,7 +1061,7 @@ export class VideoModel extends Model<VideoModel> {
 
     if (instance.isOwned()) {
       if (!Array.isArray(instance.VideoFiles)) {
-        instance.VideoFiles = await instance.$get('VideoFiles') as VideoFileModel[]
+        instance.VideoFiles = await instance.$get('VideoFiles')
       }
 
       // Remove physical files and torrents
index 0d1f154fe5bc503b231271bd5cea1bfa6888537d..8c00ba3d6fdcdc07224b86bb0f61e7753801ce17 100644 (file)
@@ -76,7 +76,6 @@ describe('Test activity pub helpers', function () {
       const mastodonObject = cloneDeep(require('./json/mastodon/bad-http-signature.json'))
       req.body = mastodonObject.body
       req.headers = mastodonObject.headers
-      req.headers.signature = 'Signature ' + req.headers.signature
 
       const parsed = parseHTTPSignature(req, 3600 * 1000 * 365 * 10)
       const publicKey = require('./json/mastodon/public-key.json').publicKey
@@ -95,7 +94,6 @@ describe('Test activity pub helpers', function () {
       const mastodonObject = cloneDeep(require('./json/mastodon/http-signature.json'))
       req.body = mastodonObject.body
       req.headers = mastodonObject.headers
-      req.headers.signature = 'Signature ' + req.headers.signature
 
       const parsed = parseHTTPSignature(req, 3600 * 1000 * 365 * 10)
       const publicKey = require('./json/mastodon/bad-public-key.json').publicKey
@@ -114,7 +112,6 @@ describe('Test activity pub helpers', function () {
       const mastodonObject = cloneDeep(require('./json/mastodon/http-signature.json'))
       req.body = mastodonObject.body
       req.headers = mastodonObject.headers
-      req.headers.signature = 'Signature ' + req.headers.signature
 
       let errored = false
       try {
@@ -126,7 +123,7 @@ describe('Test activity pub helpers', function () {
       expect(errored).to.be.true
     })
 
-    it('Should fail without scheme', async function () {
+    it('Should with a scheme', async function () {
       const req = buildRequestStub()
       req.method = 'POST'
       req.url = '/accounts/ronan/inbox'
@@ -134,6 +131,7 @@ describe('Test activity pub helpers', function () {
       const mastodonObject = cloneDeep(require('./json/mastodon/http-signature.json'))
       req.body = mastodonObject.body
       req.headers = mastodonObject.headers
+      req.headers = 'Signature ' + mastodonObject.headers
 
       let errored = false
       try {
@@ -153,7 +151,6 @@ describe('Test activity pub helpers', function () {
       const mastodonObject = cloneDeep(require('./json/mastodon/http-signature.json'))
       req.body = mastodonObject.body
       req.headers = mastodonObject.headers
-      req.headers.signature = 'Signature ' + req.headers.signature
 
       const parsed = parseHTTPSignature(req, 3600 * 1000 * 365 * 10)
       const publicKey = require('./json/mastodon/public-key.json').publicKey
index 60dbe2e6db07510d1bfd9b13392297c9d87a34ef..4ffa9e7910f75eaa29d12c4c7785301c5e6746b0 100644 (file)
@@ -419,7 +419,7 @@ describe('Test follows', function () {
       await expectAccountFollows(servers[1].url, 'peertube@localhost:' + servers[0].port, 0, 1)
       await expectAccountFollows(servers[1].url, 'peertube@localhost:' + servers[1].port, 1, 0)
 
-      await expectAccountFollows(servers[2].url, 'peertube@localhost:' + servers[0].port, 0, 2)
+      await expectAccountFollows(servers[2].url, 'peertube@localhost:' + servers[0].port, 0, 1)
       await expectAccountFollows(servers[2].url, 'peertube@localhost:' + servers[2].port, 1, 0)
     })