summaryrefslogtreecommitdiff
path: root/packages/backend/src/core/NoteCreateService.ts
diff options
context:
space:
mode:
authorJulia <julia@insertdomain.name>2025-05-29 00:07:38 +0000
committerJulia <julia@insertdomain.name>2025-05-29 00:07:38 +0000
commit6b554c178b81f13f83a69b19d44b72b282a0c119 (patch)
treef5537f1a56323a4dd57ba150b3cb84a2d8b5dc63 /packages/backend/src/core/NoteCreateService.ts
parentmerge: Security fixes (!970) (diff)
parentbump version for release (diff)
downloadsharkey-6b554c178b81f13f83a69b19d44b72b282a0c119.tar.gz
sharkey-6b554c178b81f13f83a69b19d44b72b282a0c119.tar.bz2
sharkey-6b554c178b81f13f83a69b19d44b72b282a0c119.zip
merge: release 2025.4.2 (!1051)
View MR for information: https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/1051 Approved-by: Hazelnoot <acomputerdog@gmail.com> Approved-by: Marie <github@yuugi.dev> Approved-by: Julia <julia@insertdomain.name>
Diffstat (limited to 'packages/backend/src/core/NoteCreateService.ts')
-rw-r--r--packages/backend/src/core/NoteCreateService.ts117
1 files changed, 45 insertions, 72 deletions
diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts
index df31cb4247..097d657ba3 100644
--- a/packages/backend/src/core/NoteCreateService.ts
+++ b/packages/backend/src/core/NoteCreateService.ts
@@ -42,7 +42,6 @@ import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
import { ApDeliverManagerService } from '@/core/activitypub/ApDeliverManagerService.js';
-import { NoteReadService } from '@/core/NoteReadService.js';
import { RemoteUserResolveService } from '@/core/RemoteUserResolveService.js';
import { bindThis } from '@/decorators.js';
import { RoleService } from '@/core/RoleService.js';
@@ -52,7 +51,7 @@ import { FanoutTimelineService } from '@/core/FanoutTimelineService.js';
import { UtilityService } from '@/core/UtilityService.js';
import { UserBlockingService } from '@/core/UserBlockingService.js';
import { isReply } from '@/misc/is-reply.js';
-import { trackPromise } from '@/misc/promise-tracker.js';
+import { trackTask } from '@/misc/promise-tracker.js';
import { isUserRelated } from '@/misc/is-user-related.js';
import { IdentifiableError } from '@/misc/identifiable-error.js';
import { LatestNoteService } from '@/core/LatestNoteService.js';
@@ -203,7 +202,6 @@ export class NoteCreateService implements OnApplicationShutdown {
private globalEventService: GlobalEventService,
private queueService: QueueService,
private fanoutTimelineService: FanoutTimelineService,
- private noteReadService: NoteReadService,
private notificationService: NotificationService,
private relayService: RelayService,
private federatedInstanceService: FederatedInstanceService,
@@ -541,7 +539,8 @@ export class NoteCreateService implements OnApplicationShutdown {
await this.notesRepository.insert(insert);
}
- return insert;
+ // Re-fetch note to get the default values of null / unset fields.
+ return await this.notesRepository.findOneByOrFail({ id: insert.id });
} catch (e) {
// duplicate key error
if (isDuplicateKeyValueError(e)) {
@@ -573,7 +572,7 @@ export class NoteCreateService implements OnApplicationShutdown {
if (this.meta.enableStatsForFederatedInstances) {
if (this.userEntityService.isRemoteUser(user)) {
this.federatedInstanceService.fetchOrRegister(user.host).then(async i => {
- if (note.renote && note.text || !note.renote) {
+ if (!this.isRenote(note) || this.isQuote(note)) {
this.updateNotesCountQueue.enqueue(i.id, 1);
}
if (this.meta.enableChartsForFederatedInstances) {
@@ -585,24 +584,24 @@ export class NoteCreateService implements OnApplicationShutdown {
// ハッシュタグ更新
if (data.visibility === 'public' || data.visibility === 'home') {
- if (user.isBot && this.meta.enableBotTrending) {
- this.hashtagService.updateHashtags(user, tags);
- } else if (!user.isBot) {
+ if (!user.isBot || this.meta.enableBotTrending) {
this.hashtagService.updateHashtags(user, tags);
}
}
- if (data.renote && data.text) {
- // Increment notes count (user)
- this.incNotesCountOfUser(user);
- } else if (!data.renote) {
+ if (!this.isRenote(note) || this.isQuote(note)) {
// Increment notes count (user)
this.incNotesCountOfUser(user);
+ } else {
+ this.usersRepository.update({ id: user.id }, { updatedAt: new Date() });
}
this.pushToTl(note, user);
- this.antennaService.addNoteToAntennas(note, user);
+ this.antennaService.addNoteToAntennas({
+ ...note,
+ channel: data.channel ?? null,
+ }, user);
if (data.reply) {
this.saveReply(data.reply, note);
@@ -633,8 +632,8 @@ export class NoteCreateService implements OnApplicationShutdown {
});
}
- if (data.renote && data.text == null && data.renote.userId !== user.id && !user.isBot) {
- this.incRenoteCount(data.renote);
+ if (this.isRenote(data) && !this.isQuote(data) && data.renote.userId !== user.id && !user.isBot) {
+ this.incRenoteCount(data.renote, user);
}
if (data.poll && data.poll.expiresAt) {
@@ -644,38 +643,20 @@ export class NoteCreateService implements OnApplicationShutdown {
}, {
jobId: `pollEnd:${note.id}`,
delay,
- removeOnComplete: true,
+ removeOnComplete: {
+ age: 3600 * 24 * 7, // keep up to 7 days
+ count: 30,
+ },
+ removeOnFail: {
+ age: 3600 * 24 * 7, // keep up to 7 days
+ count: 100,
+ },
});
}
if (!silent) {
if (this.userEntityService.isLocalUser(user)) this.activeUsersChart.write(user);
- // 未読通知を作成
- if (data.visibility === 'specified') {
- if (data.visibleUsers == null) throw new Error('invalid param');
-
- for (const u of data.visibleUsers) {
- // ローカルユーザーのみ
- if (!this.userEntityService.isLocalUser(u)) continue;
-
- this.noteReadService.insertNoteUnread(u.id, note, {
- isSpecified: true,
- isMentioned: false,
- });
- }
- } else {
- for (const u of mentionedUsers) {
- // ローカルユーザーのみ
- if (!this.userEntityService.isLocalUser(u)) continue;
-
- this.noteReadService.insertNoteUnread(u.id, note, {
- isSpecified: false,
- isMentioned: true,
- });
- }
- }
-
// Pack the note
const noteObj = await this.noteEntityService.pack(note, null, { skipHide: true, withReactionAndUserPairCache: true });
@@ -733,13 +714,7 @@ export class NoteCreateService implements OnApplicationShutdown {
},
});
- const [
- userIdsWhoMeMuting,
- ] = data.renote.userId ? await Promise.all([
- this.cacheService.userMutingsCache.fetch(data.renote.userId),
- ]) : [new Set<string>()];
-
- const muted = isUserRelated(note, userIdsWhoMeMuting);
+ const muted = data.renote.userId && isUserRelated(note, await this.cacheService.userMutingsCache.fetch(data.renote.userId));
if (!isThreadMuted && !muted) {
nm.push(data.renote.userId, type);
@@ -757,7 +732,7 @@ export class NoteCreateService implements OnApplicationShutdown {
//#region AP deliver
if (!data.localOnly && this.userEntityService.isLocalUser(user)) {
- (async () => {
+ trackTask(async () => {
const noteActivity = await this.renderNoteOrRenoteActivity(data, note, user);
const dm = this.apDeliverManagerService.createDeliverManager(user, noteActivity);
@@ -783,12 +758,12 @@ export class NoteCreateService implements OnApplicationShutdown {
dm.addFollowersRecipe();
}
+ await dm.execute();
+
if (['public'].includes(note.visibility)) {
- this.relayService.deliverToRelays(user, noteActivity);
+ await this.relayService.deliverToRelays(user, noteActivity);
}
-
- trackPromise(dm.execute());
- })();
+ });
}
//#endregion
}
@@ -841,8 +816,8 @@ export class NoteCreateService implements OnApplicationShutdown {
}
@bindThis
- private incRenoteCount(renote: MiNote) {
- this.notesRepository.createQueryBuilder().update()
+ private async incRenoteCount(renote: MiNote, user: MiUser) {
+ await this.notesRepository.createQueryBuilder().update()
.set({
renoteCount: () => '"renoteCount" + 1',
})
@@ -850,15 +825,18 @@ export class NoteCreateService implements OnApplicationShutdown {
.execute();
// 30%の確率、3日以内に投稿されたノートの場合ハイライト用ランキング更新
- if (Math.random() < 0.3 && (Date.now() - this.idService.parse(renote.id).date.getTime()) < 1000 * 60 * 60 * 24 * 3) {
- if (renote.channelId != null) {
- if (renote.replyId == null) {
- this.featuredService.updateInChannelNotesRanking(renote.channelId, renote.id, 5);
- }
- } else {
- if (renote.visibility === 'public' && renote.userHost == null && renote.replyId == null) {
- this.featuredService.updateGlobalNotesRanking(renote.id, 5);
- this.featuredService.updatePerUserNotesRanking(renote.userId, renote.id, 5);
+ if (user.isExplorable && Math.random() < 0.3 && (Date.now() - this.idService.parse(renote.id).date.getTime()) < 1000 * 60 * 60 * 24 * 3) {
+ const policies = await this.roleService.getUserPolicies(user);
+ if (policies.canTrend) {
+ if (renote.channelId != null) {
+ if (renote.replyId == null) {
+ this.featuredService.updateInChannelNotesRanking(renote.channelId, renote, 5);
+ }
+ } else {
+ if (renote.visibility === 'public' && renote.userHost == null && renote.replyId == null) {
+ this.featuredService.updateGlobalNotesRanking(renote, 5);
+ this.featuredService.updatePerUserNotesRanking(renote.userId, renote, 5);
+ }
}
}
}
@@ -866,7 +844,8 @@ export class NoteCreateService implements OnApplicationShutdown {
@bindThis
private async createMentionedEvents(mentionedUsers: MinimumUser[], note: MiNote, nm: NotificationManager) {
- for (const u of mentionedUsers.filter(u => this.userEntityService.isLocalUser(u))) {
+ // Only create mention events for local users, and users for whom the note is visible
+ for (const u of mentionedUsers.filter(u => (note.visibility !== 'specified' || note.visibleUserIds.some(x => x === u.id)) && this.userEntityService.isLocalUser(u))) {
const isThreadMuted = await this.noteThreadMutingsRepository.exists({
where: {
userId: u.id,
@@ -874,13 +853,7 @@ export class NoteCreateService implements OnApplicationShutdown {
},
});
- const [
- userIdsWhoMeMuting,
- ] = u.id ? await Promise.all([
- this.cacheService.userMutingsCache.fetch(u.id),
- ]) : [new Set<string>()];
-
- const muted = isUserRelated(note, userIdsWhoMeMuting);
+ const muted = u.id && isUserRelated(note, await this.cacheService.userMutingsCache.fetch(u.id));
if (isThreadMuted || muted) {
continue;