diff --git a/packages/backend/migration/1758129782800-add-user-lastFetchedFeaturedAt.js b/packages/backend/migration/1758129782800-add-user-lastFetchedFeaturedAt.js new file mode 100644 index 0000000000..fc3713cec9 --- /dev/null +++ b/packages/backend/migration/1758129782800-add-user-lastFetchedFeaturedAt.js @@ -0,0 +1,14 @@ +/* + * SPDX-FileCopyrightText: hazelnoot and other Sharkey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class AddUserLastFetchedFeaturedAt1758129782800 { + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "user" ADD "lastFetchedFeaturedAt" DATE`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "lastFetchedFeaturedAt"`); + } +} diff --git a/packages/backend/src/core/ReversiService.ts b/packages/backend/src/core/ReversiService.ts index 2edba73677..388ebf61e2 100644 --- a/packages/backend/src/core/ReversiService.ts +++ b/packages/backend/src/core/ReversiService.ts @@ -587,6 +587,7 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit { updatedAt: parsed.user1.updatedAt != null ? new Date(parsed.user1.updatedAt) : null, lastActiveDate: parsed.user1.lastActiveDate != null ? new Date(parsed.user1.lastActiveDate) : null, lastFetchedAt: parsed.user1.lastFetchedAt != null ? new Date(parsed.user1.lastFetchedAt) : null, + lastFetchedFeaturedAt: parsed.user1.lastFetchedFeaturedAt != null ? new Date(parsed.user1.lastFetchedFeaturedAt) : null, movedAt: parsed.user1.movedAt != null ? new Date(parsed.user1.movedAt) : null, instance: null, userProfile: null, @@ -599,6 +600,7 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit { updatedAt: parsed.user2.updatedAt != null ? new Date(parsed.user2.updatedAt) : null, lastActiveDate: parsed.user2.lastActiveDate != null ? new Date(parsed.user2.lastActiveDate) : null, lastFetchedAt: parsed.user2.lastFetchedAt != null ? new Date(parsed.user2.lastFetchedAt) : null, + lastFetchedFeaturedAt: parsed.user2.lastFetchedFeaturedAt != null ? new Date(parsed.user2.lastFetchedFeaturedAt) : null, movedAt: parsed.user2.movedAt != null ? new Date(parsed.user2.movedAt) : null, instance: null, userProfile: null, diff --git a/packages/backend/src/core/activitypub/models/ApPersonService.ts b/packages/backend/src/core/activitypub/models/ApPersonService.ts index f28f4cdd8d..66311d4655 100644 --- a/packages/backend/src/core/activitypub/models/ApPersonService.ts +++ b/packages/backend/src/core/activitypub/models/ApPersonService.ts @@ -701,13 +701,16 @@ export class ApPersonService implements OnModuleInit { const profileUrls = url ? [url, person.id] : [person.id]; const verifiedLinks = await verifyFieldLinks(fields, profileUrls, this.httpRequestService); + const featuredUri = person.featured ? getApId(person.featured) : undefined; const updates = { lastFetchedAt: this.timeService.date, inbox: person.inbox, sharedInbox: person.sharedInbox ?? person.endpoints?.sharedInbox ?? null, followersUri: person.followers ? getApId(person.followers) : undefined, - featured: person.featured ? getApId(person.featured) : undefined, + // If the featured collection changes, then reset the fetch timeout. + lastFetchedFeaturedAt: featuredUri !== exist.featured ? null : undefined, + featured: featuredUri, emojis: emojiNames, name: truncate(person.name, nameLength), tags, @@ -948,6 +951,10 @@ export class ApPersonService implements OnModuleInit { resolver ??= this.apResolverService.createResolver(); + // Mark as updated + await this.usersRepository.update({ id: userId }, { lastFetchedFeaturedAt: new Date() }); + await this.internalEventService.emit('remoteUserUpdated', { id: userId }); + // Resolve and regist Notes const maxPinned = (await this.roleService.getUserPolicies(user.id)).pinLimit; const items = await resolver.resolveCollectionItems(user.featured, true, user.uri, maxPinned, 2); diff --git a/packages/backend/src/models/User.ts b/packages/backend/src/models/User.ts index b2b13e1724..10c142c53b 100644 --- a/packages/backend/src/models/User.ts +++ b/packages/backend/src/models/User.ts @@ -28,6 +28,11 @@ export class MiUser { }) public lastFetchedAt: Date | null; + @Column('timestamp with time zone', { + nullable: true, + }) + public lastFetchedFeaturedAt?: Date | null; + @Index() @Column('timestamp with time zone', { nullable: true, diff --git a/packages/backend/src/queue/processors/BackgroundTaskProcessorService.ts b/packages/backend/src/queue/processors/BackgroundTaskProcessorService.ts index eb7ebbe9a4..3d10996baf 100644 --- a/packages/backend/src/queue/processors/BackgroundTaskProcessorService.ts +++ b/packages/backend/src/queue/processors/BackgroundTaskProcessorService.ts @@ -129,7 +129,7 @@ export class BackgroundTaskProcessorService { if (!isRemoteUser(user)) return `Skipping update-featured task: user ${task.userId} is local`; if (!user.featured) return `Skipping update-featured task: user ${task.userId} has no featured collection`; - if (user.lastFetchedAt && Date.now() - user.lastFetchedAt.getTime() < 1000 * 60 * 60 * 24) { + if (user.lastFetchedFeaturedAt && Date.now() - user.lastFetchedFeaturedAt.getTime() < 1000 * 60 * 60 * 24) { return `Skipping update-featured task: user ${task.userId} was recently updated`; }