]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/commitdiff
Fix remote actor creation date
authorChocobozzz <me@florianbigard.com>
Fri, 7 May 2021 06:59:59 +0000 (08:59 +0200)
committerChocobozzz <me@florianbigard.com>
Fri, 7 May 2021 07:00:09 +0000 (09:00 +0200)
server/helpers/custom-validators/activitypub/actor.ts
server/initializers/constants.ts
server/initializers/migrations/0645-actor-remote-creation-date.ts [new file with mode: 0644]
server/lib/activitypub/actor.ts
server/models/account/account.ts
server/models/activitypub/actor.ts
server/models/video/video-channel.ts
server/tests/api/users/users-multiple-servers.ts
server/types/models/account/actor.ts
shared/models/activitypub/activitypub-actor.ts

index 87734515750ba812b9d8dcab552ef0d95f60d4d4..675a7b66324e2d40781dde86faaf126768b76cf2 100644 (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,
index d390fd95e9a9b3c1f6722ec802dcbf63b1b10619..f807a1e585bc08f4e85a83f373773b0f1ec972aa 100644 (file)
@@ -24,7 +24,7 @@ import { CONFIG, registerConfigChangedHandler } from './config'
 
 // ---------------------------------------------------------------------------
 
-const LAST_MIGRATION_VERSION = 640
+const LAST_MIGRATION_VERSION = 645
 
 // ---------------------------------------------------------------------------
 
diff --git a/server/initializers/migrations/0645-actor-remote-creation-date.ts b/server/initializers/migrations/0645-actor-remote-creation-date.ts
new file mode 100644 (file)
index 0000000..38b3b88
--- /dev/null
@@ -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
+}
index eec951d4ea6478dc3c372156bfb98ea1f3e25ac8..34d53bd52e4055aaf6064a9a18a1ca6eb88eb7be 100644 (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
   }
index 312451abeb1d6e48ce03b2f9796f450d15e911df..44be0fd3ca1930cffb9390b5b79967afc87b136c 100644 (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
     }
 
index 19f3f7e04ef67279d33e5b66fb78284552302eb6..396a52337e5f27b5fbfdca8ada076dfc2138110c 100644 (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
+  }
 }
index b7ffbd3b136f5bde0f2f55be3aec2e99f2e4dcd2..b627595c9347628bd1e6893d1fd042a97fe128df 100644 (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
index dcd03879b8832738ebbb8c28df41fa35309c7306..f60c66e4bd26ec01d8b0d03b8415bf923cbdbabb 100644 (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, resList.name + '@' + resList.host)
+      const account = resAccount.body as Account
+
+      if (!createdAt) createdAt = account.createdAt
 
-      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')
+      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')
     }
   })
 
index 8f3f30074ef3026d1b3631ab188b4806fa2aed4a..0b620872eb27cb391e545f12d354fff6bf5a46ca 100644 (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>
 
index c59be3f3b322ef6e3a8c5aaaf1987c5610dc1153..09d4f7402ef2194b403a79320f2c55c035368b10 100644 (file)
@@ -29,4 +29,6 @@ export interface ActivityPubActor {
 
   icon?: ActivityIconObject
   image?: ActivityIconObject
+
+  published?: string
 }