Fix remote actor creation date

This commit is contained in:
Chocobozzz 2021-05-07 08:59:59 +02:00
parent 64df4b65ae
commit a66c2e3252
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
10 changed files with 80 additions and 42 deletions

View File

@ -1,6 +1,6 @@
import validator from 'validator'
import { CONSTRAINTS_FIELDS } from '../../../initializers/constants'
import { exists, isArray } from '../misc'
import { exists, isArray, isDateValid } from '../misc'
import { isActivityPubUrlValid, isBaseActivityValid, setValidAttributedTo } from './misc'
import { isHostValid } from '../servers'
import { peertubeTruncate } from '@server/helpers/core-utils'
@ -47,7 +47,21 @@ function isActorPrivateKeyValid (privateKey: string) {
validator.isLength(privateKey, CONSTRAINTS_FIELDS.ACTORS.PRIVATE_KEY)
}
function isActorObjectValid (actor: any) {
function isActorFollowingCountValid (value: string) {
return exists(value) && validator.isInt('' + value, { min: 0 })
}
function isActorFollowersCountValid (value: string) {
return exists(value) && validator.isInt('' + value, { min: 0 })
}
function isActorDeleteActivityValid (activity: any) {
return isBaseActivityValid(activity, 'Delete')
}
function sanitizeAndCheckActorObject (actor: any) {
normalizeActor(actor)
return exists(actor) &&
isActivityPubUrlValid(actor.id) &&
isActorTypeValid(actor.type) &&
@ -68,24 +82,6 @@ function isActorObjectValid (actor: any) {
(actor.type !== 'Group' || actor.attributedTo.length !== 0)
}
function isActorFollowingCountValid (value: string) {
return exists(value) && validator.isInt('' + value, { min: 0 })
}
function isActorFollowersCountValid (value: string) {
return exists(value) && validator.isInt('' + value, { min: 0 })
}
function isActorDeleteActivityValid (activity: any) {
return isBaseActivityValid(activity, 'Delete')
}
function sanitizeAndCheckActorObject (object: any) {
normalizeActor(object)
return isActorObjectValid(object)
}
function normalizeActor (actor: any) {
if (!actor) return
@ -95,6 +91,8 @@ function normalizeActor (actor: any) {
actor.url = actor.url.href || actor.url.url
}
if (!isDateValid(actor.published)) actor.published = undefined
if (actor.summary && typeof actor.summary === 'string') {
actor.summary = peertubeTruncate(actor.summary, { length: CONSTRAINTS_FIELDS.USERS.DESCRIPTION.max })
@ -135,7 +133,6 @@ export {
isActorPublicKeyValid,
isActorPreferredUsernameValid,
isActorPrivateKeyValid,
isActorObjectValid,
isActorFollowingCountValid,
isActorFollowersCountValid,
isActorDeleteActivityValid,

View File

@ -24,7 +24,7 @@ import { CONFIG, registerConfigChangedHandler } from './config'
// ---------------------------------------------------------------------------
const LAST_MIGRATION_VERSION = 640
const LAST_MIGRATION_VERSION = 645
// ---------------------------------------------------------------------------

View File

@ -0,0 +1,26 @@
import * as Sequelize from 'sequelize'
async function up (utils: {
transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
{
const data = {
type: Sequelize.DATE,
defaultValue: null,
allowNull: true
}
await utils.queryInterface.addColumn('actor', 'remoteCreatedAt', data)
}
}
function down (options) {
throw new Error('Not implemented.')
}
export {
up,
down
}

View File

@ -154,6 +154,8 @@ async function updateActorInstance (actorInstance: ActorModel, attributes: Activ
const followersCount = await fetchActorTotalItems(attributes.followers)
const followingCount = await fetchActorTotalItems(attributes.following)
logger.info('coucou', { attributes })
actorInstance.type = attributes.type
actorInstance.preferredUsername = attributes.preferredUsername
actorInstance.url = attributes.id
@ -165,6 +167,8 @@ async function updateActorInstance (actorInstance: ActorModel, attributes: Activ
actorInstance.followersUrl = attributes.followers
actorInstance.followingUrl = attributes.following
if (attributes.published) actorInstance.remoteCreatedAt = new Date(attributes.published)
if (attributes.endpoints?.sharedInbox) {
actorInstance.sharedInboxUrl = attributes.endpoints.sharedInbox
}

View File

@ -411,8 +411,6 @@ export class AccountModel extends Model {
id: this.id,
displayName: this.getDisplayName(),
description: this.description,
createdAt: this.createdAt,
updatedAt: this.updatedAt,
userId: this.userId ? this.userId : undefined
}

View File

@ -69,9 +69,7 @@ export const unusedActorAttributesForAPI = [
'outboxUrl',
'sharedInboxUrl',
'followersUrl',
'followingUrl',
'createdAt',
'updatedAt'
'followingUrl'
]
@DefaultScope(() => ({
@ -222,6 +220,10 @@ export class ActorModel extends Model {
@Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTORS.URL.max))
followingUrl: string
@AllowNull(true)
@Column
remoteCreatedAt: Date
@CreatedAt
createdAt: Date
@ -555,7 +557,7 @@ export class ActorModel extends Model {
followingCount: this.followingCount,
followersCount: this.followersCount,
banner,
createdAt: this.createdAt,
createdAt: this.getCreatedAt(),
updatedAt: this.updatedAt
})
}
@ -608,6 +610,7 @@ export class ActorModel extends Model {
owner: this.url,
publicKeyPem: this.publicKey
},
published: this.getCreatedAt().toISOString(),
icon,
image
}
@ -690,4 +693,8 @@ export class ActorModel extends Model {
return isOutdated(this, ACTIVITY_PUB.ACTOR_REFRESH_INTERVAL)
}
getCreatedAt (this: MActorAPChannel | MActorAPAccount | MActorFormattable) {
return this.remoteCreatedAt || this.createdAt
}
}

View File

@ -653,8 +653,6 @@ ON "Account->Actor"."serverId" = "Account->Actor->Server"."id"`
description: this.description,
support: this.support,
isLocal: this.Actor.isOwned(),
createdAt: this.createdAt,
updatedAt: this.updatedAt,
ownerAccount: undefined,
videosCount,
viewsPerDay

View File

@ -130,26 +130,32 @@ describe('Test users with multiple servers', function () {
})
it('Should have updated my profile on other servers too', async function () {
let createdAt: string | Date
for (const server of servers) {
const resAccounts = await getAccountsList(server.url, '-createdAt')
const rootServer1List = resAccounts.body.data.find(a => a.name === 'root' && a.host === 'localhost:' + servers[0].port) as Account
expect(rootServer1List).not.to.be.undefined
const resList = resAccounts.body.data.find(a => a.name === 'root' && a.host === 'localhost:' + servers[0].port) as Account
expect(resList).not.to.be.undefined
const resAccount = await getAccount(server.url, rootServer1List.name + '@' + rootServer1List.host)
const rootServer1Get = resAccount.body as Account
expect(rootServer1Get.name).to.equal('root')
expect(rootServer1Get.host).to.equal('localhost:' + servers[0].port)
expect(rootServer1Get.displayName).to.equal('my super display name')
expect(rootServer1Get.description).to.equal('my super description updated')
const resAccount = await getAccount(server.url, resList.name + '@' + resList.host)
const account = resAccount.body as Account
if (!createdAt) createdAt = account.createdAt
expect(account.name).to.equal('root')
expect(account.host).to.equal('localhost:' + servers[0].port)
expect(account.displayName).to.equal('my super display name')
expect(account.description).to.equal('my super description updated')
expect(createdAt).to.equal(account.createdAt)
if (server.serverNumber === 1) {
expect(rootServer1Get.userId).to.be.a('number')
expect(account.userId).to.be.a('number')
} else {
expect(rootServer1Get.userId).to.be.undefined
expect(account.userId).to.be.undefined
}
await testImage(server.url, 'avatar2-resized', rootServer1Get.avatar.path, '.png')
await testImage(server.url, 'avatar2-resized', account.avatar.path, '.png')
}
})

View File

@ -150,7 +150,7 @@ export type MActorSummaryFormattable =
export type MActorFormattable =
MActorSummaryFormattable &
Pick<MActor, 'id' | 'followingCount' | 'followersCount' | 'createdAt' | 'updatedAt' | 'bannerId' | 'avatarId'> &
Pick<MActor, 'id' | 'followingCount' | 'followersCount' | 'createdAt' | 'updatedAt' | 'remoteCreatedAt' | 'bannerId' | 'avatarId'> &
Use<'Server', MServerHost & Partial<Pick<MServer, 'redundancyAllowed'>>> &
UseOpt<'Banner', MActorImageFormattable>

View File

@ -29,4 +29,6 @@ export interface ActivityPubActor {
icon?: ActivityIconObject
image?: ActivityIconObject
published?: string
}