Update follower/following counts

pull/200/head
Chocobozzz 2018-01-12 11:47:45 +01:00
parent 6502c3d43e
commit 32b2b43c06
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
8 changed files with 108 additions and 1 deletions

View File

@ -9,7 +9,7 @@ import { isTestInstance, root, sanitizeHost, sanitizeUrl } from '../helpers/core
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
const LAST_MIGRATION_VERSION = 170 const LAST_MIGRATION_VERSION = 175
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

@ -0,0 +1,24 @@
import * as Sequelize from 'sequelize'
import { ACTOR_FOLLOW_SCORE } from '../index'
async function up (utils: {
transaction: Sequelize.Transaction,
queryInterface: Sequelize.QueryInterface,
sequelize: Sequelize.Sequelize
}): Promise<void> {
const query = 'UPDATE "actor" SET ' +
'"followersCount" = (SELECT COUNT(*) FROM "actorFollow" WHERE "actor"."id" = "actorFollow"."targetActorId"), ' +
'"followingCount" = (SELECT COUNT(*) FROM "actorFollow" WHERE "actor"."id" = "actorFollow"."actorId") ' +
'WHERE "actor"."serverId" IS NULL'
await utils.sequelize.query(query)
}
function down (options) {
throw new Error('Not implemented.')
}
export {
up,
down
}

View File

@ -314,6 +314,7 @@ async function refreshActorIfNeeded (actor: ActorModel) {
if (result === undefined) throw new Error('Cannot fetch remote actor in refresh actor.') if (result === undefined) throw new Error('Cannot fetch remote actor in refresh actor.')
return sequelizeTypescript.transaction(async t => { return sequelizeTypescript.transaction(async t => {
logger.info('coucou', result.actor.toJSON())
updateInstanceWithAnother(actor, result.actor) updateInstanceWithAnother(actor, result.actor)
if (result.avatarName !== undefined) { if (result.avatarName !== undefined) {

View File

@ -51,6 +51,9 @@ async function follow (actor: ActorModel, targetActorURL: string) {
transaction: t transaction: t
}) })
actorFollow.ActorFollower = actor
actorFollow.ActorFollowing = targetActor
if (actorFollow.state !== 'accepted') { if (actorFollow.state !== 'accepted') {
actorFollow.state = 'accepted' actorFollow.state = 'accepted'
await actorFollow.save({ transaction: t }) await actorFollow.save({ transaction: t })

View File

@ -2,6 +2,7 @@ import * as Bluebird from 'bluebird'
import { values } from 'lodash' import { values } from 'lodash'
import * as Sequelize from 'sequelize' import * as Sequelize from 'sequelize'
import { import {
AfterCreate, AfterDestroy, AfterUpdate,
AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, IsInt, Max, Model, Table, AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, IsInt, Max, Model, Table,
UpdatedAt UpdatedAt
} from 'sequelize-typescript' } from 'sequelize-typescript'
@ -79,6 +80,25 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
}) })
ActorFollowing: ActorModel ActorFollowing: ActorModel
@AfterCreate
@AfterUpdate
static incrementFollowerAndFollowingCount (instance: ActorFollowModel) {
if (instance.state !== 'accepted') return
return Promise.all([
ActorModel.incrementFollows(instance.actorId, 'followingCount', 1),
ActorModel.incrementFollows(instance.targetActorId, 'followersCount', 1)
])
}
@AfterDestroy
static decrementFollowerAndFollowingCount (instance: ActorFollowModel) {
return Promise.all([
ActorModel.incrementFollows(instance.actorId, 'followingCount',-1),
ActorModel.incrementFollows(instance.targetActorId, 'followersCount', -1)
])
}
// Remove actor follows with a score of 0 (too many requests where they were unreachable) // Remove actor follows with a score of 0 (too many requests where they were unreachable)
static async removeBadActorFollows () { static async removeBadActorFollows () {
const actorFollows = await ActorFollowModel.listBadActorFollows() const actorFollows = await ActorFollowModel.listBadActorFollows()

View File

@ -264,6 +264,16 @@ export class ActorModel extends Model<ActorModel> {
return ActorModel.scope(ScopeNames.FULL).findOne(query) return ActorModel.scope(ScopeNames.FULL).findOne(query)
} }
static incrementFollows (id: number, column: 'followersCount' | 'followingCount', by: number) {
// FIXME: typings
return (ActorModel as any).increment(column, {
by,
where: {
id
}
})
}
toFormattedJSON () { toFormattedJSON () {
let avatar: Avatar = null let avatar: Avatar = null
if (this.Avatar) { if (this.Avatar) {

View File

@ -12,6 +12,7 @@ import {
} from '../../utils/index' } from '../../utils/index'
import { dateIsValid } from '../../utils/miscs/miscs' import { dateIsValid } from '../../utils/miscs/miscs'
import { follow, getFollowersListPaginationAndSort, getFollowingListPaginationAndSort, unfollow } from '../../utils/server/follows' import { follow, getFollowersListPaginationAndSort, getFollowingListPaginationAndSort, unfollow } from '../../utils/server/follows'
import { expectAccountFollows } from '../../utils/users/accounts'
import { userLogin } from '../../utils/users/login' import { userLogin } from '../../utils/users/login'
import { createUser } from '../../utils/users/users' import { createUser } from '../../utils/users/users'
import { import {
@ -116,6 +117,19 @@ describe('Test follows', function () {
expect(follows.length).to.equal(0) expect(follows.length).to.equal(0)
}) })
it('Should have the correct following counts', async function () {
await expectAccountFollows(servers[0].url, 'peertube@localhost:9001', 0, 2)
await expectAccountFollows(servers[0].url, 'peertube@localhost:9002', 1, 0)
await expectAccountFollows(servers[0].url, 'peertube@localhost:9003', 1, 0)
// Server 2 and 3 does not know server 1 follow another server (there was not a refresh)
await expectAccountFollows(servers[1].url, 'peertube@localhost:9001', 0, 1)
await expectAccountFollows(servers[1].url, 'peertube@localhost:9002', 1, 0)
await expectAccountFollows(servers[2].url, 'peertube@localhost:9001', 0, 1)
await expectAccountFollows(servers[2].url, 'peertube@localhost:9003', 1, 0)
})
it('Should unfollow server 3 on server 1', async function () { it('Should unfollow server 3 on server 1', async function () {
this.timeout(5000) this.timeout(5000)
@ -144,6 +158,17 @@ describe('Test follows', function () {
expect(follows.length).to.equal(0) expect(follows.length).to.equal(0)
}) })
it('Should have the correct following counts 2', async function () {
await expectAccountFollows(servers[0].url, 'peertube@localhost:9001', 0, 1)
await expectAccountFollows(servers[0].url, 'peertube@localhost:9002', 1, 0)
await expectAccountFollows(servers[1].url, 'peertube@localhost:9001', 0, 1)
await expectAccountFollows(servers[1].url, 'peertube@localhost:9002', 1, 0)
await expectAccountFollows(servers[2].url, 'peertube@localhost:9001', 0, 0)
await expectAccountFollows(servers[2].url, 'peertube@localhost:9003', 0, 0)
})
it('Should upload a video on server 2 ans 3 and propagate only the video of server 2', async function () { it('Should upload a video on server 2 ans 3 and propagate only the video of server 2', async function () {
this.timeout(10000) this.timeout(10000)
@ -223,6 +248,18 @@ describe('Test follows', function () {
await wait(7000) await wait(7000)
}) })
it('Should have the correct following counts 2', async function () {
await expectAccountFollows(servers[0].url, 'peertube@localhost:9001', 0, 2)
await expectAccountFollows(servers[0].url, 'peertube@localhost:9002', 1, 0)
await expectAccountFollows(servers[0].url, 'peertube@localhost:9003', 1, 0)
await expectAccountFollows(servers[1].url, 'peertube@localhost:9001', 0, 1)
await expectAccountFollows(servers[1].url, 'peertube@localhost:9002', 1, 0)
await expectAccountFollows(servers[2].url, 'peertube@localhost:9001', 0, 1)
await expectAccountFollows(servers[2].url, 'peertube@localhost:9003', 1, 0)
})
it('Should propagate videos', async function () { it('Should propagate videos', async function () {
const res = await getVideosList(servers[ 0 ].url) const res = await getVideosList(servers[ 0 ].url)
expect(res.body.total).to.equal(7) expect(res.body.total).to.equal(7)

View File

@ -1,3 +1,5 @@
import { expect } from 'chai'
import { Account } from '../../../../shared/models/actors'
import { makeGetRequest } from '../requests/requests' import { makeGetRequest } from '../requests/requests'
function getAccountsList (url: string, sort = '-createdAt', statusCodeExpected = 200) { function getAccountsList (url: string, sort = '-createdAt', statusCodeExpected = 200) {
@ -21,9 +23,19 @@ function getAccount (url: string, accountId: number | string, statusCodeExpected
}) })
} }
async function expectAccountFollows (url: string, nameWithDomain: string, followersCount: number, followingCount: number) {
const res = await getAccountsList(url)
const account = res.body.data.find((a: Account) => a.name + '@' + a.host === nameWithDomain)
const message = `${nameWithDomain} on ${url}`
expect(account.followersCount).to.equal(followersCount, message)
expect(account.followingCount).to.equal(followingCount, message)
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
export { export {
getAccount, getAccount,
expectAccountFollows,
getAccountsList getAccountsList
} }