diff options
| author | syuilo <Syuilotan@yahoo.co.jp> | 2021-03-24 11:34:29 +0900 |
|---|---|---|
| committer | syuilo <Syuilotan@yahoo.co.jp> | 2021-03-24 11:34:29 +0900 |
| commit | 3e11011229ef8459747acdf6d3008dc145280fec (patch) | |
| tree | 8ebc85727c4d295f6583b63d9397651151d4394a /src/services/note | |
| parent | Merge branch 'develop' (diff) | |
| parent | 12.75.1 (diff) | |
| download | misskey-3e11011229ef8459747acdf6d3008dc145280fec.tar.gz misskey-3e11011229ef8459747acdf6d3008dc145280fec.tar.bz2 misskey-3e11011229ef8459747acdf6d3008dc145280fec.zip | |
Merge branch 'develop'
Diffstat (limited to 'src/services/note')
| -rw-r--r-- | src/services/note/create.ts | 62 | ||||
| -rw-r--r-- | src/services/note/delete.ts | 4 | ||||
| -rw-r--r-- | src/services/note/polls/vote.ts | 2 | ||||
| -rw-r--r-- | src/services/note/reaction/create.ts | 8 | ||||
| -rw-r--r-- | src/services/note/reaction/delete.ts | 6 | ||||
| -rw-r--r-- | src/services/note/read.ts | 92 | ||||
| -rw-r--r-- | src/services/note/unread.ts | 2 | ||||
| -rw-r--r-- | src/services/note/watch.ts | 2 |
8 files changed, 106 insertions, 72 deletions
diff --git a/src/services/note/create.ts b/src/services/note/create.ts index 4a737e8516..64d5513ecc 100644 --- a/src/services/note/create.ts +++ b/src/services/note/create.ts @@ -7,44 +7,45 @@ import renderAnnounce from '../../remote/activitypub/renderer/announce'; import { renderActivity } from '../../remote/activitypub/renderer'; import { parse } from '../../mfm/parse'; import { resolveUser } from '../../remote/resolve-user'; -import config from '../../config'; +import config from '@/config'; import { updateHashtags } from '../update-hashtag'; import { concat } from '../../prelude/array'; import insertNoteUnread from './unread'; import { registerOrFetchInstanceDoc } from '../register-or-fetch-instance-doc'; -import extractMentions from '../../misc/extract-mentions'; -import extractEmojis from '../../misc/extract-emojis'; -import extractHashtags from '../../misc/extract-hashtags'; +import extractMentions from '@/misc/extract-mentions'; +import extractEmojis from '@/misc/extract-emojis'; +import extractHashtags from '@/misc/extract-hashtags'; import { Note, IMentionedRemoteUsers } from '../../models/entities/note'; import { Mutings, Users, NoteWatchings, Notes, Instances, UserProfiles, Antennas, Followings, MutedNotes, Channels, ChannelFollowings } from '../../models'; import { DriveFile } from '../../models/entities/drive-file'; import { App } from '../../models/entities/app'; import { Not, getConnection, In } from 'typeorm'; import { User, ILocalUser, IRemoteUser } from '../../models/entities/user'; -import { genId } from '../../misc/gen-id'; +import { genId } from '@/misc/gen-id'; import { notesChart, perUserNotesChart, activeUsersChart, instanceChart } from '../chart'; import { Poll, IPoll } from '../../models/entities/poll'; import { createNotification } from '../create-notification'; -import { isDuplicateKeyValueError } from '../../misc/is-duplicate-key-value-error'; -import { checkHitAntenna } from '../../misc/check-hit-antenna'; -import { checkWordMute } from '../../misc/check-word-mute'; +import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error'; +import { checkHitAntenna } from '@/misc/check-hit-antenna'; +import { checkWordMute } from '@/misc/check-word-mute'; import { addNoteToAntenna } from '../add-note-to-antenna'; -import { countSameRenotes } from '../../misc/count-same-renotes'; +import { countSameRenotes } from '@/misc/count-same-renotes'; import { deliverToRelays } from '../relay'; import { Channel } from '../../models/entities/channel'; -import { normalizeForSearch } from '../../misc/normalize-for-search'; +import { normalizeForSearch } from '@/misc/normalize-for-search'; +import { getAntennas } from '@/misc/antenna-cache'; type NotificationType = 'reply' | 'renote' | 'quote' | 'mention'; class NotificationManager { - private notifier: User; + private notifier: { id: User['id']; }; private note: Note; private queue: { target: ILocalUser['id']; reason: NotificationType; }[]; - constructor(notifier: User, note: Note) { + constructor(notifier: { id: User['id']; }, note: Note) { this.notifier = notifier; this.note = note; this.queue = []; @@ -111,7 +112,7 @@ type Option = { app?: App | null; }; -export default async (user: User, data: Option, silent = false) => new Promise<Note>(async (res, rej) => { +export default async (user: { id: User['id']; username: User['username']; host: User['host']; isSilenced: User['isSilenced']; }, data: Option, silent = false) => new Promise<Note>(async (res, rej) => { // チャンネル外にリプライしたら対象のスコープに合わせる // (クライアントサイドでやっても良い処理だと思うけどとりあえずサーバーサイドで) if (data.reply && data.channel && data.reply.channelId !== data.channel.id) { @@ -241,6 +242,7 @@ export default async (user: User, data: Option, silent = false) => new Promise<N incNotesCountOfUser(user); // Word mute + // TODO: cache UserProfiles.find({ enableWordMute: true }).then(us => { @@ -262,17 +264,15 @@ export default async (user: User, data: Option, silent = false) => new Promise<N Followings.createQueryBuilder('following') .andWhere(`following.followeeId = :userId`, { userId: note.userId }) .getMany() - .then(followings => { + .then(async followings => { const followers = followings.map(f => f.followerId); - Antennas.find().then(async antennas => { - for (const antenna of antennas) { - checkHitAntenna(antenna, note, user, followers).then(hit => { - if (hit) { - addNoteToAntenna(antenna, note, user); - } - }); - } - }); + for (const antenna of (await getAntennas())) { + checkHitAntenna(antenna, note, user, followers).then(hit => { + if (hit) { + addNoteToAntenna(antenna, note, user); + } + }); + } }); // Channel @@ -328,10 +328,6 @@ export default async (user: User, data: Option, silent = false) => new Promise<N // Pack the note const noteObj = await Notes.pack(note); - if (user.notesCount === 0) { - (noteObj as any).isFirstNote = true; - } - publishNotesStream(noteObj); const nm = new NotificationManager(user, note); @@ -424,7 +420,7 @@ export default async (user: User, data: Option, silent = false) => new Promise<N // この処理が行われるのはノート作成後なので、ノートが一つしかなかったら最初の投稿だと判断できる // TODO: とはいえノートを削除して何回も投稿すればその分だけインクリメントされる雑さもあるのでどうにかしたい if (count === 1) { - Channels.increment({ id: data.channel.id }, 'usersCount', 1); + Channels.increment({ id: data.channel!.id }, 'usersCount', 1); } }); } @@ -453,7 +449,7 @@ function incRenoteCount(renote: Note) { .execute(); } -async function insertNote(user: User, data: Option, tags: string[], emojis: string[], mentionedUsers: User[]) { +async function insertNote(user: { id: User['id']; host: User['host']; }, data: Option, tags: string[], emojis: string[], mentionedUsers: User[]) { const insert = new Note({ id: genId(data.createdAt!), createdAt: data.createdAt!, @@ -559,7 +555,7 @@ function index(note: Note) { }); } -async function notifyToWatchersOfRenotee(renote: Note, user: User, nm: NotificationManager, type: NotificationType) { +async function notifyToWatchersOfRenotee(renote: Note, user: { id: User['id']; }, nm: NotificationManager, type: NotificationType) { const watchers = await NoteWatchings.find({ noteId: renote.id, userId: Not(user.id) @@ -570,7 +566,7 @@ async function notifyToWatchersOfRenotee(renote: Note, user: User, nm: Notificat } } -async function notifyToWatchersOfReplyee(reply: Note, user: User, nm: NotificationManager) { +async function notifyToWatchersOfReplyee(reply: Note, user: { id: User['id']; }, nm: NotificationManager) { const watchers = await NoteWatchings.find({ noteId: reply.id, userId: Not(user.id) @@ -598,7 +594,7 @@ function saveReply(reply: Note, note: Note) { Notes.increment({ id: reply.id }, 'repliesCount', 1); } -function incNotesCountOfUser(user: User) { +function incNotesCountOfUser(user: { id: User['id']; }) { Users.createQueryBuilder().update() .set({ updatedAt: new Date(), @@ -608,7 +604,7 @@ function incNotesCountOfUser(user: User) { .execute(); } -async function extractMentionedUsers(user: User, tokens: ReturnType<typeof parse>): Promise<User[]> { +async function extractMentionedUsers(user: { host: User['host']; }, tokens: ReturnType<typeof parse>): Promise<User[]> { if (tokens == null) return []; const mentions = extractMentions(tokens); diff --git a/src/services/note/delete.ts b/src/services/note/delete.ts index 5526302602..3f4f8b404c 100644 --- a/src/services/note/delete.ts +++ b/src/services/note/delete.ts @@ -4,14 +4,14 @@ import renderAnnounce from '../../remote/activitypub/renderer/announce'; import renderUndo from '../../remote/activitypub/renderer/undo'; import { renderActivity } from '../../remote/activitypub/renderer'; import renderTombstone from '../../remote/activitypub/renderer/tombstone'; -import config from '../../config'; +import config from '@/config'; import { registerOrFetchInstanceDoc } from '../register-or-fetch-instance-doc'; import { User, ILocalUser, IRemoteUser } from '../../models/entities/user'; import { Note, IMentionedRemoteUsers } from '../../models/entities/note'; import { Notes, Users, Instances } from '../../models'; import { notesChart, perUserNotesChart, instanceChart } from '../chart'; import { deliverToFollowers, deliverToUser } from '../../remote/activitypub/deliver-manager'; -import { countSameRenotes } from '../../misc/count-same-renotes'; +import { countSameRenotes } from '@/misc/count-same-renotes'; import { deliverToRelays } from '../relay'; import { Brackets, In } from 'typeorm'; diff --git a/src/services/note/polls/vote.ts b/src/services/note/polls/vote.ts index b4ce03ab60..aea157e558 100644 --- a/src/services/note/polls/vote.ts +++ b/src/services/note/polls/vote.ts @@ -3,7 +3,7 @@ import { User } from '../../../models/entities/user'; import { Note } from '../../../models/entities/note'; import { PollVotes, NoteWatchings, Polls } from '../../../models'; import { Not } from 'typeorm'; -import { genId } from '../../../misc/gen-id'; +import { genId } from '@/misc/gen-id'; import { createNotification } from '../../create-notification'; export default async function(user: User, note: Note, choice: number) { diff --git a/src/services/note/reaction/create.ts b/src/services/note/reaction/create.ts index 181099cc2d..e2e7fc54ef 100644 --- a/src/services/note/reaction/create.ts +++ b/src/services/note/reaction/create.ts @@ -2,19 +2,19 @@ import { publishNoteStream } from '../../stream'; import { renderLike } from '../../../remote/activitypub/renderer/like'; import DeliverManager from '../../../remote/activitypub/deliver-manager'; import { renderActivity } from '../../../remote/activitypub/renderer'; -import { toDbReaction, decodeReaction } from '../../../misc/reaction-lib'; +import { toDbReaction, decodeReaction } from '@/misc/reaction-lib'; import { User, IRemoteUser } from '../../../models/entities/user'; import { Note } from '../../../models/entities/note'; import { NoteReactions, Users, NoteWatchings, Notes, Emojis } from '../../../models'; import { Not } from 'typeorm'; import { perUserReactionsChart } from '../../chart'; -import { genId } from '../../../misc/gen-id'; +import { genId } from '@/misc/gen-id'; import { createNotification } from '../../create-notification'; import deleteReaction from './delete'; -import { isDuplicateKeyValueError } from '../../../misc/is-duplicate-key-value-error'; +import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error'; import { NoteReaction } from '../../../models/entities/note-reaction'; -export default async (user: User, note: Note, reaction?: string) => { +export default async (user: { id: User['id']; host: User['host']; }, note: Note, reaction?: string) => { // TODO: cache reaction = await toDbReaction(reaction, user.host); diff --git a/src/services/note/reaction/delete.ts b/src/services/note/reaction/delete.ts index 8d2f0682ca..712031fa88 100644 --- a/src/services/note/reaction/delete.ts +++ b/src/services/note/reaction/delete.ts @@ -3,13 +3,13 @@ import { renderLike } from '../../../remote/activitypub/renderer/like'; import renderUndo from '../../../remote/activitypub/renderer/undo'; import { renderActivity } from '../../../remote/activitypub/renderer'; import DeliverManager from '../../../remote/activitypub/deliver-manager'; -import { IdentifiableError } from '../../../misc/identifiable-error'; +import { IdentifiableError } from '@/misc/identifiable-error'; import { User, IRemoteUser } from '../../../models/entities/user'; import { Note } from '../../../models/entities/note'; import { NoteReactions, Users, Notes } from '../../../models'; -import { decodeReaction } from '../../../misc/reaction-lib'; +import { decodeReaction } from '@/misc/reaction-lib'; -export default async (user: User, note: Note) => { +export default async (user: { id: User['id']; host: User['host']; }, note: Note) => { // if already unreacted const exist = await NoteReactions.findOne({ noteId: note.id, diff --git a/src/services/note/read.ts b/src/services/note/read.ts index 35279db411..2bdb859476 100644 --- a/src/services/note/read.ts +++ b/src/services/note/read.ts @@ -1,23 +1,72 @@ import { publishMainStream } from '../stream'; import { Note } from '../../models/entities/note'; import { User } from '../../models/entities/user'; -import { NoteUnreads, Antennas, AntennaNotes, Users } from '../../models'; +import { NoteUnreads, AntennaNotes, Users, Followings, ChannelFollowings } from '../../models'; import { Not, IsNull, In } from 'typeorm'; +import { Channel } from '../../models/entities/channel'; +import { checkHitAntenna } from '@/misc/check-hit-antenna'; +import { getAntennas } from '@/misc/antenna-cache'; +import { PackedNote } from '../../models/repositories/note'; /** * Mark notes as read */ export default async function( userId: User['id'], - noteIds: Note['id'][] + notes: (Note | PackedNote)[], + info?: { + following: Set<User['id']>; + followingChannels: Set<Channel['id']>; + } ) { - async function careNoteUnreads() { + const following = info?.following ? info.following : new Set<string>((await Followings.find({ + where: { + followerId: userId + }, + select: ['followeeId'] + })).map(x => x.followeeId)); + const followingChannels = info?.followingChannels ? info.followingChannels : new Set<string>((await ChannelFollowings.find({ + where: { + followerId: userId + }, + select: ['followeeId'] + })).map(x => x.followeeId)); + + const myAntennas = (await getAntennas()).filter(a => a.userId === userId); + const readMentions: (Note | PackedNote)[] = []; + const readSpecifiedNotes: (Note | PackedNote)[] = []; + const readChannelNotes: (Note | PackedNote)[] = []; + const readAntennaNotes: (Note | PackedNote)[] = []; + + for (const note of notes) { + if (note.mentions && note.mentions.includes(userId)) { + readMentions.push(note); + } else if (note.visibleUserIds && note.visibleUserIds.includes(userId)) { + readSpecifiedNotes.push(note); + } + + if (note.channelId && followingChannels.has(note.channelId)) { + readChannelNotes.push(note); + } + + if (note.user != null) { // たぶんnullになることは無いはずだけど一応 + for (const antenna of myAntennas) { + if (checkHitAntenna(antenna, note, note.user as any, undefined, Array.from(following))) { + readAntennaNotes.push(note); + } + } + } + } + + if ((readMentions.length > 0) || (readSpecifiedNotes.length > 0) || (readChannelNotes.length > 0)) { // Remove the record await NoteUnreads.delete({ userId: userId, - noteId: In(noteIds), + noteId: In([...readMentions.map(n => n.id), ...readSpecifiedNotes.map(n => n.id), ...readChannelNotes.map(n => n.id)]), }); + // TODO: ↓まとめてクエリしたい + NoteUnreads.count({ userId: userId, isMentioned: true @@ -49,33 +98,25 @@ export default async function( }); } - async function careAntenna() { - const antennas = await Antennas.find({ userId }); - - await Promise.all(antennas.map(async antenna => { - const countBefore = await AntennaNotes.count({ - antennaId: antenna.id, - read: false - }); - - if (countBefore === 0) return; - - await AntennaNotes.update({ - antennaId: antenna.id, - noteId: In(noteIds) - }, { - read: true - }); + if (readAntennaNotes.length > 0) { + await AntennaNotes.update({ + antennaId: In(myAntennas.map(a => a.id)), + noteId: In(readAntennaNotes.map(n => n.id)) + }, { + read: true + }); - const countAfter = await AntennaNotes.count({ + // TODO: まとめてクエリしたい + for (const antenna of myAntennas) { + const count = await AntennaNotes.count({ antennaId: antenna.id, read: false }); - if (countAfter === 0) { + if (count === 0) { publishMainStream(userId, 'readAntenna', antenna); } - })); + } Users.getHasUnreadAntenna(userId).then(unread => { if (!unread) { @@ -83,7 +124,4 @@ export default async function( } }); } - - careNoteUnreads(); - careAntenna(); } diff --git a/src/services/note/unread.ts b/src/services/note/unread.ts index 8e6fb4abe8..5cfba0f342 100644 --- a/src/services/note/unread.ts +++ b/src/services/note/unread.ts @@ -2,7 +2,7 @@ import { Note } from '../../models/entities/note'; import { publishMainStream } from '../stream'; import { User } from '../../models/entities/user'; import { Mutings, NoteUnreads } from '../../models'; -import { genId } from '../../misc/gen-id'; +import { genId } from '@/misc/gen-id'; export default async function(userId: User['id'], note: Note, params: { // NOTE: isSpecifiedがtrueならisMentionedは必ずfalse diff --git a/src/services/note/watch.ts b/src/services/note/watch.ts index 966b7f0054..e333f04286 100644 --- a/src/services/note/watch.ts +++ b/src/services/note/watch.ts @@ -1,7 +1,7 @@ import { User } from '../../models/entities/user'; import { Note } from '../../models/entities/note'; import { NoteWatchings } from '../../models'; -import { genId } from '../../misc/gen-id'; +import { genId } from '@/misc/gen-id'; import { NoteWatching } from '../../models/entities/note-watching'; export default async (me: User['id'], note: Note) => { |